| /* |
| * Licensed to the Apache Software Foundation (ASF) under one |
| * or more contributor license agreements. See the NOTICE file |
| * distributed with this work for additional information |
| * regarding copyright ownership. The ASF licenses this file |
| * to you under the Apache License, Version 2.0 (the |
| * "License"); you may not use this file except in compliance |
| * with the License. You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, |
| * software distributed under the License is distributed on an |
| * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY |
| * KIND, either express or implied. See the License for the |
| * specific language governing permissions and limitations |
| * under the License. |
| */ |
| /** |
| * @fileOverview |
| * instance controls from native |
| * |
| * - fire event |
| * - callback |
| * - refresh |
| * - destroy |
| * |
| * corresponded with the API of instance manager (framework.js) |
| */ |
| import { extend, typof } from '../../util/index' |
| |
| /** |
| * Refresh an app with data to its root component options. |
| * @param {object} app |
| * @param {any} data |
| */ |
| export function refresh (app, data) { |
| console.debug(`[JS Framework] Refresh with`, data, |
| `in instance[${app.id}]`) |
| const vm = app.vm |
| if (vm && data) { |
| if (typeof vm.refreshData === 'function') { |
| vm.refreshData(data) |
| } |
| else { |
| extend(vm, data) |
| } |
| app.differ.flush() |
| app.doc.taskCenter.send('dom', { action: 'refreshFinish' }, []) |
| return |
| } |
| return new Error(`invalid data "${data}"`) |
| } |
| |
| /** |
| * Destroy an app. |
| * @param {object} app |
| */ |
| export function destroy (app) { |
| console.debug(`[JS Framework] Destory an instance(${app.id})`) |
| |
| if (app.vm) { |
| destroyVm(app.vm) |
| } |
| |
| app.id = '' |
| app.options = null |
| app.blocks = null |
| app.vm = null |
| app.doc.taskCenter.destroyCallback() |
| app.doc.destroy() |
| app.doc = null |
| app.customComponentMap = null |
| app.commonModules = null |
| } |
| |
| /** |
| * Destroy an Vm. |
| * @param {object} vm |
| */ |
| export function destroyVm (vm) { |
| delete vm._app |
| delete vm._computed |
| delete vm._css |
| delete vm._data |
| delete vm._ids |
| delete vm._methods |
| delete vm._options |
| delete vm._parent |
| delete vm._parentEl |
| delete vm._rootEl |
| |
| // remove all watchers |
| if (vm._watchers) { |
| let watcherCount = vm._watchers.length |
| while (watcherCount--) { |
| vm._watchers[watcherCount].teardown() |
| } |
| delete vm._watchers |
| } |
| |
| // destroy child vms recursively |
| if (vm._childrenVms) { |
| let vmCount = vm._childrenVms.length |
| while (vmCount--) { |
| destroyVm(vm._childrenVms[vmCount]) |
| } |
| delete vm._childrenVms |
| } |
| |
| console.debug(`[JS Framework] "destroyed" lifecycle in Vm(${vm._type})`) |
| vm.$emit('hook:destroyed') |
| |
| delete vm._type |
| delete vm._vmEvents |
| } |
| |
| /** |
| * Get a JSON object to describe the document body. |
| * @param {object} app |
| * @return {object} |
| */ |
| export function getRootElement (app) { |
| const doc = app.doc || {} |
| const body = doc.body || {} |
| return body.toJSON ? body.toJSON() : {} |
| } |
| |
| /** |
| * Fire an event from renderer. The event has type, an event object and an |
| * element ref. If the event comes with some virtual-DOM changes, it should |
| * have one more parameter to describe the changes. |
| * @param {object} app |
| * @param {string} ref |
| * @param {type} type |
| * @param {object} e |
| * @param {object} domChanges |
| */ |
| export function fireEvent (app, ref, type, e, domChanges) { |
| console.debug(`[JS Framework] Fire a "${type}" event on an element(${ref}) in instance(${app.id})`) |
| if (Array.isArray(ref)) { |
| ref.some((ref) => { |
| return fireEvent(app, ref, type, e) !== false |
| }) |
| return |
| } |
| const el = app.doc.getRef(ref) |
| if (el) { |
| const result = app.doc.fireEvent(el, type, e, domChanges) |
| app.differ.flush() |
| app.doc.taskCenter.send('dom', { action: 'updateFinish' }, []) |
| return result |
| } |
| return new Error(`invalid element reference "${ref}"`) |
| } |
| |
| /** |
| * Make a callback for a certain app. |
| * @param {object} app |
| * @param {number} callbackId |
| * @param {any} data |
| * @param {boolean} ifKeepAlive |
| */ |
| export function callback (app, callbackId, data, ifKeepAlive) { |
| console.debug(`[JS Framework] Invoke a callback(${callbackId}) with`, data, |
| `in instance(${app.id})`) |
| const result = app.doc.taskCenter.callback(callbackId, data, ifKeepAlive) |
| updateActions(app) |
| app.doc.taskCenter.send('dom', { action: 'updateFinish' }, []) |
| return result |
| } |
| |
| /** |
| * Collect all virtual-DOM mutations together and send them to renderer. |
| * @param {object} app |
| */ |
| export function updateActions (app) { |
| app.differ.flush() |
| } |
| |
| /** |
| * Call all tasks from an app to renderer (native). |
| * @param {object} app |
| * @param {array} tasks |
| */ |
| export function callTasks (app, tasks) { |
| let result |
| |
| /* istanbul ignore next */ |
| if (typof(tasks) !== 'array') { |
| tasks = [tasks] |
| } |
| |
| tasks.forEach(task => { |
| result = app.doc.taskCenter.send( |
| 'module', |
| { |
| module: task.module, |
| method: task.method |
| }, |
| task.args |
| ) |
| }) |
| |
| return result |
| } |