فهرست منبع

delete repeat.js

Evan You 10 سال پیش
والد
کامیت
552d0cc3fa
1فایلهای تغییر یافته به همراه0 افزوده شده و 776 حذف شده
  1. 0 776
      src/directives/repeat.js

+ 0 - 776
src/directives/repeat.js

@@ -1,776 +0,0 @@
-var _ = require('../util')
-var config = require('../config')
-var isObject = _.isObject
-var isPlainObject = _.isPlainObject
-var textParser = require('../parsers/text')
-var expParser = require('../parsers/expression')
-var templateParser = require('../parsers/template')
-var compiler = require('../compiler')
-var uid = 0
-
-// async component resolution states
-var UNRESOLVED = 0
-var PENDING = 1
-var RESOLVED = 2
-var ABORTED = 3
-
-module.exports = {
-
-  /**
-   * Setup.
-   */
-
-  bind: function () {
-
-    // some helpful tips...
-    /* istanbul ignore if */
-    if (
-      process.env.NODE_ENV !== 'production' &&
-      this.el.tagName === 'OPTION' &&
-      this.el.parentNode && this.el.parentNode.__v_model
-    ) {
-      _.warn(
-        'Don\'t use v-repeat for v-model options; ' +
-        'use the `options` param instead: ' +
-        'http://vuejs.org/guide/forms.html#Dynamic_Select_Options'
-      )
-    }
-
-    if (process.env.NODE_ENV !== 'production') {
-      _.deprecation.REPEAT()
-    }
-
-    // support for item in array syntax
-    var inMatch = this.expression.match(/(.*) in (.*)/)
-    if (inMatch) {
-      this.arg = inMatch[1]
-      this._watcherExp = inMatch[2]
-    }
-    // uid as a cache identifier
-    this.id = '__v_repeat_' + (++uid)
-
-    // setup anchor nodes
-    this.start = _.createAnchor('v-repeat-start')
-    this.end = _.createAnchor('v-repeat-end')
-    _.replace(this.el, this.end)
-    _.before(this.start, this.end)
-
-    // check if this is a block repeat
-    this.template = _.isTemplate(this.el)
-      ? templateParser.parse(this.el, true)
-      : this.el
-
-    // check for trackby param
-    this.idKey = this.param('track-by')
-    // check for transition stagger
-    var stagger = +this.param('stagger')
-    this.enterStagger = +this.param('enter-stagger') || stagger
-    this.leaveStagger = +this.param('leave-stagger') || stagger
-
-    // check for v-ref/v-el
-    this.refId = this.param(config.prefix + 'ref')
-    this.elID = this.param(config.prefix + 'el')
-
-    if (process.env.NODE_ENV !== 'production') {
-      if (this.refId) _.deprecation.V_REF()
-      if (this.elID) _.deprecation.V_EL()
-    }
-    this.refId = this.refId || this.param('ref')
-
-    // check other directives that need to be handled
-    // at v-repeat level
-    this.checkIf()
-    this.checkComponent()
-
-    // create cache object
-    this.cache = Object.create(null)
-  },
-
-  /**
-   * Warn against v-if usage.
-   */
-
-  checkIf: function () {
-    if (_.attr(this.el, 'if') !== null) {
-      process.env.NODE_ENV !== 'production' && _.warn(
-        'Don\'t use v-if with v-repeat. ' +
-        'Use v-show or the "filterBy" filter instead.'
-      )
-    }
-  },
-
-  /**
-   * Check the component constructor to use for repeated
-   * instances. If static we resolve it now, otherwise it
-   * needs to be resolved at build time with actual data.
-   */
-
-  checkComponent: function () {
-    this.componentState = UNRESOLVED
-    var options = this.vm.$options
-    var id = _.checkComponent(this.el, options)
-    if (!id) {
-      // default constructor
-      this.Component = _.Vue
-      // inline repeats should inherit
-      this.inline = true
-      // important: transclude with no options, just
-      // to ensure block start and block end
-      this.template = compiler.transclude(this.template)
-      var copy = _.extend({}, options)
-      copy._asComponent = false
-      this._linkFn = compiler.compile(this.template, copy)
-    } else {
-      this.Component = null
-      this.asComponent = true
-      // check inline-template
-      if (this.param('inline-template') !== null) {
-        // extract inline template as a DocumentFragment
-        this.inlineTemplate = _.extractContent(this.el, true)
-      }
-      var tokens = textParser.parse(id)
-      if (tokens) {
-        // dynamic component to be resolved later
-        var componentExp = textParser.tokensToExp(tokens)
-        this.componentGetter = expParser.parse(componentExp).get
-      } else {
-        // static
-        this.componentId = id
-        this.pendingData = null
-      }
-    }
-  },
-
-  resolveComponent: function () {
-    this.componentState = PENDING
-    this.vm._resolveComponent(this.componentId, _.bind(function (Component) {
-      if (this.componentState === ABORTED) {
-        return
-      }
-      this.Component = Component
-      this.componentState = RESOLVED
-      this.realUpdate(this.pendingData)
-      this.pendingData = null
-    }, this))
-  },
-
-  /**
-   * Resolve a dynamic component to use for an instance.
-   * The tricky part here is that there could be dynamic
-   * components depending on instance data.
-   *
-   * @param {Object} data
-   * @param {Object} meta
-   * @return {Function}
-   */
-
-  resolveDynamicComponent: function (data, meta) {
-    // create a temporary context object and copy data
-    // and meta properties onto it.
-    // use _.define to avoid accidentally overwriting scope
-    // properties.
-    var context = Object.create(this.vm)
-    var key
-    for (key in data) {
-      _.define(context, key, data[key])
-    }
-    for (key in meta) {
-      _.define(context, key, meta[key])
-    }
-    var id = this.componentGetter.call(context, context)
-    var Component = _.resolveAsset(this.vm.$options, 'components', id)
-    if (process.env.NODE_ENV !== 'production') {
-      _.assertAsset(Component, 'component', id)
-    }
-    if (!Component.options) {
-      process.env.NODE_ENV !== 'production' && _.warn(
-        'Async resolution is not supported for v-repeat ' +
-        '+ dynamic component. (component: ' + id + ')'
-      )
-      return _.Vue
-    }
-    return Component
-  },
-
-  /**
-   * Update.
-   * This is called whenever the Array mutates. If we have
-   * a component, we might need to wait for it to resolve
-   * asynchronously.
-   *
-   * @param {Array|Number|String} data
-   */
-
-  update: function (data) {
-    if (this.componentId) {
-      var state = this.componentState
-      if (state === UNRESOLVED) {
-        this.pendingData = data
-        // once resolved, it will call realUpdate
-        this.resolveComponent()
-      } else if (state === PENDING) {
-        this.pendingData = data
-      } else if (state === RESOLVED) {
-        this.realUpdate(data)
-      }
-    } else {
-      this.realUpdate(data)
-    }
-  },
-
-  /**
-   * The real update that actually modifies the DOM.
-   *
-   * @param {Array|Number|String} data
-   */
-
-  realUpdate: function (data) {
-    this.vms = this.diff(data, this.vms)
-    // update v-ref
-    if (this.refId) {
-      this.vm.$[this.refId] = this.converted
-        ? toRefObject(this.vms)
-        : this.vms
-    }
-    if (this.elID) {
-      this.vm.$$[this.elID] = this.vms.map(function (vm) {
-        return vm.$el
-      })
-    }
-  },
-
-  /**
-   * Diff, based on new data and old data, determine the
-   * minimum amount of DOM manipulations needed to make the
-   * DOM reflect the new data Array.
-   *
-   * The algorithm diffs the new data Array by storing a
-   * hidden reference to an owner vm instance on previously
-   * seen data. This allows us to achieve O(n) which is
-   * better than a levenshtein distance based algorithm,
-   * which is O(m * n).
-   *
-   * @param {Array} data
-   * @param {Array} oldVms
-   * @return {Array}
-   */
-
-  diff: function (data, oldVms) {
-    var idKey = this.idKey
-    var converted = this.converted
-    var start = this.start
-    var end = this.end
-    var inDoc = _.inDoc(start)
-    var alias = this.arg
-    var init = !oldVms
-    var vms = new Array(data.length)
-    var obj, raw, vm, i, l, primitive
-    // First pass, go through the new Array and fill up
-    // the new vms array. If a piece of data has a cached
-    // instance for it, we reuse it. Otherwise build a new
-    // instance.
-    for (i = 0, l = data.length; i < l; i++) {
-      obj = data[i]
-      raw = converted ? obj.$value : obj
-      primitive = !isObject(raw)
-      vm = !init && this.getVm(raw, i, converted ? obj.$key : null)
-      if (vm) { // reusable instance
-
-        if (process.env.NODE_ENV !== 'production' && vm._reused) {
-          _.warn(
-            'Duplicate objects found in v-repeat="' + this.expression + '": ' +
-            JSON.stringify(raw)
-          )
-        }
-
-        vm._reused = true
-        vm.$index = i // update $index
-        // update data for track-by or object repeat,
-        // since in these two cases the data is replaced
-        // rather than mutated.
-        if (idKey || converted || primitive) {
-          if (alias) {
-            vm[alias] = raw
-          } else if (_.isPlainObject(raw)) {
-            vm.$data = raw
-          } else {
-            vm.$value = raw
-          }
-        }
-      } else { // new instance
-        vm = this.build(obj, i, true)
-        vm._reused = false
-      }
-      vms[i] = vm
-      // insert if this is first run
-      if (init) {
-        vm.$before(end)
-      }
-    }
-    // if this is the first run, we're done.
-    if (init) {
-      return vms
-    }
-    // Second pass, go through the old vm instances and
-    // destroy those who are not reused (and remove them
-    // from cache)
-    var removalIndex = 0
-    var totalRemoved = oldVms.length - vms.length
-    for (i = 0, l = oldVms.length; i < l; i++) {
-      vm = oldVms[i]
-      if (!vm._reused) {
-        this.uncacheVm(vm)
-        vm.$destroy(false, true) // defer cleanup until removal
-        this.remove(vm, removalIndex++, totalRemoved, inDoc)
-      }
-    }
-    // final pass, move/insert new instances into the
-    // right place.
-    var targetPrev, prevEl, currentPrev
-    var insertionIndex = 0
-    for (i = 0, l = vms.length; i < l; i++) {
-      vm = vms[i]
-      // this is the vm that we should be after
-      targetPrev = vms[i - 1]
-      prevEl = targetPrev
-        ? targetPrev._staggerCb
-          ? targetPrev._staggerAnchor
-          : targetPrev._fragmentEnd || targetPrev.$el
-        : start
-      if (vm._reused && !vm._staggerCb) {
-        currentPrev = findPrevVm(vm, start, this.id)
-        if (currentPrev !== targetPrev) {
-          this.move(vm, prevEl)
-        }
-      } else {
-        // new instance, or still in stagger.
-        // insert with updated stagger index.
-        this.insert(vm, insertionIndex++, prevEl, inDoc)
-      }
-      vm._reused = false
-    }
-    return vms
-  },
-
-  /**
-   * Build a new instance and cache it.
-   *
-   * @param {Object} data
-   * @param {Number} index
-   * @param {Boolean} needCache
-   */
-
-  build: function (data, index, needCache) {
-    var meta = { $index: index }
-    if (this.converted) {
-      meta.$key = data.$key
-    }
-    var raw = this.converted ? data.$value : data
-    var alias = this.arg
-    if (alias) {
-      data = {}
-      data[alias] = raw
-    } else if (!isPlainObject(raw)) {
-      // non-object values
-      data = {}
-      meta.$value = raw
-    } else {
-      // default
-      data = raw
-    }
-    // resolve constructor
-    var Component = this.Component || this.resolveDynamicComponent(data, meta)
-    var parent = this._host || this.vm
-    var vm = parent.$addChild({
-      el: templateParser.clone(this.template),
-      data: data,
-      inherit: this.inline,
-      template: this.inlineTemplate,
-      // repeater meta, e.g. $index, $key
-      _meta: meta,
-      // mark this as an inline-repeat instance
-      _repeat: this.inline,
-      // is this a component?
-      _asComponent: this.asComponent,
-      // linker cachable if no inline-template
-      _linkerCachable: !this.inlineTemplate && Component !== _.Vue,
-      // pre-compiled linker for simple repeats
-      _linkFn: this._linkFn,
-      // identifier, shows that this vm belongs to this collection
-      _repeatId: this.id,
-      // transclusion content owner
-      _context: this.vm,
-      // cotnext fragment
-      _frag: this._frag
-    }, Component)
-    // cache instance
-    if (needCache) {
-      this.cacheVm(raw, vm, index, this.converted ? meta.$key : null)
-    }
-    // sync back changes for two-way bindings of primitive values
-    var dir = this
-    if (this.rawType === 'object' && isPrimitive(raw)) {
-      vm.$watch(alias || '$value', function (val) {
-        if (dir.filters) {
-          process.env.NODE_ENV !== 'production' && _.warn(
-            'You seem to be mutating the $value reference of ' +
-            'a v-repeat instance (likely through v-model) ' +
-            'and filtering the v-repeat at the same time. ' +
-            'This will not work properly with an Array of ' +
-            'primitive values. Please use an Array of ' +
-            'Objects instead.'
-          )
-        }
-        dir._withLock(function () {
-          if (dir.converted) {
-            dir.rawValue[vm.$key] = val
-          } else {
-            dir.rawValue.$set(vm.$index, val)
-          }
-        })
-      })
-    }
-    return vm
-  },
-
-  /**
-   * Unbind, teardown everything
-   */
-
-  unbind: function () {
-    this.componentState = ABORTED
-    if (this.refId) {
-      this.vm.$[this.refId] = null
-    }
-    if (this.vms) {
-      var i = this.vms.length
-      var vm
-      while (i--) {
-        vm = this.vms[i]
-        this.uncacheVm(vm)
-        vm.$destroy()
-      }
-    }
-  },
-
-  /**
-   * Cache a vm instance based on its data.
-   *
-   * If the data is an object, we save the vm's reference on
-   * the data object as a hidden property. Otherwise we
-   * cache them in an object and for each primitive value
-   * there is an array in case there are duplicates.
-   *
-   * @param {Object} data
-   * @param {Vue} vm
-   * @param {Number} index
-   * @param {String} [key]
-   */
-
-  cacheVm: function (data, vm, index, key) {
-    var idKey = this.idKey
-    var cache = this.cache
-    var primitive = !isObject(data)
-    var id
-    if (key || idKey || primitive) {
-      id = idKey
-        ? idKey === '$index'
-          ? index
-          : data[idKey]
-        : (key || index)
-      if (!cache[id]) {
-        cache[id] = vm
-      } else if (!primitive && idKey !== '$index') {
-        process.env.NODE_ENV !== 'production' && _.warn(
-          'Duplicate objects with the same track-by key in v-repeat: ' + id
-        )
-      }
-    } else {
-      id = this.id
-      if (data.hasOwnProperty(id)) {
-        if (data[id] === null) {
-          data[id] = vm
-        } else {
-          process.env.NODE_ENV !== 'production' && _.warn(
-            'Duplicate objects found in v-repeat="' + this.expression + '": ' +
-            JSON.stringify(data)
-          )
-        }
-      } else {
-        _.define(data, id, vm)
-      }
-    }
-    vm._raw = data
-  },
-
-  /**
-   * Try to get a cached instance from a piece of data.
-   *
-   * @param {Object} data
-   * @param {Number} index
-   * @param {String} [key]
-   * @return {Vue|undefined}
-   */
-
-  getVm: function (data, index, key) {
-    var idKey = this.idKey
-    var primitive = !isObject(data)
-    if (key || idKey || primitive) {
-      var id = idKey
-        ? idKey === '$index'
-          ? index
-          : data[idKey]
-        : (key || index)
-      return this.cache[id]
-    } else {
-      return data[this.id]
-    }
-  },
-
-  /**
-   * Delete a cached vm instance.
-   *
-   * @param {Vue} vm
-   */
-
-  uncacheVm: function (vm) {
-    var data = vm._raw
-    var idKey = this.idKey
-    var index = vm.$index
-    // fix #948: avoid accidentally fall through to
-    // a parent repeater which happens to have $key.
-    var key = vm.hasOwnProperty('$key') && vm.$key
-    var primitive = !isObject(data)
-    if (idKey || key || primitive) {
-      var id = idKey
-        ? idKey === '$index'
-          ? index
-          : data[idKey]
-        : (key || index)
-      this.cache[id] = null
-    } else {
-      data[this.id] = null
-      vm._raw = null
-    }
-  },
-
-  /**
-   * Insert an instance.
-   *
-   * @param {Vue} vm
-   * @param {Number} index
-   * @param {Node} prevEl
-   * @param {Boolean} inDoc
-   */
-
-  insert: function (vm, index, prevEl, inDoc) {
-    if (vm._staggerCb) {
-      vm._staggerCb.cancel()
-      vm._staggerCb = null
-    }
-    var staggerAmount = this.getStagger(vm, index, null, 'enter')
-    if (inDoc && staggerAmount) {
-      // create an anchor and insert it synchronously,
-      // so that we can resolve the correct order without
-      // worrying about some elements not inserted yet
-      var anchor = vm._staggerAnchor
-      if (!anchor) {
-        anchor = vm._staggerAnchor = _.createAnchor('stagger-anchor')
-        anchor.__vue__ = vm
-      }
-      _.after(anchor, prevEl)
-      var op = vm._staggerCb = _.cancellable(function () {
-        vm._staggerCb = null
-        vm.$before(anchor)
-        _.remove(anchor)
-      })
-      setTimeout(op, staggerAmount)
-    } else {
-      vm.$after(prevEl)
-    }
-  },
-
-  /**
-   * Move an already inserted instance.
-   *
-   * @param {Vue} vm
-   * @param {Node} prevEl
-   */
-
-  move: function (vm, prevEl) {
-    vm.$after(prevEl, null, false)
-  },
-
-  /**
-   * Remove an instance.
-   *
-   * @param {Vue} vm
-   * @param {Number} index
-   * @param {Boolean} inDoc
-   */
-
-  remove: function (vm, index, total, inDoc) {
-    if (vm._staggerCb) {
-      vm._staggerCb.cancel()
-      vm._staggerCb = null
-      // it's not possible for the same vm to be removed
-      // twice, so if we have a pending stagger callback,
-      // it means this vm is queued for enter but removed
-      // before its transition started. Since it is already
-      // destroyed, we can just leave it in detached state.
-      return
-    }
-    var staggerAmount = this.getStagger(vm, index, total, 'leave')
-    if (inDoc && staggerAmount) {
-      var op = vm._staggerCb = _.cancellable(function () {
-        vm._staggerCb = null
-        remove()
-      })
-      setTimeout(op, staggerAmount)
-    } else {
-      remove()
-    }
-    function remove () {
-      vm.$remove(function () {
-        vm._cleanup()
-      })
-    }
-  },
-
-  /**
-   * Get the stagger amount for an insertion/removal.
-   *
-   * @param {Vue} vm
-   * @param {Number} index
-   * @param {String} type
-   * @param {Number} total
-   */
-
-  getStagger: function (vm, index, total, type) {
-    type = type + 'Stagger'
-    var trans = vm.$el.__v_trans
-    var hooks = trans && trans.hooks
-    var hook = hooks && (hooks[type] || hooks.stagger)
-    return hook
-      ? hook.call(vm, index, total)
-      : index * this[type]
-  },
-
-  /**
-   * Pre-process the value before piping it through the
-   * filters, and convert non-Array objects to arrays.
-   *
-   * This function will be bound to this directive instance
-   * and passed into the watcher.
-   *
-   * @param {*} value
-   * @return {Array}
-   * @private
-   */
-
-  _preProcess: function (value) {
-    // regardless of type, store the un-filtered raw value.
-    this.rawValue = value
-    var type = this.rawType = typeof value
-    if (!isPlainObject(value)) {
-      this.converted = false
-      if (type === 'number') {
-        value = range(value)
-      } else if (type === 'string') {
-        value = _.toArray(value)
-      }
-      return value || []
-    } else {
-      // convert plain object to array.
-      var keys = Object.keys(value)
-      var i = keys.length
-      var res = new Array(i)
-      var key
-      while (i--) {
-        key = keys[i]
-        res[i] = {
-          $key: key,
-          $value: value[key]
-        }
-      }
-      this.converted = true
-      return res
-    }
-  }
-}
-
-/**
- * Helper to find the previous element that is an instance
- * root node. This is necessary because a destroyed vm's
- * element could still be lingering in the DOM before its
- * leaving transition finishes, but its __vue__ reference
- * should have been removed so we can skip them.
- *
- * If this is a block repeat, we want to make sure we only
- * return vm that is bound to this v-repeat. (see #929)
- *
- * @param {Vue} vm
- * @param {Comment|Text} anchor
- * @return {Vue}
- */
-
-function findPrevVm (vm, anchor, id) {
-  var el = vm.$el.previousSibling
-  /* istanbul ignore if */
-  if (!el) return
-  while (
-    (!el.__vue__ || el.__vue__.$options._repeatId !== id) &&
-    el !== anchor
-  ) {
-    el = el.previousSibling
-  }
-  return el.__vue__
-}
-
-/**
- * Create a range array from given number.
- *
- * @param {Number} n
- * @return {Array}
- */
-
-function range (n) {
-  var i = -1
-  var ret = new Array(n)
-  while (++i < n) {
-    ret[i] = i
-  }
-  return ret
-}
-
-/**
- * Convert a vms array to an object ref for v-ref on an
- * Object value.
- *
- * @param {Array} vms
- * @return {Object}
- */
-
-function toRefObject (vms) {
-  var ref = {}
-  for (var i = 0, l = vms.length; i < l; i++) {
-    ref[vms[i].$key] = vms[i]
-  }
-  return ref
-}
-
-/**
- * Check if a value is a primitive one:
- * String, Number, Boolean, null or undefined.
- *
- * @param {*} value
- * @return {Boolean}
- */
-
-function isPrimitive (value) {
-  var type = typeof value
-  return value == null ||
-    type === 'string' ||
-    type === 'number' ||
-    type === 'boolean'
-}