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