diff --git a/test/runner/dom.bundle.js b/test/runner/dom.bundle.js index 8300b88..9eda974 100644 --- a/test/runner/dom.bundle.js +++ b/test/runner/dom.bundle.js @@ -865,6 +865,46 @@ expect(line.$refs.line.getAttribute('class')).to.equal('active') }) + + it('feature #82', function(){ + var i = 0; + var mixins = { + events: { + $afterConfig: function(){ + i++; + expect(i).to.equal(3) + }, + $config: function(){ + i++; + expect(i).to.equal(1) + }, + $init: function(){ + i++; + expect(i).to.equal(4) + + }, + $afterInit: function(){ + i++; + expect(i).to.equal(6) + } + } + } + + var Component = Regular.extend({ + config: function(){ + i++; + expect(i).to.equal(2) + }, + init: function(){ + i++; + expect(i).to.equal(5) + } + }).implement(mixins) + + new Component(); + + expect(i).to.equal(6); + }) }) @@ -877,7 +917,7 @@ /***/ function(module, exports, __webpack_require__) { var Regular = __webpack_require__(16); - var animate = __webpack_require__(18); + var animate = __webpack_require__(19); var dom = __webpack_require__(17); function destroy(component, container){ @@ -1717,7 +1757,7 @@ var expect = __webpack_require__(26); var Regular = __webpack_require__(16); - var combine = __webpack_require__(19); + var combine = __webpack_require__(20); function destroy(component, container){ component.destroy(); expect(container.innerHTML).to.equal(''); @@ -4686,7 +4726,7 @@ var expect = __webpack_require__(26); var Regular = __webpack_require__(16); - var parse = __webpack_require__(20); + var parse = __webpack_require__(21); var Component = Regular.extend(); @@ -5853,10 +5893,10 @@ /***/ function(module, exports, __webpack_require__) { var expect = __webpack_require__(26); - var _ = __webpack_require__(22); - var shim = __webpack_require__(23); - var extend = __webpack_require__(24); - var diff = __webpack_require__(25) + var _ = __webpack_require__(18); + var shim = __webpack_require__(22); + var extend = __webpack_require__(23); + var diff = __webpack_require__(24) var diffArray = diff.diffArray; var diffObject = diff.diffObject; @@ -6180,7 +6220,7 @@ /***/ function(module, exports, __webpack_require__) { var expect = __webpack_require__(26); - var Event = __webpack_require__(21); + var Event = __webpack_require__(25); @@ -6312,8 +6352,8 @@ /***/ function(module, exports, __webpack_require__) { var env = __webpack_require__(27); - var config = __webpack_require__(29); - var Regular = module.exports = __webpack_require__(30); + var config = __webpack_require__(28); + var Regular = module.exports = __webpack_require__(29); var Parser = Regular.Parser; var Lexer = Regular.Lexer; @@ -6324,7 +6364,7 @@ Regular.dom = __webpack_require__(17); } Regular.env = env; - Regular.util = __webpack_require__(22); + Regular.util = __webpack_require__(18); Regular.parse = function(str, options){ options = options || {}; @@ -6357,8 +6397,8 @@ var dom = module.exports; var env = __webpack_require__(27); - var _ = __webpack_require__(22); - var consts = __webpack_require__(28); + var _ = __webpack_require__(18); + var consts = __webpack_require__(30); var tNode = document.createElement('div') var addEvent, removeEvent; var noop = function(){} @@ -6737,915 +6777,835 @@ /* 18 */ /***/ function(module, exports, __webpack_require__) { - var _ = __webpack_require__(22); - var dom = __webpack_require__(17); - var animate = {}; - var env = __webpack_require__(27); + /* WEBPACK VAR INJECTION */(function(global) {__webpack_require__(22)(); - var - transitionEnd = 'transitionend', - animationEnd = 'animationend', - transitionProperty = 'transition', - animationProperty = 'animation'; - if(!('ontransitionend' in window)){ - if('onwebkittransitionend' in window) { - - // Chrome/Saf (+ Mobile Saf)/Android - transitionEnd += ' webkitTransitionEnd'; - transitionProperty = 'webkitTransition' - } else if('onotransitionend' in dom.tNode || navigator.appName === 'Opera') { + var _ = module.exports; + var entities = __webpack_require__(31); + var slice = [].slice; + var o2str = ({}).toString; + var win = typeof window !=='undefined'? window: global; - // Opera - transitionEnd += ' oTransitionEnd'; - transitionProperty = 'oTransition'; - } - } - if(!('onanimationend' in window)){ - if ('onwebkitanimationend' in window){ - // Chrome/Saf (+ Mobile Saf)/Android - animationEnd += ' webkitAnimationEnd'; - animationProperty = 'webkitAnimation'; - }else if ('onoanimationend' in dom.tNode){ - // Opera - animationEnd += ' oAnimationEnd'; - animationProperty = 'oAnimation'; + _.noop = function(){}; + _.uid = (function(){ + var _uid=0; + return function(){ + return _uid++; } - } - - /** - * inject node with animation - * @param {[type]} node [description] - * @param {[type]} refer [description] - * @param {[type]} direction [description] - * @return {[type]} [description] - */ - animate.inject = function( node, refer ,direction, callback ){ - callback = callback || _.noop; - if( Array.isArray(node) ){ - var fragment = dom.fragment(); - var count=0; - - for(var i = 0,len = node.length;i < len; i++ ){ - fragment.appendChild(node[i]); - } - dom.inject(fragment, refer, direction); + })(); - // if all nodes is done, we call the callback - var enterCallback = function (){ - count++; - if( count === len ) callback(); - } - if(len === count) callback(); - for( i = 0; i < len; i++ ){ - if(node[i].onenter){ - node[i].onenter(enterCallback); - }else{ - enterCallback(); - } - } - }else{ - dom.inject( node, refer, direction ); - if(node.onenter){ - node.onenter(callback) - }else{ - callback(); + _.extend = function( o1, o2, override ){ + // if(_.typeOf(override) === 'array'){ + // for(var i = 0, len = override.length; i < len; i++ ){ + // var key = override[i]; + // o1[key] = o2[key]; + // } + // }else{ + for(var i in o2){ + if( typeof o1[i] === "undefined" || override === true ){ + o1[i] = o2[i] } } + // } + return o1; } - /** - * remove node with animation - * @param {[type]} node [description] - * @param {Function} callback [description] - * @return {[type]} [description] - */ - animate.remove = function(node, callback){ - if(!node) return; - var count = 0; - function loop(){ - count++; - if(count === len) callback && callback() - } - if(Array.isArray(node)){ - for(var i = 0, len = node.length; i < len ; i++){ - animate.remove(node[i], loop) - } - return node; - } - if(node.onleave){ - node.onleave(function(){ - removeDone(node, callback) - }) - }else{ - removeDone(node, callback) + _.keys = function(obj){ + if(Object.keys) return Object.keys(obj); + var res = []; + for(var i in obj) if(obj.hasOwnProperty(i)){ + res.push(i); } + return res; } - var removeDone = function (node, callback){ - dom.remove(node); - callback && callback(); - } - + _.varName = 'd'; + _.setName = 'p_'; + _.ctxName = 'c'; + _.extName = 'e'; + _.rWord = /^[\$\w]+$/; + _.rSimpleAccessor = /^[\$\w]+(\.[\$\w]+)*$/; - animate.startClassAnimate = function ( node, className, callback, mode ){ - var activeClassName, timeout, tid, onceAnim; - if( (!animationEnd && !transitionEnd) || env.isRunning ){ - return callback(); + _.nextTick = typeof setImmediate === 'function'? + setImmediate.bind(win) : + function(callback) { + setTimeout(callback, 0) } - if(mode !== 4){ - onceAnim = _.once(function onAnimateEnd(){ - if(tid) clearTimeout(tid); - - if(mode === 2) { - dom.delClass(node, activeClassName); - } - if(mode !== 3){ // mode hold the class - dom.delClass(node, className); - } - dom.off(node, animationEnd, onceAnim) - dom.off(node, transitionEnd, onceAnim) - - callback(); - - }); - }else{ - onceAnim = _.once(function onAnimateEnd(){ - if(tid) clearTimeout(tid); - callback(); - }); - } - if(mode === 2){ // auto removed - dom.addClass( node, className ); - activeClassName = _.map(className.split(/\s+/), function(name){ - return name + '-active'; - }).join(" "); - dom.nextReflow(function(){ - dom.addClass( node, activeClassName ); - timeout = getMaxTimeout( node ); - tid = setTimeout( onceAnim, timeout ); - }); + _.prefix = "var " + _.varName + "=" + _.ctxName + ".data;" + _.extName + "=" + _.extName + "||'';"; - }else if(mode===4){ - dom.nextReflow(function(){ - dom.delClass( node, className ); - timeout = getMaxTimeout( node ); - tid = setTimeout( onceAnim, timeout ); - }); - }else{ - dom.nextReflow(function(){ - dom.addClass( node, className ); - timeout = getMaxTimeout( node ); - tid = setTimeout( onceAnim, timeout ); - }); + _.slice = function(obj, start, end){ + var res = []; + for(var i = start || 0, len = end || obj.length; i < len; i++){ + var item = obj[i]; + res.push(item) } - - - - dom.on( node, animationEnd, onceAnim ) - dom.on( node, transitionEnd, onceAnim ) - return onceAnim; + return res; } - - animate.startStyleAnimate = function(node, styles, callback){ - var timeout, onceAnim, tid; - - dom.nextReflow(function(){ - dom.css( node, styles ); - timeout = getMaxTimeout( node ); - tid = setTimeout( onceAnim, timeout ); - }); - - - onceAnim = _.once(function onAnimateEnd(){ - if(tid) clearTimeout(tid); - - dom.off(node, animationEnd, onceAnim) - dom.off(node, transitionEnd, onceAnim) - - callback(); - - }); - - dom.on( node, animationEnd, onceAnim ) - dom.on( node, transitionEnd, onceAnim ) - - return onceAnim; + _.typeOf = function (o) { + return o == null ? String(o) :o2str.call(o).slice(8, -1).toLowerCase(); } - /** - * get maxtimeout - * @param {Node} node - * @return {[type]} [description] - */ - function getMaxTimeout(node){ - var timeout = 0, - tDuration = 0, - tDelay = 0, - aDuration = 0, - aDelay = 0, - ratio = 5 / 3, - styles ; + _.makePredicate = function makePredicate(words, prefix) { + if (typeof words === "string") { + words = words.split(" "); + } + var f = "", + cats = []; + out: for (var i = 0; i < words.length; ++i) { + for (var j = 0; j < cats.length; ++j){ + if (cats[j][0].length === words[i].length) { + cats[j].push(words[i]); + continue out; + } + } + cats.push([words[i]]); + } + function compareTo(arr) { + if (arr.length === 1) return f += "return str === '" + arr[0] + "';"; + f += "switch(str){"; + for (var i = 0; i < arr.length; ++i){ + f += "case '" + arr[i] + "':"; + } + f += "return true}return false;"; + } - if(window.getComputedStyle){ + // When there are more than three length categories, an outer + // switch first dispatches on the lengths, to save on comparisons. + if (cats.length > 3) { + cats.sort(function(a, b) { + return b.length - a.length; + }); + f += "switch(str.length){"; + for (var i = 0; i < cats.length; ++i) { + var cat = cats[i]; + f += "case " + cat[0].length + ":"; + compareTo(cat); + } + f += "}"; - styles = window.getComputedStyle(node), - tDuration = getMaxTime( styles[transitionProperty + 'Duration']) || tDuration; - tDelay = getMaxTime( styles[transitionProperty + 'Delay']) || tDelay; - aDuration = getMaxTime( styles[animationProperty + 'Duration']) || aDuration; - aDelay = getMaxTime( styles[animationProperty + 'Delay']) || aDelay; - timeout = Math.max( tDuration+tDelay, aDuration + aDelay ); + // Otherwise, simply generate a flat `switch` statement. + } else { + compareTo(words); + } + return new Function("str", f); + } + + + _.trackErrorPos = (function (){ + // linebreak + var lb = /\r\n|[\n\r\u2028\u2029]/g; + var minRange = 20, maxRange = 20; + function findLine(lines, pos){ + var tmpLen = 0; + for(var i = 0,len = lines.length; i < len; i++){ + var lineLen = (lines[i] || "").length; + if(tmpLen + lineLen > pos) { + return {num: i, line: lines[i], start: pos - i - tmpLen , prev:lines[i-1], next: lines[i+1] }; + } + // 1 is for the linebreak + tmpLen = tmpLen + lineLen ; + } } - return timeout * 1000 * ratio; - } + function formatLine(str, start, num, target){ + var len = str.length; + var min = start - minRange; + if(min < 0) min = 0; + var max = start + maxRange; + if(max > len) max = len; - function getMaxTime(str){ + var remain = str.slice(min, max); + var prefix = "[" +(num+1) + "] " + (min > 0? ".." : "") + var postfix = max < len ? "..": ""; + var res = prefix + remain + postfix; + if(target) res += "\n" + new Array(start-min + prefix.length + 1).join(" ") + "^^^"; + return res; + } + return function(input, pos){ + if(pos > input.length-1) pos = input.length-1; + lb.lastIndex = 0; + var lines = input.split(lb); + var line = findLine(lines,pos); + var start = line.start, num = line.num; - var maxTimeout = 0, time; + return (line.prev? formatLine(line.prev, start, num-1 ) + '\n': '' ) + + formatLine(line.line, start, num, true) + '\n' + + (line.next? formatLine(line.next, start, num+1 ) + '\n': '' ); - if(!str) return 0; + } + })(); - str.split(",").forEach(function(str){ - time = parseFloat(str); - if( time > maxTimeout ) maxTimeout = time; + var ignoredRef = /\((\?\!|\?\:|\?\=)/g; + _.findSubCapture = function (regStr) { + var left = 0, + right = 0, + len = regStr.length, + ignored = regStr.match(ignoredRef); // ignored uncapture + if(ignored) ignored = ignored.length + else ignored = 0; + for (; len--;) { + var letter = regStr.charAt(len); + if (len === 0 || regStr.charAt(len - 1) !== "\\" ) { + if (letter === "(") left++; + if (letter === ")") right++; + } + } + if (left !== right) throw "RegExp: "+ regStr + "'s bracket is not marched"; + else return left - ignored; + }; + + _.escapeRegExp = function( str){// Credit: XRegExp 0.6.1 (c) 2007-2008 Steven Levithan MIT License + return str.replace(/[-[\]{}()*+?.\\^$|,#\s]/g, function(match){ + return '\\' + match; }); + }; - return maxTimeout; - } - module.exports = animate; + var rEntity = new RegExp("&(?:(#x[0-9a-fA-F]+)|(#[0-9]+)|(" + _.keys(entities).join('|') + '));', 'gi'); -/***/ }, -/* 19 */ -/***/ function(module, exports, __webpack_require__) { + _.convertEntity = function(chr){ - // some nested operation in ast - // -------------------------------- + return ("" + chr).replace(rEntity, function(all, hex, dec, capture){ + var charCode; + if( dec ) charCode = parseInt( dec.slice(1), 10 ); + else if( hex ) charCode = parseInt( hex.slice(2), 16 ); + else charCode = entities[capture] - var dom = __webpack_require__(17); - var animate = __webpack_require__(18); + return String.fromCharCode( charCode ) + }); - var combine = module.exports = { + } - // get the initial dom in object - node: function(item){ - var children,node, nodes; - if(!item) return; - if(item.element) return item.element; - if(typeof item.node === "function") return item.node(); - if(typeof item.nodeType === "number") return item; - if(item.group) return combine.node(item.group) - if(children = item.children){ - if(children.length === 1){ - return combine.node(children[0]); - } - nodes = []; - for(var i = 0, len = children.length; i < len; i++ ){ - node = combine.node(children[i]); - if(Array.isArray(node)){ - nodes.push.apply(nodes, node) - }else if(node) { - nodes.push(node) - } - } - return nodes; - } - }, - // @TODO remove _gragContainer - inject: function(node, pos ){ - var group = this; - var fragment = combine.node(group.group || group); - if(node === false) { - animate.remove(fragment) - return group; - }else{ - if(!fragment) return group; - if(typeof node === 'string') node = dom.find(node); - if(!node) throw Error('injected node is not found'); - // use animate to animate firstchildren - animate.inject(fragment, node, pos); - } - // if it is a component - if(group.$emit) { - var preParent = group.parentNode; - var newParent = (pos ==='after' || pos === 'before')? node.parentNode : node; - group.parentNode = newParent; - group.$emit("$inject", node, pos, preParent); - } - return group; - }, - // get the last dom in object(for insertion operation) - last: function(item){ - var children = item.children; + // simple get accessor - if(typeof item.last === "function") return item.last(); - if(typeof item.nodeType === "number") return item; + _.createObject = function(o, props){ + function Foo() {} + Foo.prototype = o; + var res = new Foo; + if(props) _.extend(res, props); + return res; + } - if(children && children.length) return combine.last(children[children.length - 1]); - if(item.group) return combine.last(item.group); + _.createProto = function(fn, o){ + function Foo() { this.constructor = fn;} + Foo.prototype = o; + return (fn.prototype = new Foo()); + } - }, - destroy: function(item, first){ - if(!item) return; - if(Array.isArray(item)){ - for(var i = 0, len = item.length; i < len; i++ ){ - combine.destroy(item[i], first); + + /** + clone + */ + _.clone = function clone(obj){ + var type = _.typeOf(obj); + if(type === 'array'){ + var cloned = []; + for(var i=0,len = obj.length; i< len;i++){ + cloned[i] = obj[i] } + return cloned; } - var children = item.children; - if(typeof item.destroy === "function") return item.destroy(first); - if(typeof item.nodeType === "number" && first) dom.remove(item); - if(children && children.length){ - combine.destroy(children, true); - item.children = null; + if(type === 'object'){ + var cloned = {}; + for(var i in obj) if(obj.hasOwnProperty(i)){ + cloned[i] = obj[i]; + } + return cloned; } + return obj; } + _.equals = function(now, old){ + var type = typeof now; + if(type === 'number' && typeof old === 'number'&& isNaN(now) && isNaN(old)) return true + return now === old; } + var dash = /-([a-z])/g; + _.camelCase = function(str){ + return str.replace(dash, function(all, capture){ + return capture.toUpperCase(); + }) + } - // @TODO: need move to dom.js - dom.element = function( component, all ){ - if(!component) return !all? null: []; - var nodes = combine.node( component ); - if( nodes.nodeType === 1 ) return all? [nodes]: nodes; - var elements = []; - for(var i = 0; i wait) { + clearTimeout(timeout); + timeout = null; + previous = now; + result = func.apply(context, args); + context = args = null; + } else if (!timeout) { + timeout = setTimeout(later, remaining); + } + return result; + }; + }; + + // hogan escape + // ============== + _.escape = (function(){ + var rAmp = /&/g, + rLt = //g, + rApos = /\'/g, + rQuot = /\"/g, + hChars = /[&<>\"\']/; + + return function(str) { + return hChars.test(str) ? + str + .replace(rAmp, '&') + .replace(rLt, '<') + .replace(rGt, '>') + .replace(rApos, ''') + .replace(rQuot, '"') : + str; } - return !all? elements[0]: elements; + })(); + + _.cache = function(max){ + max = max || 1000; + var keys = [], + cache = {}; + return { + set: function(key, value) { + if (keys.length > this.max) { + cache[keys.shift()] = undefined; + } + // + if(cache[key] === undefined){ + keys.push(key); + } + cache[key] = value; + return value; + }, + get: function(key) { + if (key === undefined) return cache; + return cache[key]; + }, + max: max, + len:function(){ + return keys.length; + } + }; } + // // setup the raw Expression + // _.touchExpression = function(expr){ + // if(expr.type === 'expression'){ + // } + // return expr; + // } + // handle the same logic on component's `on-*` and element's `on-*` + // return the fire object + _.handleEvent = function(value, type ){ + var self = this, evaluate; + if(value.type === 'expression'){ // if is expression, go evaluated way + evaluate = value.get; + } + if(evaluate){ + return function fire(obj){ + self.$update(function(){ + var data = this.data; + data.$event = obj; + var res = evaluate(self); + if(res === false && obj && obj.preventDefault) obj.preventDefault(); + data.$event = undefined; + }) + } + }else{ + return function fire(){ + var args = slice.call(arguments) + args.unshift(value); + self.$update(function(){ + self.$emit.apply(self, args); + }) + } + } + } -/***/ }, -/* 20 */ -/***/ function(module, exports, __webpack_require__) { + // only call once + _.once = function(fn){ + var time = 0; + return function(){ + if( time++ === 0) fn.apply(this, arguments); + } + } - var exprCache = __webpack_require__(27).exprCache; - var _ = __webpack_require__(22); - var Parser = __webpack_require__(35); - module.exports = { - expression: function(expr, simple){ - // @TODO cache - if( typeof expr === 'string' && ( expr = expr.trim() ) ){ - expr = exprCache.get( expr ) || exprCache.set( expr, new Parser( expr, { mode: 2, expression: true } ).expression() ) - } - if(expr) return expr; - }, - parse: function(template){ - return new Parser(template).parse(); + _.fixObjStr = function(str){ + if(str.trim().indexOf('{') !== 0){ + return '{' + str + '}'; } + return str; } + _.map= function(array, callback){ + var res = []; + for (var i = 0, len = array.length; i < len; i++) { + res.push(callback(array[i], i)); + } + return res; + } -/***/ }, -/* 21 */ -/***/ function(module, exports, __webpack_require__) { + function log(msg, type){ + if(typeof console !== "undefined") console[type || "log"](msg); + } - // simplest event emitter 60 lines - // =============================== - var slice = [].slice, _ = __webpack_require__(22); - var API = { - $on: function(event, fn) { - if(typeof event === "object"){ - for (var i in event) { - this.$on(i, event[i]); - } - }else{ - // @patch: for list - var context = this; - var handles = context._handles || (context._handles = {}), - calls = handles[event] || (handles[event] = []); - calls.push(fn); - } - return this; - }, - $off: function(event, fn) { - var context = this; - if(!context._handles) return; - if(!event) this._handles = {}; - var handles = context._handles, - calls; + _.log = log; - if (calls = handles[event]) { - if (!fn) { - handles[event] = []; - return context; - } - for (var i = 0, len = calls.length; i < len; i++) { - if (fn === calls[i]) { - calls.splice(i, 1); - return context; - } - } - } - return context; - }, - // bubble event - $emit: function(event){ - // @patch: for list - var context = this; - var handles = context._handles, calls, args, type; - if(!event) return; - var args = slice.call(arguments, 1); - var type = event; - if(!handles) return context; - if(calls = handles[type.slice(1)]){ - for (var j = 0, len = calls.length; j < len; j++) { - calls[j].apply(context, args) - } - } - if (!(calls = handles[type])) return context; - for (var i = 0, len = calls.length; i < len; i++) { - calls[i].apply(context, args) - } - // if(calls.length) context.$update(); - return context; - }, - // capture event - $one: function(){ - + + + //http://www.w3.org/html/wg/drafts/html/master/single-page.html#void-elements + _.isVoidTag = _.makePredicate("area base br col embed hr img input keygen link menuitem meta param source track wbr r-content"); + _.isBooleanAttr = _.makePredicate('selected checked disabled readonly required open autofocus controls autoplay compact loop defer multiple'); + + _.isFalse - function(){return false} + _.isTrue - function(){return true} + + _.isExpr = function(expr){ + return expr && expr.type === 'expression'; } + // @TODO: make it more strict + _.isGroup = function(group){ + return group.inject || group.$inject; } - // container class - function Event() {} - _.extend(Event.prototype, API) - Event.mixTo = function(obj){ - obj = typeof obj === "function" ? obj.prototype : obj; - _.extend(obj, API) + _.getCompileFn = function(source, ctx, options){ + return ctx.$compile.bind(ctx,source, options) } - module.exports = Event; + + + + + + + /* WEBPACK VAR INJECTION */}.call(exports, (function() { return this; }()))) /***/ }, -/* 22 */ +/* 19 */ /***/ function(module, exports, __webpack_require__) { - /* WEBPACK VAR INJECTION */(function(global) {__webpack_require__(23)(); + var _ = __webpack_require__(18); + var dom = __webpack_require__(17); + var animate = {}; + var env = __webpack_require__(27); + var + transitionEnd = 'transitionend', + animationEnd = 'animationend', + transitionProperty = 'transition', + animationProperty = 'animation'; - var _ = module.exports; - var entities = __webpack_require__(31); - var slice = [].slice; - var o2str = ({}).toString; - var win = typeof window !=='undefined'? window: global; + if(!('ontransitionend' in window)){ + if('onwebkittransitionend' in window) { + + // Chrome/Saf (+ Mobile Saf)/Android + transitionEnd += ' webkitTransitionEnd'; + transitionProperty = 'webkitTransition' + } else if('onotransitionend' in dom.tNode || navigator.appName === 'Opera') { + // Opera + transitionEnd += ' oTransitionEnd'; + transitionProperty = 'oTransition'; + } + } + if(!('onanimationend' in window)){ + if ('onwebkitanimationend' in window){ + // Chrome/Saf (+ Mobile Saf)/Android + animationEnd += ' webkitAnimationEnd'; + animationProperty = 'webkitAnimation'; - _.noop = function(){}; - _.uid = (function(){ - var _uid=0; - return function(){ - return _uid++; + }else if ('onoanimationend' in dom.tNode){ + // Opera + animationEnd += ' oAnimationEnd'; + animationProperty = 'oAnimation'; + } + } + + /** + * inject node with animation + * @param {[type]} node [description] + * @param {[type]} refer [description] + * @param {[type]} direction [description] + * @return {[type]} [description] + */ + animate.inject = function( node, refer ,direction, callback ){ + callback = callback || _.noop; + if( Array.isArray(node) ){ + var fragment = dom.fragment(); + var count=0; + + for(var i = 0,len = node.length;i < len; i++ ){ + fragment.appendChild(node[i]); + } + dom.inject(fragment, refer, direction); + + // if all nodes is done, we call the callback + var enterCallback = function (){ + count++; + if( count === len ) callback(); + } + if(len === count) callback(); + for( i = 0; i < len; i++ ){ + if(node[i].onenter){ + node[i].onenter(enterCallback); + }else{ + enterCallback(); + } + } + }else{ + dom.inject( node, refer, direction ); + if(node.onenter){ + node.onenter(callback) + }else{ + callback(); + } } - })(); + } - _.extend = function( o1, o2, override ){ - // if(_.typeOf(override) === 'array'){ - // for(var i = 0, len = override.length; i < len; i++ ){ - // var key = override[i]; - // o1[key] = o2[key]; - // } - // }else{ - for(var i in o2){ - if( typeof o1[i] === "undefined" || override === true ){ - o1[i] = o2[i] + /** + * remove node with animation + * @param {[type]} node [description] + * @param {Function} callback [description] + * @return {[type]} [description] + */ + animate.remove = function(node, callback){ + if(!node) return; + var count = 0; + function loop(){ + count++; + if(count === len) callback && callback() + } + if(Array.isArray(node)){ + for(var i = 0, len = node.length; i < len ; i++){ + animate.remove(node[i], loop) } + return node; + } + if(node.onleave){ + node.onleave(function(){ + removeDone(node, callback) + }) + }else{ + removeDone(node, callback) } - // } - return o1; } - _.keys = function(obj){ - if(Object.keys) return Object.keys(obj); - var res = []; - for(var i in obj) if(obj.hasOwnProperty(i)){ - res.push(i); - } - return res; + var removeDone = function (node, callback){ + dom.remove(node); + callback && callback(); } - _.varName = 'd'; - _.setName = 'p_'; - _.ctxName = 'c'; - _.extName = 'e'; - _.rWord = /^[\$\w]+$/; - _.rSimpleAccessor = /^[\$\w]+(\.[\$\w]+)*$/; - _.nextTick = typeof setImmediate === 'function'? - setImmediate.bind(win) : - function(callback) { - setTimeout(callback, 0) + animate.startClassAnimate = function ( node, className, callback, mode ){ + var activeClassName, timeout, tid, onceAnim; + if( (!animationEnd && !transitionEnd) || env.isRunning ){ + return callback(); } + if(mode !== 4){ + onceAnim = _.once(function onAnimateEnd(){ + if(tid) clearTimeout(tid); + if(mode === 2) { + dom.delClass(node, activeClassName); + } + if(mode !== 3){ // mode hold the class + dom.delClass(node, className); + } + dom.off(node, animationEnd, onceAnim) + dom.off(node, transitionEnd, onceAnim) - _.prefix = "var " + _.varName + "=" + _.ctxName + ".data;" + _.extName + "=" + _.extName + "||'';"; - + callback(); - _.slice = function(obj, start, end){ - var res = []; - for(var i = start || 0, len = end || obj.length; i < len; i++){ - var item = obj[i]; - res.push(item) + }); + }else{ + onceAnim = _.once(function onAnimateEnd(){ + if(tid) clearTimeout(tid); + callback(); + }); } - return res; - } + if(mode === 2){ // auto removed + dom.addClass( node, className ); - _.typeOf = function (o) { - return o == null ? String(o) :o2str.call(o).slice(8, -1).toLowerCase(); - } + activeClassName = _.map(className.split(/\s+/), function(name){ + return name + '-active'; + }).join(" "); + dom.nextReflow(function(){ + dom.addClass( node, activeClassName ); + timeout = getMaxTimeout( node ); + tid = setTimeout( onceAnim, timeout ); + }); - _.makePredicate = function makePredicate(words, prefix) { - if (typeof words === "string") { - words = words.split(" "); - } - var f = "", - cats = []; - out: for (var i = 0; i < words.length; ++i) { - for (var j = 0; j < cats.length; ++j){ - if (cats[j][0].length === words[i].length) { - cats[j].push(words[i]); - continue out; - } - } - cats.push([words[i]]); - } - function compareTo(arr) { - if (arr.length === 1) return f += "return str === '" + arr[0] + "';"; - f += "switch(str){"; - for (var i = 0; i < arr.length; ++i){ - f += "case '" + arr[i] + "':"; - } - f += "return true}return false;"; - } + }else if(mode===4){ + dom.nextReflow(function(){ + dom.delClass( node, className ); + timeout = getMaxTimeout( node ); + tid = setTimeout( onceAnim, timeout ); + }); - // When there are more than three length categories, an outer - // switch first dispatches on the lengths, to save on comparisons. - if (cats.length > 3) { - cats.sort(function(a, b) { - return b.length - a.length; - }); - f += "switch(str.length){"; - for (var i = 0; i < cats.length; ++i) { - var cat = cats[i]; - f += "case " + cat[0].length + ":"; - compareTo(cat); - } - f += "}"; + }else{ + dom.nextReflow(function(){ + dom.addClass( node, className ); + timeout = getMaxTimeout( node ); + tid = setTimeout( onceAnim, timeout ); + }); + } - // Otherwise, simply generate a flat `switch` statement. - } else { - compareTo(words); - } - return new Function("str", f); - } - _.trackErrorPos = (function (){ - // linebreak - var lb = /\r\n|[\n\r\u2028\u2029]/g; - var minRange = 20, maxRange = 20; - function findLine(lines, pos){ - var tmpLen = 0; - for(var i = 0,len = lines.length; i < len; i++){ - var lineLen = (lines[i] || "").length; + dom.on( node, animationEnd, onceAnim ) + dom.on( node, transitionEnd, onceAnim ) + return onceAnim; + } - if(tmpLen + lineLen > pos) { - return {num: i, line: lines[i], start: pos - i - tmpLen , prev:lines[i-1], next: lines[i+1] }; - } - // 1 is for the linebreak - tmpLen = tmpLen + lineLen ; - } - } - function formatLine(str, start, num, target){ - var len = str.length; - var min = start - minRange; - if(min < 0) min = 0; - var max = start + maxRange; - if(max > len) max = len; - var remain = str.slice(min, max); - var prefix = "[" +(num+1) + "] " + (min > 0? ".." : "") - var postfix = max < len ? "..": ""; - var res = prefix + remain + postfix; - if(target) res += "\n" + new Array(start-min + prefix.length + 1).join(" ") + "^^^"; - return res; - } - return function(input, pos){ - if(pos > input.length-1) pos = input.length-1; - lb.lastIndex = 0; - var lines = input.split(lb); - var line = findLine(lines,pos); - var start = line.start, num = line.num; + animate.startStyleAnimate = function(node, styles, callback){ + var timeout, onceAnim, tid; - return (line.prev? formatLine(line.prev, start, num-1 ) + '\n': '' ) + - formatLine(line.line, start, num, true) + '\n' + - (line.next? formatLine(line.next, start, num+1 ) + '\n': '' ); + dom.nextReflow(function(){ + dom.css( node, styles ); + timeout = getMaxTimeout( node ); + tid = setTimeout( onceAnim, timeout ); + }); - } - })(); + onceAnim = _.once(function onAnimateEnd(){ + if(tid) clearTimeout(tid); - var ignoredRef = /\((\?\!|\?\:|\?\=)/g; - _.findSubCapture = function (regStr) { - var left = 0, - right = 0, - len = regStr.length, - ignored = regStr.match(ignoredRef); // ignored uncapture - if(ignored) ignored = ignored.length - else ignored = 0; - for (; len--;) { - var letter = regStr.charAt(len); - if (len === 0 || regStr.charAt(len - 1) !== "\\" ) { - if (letter === "(") left++; - if (letter === ")") right++; - } - } - if (left !== right) throw "RegExp: "+ regStr + "'s bracket is not marched"; - else return left - ignored; - }; + dom.off(node, animationEnd, onceAnim) + dom.off(node, transitionEnd, onceAnim) + callback(); - _.escapeRegExp = function( str){// Credit: XRegExp 0.6.1 (c) 2007-2008 Steven Levithan MIT License - return str.replace(/[-[\]{}()*+?.\\^$|,#\s]/g, function(match){ - return '\\' + match; }); - }; + dom.on( node, animationEnd, onceAnim ) + dom.on( node, transitionEnd, onceAnim ) - var rEntity = new RegExp("&(?:(#x[0-9a-fA-F]+)|(#[0-9]+)|(" + _.keys(entities).join('|') + '));', 'gi'); + return onceAnim; + } - _.convertEntity = function(chr){ - return ("" + chr).replace(rEntity, function(all, hex, dec, capture){ - var charCode; - if( dec ) charCode = parseInt( dec.slice(1), 10 ); - else if( hex ) charCode = parseInt( hex.slice(2), 16 ); - else charCode = entities[capture] + /** + * get maxtimeout + * @param {Node} node + * @return {[type]} [description] + */ + function getMaxTimeout(node){ + var timeout = 0, + tDuration = 0, + tDelay = 0, + aDuration = 0, + aDelay = 0, + ratio = 5 / 3, + styles ; + + if(window.getComputedStyle){ - return String.fromCharCode( charCode ) - }); + styles = window.getComputedStyle(node), + tDuration = getMaxTime( styles[transitionProperty + 'Duration']) || tDuration; + tDelay = getMaxTime( styles[transitionProperty + 'Delay']) || tDelay; + aDuration = getMaxTime( styles[animationProperty + 'Duration']) || aDuration; + aDelay = getMaxTime( styles[animationProperty + 'Delay']) || aDelay; + timeout = Math.max( tDuration+tDelay, aDuration + aDelay ); + } + return timeout * 1000 * ratio; } + function getMaxTime(str){ - // simple get accessor - - _.createObject = function(o, props){ - function Foo() {} - Foo.prototype = o; - var res = new Foo; - if(props) _.extend(res, props); - return res; - } - - _.createProto = function(fn, o){ - function Foo() { this.constructor = fn;} - Foo.prototype = o; - return (fn.prototype = new Foo()); - } + var maxTimeout = 0, time; + if(!str) return 0; + str.split(",").forEach(function(str){ - /** - clone - */ - _.clone = function clone(obj){ - var type = _.typeOf(obj); - if(type === 'array'){ - var cloned = []; - for(var i=0,len = obj.length; i< len;i++){ - cloned[i] = obj[i] - } - return cloned; - } - if(type === 'object'){ - var cloned = {}; - for(var i in obj) if(obj.hasOwnProperty(i)){ - cloned[i] = obj[i]; - } - return cloned; - } - return obj; - } + time = parseFloat(str); + if( time > maxTimeout ) maxTimeout = time; - _.equals = function(now, old){ - var type = typeof now; - if(type === 'number' && typeof old === 'number'&& isNaN(now) && isNaN(old)) return true - return now === old; - } + }); - var dash = /-([a-z])/g; - _.camelCase = function(str){ - return str.replace(dash, function(all, capture){ - return capture.toUpperCase(); - }) + return maxTimeout; } + module.exports = animate; +/***/ }, +/* 20 */ +/***/ function(module, exports, __webpack_require__) { - _.throttle = function throttle(func, wait){ - var wait = wait || 100; - var context, args, result; - var timeout = null; - var previous = 0; - var later = function() { - previous = +new Date; - timeout = null; - result = func.apply(context, args); - context = args = null; - }; - return function() { - var now = + new Date; - var remaining = wait - (now - previous); - context = this; - args = arguments; - if (remaining <= 0 || remaining > wait) { - clearTimeout(timeout); - timeout = null; - previous = now; - result = func.apply(context, args); - context = args = null; - } else if (!timeout) { - timeout = setTimeout(later, remaining); - } - return result; - }; - }; + // some nested operation in ast + // -------------------------------- - // hogan escape - // ============== - _.escape = (function(){ - var rAmp = /&/g, - rLt = //g, - rApos = /\'/g, - rQuot = /\"/g, - hChars = /[&<>\"\']/; + var dom = __webpack_require__(17); + var animate = __webpack_require__(19); - return function(str) { - return hChars.test(str) ? - str - .replace(rAmp, '&') - .replace(rLt, '<') - .replace(rGt, '>') - .replace(rApos, ''') - .replace(rQuot, '"') : - str; - } - })(); + var combine = module.exports = { - _.cache = function(max){ - max = max || 1000; - var keys = [], - cache = {}; - return { - set: function(key, value) { - if (keys.length > this.max) { - cache[keys.shift()] = undefined; + // get the initial dom in object + node: function(item){ + var children,node, nodes; + if(!item) return; + if(item.element) return item.element; + if(typeof item.node === "function") return item.node(); + if(typeof item.nodeType === "number") return item; + if(item.group) return combine.node(item.group) + if(children = item.children){ + if(children.length === 1){ + return combine.node(children[0]); } - // - if(cache[key] === undefined){ - keys.push(key); + nodes = []; + for(var i = 0, len = children.length; i < len; i++ ){ + node = combine.node(children[i]); + if(Array.isArray(node)){ + nodes.push.apply(nodes, node) + }else if(node) { + nodes.push(node) + } } - cache[key] = value; - return value; - }, - get: function(key) { - if (key === undefined) return cache; - return cache[key]; - }, - max: max, - len:function(){ - return keys.length; + return nodes; } - }; - } - - // // setup the raw Expression - // _.touchExpression = function(expr){ - // if(expr.type === 'expression'){ - // } - // return expr; - // } + }, + // @TODO remove _gragContainer + inject: function(node, pos ){ + var group = this; + var fragment = combine.node(group.group || group); + if(node === false) { + animate.remove(fragment) + return group; + }else{ + if(!fragment) return group; + if(typeof node === 'string') node = dom.find(node); + if(!node) throw Error('injected node is not found'); + // use animate to animate firstchildren + animate.inject(fragment, node, pos); + } + // if it is a component + if(group.$emit) { + var preParent = group.parentNode; + var newParent = (pos ==='after' || pos === 'before')? node.parentNode : node; + group.parentNode = newParent; + group.$emit("$inject", node, pos, preParent); + } + return group; + }, + // get the last dom in object(for insertion operation) + last: function(item){ + var children = item.children; - // handle the same logic on component's `on-*` and element's `on-*` - // return the fire object - _.handleEvent = function(value, type ){ - var self = this, evaluate; - if(value.type === 'expression'){ // if is expression, go evaluated way - evaluate = value.get; - } - if(evaluate){ - return function fire(obj){ - self.$update(function(){ - var data = this.data; - data.$event = obj; - var res = evaluate(self); - if(res === false && obj && obj.preventDefault) obj.preventDefault(); - data.$event = undefined; - }) + if(typeof item.last === "function") return item.last(); + if(typeof item.nodeType === "number") return item; - } - }else{ - return function fire(){ - var args = slice.call(arguments) - args.unshift(value); - self.$update(function(){ - self.$emit.apply(self, args); - }) - } - } - } + if(children && children.length) return combine.last(children[children.length - 1]); + if(item.group) return combine.last(item.group); - // only call once - _.once = function(fn){ - var time = 0; - return function(){ - if( time++ === 0) fn.apply(this, arguments); - } - } + }, - _.fixObjStr = function(str){ - if(str.trim().indexOf('{') !== 0){ - return '{' + str + '}'; + destroy: function(item, first){ + if(!item) return; + if(Array.isArray(item)){ + for(var i = 0, len = item.length; i < len; i++ ){ + combine.destroy(item[i], first); + } + } + var children = item.children; + if(typeof item.destroy === "function") return item.destroy(first); + if(typeof item.nodeType === "number" && first) dom.remove(item); + if(children && children.length){ + combine.destroy(children, true); + item.children = null; + } } - return str; + } - _.map= function(array, callback){ - var res = []; - for (var i = 0, len = array.length; i < len; i++) { - res.push(callback(array[i], i)); + // @TODO: need move to dom.js + dom.element = function( component, all ){ + if(!component) return !all? null: []; + var nodes = combine.node( component ); + if( nodes.nodeType === 1 ) return all? [nodes]: nodes; + var elements = []; + for(var i = 0; i true - * isArray(arguments); - * // > false - * isArray(''); - * // > false - * - * @param {mixed} val - * @return {bool} - */ - - module.exports = isArray || function (val) { - return !! val && '[object Array]' == str.call(val); - }; - - -/***/ }, -/* 47 */ -/***/ function(module, exports, __webpack_require__) { - exports.read = function(buffer, offset, isLE, mLen, nBytes) { var e, m, eLen = nBytes * 8 - mLen - 1, @@ -14212,6 +14213,45 @@ }; +/***/ }, +/* 47 */ +/***/ function(module, exports, __webpack_require__) { + + + /** + * isArray + */ + + var isArray = Array.isArray; + + /** + * toString + */ + + var str = Object.prototype.toString; + + /** + * Whether or not the given `val` + * is an array. + * + * example: + * + * isArray([]); + * // > true + * isArray(arguments); + * // > false + * isArray(''); + * // > false + * + * @param {mixed} val + * @return {bool} + */ + + module.exports = isArray || function (val) { + return !! val && '[object Array]' == str.call(val); + }; + + /***/ }, /* 48 */ /***/ function(module, exports, __webpack_require__) { diff --git a/test/spec/browser-bugfix.js b/test/spec/browser-bugfix.js index a771929..a02d6ea 100644 --- a/test/spec/browser-bugfix.js +++ b/test/spec/browser-bugfix.js @@ -612,6 +612,46 @@ it('bugfix #50', function(){ expect(line.$refs.line.getAttribute('class')).to.equal('active') }) + + it('feature #82', function(){ + var i = 0; + var mixins = { + events: { + $afterConfig: function(){ + i++; + expect(i).to.equal(3) + }, + $config: function(){ + i++; + expect(i).to.equal(1) + }, + $init: function(){ + i++; + expect(i).to.equal(4) + + }, + $afterInit: function(){ + i++; + expect(i).to.equal(6) + } + } + } + + var Component = Regular.extend({ + config: function(){ + i++; + expect(i).to.equal(2) + }, + init: function(){ + i++; + expect(i).to.equal(5) + } + }).implement(mixins) + + new Component(); + + expect(i).to.equal(6); + }) })