• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1/*
2 * Copyright (c) 2021 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 *     http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16import { Log } from '../../utils/index';
17import {
18  defineFn,
19  bootstrap,
20  genTimerAPI
21} from './bundle';
22import { appMap } from './map';
23import { getPageGlobal } from './helper';
24import { App } from './App';
25import { PageLinkedMap } from './map';
26import Page from '../page/index';
27import { destroy } from '../page/api/index';
28import { compileBundle } from '../page/entry/init';
29import { removePrefix } from '../util/index';
30import { requireModule } from '../page/register';
31
32/**
33 * Device information for mediaQuery.
34 */
35export interface MediaQueryInfo {
36  'orientation': string;
37  'device-type': string;
38  'device-width': string;
39  'device-height': string;
40  'round-screen': boolean;
41  'width': string;
42  'height': string;
43  'isInit': boolean;
44  'resolution': string;
45  'aspect-ratio': string;
46  'dark-mode': string;
47}
48
49/**
50 * Information of App.
51 */
52export interface Options extends MediaQueryInfo {
53  'appInstanceId': string;
54  'packageName': string;
55  'appCreate': boolean;
56  'appCode': string | Function;
57  'pcPreview': string;
58  'resourcesConfiguration': object;
59  'i18n': object;
60  'language': string;
61  'appGlobalData'?: object;
62  'bundleUrl': string;
63}
64
65/**
66 * Framework Services.
67 */
68export interface Services {
69  service: object;
70  I18n?: Function;
71  dpi?: Function;
72}
73
74interface ParseOptions {
75  $app_define$(...args: any[]): void; // eslint-disable-line camelcase
76  $app_bootstrap$(name: string, config: any, _data: any): void; // eslint-disable-line camelcase
77  $app_require$(name: string): void; // eslint-disable-line camelcase
78}
79
80const pageMap: PageLinkedMap = App.pageMap;
81
82/**
83 * Create app page, run jsbundle code.
84 * @param {Page} page
85 * @param {Options} options
86 * @param {Object} data
87 * @param {Services} services
88 */
89export function appCreate(page: Page, options: Options, data: object, services: Services): void {
90  if (!options || !options.appCreate || !options.appCode) {
91    return;
92  }
93  if (options.pcPreview && options.pcPreview === 'enable') {
94    global.pcPreview = true;
95  }
96  const packageName: string = page.packageName;
97  const appPage: Page = new Page(options.appInstanceId, options, packageName, data);
98  pageMap.unshift(appPage);
99  Log.debug(`Create a page with: ${packageName}.`);
100  appMap[packageName] = new App(packageName, options.appInstanceId);
101  const timerAPIs: object = genTimerAPI(appPage);
102  appMap[packageName].setTimer(timerAPIs);
103  const code = options.appCode;
104  global.__appProto__ = getPageGlobal(packageName);
105
106  // prepare page env methods
107  const appDefine = (...args: any[]): void => defineFn(page, packageName, ...args);
108  const appBootstrap = (name: string, config: any, _data: any): void => {
109    bootstrap(page, packageName, name, config, _data || data);
110    Log.debug(`After create a page(${page.id}).`);
111  };
112
113  const appFunction = () => pageMap.getTop(packageName) || page;
114
115  // require in top app(instance)
116  const appRequireModule = name => requireModule(appFunction, removePrefix(name));
117  const parseOptions: ParseOptions = {
118    $app_define$: appDefine,
119    $app_bootstrap$: appBootstrap,
120    $app_require$: appRequireModule
121  };
122  global.$app_require$ = appRequireModule;
123
124  // Compile js bundle code and get result.
125  if (typeof code === 'function') {
126    Log.info('call Function directly when appCreate');
127    code.call(global, parseOptions);
128  } else {
129    // Function with code and use strict mode.
130    const functionCode: string = `(function(global){\n\n"use strict";\n\n ${code} \n\n})(this.__appProto__)`;
131    compileBundle(functionCode, 'app.js', parseOptions, timerAPIs, services);
132  }
133}
134
135/**
136 * Emit onError event.
137 * @param {string} packageName
138 * @param {*} errors
139 */
140export function appError(packageName: string, errors: any): void {
141  Log.debug(`AppError an app with: ${packageName}.`);
142  const app: App = appMap[packageName];
143  if (!app) {
144    Log.debug(`AppError an app error ${packageName}.`);
145    return;
146  }
147  Log.debug(`AppError an app error ${packageName}.`);
148  app.emitEvent('hook:onError', errors);
149}
150
151/**
152 * Emit onShow event.
153 * @param {string} packageName - Package name.
154 */
155export function appShow(packageName: string): void {
156  Log.debug(`Show an app with: ${packageName}.`);
157  const app: App = appMap[packageName];
158  if (!app) {
159    Log.debug(`Show an app error ${packageName}.`);
160    return;
161  }
162  app.emitEvent('hook:onShow');
163}
164
165/**
166 * Emit onHide event.
167 * @param {string} packageName - Package name.
168 */
169export function appHide(packageName: string): void {
170  Log.debug(`Hide an app with: ${packageName}.`);
171  const app: App = appMap[packageName];
172  if (!app) {
173    Log.debug(`Hide an app error ${packageName}.`);
174    return;
175  }
176  app.emitEvent('hook:onHide');
177}
178
179/**
180 * Emit onDestroy event.
181 * @param {string} packageName - Package name.
182 */
183export function appDestroy(packageName: string): void {
184  Log.debug(`Destroy an app with: ${packageName}.`);
185  const app: App = appMap[packageName];
186  if (!app) {
187    Log.error(`Destroy an app error ${packageName}.`);
188    return;
189  }
190  app.emitEvent('hook:onDestroy');
191  app.deleteGlobalKeys();
192  delete appMap[packageName];
193  const appPage: Page = pageMap[app.appInstanceId];
194  if (appPage) {
195    if (appPage.doc.taskCenter.callbackIsEmpty()) {
196      appPage.callTasks([{
197        module: 'internal.jsResult',
198        method: 'appDestroyFinish',
199        args: []
200      }]);
201      destroy(appPage);
202      pageMap.remove(appPage);
203    } else {
204      appPage.destroyed = true;
205    }
206  }
207}
208
209/**
210 * Init language resource.
211 * @param {*} i18nData
212 */
213export function updateLocale(i18nData: any): void {
214  if (i18nData) {
215    global.aceapp._i18n_data_ = { messages: i18nData.resources };
216  } else {
217    global.aceapp._i18n_data_ = null;
218  }
219}
220
221/**
222 * Init image dpi.
223 * @param {Object} dpiData
224 */
225export function updateDpi(dpiData: object): void {
226  if (dpiData) {
227    global.aceapp._dpi_data_ = { images: dpiData };
228  } else {
229    global.aceapp._dpi_data_ = null;
230  }
231}
232