Просмотр исходного кода

utils.attr()

A method that access an attribute on a node, removes that attribute
and returns the value. Makes code a bit shorter and reduces the need to
explicitly remove attributes.
Evan You 12 лет назад
Родитель
Сommit
2c0d8a490b
8 измененных файлов с 90 добавлено и 79 удалено
  1. 37 26
      src/compiler.js
  2. 2 1
      src/config.js
  3. 13 14
      src/directives/repeat.js
  4. 16 9
      src/main.js
  5. 3 10
      src/transition.js
  6. 11 0
      src/utils.js
  7. 2 4
      test/functional/fixtures/repeated-vms.html
  8. 6 15
      test/unit/specs/transition.js

+ 37 - 26
src/compiler.js

@@ -33,16 +33,16 @@ function Compiler (vm, options) {
     utils.extend(compiler, options.compilerOptions)
 
     // initialize element
-    compiler.setupElement(options)
-    log('\nnew VM instance:', compiler.el.tagName, '\n')
+    var el = compiler.setupElement(options)
+    log('\nnew VM instance:', el.tagName, '\n')
 
     // copy scope properties to vm
     var scope = options.scope
     if (scope) utils.extend(vm, scope, true)
 
     compiler.vm  = vm
-    vm.$ = makeHash()
-    vm.$el = compiler.el
+    vm.$         = makeHash()
+    vm.$el       = el
     vm.$compiler = compiler
 
     // keep track of directives and expressions
@@ -69,7 +69,7 @@ function Compiler (vm, options) {
 
     // set parent VM
     // and register child id on parent
-    var childId = compiler.el.getAttribute(config.idAttr)
+    var childId = utils.attr(el, 'id')
     if (parent) {
         vm.$parent = parent.vm
         if (childId) {
@@ -105,7 +105,7 @@ function Compiler (vm, options) {
 
     // now parse the DOM, during which we will create necessary bindings
     // and bind the parsed directives
-    compiler.compile(compiler.el, true)
+    compiler.compile(el, true)
 
     // observe root values so that they emit events when
     // their nested values change (for an Object)
@@ -150,6 +150,7 @@ CompilerProto.setupElement = function (options) {
         el.innerHTML = ''
         el.appendChild(template.cloneNode(true))
     }
+    return el
 }
 
 /**
@@ -191,31 +192,40 @@ CompilerProto.compile = function (node, root) {
 
     var compiler = this
 
-    if (node.nodeType === 1) {
+    if (node.nodeType === 1) { // a normal node
 
-        // a normal node
-        if (node.hasAttribute(config.preAttr)) return
-        var vmId       = node.getAttribute(config.vmAttr),
-            repeatExp  = node.getAttribute(config.repeatAttr),
-            partialId  = node.getAttribute(config.partialAttr),
-            transId    = node.getAttribute(config.transAttr),
-            transClass = node.getAttribute(config.transClassAttr)
+        // skip anything with sd-pre
+        if (utils.attr(node, 'pre') !== null) return
 
-        // we need to check for any possbile special directives
-        // e.g. sd-repeat, sd-component & sd-partial
-        if (repeatExp) { // repeat block
+        // special attributes to check
+        var repeatExp,
+            componentId,
+            partialId,
+            transId,
+            transClass
+
+        // It is important that we access these attributes
+        // procedurally because the order matters.
+        //
+        // `utils.attr` removes the attribute once it gets the
+        // value, so we should not access them all at once.
+
+        // sd-repeat has the highest priority
+        // and we need to preserve all other attributes for it.
+        /* jshint boss: true */
+        if (repeatExp = utils.attr(node, 'repeat')) {
 
             // repeat block cannot have sd-id at the same time.
-            node.removeAttribute(config.idAttr)
-            var directive = Directive.parse(config.repeatAttr, repeatExp, compiler, node)
+            var directive = Directive.parse(config.attrs.repeat, repeatExp, compiler, node)
             if (directive) {
                 compiler.bindDirective(directive)
             }
 
-        } else if (vmId && !root) { // child ViewModels
+        // sd-component has second highest priority
+        // and we preseve all other attributes as well.
+        } else if (!root && (componentId = utils.attr(node, 'component'))) {
 
-            node.removeAttribute(config.vmAttr)
-            var ChildVM = compiler.getOption('components', vmId)
+            var ChildVM = compiler.getOption('components', componentId)
             if (ChildVM) {
                 var child = new ChildVM({
                     el: node,
@@ -228,10 +238,13 @@ CompilerProto.compile = function (node, root) {
             }
 
         } else {
+            
+            partialId   = utils.attr(node, 'partial')
+            transId     = utils.attr(node, 'transition')
+            transClass  = utils.attr(node, 'transition-class')
 
             // replace innerHTML with partial
             if (partialId) {
-                node.removeAttribute(config.partialAttr)
                 var partial = compiler.getOption('partials', partialId)
                 if (partial) {
                     node.innerHTML = ''
@@ -241,13 +254,11 @@ CompilerProto.compile = function (node, root) {
 
             // Javascript transition
             if (transId) {
-                node.removeAttribute(config.transAttr)
                 node.sd_trans = transId
             }
 
             // CSS class transition
             if (transClass) {
-                node.removeAttribute(config.transClassAttr)
                 node.sd_trans_class = transClass
             }
 
@@ -306,7 +317,7 @@ CompilerProto.compileNode = function (node) {
 CompilerProto.compileTextNode = function (node) {
     var tokens = TextParser.parse(node.nodeValue)
     if (!tokens) return
-    var dirname = config.textAttr,
+    var dirname = config.attrs.text,
         el, token, directive
     for (var i = 0, l = tokens.length; i < l; i++) {
         token = tokens[i]

+ 2 - 1
src/config.js

@@ -1,6 +1,7 @@
 module.exports = {
 
     prefix      : 'sd',
-    debug       : false
+    debug       : false,
+    attrs       : {}
     
 }

+ 13 - 14
src/directives/repeat.js

@@ -1,5 +1,4 @@
-var config     = require('../config'),
-    Observer   = require('../observer'),
+var Observer   = require('../observer'),
     Emitter    = require('../emitter'),
     utils      = require('../utils'),
     transition = require('../transition'),
@@ -90,19 +89,15 @@ module.exports = {
             el   = self.el,
             ctn  = self.container = el.parentNode
 
-        el.removeAttribute(config.repeatAttr)
-
         // extract child VM information, if any
-        ViewModel   = ViewModel || require('../viewmodel')
-        var vmId    = el.getAttribute(config.vmAttr)
-        if (vmId) el.removeAttribute(config.vmAttr)
-        self.ChildVM = self.compiler.getOption('components', vmId) || ViewModel
+        ViewModel       = ViewModel || require('../viewmodel')
+        var componentId = utils.attr(el, 'component')
+        self.ChildVM    = self.compiler.getOption('components', componentId) || ViewModel
 
         // extract transition information
-        self.hasTransition = !!(
-            el.getAttribute(config.transAttr) ||
-            el.getAttribute(config.transClassAttr)
-        )
+        self.trans      = utils.attr(el, 'transition')
+        self.transClass = utils.attr(el, 'transition-class')
+        self.hasTrans   = self.trans || self.transClass
 
         // create a comment node as a reference node for DOM insertions
         self.ref = document.createComment('sd-repeat-' + self.arg)
@@ -162,6 +157,10 @@ module.exports = {
             scope   = {},
             ref, item
 
+        // add transition info
+        node.sd_trans = this.trans
+        node.sd_trans_class = this.transClass
+
         // append node into DOM first
         // so sd-if can get access to parentNode
         if (data) {
@@ -214,7 +213,7 @@ module.exports = {
      *  so that batch DOM updates are done in-memory and faster
      */
     detach: function () {
-        if (this.hasTransition) return
+        if (this.hasTrans) return
         var c = this.container,
             p = this.parent = c.parentNode
         this.next = c.nextSibling
@@ -222,7 +221,7 @@ module.exports = {
     },
 
     retach: function () {
-        if (this.hasTransition) return
+        if (this.hasTrans) return
         var n = this.next,
             p = this.parent,
             c = this.container

+ 16 - 9
src/main.js

@@ -131,16 +131,23 @@ function inheritOptions (child, parent, topLevel) {
  *  Update prefix for some special directives
  *  that are used in compilation.
  */
+var specialAttributes = [
+    'id',
+    'pre',
+    'text',
+    'repeat',
+    'partial',
+    'component',
+    'transition',
+    'transition-class'
+]
+
 function updatePrefix () {
-    var prefix = config.prefix
-    config.idAttr         = prefix + '-id'
-    config.vmAttr         = prefix + '-component'
-    config.preAttr        = prefix + '-pre'
-    config.textAttr       = prefix + '-text'
-    config.repeatAttr     = prefix + '-repeat'
-    config.partialAttr    = prefix + '-partial'
-    config.transAttr      = prefix + '-transition'
-    config.transClassAttr = prefix + '-transition-class'
+    specialAttributes.forEach(setPrefix)
+}
+
+function setPrefix (attr) {
+    config.attrs[attr] = config.prefix + '-' + attr
 }
 
 updatePrefix()

+ 3 - 10
src/transition.js

@@ -1,5 +1,4 @@
-var config   = require('./config'),
-    endEvent = sniffTransitionEndEvent(),
+var endEvent = sniffTransitionEndEvent(),
     codes    = {
         CSS_E     : 1,
         CSS_L     : 2,
@@ -25,14 +24,8 @@ var transition = module.exports = function (el, stage, changeState, compiler) {
         return codes.INIT
     }
 
-    // in sd-repeat, the transition directives
-    // might not have been processed yet
-    var transitionFunctionId =
-            el.sd_trans ||
-            el.getAttribute(config.transAttr),
-        transitionClass =
-            el.sd_trans_class ||
-            el.getAttribute(config.transClassAttr)
+    var transitionFunctionId = el.sd_trans,
+        transitionClass = el.sd_trans_class
 
     if (transitionFunctionId) {
         return applyTransitionFunctions(

+ 11 - 0
src/utils.js

@@ -1,4 +1,5 @@
 var config    = require('./config'),
+    attrs     = config.attrs,
     toString  = Object.prototype.toString,
     join      = Array.prototype.join,
     console   = window.console,
@@ -22,6 +23,16 @@ var utils = module.exports = {
     partials    : makeHash(),
     transitions : makeHash(),
 
+    /**
+     *  get an attribute and remove it.
+     */
+    attr: function (el, type) {
+        var attr = attrs[type],
+            val = el.getAttribute(attr)
+        if (val) el.removeAttribute(attr)
+        return val
+    },
+
     /**
      *  Define an ienumerable property
      *  This avoids it being included in JSON.stringify

+ 2 - 4
test/functional/fixtures/repeated-vms.html

@@ -12,8 +12,8 @@
         </div>
         <script>
             Seed.config({ debug: true })
-
-            var Item = Seed.extend({
+            
+            Seed.component('item', {
                 init: function () {
                     this.item.title += ' init'
                 },
@@ -27,8 +27,6 @@
                 }
             })
 
-            Seed.component('item', Item)
-
             new Seed({
                 el: 'body',
                 scope: {

+ 6 - 15
test/unit/specs/transition.js

@@ -2,8 +2,7 @@ describe('UNIT: Transition', function () {
 
     var transition = require('seed/src/transition'),
         codes      = transition.codes,
-        endEvent   = sniffTransitionEndEvent(),
-        config     = require('seed/src/config')
+        endEvent   = sniffTransitionEndEvent()
 
     describe('General', function () {
         
@@ -77,7 +76,7 @@ describe('UNIT: Transition', function () {
 
         describe('leave', function () {
 
-            var el = mockEl('css', true),
+            var el = mockEl('css'),
                 c = mockChange(),
                 code = transition(el, -1, c.change, {})
 
@@ -176,7 +175,7 @@ describe('UNIT: Transition', function () {
 
             var code,
                 c = mockChange(),
-                el = mockEl('js', true),
+                el = mockEl('js'),
                 def = {
                     leave: function (element, change) {
                         assert.strictEqual(el, element)
@@ -213,20 +212,12 @@ describe('UNIT: Transition', function () {
         return c
     }
 
-    function mockEl (type, attr) {
+    function mockEl (type) {
         var el = document.createElement('div')
         if (type === 'css') {
-            if (attr) {
-                el.setAttribute(config.transClassAttr, 'test')
-            } else {
-                el.sd_trans_class = 'test'
-            }
+            el.sd_trans_class = 'test'
         } else if (type === 'js') {
-            if (attr) {
-                el.setAttribute(config.transAttr, 'test')
-            } else {
-                el.sd_trans = 'test'
-            }
+            el.sd_trans = 'test'
         }
         return el
     }