• 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
20import { Log } from '../../utils/index';
21import Watcher from '../reactivity/watcher';
22import Element from '../../vdom/Element';
23import Vm from './index';
24
25/**
26 * Enum for Page lifecycle hooks.
27 * @enum {string}
28 * @readonly
29 */
30/* eslint-disable no-unused-vars */
31export const enum PageLifecycleHooks {
32  /**
33   * ONINIT Type
34   */
35  ONINIT = 'onInit',
36  /**
37   * ONREADY Type
38   */
39  ONREADY = 'onReady',
40  /**
41   * ONSHOW Type
42   */
43  ONSHOW = 'onShow',
44  /**
45   * ONHIDE Type
46   */
47  ONHIDE = 'onHide',
48  /**
49   * ONBACKPRESS Type
50   */
51  ONBACKPRESS = 'onBackPress',
52  /**
53   * ONMENUPRESS Type
54   */
55  ONMENUPRESS = 'onMenuPress',
56  /**
57   * ONMENUBUTTONPRESS Type
58   */
59  ONMENUBUTTONPRESS = 'onMenuButtonPress',
60  /**
61   * ONSUSPENDED Type
62   */
63  ONSUSPENDED = 'onSuspended',
64  /**
65   * ONSTARTCONTINUATUIN Type
66   */
67  ONSTARTCONTINUATUIN = 'onStartContinuation',
68  /**
69   * ONCOMPLETECONTINUATION Type
70   */
71  ONCOMPLETECONTINUATION = 'onCompleteContinuation',
72  /**
73   * ONSAVEDATA Type
74   */
75  ONSAVEDATA = 'onSaveData',
76  /**
77   * ONRESTOREDATA Type
78   */
79  ONRESTOREDATA = 'onRestoreData',
80  /**
81   * ONNEWREQUEST Type
82   */
83  ONNEWREQUEST = 'onNewRequest',
84  /**
85   * ONCONFIGURATIONUPDATED Type
86   */
87  ONCONFIGURATIONUPDATED = 'onConfigurationUpdated',
88  /**
89   * ONLAYOUTREADY Type
90   */
91  ONLAYOUTREADY = 'onLayoutReady',
92  /**
93   * ONACTIVE Type
94   */
95  ONACTIVE = 'onActive',
96  /**
97   * ONLAYOUTREADY Type
98   */
99  ONINACTIVE = 'onInactive'
100}
101/* eslint-enable no-unused-vars */
102
103const PAGE_LIFE_CYCLE_TYPES: Array<PageLifecycleHooks> = [
104  PageLifecycleHooks.ONSHOW,
105  PageLifecycleHooks.ONHIDE,
106  PageLifecycleHooks.ONBACKPRESS,
107  PageLifecycleHooks.ONMENUPRESS,
108  PageLifecycleHooks.ONMENUBUTTONPRESS,
109  PageLifecycleHooks.ONSTARTCONTINUATUIN,
110  PageLifecycleHooks.ONCOMPLETECONTINUATION,
111  PageLifecycleHooks.ONSAVEDATA,
112  PageLifecycleHooks.ONRESTOREDATA,
113  PageLifecycleHooks.ONNEWREQUEST,
114  PageLifecycleHooks.ONCONFIGURATIONUPDATED,
115  PageLifecycleHooks.ONLAYOUTREADY,
116  PageLifecycleHooks.ONACTIVE,
117  PageLifecycleHooks.ONINACTIVE
118];
119
120/**
121 * Bind page lifeCycle.
122 * @param {Vm} vm - Vm object.
123 * @param {Element} element - Element object.
124 */
125export function bindPageLifeCycle(vm: Vm, element: Element): void {
126  const options = vm.vmOptions || {};
127  PAGE_LIFE_CYCLE_TYPES.forEach(type => {
128    let eventType;
129    if (type === PageLifecycleHooks.ONSHOW) {
130      eventType = 'viewappear';
131    } else if (type === PageLifecycleHooks.ONHIDE) {
132      eventType = 'viewdisappear';
133    } else if (type === PageLifecycleHooks.ONBACKPRESS) {
134      eventType = 'clickbackitem';
135    } else if (type === PageLifecycleHooks.ONSUSPENDED) {
136      eventType = 'viewsuspended';
137    } else if (type === 'onConfigurationUpdated') {
138      eventType = 'onConfigurationUpdated';
139    } else if (type === 'onLayoutReady') {
140      eventType = 'layoutReady';
141    } else if (type === 'onActive') {
142      eventType = 'viewactive';
143    } else if (type === 'onInactive') {
144      eventType = 'viewinactive';
145    } else {
146      eventType = type;
147    }
148
149    const handle = options[type];
150    let isEmitEvent = false;
151    if (handle) {
152      isEmitEvent = true;
153      element.addEvent(eventType, eventHandle);
154    } else {
155      if (type === PageLifecycleHooks.ONSHOW || type === PageLifecycleHooks.ONHIDE) {
156        element.addEvent(eventType, eventHandle);
157      }
158    }
159
160    /**
161     * Hadle event methods.
162     * @param {*} event - Event methods.
163     * @param {*} args - Arg list.
164     * @return {*}
165     */
166    function eventHandle(event, ...args: any[]): any {
167      if (type === PageLifecycleHooks.ONSHOW) {
168        emitSubVmLife(vm, 'onPageShow');
169        vm.visible = true;
170      } else if (type === PageLifecycleHooks.ONHIDE) {
171        emitSubVmLife(vm, 'onPageHide');
172        vm.visible = false;
173      } else if (type === PageLifecycleHooks.ONCONFIGURATIONUPDATED) {
174        return vm.$emitDirect(`hook:${type}`, ...args);
175      }
176
177      Log.debug(`EventHandle: isEmitEvent = ${isEmitEvent}, event = ${event}, args = ${JSON.stringify(args)}.`);
178      if (isEmitEvent) {
179        if (type === PageLifecycleHooks.ONNEWREQUEST) {
180          return handleNewRequest(args[0]);
181        } else if (type === PageLifecycleHooks.ONSAVEDATA) {
182          return handleSaveData();
183        } else if (type === PageLifecycleHooks.ONRESTOREDATA) {
184          return handleRestoreData(args[0]);
185        } else if (type === PageLifecycleHooks.ONCOMPLETECONTINUATION) {
186          return vm.$emitDirect(`hook:${type}`, ...args);
187        } else {
188          return vm.$emit(`hook:${type}`, {}, ...args);
189        }
190      }
191    }
192
193    /**
194     * Handle saveData.
195     * @return {string | boolean} If no hook, return false. Otherwise return vm.shareData.
196     */
197    function handleSaveData(): string | boolean {
198      const allData = {
199        saveData: {},
200        shareData: {}
201      };
202      const result = vm.$emitDirect(`hook:${type}`, allData.saveData);
203      if (!result) {
204        return false;
205      }
206      const shareResult = vm.shareData || {};
207      if (shareResult instanceof Object && !(shareResult instanceof Array)) {
208        allData.shareData = shareResult;
209      }
210      return JSON.stringify(allData);
211    }
212
213    /**
214     * Handle restore Data.
215     * @param {*} restoreData - Restore data.
216     * @return {*}
217     */
218    function handleRestoreData(restoreData: any) {
219      const saveData = restoreData.saveData || {};
220      const shareData = restoreData.shareData || {};
221
222      Object.assign(vm.shareData, shareData);
223      return vm.$emitDirect(`hook:${type}`, saveData);
224    }
225    function handleNewRequest(data: any) {
226      Object.assign(vm.__data, data);
227      return vm.$emitDirect(`hook:${type}`);
228    }
229  });
230}
231
232/**
233 * Watch a calc function and callback if the calc value changes.
234 * @param {Vm} vm - Vm object.
235 * @param {string} data - Data that needed.
236 * @param {Function | string} callback - Callback function.
237 * @return {*}
238 */
239export function watch(vm: Vm, data: string, callback: ((...args: any) => any) | string): any {
240  function calc() {
241    let arr = [];
242    arr = data.split('.');
243    let retData = this;
244    arr.forEach(type => {
245      if (retData) {
246        retData = retData[type];
247      }
248    });
249    return retData;
250  }
251  const watcher = new Watcher(vm, calc, function(value, oldValue) {
252    if (typeof value !== 'object' && value === oldValue) {
253      return;
254    }
255    if (typeof callback === 'function') {
256      callback(value, oldValue);
257    } else {
258      if (vm.methods[callback] && typeof vm.methods[callback] === 'function') {
259        vm.methods[callback](value, oldValue);
260      }
261    }
262  }, null);
263  return watcher.value;
264}
265
266/**
267 * Prop is assigned to data to observe prop.
268 * @param {Vm} vm - Vm object.
269 */
270export function initPropsToData(vm: Vm): void {
271  vm.props.forEach(prop => {
272    if (vm.__data) {
273      vm.__data[prop] = vm[prop];
274    }
275  });
276}
277
278/**
279 * Emit subVm lifecycle
280 * @param {Vm} vm - Vm object.
281 * @param {String} type - event type
282 */
283export function emitSubVmLife(vm: Vm, type:string) {
284  if (vm.childrenVms) {
285    vm.childrenVms.forEach((subVm) => {
286      subVm.$emit(`hook:${type}`);
287      emitSubVmLife(subVm, type);
288    });
289  }
290}
291