Parcourir la source

refactor util

Evan You il y a 11 ans
Parent
commit
0813e461b7
8 fichiers modifiés avec 448 ajouts et 336 suppressions
  1. 17 8
      src/api/global.js
  2. 1 15
      src/config.js
  3. 19 49
      src/instance/init.js
  4. 0 264
      src/util.js
  5. 67 0
      src/util/dom.js
  6. 87 0
      src/util/env.js
  7. 136 0
      src/util/index.js
  8. 121 0
      src/util/lang.js

+ 17 - 8
src/api/global.js

@@ -1,5 +1,11 @@
 var _ = require('../util')
-var config = require('../config')
+var assetTypes = [
+  'directive',
+  'filter',
+  'partial',
+  'effect',
+  'component'
+]
 
 /**
  * Vue and every constructor that extends Vue has an associated
@@ -19,9 +25,9 @@ exports.options = {
  * Expose useful internals
  */
 
-exports.util = _
-exports.config = config
-exports.nextTick = _.nextTick
+exports.util       = _
+exports.nextTick   = _.nextTick
+exports.config     = require('../config')
 exports.transition = require('../transition/transition')
 
 /**
@@ -33,12 +39,15 @@ exports.transition = require('../transition/transition')
 exports.extend = function (extendOptions) {
   var Super = this
   var Sub = function (instanceOptions) {
-    var mergedOptions = _.mergeOptions(Sub.options, instanceOptions)
-    Super.call(this, mergedOptions)
+    Super.call(this, instanceOptions)
   }
   Sub.prototype = Object.create(Super.prototype)
   _.define(Sub.prototype, 'constructor', Sub)
-  Sub.options = _.mergeOptions(Super.options, extendOptions)
+  Sub.options = _.mergeOptions(
+    Super.options,
+    extendOptions,
+    true // indicates an inheritance merge
+  )
   Sub.super = Super
   // allow further extension
   Sub.extend = Super.extend
@@ -80,7 +89,7 @@ exports.use = function (plugin) {
 
 createAssetRegisters(exports)
 function createAssetRegisters (Ctor) {
-  config._assetTypes.forEach(function (type) {
+  assetTypes.forEach(function (type) {
 
     /**
      * Asset registration method.

+ 1 - 15
src/config.js

@@ -27,20 +27,6 @@ module.exports = {
    * @type {Boolean}
    */
 
-  interpolate: true,
-
-  /**
-   * Asset types
-   * @type {Array.<String>}
-   * @readonly
-   */
-
-  _assetTypes: [
-    'directive',
-    'filter',
-    'partial',
-    'effect',
-    'component'
-  ]
+  interpolate: true
 
 }

+ 19 - 49
src/instance/init.js

