Forráskód Böngészése

v-model for text/number

Evan You 11 éve
szülő
commit
2a9e6550b0

+ 5 - 1
component.json

@@ -29,7 +29,11 @@
     "src/directives/html.js",
     "src/directives/if.js",
     "src/directives/index.js",
-    "src/directives/model.js",
+    "src/directives/model/checkbox.js",
+    "src/directives/model/index.js",
+    "src/directives/model/radio.js",
+    "src/directives/model/select.js",
+    "src/directives/model/text.js",
     "src/directives/on.js",
     "src/directives/partial.js",
     "src/directives/ref.js",

+ 12 - 4
src/api/global.js

@@ -91,7 +91,11 @@ function createAssetRegisters (Constructor) {
 
   assetTypes.forEach(function (type) {
     Constructor[type] = function (id, definition) {
-      this.options[type + 's'][id] = definition
+      if (!definition) {
+        return this.options[type + 's'][id]
+      } else {
+        this.options[type + 's'][id] = definition
+      }
     }
   })
 
@@ -104,10 +108,14 @@ function createAssetRegisters (Constructor) {
    */
 
   Constructor.component = function (id, definition) {
-    if (_.isPlainObject(definition)) {
-      definition = _.Vue.extend(definition)
+    if (!definition) {
+      return this.options.components[id]
+    } else {
+      if (_.isPlainObject(definition)) {
+        definition = _.Vue.extend(definition)
+      }
+      this.options.components[id] = definition
     }
-    this.options.components[id] = definition
   }
 }
 

+ 0 - 17
src/directives/model.js

@@ -1,17 +0,0 @@
-module.exports = {
-
-  priority: 800,
-
-  bind: function () {
-    
-  },
-
-  update: function () {
-    
-  },
-
-  unbind: function () {
-    
-  }
-
-}

+ 0 - 0
src/directives/model/checkbox.js


+ 46 - 0
src/directives/model/index.js

@@ -0,0 +1,46 @@
+var _ = require('../../util')
+
+var handlers = {
+  text: require('./text'),
+  radio: require('./radio'),
+  select: require('./select'),
+  checkbox: require('./checkbox')
+}
+
+module.exports = {
+
+  priority: 800,
+  twoWay: true,
+  handlers: handlers,
+
+  /**
+   * Possible elements:
+   *   <select>
+   *   <textarea>
+   *   <input type="*">
+   *     - text
+   *     - checkbox
+   *     - radio
+   *     - number
+   *     - TODO: more types may be supplied as a plugin
+   */
+
+  bind: function () {
+    var el = this.el
+    var tag = el.tagName
+    if (tag === 'INPUT') {
+      handler = handlers[el.type] || handlers.text
+    } else if (tag === 'SELECT') {
+      handler = handlers.select
+    } else if (tag === 'TEXTAREA') {
+      handler = handlers.text
+    } else {
+      _.warn("v-model doesn't support element type: " + tag)
+      return
+    }
+    handler.bind.call(this)
+    this.update = handler.update
+    this.unbind = handler.unbind
+  }
+
+}

+ 0 - 0
src/directives/model/radio.js


+ 0 - 0
src/directives/model/select.js


+ 98 - 0
src/directives/model/text.js

@@ -0,0 +1,98 @@
+var _ = require('../../util')
+
+module.exports = {
+
+  bind: function () {
+    var self = this
+    var el = this.el
+    // check params
+    // - lazy: update model on "change" instead of "input"
+    var lazy = el.hasAttribute('lazy')
+    if (lazy) {
+      el.removeAttribute('lazy')
+    }
+    // - number: cast value into number when updating model.
+    var number =
+      el.hasAttribute('number') ||
+      el.type === 'number'
+    if (number) {
+      el.removeAttribute('number')
+    }
+    this.event = lazy ? 'change' : 'input'
+    // handle composition events.
+    // http://blog.evanyou.me/2014/01/03/composition-event/
+    var cpLocked = false
+    this.cpLock = function () {
+      cpLocked = true
+    }
+    this.cpUnlock = function () {
+      cpLocked = false
+    }
+    _.on(el,'compositionstart', this.cpLock)
+    _.on(el,'compositionend', this.cpUnlock)
+    // if the directive has read filters, we need to
+    // record cursor position and restore it after updating
+    // the input with the filtered value.
+    this.listener = function textInputListener () {
+      if (cpLocked) return
+      try {
+        var cursorPos = el.selectionStart
+      } catch (e) {}
+      self.set(
+        number
+          ? _.toNumber(el.value)
+          : el.value
+      )
+      if (cursorPos) {
+        _.nextTick(function () {
+          el.setSelectionRange(cursorPos, cursorPos)
+        })
+      }
+    }
+    _.on(el, this.event, this.listener)
+    // IE9 doesn't fire input event on backspace/del/cut
+    if (!lazy && _.isIE9) {
+      shimIE9(this)
+    }
+    // set initial value if present
+    if (el.value) {
+      this.set(el.value, true)
+    }
+  },
+
+  update: function (value) {
+    this.el.value = value
+  },
+
+  unbind: function () {
+    var el = this.el
+    _.off(el, this.event, this.listener)
+    _.off(el,'compositionstart', this.cpLock)
+    _.off(el,'compositionend', this.cpUnlock)
+    if (this.onCut) {
+      _.off(el,'cut', this.onCut)
+      _.off(el,'keyup', this.onDel)
+    }
+  }
+
+}
+
+/**
+ * IE9 doesn't fire input event on backspace/del/cut,
+ * so we have to shim it by adding some additoinal listners.
+ *
+ * @param {Directive} dir
+ */
+
+function shimIE9 (dir) {
+  dir.onCut = function () {
+    _.nextTick(dir.listener)
+  }
+  dir.onDel = function (e) {
+    if (e.keyCode === 46 || e.keyCode === 8) {
+      dir.listener()
+    }
+  }
+  _.on(el, 'cut', dir.onCut)
+  _.on(el, 'keyup', dir.onDel)
+}

+ 5 - 9
src/directives/on.js

@@ -3,7 +3,6 @@ var _ = require('../util')
 module.exports = {
 
   isFn: true,
-
   priority: 700,
 
   bind: function () {
@@ -14,12 +13,9 @@ module.exports = {
     ) {
       var self = this
       this.iframeBind = function () {
-        self.el.contentWindow.addEventListener(
-          self.arg,
-          self.handler
-        )
+        _.on(self.el.contentWindow, self.arg, self.handler)
       }
-      this.el.addEventListener('load', this.iframeBind)
+      _.on(this.el, 'load', this.iframeBind)
     }
   },
 
@@ -44,7 +40,7 @@ module.exports = {
     if (this.iframeBind) {
       this.iframeBind()
     } else {
-      this.el.addEventListener(this.arg, this.handler)
+      _.on(this.el, this.arg, this.handler)
     }
   },
 
@@ -53,12 +49,12 @@ module.exports = {
       ? this.el.contentWindow
       : this.el
     if (this.handler) {
-      el.removeEventListener(this.arg, this.handler)
+      _.off(el, this.arg, this.handler)
     }
   },
 
   unbind: function () {
     this.reset()
-    this.el.removeEventListener('load', this.iframeBind)
+    _.off(this.el, 'load', this.iframeBind)
   }
 }

+ 5 - 5
src/transition/css.js

@@ -49,7 +49,7 @@ module.exports = function (el, direction, op, data) {
   var leaveClass = prefix + '-leave'
   // clean up potential previously running transitions
   if (data.callback) {
-    el.removeEventListener(data.event, callback)
+    _.off(el, data.event, callback)
     classList.remove(enterClass)
     classList.remove(leaveClass)
     data.event = data.callback = null
@@ -82,12 +82,12 @@ module.exports = function (el, direction, op, data) {
       endEvent = data.event = _.animationEndEvent
       onEnd = data.callback = function (e) {
         if (e.target === el) {
-          el.removeEventListener(endEvent, onEnd)
+          _.off(el, endEvent, onEnd)
           data.event = data.callback = null
           classList.remove(enterClass)
         }
       }
-      el.addEventListener(endEvent, onEnd)
+      _.on(el, endEvent, onEnd)
     }
 
   } else { // leave
@@ -112,14 +112,14 @@ module.exports = function (el, direction, op, data) {
         : _.animationEndEvent
       onEnd = data.callback = function (e) {
         if (e.target === el) {
-          el.removeEventListener(endEvent, onEnd)
+          _.off(el, endEvent, onEnd)
           data.event = data.callback = null
           // actually remove node here
           op()
           classList.remove(leaveClass)
         }
       }
-      el.addEventListener(endEvent, onEnd)
+      _.on(el, endEvent, onEnd)
     } else {
       op()
     }

+ 24 - 0
src/util/dom.js

@@ -110,4 +110,28 @@ exports.copyAttributes = function (from, to) {
       to.setAttribute(attr.name, attr.value)
     }
   }
+}
+
+/**
+ * Add event listener shorthand.
+ *
+ * @param {Element} el
+ * @param {String} event
+ * @param {Function} cb
+ */
+
+exports.on = function (el, event, cb) {
+  el.addEventListener(event, cb)
+}
+
+/**
+ * Remove event listener shorthand.
+ *
+ * @param {Element} el
+ * @param {String} event
+ * @param {Function} cb
+ */
+
+exports.off = function (el, event, cb) {
+  el.removeEventListener(event, cb)
 }