diff --git a/src/widgets/battery/battery.ts b/src/widgets/battery/battery.ts index df66ba0..a778035 100644 --- a/src/widgets/battery/battery.ts +++ b/src/widgets/battery/battery.ts @@ -35,6 +35,15 @@ class BatteryWidget extends GaiaWidget { this.charge = this._battery.charging this._battery.addEventListener('levelchange', this) this._battery.addEventListener('chargingchange', this) + this.lifeCycle = 'initialized' + } + + run = async () => { + if (this.lifeCycle == 'initializing') { + await this.init() + } + this.percent = this._battery.level * 100 + this.charge = this._battery.charging } handleEvent(event: Event): void { diff --git a/src/widgets/clock/clock.ts b/src/widgets/clock/clock.ts index 4e2cc7e..6dda0b6 100644 --- a/src/widgets/clock/clock.ts +++ b/src/widgets/clock/clock.ts @@ -40,14 +40,20 @@ class ClockWidget extends GaiaWidget { }) } - init() {} - clock!: StarClock connectedCallback() { this.clock = this.shadowRoot!.querySelector('star-clock')! + } + + run = () => { + if (!this.clock) this.clock = this.shadowRoot!.querySelector('star-clock')! this.clock.date = new Date() } + openActivity = (_: any): any => { + return Promise.resolve() + } + refresh() { this.clock.date = new Date() } diff --git a/src/widgets/gaia-widget.ts b/src/widgets/gaia-widget.ts index 0b8b05e..ba5af8f 100644 --- a/src/widgets/gaia-widget.ts +++ b/src/widgets/gaia-widget.ts @@ -45,6 +45,15 @@ export default class GaiaWidget extends StarBaseElement { createTime: number = new Date().getTime() container!: HTMLElement activityRequestTimer: number | undefined + lifeCycle!: + | 'initializing' + | 'initializition-failed' + | 'initialized' + | 'preparing' + | 'running' + | 'preparation-failed' + // TODO: 补充activity失败原因 + status!: 'requesting' | 'idle' | 'activity-shut-down' | 'err' constructor({ url, size, @@ -70,35 +79,64 @@ export default class GaiaWidget extends StarBaseElement { this.attachShadow({mode: 'open'}) this.shadowRoot!.innerHTML = this.template + this.lifeCycle = 'initializing' this.init() - this.dispatchReady() } init() { - // 补全小组件入口地址 - if (!/^http(s)?:\/\//.test(this.url)) { - if (/^\//.test(this.url)) { - this.url = this.origin + this.url + return new Promise((res, rej) => { + if (this.lifeCycle == 'initializing') { + // 补全小组件入口地址 + if (!/^http(s)?:\/\//.test(this.url)) { + if (/^\//.test(this.url)) { + this.url = this.origin + this.url + } else { + this.url = this.origin + '/' + this.url + } + } + if (this.url.endsWith('html')) { + this.container = this.shadowRoot!.querySelector( + '#gaia-widget-container-' + this.createTime + )! + this.container.addEventListener('touchstart', this) + this.container.addEventListener('touchmove', this) + this.container.addEventListener('touchend', this) + this.container.addEventListener('click', this) + + // 需要在构造函数中被调用,在connectedCallback中调用会导致移动元素时刷新的问题 + this.querySources(this.url) + .then(this.parseHTML) + .then(() => { + this.lifeCycle = 'initialized' + res(undefined) + }) + .catch((err) => { + this.lifeCycle = 'initializition-failed' + console.error(err) + rej(err) + }) + } else { + this.lifeCycle = 'initialized' + res(undefined) + } } else { - this.url = this.origin + '/' + this.url + res(undefined) } - } - this.container = this.shadowRoot!.querySelector( - '#gaia-widget-container-' + this.createTime - )! - this.container.addEventListener('touchstart', this) - this.container.addEventListener('touchmove', this) - this.container.addEventListener('touchend', this) - this.container.addEventListener('click', this) + }) } - dispatchReady = () => { - // 需要在构造函数中被调用,在connectedCallback中调用会导致移动元素时刷新的问题 + run = () => { + this.lifeCycle = 'preparing' // 防止安装、更新应用时,首次 Activity 请求因注册方 Service Worker 未完成安装而丢失 let n = 0 this.activityRequestTimer = window.setInterval(() => { - if (n++ > 4) clearInterval(this.activityRequestTimer) - this.openActivity({data: {type: 'ready'}}) + if (n++ > 4) { + clearInterval(this.activityRequestTimer) + this.lifeCycle = 'preparation-failed' + } + this.openActivity({data: {type: 'ready'}}).then( + () => (this.lifeCycle = 'running') + ) }, 100) } @@ -164,23 +202,35 @@ export default class GaiaWidget extends StarBaseElement { } openActivity = ({data}: any) => { - data.widgetTitle = this.widgetTitle - data.manifestName = this.manifestWidgetName - data.viewName = this.viewName + // TODO: 添加任务队列 + this.status = 'requesting' + return new Promise((res, rej) => { + data.widgetTitle = this.widgetTitle + data.manifestName = this.manifestWidgetName + data.viewName = this.viewName - // @ts-ignore - const activity = new WebActivity( - `${this.appName}_${this.manifestWidgetName}`, - {data, type: ['widget']} - ) + // @ts-ignore + const activity = new WebActivity( + `${this.appName}_${this.manifestWidgetName}`, + {data, type: ['widget']} + ) - activity - .start() - .then((result: any) => { - if (this.activityRequestTimer) clearInterval(this.activityRequestTimer) - this.handleActivity(result) - }) - .catch((err: any) => console.log(err)) + activity + .start() + .then((result: any) => { + if (this.activityRequestTimer) { + clearInterval(this.activityRequestTimer) + } + this.handleActivity(result) + this.status = 'idle' + res(result) + }) + .catch((err: any) => { + console.log(err) + this.status = 'err' + rej(err) + }) + }) } wrapEvent = (event: any) => { @@ -206,7 +256,7 @@ export default class GaiaWidget extends StarBaseElement { /** * 请求组件资源 */ - querySources(url: string) { + querySources(url: string): Promise { return new Promise((res, rej) => { // @ts-ignore const xhr = new XMLHttpRequest({mozSystem: true}) @@ -240,21 +290,24 @@ export default class GaiaWidget extends StarBaseElement { * @param {DOMString} html 文档字符串 * @returns */ - parseHTML = (html: string) => { - html = this.handleSource(this.filterDom(html)) + parseHTML = (html?: string) => { + return new Promise((res, rej) => { + if (!html) return rej() + html = this.handleSource(this.filterDom(html)) - const parse = new DOMParser() - const htmlDocument = parse.parseFromString(html, 'text/html') - const {head, body} = htmlDocument - // @ts-ignore - this.widgetTitle = head?.querySelector('title').innerHTML - if (this.widgetTitle === void 0) { - throw new Error('There is not a widget name yet!') - } + const parse = new DOMParser() + const htmlDocument = parse.parseFromString(html, 'text/html') + const {head, body} = htmlDocument + // @ts-ignore + this.widgetTitle = head?.querySelector('title').innerHTML + if (this.widgetTitle === void 0) { + throw rej(new Error('There is not a widget name yet!')) + } - this.appendStyle(htmlDocument) - this.container.innerHTML = body.innerHTML - return Promise.resolve() + this.appendStyle(htmlDocument) + this.container.innerHTML = body.innerHTML + res(undefined) + }) } /**