/* @flow */ 
 | 
  
 | 
// https://github.com/Hanks10100/weex-native-directive/tree/master/component 
 | 
  
 | 
import { mergeOptions, isPlainObject, noop } from 'core/util/index' 
 | 
import Watcher from 'core/observer/watcher' 
 | 
import { initProxy } from 'core/instance/proxy' 
 | 
import { initState, getData } from 'core/instance/state' 
 | 
import { initRender } from 'core/instance/render' 
 | 
import { initEvents } from 'core/instance/events' 
 | 
import { initProvide, initInjections } from 'core/instance/inject' 
 | 
import { initLifecycle, callHook } from 'core/instance/lifecycle' 
 | 
import { initInternalComponent, resolveConstructorOptions } from 'core/instance/init' 
 | 
import { registerComponentHook, updateComponentData } from '../../util/index' 
 | 
  
 | 
let uid = 0 
 | 
  
 | 
// override Vue.prototype._init 
 | 
function initVirtualComponent (options: Object = {}) { 
 | 
  const vm: Component = this 
 | 
  const componentId = options.componentId 
 | 
  
 | 
  // virtual component uid 
 | 
  vm._uid = `virtual-component-${uid++}` 
 | 
  
 | 
  // a flag to avoid this being observed 
 | 
  vm._isVue = true 
 | 
  // merge options 
 | 
  if (options && options._isComponent) { 
 | 
    // optimize internal component instantiation 
 | 
    // since dynamic options merging is pretty slow, and none of the 
 | 
    // internal component options needs special treatment. 
 | 
    initInternalComponent(vm, options) 
 | 
  } else { 
 | 
    vm.$options = mergeOptions( 
 | 
      resolveConstructorOptions(vm.constructor), 
 | 
      options || {}, 
 | 
      vm 
 | 
    ) 
 | 
  } 
 | 
  
 | 
  /* istanbul ignore else */ 
 | 
  if (process.env.NODE_ENV !== 'production') { 
 | 
    initProxy(vm) 
 | 
  } else { 
 | 
    vm._renderProxy = vm 
 | 
  } 
 | 
  
 | 
  vm._self = vm 
 | 
  initLifecycle(vm) 
 | 
  initEvents(vm) 
 | 
  initRender(vm) 
 | 
  callHook(vm, 'beforeCreate') 
 | 
  initInjections(vm) // resolve injections before data/props 
 | 
  initState(vm) 
 | 
  initProvide(vm) // resolve provide after data/props 
 | 
  callHook(vm, 'created') 
 | 
  
 | 
  // send initial data to native 
 | 
  const data = vm.$options.data 
 | 
  const params = typeof data === 'function' 
 | 
    ? getData(data, vm) 
 | 
    : data || {} 
 | 
  if (isPlainObject(params)) { 
 | 
    updateComponentData(componentId, params) 
 | 
  } 
 | 
  
 | 
  registerComponentHook(componentId, 'lifecycle', 'attach', () => { 
 | 
    callHook(vm, 'beforeMount') 
 | 
  
 | 
    const updateComponent = () => { 
 | 
      vm._update(vm._vnode, false) 
 | 
    } 
 | 
    new Watcher(vm, updateComponent, noop, null, true) 
 | 
  
 | 
    vm._isMounted = true 
 | 
    callHook(vm, 'mounted') 
 | 
  }) 
 | 
  
 | 
  registerComponentHook(componentId, 'lifecycle', 'detach', () => { 
 | 
    vm.$destroy() 
 | 
  }) 
 | 
} 
 | 
  
 | 
// override Vue.prototype._update 
 | 
function updateVirtualComponent (vnode?: VNode) { 
 | 
  const vm: Component = this 
 | 
  const componentId = vm.$options.componentId 
 | 
  if (vm._isMounted) { 
 | 
    callHook(vm, 'beforeUpdate') 
 | 
  } 
 | 
  vm._vnode = vnode 
 | 
  if (vm._isMounted && componentId) { 
 | 
    // TODO: data should be filtered and without bindings 
 | 
    const data = Object.assign({}, vm._data) 
 | 
    updateComponentData(componentId, data, () => { 
 | 
      callHook(vm, 'updated') 
 | 
    }) 
 | 
  } 
 | 
} 
 | 
  
 | 
// listening on native callback 
 | 
export function resolveVirtualComponent (vnode: MountedComponentVNode): VNode { 
 | 
  const BaseCtor = vnode.componentOptions.Ctor 
 | 
  const VirtualComponent = BaseCtor.extend({}) 
 | 
  const cid = VirtualComponent.cid 
 | 
  VirtualComponent.prototype._init = initVirtualComponent 
 | 
  VirtualComponent.prototype._update = updateVirtualComponent 
 | 
  
 | 
  vnode.componentOptions.Ctor = BaseCtor.extend({ 
 | 
    beforeCreate () { 
 | 
      // const vm: Component = this 
 | 
  
 | 
      // TODO: listen on all events and dispatch them to the 
 | 
      // corresponding virtual components according to the componentId. 
 | 
      // vm._virtualComponents = {} 
 | 
      const createVirtualComponent = (componentId, propsData) => { 
 | 
        // create virtual component 
 | 
        // const subVm = 
 | 
        new VirtualComponent({ 
 | 
          componentId, 
 | 
          propsData 
 | 
        }) 
 | 
        // if (vm._virtualComponents) { 
 | 
        //   vm._virtualComponents[componentId] = subVm 
 | 
        // } 
 | 
      } 
 | 
  
 | 
      registerComponentHook(cid, 'lifecycle', 'create', createVirtualComponent) 
 | 
    }, 
 | 
    beforeDestroy () { 
 | 
      delete this._virtualComponents 
 | 
    } 
 | 
  }) 
 | 
} 
 |