@@ -1,3 +1,5 @@
+var _ = require('../util')
+
 /**
  * The main init sequence. This is called for every instance,
  * including ones that are created from extended constructors.
@@ -9,67 +11,35 @@
  */
 
 exports._init = function (options) {
-
-  /**
-   * Expose instance options.
-   * @type {Object}
-   *
-   * @public
-   */
-
-  this.$options = options || {}
-
-  /**
-   * Indicates whether this is a block instance. (One with more
-   * than one top-level nodes)
-   *
-   * @type {Boolean}
-   * @private
-   */
-
-  this._isBlock = false
-
-  /**
-   * Indicates whether the instance has been mounted to a DOM node.
-   *
-   * @type {Boolean}
-   * @private
-   */
-
-  this._isMounted = false
-
-  /**
-   * Indicates whether the instance has been destroyed.
-   *
-   * @type {Boolean}
-   * @private
-   */
-
-  this._isDestroyed = false
-
-  /**
-   * If the instance has a template option, the raw content it holds
-   * before compilation will be preserved so they can be queried against
-   * during content insertion.
-   *
-   * @type {DocumentFragment}
-   * @private
-   */
-
-  this._rawContent = null
+  // merge options.
+  this.$options = _.mergeOptions(
+    this.constructor.options,
+    options
+  )
 
   // create scope.
+  // @creates this.$parent
+  // @creates this.$scope
   this._initScope()
 
   // setup initial data.
+  // @creates this._data
   this._initData(this.$options.data || {}, true)
 
   // setup property proxying
   this._initProxy()
 
   // setup binding tree.
+  // @creates this._rootBinding
   this._initBindings()
-  
+
+  // compilation and lifecycle related state properties
+  this.$el = null
+  this._rawContent = null
+  this._isBlock = false
+  this._isMounted = false
+  this._isDestroyed = false 
+
   // if `el` option is passed, start compilation.
   if (this.$options.el) {
     this.$mount(this.$options.el)

+ 0 - 264
src/util.js

@@ -1,264 +0,0 @@
-var config = require('./config')
-
-/**
- * Defer a task to the start of the next event loop
- *
- * @param {Function} fn
- */
-
-var defer = typeof window === 'undefined'
-  ? setTimeout
-  : (window.requestAnimationFrame ||
-    window.webkitRequestAnimationFrame ||
-    setTimeout)
-
-exports.nextTick = function (fn) {
-  return defer(fn, 0)
-}
-
-/**
- * Convert an Array-like object to a real Array.
- *
- * @param {Array-like} list
- * @param {Number} [i] - start index
- */
-
-var slice = [].slice
-
-exports.toArray = function (list, i) {
-  return slice.call(list, i || 0)
-}
-
-/**
- * Mix properties into target object.
- *
- * @param {Object} to
- * @param {Object} from
- */
-
-exports.mixin = function (to, from) {
-  for (var key in from) {
-    if (to[key] !== from[key]) {
-      to[key] = from[key]
-    }
-  }
-}
-
-/**
- * Mixin including non-enumerables, and copy property descriptors.
- *
- * @param {Object} to
- * @param {Object} from
- */
-
-exports.deepMixin = function (to, from) {
-  Object.getOwnPropertyNames(from).forEach(function (key) {
-    var descriptor = Object.getOwnPropertyDescriptor(from, key)
-    Object.defineProperty(to, key, descriptor)
-  })
-}
-
-/**
- * Proxy a property on one object to another.
- *
- * @param {Object} to
- * @param {Object} from
- * @param {String} key
- */
-
-exports.proxy = function (to, from, key) {
-  if (to.hasOwnProperty(key)) return
-  Object.defineProperty(to, key, {
-    enumerable: true,
-    configurable: true,
-    get: function () {
-      return from[key]
-    },
-    set: function (val) {
-      from[key] = val
-    }
-  })
-}
-
-/**
- * Object type check. Only returns true
- * for plain JavaScript objects.
- *
- * @param {*} obj
- * @return {Boolean}
- */
-
-exports.isObject = function (obj) {
-  return Object.prototype.toString.call(obj) === '[object Object]'
-}
-
-/**
- * Array type check.
- *
- * @param {*} obj
- * @return {Boolean}
- */
-
-exports.isArray = function (obj) {
-  return Array.isArray(obj)
-}
-
-/**
- * Define a non-enumerable property
- *
- * @param {Object} obj
- * @param {String} key
- * @param {*} val
- * @param {Boolean} [enumerable]
- */
-
-exports.define = function (obj, key, val, enumerable) {
-  Object.defineProperty(obj, key, {
-    value        : val,
-    enumerable   : !!enumerable,
-    writable     : true,
-    configurable : true
-  })
-}
-
-/**
- * Augment an target Object or Array by either
- * intercepting the prototype chain using __proto__,
- * or copy over property descriptors
- *
- * @param {Object|Array} target
- * @param {Object} proto
- */
-
-if ('__proto__' in {}) {
-  exports.augment = function (target, proto) {
-    target.__proto__ = proto
-  }
-} else {
-  exports.augment = exports.deepMixin
-}
-
-/**
- * Merge two option objects.
- *
- * @param {Object} parent
- * @param {Object} child
- * @param {Boolean} noRecurse
- */
-
-exports.mergeOptions = function (parent, child, noRecurse) {
-  // TODO
-  // - merge lifecycle hooks
-  // - merge asset registries
-  // - else override
-  // - use prototypal inheritance where appropriate
-}
-
-/**
- * Insert el before target
- *
- * @param {Element} el
- * @param {Element} target 
- */
-
-exports.before = function (el, target) {
-  target.parentNode.insertBefore(el, target)
-}
-
-/**
- * Insert el after target
- *
- * @param {Element} el
- * @param {Element} target 
- */
-
-exports.after = function (el, target) {
-  if (target.nextSibling) {
-    exports.before(el, target.nextSibling)
-  } else {
-    target.parentNode.appendChild(el)
-  }
-}
-
-/**
- * Remove el from DOM
- *
- * @param {Element} el
- */
-
-exports.remove = function (el) {
-  el.parentNode.removeChild(el)
-}
-
-/**
- * Prepend el to target
- *
- * @param {Element} el
- * @param {Element} target 
- */
-
-exports.prepend = function (el, target) {
-  if (target.firstChild) {
-    exports.before(el, target.firstChild)
-  } else {
-    target.appendChild(el)
-  }
-}
-
-/**
- * Copy attributes from one element to another.
- *
- * @param {Element} from
- * @param {Element} to
- */
-
-exports.copyAttributes = function (from, to) {
-  if (from.hasAttributes()) {
-    var attrs = from.attributes
-    for (var i = 0, l = attrs.length; i < l; i++) {
-      var attr = attrs[i]
-      to.setAttribute(attr.name, attr.value)
-    }
-  }
-}
-
-/**
- * Enable debug utilities. The enableDebug() function and all
- * _.log() & _.warn() calls will be dropped in the minified
- * production build.
- */
-
-enableDebug()
-
-function enableDebug () {
-
-  var hasConsole = typeof console !== 'undefined'
-  
-  /**
-   * Log a message.
-   *
-   * @param {String} msg
-   */
-
-  exports.log = function (msg) {
-    if (hasConsole && config.debug) {
-      console.log(msg)
-    }
-  }
-
-  /**
-   * We've got a problem here.
-   *
-   * @param {String} msg
-   */
-
-  exports.warn = function (msg) {
-    if (hasConsole && !config.silent) {
-      console.warn(msg)
-      if (config.debug && console.trace) {
-        console.trace(msg)
-      }
-    }
-  }
-
-}

+ 67 - 0
src/util/dom.js

@@ -0,0 +1,67 @@
+/**
+ * Insert el before target
+ *
+ * @param {Element} el
+ * @param {Element} target 
+ */
+
+exports.before = function (el, target) {
+  target.parentNode.insertBefore(el, target)
+}
+
+/**
+ * Insert el after target
+ *
+ * @param {Element} el
+ * @param {Element} target 
+ */
+
+exports.after = function (el, target) {
+  if (target.nextSibling) {
+    exports.before(el, target.nextSibling)
+  } else {
+    target.parentNode.appendChild(el)
+  }
+}
+
+/**
+ * Remove el from DOM
+ *
+ * @param {Element} el
+ */
+
+exports.remove = function (el) {
+  el.parentNode.removeChild(el)
+}
+
+/**
+ * Prepend el to target
+ *
+ * @param {Element} el
+ * @param {Element} target 
+ */
+
+exports.prepend = function (el, target) {
+  if (target.firstChild) {
+    exports.before(el, target.firstChild)
+  } else {
+    target.appendChild(el)
+  }
+}
+
+/**
+ * Copy attributes from one element to another.
+ *
+ * @param {Element} from
+ * @param {Element} to
+ */
+
+exports.copyAttributes = function (from, to) {
+  if (from.hasAttributes()) {
+    var attrs = from.attributes
+    for (var i = 0, l = attrs.length; i < l; i++) {
+      var attr = attrs[i]
+      to.setAttribute(attr.name, attr.value)
+    }
+  }
+}

+ 87 - 0
src/util/env.js

@@ -0,0 +1,87 @@
+/**
+ * Are we in a browser or in Node?
+ *
+ * @type {Boolean}
+ */
+
+var inBrowser = exports.inBrowser =
+  typeof window !== 'undefined' &&
+  Object.prototype.toString.call(window) === '[object global]'
+
+/**
+ * Defer a task to the start of the next event loop
+ *
+ * @param {Function} fn
+ */
+
+var defer = inBrowser
+  ? (window.requestAnimationFrame ||
+    window.webkitRequestAnimationFrame ||
+    setTimeout)
+  : setTimeout
+
+exports.nextTick = function (fn) {
+  return defer(fn, 0)
+}
+
+/**
+ * Detect if the environment allows creating
+ * a function from strings.
+ *
+ * @type {Boolean}
+ */
+
+exports.hasEval = (function () {
+  // chrome apps enforces CSP
+  if (typeof chrome !== 'undefined' &&
+      chrome.app &&
+      chrome.app.runtime) {
+    return false
+  }
+  try {
+    var f = new Function('', 'return true;')
+    return f()
+  } catch (e) {
+    return false
+  }
+})()
+
+/**
+ * Detect if we are in IE9...
+ *
+ * @type {Boolean}
+ */
+
+exports.isIE9 =
+  inBrowser &&
+  navigator.userAgent.indexOf('MSIE 9.0') > 0
+
+/**
+ * Detect transition and animation end events.
+ */
+
+var testElement = inBrowser
+  ? document.createElement('div')
+  : null
+
+exports.transitionEndEvent = (function () {
+  if (!inBrowser) {
+    return null
+  }
+  var map = {
+    'webkitTransition' : 'webkitTransitionEnd',
+    'transition'       : 'transitionend',
+    'mozTransition'    : 'transitionend'
+  }
+  for (var prop in map) {
+    if (testElement.style[prop] !== undefined) {
+      return map[prop]
+    }
+  }
+})()
+
+exports.animationEndEvent = inBrowser
+  ? testElement.style.animation !== undefined
+    ? 'animationend'
+    : 'webkitAnimationEnd'
+  : null

+ 136 - 0
src/util/index.js

@@ -0,0 +1,136 @@
+var _ = exports
+var env = require('./env')
+var lang = require('./lang')
+var dom = require('./dom')
+
+var mixin = lang.mixin
+
+mixin(_, env)
+mixin(_, lang)
+mixin(_, dom)
+
+/**
+ * Option overwriting strategies are functions that handle
+ * how to merge a parent option value and a child option
+ * value into the final value.
+ */
+
+var strats = {}
+
+/**
+ * Hooks and param attributes are merged as arrays.
+ */
+
+strats.created =
+strats.ready =
+strats.attached =
+strats.detached =
+strats.beforeDestroy =
+strats.afterDestroy =
+strats.paramAttributes = function (parentVal, childVal) {
+  return (parentVal || []).concat(childVal || [])
+}
+
+/**
+ * Assets, methods and computed properties are hash objects,
+ * and are merged with prototypal inheritance.
+ */
+
+strats.directives =
+strats.filters =
+strats.partials =
+strats.effects =
+strats.components = 
+strats.methods =
+strats.computed = function (parentVal, childVal) {
+  var ret = Object.create(parentVal || null)
+  for (var key in childVal) {
+    ret[key] = childVal[key]
+  }
+  return ret
+}
+
+/**
+ * Default strategy - overwrite if child value is not undefined.
+ */
+
+var defaultStrat = function (parentVal, childVal) {
+  return childVal === undefined
+    ? parentVal
+    : childVal
+}
+
+/**
+ * Merge two option objects into a new one.
+ * Core utility used in both instantiation and inheritance.
+ *
+ * @param {Object} parent
+ * @param {Object} child
+ * @param {Boolean} inheriting
+ */
+
+exports.mergeOptions = function (parent, child, inheriting) {
+  var options = {}
+  var key
+  for (key in parent) {
+    merge(key)
+  }
+  for (key in child) {
+    if (!(key in parent)) {
+      merge(key)
+    }
+  }
+  function merge (key) {
+    if (inheriting && (key === 'el' || key === 'data')) {
+      _.warn(
+        'The "' + key + '" option can only be used as an instantiation ' +
+        'option and will be ignored in Vue.extend().'
+      )
+      return
+    }
+    var strat = strats[key] || defaultStrat
+    options[key] = strat(parent[key], child[key])
+  }
+  return options
+}
+
+/**
+ * Enable debug utilities. The enableDebug() function and all
+ * _.log() & _.warn() calls will be dropped in the minified
+ * production build.
+ */
+
+enableDebug()
+
+function enableDebug () {
+
+  var hasConsole = typeof console !== 'undefined'
+  
+  /**
+   * Log a message.
+   *
+   * @param {String} msg
+   */
+
+  exports.log = function (msg) {
+    if (hasConsole && config.debug) {
+      console.log(msg)
+    }
+  }
+
+  /**
+   * We've got a problem here.
+   *
+   * @param {String} msg
+   */
+
+  exports.warn = function (msg) {
+    if (hasConsole && !config.silent) {
+      console.warn(msg)
+      if (config.debug && console.trace) {
+        console.trace(msg)
+      }
+    }
+  }
+
+}

+ 121 - 0
src/util/lang.js

@@ -0,0 +1,121 @@
+/**
+ * Convert an Array-like object to a real Array.
+ *
+ * @param {Array-like} list
+ * @param {Number} [i] - start index
+ */
+
+var slice = [].slice
+
+exports.toArray = function (list, i) {
+  return slice.call(list, i || 0)
+}
+
+/**
+ * Mix properties into target object.
+ *
+ * @param {Object} to
+ * @param {Object} from
+ */
+
+exports.mixin = function (to, from) {
+  for (var key in from) {
+    if (to[key] !== from[key]) {
+      to[key] = from[key]
+    }
+  }
+}
+
+/**
+ * Mixin including non-enumerables, and copy property descriptors.
+ *
+ * @param {Object} to
+ * @param {Object} from
+ */
+
+exports.deepMixin = function (to, from) {
+  Object.getOwnPropertyNames(from).forEach(function (key) {
+    var descriptor = Object.getOwnPropertyDescriptor(from, key)
+    Object.defineProperty(to, key, descriptor)
+  })
+}
+
+/**
+ * Proxy a property on one object to another.
+ *
+ * @param {Object} to
+ * @param {Object} from
+ * @param {String} key
+ */
+
+exports.proxy = function (to, from, key) {
+  if (to.hasOwnProperty(key)) return
+  Object.defineProperty(to, key, {
+    enumerable: true,
+    configurable: true,
+    get: function () {
+      return from[key]
+    },
+    set: function (val) {
+      from[key] = val
+    }
+  })
+}
+
+/**
+ * Object type check. Only returns true
+ * for plain JavaScript objects.
+ *
+ * @param {*} obj
+ * @return {Boolean}
+ */
+
+exports.isObject = function (obj) {
+  return Object.prototype.toString.call(obj) === '[object Object]'
+}
+
+/**
+ * Array type check.
+ *
+ * @param {*} obj
+ * @return {Boolean}
+ */
+
+exports.isArray = function (obj) {
+  return Array.isArray(obj)
+}
+
+/**
+ * Define a non-enumerable property
+ *
+ * @param {Object} obj
+ * @param {String} key
+ * @param {*} val
+ * @param {Boolean} [enumerable]
+ */
+
+exports.define = function (obj, key, val, enumerable) {
+  Object.defineProperty(obj, key, {
+    value        : val,
+    enumerable   : !!enumerable,
+    writable     : true,
+    configurable : true
+  })
+}
+
+/**
+ * Augment an target Object or Array by either
+ * intercepting the prototype chain using __proto__,
+ * or copy over property descriptors
+ *
+ * @param {Object|Array} target
+ * @param {Object} proto
+ */
+
+if ('__proto__' in {}) {
+  exports.augment = function (target, proto) {
+    target.__proto__ = proto
+  }
+} else {
+  exports.augment = exports.deepMixin
+}