• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1/*
2 * Licensed to the Apache Software Foundation (ASF) under one
3 * or more contributor license agreements.  See the NOTICE file
4 * distributed with this work for additional information
5 * regarding copyright ownership.  The ASF licenses this file
6 * to you under the Apache License, Version 2.0 (the
7 * "License"); you may not use this file except in compliance
8 * with the License.  You may obtain a copy of the License at
9 *
10 *   http://www.apache.org/licenses/LICENSE-2.0
11 *
12 * Unless required by applicable law or agreed to in writing,
13 * software distributed under the License is distributed on an
14 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15 * KIND, either express or implied.  See the License for the
16 * specific language governing permissions and limitations
17 * under the License.
18 */
19/*
20 * 2021.01.08 - Add init global data and hook life cycle of App.
21 * Copyright (c) 2021 Huawei Device Co., Ltd.
22 */
23
24import {
25  isModule,
26  removePrefix,
27  isApplication,
28  removeApplicationPrefix,
29  Log
30} from '../../utils/index';
31import {
32  registerCustomComponent,
33  requireModule
34} from '../page/register';
35import { pageMap, appMap } from './map';
36import { updateLocale, updateDpi } from './index';
37import Page from '../page/index';
38import { App } from './App';
39
40const APP_LIFE_CYCLE_TYPES: string[] = ['onCreate', 'onError', 'onDestroy', 'onShow', 'onHide'];
41
42export let CSS_INHERITANCE: string[];
43
44/**
45 * Parse app page code.
46 * @param {Page} page
47 * @param {string} packageName - PackageName of App.
48 * @param {string} name - Name of page.
49 * @param {*[]} args
50 */
51export const defineFn = function(page: Page, packageName: string, name?: string, ...args: any[] | null): void {
52  Log.debug(`Define a page ${name}.`);
53  const parseContent: Function = args[1];
54  let bundleContent: any = null;
55
56  // Function to obtain bundle content.
57  if (parseContent) {
58    const pageRequire = (name: string) : any => {
59      if (isModule(name)) {
60        const appFunction = (): Page => {
61          return pageMap.getTop(packageName) || page;
62        };
63        return requireModule(appFunction, removePrefix(name));
64      }
65    };
66    const moduleContent = { exports: {} };
67    parseContent(pageRequire, moduleContent.exports, moduleContent);
68    bundleContent = moduleContent.exports;
69
70    let minPlatformVersion: number = 5;
71    if (bundleContent.manifest) {
72      minPlatformVersion = bundleContent.manifest.minPlatformVersion;
73    }
74    CSS_INHERITANCE = minPlatformVersion > 5 ?
75      ['fontFamily', 'fontWeight', 'fontSize', 'fontStyle', 'textAlign', 'lineHeight', 'letterSpacing', 'color', 'visibility'] :
76      [];
77  }
78
79  // Apply bundleContent.
80  if (isApplication(name)) {
81    const componetName: string = removeApplicationPrefix(name);
82    registerCustomComponent(page, componetName, bundleContent);
83  }
84};
85
86/**
87 * Set i18n and dpi data, hook life cycle of App.
88 * @param {Page} page
89 * @param {string} packageName - PackageName of App.
90 * @param {string} name - Name of page.
91 * @param {*} config
92 * @param {*} data
93 * @return {*}
94 */
95export function bootstrap(page: Page, packageName: string, name: string, config: any, data: any): any {
96  Log.debug(`Bootstrap for ${name}.`);
97  Log.debug(`${config} ${data}`);
98
99  // Check component name.
100  let componentName: string;
101  if (isApplication(name)) {
102    componentName = removeApplicationPrefix(name);
103  } else {
104    return new Error(`Wrong component name: ${name}.`);
105  }
106
107  // Init global data when page first load,
108  // global.aceapp.$data means config.data in manifest.json, can add new data by this.$app.$data api.
109  if (page.options && page.options.appCreate) {
110    const getApp = function() {
111      return global.aceapp;
112    };
113    global.getApp = getApp;
114    global.aceapp = {};
115    global.aceapp.$data = page.options.appGlobalData || {};
116
117    // Set i18n and dpi data.
118    if (page.options.i18n) {
119      updateLocale(page.options.i18n);
120    }
121    if (page.options.resourcesConfiguration) {
122      updateDpi(page.options.resourcesConfiguration);
123    }
124  }
125  if (page.customComponentMap) {
126    const app: App = appMap[packageName];
127    if (app) {
128      const options: object = page.customComponentMap[componentName] || {};
129      const aceapp: any = global.aceapp || {};
130      for (const key in options) {
131        if (!isReserved(key)) {
132          app[key] = options[key];
133          aceapp[key] = options[key];
134        }
135      }
136      aceapp.$def = aceapp;
137      aceapp._def = aceapp.$def;
138      aceapp._data = aceapp.$data;
139
140      // Exit api to $app.
141      aceapp.exit = function(): void {
142      };
143      APP_LIFE_CYCLE_TYPES.forEach((type) => {
144        app.onEvent(`hook:${type}`, options[type]);
145      });
146
147      // Last fire on Create.
148      Log.debug(`Page "onCreate" lifecycle in app(${app.packageName}).`);
149      app.emitEvent('hook:onCreate');
150    }
151  }
152}
153
154/**
155 * Check input param is onCreate or onDestroy.
156 * @param {string} key
157 * @return {boolean}
158 */
159function isReserved(key: string): boolean {
160  if (key === 'onCreate' || key === 'onDestroy') {
161    return true;
162  }
163  return false;
164}
165
166/**
167 * Return timerAPIs.
168 * @param {Page} page - Page
169 * @return {Object}
170 */
171export function genTimerAPI(page: Page): object {
172  const timerAPIs: object = {};
173
174  // Timer APIs polyfill in native
175  const timer: any = page.requireModule('timer');
176  const animation = page.requireModule('animation');
177  Object.assign(timerAPIs, {
178    setTimeout: (...args) => {
179      const handler = () => {
180        args[0](...args.slice(2));
181      };
182      timer.setTimeout(handler, args[1]);
183      return page.doc.taskCenter.callbackManager.currCallbackId.toString();
184    },
185    setInterval: (...args) => {
186      const handler = () => {
187        args[0](...args.slice(2));
188      };
189      timer.setInterval(handler, args[1]);
190      return page.doc.taskCenter.callbackManager.currCallbackId.toString();
191    },
192    clearTimeout: (n) => {
193      timer.clearTimeout(n);
194      page.doc.taskCenter.callbackManager.remove(n);
195    },
196    clearInterval: (n) => {
197      timer.clearInterval(n);
198      page.doc.taskCenter.callbackManager.remove(n);
199    },
200    requestAnimationFrame: (...args) => {
201      const handler = function(timestamp) {
202        args[0](timestamp, ...args.slice(1));
203      };
204      animation.requestAnimationFrame(handler);
205      return page.doc.taskCenter.callbackManager.currCallbackId.toString();
206    },
207    cancelAnimationFrame: (n) => {
208      animation.cancelAnimationFrame(n);
209    }
210  });
211  return timerAPIs;
212}
213