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/**
21e484b35bSopenharmony_ci * @fileOverview
22e484b35bSopenharmony_ci * page controls from native
23e484b35bSopenharmony_ci *
24e484b35bSopenharmony_ci * - init bundle
25e484b35bSopenharmony_ci *
26e484b35bSopenharmony_ci * corresponded with the API of page manager (framework.js)
27e484b35bSopenharmony_ci */
28e484b35bSopenharmony_ci
29e484b35bSopenharmony_ciimport {
30e484b35bSopenharmony_ci  Log
31e484b35bSopenharmony_ci} from '../../../utils/index';
32e484b35bSopenharmony_ciimport { removePrefix } from '../../util/index';
33e484b35bSopenharmony_ciimport {
34e484b35bSopenharmony_ci  defineFn,
35e484b35bSopenharmony_ci  bootstrap
36e484b35bSopenharmony_ci} from './bundle';
37e484b35bSopenharmony_ciimport { updateActions } from '../api/misc';
38e484b35bSopenharmony_ciimport { getPageGlobal } from '../../app/helper';
39e484b35bSopenharmony_ciimport { Image } from '../Image';
40e484b35bSopenharmony_ciimport { OffscreenCanvas } from '../OffscreenCanvas';
41e484b35bSopenharmony_ciimport Page from '../index';
42e484b35bSopenharmony_ciimport { Services } from '../../app/index';
43e484b35bSopenharmony_ciimport { requireModule } from '../register';
44e484b35bSopenharmony_ciimport { App } from '../../app/App';
45e484b35bSopenharmony_ci
46e484b35bSopenharmony_ciinterface ParseOptions {
47e484b35bSopenharmony_ci  $app_define$(...args: any[]): void; // eslint-disable-line camelcase
48e484b35bSopenharmony_ci  $app_bootstrap$(name: string): void; // eslint-disable-line camelcase
49e484b35bSopenharmony_ci  $app_require$(name: string): void; // eslint-disable-line camelcase
50e484b35bSopenharmony_ci  Image(): void;
51e484b35bSopenharmony_ci  OffscreenCanvas(width, height): void;
52e484b35bSopenharmony_ci}
53e484b35bSopenharmony_ci
54e484b35bSopenharmony_ci/**
55e484b35bSopenharmony_ci * Init a page by run code with data.
56e484b35bSopenharmony_ci * @param {Page} page
57e484b35bSopenharmony_ci * @param {string} code
58e484b35bSopenharmony_ci * @param {Object} data
59e484b35bSopenharmony_ci * @param {Services} services
60e484b35bSopenharmony_ci * @return {*}
61e484b35bSopenharmony_ci */
62e484b35bSopenharmony_ciexport function init(page: Page, code: string | Function, data: object, services: Services): any {
63e484b35bSopenharmony_ci  Log.debug('Intialize a page with:\n', data);
64e484b35bSopenharmony_ci  let result;
65e484b35bSopenharmony_ci
66e484b35bSopenharmony_ci  // Methods to parse code.
67e484b35bSopenharmony_ci  const pageDefine = (...args) => defineFn(page, ...args);
68e484b35bSopenharmony_ci  const pageBoot = (name) => {
69e484b35bSopenharmony_ci    result = bootstrap(page, name, data);
70e484b35bSopenharmony_ci    updateActions(page);
71e484b35bSopenharmony_ci    page.doc.taskCenter.send('dom', { action: 'createFinish' }, []);
72e484b35bSopenharmony_ci    Log.debug(`After initialized a page(${page.id}).`);
73e484b35bSopenharmony_ci  };
74e484b35bSopenharmony_ci
75e484b35bSopenharmony_ci  const packageName = page.packageName;
76e484b35bSopenharmony_ci  const appFunction = () => {
77e484b35bSopenharmony_ci    if (page && page.doc) {
78e484b35bSopenharmony_ci      return page;
79e484b35bSopenharmony_ci    }
80e484b35bSopenharmony_ci    // card not has packageName
81e484b35bSopenharmony_ci    if (packageName === 'notset') {
82e484b35bSopenharmony_ci      return page;
83e484b35bSopenharmony_ci    }
84e484b35bSopenharmony_ci    const instance = App.pageMap.getTop(packageName);
85e484b35bSopenharmony_ci    return instance || page;
86e484b35bSopenharmony_ci  };
87e484b35bSopenharmony_ci
88e484b35bSopenharmony_ci  const pageRequireModule = name => requireModule(appFunction, removePrefix(name));
89e484b35bSopenharmony_ci
90e484b35bSopenharmony_ci  const imageObj: () => Image = function() {
91e484b35bSopenharmony_ci    return new Image(page);
92e484b35bSopenharmony_ci  };
93e484b35bSopenharmony_ci  const offscreenCanvasObj: (width, height) => OffscreenCanvas = function(width, height) {
94e484b35bSopenharmony_ci    return new OffscreenCanvas(page, width, height);
95e484b35bSopenharmony_ci  };
96e484b35bSopenharmony_ci  const options: ParseOptions = {
97e484b35bSopenharmony_ci    $app_define$: pageDefine,
98e484b35bSopenharmony_ci    $app_bootstrap$: pageBoot,
99e484b35bSopenharmony_ci    $app_require$: pageRequireModule,
100e484b35bSopenharmony_ci    Image: imageObj,
101e484b35bSopenharmony_ci    OffscreenCanvas: offscreenCanvasObj
102e484b35bSopenharmony_ci  };
103e484b35bSopenharmony_ci
104e484b35bSopenharmony_ci  // Support page global and init language.
105e484b35bSopenharmony_ci  global.__appProto__ = getPageGlobal(page.packageName);
106e484b35bSopenharmony_ci  global.language = page.options.language;
107e484b35bSopenharmony_ci  global.$app_define$ = pageDefine;
108e484b35bSopenharmony_ci  global.$app_require$ = pageRequireModule;
109e484b35bSopenharmony_ci  global.Image = imageObj;
110e484b35bSopenharmony_ci  global.OffscreenCanvas = offscreenCanvasObj;
111e484b35bSopenharmony_ci
112e484b35bSopenharmony_ci  let functionCode: string;
113e484b35bSopenharmony_ci  if (typeof code !== 'function') {
114e484b35bSopenharmony_ci    functionCode = `(function(global){\n\n"use strict";\n\n ${code} \n\n})(this.__appProto__)`;
115e484b35bSopenharmony_ci  }
116e484b35bSopenharmony_ci
117e484b35bSopenharmony_ci  // Compile js bundle code and get result.
118e484b35bSopenharmony_ci  if (typeof code === 'function') {
119e484b35bSopenharmony_ci    code.call(global, options);
120e484b35bSopenharmony_ci  } else {
121e484b35bSopenharmony_ci    compileBundle(functionCode, page.doc.url, options, services);
122e484b35bSopenharmony_ci  }
123e484b35bSopenharmony_ci  return result;
124e484b35bSopenharmony_ci}
125e484b35bSopenharmony_ci
126e484b35bSopenharmony_ci/**
127e484b35bSopenharmony_ci * Run bundle code by a new function.
128e484b35bSopenharmony_ci * @param {string} functionCode - Js bundle code.
129e484b35bSopenharmony_ci * @param {Object[]} args - Global methods for compile js bundle code.
130e484b35bSopenharmony_ci * @return {*}
131e484b35bSopenharmony_ci */
132e484b35bSopenharmony_ciexport function compileBundle(functionCode: string, file: string, ...args: object[]): any {
133e484b35bSopenharmony_ci  const funcKeys: string[] = [];
134e484b35bSopenharmony_ci  const funcValues: Function[] = [];
135e484b35bSopenharmony_ci  args.forEach((module) => {
136e484b35bSopenharmony_ci    for (const key in module) {
137e484b35bSopenharmony_ci      funcKeys.push(key);
138e484b35bSopenharmony_ci      funcValues.push(module[key]);
139e484b35bSopenharmony_ci    }
140e484b35bSopenharmony_ci  });
141e484b35bSopenharmony_ci
142e484b35bSopenharmony_ci  // If failed to run code on native, then run code on framework.
143e484b35bSopenharmony_ci  if (!compileBundleNative(funcKeys, funcValues, functionCode, file)) {
144e484b35bSopenharmony_ci    Log.error(`Compile js bundle failed, typeof code is not 'function'`)
145e484b35bSopenharmony_ci    return;
146e484b35bSopenharmony_ci  }
147e484b35bSopenharmony_ci}
148e484b35bSopenharmony_ci
149e484b35bSopenharmony_ci/**
150e484b35bSopenharmony_ci * Call a new function generated on the V8 native side.
151e484b35bSopenharmony_ci * @param {string[]} funcKeys
152e484b35bSopenharmony_ci * @param {Function[]} funcValues
153e484b35bSopenharmony_ci * @param {string} functionCode
154e484b35bSopenharmony_ci * @return {boolean} Return true if no error occurred.
155e484b35bSopenharmony_ci */
156e484b35bSopenharmony_cifunction compileBundleNative(funcKeys: string[], funcValues: Function[], functionCode: string, file: string): boolean {
157e484b35bSopenharmony_ci  if (typeof compileAndRunBundle !== 'function') {
158e484b35bSopenharmony_ci    return false;
159e484b35bSopenharmony_ci  }
160e484b35bSopenharmony_ci
161e484b35bSopenharmony_ci  let isSuccess: boolean = false;
162e484b35bSopenharmony_ci  const bundle: string = `(function (${funcKeys.toString()}) {${functionCode}})`;
163e484b35bSopenharmony_ci  try {
164e484b35bSopenharmony_ci    const compileFunction: Function = compileAndRunBundle(bundle, file);
165e484b35bSopenharmony_ci    if (compileFunction && typeof compileFunction === 'function') {
166e484b35bSopenharmony_ci      compileFunction(...funcValues);
167e484b35bSopenharmony_ci      isSuccess = true;
168e484b35bSopenharmony_ci    }
169e484b35bSopenharmony_ci  } catch (e) {
170e484b35bSopenharmony_ci    Log.error(e);
171e484b35bSopenharmony_ci  }
172e484b35bSopenharmony_ci  return isSuccess;
173e484b35bSopenharmony_ci}
174