import { DoricSuperNode, DoricViewNode, DVModel } from "./DoricViewNode"; export class DoricRefreshableNode extends DoricSuperNode { headerViewId = "" headerNode?: DoricViewNode contentViewId = "" contentNode?: DoricViewNode onRefreshCallback?: Function headerContainer?: HTMLDivElement contentContainer?: HTMLDivElement refreshable = true build() { const ret = document.createElement('div') ret.style.overflow = "hidden" const header = document.createElement('div') const content = document.createElement('div') header.style.width = "100%" header.style.height = "100%" header.style.display = "flex" header.style.alignItems = "flex-end" header.style.justifyContent = "center" content.style.width = "100%" content.style.height = "100%" ret.appendChild(header) ret.appendChild(content) let touchStart = 0 ret.ontouchstart = (ev) => { if (!this.refreshable) { return } touchStart = ev.touches[0].pageY } ret.ontouchmove = (ev) => { if (!this.refreshable) { return } const offset = (ev.touches[0].pageY - touchStart) * 0.68 ret.scrollTop = Math.max(0, header.offsetHeight - offset) this.headerNode?.callJSResponse("setPullingDistance", offset) } const touchend = () => { if (!this.refreshable) { return } if (header.offsetHeight - ret.scrollTop >= (this.headerNode?.getWidth() || 0)) { this.setRefreshing(true) this.onRefreshCallback?.() } else { // To idel ret.scrollTo({ top: header.offsetHeight, behavior: "smooth" }) } } ret.ontouchcancel = () => { touchend() } ret.ontouchend = () => { touchend() } window.requestAnimationFrame(() => { ret.scrollTop = header.offsetHeight }) this.headerContainer = header this.contentContainer = content return ret } blendProps(v: HTMLElement, propName: string, prop: any) { if (propName === 'content') { this.contentViewId = prop } else if (propName === 'header') { this.headerViewId = prop } else if (propName === 'onRefresh') { this.onRefreshCallback = () => { this.callJSResponse(prop) } } else { super.blendProps(v, propName, prop) } } blendSubNode(model: DVModel) { this.getSubNodeById(model.id)?.blend(model.props) } getSubNodeById(viewId: string) { if (viewId === this.headerViewId) { return this.headerNode } else if (viewId === this.contentViewId) { return this.contentNode } return undefined } onBlending() { super.onBlending() { const headerModel = this.getSubModel(this.headerViewId) if (headerModel) { if (this.headerNode) { if (this.headerNode.viewId !== this.headerViewId) { if (this.reusable && this.headerNode.viewType === headerModel.type) { this.headerNode.viewId = headerModel.id this.headerNode.blend(headerModel.props) } else { this.headerContainer?.removeChild(this.headerNode.view) const headerNode = DoricViewNode.create(this.context, headerModel.type) if (headerNode) { headerNode.viewId = headerModel.id headerNode.init(this) headerNode.blend(headerModel.props) this.headerContainer?.appendChild(headerNode.view) this.headerNode = headerNode } } } } else { const headerNode = DoricViewNode.create(this.context, headerModel.type) if (headerNode) { headerNode.viewId = headerModel.id headerNode.init(this) headerNode.blend(headerModel.props) this.headerContainer?.appendChild(headerNode.view) this.headerNode = headerNode } } } } { const contentModel = this.getSubModel(this.contentViewId) if (contentModel) { if (this.contentNode) { if (this.contentNode.viewId !== this.contentViewId) { if (this.reusable && this.contentNode.viewType === contentModel.type) { this.contentNode.viewId = contentModel.id this.contentNode.blend(contentModel.props) } else { this.contentContainer?.removeChild(this.contentNode.view) const contentNode = DoricViewNode.create(this.context, contentModel.type) if (contentNode) { contentNode.viewId = contentModel.id contentNode.init(this) contentNode.blend(contentModel.props) this.contentContainer?.appendChild(contentNode.view) this.contentNode = contentNode } } } } else { const contentNode = DoricViewNode.create(this.context, contentModel.type) if (contentNode) { contentNode.viewId = contentModel.id contentNode.init(this) contentNode.blend(contentModel.props) this.contentContainer?.appendChild(contentNode.view) this.contentNode = contentNode } } } } } onBlended() { super.onBlended() } setRefreshing(v: boolean) { if (!this.headerContainer || !this.headerNode) { return } if (v) { this.view.scrollTo({ top: this.headerContainer.offsetHeight - this.headerNode.getHeight(), behavior: "smooth" }) this.headerNode.callJSResponse("startAnimation") } else { this.view.scrollTo({ top: this.headerContainer?.offsetHeight, behavior: "smooth" }) this.headerNode.callJSResponse("stopAnimation") } } setRefreshable(v: boolean) { this.refreshable = v if (!v) { this.setRefreshing(false) } } }