(function (global, factory) { typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory() : typeof define === 'function' && define.amd ? define(factory) : (global.Intact = factory()); }(this, (function () { 'use strict'; var _typeof = typeof Symbol === "function" && typeof Symbol.iterator === "symbol" ? function (obj) { return typeof obj; } : function (obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; }; var toString$1 = Object.prototype.toString; var doc = typeof document === 'undefined' ? {} : document; var isArray = Array.isArray || function (arr) { return toString$1.call(arr) === '[object Array]'; }; function isObject$1(o) { return (typeof o === 'undefined' ? 'undefined' : _typeof(o)) === 'object' && o !== null; } function isStringOrNumber(o) { var type = typeof o === 'undefined' ? 'undefined' : _typeof(o); return type === 'string' || type === 'number'; } function isNullOrUndefined(o) { return o === null || o === undefined; } function isComponentInstance(o) { return o && typeof o.init === 'function'; } function isEventProp(propName) { return propName.substr(0, 3) === 'ev-'; } var indexOf = function () { if (Array.prototype.indexOf) { return function (arr, value) { return arr.indexOf(value); }; } else { return function (arr, value) { for (var i = 0; i < arr.length; i++) { if (arr[i] === value) { return i; } } return -1; }; } }(); var SimpleMap = typeof Map === 'function' ? Map : function () { function SimpleMap() { this._keys = []; this._values = []; this.size = 0; } SimpleMap.prototype.set = function (key, value) { var index = indexOf(this._keys, key); if (!~index) { index = this._keys.push(key) - 1; this.size++; } this._values[index] = value; return this; }; SimpleMap.prototype.get = function (key) { var index = indexOf(this._keys, key); if (!~index) return; return this._values[index]; }; SimpleMap.prototype.delete = function (key) { var index = indexOf(this._keys, key); if (!~index) return false; this._keys.splice(index, 1); this._values.splice(index, 1); this.size--; return true; }; return SimpleMap; }(); var skipProps = { key: true, ref: true, children: true, className: true, checked: true, multiple: true, defaultValue: true, 'v-model': true }; function isSkipProp(prop) { // treat prop which start with '_' as private prop, so skip it return skipProps[prop] || prop[0] === '_'; } var booleanProps = { muted: true, scoped: true, loop: true, open: true, checked: true, default: true, capture: true, disabled: true, readOnly: true, required: true, autoplay: true, controls: true, seamless: true, reversed: true, allowfullscreen: true, noValidate: true, hidden: true, autofocus: true, selected: true, indeterminate: true, multiple: true }; var strictProps = { volume: true, defaultChecked: true, value: true, htmlFor: true, scrollLeft: true, scrollTop: true }; var selfClosingTags = { 'area': true, 'base': true, 'br': true, 'col': true, 'command': true, 'embed': true, 'hr': true, 'img': true, 'input': true, 'keygen': true, 'link': true, 'menuitem': true, 'meta': true, 'param': true, 'source': true, 'track': true, 'wbr': true }; function MountedQueue() { this.queue = []; // if done is true, it indicate that this queue should be discarded this.done = false; } MountedQueue.prototype.push = function (fn) { this.queue.push(fn); }; MountedQueue.prototype.unshift = function (fn) { this.queue.unshift(fn); }; MountedQueue.prototype.trigger = function () { var queue = this.queue; var callback = void 0; while (callback = queue.shift()) { callback(); } this.done = true; }; var browser = {}; if (typeof navigator !== 'undefined') { var ua = navigator.userAgent.toLowerCase(); var index = ua.indexOf('msie '); if (~index) { browser.isIE = true; var version = parseInt(ua.substring(index + 5, ua.indexOf('.', index)), 10); browser.version = version; browser.isIE8 = version === 8; } else if (~ua.indexOf('trident/')) { browser.isIE = true; var rv = ua.indexOf('rv:'); browser.version = parseInt(ua.substring(rv + 3, ua.indexOf('.', rv)), 10); } else if (~ua.indexOf('edge')) { browser.isEdge = true; } else if (~ua.indexOf('safari')) { if (~ua.indexOf('chrome')) { browser.isChrome = true; } else { browser.isSafari = true; } } } var setTextContent = browser.isIE8 ? function (dom, text) { dom.innerText = text; } : function (dom, text) { dom.textContent = text; }; var svgNS = "http://www.w3.org/2000/svg"; var xlinkNS = "http://www.w3.org/1999/xlink"; var xmlNS = "http://www.w3.org/XML/1998/namespace"; var namespaces = { 'xlink:href': xlinkNS, 'xlink:arcrole': xlinkNS, 'xlink:actuate': xlinkNS, 'xlink:show': xlinkNS, 'xlink:role': xlinkNS, 'xlink:title': xlinkNS, 'xlink:type': xlinkNS, 'xml:base': xmlNS, 'xml:lang': xmlNS, 'xml:space': xmlNS }; var hooks = { beforeInsert: null }; var config = { disableDelegate: false, // for using in React/Vue, disable delegate the event delegateTarget: doc }; /** * @fileoverview utility methods * @author javey * @date 15-4-22 */ var i = 0; var Type = { JS: i++, JSImport: i++, JSXText: i++, JSXUnescapeText: i++, JSXElement: i++, JSXExpressionContainer: i++, JSXAttribute: i++, JSXEmptyExpression: i++, JSXWidget: i++, JSXVdt: i++, JSXBlock: i++, JSXComment: i++, JSXDirective: i++, JSXTemplate: i++, JSXString: i++ }; var TypeName = []; for (var type in Type) { TypeName[Type[type]] = type; } // which children must be text var TextTags = { style: true, script: true, textarea: true }; var Directives = { 'v-if': true, 'v-else-if': true, 'v-else': true, 'v-for': true, 'v-for-value': true, 'v-for-key': true, 'v-raw': true }; var Options = { autoReturn: true, onlySource: false, delimiters: ['{', '}'], // remove `with` statement noWith: false, // whether rendering on server or not server: false, // skip all whitespaces in template skipWhitespace: true, setModel: function setModel(data, key, value, self) { data[key] = value; self.update(); }, getModel: function getModel(data, key) { return data[key]; }, disableSplitText: false, // split text with sourceMap: false, indent: ' ' // code indent style }; var hasOwn = Object.prototype.hasOwnProperty; var noop = function noop() {}; function isArrayLike(value) { if (isNullOrUndefined(value)) return false; var length = value.length; return typeof length === 'number' && length > -1 && length % 1 === 0 && length <= 9007199254740991 && typeof value !== 'function'; } function each(obj, iter, thisArg) { if (isArrayLike(obj)) { for (var i = 0, l = obj.length; i < l; i++) { iter.call(thisArg, obj[i], i, obj); } } else if (isObject$$1(obj)) { for (var key in obj) { if (hasOwn.call(obj, key)) { iter.call(thisArg, obj[key], key, obj); } } } } function isObject$$1(obj) { var type = typeof obj === 'undefined' ? 'undefined' : _typeof(obj); return type === 'function' || type === 'object' && !!obj; } function map(obj, iter, thisArgs) { var ret = []; each(obj, function (value, key, obj) { ret.push(iter.call(thisArgs, value, key, obj)); }); return ret; } function className(obj) { if (isNullOrUndefined(obj)) return; if (typeof obj === 'string') return obj; var ret = []; for (var key in obj) { if (hasOwn.call(obj, key) && obj[key]) { ret.push(key); } } return ret.join(' '); } function isWhiteSpace(charCode) { return charCode <= 160 && charCode >= 9 && charCode <= 13 || charCode == 32 || charCode == 160 || charCode == 5760 || charCode == 6158 || charCode >= 8192 && (charCode <= 8202 || charCode == 8232 || charCode == 8233 || charCode == 8239 || charCode == 8287 || charCode == 12288 || charCode == 65279); } function isWhiteSpaceExpectLinebreak(charCode) { return charCode !== 10 && // \n charCode !== 13 && // \r isWhiteSpace(charCode); } function trimRight(str) { var index = str.length; while (index-- && isWhiteSpace(str.charCodeAt(index))) {} return str.slice(0, index + 1); } function trimLeft(str) { var length = str.length, index = -1; while (index++ < length && isWhiteSpace(str.charCodeAt(index))) {} return str.slice(index); } function setDelimiters(delimiters) { if (!isArray(delimiters)) { throw new Error('The parameter must be an array like ["{{", "}}"]'); } Options.delimiters = delimiters; } function getDelimiters() { return Options.delimiters; } function configure(key, value) { if (typeof key === 'string') { if (value === undefined) { return Options[key]; } else { Options[key] = value; } } else if (isObject$$1(key)) { extend(Options, key); } return Options; } function isSelfClosingTag(tag) { return selfClosingTags[tag]; } function isTextTag(tag) { return TextTags[tag]; } function isDirective(name) { return hasOwn.call(Directives, name); } function isVModel(name) { return name === 'v-model' || name.substr(0, 8) === 'v-model:'; } function extend() { for (var _len = arguments.length, args = Array(_len), _key = 0; _key < _len; _key++) { args[_key] = arguments[_key]; } var dest = args[0]; var length = args.length; if (length > 1) { for (var i = 1; i < length; i++) { var source = args[i]; if (source) { for (var key in source) { if (hasOwn.call(source, key)) { dest[key] = source[key]; } } } } } return dest; } function setCheckboxModel(data, key, trueValue, falseValue, e, self) { var value = Options.getModel(data, key), checked = e.target.checked; if (isArray(value)) { value = value.slice(0); var index = indexOf(value, trueValue); if (checked) { if (!~index) { value.push(trueValue); } } else { if (~index) { value.splice(index, 1); } } } else { value = checked ? trueValue : falseValue; } Options.setModel(data, key, value, self); } function detectCheckboxChecked(data, key, trueValue) { var value = Options.getModel(data, key); if (isArray(value)) { return indexOf(value, trueValue) > -1; } else { return value === trueValue; } } function setSelectModel(data, key, e, self) { var target = e.target, multiple = target.multiple, value, i, opt, options = target.options; if (multiple) { value = []; for (i = 0; i < options.length; i++) { opt = options[i]; if (opt.selected) { value.push(isNullOrUndefined(opt._value) ? opt.value : opt._value); } } } else { for (i = 0; i < options.length; i++) { opt = options[i]; if (opt.selected) { value = isNullOrUndefined(opt._value) ? opt.value : opt._value; break; } } } Options.setModel(data, key, value, self); } var slice = Array.prototype.slice; // in ie8 console.log is an object var hasConsole = typeof console !== 'undefined' && typeof console.log === 'function'; var error$2 = hasConsole ? function (e) { console.error(e.stack); } : noop; var utils$1 = (Object.freeze || Object)({ isNullOrUndefined: isNullOrUndefined, isArray: isArray, indexOf: indexOf, SelfClosingTags: selfClosingTags, isEventProp: isEventProp, Type: Type, TypeName: TypeName, TextTags: TextTags, Directives: Directives, Options: Options, hasOwn: hasOwn, noop: noop, each: each, isObject: isObject$$1, map: map, className: className, isWhiteSpace: isWhiteSpace, isWhiteSpaceExpectLinebreak: isWhiteSpaceExpectLinebreak, trimRight: trimRight, trimLeft: trimLeft, setDelimiters: setDelimiters, getDelimiters: getDelimiters, configure: configure, isSelfClosingTag: isSelfClosingTag, isTextTag: isTextTag, isDirective: isDirective, isVModel: isVModel, extend: extend, setCheckboxModel: setCheckboxModel, detectCheckboxChecked: detectCheckboxChecked, setSelectModel: setSelectModel, slice: slice, hasConsole: hasConsole, error: error$2 }); /** * @fileoverview parse jsx to ast * @author javey * @date 15-4-22 */ var Type$1 = Type; var TypeName$1 = TypeName; var elementNameRegexp = /^<\w+:?\s*[\{\w\/>]/; // const importRegexp = /^\s*\bimport\b/; function isJSIdentifierPart(ch) { return ch === 95 || ch === 36 || // _ (underscore) $ ch >= 65 && ch <= 90 || // A..Z ch >= 97 && ch <= 122 || // a..z ch >= 48 && ch <= 57; // 0..9 } function isJSXIdentifierPart(ch) { return ch === 58 || ch === 45 || ch === 46 || isJSIdentifierPart(ch); // : - . } function Parser() { this.source = ''; this.index = 0; this.length = 0; } Parser.prototype = { constructor: Parser, parse: function parse(source, options) { this.source = trimRight(source); this.index = 0; this.line = 1; this.column = 0; this.length = this.source.length; this.options = extend({}, configure(), options); return this._parseTemplate(true); }, _parseTemplate: function _parseTemplate(isRoot) { var elements = [], braces = { count: 0 }; while (this.index < this.length && braces.count >= 0) { elements.push(this._advance(braces, isRoot)); } return elements; }, _advance: function _advance(braces, isRoot) { var ch = this._char(); if (isRoot && this._isJSImport()) { return this._scanJSImport(); } else if (ch !== '<') { return this._scanJS(braces, isRoot); } else { return this._scanJSX(); } }, _scanJS: function _scanJS(braces, isRoot) { var start = this.index, tmp, Delimiters = this.options.delimiters, element = this._type(Type$1.JS); while (this.index < this.length) { this._skipJSComment(); var ch = this._char(); var tmp; if (ch === '\'' || ch === '"' || ch === '`' || // is a RegExp, treat it as literal sting ch === '/' && ( // is not /* and //, this is comment tmp = this._char(this.index + 1)) && tmp !== '*' && tmp !== '/' && ( // is the first char this.index === 0 || // is not 1) /test/` tmp = this._getLastCharCode()) && !isJSIdentifierPart(tmp) && tmp !== 41 // ) )) { // skip element(
) in quotes this._scanStringLiteral(); } else if (this._isElementStart()) { break; } else if (isRoot && this._isJSImport()) { break; } else { if (ch === '{') { braces.count++; } else if (braces.count > 0 && ch === '}') { braces.count--; } else if (this._isExpect(Delimiters[1])) { // for parseTemplate break braces.count--; break; } else if (ch === '\n') { this._updateLine(); } this._updateIndex(); } } element.value = this.source.slice(start, this.index); return element; }, _scanJSImport: function _scanJSImport() { var start = this.index, element = this._type(Type$1.JSImport); this._updateIndex(7); // 'import '.length while (this.index < this.length) { var ch = this._char(); if (ch === '\'' || ch === '"') { this._scanStringLiteral(); var _start2 = void 0; do { _start2 = this.index; this._skipWhitespaceAndJSComment(); if (this._char() === ';') { this._updateIndex(); } } while (_start2 !== this.index); break; } else { this._updateIndex(); } } element.value = this.source.slice(start, this.index); return element; }, _scanStringLiteral: function _scanStringLiteral() { var quote = this._char(), start = this.index, str = '', element = this._type(Type$1.StringLiteral); this._updateIndex(); while (this.index < this.length) { var ch = this._char(); if (ch.charCodeAt(0) === 10) { this._updateLine(); } this._updateIndex(); if (ch === quote) { quote = ''; break; } else if (ch === '\\') { str += this._char(this._updateIndex()); } else { str += ch; } } if (quote !== '') { this._error('Unclosed quote'); } element.value = this.source.slice(start, this.index); return element; }, _scanJSX: function _scanJSX() { return this._parseJSXElement(); }, _scanJSXText: function _scanJSXText(stopChars) { var start = this.index, l = stopChars.length, i, charCode, element = this._type(Type$1.JSXText); loop: while (this.index < this.length) { charCode = this._charCode(); if (isWhiteSpace(charCode)) { if (charCode === 10) { this._updateLine(); } } else { for (i = 0; i < l; i++) { if (typeof stopChars[i] === 'function' && stopChars[i].call(this) || this._isExpect(stopChars[i])) { break loop; } } } this._updateIndex(); } element.value = this.source.slice(start, this.index); return element; }, _scanJSXStringLiteral: function _scanJSXStringLiteral() { var quote = this._char(); if (quote !== '\'' && quote !== '"' && quote !== '`') { this._error('String literal must starts with a qoute'); } this._updateIndex(); var token = this._scanJSXText([quote]); this._updateIndex(); return token; }, _parseJSXElement: function _parseJSXElement(prev) { this._expect('<'); var start = this.index, ret = {}, flag = this._charCode(); if (flag >= 65 && flag <= 90 /* upper case */) { // is a widget this._type(Type$1.JSXWidget, ret); } else if (this._isExpect('!--')) { // is html comment return this._parseJSXComment(); } else if (this._charCode(this.index + 1) === 58 /* : */) { // is a directive start += 2; switch (flag) { case 116: // t this._type(Type$1.JSXVdt, ret); break; case 98: // b this._type(Type$1.JSXBlock, ret); break; default: this._error('Unknown directive ' + String.fromCharCode(flag) + ':'); } this._updateIndex(2); } else { // is an element this._type(Type$1.JSXElement, ret); } while (this.index < this.length) { if (!isJSXIdentifierPart(this._charCode())) { break; } this._updateIndex(); } ret.value = this.source.slice(start, this.index); return this._parseAttributeAndChildren(ret, prev); }, _parseAttributeAndChildren: function _parseAttributeAndChildren(ret, prev) { ret.children = []; this._parseJSXAttribute(ret, prev); if (ret.type === Type$1.JSXElement && isSelfClosingTag(ret.value)) { // self closing tag if (this._char() === '/') { this._updateIndex(); } this._expect('>'); } else if (this._char() === '/') { // unknown self closing tag this._updateIndex(); this._expect('>'); } else { this._expect('>'); if (isTextTag(ret.value)) { // if it is a text element, treat children as innerHTML attribute var attr = this._type(Type$1.JSXAttribute, { name: 'innerHTML', value: this._type(Type$1.JSXString) }); var children = this._parseJSXChildren(ret, ret.hasVRaw); if (children.length) { attr.value.value = children; ret.attributes.push(attr); } } else { ret.children = this._parseJSXChildren(ret, ret.hasVRaw); } } return ret; }, _parseJSXAttribute: function _parseJSXAttribute(ret, prev) { ret = extend(ret, { attributes: [], directives: {}, hasVRaw: false }); while (this.index < this.length) { this._skipWhitespace(); if (this._char() === '/' || this._char() === '>') { break; } else { var Delimiters = this.options.delimiters; if (this._isExpect(Delimiters[0])) { // support dynamic attributes ret.attributes.push(this._parseJSXExpressionContainer()); continue; } var attr = this._parseJSXAttributeName(ret, prev); if (attr.name === 'v-raw') { ret.hasVRaw = true; continue; } if (this._char() === '=') { this._updateIndex(); attr.value = this._parseJSXAttributeValue(); } else { // treat no-value attribute as true attr.value = this._type(Type$1.JSXExpressionContainer, { value: [this._type(Type$1.JS, { value: 'true' })] }); } if (attr.type === Type$1.JSXAttribute) { ret.attributes.push(attr); } else { ret.directives[attr.name] = attr; } } } return ret; }, _parseJSXAttributeName: function _parseJSXAttributeName(ret, prev) { var start = this.index; var line = this.line; var column = this.column; var element = void 0; if (!isJSXIdentifierPart(this._charCode())) { this._error('Unexpected identifier ' + this._char()); } while (this.index < this.length) { var ch = this._charCode(); if (!isJSXIdentifierPart(ch)) { break; } this._updateIndex(); } var name = this.source.slice(start, this.index); if (isDirective(name)) { element = this._type(Type$1.JSXDirective, { name: name }); this._parseJSXAttributeVIf(ret, element, prev); } else { element = this._type(Type$1.JSXAttribute, { name: name }); } element.line = line; element.column = column; return element; }, _parseJSXAttributeVIf: function _parseJSXAttributeVIf(ret, attr, prev) { var name = attr.name; if (name === 'v-else-if' || name === 'v-else') { var emptyTextNodes = []; // persist empty text node, skip them if find v-else-if or v-else var skipNodes = function skipNodes() { each(emptyTextNodes, function (item) { item.skip = true; }); emptyTextNodes = []; }; prev = { prev: prev }; while (prev = prev.prev) { if (prev.type === Type$1.JSXText && /^\s*$/.test(prev.value)) { emptyTextNodes.push(prev); continue; } var type = prev.type; if (type === Type$1.JSXComment) continue; if (type === Type$1.JSXElement || type === Type$1.JSXWidget || type === Type$1.JSXVdt || type === Type$1.JSXBlock) { var prevDirectives = prev.directives; if (prevDirectives['v-if'] || prevDirectives['v-else-if']) { prev.next = ret; ret.skip = true; skipNodes(); } } break; } if (!ret.skip) { this._error(name + ' must be led with v-if or v-else-if'); } } }, _parseJSXAttributeValue: function _parseJSXAttributeValue() { var value, Delimiters = this.options.delimiters; if (this._isExpect(Delimiters[0])) { value = this._parseJSXExpressionContainer(); } else { value = this._scanJSXStringLiteral(); } return value; }, _parseJSXExpressionContainer: function _parseJSXExpressionContainer() { var expression, Delimiters = this.options.delimiters, element = this._type(Type$1.JSXExpressionContainer); this._expect(Delimiters[0]); this._skipWhitespaceAndJSComment(); if (this._isExpect(Delimiters[1])) { expression = [this._parseJSXEmptyExpression()]; } else if (this._isExpect('=')) { // if the lead char is '=', then treat it as unescape string this._skipWhitespace(); expression = this._parseJSXUnescapeText(); this._expect(Delimiters[1], 'Unclosed delimiter', expression); return expression; } else { expression = this._parseExpression(); } this._expect(Delimiters[1], 'Unclosed delimiter', element); element.value = expression; return element; }, _parseJSXEmptyExpression: function _parseJSXEmptyExpression() { return this._type(Type$1.JSXEmptyExpression, { value: null }); }, _parseExpression: function _parseExpression() { return this._parseTemplate(); }, _parseJSXUnescapeText: function _parseJSXUnescapeText() { this._expect('='); return this._type(Type$1.JSXUnescapeText, { value: this._parseTemplate() }); }, _parseJSXChildren: function _parseJSXChildren(element, hasVRaw) { var children = [], endTag = element.value + '>', current = null; switch (element.type) { case Type$1.JSXBlock: endTag = ''); }, _parseJSXComment: function _parseJSXComment() { this._expect('!--'); var start = this.index, element = this._type(Type$1.JSXComment); while (this.index < this.length) { if (this._isExpect('-->')) { break; } else if (this._charCode() === 10) { this._updateLine(); } this._updateIndex(); } element.value = this.source.slice(start, this.index); this._expect('-->'); return element; }, _char: function _char() { var index = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : this.index; return this.source.charAt(index); }, _charCode: function _charCode() { var index = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : this.index; return this.source.charCodeAt(index); }, _skipWhitespaceBetweenElements: function _skipWhitespaceBetweenElements(endTag) { var skipBeforeDelimiter = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : true; if (!this.options.skipWhitespace) return; var Delimiters = this.options.delimiters; var start = this.index; while (start < this.length) { var code = this._charCode(start); if (isWhiteSpace(code)) { start++; } else if (this._isExpect(endTag, start) || this._isElementStart(start) || // skip whitespaces between after element starting and expression // but not skip before element ending skipBeforeDelimiter && this._isExpect(Delimiters[0], start)) { this._skipWhitespace(); break; } else { break; } } }, _skipWhitespace: function _skipWhitespace() { while (this.index < this.length) { var code = this._charCode(); if (!isWhiteSpace(code)) { break; } else if (code === 10) { // is \n this._updateLine(); } this._updateIndex(); } }, _skipJSComment: function _skipJSComment() { var start = void 0; do { start = this.index; if (this._char() === '/') { var ch = this._char(this.index + 1); if (ch === '/') { this._updateIndex(2); while (this.index < this.length) { var code = this._charCode(); this._updateIndex(); if (code === 10) { // is \n this._updateLine(); break; } } } else if (ch === '*') { this._updateIndex(2); while (this.index < this.length) { if (this._isExpect('*/')) { this._updateIndex(2); break; } else if (this._charCode() === 10) { this._updateLine(); } this._updateIndex(); } } } } while (start !== this.index); }, _skipWhitespaceAndJSComment: function _skipWhitespaceAndJSComment() { var start = void 0; do { start = this.index; this._skipWhitespace(); this._skipJSComment(); } while (start !== this.index); }, _expect: function _expect(str, msg, element) { if (!this._isExpect(str)) { this._error(msg || 'Expect string ' + str, element); } this._updateIndex(str.length); }, _isExpect: function _isExpect(str) { var index = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : this.index; return this.source.slice(index, index + str.length) === str; }, _isElementStart: function _isElementStart() { var index = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : this.index; return this._char(index) === '<' && (this._isExpect('') + (children === '' ? ' ' : escapeText(children)); } else if (type & Types.HtmlComment) { html = ''; } else if (type & Types.UnescapeText) { html = isNullOrUndefined(children) ? '' : children; } else { throw new Error('Unknown vNode: ' + vNode); } return html; } function escapeText(text) { var result = text; var escapeString = ""; var start = 0; var i = void 0; for (i = 0; i < text.length; i++) { switch (text.charCodeAt(i)) { case 34: // " escapeString = """; break; case 39: // \ escapeString = "'"; break; case 38: // & escapeString = "&"; break; case 60: // < escapeString = "<"; break; case 62: // > escapeString = ">"; break; default: continue; } if (start) { result += text.slice(start, i); } else { result = text.slice(start, i); } result += escapeString; start = i + 1; } if (start && i !== start) { return result + text.slice(start, i); } return result; } function isString$1(o) { return typeof o === 'string'; } function isNumber(o) { return typeof o === 'number'; } function renderStylesToString(styles) { if (isStringOrNumber(styles)) { return styles; } else { var renderedString = ""; for (var styleName in styles) { var value = styles[styleName]; if (isStringOrNumber(value)) { renderedString += kebabCase(styleName) + ':' + value + ';'; } } return renderedString; } } function renderDatasetToString(dataset) { var renderedString = ''; for (var key in dataset) { var dataKey = 'data-' + kebabCase(key); var value = dataset[key]; if (isString$1(value)) { renderedString += ' ' + dataKey + '="' + escapeText(value) + '"'; } else if (isNumber(value)) { renderedString += ' ' + dataKey + '="' + value + '"'; } else if (value === true) { renderedString += ' ' + dataKey + '="true"'; } } return renderedString; } function renderAttributesToString(attributes) { var renderedString = ''; for (var key in attributes) { renderedString += renderAttributeToString(key, attributes[key]); } return renderedString; } function renderAttributeToString(key, value) { if (isString$1(value)) { return ' ' + key + '="' + escapeText(value) + '"'; } else if (isNumber(value)) { return ' ' + key + '="' + value + '"'; } else if (value === true) { return ' ' + key; } else { return ''; } } function hydrateRoot(vNode, parentDom, mountedQueue) { if (!isNullOrUndefined(parentDom)) { var dom = parentDom.firstChild; if (isNullOrUndefined(dom)) { return render(vNode, parentDom, mountedQueue, null, false); } var newDom = hydrate(vNode, dom, mountedQueue, parentDom, null, false); dom = dom.nextSibling; // should only one entry while (dom) { var next = dom.nextSibling; parentDom.removeChild(dom); dom = next; } return newDom; } return null; } function hydrate(vNode, dom, mountedQueue, parentDom, parentVNode, isSVG) { if (dom !== null) { var isTrigger = true; if (mountedQueue) { isTrigger = false; } else { mountedQueue = new MountedQueue(); } dom = hydrateElement(vNode, dom, mountedQueue, parentDom, parentVNode, isSVG); if (isTrigger) { mountedQueue.trigger(); } } return dom; } function hydrateElement(vNode, dom, mountedQueue, parentDom, parentVNode, isSVG) { var type = vNode.type; if (type & Types.Element) { return hydrateHtmlElement(vNode, dom, mountedQueue, parentDom, parentVNode, isSVG); } else if (type & Types.Text) { return hydrateText(vNode, dom); } else if (type & Types.HtmlComment) { return hydrateComment(vNode, dom); } else if (type & Types.ComponentClassOrInstance) { return hydrateComponentClassOrInstance(vNode, dom, mountedQueue, parentDom, parentVNode, isSVG); } } function hydrateComponentClassOrInstance(vNode, dom, mountedQueue, parentDom, parentVNode, isSVG) { return createOrHydrateComponentClassOrInstance(vNode, parentDom, mountedQueue, null, true, parentVNode, isSVG, function (instance) { var newDom = instance.hydrate(vNode, dom); if (dom !== newDom && dom.parentNode) { dom.parentNode.replaceChild(newDom, dom); } return newDom; }); } function hydrateComment(vNode, dom) { if (dom.nodeType !== 8) { var newDom = createCommentElement(vNode, null); dom.parentNode.replaceChild(newDom, dom); return newDom; } var comment = vNode.children; if (dom.data !== comment) { dom.data = comment; } vNode.dom = dom; return dom; } function hydrateText(vNode, dom) { if (dom.nodeType !== 3) { var newDom = createTextElement(vNode, null); dom.parentNode.replaceChild(newDom, dom); return newDom; } var text = vNode.children; if (dom.nodeValue !== text) { dom.nodeValue = text; } vNode.dom = dom; return dom; } function hydrateHtmlElement(vNode, dom, mountedQueue, parentDom, parentVNode, isSVG) { var children = vNode.children; var props = vNode.props; var className = vNode.className; var type = vNode.type; var ref = vNode.ref; vNode.parentVNode = parentVNode; isSVG = isSVG || (type & Types.SvgElement) > 0; if (dom.nodeType !== 1 || dom.tagName.toLowerCase() !== vNode.tag) { warning('Server-side markup doesn\'t match client-side markup'); var newDom = createElement(vNode, null, mountedQueue, parentDom, parentVNode, isSVG); dom.parentNode.replaceChild(newDom, dom); return newDom; } vNode.dom = dom; if (!isNullOrUndefined(children)) { hydrateChildren(children, dom, mountedQueue, vNode, isSVG); } else if (dom.firstChild !== null) { setTextContent(dom, ''); } if (props !== EMPTY_OBJ) { var isFormElement = (type & Types.FormElement) > 0; for (var prop in props) { patchProp(prop, null, props[prop], dom, isFormElement, isSVG); } if (isFormElement) { processForm(vNode, dom, props, true); } } if (!isNullOrUndefined(className)) { if (isSVG) { dom.setAttribute('class', className); } else { dom.className = className; } } else if (dom.className !== '') { dom.removeAttribute('class'); } if (ref) { createRef(dom, ref, mountedQueue); } return dom; } function hydrateChildren(children, parentDom, mountedQueue, parentVNode, isSVG) { normalizeChildren$1(parentDom); var dom = parentDom.firstChild; if (isStringOrNumber(children)) { if (dom !== null && dom.nodeType === 3) { if (dom.nodeValue !== children) { dom.nodeValue = children; } } else if (children === '') { parentDom.appendChild(document.createTextNode('')); } else { setTextContent(parentDom, children); } if (dom !== null) { dom = dom.nextSibling; } } else if (isArray(children)) { for (var i = 0; i < children.length; i++) { var child = children[i]; if (!isNullOrUndefined(child)) { if (dom !== null) { var nextSibling = dom.nextSibling; hydrateElement(child, dom, mountedQueue, parentDom, parentVNode, isSVG); dom = nextSibling; } else { createElement(child, parentDom, mountedQueue, true, parentVNode, isSVG); } } } } else { if (dom !== null) { hydrateElement(children, dom, mountedQueue, parentDom, parentVNode, isSVG); dom = dom.nextSibling; } else { createElement(children, parentDom, mountedQueue, true, parentVNode, isSVG); } } // clear any other DOM nodes, there should be on a single entry for the root while (dom) { var _nextSibling = dom.nextSibling; parentDom.removeChild(dom); dom = _nextSibling; } } function normalizeChildren$1(parentDom) { var dom = parentDom.firstChild; while (dom) { if (dom.nodeType === 8 && dom.data === '') { var lastDom = dom.previousSibling; parentDom.removeChild(dom); dom = lastDom || parentDom.firstChild; } else { dom = dom.nextSibling; } } } var warning = (typeof console === 'undefined' ? 'undefined' : _typeof(console)) === 'object' ? function (message) { console.warn(message); } : function () {}; var miss = (Object.freeze || Object)({ h: createVNode, patch: patch, render: render, hc: createCommentVNode, hu: createUnescapeTextVNode, remove: removeElement, MountedQueue: MountedQueue, renderString: toString$2, hydrateRoot: hydrateRoot, hydrate: hydrate, Types: Types, VNode: VNode, hooks: hooks, clone: directClone, config: config }); var parser = new Parser(); var stringifier = new Stringifier(); function Vdt$1(source, options) { if (!(this instanceof Vdt$1)) return new Vdt$1(source, options); this.template = compile(source, options); this.data = null; this.vNode = null; this.node = null; this.widgets = {}; this.blocks = {}; } Vdt$1.prototype = { constructor: Vdt$1, render: function render$$1(data, parentDom, queue, parentVNode, isSVG, blocks) { this.renderVNode(data, blocks, parentVNode); this.node = render(this.vNode, parentDom, queue, parentVNode, isSVG); return this.node; }, renderVNode: function renderVNode(data, blocks, parentVNode) { if (data !== undefined) { this.data = data; } this.blocks = blocks; var vNode = this.vNode = this.template(this.data, Vdt$1, this.blocks, this.template) || createCommentVNode('empty'); // for Animate we need this key if (vNode.key === undefined && parentVNode) { vNode.key = parentVNode.key; } return vNode; }, renderString: function renderString$$1(data, blocks, parent) { this.data = data; var vNode = this.template(data, Vdt$1, blocks, this.template) || createCommentVNode('empty'); return toString$2(vNode, parent, Vdt$1.configure().disableSplitText); }, update: function update(data, parentDom, queue, parentVNode, isSVG, blocks) { var oldVNode = this.vNode; this.renderVNode(data, blocks, parentVNode); this.node = patch(oldVNode, this.vNode, parentDom, queue, parentVNode, isSVG); return this.node; }, hydrate: function hydrate$$1(data, dom, queue, parentDom, parentVNode, isSVG, blocks) { this.renderVNode(data, blocks, parentVNode); hydrate(this.vNode, dom, queue, parentDom, parentVNode, isSVG); this.node = this.vNode.dom; return this.node; }, destroy: function destroy() { removeElement(this.vNode); } }; function compile(source, options) { var templateFn; // backward compatibility v0.2.2 if (options === true || options === false) { options = { autoReturn: options }; } options = extend({}, configure(), options); switch (typeof source === 'undefined' ? 'undefined' : _typeof(source)) { case 'string': var ast = parser.parse(source, options), hscript = stringifier.stringify(ast, options); if (options.onlySource) { templateFn = function templateFn() {}; } else { var buffer = stringifier.buffer; templateFn = new Function('obj', '_Vdt', 'blocks', '$callee', buffer.slice(1, buffer.length - 1).join('')); } templateFn.source = hscript; templateFn.head = stringifier.head; templateFn.mappings = stringifier.mappings; break; case 'function': templateFn = source; break; default: throw new Error('Expect a string or function'); } return templateFn; } Vdt$1.parser = parser; Vdt$1.stringifier = stringifier; Vdt$1.miss = extend({}, miss); Vdt$1.compile = compile; Vdt$1.utils = utils$1; Vdt$1.setDelimiters = setDelimiters; Vdt$1.getDelimiters = getDelimiters; Vdt$1.configure = configure; // for compatibility v1.0 Vdt$1.virtualDom = miss; var inBrowser = typeof window !== 'undefined'; var UA = inBrowser && window.navigator.userAgent.toLowerCase(); var isIOS = UA && /iphone|ipad|ipod|ios/.test(UA); var getPrototypeOf = Object.getPrototypeOf; if (!(Object.setPrototypeOf || {}.__proto__)) { // ie <= 10 exists getPrototypeOf but not setPrototypeOf var nativeGetPrototypeOf = Object.getPrototypeOf; if (typeof nativeGetPrototypeOf !== 'function') { getPrototypeOf = function getPrototypeOf(object) { // May break if the constructor has been tampered with return object.__proto__ || object.constructor.prototype; }; } else { getPrototypeOf = function getPrototypeOf(object) { // in ie <= 10 __proto__ is not supported // getPrototypeOf will return a native function // but babel will set __proto__ prototyp to target // so we get __proto__ in this case return object.__proto__ || nativeGetPrototypeOf.call(Object, object); }; } // fix that if ie <= 10 babel can't inherit class static methods // Object.setPrototypeOf = function(O, proto) { // extend(O, proto); // O.__proto__ = proto; // } } /** * inherit * @param Parent * @param prototype * @returns {Function} */ var isSupportGetDescriptor = function () { var a = {}; try { Object.getOwnPropertyDescriptor(a, 'a'); } catch (e) { return false; } return true; }(); function setPrototype(Parent, Child, name, value) { var prototype = Child.prototype; var tmp = void 0; if (isSupportGetDescriptor && (tmp = Object.getOwnPropertyDescriptor(Parent.prototype, name)) && tmp.get) { Object.defineProperty(prototype, name, { get: function get$$1() { return value; }, enumerable: true, configurable: true }); } else { prototype[name] = value; } } function inherit(Parent, prototype) { var Child = function Child() { for (var _len = arguments.length, args = Array(_len), _key = 0; _key < _len; _key++) { args[_key] = arguments[_key]; } return Parent.apply(this, args); }; Child.prototype = create(Parent.prototype); // for ie 8 which does not support getPrototypeOf Child.prototype.__proto__ = Parent.prototype; each(prototype, function (proto, name) { if (name === 'displayName') { Child.displayName = proto; } if (name === 'template') { if (isString(proto)) { proto = Vdt$1.compile(proto); prototype.template = proto; } var _super = Parent.template; if (!_super || _super === templateDecorator) { _super = Parent.prototype.template; } proto._super = _super; Child.template = undefined; return setPrototype(Parent, Child, 'template', proto); } else if (!isFunction(proto)) { Child.prototype[name] = proto; return; } var fn = function () { var _super = function _super() { for (var _len2 = arguments.length, args = Array(_len2), _key2 = 0; _key2 < _len2; _key2++) { args[_key2] = arguments[_key2]; } return Parent.prototype[name].apply(this, args); }, _superApply = function _superApply(args) { return Parent.prototype[name].apply(this, args); }; return function () { var self = this || {}, __super = self._super, __superApply = self._superApply, returnValue = void 0; self._super = _super; self._superApply = _superApply; for (var _len3 = arguments.length, args = Array(_len3), _key3 = 0; _key3 < _len3; _key3++) { args[_key3] = arguments[_key3]; } returnValue = proto.apply(this, args); self._super = __super; self._superApply = __superApply; return returnValue; }; }(); setPrototype(Parent, Child, name, fn); }); Child.prototype.constructor = Child; for (var key in Parent) { if (!hasOwn.call(Child, key)) { Child[key] = Parent[key]; } } Child.__super = Parent.prototype; return Child; } function templateDecorator(options) { return function (target, name, descriptor) { var template = target.template; if (isString(template)) { template = Vdt$1.compile(template, options); } var Parent = getPrototypeOf(target); var _super = void 0; if (typeof Parent === 'function') { // is define by static _super = Parent.template; if (!_super || _super === templateDecorator) { _super = Parent.prototype.template; } } else { // is define by prototype _super = Parent.constructor.template; if (!_super || _super === templateDecorator) { _super = Parent.template; } } template._super = _super; if (typeof target === 'function') { // for: static template = '' target.template = template; return template; } else { // for: get template() { } descriptor.get = function () { return template; }; // remove static template. Maybe it inherited from parent target.constructor.template = undefined; } }; } var nativeCreate = Object.create; var create = nativeCreate ? nativeCreate : function (object) { var fn = function fn() {}; fn.prototype = object; return new fn(); }; function isFunction(obj) { return typeof obj === 'function'; } function isString(s) { return typeof s === 'string'; } function result(obj, property, fallback) { var value = isNullOrUndefined(obj) ? undefined : obj[property]; if (value === undefined) { value = fallback; } return isFunction(value) ? value.call(obj) : value; } var executeBound = function executeBound(sourceFunc, boundFunc, context, callingContext, args) { if (!(callingContext instanceof boundFunc)) return sourceFunc.apply(context, args); var self = create(sourceFunc.prototype); var result = sourceFunc.apply(self, args); if (isObject$$1(result)) return result; return self; }; var nativeBind = Function.prototype.bind; function bind(func, context) { for (var _len4 = arguments.length, args = Array(_len4 > 2 ? _len4 - 2 : 0), _key4 = 2; _key4 < _len4; _key4++) { args[_key4 - 2] = arguments[_key4]; } if (nativeBind && func.bind === nativeBind) { return nativeBind.call.apply(nativeBind, [func, context].concat(args)); } if (!isFunction(func)) throw new TypeError('Bind must be called on a function'); var bound = function bound() { for (var _len5 = arguments.length, args1 = Array(_len5), _key5 = 0; _key5 < _len5; _key5++) { args1[_key5] = arguments[_key5]; } return executeBound(func, bound, context, this, [].concat(args, args1)); }; return bound; } var toString = Object.prototype.toString; var reEvent = /Event/; // Internal recursive comparison function for `isEqual`. var eq = function eq(a, b, aStack, bStack) { // Identical objects are equal. `0 === -0`, but they aren't identical. // See the [Harmony `egal` proposal](http://wiki.ecmascript.org/doku.php?id=harmony:egal). if (a === b) return a !== 0 || 1 / a === 1 / b; // A strict comparison is necessary because `null == undefined`. if (isNullOrUndefined(a) || isNullOrUndefined(b)) return a === b; // For misstime VNode if (a instanceof VNode || b instanceof VNode) return a === b; // Compare `[[Class]]` names. var className$$1 = toString.call(a); if (className$$1 !== toString.call(b)) return false; switch (className$$1) { // Strings, numbers, regular expressions, dates, and booleans are compared by value. case '[object RegExp]': // RegExps are coerced to strings for comparison (Note: '' + /a/i === '/a/i') case '[object String]': // Primitives and their corresponding object wrappers are equivalent; thus, `"5"` is // equivalent to `new String("5")`. return '' + a === '' + b; case '[object Number]': // `NaN`s are equivalent, but non-reflexive. // Object(NaN) is equivalent to NaN if (+a !== +a) return +b !== +b; // An `egal` comparison is performed for other numeric values. return +a === 0 ? 1 / +a === 1 / b : +a === +b; case '[object Date]': case '[object Boolean]': // Coerce dates and booleans to numeric primitive values. Dates are compared by their // millisecond representations. Note that invalid dates with millisecond representations // of `NaN` are not equivalent. return +a === +b; } var areArrays = className$$1 === '[object Array]'; if (!areArrays) { if ((typeof a === 'undefined' ? 'undefined' : _typeof(a)) != 'object' || (typeof b === 'undefined' ? 'undefined' : _typeof(b)) != 'object') return false; // Event if (reEvent.test(className$$1)) return a === b; // Objects with different constructors are not equivalent, but `Object`s or `Array`s // from different frames are. var aCtor = a.constructor, bCtor = b.constructor; if (aCtor !== bCtor && !(isFunction(aCtor) && aCtor instanceof aCtor && isFunction(bCtor) && bCtor instanceof bCtor) && 'constructor' in a && 'constructor' in b) { return false; } } // Assume equality for cyclic structures. The algorithm for detecting cyclic // structures is adapted from ES 5.1 section 15.12.3, abstract operation `JO`. // Initializing stack of traversed objects. // It's done here since we only need them for objects and arrays comparison. aStack = aStack || []; bStack = bStack || []; var length = aStack.length; while (length--) { // Linear search. Performance is inversely proportional to the number of // unique nested structures. if (aStack[length] === a) return bStack[length] === b; } // Add the first object to the stack of traversed objects. aStack.push(a); bStack.push(b); // Recursively compare objects and arrays. if (areArrays) { // Compare array lengths to determine if a deep comparison is necessary. length = a.length; if (length !== b.length) return false; // Deep compare the contents, ignoring non-numeric properties. while (length--) { if (!eq(a[length], b[length], aStack, bStack)) return false; } } else { // Deep compare objects. var aKeys = keys(a), key; length = aKeys.length; // Ensure that both objects contain the same number of properties before comparing deep equality. if (keys(b).length !== length) return false; while (length--) { // Deep compare each member key = aKeys[length]; if (!(hasOwn.call(b, key) && eq(a[key], b[key], aStack, bStack))) return false; } } // Remove the first object from the stack of traversed objects. aStack.pop(); bStack.pop(); return true; }; function isEqual(a, b) { return eq(a, b); } var idCounter = 0; function uniqueId(prefix) { var id = ++idCounter + ''; return prefix ? prefix + id : id; } var keys = Object.keys || function (obj) { var ret = []; each(obj, function (value, key) { return ret.push(key); }); return ret; }; function values(obj) { var ret = []; each(obj, function (value) { return ret.push(value); }); return ret; } // @reference https://github.com/lodash/lodash/blob/master/.internal/stringToPath.js var charCodeOfDot = '.'.charCodeAt(0); var reEscapeChar = /\\(\\)?/g; var rePropName = RegExp( // Match anything that isn't a dot or bracket. '[^.[\\]]+' + '|' + // Or match property names within brackets. '\\[(?:' + // Match a non-string expression. '([^"\'].*)' + '|' + // Or match strings (supports escaping characters). '(["\'])((?:(?!\\2)[^\\\\]|\\\\.)*?)\\2' + ')\\]' + '|' + // Or match "" as the space between consecutive dots or empty brackets. '(?=(?:\\.|\\[\\])(?:\\.|\\[\\]|$))', 'g'); var pathMap = {}; var reIsUint = /^(?:0|[1-9]\d*)$/; /** * Converts `string` to a property path array. * * @private * @param {string} string The string to convert. * @returns {Array} Returns the property path array. */ function castPath(path) { if (typeof path !== 'string') return path; if (pathMap[path]) return pathMap[path]; var result = []; if (path.charCodeAt(0) === charCodeOfDot) { result.push(''); } path.replace(rePropName, function (match, expression, quote, subString) { var key = match; if (quote) { key = subString.replace(reEscapeChar, '$1'); } else if (expression) { key = expression; } result.push(key); }); pathMap[path] = result; return result; } function isIndex(value) { return (typeof value === 'number' || reIsUint.test(value)) && value > -1 && value % 1 === 0; } function get$$1(object, path, defaultValue) { if (hasOwn.call(object, path)) return object[path]; path = castPath(path); var index = 0, length = path.length; while (!isNullOrUndefined(object) && index < length) { object = object[path[index++]]; } return index && index === length && object !== undefined ? object : defaultValue; } function set$$1(object, path, value) { if (hasOwn.call(object, path)) { object[path] = value; return object; } path = castPath(path); var index = -1, length = path.length, lastIndex = length - 1, nested = object; while (!isNullOrUndefined(nested) && ++index < length) { var key = path[index], newValue = value; if (index !== lastIndex) { var objValue = nested[key]; newValue = isObject$$1(objValue) ? objValue : isIndex(path[index + 1]) ? [] : {}; } nested[key] = newValue; nested = nested[key]; } return object; } var warn = hasConsole ? function () { console.warn.apply(console, arguments); } : noop; var error$1 = hasConsole ? function () { console.error.apply(console, arguments); } : noop; function isNative(Ctor) { return typeof Ctor === 'function' && /native code/.test(Ctor.toString()); } var nextTick = function () { if (typeof Promise !== 'undefined' && isNative(Promise)) { var p = Promise.resolve(); return function (callback) { p.then(callback).catch(function (err) { return error$1(err); }); // description in vue if (isIOS) setTimeout(noop); }; } else if (typeof MutationObserver !== 'undefined' && (isNative(MutationObserver) || // PhantomJS and iOS 7.x MutationObserver.toString() === '[object MutationObserverConstructor]')) { var callbacks = []; var nextTickHandler = function nextTickHandler() { var _callbacks = callbacks.slice(0); callbacks.length = 0; for (var _i = 0; _i < _callbacks.length; _i++) { _callbacks[_i](); } }; var node = document.createTextNode(''); new MutationObserver(nextTickHandler).observe(node, { characterData: true }); var i = 1; return function (callback) { callbacks.push(callback); i = (i + 1) % 2; node.data = String(i); }; } else { return function (callback) { setTimeout(callback, 0); }; } }(); function NextTick(eachCallback) { var _this = this; this.callback = null; this.eachCallback = eachCallback; nextTick(function () { return _this.callback(); }); } NextTick.prototype.fire = function (callback, data) { this.callback = callback; if (this.eachCallback) { this.eachCallback(data); } }; var wontBind = ['constructor', 'template', 'defaults']; var getOwnPropertyNames = typeof Object.getOwnPropertyNames !== 'function' ? keys : Object.getOwnPropertyNames; function autobind(prototype, context, Intact, bound) { if (!prototype) return; if (prototype === Intact.prototype) return; var toBind = getOwnPropertyNames(prototype); each(toBind, function (method) { var fn = prototype[method]; if (fn === undefined) { // warn(`Autobind: '${method}' method not found in class.`); return; } if (~indexOf(wontBind, method) || bound[method] || typeof fn !== 'function') { return; } context[method] = bind(fn, context); bound[method] = true; }); // bind super method autobind(getPrototypeOf(prototype), context, Intact, bound); } var utils = (Object.freeze || Object)({ extend: extend, isArray: isArray, each: each, isObject: isObject$$1, hasOwn: hasOwn, isNullOrUndefined: isNullOrUndefined, noop: noop, isStringOrNumber: isStringOrNumber, inBrowser: inBrowser, UA: UA, isIOS: isIOS, getPrototypeOf: getPrototypeOf, inherit: inherit, templateDecorator: templateDecorator, create: create, isFunction: isFunction, isString: isString, result: result, bind: bind, isEqual: isEqual, uniqueId: uniqueId, keys: keys, values: values, castPath: castPath, get: get$$1, set: set$$1, warn: warn, error: error$1, nextTick: nextTick, NextTick: NextTick, autobind: autobind }); /** * 验证属性合法性,参考vue实现 * 这种实现方式,使用起来很简单,无需引入额外的模块 * 但是也无法验证复杂的数据结构(需要自己实现验证函数) */ function validateProps(props, propTypes) { var componentName = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : ''; if (!props || !propTypes) return; for (var prop in propTypes) { var value = props[prop]; var expectedType = propTypes[prop]; if (!isPlainObject(expectedType)) { expectedType = { type: expectedType }; } if (isNullOrUndefined(value)) { var required = expectedType.required; if (isFunction(required)) { required = required(props); } if (required) { error$1('Missing required prop on component "' + componentName + '": "' + prop + '".'); return; } else { continue; } } var type = expectedType.type; if (type) { if (!isArray(type)) { type = [type]; } var _valid = false; var _isStringOrNumber = false; var expectedTypes = []; for (var i = 0; i < type.length; i++) { var _assertType = assertType(value, type[i]), _expectedType = _assertType.expectedType, valid = _assertType.valid, isStringOrNumber$$1 = _assertType.isStringOrNumber; expectedTypes.push(_expectedType || ''); _isStringOrNumber = isStringOrNumber$$1; if (valid) { _valid = valid; break; } } if (!_valid) { error$1('Invalid type of prop "' + prop + '" on component "' + componentName + '". ' + ('Expected ' + expectedTypes.join(', ') + ', but got ') + (toRawType(value, _isStringOrNumber) + '.')); return; } } var validator = expectedType.validator; if (validator) { var result$$1 = validator(value); if (result$$1 === false) { error$1('Invalid prop "' + prop + '" on component "' + componentName + '": custom validator check failed.'); return; } else if (result$$1 !== true) { error$1('Invalid prop "' + prop + '" on component "' + componentName + '": ' + result$$1); return; } } } } var simpleCheckRE = /^(String|Number|Boolean|Function|Symbol)$/; function assertType(value, type) { var valid = void 0; var _type = typeof type === 'undefined' ? 'undefined' : _typeof(type); if (_type === 'number') { return { valid: type === value, expectedType: type, isStringOrNumber: true }; } else if (_type === 'string') { return { valid: type === value, expectedType: '"' + type + '"', isStringOrNumber: true }; } var expectedType = getType(type); if (simpleCheckRE.test(expectedType)) { var t = typeof value === 'undefined' ? 'undefined' : _typeof(value); valid = t === expectedType.toLowerCase(); if (valid && t === 'number' && value !== value) { // for NaN valid = false; } else if (!valid && t === 'object') { // for primitive wrapper objects valid = value instanceof type; } } else if (expectedType === 'Object') { valid = isPlainObject(value); } else if (expectedType === 'Array') { valid = isArray(value); } else { valid = value instanceof type; } return { valid: valid, expectedType: expectedType }; } function getType(fn) { var match = fn && fn.toString().match(/^\s*function (\w+)/); return match ? match[1] : ''; } var toString$3 = Object.prototype.toString; function toRawType(value, isStringOrNumber$$1) { if (isStringOrNumber$$1) { var _type = typeof value === 'undefined' ? 'undefined' : _typeof(value); if (_type === 'string') { return '"' + value + '"'; } return value; } if (value !== value) return 'NaN'; return toString$3.call(value).slice(8, -1); } function isPlainObject(value) { return toString$3.call(value) === '[object Object]'; } function Intact$2(props) { var template = this.constructor.template; // Intact.template is a decorator if (!template || template === templateDecorator) { template = this.template; } if (!template) { throw new Error('Can not instantiate when template does not exist.'); } // for debug this.displayName = this.displayName; // autobind this for methods // in ie 8 we must get prototype through constructor first time autobind(this.constructor.prototype, this, Intact$2, {}); this.vdt = Vdt$1(template); // for string ref this.refs = this.vdt.widgets || {}; // for compatibility v1.0 this.widgets = this.refs; this.props = extend({}, result(this, 'defaults')); this.uniqueId = this.props.widget || uniqueId('widget'); // for compatibility v1.0 this.attributes = this.props; this._widget = this.uniqueId; this._events = {}; this._keptEvents = {}; // save the events that do not off when destroyed // lifecycle states this.inited = false; this.rendered = false; this.mounted = false; this.destroyed = false; // if the flag is false, any set operation will not lead to update this._startRender = false; this._updateCount = 0; this._pendingUpdate = null; this._pendingChangedEvents = []; this.mountedQueue = null; this._constructor(props); } Intact$2.prototype._constructor = function (props) { var _this = this; { validateProps(props, this.constructor.propTypes, this.displayName || this.constructor.name); } extend(this.props, props); // bind events each(props, function (value, key) { if (isEventProp(key)) { if (isArray(value)) { for (var i = 0; i < value.length; i++) { if (value[i]) { _this.on(key.substr(3), value[i]); } } } else if (value) { _this.on(key.substr(3), value); } } }); var inited = function inited() { _this.inited = true; // trigger $receive event when initialize component var keys$$1 = []; each(props, function (value, key) { _this.trigger('$receive:' + key, _this, value); keys$$1.push(key); }); if (keys$$1.length) { _this.trigger('$receive', _this, keys$$1); } _this.trigger('$inited', _this); }; var ret = this._init(props); if (ret && ret.then) { ret.then(inited, function (err) { error$1('Unhandled promise rejection in _init: ', err); inited(); }); } else { inited(); } }; // for intact compatibility layer to inherit it Intact$2.template = templateDecorator; Intact$2.prototype.defaults = noop; // function name conflict with utils.get Intact$2.prototype.get = function _get(key, defaultValue) { if (key === undefined) return this.props; return get$$1(this.props, key, defaultValue); }; Intact$2.prototype.set = function _set(key, val, options) { var _this = this; if (isNullOrUndefined(key)) return this; if ((typeof key === 'undefined' ? 'undefined' : _typeof(key)) === 'object') { options = val; } else { var obj = {}; obj[key] = val; key = obj; } options = extend({ silent: false, update: true, async: false, _fromPatchProps: false }, options); // 兼容老版本 if (hasOwn.call(options, 'global')) { options.update = options.global; } var props = this.props; var changes = []; if (!options.silent) { changes = setProps(key, props); } else { // 如果静默更新,则直接赋值 for (var prop in key) { set$$1(props, prop, key[prop]); } } if (changes.length) { var changeKeys = []; for (var i = 0; i < changes.length; i++) { var _changes$i = changes[i], _prop = _changes$i[0], values$$1 = _changes$i[1]; if (options._fromPatchProps) { // trigger a $receive event to show that we received a different prop this.trigger('$receive:' + _prop, this, values$$1[1], values$$1[0]); // 存在如下情况 // 当prop为value通过v-model进行双向绑定时,receive事件有可能会修正该value // 而修正的过程中,触发了change事件,会去修改绑定的属性 // 但是下面触发的change事件,又会将绑定的属性置为未修正的值 // 这会导致死循坏 // 所以这里将values[1]设为修正后的值,避免死循坏发生 values$$1[1] = this.get(_prop); // 如果修正后,前后值相等,则不去触发change事件 if (values$$1[1] === values$$1[0]) { changes.splice(i, 1); i--; continue; } } changeKeys.push(_prop); // trigger `change*` events this.trigger('$change:' + _prop, this, values$$1[1], values$$1[0]); } if (!changeKeys.length) return; if (options._fromPatchProps) { this.trigger('$receive', this, changeKeys); } this.trigger('$change', this, changeKeys); if (options.update && this._startRender) { if (options.async) { if (!this._$nextTick) { this._$nextTick = new NextTick(function (data) { // 将每次改变的属性放入数组 this.args.push(data); }); this._$nextTick.args = []; } var self = this; this._$nextTick.fire(function () { // 合并执行更新后,触发所有$changed事件 var args = this.args; var changes = []; for (var _i = 0; _i < args.length; _i++) { changes = changes.concat(args[_i]); } self._$nextTick = null; triggerChange(self, changes); }, changes); } else { triggerChange(this, changes); } } else if (this.mountedQueue && this._startRender) { // 如果是父组件导致子组件更新,此时存在mountedQueue // 则在组件树更新完毕,触发$changed事件 // 现将该事件暂存起来,待子组件更新完毕在加入mountedQueue // 以保证子组件的事件优先于父组件执行 this._pendingChangedEvents.push(function () { triggerChangedEvent(_this, changes); }); } } return this; }; function triggerChange(o, changes) { o.update(); triggerChangedEvent(o, changes); } function triggerChangedEvent(o, changes) { var changeKeys = []; for (var i = 0; i < changes.length; i++) { var _changes$i2 = changes[i], prop = _changes$i2[0], values$$1 = _changes$i2[1]; changeKeys.push(prop); o.trigger('$changed:' + prop, o, values$$1[1], values$$1[0]); } o.trigger('$changed', o, changeKeys); } var reWithDot = /\./; function setProps(newProps, props) { var propsPathTree = {}; var changes = {}; var changesWithoutNextValue = []; for (var prop in newProps) { var nextValue = newProps[prop]; var lastValue = get$$1(props, prop); if (!isEqual(lastValue, nextValue)) { var tree = propsPathTree; if (!hasOwn.call(props, prop)) { // a.b.c => ['a', 'b', 'c'] var paths = castPath(prop); var length = paths.length; var path = ''; for (var i = 0; i < length; i++) { var name = paths[i]; if (reWithDot.test(name)) { name = '["' + name + '"]'; } else { name = path ? '.' + name : name; } path = '' + path + name; if (!tree[name]) { if (i < length - 1) { tree[name] = {}; changes[path] = [get$$1(props, path)]; changesWithoutNextValue.push(path); } else { changes[path] = [lastValue, nextValue]; tree[name] = null; } } tree = tree[name]; } // tree = {a: {b: {c: {}}}} // changes = {'a.b.c': [v1, v2], 'a': [v1], 'a.b': [v1]} } else { if (reWithDot.test(prop)) { prop = '["' + prop + '"]'; } changes[prop] = [lastValue, nextValue]; tree[prop] = null; } } // 即使相等,也要重新复制,因为有可能引用地址变更 set$$1(props, prop, nextValue); } for (var _i2 = 0; _i2 < changesWithoutNextValue.length; _i2++) { var _path2 = changesWithoutNextValue[_i2]; changes[_path2].push(get$$1(props, _path2)); } return getChanges(propsPathTree, changes); } // 深度优先遍历,得到正确的事件触发顺序 function getChanges(tree, data) { var path = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : ''; var changes = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : []; for (var key in tree) { // let _path = reWithDot.test(key) ? // `${path}["${key}"]` : // path ? // `${path}.${key}` : // key; var _path = path + key; if (tree[key]) { getChanges(tree[key], data, _path, changes); } changes.push([_path, data[_path]]); } return changes; } Intact$2.prototype.on = function (name, callback) { var options = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {}; // the event which write in template must insert before which add in self component (this._events[name] || (this._events[name] = []))[options.unshift ? 'unshift' : 'push'](callback); // save the kept event if (options.keep) { (this._keptEvents[name] || (this._keptEvents[name] = [])).push(callback); } return this; }; Intact$2.prototype.one = function (name, callback) { var _this = this; var fn = function fn() { for (var _len = arguments.length, args = Array(_len), _key = 0; _key < _len; _key++) { args[_key] = arguments[_key]; } callback.apply(_this, args); _this.off(name, fn); }; this.on(name, fn); return this; }; Intact$2.prototype.off = function (name, callback) { if (name === undefined) { this._events = extend({}, this._keptEvents); return this; } var callbacks = this._events[name]; if (!callbacks) return this; if (callback === undefined) { delete this._events[name]; return this; } for (var cb, i = 0; i < callbacks.length; i++) { cb = callbacks[i]; if (cb === callback) { callbacks.splice(i, 1); // i--; break; } } return this; }; Intact$2.prototype.trigger = function (name) { var callbacks = this._events[name]; if (callbacks) { callbacks = callbacks.slice(); for (var _len2 = arguments.length, args = Array(_len2 > 1 ? _len2 - 1 : 0), _key2 = 1; _key2 < _len2; _key2++) { args[_key2 - 1] = arguments[_key2]; } for (var i = 0, l = callbacks.length; i < l; i++) { callbacks[i].apply(this, args); } } return this; }; Intact$2.prototype._init = noop; Intact$2.prototype._beforeCreate = noop; Intact$2.prototype._create = noop; Intact$2.prototype._mount = noop; Intact$2.prototype._beforeUpdate = noop; Intact$2.prototype._update = noop; Intact$2.prototype._destroy = noop; Intact$2.prototype.init = function (lastVNode, nextVNode) { this._lastVNode = lastVNode; if (!this.inited) { return initAsyncComponnet(this, lastVNode, nextVNode); } return initSyncComponent(this, lastVNode, nextVNode); }; Intact$2.prototype.mount = function (lastVNode, nextVNode) { // 异步组件,直接返回 if (!this.inited) return; this.mounted = true; this.trigger('$mounted', this); this._mount(lastVNode, nextVNode); }; Intact$2.prototype.update = function (lastVNode, nextVNode, fromPending) { // 如果该组件已被销毁,则不更新 // 组件的销毁顺序是从自下而上逐步销毁的,对于子组件,即使将要销毁也要更新 // 只有父组件被销毁了才不去更新,父组件的更新是没有vNode参数 if (!lastVNode && !nextVNode && this.destroyed) { return lastVNode ? lastVNode.dom : undefined; } // 如果还没有渲染,则等待结束再去更新 if (!this.rendered) { this._pendingUpdate = function (lastVNode, nextVNode) { this.update(lastVNode, nextVNode, true); }; return lastVNode ? lastVNode.dom : undefined; } // mountedQueue在一次更新周期里,只能使用使用,根据done字段判断 // 在同一更新周期里,共用该对象,否则置为null,让misstime自己去重新初始化 if (this.mountedQueue && this.mountedQueue.done) { this.mountedQueue = null; } // 如果不存在nextVNode,则为直接调用update方法更新自己 // 否则则是父组件触发的子组件更新,此时需要更新一些状态 // 有一种情况,在父组件初次渲染时,子组件渲染过程中, // 又触发了父组件的数据变更,此时父组件渲染完成执行_pendingUpdate // 是没有lastVNode的 if (nextVNode && lastVNode) { patchProps$1(this, lastVNode.props, nextVNode.props); } ++this._updateCount; if (this._updateCount > 1) { return this.element; } if (this._updateCount === 1) { return updateComponent(this, lastVNode, nextVNode); } }; Intact$2.prototype.destroy = function (lastVNode, nextVNode, parentDom) { if (this.destroyed) { return warn('destroyed multiple times'); } // 如果存在nextVNode,并且nextVNode也是一个组件类型, // 并且,它俩的key相等,则不去destroy,而是在下一个组件init时 // 复用上一个dom,然后destroy上一个元素 this._destroy(lastVNode, nextVNode); var vdt = this.vdt; // 异步组件,可能还没有渲染 if (!this.rendered) { // 异步组件,只有开始渲染时才销毁上一个组件 // 如果没有渲染当前异步组件就被销毁了,则要 // 在这里销毁上一个组件 var _lastVNode = this._lastVNode; if (_lastVNode && !_lastVNode.children.destroyed) { removeComponentClassOrInstance(_lastVNode, null, lastVNode); } } else if (!nextVNode || !(nextVNode.type & Types.ComponentClassOrInstance) || nextVNode.key !== lastVNode.key) { vdt.destroy(); } this.destroyed = true; this.trigger('$destroyed', this); this.off(); }; Intact$2.prototype._initMountedQueue = function () { this.mountedQueue = new MountedQueue(); }; Intact$2.prototype._triggerMountedQueue = function () { this.mountedQueue.trigger(); }; function initSyncComponent(o, lastVNode, nextVNode) { o._beforeCreate(lastVNode, nextVNode); var vdt = o.vdt; o._startRender = true; // 如果key不相同,则不复用dom,直接返回新dom来替换 if (lastVNode && lastVNode.key === nextVNode.key) { // destroy the last component if (!lastVNode.children.destroyed) { removeComponentClassOrInstance(lastVNode, null, nextVNode); } // make the dom not be replaced, but update the last one vdt.vNode = lastVNode.children.vdt.vNode; o.element = vdt.update(o, o.parentDom, o.mountedQueue, nextVNode, o.isSVG, o.get('_blocks')); } else { if (lastVNode) { removeComponentClassOrInstance(lastVNode, null, nextVNode); } o.element = vdt.render(o, o.parentDom, o.mountedQueue, nextVNode, o.isSVG, o.get('_blocks')); } o.rendered = true; if (o._pendingUpdate) { o._pendingUpdate(lastVNode, nextVNode); o._pendingUpdate = null; } o.trigger('$rendered', o); o._create(lastVNode, nextVNode); return o.element; } function initAsyncComponnet(o, lastVNode, nextVNode) { var vdt = o.vdt; var placeholder = void 0; if (lastVNode) { placeholder = lastVNode.dom; var lastInstance = lastVNode.children; vdt.vNode = lastInstance.vdt.vNode; // 如果上一个组件是异步组件,并且也还没渲染完成,则直接destroy掉 // 让它不再渲染了 if (!lastInstance.inited) { removeComponentClassOrInstance(lastVNode, null, nextVNode); } } else { var vNode = createCommentVNode('!'); placeholder = render(vNode); vdt.vNode = vNode; } // 组件销毁事件也会解绑,所以这里无需判断组件是否销毁了 o.one('$inited', function () { // 异步组件进入了新的更新周期,需要初始化mountedQueue o._initMountedQueue(); var element = o.init(lastVNode, nextVNode); var dom = nextVNode.dom; // 存在一种情况,组件的返回的元素是一个组件,他们指向同一个dom // 但是当嵌套组件的dom变更时,父组件的vNode却没有变 // 所以这里强制保持一致 nextVNode.dom = element; if (!lastVNode || lastVNode.key !== nextVNode.key) { dom.parentNode.replaceChild(element, dom); } o._triggerMountedQueue(); o.mount(lastVNode, nextVNode); }); vdt.node = placeholder; return placeholder; } function updateComponent(o, lastVNode, nextVNode) { o._beforeUpdate(lastVNode, nextVNode); // 直接调用update方法,保持parentVNode不变 o.element = o.vdt.update(o, o.parentDom, o.mountedQueue, nextVNode || o.vNode, o.isSVG, o.get('_blocks')); // 让整个更新完成,才去触发_update生命周期函数 if (o.mountedQueue) { // 加入$changed事件队列 var events = o._pendingChangedEvents; for (var i = 0; i < events.length; i++) { o.mountedQueue.push(events[i]); } o._pendingChangedEvents = []; o.mountedQueue.push(function () { o._update(lastVNode, nextVNode); }); } else { o._update(lastVNode, nextVNode); } if (--o._updateCount > 0) { // 如果更新完成,发现还有更新,则是在更新过程中又触发了更新 // 此时直接将_updateCount置为1,因为所有数据都已更新,只做最后一次模板更新即可 // --o._updateCount会将该值设为0,所以这里设为1 o._updateCount = 1; return updateComponent(o, lastVNode, nextVNode); } // 组件模板可能根据情况返回不同的dom,这种情况下,当组件自身更新(即:直接调用update) // 组件的dom可能变更了,但是当前组件的vNode的dom属性却不会变更,此后该dom如果被v-if // 指令删除,会报错 // 所以这里要强制更新 var vNode = o.vNode; if (vNode) { // 有可能直接new组件,所以这里判断vNode是否存在 var lastDom = vNode.dom; var nextDom = o.element; if (lastDom !== nextDom) { vNode.dom = nextDom; var parentVNode = vNode.parentVNode; // 需要递归判断父组件是不是也指向同一个元素 while (parentVNode && parentVNode.type & Types.ComponentClassOrInstance && parentVNode.dom === lastDom) { parentVNode.dom = nextDom; parentVNode = parentVNode.parentVNode; } } } return o.element; } function patchProps$1(o, lastProps, nextProps) { var options = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : { update: false, _fromPatchProps: true }; lastProps = lastProps || EMPTY_OBJ; nextProps = nextProps || EMPTY_OBJ; var lastValue = void 0; var nextValue = void 0; if (lastProps !== nextProps) { // 需要先处理事件,因为prop变更可能触发相应的事件 var lastPropsWithoutEvents = void 0; var nextPropsWithoutEvents = void 0; // 如果该属性只存在lastProps中,则是事件就解绑; // 是属性就加入lastPropsWithoutEvents对象,待会儿再处理 var handlePropOnlyInLastProps = function handlePropOnlyInLastProps(prop) { var lastValue = lastProps[prop]; if (isEventProp(prop)) { // 解绑上一个属性中的事件 removeEvents(o, prop, lastValue); } else { if (!lastPropsWithoutEvents) { lastPropsWithoutEvents = {}; } lastPropsWithoutEvents[prop] = lastValue; } }; if (nextProps !== EMPTY_OBJ) { { validateProps(nextProps, o.constructor.propTypes, o.displayName || o.constructor.name); } for (var prop in nextProps) { nextValue = nextProps[prop]; if (isEventProp(prop)) { lastValue = lastProps[prop]; if (lastValue === nextValue) continue; patchEventProps(o, prop, lastValue, nextValue); } else { if (!nextPropsWithoutEvents) { nextPropsWithoutEvents = {}; } nextPropsWithoutEvents[prop] = nextValue; } } if (lastProps !== EMPTY_OBJ) { for (var _prop in lastProps) { if (!hasOwn.call(nextProps, _prop)) { handlePropOnlyInLastProps(_prop); } } } if (nextPropsWithoutEvents) { o.set(nextPropsWithoutEvents, options); } } else { for (var _prop2 in lastProps) { handlePropOnlyInLastProps(_prop2); } } // 将不存在nextProps中,但存在lastProps中的属性,统统置为默认值 var defaults = result(o, 'defaults') || EMPTY_OBJ; if (lastPropsWithoutEvents) { for (var _prop3 in lastPropsWithoutEvents) { o.set(_prop3, defaults[_prop3], options); } } } } /** * @brief diff事件属性,属性值可以是空、函数、数组,为了保证事件属性执行顺序优先于 * 组件内部绑定的同名事件,这里采用unshift倒着处理 * * @param o * @param prop * @param lastValue * @param nextValue * * @return */ function patchEventProps(o, prop, lastValue, nextValue) { o.set(prop, nextValue, { silent: true }); var eventName = prop.substr(3); if (isArray(nextValue)) { if (isArray(lastValue)) { // 由于实际应用中,nextValue和lastValue一般长度相等, // 而且顺序也不会变化,极有可能仅仅只是改变了数组中 // 的一项或几项,所以可以一一对比处理 var nextLength = nextValue.length; var lastLength = lastValue.length; var i = void 0; var l = Math.min(nextLength, lastLength); if (l < nextLength) { // 如果nextValue > lastValue // 则绑定剩下的事件函数 for (i = nextLength - 1; i >= l; i--) { var _nextValue = nextValue[i]; if (_nextValue) { o.on(eventName, _nextValue, { unshift: true }); } } } else if (l < lastLength) { // 如果nextValue < lastValue // 则解绑剩下的事件函数 for (i = lastLength - 1; i >= l; i--) { var _lastValue = lastValue[i]; if (_lastValue) { o.off(eventName, _lastValue); } } } for (i = l - 1; i >= 0; i--) { var _lastValue2 = lastValue[i]; var _nextValue2 = nextValue[i]; // 因为要保证顺序不变,所以即使相同,也要重新unshift到前面 // if (_lastValue !== _nextValue) { if (_lastValue2) { o.off(eventName, _lastValue2); } if (_nextValue2) { o.on(eventName, _nextValue2, { unshift: true }); } // } } } else if (lastValue) { o.off(eventName, lastValue); for (var _i = nextValue.length - 1; _i >= 0; _i--) { var _nextValue3 = nextValue[_i]; if (_nextValue3) { o.on(eventName, _nextValue3, { unshift: true }); } } } else { for (var _i2 = nextValue.length - 1; _i2 >= 0; _i2--) { var _nextValue4 = nextValue[_i2]; if (_nextValue4) { o.on(eventName, _nextValue4, { unshift: true }); } } } } else if (nextValue) { if (isArray(lastValue)) { var found = false; for (var _i3 = 0; _i3 < lastValue.length; _i3++) { var _lastValue3 = lastValue[_i3]; if (_lastValue3) { if (_lastValue3 !== nextValue) { o.off(eventName, _lastValue3); } else { found = true; } } } // 如果下一个事件函数不在上一个数组中,则绑定 if (!found) { o.on(eventName, nextValue, { unshift: true }); } } else if (lastValue) { o.off(eventName, lastValue); o.on(eventName, nextValue, { unshift: true }); } else { o.on(eventName, nextValue, { unshift: true }); } } else { removeEvents(o, prop, lastValue); } } function removeEvents(o, prop, value) { var eventName = void 0; if (isArray(value)) { eventName = prop.substr(3); for (var i = 0; i < value.length; i++) { var v = value[i]; if (v) { o.off(eventName, v); } } } else if (value) { eventName = prop.substr(3); o.off(eventName, value); } o.set(prop, undefined, { silent: true }); } Intact$2.prototype.hydrate = function (vNode, dom) { var _this = this; var vdt = this.vdt; if (!this.inited) { this.one('$inited', function () { var element = _this.hydrate(vNode, dom); if (dom !== element) { vNode.dom = element; } _this._triggerMountedQueue(); _this.mount(null, vNode); }); return dom; } this._beforeCreate(null, vNode); this._startRender = true; this.element = vdt.hydrate(this, dom, this.mountedQueue, this.parentDom, vNode, this.isSVG, this.get('_blocks')); this.rendered = true; this.trigger('$rendered', this); this._create(null, vNode); return this.element; }; Intact$2.prototype.toString = function () { this._beforeCreate(null, this.vNode); return this.vdt.renderString(this, this.get('_blocks'), this.vNode); }; /** * @brief 继承某个组件 * * @param prototype */ Intact$2.extend = function () { var prototype = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {}; if (_typeof(this.prototype.defaults) === 'object' && _typeof(prototype.defaults) === 'object') { prototype.defaults = extend({}, this.prototype.defaults, prototype.defaults); } return inherit(this, prototype); }; /** * 挂载组件到dom中 * @param Component {Intact} Intact类或子类 * @param node {Node} html节点 */ Intact$2.mount = function (Component, node) { if (!node) throw new Error('expect a parent dom to mount Component, but got ' + node); var vNode = createVNode(Component); var mountedQueue = new MountedQueue(); render(vNode, node, mountedQueue); var instance = vNode.children; // 如果不是异步组件,则触发mount事件,否则 // 交给组件的init方法,等异步处理完成后触发 if (instance.inited) { mountedQueue.trigger(); } return instance; }; Intact$2.hydrate = function (Component, node) { if (!node) throw new Error('expect a parent dom to hydrate Component, but got ' + node); var vNode = createVNode(Component); hydrateRoot(vNode, node); return vNode.children; }; // for type check Intact$2.VNode = VNode; function addClass(element, className) { if (className) { if (element.classList) { element.classList.add(className); } else if (!hasClass(element, className)) { element.className += ' ' + className; } } return element; } function hasClass(element, className) { if (element.classList) { return !!className && element.className.contains(className); } return (' ' + element.className + ' ').indexOf(' ' + className + ' ') > -1; } function removeClass(element, className) { if (className) { if (element.classList) { element.classList.remove(className); } else if (hasClass(element, className)) { element.className = element.className.replace(new RegExp('(^|\\s)' + className + '(?:\\s|$)', 'g'), '$1').replace(/\s+/g, ' ') // multiple spaces to one .replace(/^\s*|\s*$/g, ''); // trim the ends } } } var EVENT_NAME_MAP = { transitionend: { 'transition': 'transitionend', 'WebkitTransition': 'webkitTransitionEnd', 'MozTransition': 'mozTransitionEnd', 'OTransition': 'oTransitionEnd', 'msTransition': 'MSTransitionEnd' }, animationend: { 'animation': 'animationend', 'WebkitAnimation': 'webkitAnimationEnd', 'MozAnimation': 'mozAnimationEnd', 'OAnimation': 'oAnimationEnd', 'msAnimation': 'MSAnimationEnd' } }; var endEvents = []; var transitionProp = 'transition'; var animationProp = 'animation'; function detectEvents() { var testEl = document.createElement('div'); var style = testEl.style; // On some platforms, in particular some releases of Android 4.x, // the un-prefixed "animation" and "transition" properties are defined on the // style object but the events that fire will still be prefixed, so we need // to check if the un-prefixed events are useable, and if not remove them // from the map if (!('AnimationEvent' in window)) { delete EVENT_NAME_MAP.animationend.animation; } if (!('TransitionEvent' in window)) { delete EVENT_NAME_MAP.transitionend.transition; } for (var baseEventName in EVENT_NAME_MAP) { var baseEvents = EVENT_NAME_MAP[baseEventName]; for (var styleName in baseEvents) { if (styleName in style) { endEvents.push(baseEvents[styleName]); if (baseEventName === 'transitionend') { transitionProp = styleName; } else { animationProp = styleName; } break; } } } } function whenTransitionEnds(element, info, cb) { var timeout = info.timeout, propCount = info.propCount; var ended = 0; var end = function end() { TransitionEvents.off(element, onEnd); !cb.isCalled && cb(); clearTimeout(timer); }; var onEnd = function onEnd(e) { if (e.target === element) { e.stopPropagation(); if (++ended >= propCount) { end(); } } }; var timer = setTimeout(function () { if (ended < propCount) { end(); } }, timeout + 1); TransitionEvents.on(element, onEnd); return end; } // inspired by vue function getAnimateInfo(element, className) { if (className) addClass(element, className); var style = window.getComputedStyle(element); var transitionDelays = style[transitionProp + 'Delay'].split(', '); var transitionDurations = style[transitionProp + 'Duration'].split(', '); var transitionTimeout = getTimeout(transitionDelays, transitionDurations); var animationDelays = style[animationProp + 'Delay'].split(', '); var animationDurations = style[animationProp + 'Duration'].split(', '); var animationTimeout = getTimeout(animationDelays, animationDurations); if (className) removeClass(element, className); var type = transitionTimeout > animationTimeout ? 'transition' : 'animation'; var timeout = Math.max(transitionTimeout, animationTimeout); var propCount = type === 'transition' ? transitionDurations.length : animationDurations.length; return { type: type, timeout: timeout, propCount: propCount }; } function getTimeout(delays, durations) { var l = delays.length; return Math.max.apply(null, durations.map(function (d, i) { return toMs(d) + toMs(delays[i % l]); })); } function toMs(s) { return s.slice(0, -1) * 1000; } function addEventListener$1(node, eventName, eventListener) { node.addEventListener(eventName, eventListener, false); } function removeEventListener$1(node, eventName, eventListener) { node.removeEventListener(eventName, eventListener, false); } var TransitionEvents = { on: function on(node, eventListener) { if (endEvents.length === 0) { // If CSS transitions are not supported, trigger an "end animation" // event immediately. window.setTimeout(eventListener, 0); return; } endEvents.forEach(function (endEvent) { addEventListener$1(node, endEvent, eventListener); }); }, off: function off(node, eventListener) { if (endEvents.length === 0) { return; } endEvents.forEach(function (endEvent) { removeEventListener$1(node, endEvent, eventListener); }); }, one: function one(node, eventListener) { var listener = function listener() { eventListener.apply(this, arguments); TransitionEvents.off(node, listener); }; TransitionEvents.on(node, listener); } }; var raf = void 0; function nextFrame(fn) { var _fn = function _fn() { if (_fn.cancelled) return; fn(); }; raf(function () { return raf(_fn); }); return function () { _fn.cancelled = true; }; } if (inBrowser) { raf = window.requestAnimationFrame ? window.requestAnimationFrame.bind(window) : setTimeout; detectEvents(); } var CSSMatrix = typeof WebKitCSSMatrix !== 'undefined' ? WebKitCSSMatrix : function (transform) { this.m42 = 0; this.m41 = 0; var type = transform.slice(0, transform.indexOf('(')); var parts = void 0; if (type === 'matrix3d') { parts = transform.slice(9, -1).split(','); this.m41 = parseFloat(parts[12]); this.m42 = parseFloat(parts[13]); } else if (type === 'matrix') { parts = transform.slice(7, -1).split(','); this.m41 = parseFloat(parts[4]); this.m42 = parseFloat(parts[5]); } }; // the elements that can not be moved by relative position var immovableElements = { tr: true, tbody: true, td: true, thead: true }; var h = Vdt$1.miss.h; var _Vdt$utils = Vdt$1.utils; var c = _Vdt$utils.className; var e$1 = _Vdt$utils.extend; var prototype = { defaults: function defaults$$1() { return { 'a:continuity': true, // 是否保持连贯性 'a:tag': 'div', 'a:transition': 'animate', 'a:appear': false, 'a:mode': 'both', // out-in | in-out | both 'a:disabled': false, // 只做动画管理者,自己不进行动画 'a:move': true, // 是否执行move动画 'a:css': true, // 是否使用css动画,如果自定义动画函数,可以将它置为false 'a:delayDestroy': true, // 是否动画完成才destroy子元素 'a:show': true // 是否应用展示、隐藏动画 }; }, template: function template() { var _e; var self = this.data; var tagName = self.get('a:tag'); var props = {}; var _props = self.get(); var _staticClass = self._staticClass; for (var key in _props) { if (key !== 'ref' && key !== 'key' && (key[0] !== 'a' || key[1] !== ':') && key.substr(0, 5) !== 'ev-a:') { props[key] = _props[key]; } } var oClassName = props.className; props.className = c(e$1((_e = {}, _e[oClassName] = oClassName, _e), _staticClass)) || undefined; if (self._isRenderString) { var show = self.get('a:show'); if (!show) { var oStyle = props.style; if (!oStyle) { props.style = { display: 'none' }; } else { var type = typeof oStyle === 'undefined' ? 'undefined' : _typeof(oStyle); if (type === 'string') { props.style = oStyle + 'display: none;'; } else if (type === 'object' && oStyle) { props.style.display = 'none'; } } } } return h(tagName, props, self.get('children')); }, _init: function _init() { var _this = this; if (!endEvents.length) { // 如果不支持css动画,则关闭css this.set({ 'a:css': false, 'a:move': false }, { silent: true }); } this.mountChildren = []; this.unmountChildren = []; this.updateChildren = []; this.children = []; this._enteringAmount = 0; this._leavingAmount = 0; // convert show to Boolean this.on('$receive:a:show', function (c, v) { _this.set('a:show', !!v, { silent: true }); }); this._staticClass = {}; }, _addClass: function _addClass(className) { this._staticClass[className] = true; addClass(this.element, className); }, _removeClass: function _removeClass(className) { delete this._staticClass[className]; removeClass(this.element, className); }, toString: function toString() { this._isRenderString = true; var ret = this._super(); this._isRenderString = false; return ret; } }; function checkMode(o) { var mountChildren = []; var updateChildren = []; var unmountChildren = []; var children = o.children = o.children.filter(function (instance) { if (instance._delayEnter) { instance._delayEnter = false; mountChildren.push(instance); return false; } else if (instance._delayLeave) { instance._delayLeave = false; unmountChildren.push(instance); return true; } else if (instance._leaving !== false) { updateChildren.push(instance); return true; } return false; }); o._beforeUpdate(); mountChildren.forEach(function (instance) { instance.element.style.display = ''; instance.position = null; }); o.mountChildren = mountChildren; o.updateChildren = updateChildren; o.unmountChildren = unmountChildren; o.children = children.concat(mountChildren); o._update(null, null, true); } prototype.init = inBrowser ? function (lastVNode, nextVNode) { if (!lastVNode) { var parentDom = this.parentVNode && this.parentVNode.dom || this.parentDom; if (parentDom && parentDom._reserve) { lastVNode = parentDom._reserve[nextVNode.key]; } } return this._super(lastVNode, nextVNode); } : function () { return this._superApply(arguments); }; prototype.destroy = function (lastVNode, nextVNode, parentDom, _directly) { // 1: 不存在parentDom,有两种情况: // 1): 父元素也要被销毁,此时: !parentDom && lastVNode && !nextVNode // 2): 该元素将被替换,此时:!parentDom && lastVNode && nextVNode // 对于1),既然父元素要销毁,那本身也要直接销毁 // 对于2),本身必须待动画结束方能销毁 // 2: 如果该元素已经动画完成,直接销毁 // 3: 如果直接调用destroy方法,则直接销毁,此时:!lastVNode && !nextVNode && !parentDom // 4: 如果不是延迟destroy子元素,则立即销毁 // 5: 如果是禁止动画的元素,且该元素是组件直接返回的动画元素,则直接销毁 if (!this.get('a:delayDestroy') || !parentDom && !nextVNode && !isRemoveDirectly(this) || this._leaving === false || _directly) { this._super(lastVNode, nextVNode, parentDom); } }; function isRemoveDirectly(instance) { var parentVNode = instance.parentVNode; while (parentVNode && parentVNode.type & Types.ComponentClassOrInstance) { var i = parentVNode.children; if (i._isRemoveDirectly) { return instance.element === i.element; } parentVNode = parentVNode.parentVNode; } return false; } function leave(o) { // maybe a a:show animation is leaving if (o._leaving) return; var element = o.element; if (element.style.display === 'none') return o.leaveEndCallback(true); var isCss = o.get('a:css'); var continuity = o.get('a:continuity'); var disabled = o.get('a:disabled'); var endDirectly = false; if (o._entering) { if (continuity && !o._triggeredEnter) { endDirectly = true; o._cancelEnterNextFrame(); } o._enterEnd(true); } if (disabled) return o.leaveEndCallback(); var vNode = o.vNode; var parentDom = o._parentDom; // vNode都会被添加key,当只有一个子元素时,vNode.key === undefined // 这种情况,我们也当成有key处理,此时key为undefined if (!parentDom._reserve) { parentDom._reserve = {}; } parentDom._reserve[vNode.key] = vNode; o._leaving = true; initLeaveEndCallback(o); // 为了保持动画连贯,我们立即添加leaveActiveClass // 但如果当前元素还没有来得及做enter动画,就被删除 // 则leaveActiveClass和leaveClass都放到下一帧添加 // 否则leaveClass和enterClass一样就不会有动画效果 if (continuity && !endDirectly && isCss) { o._addClass(o.leaveActiveClass); } o.trigger('a:leaveStart', element); if (!endDirectly) { // TransitionEvents.on(element, o._leaveEnd); // triggerLeave(o); var info = isCss ? getAnimateInfo(element) : null; o._cancelLeaveNextFrame = nextFrame(function () { // 存在一种情况,当一个enter动画在完成的瞬间, // 这个元素被删除了,由于前面保持动画的连贯性 // 添加了leaveActiveClass,则会导致绑定的leaveEnd // 立即执行,所以这里放到下一帧来绑定 // TransitionEvents.on(element, o._leaveEnd); if (isCss) { o._cancelLeaveEnd = whenTransitionEnds(element, info, o._leaveEnd); } triggerLeave(o); }); } else { o._leaveEnd(); } } function triggerLeave(o) { if (o._leaving === false) return; o._triggeredLeave = true; var element = o.element; if (o.get('a:css')) { o._addClass(o.leaveActiveClass); o._addClass(o.leaveClass); } o.trigger('a:leave', element, o._leaveEnd); } function initLeaveEndCallback(o) { var element = o.element, _parentDom = o._parentDom, vNode = o.vNode; var isCss = o.get('a:css'); var disabled = o.get('a:disabled'); o._leaveEnd = function (isCancel) { o._leaveEnd.isCalled = true; if (o._cancelLeaveEnd) { o._cancelLeaveEnd(); o._cancelLeaveEnd = null; } if (isCss && !disabled) { o._removeClass(o.leaveClass); o._removeClass(o.leaveActiveClass); } if (o._triggeredLeave) { var s = element.style; s.position = s.top = s.left = s.transform = s.WebkitTransform = ''; } o._leaving = false; o._triggeredLeave = false; delete _parentDom._reserve[vNode.key]; var parentInstance = o.parentInstance; if (parentInstance) { if (--parentInstance._leavingAmount === 0 && parentInstance.get('a:mode') === 'out-in') { checkMode(parentInstance); } } o.trigger('a:leaveEnd', element, isCancel); if (!isCancel) { o.leaveEndCallback(true); } }; } prototype._mount = function (lastVNode, vNode) { this.isAppear = detectIsAppear(this); this._parentDom = this.parentVNode && this.parentVNode.dom || this.parentDom; this._isImmovable = !!immovableElements[this.element.tagName.toLowerCase()]; this.on('$change:a:transition', initClassName); initClassName(this); // for show/hide animation initAShow(this); // 一个动画元素被删除后,会被保存 // 如果在删除的过程中,又添加了,则要清除上一个动画状态 // 将这种情况记录下来 if (this._lastVNode && this._lastVNode !== lastVNode) { var lastInstance = this._lastVNode.children; if (lastInstance._leaving) { this.lastInstance = lastInstance; } else { lastInstance._cancelLeaveNextFrame(); } } this.parentInstance = getParentAnimate(this); initUnmountCallback(this, vNode); startEnterAnimate(this); }; function initAShow(o) { var element = o.element; var display = element.style.display; var originDisplay = display === 'none' ? '' : display; if (!o.get('a:show')) { element.style.display = 'none'; } // o.on('$change:a:disabled', (c, v) => { // if (v) { // const lastInstance = o.lastInstance; // if (lastInstance && lastInstance._leaving === true) { // lastInstance._leaveEnd(); // } // } // }); o.on('$changed:a:show', function (c, v) { // 如果是appear动画,则在show/hide改为enter动画 if (o.isAppear) { o.isAppear = false; initClassName(o); } if (v) { // 如果在leaveEnd事件中,又触发了enter // 此时_leaving为false,如果不清空lastInstance // 将会在enter中再次触发leaveEnd var lastInstance = o.lastInstance; if (lastInstance && lastInstance._leaving === false) { o.leaveEndCallback = noop; o.lastInstance = null; } element.style.display = originDisplay; startEnterAnimate(o); } else { o.lastInstance = o; o.leaveEndCallback = function () { element.style.display = 'none'; o.lastInstance = null; }; unmountCallback(o); } }); } function startEnterAnimate(o) { if (o.parentInstance) { // 如果存在父动画组件,则使用父级进行管理 // 统一做动画 animateList(o); } else if (o.isAppear || !o.isRender) { // 否则单个元素自己动画 enter(o); } } function enter(o) { if (!o.get('a:show') || o._entering) return; var element = o.element; var isCss = o.get('a:css'); var enterStart = o.get('a:enterStart'); var continuity = o.get('a:continuity'); var disabled = o.get('a:disabled'); // getAnimateInfo将添加enter-active className,在firefox下将导致动画提前执行 // 我们应该先于添加`enter` className去调用该函数 var isTransition = false; var info = void 0; if (isCss) { info = getAnimateInfo(element, o.enterActiveClass); if (info.type !== 'animation') { isTransition = true; } } var endDirectly = false; // 如果这个元素是上一个删除的元素,则从当前状态回到原始状态 if (o.lastInstance) { endDirectly = continuity && !o.lastInstance._triggeredLeave; o.lastInstance._cancelLeaveNextFrame(); o.lastInstance._leaveEnd(true); // 保持连贯,添加leaveActiveClass if (continuity && !endDirectly && isCss && !disabled) { o._addClass(o.enterActiveClass); } } if (disabled) return; initEnterEndCallback(o, info); function start() { o._entering = true; o.trigger(o.enterEventName + 'Start', element); if (!endDirectly) { if (isCss) { o._addClass(o.enterClass); } var cb = function cb() { if (isCss) { o._cancelEnterEnd = whenTransitionEnds(element, info, o._enterEnd); } triggerEnter(o); }; if (isTransition) { o._cancelEnterNextFrame = nextFrame(cb); } else { // 对于animation动画,同步添加enterActiveClass,避免闪动 cb(); } } else { o._enterEnd(); } } // 要保持leave的过程中,enter动画的连贯,enterStart中必须不能操作dom导致重绘 // 但是往往enterStart中会重绘,一种解决思路是: // 将leaveEnd放在enterStart之后执行,但如果enterStart依赖元素的初始状态,而非 // leave的中间状态,此时会导致enterStart中dom操作不符合预期 // 另种一种思路是: // 不去保证拥有enterStart函数的动画的连贯性,此时我们会从enter动画初始状态进行动画 // 这里采取第二种思路 var i = void 0; if (enterStart && (i = enterStart(element)) && i.then) { i.then(function () { if (o.destroyed || !o.get('a:show')) return; start(); }); } else { start(); } } function triggerEnter(o) { var element = o.element; if (o.get('a:css')) { // if (o._entering === false) { // return o._removeClass(o.enterActiveClass); // } o._addClass(o.enterActiveClass); o._removeClass(o.enterClass); } o._triggeredEnter = true; o.trigger(o.enterEventName, element, o._enterEnd); } function detectIsAppear(o) { var isAppear = false; if (o.isRender) { var parent = void 0; if (o.get('a:appear') && (o.parentDom || (parent = o.parentVNode) && parent.type & Types.ComponentClassOrInstance && !parent.children.isRender)) { isAppear = true; } } return isAppear; } function initClassName(o, newValue, oldValue) { var transition = o.get('a:transition'); var element = o.element, isAppear = o.isAppear; var enterClass = void 0; var enterActiveClass = void 0; if (isAppear) { enterClass = transition + '-appear'; enterActiveClass = transition + '-appear-active'; } else { enterClass = transition + '-enter'; enterActiveClass = transition + '-enter-active'; } // o.isAppear = isAppear; o.enterClass = enterClass; o.enterActiveClass = enterActiveClass; o.leaveClass = transition + '-leave'; o.leaveActiveClass = transition + '-leave-active'; o.moveClass = transition + '-move'; o.enterEventName = isAppear ? 'a:appear' : 'a:enter'; if (oldValue) { element.className = element.className.replace(new RegExp('\\b(' + oldValue + '(?=\\-(appear|enter|leave|move)))', 'g'), newValue); var staticClass = {}; var index = oldValue.length; for (var key in this._staticClass) { staticClass[newValue + key.substring(index)] = true; } this._staticClass = staticClass; } } function initEnterEndCallback(o) { var element = o.element, parentInstance = o.parentInstance; var isCss = o.get('a:css'); var disabled = o.get('a:disabled'); o._enterEnd = function (isCancel) { o._enterEnd.isCalled = true; if (o._cancelEnterEnd) { o._cancelEnterEnd(); o._cancelEnterEnd = null; } if (isCss && !disabled) { o._removeClass(o.enterClass); o._removeClass(o.enterActiveClass); } o._entering = false; o._triggeredEnter = false; if (parentInstance) { if (--parentInstance._enteringAmount === 0 && parentInstance.get('a:mode') === 'in-out') { nextFrame(function () { checkMode(parentInstance); }); } } // maybe this animation has ended before next enter frame // so we cancel it if (o._cancelEnterNextFrame) { o._cancelEnterNextFrame(); o._cancelEnterNextFrame = null; } o.trigger(o.enterEventName + 'End', element, isCancel); }; } function initUnmountCallback(o, vNode) { var element = o.element; element._unmount = function (nouse, parentDom) { o.vNode = vNode; o._parentDom = parentDom; o.leaveEndCallback = function (isLeaveEnd) { parentDom.removeChild(element); if (!o.destroyed) { o.destroy(vNode, null, parentDom, true); } }; unmountCallback(o); // 存在一种情况,相同的dom,同时被子组件和父组件管理的情况 // 所以unmount后,将其置为空函数,以免再次unmount element._unmount = noop; }; } function unmountCallback(o) { var parentInstance = o.parentInstance; // 如果该元素是延迟mount的元素,则直接删除 if (o._delayEnter) { o.leaveEndCallback(); parentInstance._enteringAmount--; return; } var isNotAnimate = !o.get('a:css') && !hasJsTransition(o); if (parentInstance && !isNotAnimate) { parentInstance._leavingAmount++; if (parentInstance.get('a:mode') === 'in-out') { parentInstance.updateChildren.push(o); o._delayLeave = true; } else { // add a flag to indicate that this child will leave but we maybe call // _beforeUpdate twice before _update, so let _beforeUpdate reserve it // ksc-fe/kpc#238 o._needLeave = true; parentInstance.unmountChildren.push(o); } parentInstance.children.push(o); } else if (isNotAnimate) { o.leaveEndCallback(); } else { leave(o); } } function animateList(o) { var element = o.element, isAppear = o.isAppear, parentInstance = o.parentInstance; if (isAppear || !o.isRender) { if (o.lastInstance && o.lastInstance._delayLeave) { parentInstance.updateChildren.push(o); } else { parentInstance._enteringAmount++; // 如果没有unmount的元素,则直接enter if (parentInstance._leavingAmount > 0 && parentInstance.get('a:mode') === 'out-in') { o._delayEnter = true; element.style.display = 'none'; } else { parentInstance.mountChildren.push(o); } } } parentInstance.children.push(o); } function getParentAnimate(o) { // 根节点为Animate,不存在parentVNode if (!o.parentVNode) return; // o.parentVNode是animate的tag,所以要拿o.parentVNode.parentVNode var parentVNode = o.parentVNode.parentVNode; if (parentVNode) { var parentInstance = parentVNode.children; if (parentInstance instanceof o.constructor) { return parentInstance; } } } function hasJsTransition(o) { var events = o._events; for (var key in events) { if (key[0] === 'a' && key[1] === ':') { if (events[key].length) { return true; } } } return false; } prototype._beforeUpdate = function (lastVNode, vNode) { // 更新之前,这里的children不包含本次更新mount进来的元素 var children = this.children; var reservedChildren = []; var isMove = this.get('a:move'); for (var i = 0; i < children.length; i++) { var instance = children[i]; if (!instance._leaving && isMove) { instance.position = getPosition(instance); } if (instance._delayLeave) { reservedChildren.push(instance); this.updateChildren.push(instance); } else if (instance._needLeave) { // when we call _beforeUpdate twice before _update // the unmount children will miss // so we add a flag for the children and reserve it // ksc-fe/kpc#238 reservedChildren.push(instance); } } this.children = reservedChildren; }; prototype._update = function (lastVNode, vNode, isFromCheckMode) { var parentInstance = void 0; if (!this.get('a:disabled')) { parentInstance = this.parentInstance; if (parentInstance) { if (!this._needLeave) { parentInstance.updateChildren.push(this); } // when we call _beforeUpdate twice then call _update twice // this instance may exist in children // so we don't push it, but we need update position of it // ksc-fe/kpc#238 var _children = parentInstance.children; var index = _children.indexOf(this); if (!~index) { _children.push(this); } else { this._needUpdatePosition = true; } } } // 更新之后,这里的children包括当前mount/update/unmount的元素 var children = this.children; // 不存在children,则表示没有子动画元素要管理,直接返回 if (!children.length) return; var mountChildren = this.mountChildren; var unmountChildren = this.unmountChildren; var updateChildren = this.updateChildren; var isMove = this.get('a:move'); // 如果是in-out模式,但是没有元素enter,则直接leave if (!isFromCheckMode && this._enteringAmount === 0 && parentInstance && parentInstance.get('a:mode') === 'in-out') { for (var i = 0; i < updateChildren.length; i++) { var instance = updateChildren[i]; if (instance._delayLeave) { unmountChildren.push(instance); updateChildren.splice(i, 1); instance._delayLeave = false; i--; } } } // 进行mount元素的进入动画 // 因为存在moving元素被unmount又被mount的情况 // 所以最先处理 if (isMove) { // if the _needUpdatePosition is true, see above for detail, update the position updateChildren.forEach(function (instance) { if (!instance._leaving && instance._needUpdatePosition) { instance.position = getPosition(instance); } instance._needUpdatePosition = false; }); mountChildren.forEach(function (instance) { // 如果当前元素是从上一个unmount的元素来的, // 则要初始化最新位置,因为beforeUpdate中 // 不包括当前mount元素的位置初始化 // 这样才能保持位置的连贯性 if (instance.lastInstance) { instance.position = getPosition(instance); } }); } mountChildren.forEach(function (instance) { return enter(instance); }); // 先将之前的动画清空 // 只有既在move又在enter的unmount元素才清空动画 // 这种情况保持不了连贯性 if (isMove) { unmountChildren.forEach(function (instance) { if (instance._moving) { instance._moveEnd(); if (instance._entering) { instance._enterEnd(); } } }); // 对于更新的元素,如果正在move,则将位置清空,以便确定最终位置 updateChildren.forEach(function (instance) { if (instance._moving) { if (instance._isImmovable) { instance._moveEnd(); } else { var s = instance.element.style; s.left = s.top = ''; } } }); // 将要删除的元素,设为absolute,以便确定其它元素最终位置 unmountChildren.forEach(function (instance) { // 对于tr等表格元素,不能设置absolute if (!instance._isImmovable) { instance.element.style.position = 'absolute'; } }); // 获取所有元素的新位置 children.forEach(function (instance) { instance._needLeave = false; instance.newPosition = getPosition(instance); }); // 分别判断元素是否需要移动,并保持当前位置不变 // unmount的元素,从当前位置直接leave,不要move了 unmountChildren.forEach(function (instance) { return initMove(instance, true); }); updateChildren.forEach(function (instance) { return initMove(instance); }); mountChildren.forEach(function (instance) { return initMove(instance); }); // 对于animation动画,enterEnd了entering元素 // 需要re-layout,来触发move动画 document.body.offsetWidth; // 如果元素需要移动,则进行move动画 children.forEach(function (instance) { if (instance._needMove) { if (!instance._moving) { move(instance); } else { // 如果已经在移动了,那直接改变translate,保持动画连贯 triggerMove(instance); } } }); } // unmount元素做leave动画 unmountChildren.forEach(function (instance) { // for call _beforeUpdate twice before _update, ksc-fe/kpc#238 children.splice(children.indexOf(instance), 1); leave(instance); }); this.mountChildren = []; this.updateChildren = []; this.unmountChildren = []; }; function initMove(o, isUnmount) { var element = o.element, oldPosition = o.position, newPosition = o.newPosition; o.position = newPosition; // 对于新mount的元素,不进行move判断 if (!oldPosition) return; var dx = oldPosition.left - newPosition.left; var dy = oldPosition.top - newPosition.top; var oDx = o.dx; var oDy = o.dy; o.dx = dx; o.dy = dy; if (dx || dy || oDx || oDy) { // 对于move中的元素,需要将它重新回到0 var s = element.style; var setOffset = !o._isImmovable ? function (x, y) { s.left = x + 'px'; s.top = y + 'px'; } : function (x, y) { s.transform = s.WebkitTransform = 'translate(' + x + 'px, ' + y + 'px)'; }; if (isUnmount) { setOffset(oldPosition.left, oldPosition.top); o._needMove = false; } else { // 如果当前元素正在enter,而且是animation动画,则要enterEnd // 否则无法move if (o._entering && getAnimateInfo(element).type !== 'transition') { o._enterEnd(); } o._needMove = true; if (!o._isImmovable) { s.position = 'relative'; } else { s.transition = s.WebkitTransition = 'none'; } setOffset(dx, dy); } } else { o._needMove = false; // if exist lastInstance but it has not moved // reset the style var lastInstance = o.lastInstance; if (!isUnmount && lastInstance) { var _s = element.style; _s.transition = _s.WebkitTransition = _s.WebkitTransform = _s.transform = _s.position = _s.left = _s.top = ''; } } } function move(o) { if (o.get('a:disabled')) return; o._moving = true; var element = o.element; var s = element.style; o._addClass(o.moveClass); if (o._isImmovable) { s.transition = s.WebkitTransition = ''; } o._moveEnd = function (e) { e && e.stopPropagation(); if (!e || /transform$/.test(e.propertyName)) { TransitionEvents.off(element, o._moveEnd); o._removeClass(o.moveClass); s.transition = s.WebkitTransition = s.position = s.left = s.top = s.transform = s.WebkitTransform = ''; o.dx = o.dy = 0; o._moving = false; } }; TransitionEvents.on(element, o._moveEnd); triggerMove(o); // nextFrame(() => o._triggerMove()); } function triggerMove(o) { var s = o.element.style; if (!o._isImmovable) { s.transform = s.WebkitTransform = 'translate(' + (0 - o.dx) + 'px, ' + (0 - o.dy) + 'px)'; } else { s.transform = s.WebkitTransform = 'translate(0, 0)'; } } function getPosition(o) { var element = o.element; var style = getComputedStyle(element); var transform = style.transform || style.WebkitTransform; if (transform === 'none') { return { top: element.offsetTop, left: element.offsetLeft }; } // const transform = element.style.transform; var matrix = new CSSMatrix(transform); return { top: element.offsetTop + matrix.m42, left: element.offsetLeft + matrix.m41 }; } var Animate = Intact$2.extend(prototype); Intact$2.prototype.Animate = Animate; Intact$2.Animate = Animate; Intact$2.Vdt = Vdt$1; Intact$2.utils = utils; Vdt$1.configure({ getModel: function getModel(self, key) { return self.get(key); }, setModel: function setModel(self, key, value) { // self.set(key, value, {async: true}); self.set(key, value); } }); return Intact$2; })));