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