• 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   * ONDIALOGUPDATED Type
102   */
103  ONDIALOGUPDATED = 'onDialogUpdated'
104}
105/* eslint-enable no-unused-vars */
106
107const PAGE_LIFE_CYCLE_TYPES: Array<PageLifecycleHooks> = [
108  PageLifecycleHooks.ONSHOW,
109  PageLifecycleHooks.ONHIDE,
110  PageLifecycleHooks.ONBACKPRESS,
111  PageLifecycleHooks.ONMENUPRESS,
112  PageLifecycleHooks.ONMENUBUTTONPRESS,
113  PageLifecycleHooks.ONSTARTCONTINUATUIN,
114  PageLifecycleHooks.ONCOMPLETECONTINUATION,
115  PageLifecycleHooks.ONSAVEDATA,
116  PageLifecycleHooks.ONRESTOREDATA,
117  PageLifecycleHooks.ONNEWREQUEST,
118  PageLifecycleHooks.ONCONFIGURATIONUPDATED,
119  PageLifecycleHooks.ONLAYOUTREADY,
120  PageLifecycleHooks.ONACTIVE,
121  PageLifecycleHooks.ONINACTIVE,
122  PageLifecycleHooks.ONDIALOGUPDATED
123];
124
125/**
126 * Bind page lifeCycle.
127 * @param {Vm} vm - Vm object.
128 * @param {Element} element - Element object.
129 */
130export function bindPageLifeCycle(vm: Vm, element: Element): void {
131  const options = vm._vmOptions || {};
132  PAGE_LIFE_CYCLE_TYPES.forEach(type => {
133    let eventType;
134    if (type === PageLifecycleHooks.ONSHOW) {
135      eventType = 'viewappear';
136    } else if (type === PageLifecycleHooks.ONHIDE) {
137      eventType = 'viewdisappear';
138    } else if (type === PageLifecycleHooks.ONBACKPRESS) {
139      eventType = 'clickbackitem';
140    } else if (type === PageLifecycleHooks.ONSUSPENDED) {
141      eventType = 'viewsuspended';
142    } else if (type === 'onConfigurationUpdated') {
143      eventType = 'onConfigurationUpdated';
144    } else if (type === 'onLayoutReady') {
145      eventType = 'layoutReady';
146    } else if (type === 'onActive') {
147      eventType = 'viewactive';
148    } else if (type === 'onInactive') {
149      eventType = 'viewinactive';
150    } else {
151      eventType = type;
152    }
153
154    const handle = options[type];
155    let isEmitEvent = false;
156    if (handle) {
157      isEmitEvent = true;
158      element.addEvent(eventType, eventHandle);
159    } else {
160      if (type === PageLifecycleHooks.ONSHOW || type === PageLifecycleHooks.ONHIDE) {
161        element.addEvent(eventType, eventHandle);
162      }
163    }
164
165    /**
166     * Hadle event methods.
167     * @param {*} event - Event methods.
168     * @param {*} args - Arg list.
169     * @return {*}
170     */
171    function eventHandle(event, ...args: any[]): any {
172      if (type === PageLifecycleHooks.ONSHOW) {
173        emitSubVmLife(vm, 'onPageShow');
174        vm._visible = true;
175      } else if (type === PageLifecycleHooks.ONHIDE) {
176        emitSubVmLife(vm, 'onPageHide');
177        vm._visible = false;
178      } else if (type === PageLifecycleHooks.ONCONFIGURATIONUPDATED) {
179        return vm.$emitDirect(`hook:${type}`, ...args);
180      }
181
182      Log.debug(`EventHandle: isEmitEvent = ${isEmitEvent}, event = ${event}, args = ${JSON.stringify(args)}.`);
183      if (isEmitEvent) {
184        if (type === PageLifecycleHooks.ONNEWREQUEST) {
185          return handleNewRequest(args[0]);
186        } else if (type === PageLifecycleHooks.ONSAVEDATA) {
187          return handleSaveData();
188        } else if (type === PageLifecycleHooks.ONRESTOREDATA) {
189          return handleRestoreData(args[0]);
190        } else if (type === PageLifecycleHooks.ONCOMPLETECONTINUATION) {
191          return vm.$emitDirect(`hook:${type}`, ...args);
192        } else if (type === PageLifecycleHooks.ONDIALOGUPDATED) {
193          return vm.$emitDirect(`hook:${type}`, args[0]);
194        } else {
195          return vm.$emit(`hook:${type}`, {}, ...args);
196        }
197      }
198    }
199
200    /**
201     * Handle saveData.
202     * @return {string | boolean} If no hook, return false. Otherwise return vm.shareData.
203     */
204    function handleSaveData(): string | boolean {
205      const allData = {
206        saveData: {},
207        shareData: {}
208      };
209      const result = vm.$emitDirect(`hook:${type}`, allData.saveData);
210      if (!result) {
211        return false;
212      }
213      const shareResult = vm._shareData || {};
214      if (shareResult instanceof Object && !(shareResult instanceof Array)) {
215        allData.shareData = shareResult;
216      }
217      return JSON.stringify(allData);
218    }
219
220    /**
221     * Handle restore Data.
222     * @param {*} restoreData - Restore data.
223     * @return {*}
224     */
225    function handleRestoreData(restoreData: any) {
226      const saveData = restoreData.saveData || {};
227      const shareData = restoreData.shareData || {};
228
229      Object.assign(vm._shareData, shareData);
230      return vm.$emitDirect(`hook:${type}`, saveData);
231    }
232    function handleNewRequest(data: any) {
233      Object.assign(vm._data, data);
234      return vm.$emitDirect(`hook:${type}`);
235    }
236  });
237}
238
239/**
240 * Watch a calc function and callback if the calc value changes.
241 * @param {Vm} vm - Vm object.
242 * @param {string} data - Data that needed.
243 * @param {Function | string} callback - Callback function.
244 * @return {*}
245 */
246export function watch(vm: Vm, data: string, callback: ((...args: any) => any) | string): any {
247  function calc() {
248    let arr = [];
249    arr = data.split('.');
250    let retData = this;
251    arr.forEach(type => {
252      if (retData) {
253        retData = retData[type];
254      }
255    });
256    return retData;
257  }
258  const watcher = new Watcher(vm, calc, function(value, oldValue) {
259    if (typeof value !== 'object' && value === oldValue) {
260      return;
261    }
262    if (typeof callback === 'function') {
263      callback(value, oldValue);
264    } else {
265      if (vm._methods[callback] && typeof vm._methods[callback] === 'function') {
266        vm._methods[callback](value, oldValue);
267      }
268    }
269  }, null);
270  return watcher.value;
271}
272
273/**
274 * Prop is assigned to data to observe prop.
275 * @param {Vm} vm - Vm object.
276 */
277export function initPropsToData(vm: Vm): void {
278  vm._props.forEach(prop => {
279    if (vm._data) {
280      vm._data[prop] = vm[prop];
281    }
282  });
283}
284
285/**
286 * Emit subVm lifecycle
287 * @param {Vm} vm - Vm object.
288 * @param {String} type - event type
289 */
290export function emitSubVmLife(vm: Vm, type:string) {
291  if (vm._childrenVms) {
292    vm._childrenVms.forEach((subVm) => {
293      subVm.$emit(`hook:${type}`);
294      emitSubVmLife(subVm, type);
295    });
296  }
297}
298