alue', attrs.value); } for (key in oldAttrs) { if (isUndef(attrs[key])) { if (isXlink(key)) { elm.removeAttributeNS(xlinkNS, getXlinkProp(key)); } else if (!isEnumeratedAttr(key)) { elm.removeAttribute(key); } } } } function setAttr (el, key, value) { if (el.tagName.indexOf('-') > -1) { baseSetAttr(el, key, value); } else if (isBooleanAttr(key)) { // set attribute for blank value // e.g. <option disabled>Select one</option> if (isFalsyAttrValue(value)) { el.removeAttribute(key); } else { // technically allowfullscreen is a boolean attribute for <iframe>, // but Flash expects a value of "true" when used on <embed> tag value = key === 'allowfullscreen' && el.tagName === 'EMBED' ? 'true' : key; el.setAttribute(key, value); } } else if (isEnumeratedAttr(key)) { el.setAttribute(key, isFalsyAttrValue(value) || value === 'false' ? 'false' : 'true'); } else if (isXlink(key)) { if (isFalsyAttrValue(value)) { el.removeAttributeNS(xlinkNS, getXlinkProp(key)); } else { el.setAttributeNS(xlinkNS, key, value); } } else { baseSetAttr(el, key, value); } } function baseSetAttr (el, key, value) { if (isFalsyAttrValue(value)) { el.removeAttribute(key); } else { // #7138: IE10 & 11 fires input event when setting placeholder on // <textarea>... block the first input event and remove the blocker // immediately. /* istanbul ignore if */ if ( isIE && !isIE9 && el.tagName === 'TEXTAREA' && key === 'placeholder' && !el.__ieph ) { var blocker = function (e) { e.stopImmediatePropagation(); el.removeEventListener('input', blocker); }; el.addEventListener('input', blocker); // $flow-disable-line el.__ieph = true; /* IE placeholder patched */ } el.setAttribute(key, value); } } var attrs = { create: updateAttrs, update: updateAttrs } /* */ function updateClass (oldVnode, vnode) { var el = vnode.elm; var data = vnode.data; var oldData = oldVnode.data; if ( isUndef(data.staticClass) && isUndef(data.class) && ( isUndef(oldData) || ( isUndef(oldData.staticClass) && isUndef(oldData.class) ) ) ) { return } var cls = genClassForVnode(vnode); // handle transition classes var transitionClass = el._transitionClasses; if (isDef(transitionClass)) { cls = concat(cls, stringifyClass(transitionClass)); } // set the class if (cls !== el._prevClass) { el.setAttribute('class', cls); el._prevClass = cls; } } var klass = { create: updateClass, update: updateClass } /* */ var validDivisionCharRE = /[\w).+\-_$\]]/; function parseFilters (exp) { var inSingle = false; var inDouble = false; var inTemplateString = false; var inRegex = false; var curly = 0; var square = 0; var paren = 0; var lastFilterIndex = 0; var c, prev, i, expression, filters; for (i = 0; i < exp.length; i++) { prev = c; c = exp.charCodeAt(i); if (inSingle) { if (c === 0x27 && prev !== 0x5C) { inSingle = false; } } else if (inDouble) { if (c === 0x22 && prev !== 0x5C) { inDouble = false; } } else if (inTemplateString) { if (c === 0x60 && prev !== 0x5C) { inTemplateString = false; } } else if (inRegex) { if (c === 0x2f && prev !== 0x5C) { inRegex = false; } } else if ( c === 0x7C && // pipe exp.charCodeAt(i + 1) !== 0x7C && exp.charCodeAt(i - 1) !== 0x7C && !curly && !square && !paren ) { if (expression === undefined) { // first filter, end of expression lastFilterIndex = i + 1; expression = exp.slice(0, i).trim(); } else { pushFilter(); } } else { switch (c) { case 0x22: inDouble = true; break // " case 0x27: inSingle = true; break // ' case 0x60: inTemplateString = true; break // ` case 0x28: paren++; break // ( case 0x29: paren--; break // ) case 0x5B: square++; break // [ case 0x5D: square--; break // ] case 0x7B: curly++; break // { case 0x7D: curly--; break // } } if (c === 0x2f) { // / var j = i - 1; var p = (void 0); // find first non-whitespace prev char for (; j >= 0; j--) { p = exp.charAt(j); if (p !== ' ') { break } } if (!p || !validDivisionCharRE.test(p)) { inRegex = true; } } } } if (expression === undefined) { expression = exp.slice(0, i).trim(); } else if (lastFilterIndex !== 0) { pushFilter(); } function pushFilter () { (filters || (filters = [])).push(exp.slice(lastFilterIndex, i).trim()); lastFilterIndex = i + 1; } if (filters) { for (i = 0; i < filters.length; i++) { expression = wrapFilter(expression, filters[i]); } } return expression } function wrapFilter (exp, filter) { var i = filter.indexOf('('); if (i < 0) { // _f: resolveFilter return ("_f(\"" + filter + "\")(" + exp + ")") } else { var name = filter.slice(0, i); var args = filter.slice(i + 1); return ("_f(\"" + name + "\")(" + exp + (args !== ')' ? ',' + args : args)) } } /* */ function baseWarn (msg) { console.error(("[Vue compiler]: " + msg)); } function pluckModuleFunction ( modules, key ) { return modules ? modules.map(function (m) { return m[key]; }).filter(function (_) { return _; }) : [] } function addProp (el, name, value) { (el.props || (el.props = [])).push({ name: name, value: value }); el.plain = false; } function addAttr (el, name, value) { (el.attrs || (el.attrs = [])).push({ name: name, value: value }); el.plain = false; } // add a raw attr (use this in preTransforms) function addRawAttr (el, name, value) { el.attrsMap[name] = value; el.attrsList.push({ name: name, value: value }); } function addDirective ( el, name, rawName, value, arg, modifiers ) { (el.directives || (el.directives = [])).push({ name: name, rawName: rawName, value: value, arg: arg, modifiers: modifiers }); el.plain = false; } function addHandler ( el, name, value, modifiers, important, warn ) { modifiers = modifiers || emptyObject; // warn prevent and passive modifier /* istanbul ignore if */ if ( process.env.NODE_ENV !== 'production' && warn && modifiers.prevent && modifiers.passive ) { warn( 'passive and prevent can\'t be used together. ' + 'Passive handler can\'t prevent default event.' ); } // check capture modifier if (modifiers.capture) { delete modifiers.capture; name = '!' + name; // mark the event as captured } if (modifiers.once) { delete modifiers.once; name = '~' + name; // mark the event as once } /* istanbul ignore if */ if (modifiers.passive) { delete modifiers.passive; name = '&' + name; // mark the event as passive } // normalize click.right and click.middle since they don't actually fire // this is technically browser-specific, but at least for now browsers are // the only target envs that have right/middle clicks. if (name === 'click') { if (modifiers.right) { name = 'contextmenu'; delete modifiers.right; } else if (modifiers.middle) { name = 'mouseup'; } } var events; if (modifiers.native) { delete modifiers.native; events = el.nativeEvents || (el.nativeEvents = {}); } else { events = el.events || (el.events = {}); } var newHandler = { value: value.trim() }; if (modifiers !== emptyObject) { newHandler.modifiers = modifiers; } var handlers = events[name]; /* istanbul ignore if */ if (Array.isArray(handlers)) { important ? handlers.unshift(newHandler) : handlers.push(newHandler); } else if (handlers) { events[name] = important ? [newHandler, handlers] : [handlers, newHandler]; } else { events[name] = newHandler; } el.plain = false; } function getBindingAttr ( el, name, getStatic ) { var dynamicValue = getAndRemoveAttr(el, ':' + name) || getAndRemoveAttr(el, 'v-bind:' + name); if (dynamicValue != null) { return parseFilters(dynamicValue) } else if (getStatic !== false) { var staticValue = getAndRemoveAttr(el, name); if (staticValue != null) { return JSON.stringify(staticValue) } } } // note: this only removes the attr from the Array (attrsList) so that it // doesn't get processed by processAttrs. // By default it does NOT remove it from the map (attrsMap) because the map is // needed during codegen. function getAndRemoveAttr ( el, name, removeFromMap ) { var val; if ((val = el.attrsMap[name]) != null) { var list = el.attrsList; for (var i = 0, l = list.length; i < l; i++) { if (list[i].name === name) { list.splice(i, 1); break } } } if (removeFromMap) { delete el.attrsMap[name]; } return val } /* */ /** * Cross-platform code generation for component v-model */ function genComponentModel ( el, value, modifiers ) { var ref = modifiers || {}; var number = ref.number; var trim = ref.trim; var baseValueExpression = '$$v'; var valueExpression = baseValueExpression; if (trim) { valueExpression = "(typeof " + baseValueExpression + " === 'string'" + "? " + baseValueExpression + ".trim()" + ": " + baseValueExpression + ")"; } if (number) { valueExpression = "_n(" + valueExpression + ")"; } var assignment = genAssignmentCode(value, valueExpression); el.model = { value: ("(" + value + ")"), expression: ("\"" + value + "\""), callback: ("function (" + baseValueExpression + ") {" + assignment + "}") }; } /** * Cross-platform codegen helper for generating v-model value assignment code. */ function genAssignmentCode ( value, assignment ) { var res = parseModel(value); if (res.key === null) { return (value + "=" + assignment) } else { return ("$set(" + (res.exp) + ", " + (res.key) + ", " + assignment + ")") } } /** * Parse a v-model expression into a base path and a final key segment. * Handles both dot-path and possible square brackets. * * Possible cases: * * - test * - test[key] * - test[test1[key]] * - test["a"][key] * - xxx.test[a[a].test1[key]] * - test.xxx.a["asa"][test1[key]] * */ var len; var str; var chr; var index$1; var expressionPos; var expressionEndPos; function parseModel (val) { // Fix https://github.com/vuejs/vue/pull/7730 // allow v-model="obj.val " (trailing whitespace) val = val.trim(); len = val.length; if (val.indexOf('[') < 0 || val.lastIndexOf(']') < len - 1) { index$1 = val.lastIndexOf('.'); if (index$1 > -1) { return { exp: val.slice(0, index$1), key: '"' + val.slice(index$1 + 1) + '"' } } else { return { exp: val, key: null } } } str = val; index$1 = expressionPos = expressionEndPos = 0; while (!eof()) { chr = next(); /* istanbul ignore if */ if (isStringStart(chr)) { parseString(chr); } else if (chr === 0x5B) { parseBracket(chr); } } return { exp: val.slice(0, expressionPos), key: val.slice(expressionPos + 1, expressionEndPos) } } function next () { return str.charCodeAt(++index$1) } function eof () { return index$1 >= len } function isStringStart (chr) { return chr === 0x22 || chr === 0x27 } function parseBracket (chr) { var inBracket = 1; expressionPos = index$1; while (!eof()) { chr = next(); if (isStringStart(chr)) { parseString(chr); continue } if (chr === 0x5B) { inBracket++; } if (chr === 0x5D) { inBracket--; } if (inBracket === 0) { expressionEndPos = index$1; break } } } function parseString (chr) { var stringQuote = chr; while (!eof()) { chr = next(); if (chr === stringQuote) { break } } } /* */ var warn$1; // in some cases, the event used has to be determined at runtime // so we used some reserved tokens during compile. var RANGE_TOKEN = '__r'; var CHECKBOX_RADIO_TOKEN = '__c'; function model ( el, dir, _warn ) { warn$1 = _warn; var value = dir.value; var modifiers = dir.modifiers; var tag = el.tag; var type = el.attrsMap.type; if (process.env.NODE_ENV !== 'production') { // inputs with type="file" are read only and setting the input's // value will throw an error. if (tag === 'input' && type === 'file') { warn$1( "<" + (el.tag) + " v-model=\"" + value + "\" type=\"file\">:\n" + "File inputs are read only. Use a v-on:change listener instead." ); } } if (el.component) { genComponentModel(el, value, modifiers); // component v-model doesn't need extra runtime return false } else if (tag === 'select') { genSelect(el, value, modifiers); } else if (tag === 'input' && type === 'checkbox') { genCheckboxModel(el, value, modifiers); } else if (tag === 'input' && type === 'radio') { genRadioModel(el, value, modifiers); } else if (tag === 'input' || tag === 'textarea') { genDefaultModel(el, value, modifiers); } else if (!config.isReservedTag(tag)) { genComponentModel(el, value, modifiers); // component v-model doesn't need extra runtime return false } else if (process.env.NODE_ENV !== 'production') { warn$1( "<" + (el.tag) + " v-model=\"" + value + "\">: " + "v-model is not supported on this element type. " + 'If you are working with contenteditable, it\'s recommended to ' + 'wrap a library dedicated for that purpose inside a custom component.' ); } // ensure runtime directive metadata return true } function genCheckboxModel ( el, value, modifiers ) { var number = modifiers && modifiers.number; var valueBinding = getBindingAttr(el, 'value') || 'null'; var trueValueBinding = getBindingAttr(el, 'true-value') || 'true'; var falseValueBinding = getBindingAttr(el, 'false-value') || 'false'; addProp(el, 'checked', "Array.isArray(" + value + ")" + "?_i(" + value + "," + valueBinding + ")>-1" + ( trueValueBinding === 'true' ? (":(" + value + ")") : (":_q(" + value + "," + trueValueBinding + ")") ) ); addHandler(el, 'change', "var $$a=" + value + "," + '$$el=$event.target,' + "$$c=$$el.checked?(" + trueValueBinding + "):(" + falseValueBinding + ");" + 'if(Array.isArray($$a)){' + "var $$v=" + (number ? '_n(' + valueBinding + ')' : valueBinding) + "," + '$$i=_i($$a,$$v);' + "if($$el.checked){$$i<0&&(" + (genAssignmentCode(value, '$$a.concat([$$v])')) + ")}" + "else{$$i>-1&&(" + (genAssignmentCode(value, '$$a.slice(0,$$i).concat($$a.slice($$i+1))')) + ")}" + "}else{" + (genAssignmentCode(value, '$$c')) + "}", null, true ); } function genRadioModel ( el, value, modifiers ) { var number = modifiers && modifiers.number; var valueBinding = getBindingAttr(el, 'value') || 'null'; valueBinding = number ? ("_n(" + valueBinding + ")") : valueBinding; addProp(el, 'checked', ("_q(" + value + "," + valueBinding + ")")); addHandler(el, 'change', genAssignmentCode(value, valueBinding), null, true); } function genSelect ( el, value, modifiers ) { var number = modifiers && modifiers.number; var selectedVal = "Array.prototype.filter" + ".call($event.target.options,function(o){return o.selected})" + ".map(function(o){var val = \"_value\" in o ? o._value : o.value;" + "return " + (number ? '_n(val)' : 'val') + "})"; var assignment = '$event.target.multiple ? $$selectedVal : $$selectedVal[0]'; var code = "var $$selectedVal = " + selectedVal + ";"; code = code + " " + (genAssignmentCode(value, assignment)); addHandler(el, 'change', code, null, true); } function genDefaultModel ( el, value, modifiers ) { var type = el.attrsMap.type; // warn if v-bind:value conflicts with v-model // except for inputs with v-bind:type if (process.env.NODE_ENV !== 'production') { var value$1 = el.attrsMap['v-bind:value'] || el.attrsMap[':value']; var typeBinding = el.attrsMap['v-bind:type'] || el.attrsMap[':type']; if (value$1 && !typeBinding) { var binding = el.attrsMap['v-bind:value'] ? 'v-bind:value' : ':value'; warn$1( binding + "=\"" + value$1 + "\" conflicts with v-model on the same element " + 'because the latter already expands to a value binding internally' ); } } var ref = modifiers || {}; var lazy = ref.lazy; var number = ref.number; var trim = ref.trim; var needCompositionGuard = !lazy && type !== 'range'; var event = lazy ? 'change' : type === 'range' ? RANGE_TOKEN : 'input'; var valueExpression = '$event.target.value'; if (trim) { valueExpression = "$event.target.value.trim()"; } if (number) { valueExpression = "_n(" + valueExpression + ")"; } var code = genAssignmentCode(value, valueExpression); if (needCompositionGuard) { code = "if($event.target.composing)return;" + code; } addProp(el, 'value', ("(" + value + ")")); addHandler(el, event, code, null, true); if (trim || number) { addHandler(el, 'blur', '$forceUpdate()'); } } /* */ // normalize v-model event tokens that can only be determined at runtime. // it's important to place the event as the first in the array because // the whole point is ensuring the v-model callback gets called before // user-attached handlers. function normalizeEvents (on) { /* istanbul ignore if */ if (isDef(on[RANGE_TOKEN])) { // IE input[type=range] only supports `change` event var event = isIE ? 'change' : 'input'; on[event] = [].concat(on[RANGE_TOKEN], on[event] || []); delete on[RANGE_TOKEN]; } // This was originally intended to fix #4521 but no longer necessary // after 2.5. Keeping it for backwards compat with generated code from < 2.4 /* istanbul ignore if */ if (isDef(on[CHECKBOX_RADIO_TOKEN])) { on.change = [].concat(on[CHECKBOX_RADIO_TOKEN], on.change || []); delete on[CHECKBOX_RADIO_TOKEN]; } } var target$1; function createOnceHandler (handler, event, capture) { var _target = target$1; // save current target element in closure return function onceHandler () { var res = handler.apply(null, arguments); if (res !== null) { remove$2(event, onceHandler, capture, _target); } } } function add$1 ( event, handler, once$$1, capture, passive ) { handler = withMacroTask(handler); if (once$$1) { handler = createOnceHandler(handler, event, capture); } target$1.addEventListener( event, handler, supportsPassive ? { capture: capture, passive: passive } : capture ); } function remove$2 ( event, handler, capture, _target ) { (_target || target$1).removeEventListener( event, handler._withTask || handler, capture ); } function updateDOMListeners (oldVnode, vnode) { if (isUndef(oldVnode.data.on) && isUndef(vnode.data.on)) { return } var on = vnode.data.on || {}; var oldOn = oldVnode.data.on || {}; target$1 = vnode.elm; normalizeEvents(on); updateListeners(on, oldOn, add$1, remove$2, vnode.context); target$1 = undefined; } var events = { create: updateDOMListeners, update: updateDOMListeners } /* */ function updateDOMProps (oldVnode, vnode) { if (isUndef(oldVnode.data.domProps) && isUndef(vnode.data.domProps)) { return } var key, cur; var elm = vnode.elm; var oldProps = oldVnode.data.domProps || {}; var props = vnode.data.domProps || {}; // clone observed objects, as the user probably wants to mutate it if (isDef(props.__ob__)) { props = vnode.data.domProps = extend({}, props); } for (key in oldProps) { if (isUndef(props[key])) { elm[key] = ''; } } for (key in props) { cur = props[key]; // ignore children if the node has textContent or innerHTML, // as these will throw away existing DOM nodes and cause removal errors // on subsequent patches (#3360) if (key === 'textContent' || key === 'innerHTML') { if (vnode.children) { vnode.children.length = 0; } if (cur === oldProps[key]) { continue } // #6601 work around Chrome version <= 55 bug where single textNode // replaced by innerHTML/textContent retains its parentNode property if (elm.childNodes.length === 1) { elm.removeChild(elm.childNodes[0]); } } if (key === 'value') { // store value as _value as well since // non-string values will be stringified elm._value = cur; // avoid resetting cursor position when value is the same var strCur = isUndef(cur) ? '' : String(cur); if (shouldUpdateValue(elm, strCur)) { elm.value = strCur; } } else { elm[key] = cur; } } } // check platforms/web/util/attrs.js acceptValue function shouldUpdateValue (elm, checkVal) { return (!elm.composing && ( elm.tagName === 'OPTION' || isNotInFocusAndDirty(elm, checkVal) || isDirtyWithModifiers(elm, checkVal) )) } function isNotInFocusAndDirty (elm, checkVal) { // return true when textbox (.number and .trim) loses focus and its value is // not equal to the updated value var notInFocus = true; // #6157 // work around IE bug when accessing document.activeElement in an iframe try { notInFocus = document.activeElement !== elm; } catch (e) {} return notInFocus && elm.value !== checkVal } function isDirtyWithModifiers (elm, newVal) { var value = elm.value; var modifiers = elm._vModifiers; // injected by v-model runtime if (isDef(modifiers)) { if (modifiers.lazy) { // inputs with lazy should only be updated when not in focus return false } if (modifiers.number) { return toNumber(value) !== toNumber(newVal) } if (modifiers.trim) { return value.trim() !== newVal.trim() } } return value !== newVal } var domProps = { create: updateDOMProps, update: updateDOMProps } /* */ var parseStyleText = cached(function (cssText) { var res = {}; var listDelimiter = /;(?![^(]*\))/g; var propertyDelimiter = /:(.+)/; cssText.split(listDelimiter).forEach(function (item) { if (item) { var tmp = item.split(propertyDelimiter); tmp.length > 1 && (res[tmp[0].trim()] = tmp[1].trim()); } }); return res }); // merge static and dynamic style data on the same vnode function normalizeStyleData (data) { var style = normalizeStyleBinding(data.style); // static style is pre-processed into an object during compilation // and is always a fresh object, so it's safe to merge into it return data.staticStyle ? extend(data.staticStyle, style) : style } // normalize possible array / string values into Object function normalizeStyleBinding (bindingStyle) { if (Array.isArray(bindingStyle)) { return toObject(bindingStyle) } if (typeof bindingStyle === 'string') { return parseStyleText(bindingStyle) } return bindingStyle } /** * parent component style should be after child's * so that parent component's style could override it */ function getStyle (vnode, checkChild) { var res = {}; var styleData; if (checkChild) { var childNode = vnode; while (childNode.componentInstance) { childNode = childNode.componentInstance._vnode; if ( childNode && childNode.data && (styleData = normalizeStyleData(childNode.data)) ) { extend(res, styleData); } } } if ((styleData = normalizeStyleData(vnode.data))) { extend(res, styleData); } var parentNode = vnode; while ((parentNode = parentNode.parent)) { if (parentNode.data && (styleData = normalizeStyleData(parentNode.data))) { extend(res, styleData); } } return res } /* */ var cssVarRE = /^--/; var importantRE = /\s*!important$/; var setProp = function (el, name, val) { /* istanbul ignore if */ if (cssVarRE.test(name)) { el.style.setProperty(name, val); } else if (importantRE.test(val)) { el.style.setProperty(name, val.replace(importantRE, ''), 'important'); } else { var normalizedName = normalize(name); if (Array.isArray(val)) { // Support values array created by autoprefixer, e.g. // {display: ["-webkit-box", "-ms-flexbox", "flex"]} // Set them one by one, and the browser will only set those it can recognize for (var i = 0, len = val.length; i < len; i++) { el.style[normalizedName] = val[i]; } } else { el.style[normalizedName] = val; } } }; var vendorNames = ['Webkit', 'Moz', 'ms']; var emptyStyle; var normalize = cached(function (prop) { emptyStyle = emptyStyle || document.createElement('div').style; prop = camelize(prop); if (prop !== 'filter' && (prop in emptyStyle)) { return prop } var capName = prop.charAt(0).toUpperCase() + prop.slice(1); for (var i = 0; i < vendorNames.length; i++) { var name = vendorNames[i] + capName; if (name in emptyStyle) { return name } } }); function updateStyle (oldVnode, vnode) { var data = vnode.data; var oldData = oldVnode.data; if (isUndef(data.staticStyle) && isUndef(data.style) && isUndef(oldData.staticStyle) && isUndef(oldData.style) ) { return } var cur, name; var el = vnode.elm; var oldStaticStyle = oldData.staticStyle; var oldStyleBinding = oldData.normalizedStyle || oldData.style || {}; // if static style exists, stylebinding already merged into it when doing normalizeStyleData var oldStyle = oldStaticStyle || oldStyleBinding; var style = normalizeStyleBinding(vnode.data.style) || {}; // store normalized style under a different key for next diff // make sure to clone it if it's reactive, since the user likely wants // to mutate it. vnode.data.normalizedStyle = isDef(style.__ob__) ? extend({}, style) : style; var newStyle = getStyle(vnode, true); for (name in oldStyle) { if (isUndef(newStyle[name])) { setProp(el, name, ''); } } for (name in newStyle) { cur = newStyle[name]; if (cur !== oldStyle[name]) { // ie9 setting to null has no effect, must use empty string setProp(el, name, cur == null ? '' : cur); } } } var style = { create: updateStyle, update: updateStyle } /* */ /** * Add class with compatibility for SVG since classList is not supported on * SVG elements in IE */ function addClass (el, cls) { /* istanbul ignore if */ if (!cls || !(cls = cls.trim())) { return } /* istanbul ignore else */ if (el.classList) { if (cls.indexOf(' ') > -1) { cls.split(/\s+/).forEach(function (c) { return el.classList.add(c); }); } else { el.classList.add(cls); } } else { var cur = " " + (el.getAttribute('class') || '') + " "; if (cur.indexOf(' ' + cls + ' ') < 0) { el.setAttribute('class', (cur + cls).trim()); } } } /** * Remove class with compatibility for SVG since classList is not supported on * SVG elements in IE */ function removeClass (el, cls) { /* istanbul ignore if */ if (!cls || !(cls = cls.trim())) { return } /* istanbul ignore else */ if (el.classList) { if (cls.indexOf(' ') > -1) { cls.split(/\s+/).forEach(function (c) { return el.classList.remove(c); }); } else { el.classList.remove(cls); } if (!el.classList.length) { el.removeAttribute('class'); } } else { var cur = " " + (el.getAttribute('class') || '') + " "; var tar = ' ' + cls + ' '; while (cur.indexOf(tar) >= 0) { cur = cur.replace(tar, ' '); } cur = cur.trim(); if (cur) { el.setAttribute('class', cur); } else { el.removeAttribute('class'); } } } /* */ function resolveTransition (def) { if (!def) { return } /* istanbul ignore else */ if (typeof def === 'object') { var res = {}; if (def.css !== false) { extend(res, autoCssTransition(def.name || 'v')); } extend(res, def); return res } else if (typeof def === 'string') { return autoCssTransition(def) } } var autoCssTransition = cached(function (name) { return { enterClass: (name + "-enter"), enterToClass: (name + "-enter-to"), enterActiveClass: (name + "-enter-active"), leaveClass: (name + "-leave"), leaveToClass: (name + "-leave-to"), leaveActiveClass: (name + "-leave-active") } }); var hasTransition = inBrowser && !isIE9; var TRANSITION = 'transition'; var ANIMATION = 'animation'; // Transition property/event sniffing var transitionProp = 'transition'; var transitionEndEvent = 'transitionend'; var animationProp = 'animation'; var animationEndEvent = 'animationend'; if (hasTransition) { /* istanbul ignore if */ if (window.ontransitionend === undefined && window.onwebkittransitionend !== undefined ) { transitionProp = 'WebkitTransition'; transitionEndEvent = 'webkitTransitionEnd'; } if (window.onanimationend === undefined && window.onwebkitanimationend !== undefined ) { animationProp = 'WebkitAnimation'; animationEndEvent = 'webkitAnimationEnd'; } } // binding to window is necessary to make hot reload work in IE in strict mode var raf = inBrowser ? window.requestAnimationFrame ? window.requestAnimationFrame.bind(window) : setTimeout : /* istanbul ignore next */ function (fn) { return fn(); }; function nextFrame (fn) { raf(function () { raf(fn); }); } function addTransitionClass (el, cls) { var transitionClasses = el._transitionClasses || (el._transitionClasses = []); if (transitionClasses.indexOf(cls) < 0) { transitionClasses.push(cls); addClass(el, cls); } } function removeTransitionClass (el, cls) { if (el._transitionClasses) { remove(el._transitionClasses, cls); } removeClass(el, cls); } function whenTransitionEnds ( el, expectedType, cb ) { var ref = getTransitionInfo(el, expectedType); var type = ref.type; var timeout = ref.timeout; var propCount = ref.propCount; if (!type) { return cb() } var event = type === TRANSITION ? transitionEndEvent : animationEndEvent; var ended = 0; var end = function () { el.removeEventListener(event, onEnd); cb(); }; var onEnd = function (e) { if (e.target === el) { if (++ended >= propCount) { end(); } } }; setTimeout(function () { if (ended < propCount) { end(); } }, timeout + 1); el.addEventListener(event, onEnd); } var transformRE = /\b(transform|all)(,|$)/; function getTransitionInfo (el, expectedType) { var styles = window.getComputedStyle(el); var transitionDelays = styles[transitionProp + 'Delay'].split(', '); var transitionDurations = styles[transitionProp + 'Duration'].split(', '); var transitionTimeout = getTimeout(transitionDelays, transitionDurations); var animationDelays = styles[animationProp + 'Delay'].split(', '); var animationDurations = styles[animationProp + 'Duration'].split(', '); var animationTimeout = getTimeout(animationDelays, animationDurations); var type; var timeout = 0; var propCount = 0; /* istanbul ignore if */ if (expectedType === TRANSITION) { if (transitionTimeout > 0) { type = TRANSITION; timeout = transitionTimeout; propCount = transitionDurations.length; } } else if (expectedType === ANIMATION) { if (animationTimeout > 0) { type = ANIMATION; timeout = animationTimeout; propCount = animationDurations.length; } } else { timeout = Math.max(transitionTimeout, animationTimeout); type = timeout > 0 ? transitionTimeout > animationTimeout ? TRANSITION : ANIMATION : null; propCount = type ? type === TRANSITION ? transitionDurations.length : animationDurations.length : 0; } var hasTransform = type === TRANSITION && transformRE.test(styles[transitionProp + 'Property']); return { type: type, timeout: timeout, propCount: propCount, hasTransform: hasTransform } } function getTimeout (delays, durations) { /* istanbul ignore next */ while (delays.length < durations.length) { delays = delays.concat(delays); } return Math.max.apply(null, durations.map(function (d, i) { return toMs(d) + toMs(delays[i]) })) } function toMs (s) { return Number(s.slice(0, -1)) * 1000 } /* */ function enter (vnode, toggleDisplay) { var el = vnode.elm; // call leave callback now if (isDef(el._leaveCb)) { el._leaveCb.cancelled = true; el._leaveCb(); } var data = resolveTransition(vnode.data.transition); if (isUndef(data)) { return } /* istanbul ignore if */ if (isDef(el._enterCb) || el.nodeType !== 1) { return } var css = data.css; var type = data.type; var enterClass = data.enterClass; var enterToClass = data.enterToClass; var enterActiveClass = data.enterActiveClass; var appearClass = data.appearClass; var appearToClass = data.appearToClass; var appearActiveClass = data.appearActiveClass; var beforeEnter = data.beforeEnter; var enter = data.enter; var afterEnter = data.afterEnter; var enterCancelled = data.enterCancelled; var beforeAppear = data.beforeAppear; var appear = data.appear; var afterAppear = data.afterAppear; var appearCancelled = data.appearCancelled; var duration = data.duration; // activeInstance will always be the <transition> component managing this // transition. One edge case to check is when the <transition> is placed // as the root node of a child component. In that case we need to check // <transition>'s parent for appear check. var context = activeInstance; var transitionNode = activeInstance.$vnode; while (transitionNode && transitionNode.parent) { transitionNode = transitionNode.parent; context = transitionNode.context; } var isAppear = !context._isMounted || !vnode.isRootInsert; if (isAppear && !appear && appear !== '') { return } var startClass = isAppear && appearClass ? appearClass : enterClass; var activeClass = isAppear && appearActiveClass ? appearActiveClass : enterActiveClass; var toClass = isAppear && appearToClass ? appearToClass : enterToClass; var beforeEnterHook = isAppear ? (beforeAppear || beforeEnter) : beforeEnter; var enterHook = isAppear ? (typeof appear === 'function' ? appear : enter) : enter; var afterEnterHook = isAppear ? (afterAppear || afterEnter) : afterEnter; var enterCancelledHook = isAppear ? (appearCancelled || enterCancelled) : enterCancelled; var explicitEnterDuration = toNumber( isObject(duration) ? duration.enter : duration ); if (process.env.NODE_ENV !== 'production' && explicitEnterDuration != null) { checkDuration(explicitEnterDuration, 'enter', vnode); } var expectsCSS = css !== false && !isIE9; var userWantsControl = getHookArgumentsLength(enterHook); var cb = el._enterCb = once(function () { if (expectsCSS) { removeTransitionClass(el, toClass); removeTransitionClass(el, activeClass); } if (cb.cancelled) { if (expectsCSS) { removeTransitionClass(el, startClass); } enterCancelledHook && enterCancelledHook(el); } else { afterEnterHook && afterEnterHook(el); } el._enterCb = null; }); if (!vnode.data.show) { // remove pending leave element on enter by injecting an insert hook mergeVNodeHook(vnode, 'insert', function () { var parent = el.parentNode; var pendingNode = parent && parent._pending && parent._pending[vnode.key]; if (pendingNode && pendingNode.tag === vnode.tag && pendingNode.elm._leaveCb ) { pendingNode.elm._leaveCb(); } enterHook && enterHook(el, cb); }); } // start enter transition beforeEnterHook && beforeEnterHook(el); if (expectsCSS) { addTransitionClass(el, startClass); addTransitionClass(el, activeClass); nextFrame(function () { removeTransitionClass(el, startClass); if (!cb.cancelled) { addTransitionClass(el, toClass); if (!userWantsControl) { if (isValidDuration(explicitEnterDuration)) { setTimeout(cb, explicitEnterDuration); } else { whenTransitionEnds(el, type, cb); } } } }); } if (vnode.data.show) { toggleDisplay && toggleDisplay(); enterHook && enterHook(el, cb); } if (!expectsCSS && !userWantsControl) { cb(); } } function leave (vnode, rm) { var el = vnode.elm; // call enter callback now if (isDef(el._enterCb)) { el._enterCb.cancelled = true; el._enterCb(); } var data = resolveTransition(vnode.data.transition); if (isUndef(data) || el.nodeType !== 1) { return rm() } /* istanbul ignore if */ if (isDef(el._leaveCb)) { return } var css = data.css; var type = data.type; var leaveClass = data.leaveClass; var leaveToClass = data.leaveToClass; var leaveActiveClass = data.leaveActiveClass; var beforeLeave = data.beforeLeave; var leave = data.leave; var afterLeave = data.afterLeave; var leaveCancelled = data.leaveCancelled; var delayLeave = data.delayLeave; var duration = data.duration; var expectsCSS = css !== false && !isIE9; var userWantsControl = getHookArgumentsLength(leave); var explicitLeaveDuration = toNumber( isObject(duration) ? duration.leave : duration ); if (process.env.NODE_ENV !== 'production' && isDef(explicitLeaveDuration)) { checkDuration(explicitLeaveDuration, 'leave', vnode); } var cb = el._leaveCb = once(function () { if (el.parentNode && el.parentNode._pending) { el.parentNode._pending[vnode.key] = null; } if (expectsCSS) { removeTransitionClass(el, leaveToClass); removeTransitionClass(el, leaveActiveClass); } if (cb.cancelled) { if (expectsCSS) { removeTransitionClass(el, leaveClass); } leaveCancelled && leaveCancelled(el); } else { rm(); afterLeave && afterLeave(el); } el._leaveCb = null; }); if (delayLeave) { delayLeave(performLeave); } else { performLeave(); } function performLeave () { // the delayed leave may have already been cancelled if (cb.cancelled) { return } // record leaving element if (!vnode.data.show) { (el.parentNode._pending || (el.parentNode._pending = {}))[(vnode.key)] = vnode; } beforeLeave && beforeLeave(el); if (expectsCSS) { addTransitionClass(el, leaveClass); addTransitionClass(el, leaveActiveClass); nextFrame(function () { removeTransitionClass(el, leaveClass); if (!cb.cancelled) { addTransitionClass(el, leaveToClass); if (!userWantsControl) { if (isValidDuration(explicitLeaveDuration)) { setTimeout(cb, explicitLeaveDuration); } else { whenTransitionEnds(el, type, cb); } } } }); } leave && leave(el, cb); if (!expectsCSS && !userWantsControl) { cb(); } } } // only used in dev mode function checkDuration (val, name, vnode) { if (typeof val !== 'number') { warn( "<transition> explicit " + name + " duration is not a valid number - " + "got " + (JSON.stringify(val)) + ".", vnode.context ); } else if (isNaN(val)) { warn( "<transition> explicit " + name + " duration is NaN - " + 'the duration expression might be incorrect.', vnode.context ); } } function isValidDuration (val) { return typeof val === 'number' && !isNaN(val) } /** * Normalize a transition hook's argument length. The hook may be: * - a merged hook (invoker) with the original in .fns * - a wrapped component method (check ._length) * - a plain function (.length) */ function getHookArgumentsLength (fn) { if (isUndef(fn)) { return false } var invokerFns = fn.fns; if (isDef(invokerFns)) { // invoker return getHookArgumentsLength( Array.isArray(invokerFns) ? invokerFns[0] : invokerFns ) } else { return (fn._length || fn.length) > 1 } } function _enter (_, vnode) { if (vnode.data.show !== true) { enter(vnode); } } var transition = inBrowser ? { create: _enter, activate: _enter, remove: function remove$$1 (vnode, rm) { /* istanbul ignore else */ if (vnode.data.show !== true) { leave(vnode, rm); } else { rm(); } } } : {} var platformModules = [ attrs, klass, events, domProps, style, transition ] /* */ // the directive module should be applied last, after all // built-in modules have been applied. var modules = platformModules.concat(baseModules); var patch = createPatchFunction({ nodeOps: nodeOps, modules: modules }); /** * Not type checking this file because flow doesn't like attaching * properties to Elements. */ /* istanbul ignore if */ if (isIE9) { // http://www.matts411.com/post/internet-explorer-9-oninput/ document.addEventListener('selectionchange', function () { var el = document.activeElement; if (el && el.vmodel) { trigger(el, 'input'); } }); } var directive = { inserted: function inserted (el, binding, vnode, oldVnode) { if (vnode.tag === 'select') { // #6903 if (oldVnode.elm && !oldVnode.elm._vOptions) { mergeVNodeHook(vnode, 'postpatch', function () { directive.componentUpdated(el, binding, vnode); }); } else { setSelected(el, binding, vnode.context); } el._vOptions = [].map.call(el.options, getValue); } else if (vnode.tag === 'textarea' || isTextInputType(el.type)) { el._vModifiers = binding.modifiers; if (!binding.modifiers.lazy) { el.addEventListener('compositionstart', onCompositionStart); el.addEventListener('compositionend', onCompositionEnd); // Safari < 10.2 & UIWebView doesn't fire compositionend when // switching focus before confirming composition choice // this also fixes the issue where some browsers e.g. iOS Chrome // fires "change" instead of "input" on autocomplete. el.addEventListener('change', onCompositionEnd); /* istanbul ignore if */ if (isIE9) { el.vmodel = true; } } } }, componentUpdated: function componentUpdated (el, binding, vnode) { if (vnode.tag === 'select') { setSelected(el, binding, vnode.context); // in case the options rendered by v-for have changed, // it's possible that the value is out-of-sync with the rendered options. // detect such cases and filter out values that no longer has a matching // option in the DOM. var prevOptions = el._vOptions; var curOptions = el._vOptions = [].map.call(el.options, getValue); if (curOptions.some(function (o, i) { return !looseEqual(o, prevOptions[i]); })) { // trigger change event if // no matching option found for at least one value var needReset = el.multiple ? binding.value.some(function (v) { return hasNoMatchingOption(v, curOptions); }) : binding.value !== binding.oldValue && hasNoMatchingOption(binding.value, curOptions); if (needReset) { trigger(el, 'change'); } } } } }; function setSelected (el, binding, vm) { actuallySetSelected(el, binding, vm); /* istanbul ignore if */ if (isIE || isEdge) { setTimeout(function () { actuallySetSelected(el, binding, vm); }, 0); } } function actuallySetSelected (el, binding, vm) { var value = binding.value; var isMultiple = el.multiple; if (isMultiple && !Array.isArray(value)) { process.env.NODE_ENV !== 'production' && warn( "<select multiple v-model=\"" + (binding.expression) + "\"> " + "expects an Array value for its binding, but got " + (Object.prototype.toString.call(value).slice(8, -1)), vm ); return } var selected, option; for (var i = 0, l = el.options.length; i < l; i++) { option = el.options[i]; if (isMultiple) { selected = looseIndexOf(value, getValue(option)) > -1; if (option.selected !== selected) { option.selected = selected; } } else { if (looseEqual(getValue(option), value)) { if (el.selectedIndex !== i) { el.selectedIndex = i; } return } } } if (!isMultiple) { el.selectedIndex = -1; } } function hasNoMatchingOption (value, options) { return options.every(function (o) { return !looseEqual(o, value); }) } function getValue (option) { return '_value' in option ? option._value : option.value } function onCompositionStart (e) { e.target.composing = true; } function onCompositionEnd (e) { // prevent triggering an input event for no reason if (!e.target.composing) { return } e.target.composing = false; trigger(e.target, 'input'); } function trigger (el, type) { var e = document.createEvent('HTMLEvents'); e.initEvent(type, true, true); el.dispatchEvent(e); } /* */ // recursively search for possible transition defined inside the component root function locateNode (vnode) { return vnode.componentInstance && (!vnode.data || !vnode.data.transition) ? locateNode(vnode.componentInstance._vnode) : vnode } var show = { bind: function bind (el, ref, vnode) { var value = ref.value; vnode = locateNode(vnode); var transition$$1 = vnode.data && vnode.data.transition; var originalDisplay = el.__vOriginalDisplay = el.style.display === 'none' ? '' : el.style.display; if (value && transition$$1) { vnode.data.show = true; enter(vnode, function () { el.style.display = originalDisplay; }); } else { el.style.display = value ? originalDisplay : 'none'; } }, update: function update (el, ref, vnode) { var value = ref.value; var oldValue = ref.oldValue; /* istanbul ignore if */ if (!value === !oldValue) { return } vnode = locateNode(vnode); var transition$$1 = vnode.data && vnode.data.transition; if (transition$$1) { vnode.data.show = true; if (value) { enter(vnode, function () { el.style.display = el.__vOriginalDisplay; }); } else { leave(vnode, function () { el.style.display = 'none'; }); } } else { el.style.display = value ? el.__vOriginalDisplay : 'none'; } }, unbind: function unbind ( el, binding, vnode, oldVnode, isDestroy ) { if (!isDestroy) { el.style.display = el.__vOriginalDisplay; } } } var platformDirectives = { model: directive, show: show } /* */ // Provides transition support for a single element/component. // supports transition mode (out-in / in-out) var transitionProps = { name: String, appear: Boolean, css: Boolean, mode: String, type: String, enterClass: String, leaveClass: String, enterToClass: String, leaveToClass: String, enterActiveClass: String, leaveActiveClass: String, appearClass: String, appearActiveClass: String, appearToClass: String, duration: [Number, String, Object] }; // in case the child is also an abstract component, e.g. <keep-alive> // we want to recursively retrieve the real component to be rendered function getRealChild (vnode) { var compOptions = vnode && vnode.componentOptions; if (compOptions && compOptions.Ctor.options.abstract) { return getRealChild(getFirstComponentChild(compOptions.children)) } else { return vnode } } function extractTransitionData (comp) { var data = {}; var options = comp.$options; // props for (var key in options.propsData) { data[key] = comp[key]; } // events. // extract listeners and pass them directly to the transition methods var listeners = options._parentListeners; for (var key$1 in listeners) { data[camelize(key$1)] = listeners[key$1]; } return data } function placeholder (h, rawChild) { if (/\d-keep-alive$/.test(rawChild.tag)) { return h('keep-alive', { props: rawChild.componentOptions.propsData }) } } function hasParentTransition (vnode) { while ((vnode = vnode.parent)) { if (vnode.data.transition) { return true } } } function isSameChild (child, oldChild) { return oldChild.key === child.key && oldChild.tag === child.tag } var Transition = { name: 'transition', props: transitionProps, abstract: true, render: function render (h) { var this$1 = this; var children = this.$slots.default; if (!children) { return } // filter out text nodes (possible whitespaces) children = children.filter(function (c) { return c.tag || isAsyncPlaceholder(c); }); /* istanbul ignore if */ if (!children.length) { return } // warn multiple elements if (process.env.NODE_ENV !== 'production' && children.length > 1) { warn( '<transition> can only be used on a single element. Use ' + '<transition-group> for lists.', this.$parent ); } var mode = this.mode; // warn invalid mode if (process.env.NODE_ENV !== 'production' && mode && mode !== 'in-out' && mode !== 'out-in' ) { warn( 'invalid <transition> mode: ' + mode, this.$parent ); } var rawChild = children[0]; // if this is a component root node and the component's // parent container node also has transition, skip. if (hasParentTransition(this.$vnode)) { return rawChild } // apply transition data to child // use getRealChild() to ignore abstract components e.g. keep-alive var child = getRealChild(rawChild); /* istanbul ignore if */ if (!child) { return rawChild } if (this._leaving) { return placeholder(h, rawChild) } // ensure a key that is unique to the vnode type and to this transition // component instance. This key will be used to remove pending leaving nodes // during entering. var id = "__transition-" + (this._uid) + "-"; child.key = child.key == null ? child.isComment ? id + 'comment' : id + child.tag : isPrimitive(child.key) ? (String(child.key).indexOf(id) === 0 ? child.key : id + child.key) : child.key; var data = (child.data || (child.data = {})).transition = extractTransitionData(this); var oldRawChild = this._vnode; var oldChild = getRealChild(oldRawChild); // mark v-show // so that the transition module can hand over the control to the directive if (child.data.directives && child.data.directives.some(function (d) { return d.name === 'show'; })) { child.data.show = true; } if ( oldChild && oldChild.data && !isSameChild(child, oldChild) && !isAsyncPlaceholder(oldChild) && // #6687 component root is a comment node !(oldChild.componentInstance && oldChild.componentInstance._vnode.isComment) ) { // replace old child transition data with fresh one // important for dynamic transitions! var oldData = oldChild.data.transition = extend({}, data); // handle transition mode if (mode === 'out-in') { // return placeholder node and queue update when leave finishes this._leaving = true; mergeVNodeHook(oldData, 'afterLeave', function () { this$1._leaving = false; this$1.$forceUpdate(); }); return placeholder(h, rawChild) } else if (mode === 'in-out') { if (isAsyncPlaceholder(child)) { return oldRawChild } var delayedLeave; var performLeave = function () { delayedLeave(); }; mergeVNodeHook(data, 'afterEnter', performLeave); mergeVNodeHook(data, 'enterCancelled', performLeave); mergeVNodeHook(oldData, 'delayLeave', function (leave) { delayedLeave = leave; }); } } return rawChild } } /* */ // Provides transition support for list items. // supports move transitions using the FLIP technique. // Because the vdom's children update algorithm is "unstable" - i.e. // it doesn't guarantee the relative positioning of removed elements, // we force transition-group to update its children into two passes: // in the first pass, we remove all nodes that need to be removed, // triggering their leaving transition; in the second pass, we insert/move // into the final desired state. This way in the second pass removed // nodes will remain where they should be. var props = extend({ tag: String, moveClass: String }, transitionProps); delete props.mode; var TransitionGroup = { props: props, render: function render (h) { var tag = this.tag || this.$vnode.data.tag || 'span'; var map = Object.create(null); var prevChildren = this.prevChildren = this.children; var rawChildren = this.$slots.default || []; var children = this.children = []; var transitionData = extractTransitionData(this); for (var i = 0; i < rawChildren.length; i++) { var c = rawChildren[i]; if (c.tag) { if (c.key != null && String(c.key).indexOf('__vlist') !== 0) { children.push(c); map[c.key] = c ;(c.data || (c.data = {})).transition = transitionData; } else if (process.env.NODE_ENV !== 'production') { var opts = c.componentOptions; var name = opts ? (opts.Ctor.options.name || opts.tag || '') : c.tag; warn(("<transition-group> children must be keyed: <" + name + ">")); } } } if (prevChildren) { var kept = []; var removed = []; for (var i$1 = 0; i$1 < prevChildren.length; i$1++) { var c$1 = prevChildren[i$1]; c$1.data.transition = transitionData; c$1.data.pos = c$1.elm.getBoundingClientRect(); if (map[c$1.key]) { kept.push(c$1); } else { removed.push(c$1); } } this.kept = h(tag, null, kept); this.removed = removed; } return h(tag, null, children) }, beforeUpdate: function beforeUpdate () { // force removing pass this.__patch__( this._vnode, this.kept, false, // hydrating true // removeOnly (!important, avoids unnecessary moves) ); this._vnode = this.kept; }, updated: function updated () { var children = this.prevChildren; var moveClass = this.moveClass || ((this.name || 'v') + '-move'); if (!children.length || !this.hasMove(children[0].elm, moveClass)) { return } // we divide the work into three loops to avoid mixing DOM reads and writes // in each iteration - which helps prevent layout thrashing. children.forEach(callPendingCbs); children.forEach(recordPosition); children.forEach(applyTranslation); // force reflow to put everything in position // assign to this to avoid being removed in tree-shaking // $flow-disable-line this._reflow = document.body.offsetHeight; children.forEach(function (c) { if (c.data.moved) { var el = c.elm; var s = el.style; addTransitionClass(el, moveClass); s.transform = s.WebkitTransform = s.transitionDuration = ''; el.addEventListener(transitionEndEvent, el._moveCb = function cb (e) { if (!e || /transform$/.test(e.propertyName)) { el.removeEventListener(transitionEndEvent, cb); el._moveCb = null; removeTransitionClass(el, moveClass); } }); } }); }, methods: { hasMove: function hasMove (el, moveClass) { /* istanbul ignore if */ if (!hasTransition) { return false } /* istanbul ignore if */ if (this._hasMove) { return this._hasMove } // Detect whether an element with the move class applied has // CSS transitions. Since the element may be inside an entering // transition at this very moment, we make a clone of it and remove // all other transition classes applied to ensure only the move class // is applied. var clone = el.cloneNode(); if (el._transitionClasses) { el._transitionClasses.forEach(function (cls) { removeClass(clone, cls); }); } addClass(clone, moveClass); clone.style.display = 'none'; this.$el.appendChild(clone); var info = getTransitionInfo(clone); this.$el.removeChild(clone); return (this._hasMove = info.hasTransform) } } } function callPendingCbs (c) { /* istanbul ignore if */ if (c.elm._moveCb) { c.elm._moveCb(); } /* istanbul ignore if */ if (c.elm._enterCb) { c.elm._enterCb(); } } function recordPosition (c) { c.data.newPos = c.elm.getBoundingClientRect(); } function applyTranslation (c) { var oldPos = c.data.pos; var newPos = c.data.newPos; var dx = oldPos.left - newPos.left; var dy = oldPos.top - newPos.top; if (dx || dy) { c.data.moved = true; var s = c.elm.style; s.transform = s.WebkitTransform = "translate(" + dx + "px," + dy + "px)"; s.transitionDuration = '0s'; } } var platformComponents = { Transition: Transition, TransitionGroup: TransitionGroup } /* */ // install platform specific utils Vue.config.mustUseProp = mustUseProp; Vue.config.isReservedTag = isReservedTag; Vue.config.isReservedAttr = isReservedAttr; Vue.config.getTagNamespace = getTagNamespace; Vue.config.isUnknownElement = isUnknownElement; // install platform runtime directives & components extend(Vue.options.directives, platformDirectives); extend(Vue.options.components, platformComponents); // install platform patch function Vue.prototype.__patch__ = inBrowser ? patch : noop; // public mount method Vue.prototype.$mount = function ( el, hydrating ) { el = el && inBrowser ? query(el) : undefined; return mountComponent(this, el, hydrating) }; // devtools global hook /* istanbul ignore next */ if (inBrowser) { setTimeout(function () { if (config.devtools) { if (devtools) { devtools.emit('init', Vue); } else if ( process.env.NODE_ENV !== 'production' && process.env.NODE_ENV !== 'test' && isChrome ) { console[console.info ? 'info' : 'log']( 'Download the Vue Devtools extension for a better development experience:\n' + 'https://github.com/vuejs/vue-devtools' ); } } if (process.env.NODE_ENV !== 'production' && process.env.NODE_ENV !== 'test' && config.productionTip !== false && typeof console !== 'undefined' ) { console[console.info ? 'info' : 'log']( "You are running Vue in development mode.\n" + "Make sure to turn on production mode when deploying for production.\n" + "See more tips at https://vuejs.org/guide/deployment.html" ); } }, 0); } /* */ var defaultTagRE = /\{\{((?:.|\n)+?)\}\}/g; var regexEscapeRE = /[-.*+?^${}()|[\]\/\\]/g; var buildRegex = cached(function (delimiters) { var open = delimiters[0].replace(regexEscapeRE, '\\$&'); var close = delimiters[1].replace(regexEscapeRE, '\\$&'); return new RegExp(open + '((?:.|\\n)+?)' + close, 'g') }); function parseText ( text, delimiters ) { var tagRE = delimiters ? buildRegex(delimiters) : defaultTagRE; if (!tagRE.test(text)) { return } var tokens = []; var rawTokens = []; var lastIndex = tagRE.lastIndex = 0; var match, index, tokenValue; while ((match = tagRE.exec(text))) { index = match.index; // push text token if (index > lastIndex) { rawTokens.push(tokenValue = text.slice(lastIndex, index)); tokens.push(JSON.stringify(tokenValue)); } // tag token var exp = parseFilters(match[1].trim()); tokens.push(("_s(" + exp + ")")); rawTokens.push({ '@binding': exp }); lastIndex = index + match[0].length; } if (lastIndex < text.length) { rawTokens.push(tokenValue = text.slice(lastIndex)); tokens.push(JSON.stringify(tokenValue)); } return { expression: tokens.join('+'), tokens: rawTokens } } /* */ function transformNode (el, options) { var warn = options.warn || baseWarn; var staticClass = getAndRemoveAttr(el, 'class'); if (process.env.NODE_ENV !== 'production' && staticClass) { var res = parseText(staticClass, options.delimiters); if (res) { warn( "class=\"" + staticClass + "\": " + 'Interpolation inside attributes has been removed. ' + 'Use v-bind or the colon shorthand instead. For example, ' + 'instead of <div class="{{ val }}">, use <div :class="val">.' ); } } if (staticClass) { el.staticClass = JSON.stringify(staticClass); } var classBinding = getBindingAttr(el, 'class', false /* getStatic */); if (classBinding) { el.classBinding = classBinding; } } function genData (el) { var data = ''; if (el.staticClass) { data += "staticClass:" + (el.staticClass) + ","; } if (el.classBinding) { data += "class:" + (el.classBinding) + ","; } return data } var klass$1 = { staticKeys: ['staticClass'], transformNode: transformNode, genData: genData } /* */ function transformNode$1 (el, options) { var warn = options.warn || baseWarn; var staticStyle = getAndRemoveAttr(el, 'style'); if (staticStyle) { /* istanbul ignore if */ if (process.env.NODE_ENV !== 'production') { var res = parseText(staticStyle, options.delimiters); if (res) { warn( "style=\"" + staticStyle + "\": " + 'Interpolation inside attributes has been removed. ' + 'Use v-bind or the colon shorthand instead. For example, ' + 'instead of <div style="{{ val }}">, use <div :style="val">.' ); } } el.staticStyle = JSON.stringify(parseStyleText(staticStyle)); } var styleBinding = getBindingAttr(el, 'style', false /* getStatic */); if (styleBinding) { el.styleBinding = styleBinding; } } function genData$1 (el) { var data = ''; if (el.staticStyle) { data += "staticStyle:" + (el.staticStyle) + ","; } if (el.styleBinding) { data += "style:(" + (el.styleBinding) + "),"; } return data } var style$1 = { staticKeys: ['staticStyle'], transformNode: transformNode$1, genData: genData$1 } /* */ var decoder; var he = { decode: function decode (html) { decoder = decoder || document.createElement('div'); decoder.innerHTML = html; return decoder.textContent } } /* */ var isUnaryTag = makeMap( 'area,base,br,col,embed,frame,hr,img,input,isindex,keygen,' + 'link,meta,param,source,track,wbr' ); // Elements that you can, intentionally, leave open // (and which close themselves) var canBeLeftOpenTag = makeMap( 'colgroup,dd,dt,li,options,p,td,tfoot,th,thead,tr,source' ); // HTML5 tags https://html.spec.whatwg.org/multipage/indices.html#elements-3 // Phrasing Content https://html.spec.whatwg.org/multipage/dom.html#phrasing-content var isNonPhrasingTag = makeMap( 'address,article,aside,base,blockquote,body,caption,col,colgroup,dd,' + 'details,dialog,div,dl,dt,fieldset,figcaption,figure,footer,form,' + 'h1,h2,h3,h4,h5,h6,head,header,hgroup,hr,html,legend,li,menuitem,meta,' + 'optgroup,option,param,rp,rt,source,style,summary,tbody,td,tfoot,th,thead,' + 'title,tr,track' ); /** * Not type-checking this file because it's mostly vendor code. */ /*! * HTML Parser By John Resig (ejohn.org) * Modified by Juriy "kangax" Zaytsev * Original code by Erik Arvidsson, Mozilla Public License * http://erik.eae.net/simplehtmlparser/simplehtmlparser.js */ // Regular Expressions for parsing tags and attributes var attribute = /^\s*([^\s"'<>\/=]+)(?:\s*(=)\s*(?:"([^"]*)"+|'([^']*)'+|([^\s"'=<>`]+)))?/; // could use https://www.w3.org/TR/1999/REC-xml-names-19990114/#NT-QName // but for Vue templates we can enforce a simple charset var ncname = '[a-zA-Z_][\\w\\-\\.]*'; var qnameCapture = "((?:" + ncname + "\\:)?" + ncname + ")"; var startTagOpen = new RegExp(("^<" + qnameCapture)); var startTagClose = /^\s*(\/?)>/; var endTag = new RegExp(("^<\\/" + qnameCapture + "[^>]*>")); var doctype = /^<!DOCTYPE [^>]+>/i; // #7298: escape - to avoid being pased as HTML comment when inlined in page var comment = /^<!\--/; var conditionalComment = /^<!\[/; var IS_REGEX_CAPTURING_BROKEN = false; 'x'.replace(/x(.)?/g, function (m, g) { IS_REGEX_CAPTURING_BROKEN = g === ''; }); // Special Elements (can contain anything) var isPlainTextElement = makeMap('script,style,textarea', true); var reCache = {}; var decodingMap = { '&lt;': '<', '&gt;': '>', '&quot;': '"', '&amp;': '&', '&#10;': '\n', '&#9;': '\t' }; var encodedAttr = /&(?:lt|gt|quot|amp);/g; var encodedAttrWithNewLines = /&(?:lt|gt|quot|amp|#10|#9);/g; // #5992 var isIgnoreNewlineTag = makeMap('pre,textarea', true); var shouldIgnoreFirstNewline = function (tag, html) { return tag && isIgnoreNewlineTag(tag) && html[0] === '\n'; }; function decodeAttr (value, shouldDecodeNewlines) { var re = shouldDecodeNewlines ? encodedAttrWithNewLines : encodedAttr; return value.replace(re, function (match) { return decodingMap[match]; }) } function parseHTML (html, options) { var stack = []; var expectHTML = options.expectHTML; var isUnaryTag$$1 = options.isUnaryTag || no; var canBeLeftOpenTag$$1 = options.canBeLeftOpenTag || no; var index = 0; var last, lastTag; while (html) { last = html; // Make sure we're not in a plaintext content element like script/style if (!lastTag || !isPlainTextElement(lastTag)) { var textEnd = html.indexOf('<'); if (textEnd === 0) { // Comment: if (comment.test(html)) { var commentEnd = html.indexOf('-->'); if (commentEnd >= 0) { if (options.shouldKeepComment) { options.comment(html.substring(4, commentEnd)); } advance(commentEnd + 3); continue } } // http://en.wikipedia.org/wiki/Conditional_comment#Downlevel-revealed_conditional_comment if (conditionalComment.test(html)) { var conditionalEnd = html.indexOf(']>'); if (conditionalEnd >= 0) { advance(conditionalEnd + 2); continue } } // Doctype: var doctypeMatch = html.match(doctype); if (doctypeMatch) { advance(doctypeMatch[0].length); continue } // End tag: var endTagMatch = html.match(endTag); if (endTagMatch) { var curIndex = index; advance(endTagMatch[0].length); parseEndTag(endTagMatch[1], curIndex, index); continue } // Start tag: var startTagMatch = parseStartTag(); if (startTagMatch) { handleStartTag(startTagMatch); if (shouldIgnoreFirstNewline(lastTag, html)) { advance(1); } continue } } var text = (void 0), rest = (void 0), next = (void 0); if (textEnd >= 0) { rest = html.slice(textEnd); while ( !endTag.test(rest) && !startTagOpen.test(rest) && !comment.test(rest) && !conditionalComment.test(rest) ) { // < in plain text, be forgiving and treat it as text next = rest.indexOf('<', 1); if (next < 0) { break } textEnd += next; rest = html.slice(textEnd); } text = html.substring(0, textEnd); advance(textEnd); } if (textEnd < 0) { text = html; html = ''; } if (options.chars && text) { options.chars(text); } } else { var endTagLength = 0; var stackedTag = lastTag.toLowerCase(); var reStackedTag = reCache[stackedTag] || (reCache[stackedTag] = new RegExp('([\\s\\S]*?)(</' + stackedTag + '[^>]*>)', 'i')); var rest$1 = html.replace(reStackedTag, function (all, text, endTag) { endTagLength = endTag.length; if (!isPlainTextElement(stackedTag) && stackedTag !== 'noscript') { text = text .replace(/<!\--([\s\S]*?)-->/g, '$1') // #7298 .replace(/<!\[CDATA\[([\s\S]*?)]]>/g, '$1'); } if (shouldIgnoreFirstNewline(stackedTag, text)) { text = text.slice(1); } if (options.chars) { options.chars(text); } return '' }); index += html.length - rest$1.length; html = rest$1; parseEndTag(stackedTag, index - endTagLength, index); } if (html === last) { options.chars && options.chars(html); if (process.env.NODE_ENV !== 'production' && !stack.length && options.warn) { options.warn(("Mal-formatted tag at end of template: \"" + html + "\"")); } break } } // Clean up any remaining tags parseEndTag(); function advance (n) { index += n; html = html.substring(n); } function parseStartTag () { var start = html.match(startTagOpen); if (start) { var match = { tagName: start[1], attrs: [], start: index }; advance(start[0].length); var end, attr; while (!(end = html.match(startTagClose)) && (attr = html.match(attribute))) { advance(attr[0].length); match.attrs.push(attr); } if (end) { match.unarySlash = end[1]; advance(end[0].length); match.end = index; return match } } } function handleStartTag (match) { var tagName = match.tagName; var unarySlash = match.unarySlash; if (expectHTML) { if (lastTag === 'p' && isNonPhrasingTag(tagName)) { parseEndTag(lastTag); } if (canBeLeftOpenTag$$1(tagName) && lastTag === tagName) { parseEndTag(tagName); } } var unary = isUnaryTag$$1(tagName) || !!unarySlash; var l = match.attrs.length; var attrs = new Array(l); for (var i = 0; i < l; i++) { var args = match.attrs[i]; // hackish work around FF bug https://bugzilla.mozilla.org/show_bug.cgi?id=369778 if (IS_REGEX_CAPTURING_BROKEN && args[0].indexOf('""') === -1) { if (args[3] === '') { delete args[3]; } if (args[4] === '') { delete args[4]; } if (args[5] === '') { delete args[5]; } } var value = args[3] || args[4] || args[5] || ''; var shouldDecodeNewlines = tagName === 'a' && args[1] === 'href' ? options.shouldDecodeNewlinesForHref : options.shouldDecodeNewlines; attrs[i] = { name: args[1], value: decodeAttr(value, shouldDecodeNewlines) }; } if (!unary) { stack.push({ tag: tagName, lowerCasedTag: tagName.toLowerCase(), attrs: attrs }); lastTag = tagName; } if (options.start) { options.start(tagName, attrs, unary, match.start, match.end); } } function parseEndTag (tagName, start, end) { var pos, lowerCasedTagName; if (start == null) { start = index; } if (end == null) { end = index; } if (tagName) { lowerCasedTagName = tagName.toLowerCase(); } // Find the closest opened tag of the same type if (tagName) { for (pos = stack.length - 1; pos >= 0; pos--) { if (stack[pos].lowerCasedTag === lowerCasedTagName) { break } } } else { // If no tag name is provided, clean shop pos = 0; } if (pos >= 0) { // Close all the open elements, up the stack for (var i = stack.length - 1; i >= pos; i--) { if (process.env.NODE_ENV !== 'production' && (i > pos || !tagName) && options.warn ) { options.warn( ("tag <" + (stack[i].tag) + "> has no matching end tag.") ); } if (options.end) { options.end(stack[i].tag, start, end); } } // Remove the open elements from the stack stack.length = pos; lastTag = pos && stack[pos - 1].tag; } else if (lowerCasedTagName === 'br') { if (options.start) { options.start(tagName, [], true, start, end); } } else if (lowerCasedTagName === 'p') { if (options.start) { options.start(tagName, [], false, start, end); } if (options.end) { options.end(tagName, start, end); } } } } /* */ var onRE = /^@|^v-on:/; var dirRE = /^v-|^@|^:/; var forAliasRE = /([^]*?)\s+(?:in|of)\s+([^]*)/; var forIteratorRE = /,([^,\}\]]*)(?:,([^,\}\]]*))?$/; var stripParensRE = /^\(|\)$/g; var argRE = /:(.*)$/; var bindRE = /^:|^v-bind:/; var modifierRE = /\.[^.]+/g; var decodeHTMLCached = cached(he.decode); // configurable state var warn$2; var delimiters; var transforms; var preTransforms; var postTransforms; var platformIsPreTag; var platformMustUseProp; var platformGetTagNamespace; function createASTElement ( tag, attrs, parent ) { return { type: 1, tag: tag, attrsList: attrs, attrsMap: makeAttrsMap(attrs), parent: parent, children: [] } } /** * Convert HTML string to AST. */ function parse ( template, options ) { warn$2 = options.warn || baseWarn; platformIsPreTag = options.isPreTag || no; platformMustUseProp = options.mustUseProp || no; platformGetTagNamespace = options.getTagNamespace || no; transforms = pluckModuleFunction(options.modules, 'transformNode'); preTransforms = pluckModuleFunction(options.modules, 'preTransformNode'); postTransforms = pluckModuleFunction(options.modules, 'postTransformNode'); delimiters = options.delimiters; var stack = []; var preserveWhitespace = options.preserveWhitespace !== false; var root; var currentParent; var inVPre = false; var inPre = false; var warned = false; function warnOnce (msg) { if (!warned) { warned = true; warn$2(msg); } } function closeElement (element) { // check pre state if (element.pre) { inVPre = false; } if (platformIsPreTag(element.tag)) { inPre = false; } // apply post-transforms for (var i = 0; i < postTransforms.length; i++) { postTransforms[i](element, options); } } parseHTML(template, { warn: warn$2, expectHTML: options.expectHTML, isUnaryTag: options.isUnaryTag, canBeLeftOpenTag: options.canBeLeftOpenTag, shouldDecodeNewlines: options.shouldDecodeNewlines, shouldDecodeNewlinesForHref: options.shouldDecodeNewlinesForHref, shouldKeepComment: options.comments, start: function start (tag, attrs, unary) { // check namespace. // inherit parent ns if there is one var ns = (currentParent && currentParent.ns) || platformGetTagNamespace(tag); // handle IE svg bug /* istanbul ignore if */ if (isIE && ns === 'svg') { attrs = guardIESVGBug(attrs); } var element = createASTElement(tag, attrs, currentParent); if (ns) { element.ns = ns; } if (isForbiddenTag(element) && !isServerRendering()) { element.forbidden = true; process.env.NODE_ENV !== 'production' && warn$2( 'Templates should only be responsible for mapping the state to the ' + 'UI. Avoid placing tags with side-effects in your templates, such as ' + "<" + tag + ">" + ', as they will not be parsed.' ); } // apply pre-transforms for (var i = 0; i < preTransforms.length; i++) { element = preTransforms[i](element, options) || element; } if (!inVPre) { processPre(element); if (element.pre) { inVPre = true; } } if (platformIsPreTag(element.tag)) { inPre = true; } if (inVPre) { processRawAttrs(element); } else if (!element.processed) { // structural directives processFor(element); processIf(element); processOnce(element); // element-scope stuff processElement(element, options); } function checkRootConstraints (el) { if (process.env.NODE_ENV !== 'production') { if (el.tag === 'slot' || el.tag === 'template') { warnOnce( "Cannot use <" + (el.tag) + "> as component root element because it may " + 'contain multiple nodes.' ); } if (el.attrsMap.hasOwnProperty('v-for')) { warnOnce( 'Cannot use v-for on stateful component root element because ' + 'it renders multiple elements.' ); } } } // tree management if (!root) { root = element; checkRootConstraints(root); } else if (!stack.length) { // allow root elements with v-if, v-else-if and v-else if (root.if && (element.elseif || element.else)) { checkRootConstraints(element); addIfCondition(root, { exp: element.elseif, block: element }); } else if (process.env.NODE_ENV !== 'production') { warnOnce( "Component template should contain exactly one root element. " + "If you are using v-if on multiple elements, " + "use v-else-if to chain them instead." ); } } if (currentParent && !element.forbidden) { if (element.elseif || element.else) { processIfConditions(element, currentParent); } else if (element.slotScope) { // scoped slot currentParent.plain = false; var name = element.slotTarget || '"default"';(currentParent.scopedSlots || (currentParent.scopedSlots = {}))[name] = element; } else { currentParent.children.push(element); element.parent = currentParent; } } if (!unary) { currentParent = element; stack.push(element); } else { closeElement(element); } }, end: function end () { // remove trailing whitespace var element = stack[stack.length - 1]; var lastNode = element.children[element.children.length - 1]; if (lastNode && lastNode.type === 3 && lastNode.text === ' ' && !inPre) { element.children.pop(); } // pop stack stack.length -= 1; currentParent = stack[stack.length - 1]; closeElement(element); }, chars: function chars (text) { if (!currentParent) { if (process.env.NODE_ENV !== 'production') { if (text === template) { warnOnce( 'Component template requires a root element, rather than just text.' ); } else if ((text = text.trim())) { warnOnce( ("text \"" + text + "\" outside root element will be ignored.") ); } } return } // IE textarea placeholder bug /* istanbul ignore if */ if (isIE && currentParent.tag === 'textarea' && currentParent.attrsMap.placeholder === text ) { return } var children = currentParent.children; text = inPre || text.trim() ? isTextTag(currentParent) ? text : decodeHTMLCached(text) // only preserve whitespace if its not right after a starting tag : preserveWhitespace && children.length ? ' ' : ''; if (text) { var res; if (!inVPre && text !== ' ' && (res = parseText(text, delimiters))) { children.push({ type: 2, expression: res.expression, tokens: res.tokens, text: text }); } else if (text !== ' ' || !children.length || children[children.length - 1].text !== ' ') { children.push({ type: 3, text: text }); } } }, comment: function comment (text) { currentParent.children.push({ type: 3, text: text, isComment: true }); } }); return root } function processPre (el) { if (getAndRemoveAttr(el, 'v-pre') != null) { el.pre = true; } } function processRawAttrs (el) { var l = el.attrsList.length; if (l) { var attrs = el.attrs = new Array(l); for (var i = 0; i < l; i++) { attrs[i] = { name: el.attrsList[i].name, value: JSON.stringify(el.attrsList[i].value) }; } } else if (!el.pre) { // non root node in pre blocks with no attributes el.plain = true; } } function processElement (element, options) { processKey(element); // determine whether this is a plain element after // removing structural attributes element.plain = !element.key && !element.attrsList.length; processRef(element); processSlot(element); processComponent(element); for (var i = 0; i < transforms.length; i++) { element = transforms[i](element, options) || element; } processAttrs(element); } function processKey (el) { var exp = getBindingAttr(el, 'key'); if (exp) { if (process.env.NODE_ENV !== 'production' && el.tag === 'template') { warn$2("<template> cannot be keyed. Place the key on real elements instead."); } el.key = exp; } } function processRef (el) { var ref = getBindingAttr(el, 'ref'); if (ref) { el.ref = ref; el.refInFor = checkInFor(el); } } function processFor (el) { var exp; if ((exp = getAndRemoveAttr(el, 'v-for'))) { var res = parseFor(exp); if (res) { extend(el, res); } else if (process.env.NODE_ENV !== 'production') { warn$2( ("Invalid v-for expression: " + exp) ); } } } function parseFor (exp) { var inMatch = exp.match(forAliasRE); if (!inMatch) { return } var res = {}; res.for = inMatch[2].trim(); var alias = inMatch[1].trim().replace(stripParensRE, ''); var iteratorMatch = alias.match(forIteratorRE); if (iteratorMatch) { res.alias = alias.replace(forIteratorRE, ''); res.iterator1 = iteratorMatch[1].trim(); if (iteratorMatch[2]) { res.iterator2 = iteratorMatch[2].trim(); } } else { res.alias = alias; } return res } function processIf (el) { var exp = getAndRemoveAttr(el, 'v-if'); if (exp) { el.if = exp; addIfCondition(el, { exp: exp, block: el }); } else { if (getAndRemoveAttr(el, 'v-else') != null) { el.else = true; } var elseif = getAndRemoveAttr(el, 'v-else-if'); if (elseif) { el.elseif = elseif; } } } function processIfConditions (el, parent) { var prev = findPrevElement(parent.children); if (prev && prev.if) { addIfCondition(prev, { exp: el.elseif, block: el }); } else if (process.env.NODE_ENV !== 'production') { warn$2( "v-" + (el.elseif ? ('else-if="' + el.elseif + '"') : 'else') + " " + "used on element <" + (el.tag) + "> without corresponding v-if." ); } } function findPrevElement (children) { var i = children.length; while (i--) { if (children[i].type === 1) { return children[i] } else { if (process.env.NODE_ENV !== 'production' && children[i].text !== ' ') { warn$2( "text \"" + (children[i].text.trim()) + "\" between v-if and v-else(-if) " + "will be ignored." ); } children.pop(); } } } function addIfCondition (el, condition) { if (!el.ifConditions) { el.ifConditions = []; } el.ifConditions.push(condition); } function processOnce (el) { var once$$1 = getAndRemoveAttr(el, 'v-once'); if (once$$1 != null) { el.once = true; } } function processSlot (el) { if (el.tag === 'slot') { el.slotName = getBindingAttr(el, 'name'); if (process.env.NODE_ENV !== 'production' && el.key) { warn$2( "`key` does not work on <slot> because slots are abstract outlets " + "and can possibly expand into multiple elements. " + "Use the key on a wrapping element instead." ); } } else { var slotScope; if (el.tag === 'template') { slotScope = getAndRemoveAttr(el, 'scope'); /* istanbul ignore if */ if (process.env.NODE_ENV !== 'production' && slotScope) { warn$2( "the \"scope\" attribute for scoped slots have been deprecated and " + "replaced by \"slot-scope\" since 2.5. The new \"slot-scope\" attribute " + "can also be used on plain elements in addition to <template> to " + "denote scoped slots.", true ); } el.slotScope = slotScope || getAndRemoveAttr(el, 'slot-scope'); } else if ((slotScope = getAndRemoveAttr(el, 'slot-scope'))) { /* istanbul ignore if */ if (process.env.NODE_ENV !== 'production' && el.attrsMap['v-for']) { warn$2( "Ambiguous combined usage of slot-scope and v-for on <" + (el.tag) + "> " + "(v-for takes higher priority). Use a wrapper <template> for the " + "scoped slot to make it clearer.", true ); } el.slotScope = slotScope; } var slotTarget = getBindingAttr(el, 'slot'); if (slotTarget) { el.slotTarget = slotTarget === '""' ? '"default"' : slotTarget; // preserve slot as an attribute for native shadow DOM compat // only for non-scoped slots. if (el.tag !== 'template' && !el.slotScope) { addAttr(el, 'slot', slotTarget); } } } } function processComponent (el) { var binding; if ((binding = getBindingAttr(el, 'is'))) { el.component = binding; } if (getAndRemoveAttr(el, 'inline-template') != null) { el.inlineTemplate = true; } } function processAttrs (el) { var list = el.attrsList; var i, l, name, rawName, value, modifiers, isProp; for (i = 0, l = list.length; i < l; i++) { name = rawName = list[i].name; value = list[i].value; if (dirRE.test(name)) { // mark element as dynamic el.hasBindings = true; // modifiers modifiers = parseModifiers(name); if (modifiers) { name = name.replace(modifierRE, ''); } if (bindRE.test(name)) { // v-bind name = name.replace(bindRE, ''); value = parseFilters(value); isProp = false; if (modifiers) { if (modifiers.prop) { isProp = true; name = camelize(name); if (name === 'innerHtml') { name = 'innerHTML'; } } if (modifiers.camel) { name = camelize(name); } if (modifiers.sync) { addHandler( el, ("update:" + (camelize(name))), genAssignmentCode(value, "$event") ); } } if (isProp || ( !el.component && platformMustUseProp(el.tag, el.attrsMap.type, name) )) { addProp(el, name, value); } else { addAttr(el, name, value); } } else if (onRE.test(name)) { // v-on name = name.replace(onRE, ''); addHandler(el, name, value, modifiers, false, warn$2); } else { // normal directives name = name.replace(dirRE, ''); // parse arg var argMatch = name.match(argRE); var arg = argMatch && argMatch[1]; if (arg) { name = name.slice(0, -(arg.length + 1)); } addDirective(el, name, rawName, value, arg, modifiers); if (process.env.NODE_ENV !== 'production' && name === 'model') { checkForAliasModel(el, value); } } } else { // literal attribute if (process.env.NODE_ENV !== 'production') { var res = parseText(value, delimiters); if (res) { warn$2( name + "=\"" + value + "\": " + 'Interpolation inside attributes has been removed. ' + 'Use v-bind or the colon shorthand instead. For example, ' + 'instead of <div id="{{ val }}">, use <div :id="val">.' ); } } addAttr(el, name, JSON.stringify(value)); // #6887 firefox doesn't update muted state if set via attribute // even immediately after element creation if (!el.component && name === 'muted' && platformMustUseProp(el.tag, el.attrsMap.type, name)) { addProp(el, name, 'true'); } } } } function checkInFor (el) { var parent = el; while (parent) { if (parent.for !== undefined) { return true } parent = parent.parent; } return false } function parseModifiers (name) { var match = name.match(modifierRE); if (match) { var ret = {}; match.forEach(function (m) { ret[m.slice(1)] = true; }); return ret } } function makeAttrsMap (attrs) { var map = {}; for (var i = 0, l = attrs.length; i < l; i++) { if ( process.env.NODE_ENV !== 'production' && map[attrs[i].name] && !isIE && !isEdge ) { warn$2('duplicate attribute: ' + attrs[i].name); } map[attrs[i].name] = attrs[i].value; } return map } // for script (e.g. type="x/template") or style, do not decode content function isTextTag (el) { return el.tag === 'script' || el.tag === 'style' } function isForbiddenTag (el) { return ( el.tag === 'style' || (el.tag === 'script' && ( !el.attrsMap.type || el.attrsMap.type === 'text/javascript' )) ) } var ieNSBug = /^xmlns:NS\d+/; var ieNSPrefix = /^NS\d+:/; /* istanbul ignore next */ function guardIESVGBug (attrs) { var res = []; for (var i = 0; i < attrs.length; i++) { var attr = attrs[i]; if (!ieNSBug.test(attr.name)) { attr.name = attr.name.replace(ieNSPrefix, ''); res.push(attr); } } return res } function checkForAliasModel (el, value) { var _el = el; while (_el) { if (_el.for && _el.alias === value) { warn$2( "<" + (el.tag) + " v-model=\"" + value + "\">: " + "You are binding v-model directly to a v-for iteration alias. " + "This will not be able to modify the v-for source array because " + "writing to the alias is like modifying a function local variable. " + "Consider using an array of objects and use v-model on an object property instead." ); } _el = _el.parent; } } /* */ /** * Expand input[v-model] with dyanmic type bindings into v-if-else chains * Turn this: * <input v-model="data[type]" :type="type"> * into this: * <input v-if="type === 'checkbox'" type="checkbox" v-model="data[type]"> * <input v-else-if="type === 'radio'" type="radio" v-model="data[type]"> * <input v-else :type="type" v-model="data[type]"> */ function preTransformNode (el, options) { if (el.tag === 'input') { var map = el.attrsMap; if (!map['v-model']) { return } var typeBinding; if (map[':type'] || map['v-bind:type']) { typeBinding = getBindingAttr(el, 'type'); } if (!map.type && !typeBinding && map['v-bind']) { typeBinding = "(" + (map['v-bind']) + ").type"; } if (typeBinding) { var ifCondition = getAndRemoveAttr(el, 'v-if', true); var ifConditionExtra = ifCondition ? ("&&(" + ifCondition + ")") : ""; var hasElse = getAndRemoveAttr(el, 'v-else', true) != null; var elseIfCondition = getAndRemoveAttr(el, 'v-else-if', true); // 1. checkbox var branch0 = cloneASTElement(el); // process for on the main node processFor(branch0); addRawAttr(branch0, 'type', 'checkbox'); processElement(branch0, options); branch0.processed = true; // prevent it from double-processed branch0.if = "(" + typeBinding + ")==='checkbox'" + ifConditionExtra; addIfCondition(branch0, { exp: branch0.if, block: branch0 }); // 2. add radio else-if condition var branch1 = cloneASTElement(el); getAndRemoveAttr(branch1, 'v-for', true); addRawAttr(branch1, 'type', 'radio'); processElement(branch1, options); addIfCondition(branch0, { exp: "(" + typeBinding + ")==='radio'" + ifConditionExtra, block: branch1 }); // 3. other var branch2 = cloneASTElement(el); getAndRemoveAttr(branch2, 'v-for', true); addRawAttr(branch2, ':type', typeBinding); processElement(branch2, options); addIfCondition(branch0, { exp: ifCondition, block: branch2 }); if (hasElse) { branch0.else = true; } else if (elseIfCondition) { branch0.elseif = elseIfCondition; } return branch0 } } } function cloneASTElement (el) { return createASTElement(el.tag, el.attrsList.slice(), el.parent) } var model$2 = { preTransformNode: preTransformNode } var modules$1 = [ klass$1, style$1, model$2 ] /* */ function text (el, dir) { if (dir.value) { addProp(el, 'textContent', ("_s(" + (dir.value) + ")")); } } /* */ function html (el, dir) { if (dir.value) { addProp(el, 'innerHTML', ("_s(" + (dir.value) + ")")); } } var directives$1 = { model: model, text: text, html: html } /* */ var baseOptions = { expectHTML: true, modules: modules$1, directives: directives$1, isPreTag: isPreTag, isUnaryTag: isUnaryTag, mustUseProp: mustUseProp, canBeLeftOpenTag: canBeLeftOpenTag, isReservedTag: isReservedTag, getTagNamespace: getTagNamespace, staticKeys: genStaticKeys(modules$1) }; /* */ var isStaticKey; var isPlatformReservedTag; var genStaticKeysCached = cached(genStaticKeys$1); /** * Goal of the optimizer: walk the generated template AST tree * and detect sub-trees that are purely static, i.e. parts of * the DOM that never needs to change. * * Once we detect these sub-trees, we can: * * 1. Hoist them into constants, so that we no longer need to * create fresh nodes for them on each re-render; * 2. Completely skip them in the patching process. */ function optimize (root, options) { if (!root) { return } isStaticKey = genStaticKeysCached(options.staticKeys || ''); isPlatformReservedTag = options.isReservedTag || no; // first pass: mark all non-static nodes. markStatic$1(root); // second pass: mark static roots. markStaticRoots(root, false); } function genStaticKeys$1 (keys) { return makeMap( 'type,tag,attrsList,attrsMap,plain,parent,children,attrs' + (keys ? ',' + keys : '') ) } function markStatic$1 (node) { node.static = isStatic(node); if (node.type === 1) { // do not make component slot content static. this avoids // 1. components not able to mutate slot nodes // 2. static slot content fails for hot-reloading if ( !isPlatformReservedTag(node.tag) && node.tag !== 'slot' && node.attrsMap['inline-template'] == null ) { return } for (var i = 0, l = node.children.length; i < l; i++) { var child = node.children[i]; markStatic$1(child); if (!child.static) { node.static = false; } } if (node.ifConditions) { for (var i$1 = 1, l$1 = node.ifConditions.length; i$1 < l$1; i$1++) { var block = node.ifConditions[i$1].block; markStatic$1(block); if (!block.static) { node.static = false; } } } } } function markStaticRoots (node, isInFor) { if (node.type === 1) { if (node.static || node.once) { node.staticInFor = isInFor; } // For a node to qualify as a static root, it should have children that // are not just static text. Otherwise the cost of hoisting out will // outweigh the benefits and it's better off to just always render it fresh. if (node.static && node.children.length && !( node.children.length === 1 && node.children[0].type === 3 )) { node.staticRoot = true; return } else { node.staticRoot = false; } if (node.children) { for (var i = 0, l = node.children.length; i < l; i++) { markStaticRoots(node.children[i], isInFor || !!node.for); } } if (node.ifConditions) { for (var i$1 = 1, l$1 = node.ifConditions.length; i$1 < l$1; i$1++) { markStaticRoots(node.ifConditions[i$1].block, isInFor); } } } } function isStatic (node) { if (node.type === 2) { // expression return false } if (node.type === 3) { // text return true } return !!(node.pre || ( !node.hasBindings && // no dynamic bindings !node.if && !node.for && // not v-if or v-for or v-else !isBuiltInTag(node.tag) && // not a built-in isPlatformReservedTag(node.tag) && // not a component !isDirectChildOfTemplateFor(node) && Object.keys(node).every(isStaticKey) )) } function isDirectChildOfTemplateFor (node) { while (node.parent) { node = node.parent; if (node.tag !== 'template') { return false } if (node.for) { return true } } return false } /* */ var fnExpRE = /^([\w$_]+|\([^)]*?\))\s*=>|^function\s*\(/; var simplePathRE = /^[A-Za-z_$][\w$]*(?:\.[A-Za-z_$][\w$]*|\['[^']*?']|\["[^"]*?"]|\[\d+]|\[[A-Za-z_$][\w$]*])*$/; // KeyboardEvent.keyCode aliases var keyCodes = { esc: 27, tab: 9, enter: 13, space: 32, up: 38, left: 37, right: 39, down: 40, 'delete': [8, 46] }; // KeyboardEvent.key aliases var keyNames = { esc: 'Escape', tab: 'Tab', enter: 'Enter', space: ' ', // #7806: IE11 uses key names without `Arrow` prefix for arrow keys. up: ['Up', 'ArrowUp'], left: ['Left', 'ArrowLeft'], right: ['Right', 'ArrowRight'], down: ['Down', 'ArrowDown'], 'delete': ['Backspace', 'Delete'] }; // #4868: modifiers that prevent the execution of the listener // need to explicitly return null so that we can determine whether to remove // the listener for .once var genGuard = function (condition) { return ("if(" + condition + ")return null;"); }; var modifierCode = { stop: '$event.stopPropagation();', prevent: '$event.preventDefault();', self: genGuard("$event.target !== $event.currentTarget"), ctrl: genGuard("!$event.ctrlKey"), shift: genGuard("!$event.shiftKey"), alt: genGuard("!$event.altKey"), meta: genGuard("!$event.metaKey"), left: genGuard("'button' in $event && $event.button !== 0"), middle: genGuard("'button' in $event && $event.button !== 1"), right: genGuard("'button' in $event && $event.button !== 2") }; function genHandlers ( events, isNative, warn ) { var res = isNative ? 'nativeOn:{' : 'on:{'; for (var name in events) { res += "\"" + name + "\":" + (genHandler(name, events[name])) + ","; } return res.slice(0, -1) + '}' } function genHandler ( name, handler ) { if (!handler) { return 'function(){}' } if (Array.isArray(handler)) { return ("[" + (handler.map(function (handler) { return genHandler(name, handler); }).join(',')) + "]") } var isMethodPath = simplePathRE.test(handler.value); var isFunctionExpression = fnExpRE.test(handler.value); if (!handler.modifiers) { if (isMethodPath || isFunctionExpression) { return handler.value } /* istanbul ignore if */ return ("function($event){" + (handler.value) + "}") // inline statement } else { var code = ''; var genModifierCode = ''; var keys = []; for (var key in handler.modifiers) { if (modifierCode[key]) { genModifierCode += modifierCode[key]; // left/right if (keyCodes[key]) { keys.push(key); } } else if (key === 'exact') { var modifiers = (handler.modifiers); genModifierCode += genGuard( ['ctrl', 'shift', 'alt', 'meta'] .filter(function (keyModifier) { return !modifiers[keyModifier]; }) .map(function (keyModifier) { return ("$event." + keyModifier + "Key"); }) .join('||') ); } else { keys.push(key); } } if (keys.length) { code += genKeyFilter(keys); } // Make sure modifiers like prevent and stop get executed after key filtering if (genModifierCode) { code += genModifierCode; } var handlerCode = isMethodPath ? ("return " + (handler.value) + "($event)") : isFunctionExpression ? ("return (" + (handler.value) + ")($event)") : handler.value; /* istanbul ignore if */ return ("function($event){" + code + handlerCode + "}") } } function genKeyFilter (keys) { return ("if(!('button' in $event)&&" + (keys.map(genFilterCode).join('&&')) + ")return null;") } function genFilterCode (key) { var keyVal = parseInt(key, 10); if (keyVal) { return ("$event.keyCode!==" + keyVal) } var keyCode = keyCodes[key]; var keyName = keyNames[key]; return ( "_k($event.keyCode," + (JSON.stringify(key)) + "," + (JSON.stringify(keyCode)) + "," + "$event.key," + "" + (JSON.stringify(keyName)) + ")" ) } /* */ function on (el, dir) { if (process.env.NODE_ENV !== 'production' && dir.modifiers) { warn("v-on without argument does not support modifiers."); } el.wrapListeners = function (code) { return ("_g(" + code + "," + (dir.value) + ")"); }; } /* */ function bind$1 (el, dir) { el.wrapData = function (code) { return ("_b(" + code + ",'" + (el.tag) + "'," + (dir.value) + "," + (dir.modifiers && dir.modifiers.prop ? 'true' : 'false') + (dir.modifiers && dir.modifiers.sync ? ',true' : '') + ")") }; } /* */ var baseDirectives = { on: on, bind: bind$1, cloak: noop } /* */ var CodegenState = function CodegenState (options) { this.options = options; this.warn = options.warn || baseWarn; this.transforms = pluckModuleFunction(options.modules, 'transformCode'); this.dataGenFns = pluckModuleFunction(options.modules, 'genData'); this.directives = extend(extend({}, baseDirectives), options.directives); var isReservedTag = options.isReservedTag || no; this.maybeComponent = function (el) { return !isReservedTag(el.tag); }; this.onceId = 0; this.staticRenderFns = []; }; function generate ( ast, options ) { var state = new CodegenState(options); var code = ast ? genElement(ast, state) : '_c("div")'; return { render: ("with(this){return " + code + "}"), staticRenderFns: state.staticRenderFns } } function genElement (el, state) { if (el.staticRoot && !el.staticProcessed) { return genStatic(el, state) } else if (el.once && !el.onceProcessed) { return genOnce(el, state) } else if (el.for && !el.forProcessed) { return genFor(el, state) } else if (el.if && !el.ifProcessed) { return genIf(el, state) } else if (el.tag === 'template' && !el.slotTarget) { return genChildren(el, state) || 'void 0' } else if (el.tag === 'slot') { return genSlot(el, state) } else { // component or element var code; if (el.component) { code = genComponent(el.component, el, state); } else { var data = el.plain ? undefined : genData$2(el, state); var children = el.inlineTemplate ? null : genChildren(el, state, true); code = "_c('" + (el.tag) + "'" + (data ? ("," + data) : '') + (children ? ("," + children) : '') + ")"; } // module transforms for (var i = 0; i < state.transforms.length; i++) { code = state.transforms[i](el, code); } return code } } // hoist static sub-trees out function genStatic (el, state) { el.staticProcessed = true; state.staticRenderFns.push(("with(this){return " + (genElement(el, state)) + "}")); return ("_m(" + (state.staticRenderFns.length - 1) + (el.staticInFor ? ',true' : '') + ")") } // v-once function genOnce (el, state) { el.onceProcessed = true; if (el.if && !el.ifProcessed) { return genIf(el, state) } else if (el.staticInFor) { var key = ''; var parent = el.parent; while (parent) { if (parent.for) { key = parent.key; break } parent = parent.parent; } if (!key) { process.env.NODE_ENV !== 'production' && state.warn( "v-once can only be used inside v-for that is keyed. " ); return genElement(el, state) } return ("_o(" + (genElement(el, state)) + "," + (state.onceId++) + "," + key + ")") } else { return genStatic(el, state) } } function genIf ( el, state, altGen, altEmpty ) { el.ifProcessed = true; // avoid recursion return genIfConditions(el.ifConditions.slice(), state, altGen, altEmpty) } function genIfConditions ( conditions, state, altGen, altEmpty ) { if (!conditions.length) { return altEmpty || '_e()' } var condition = conditions.shift(); if (condition.exp) { return ("(" + (condition.exp) + ")?" + (genTernaryExp(condition.block)) + ":" + (genIfConditions(conditions, state, altGen, altEmpty))) } else { return ("" + (genTernaryExp(condition.block))) } // v-if with v-once should generate code like (a)?_m(0):_m(1) function genTernaryExp (el) { return altGen ? altGen(el, state) : el.once ? genOnce(el, state) : genElement(el, state) } } function genFor ( el, state, altGen, altHelper ) { var exp = el.for; var alias = el.alias; var iterator1 = el.iterator1 ? ("," + (el.iterator1)) : ''; var iterator2 = el.iterator2 ? ("," + (el.iterator2)) : ''; if (process.env.NODE_ENV !== 'production' && state.maybeComponent(el) && el.tag !== 'slot' && el.tag !== 'template' && !el.key ) { state.warn( "<" + (el.tag) + " v-for=\"" + alias + " in " + exp + "\">: component lists rendered with " + "v-for should have explicit keys. " + "See https://vuejs.org/guide/list.html#key for more info.", true /* tip */ ); } el.forProcessed = true; // avoid recursion return (altHelper || '_l') + "((" + exp + ")," + "function(" + alias + iterator1 + iterator2 + "){" + "return " + ((altGen || genElement)(el, state)) + '})' } function genData$2 (el, state) { var data = '{'; // directives first. // directives may mutate the el's other properties before they are generated. var dirs = genDirectives(el, state); if (dirs) { data += dirs + ','; } // key if (el.key) { data += "key:" + (el.key) + ","; } // ref if (el.ref) { data += "ref:" + (el.ref) + ","; } if (el.refInFor) { data += "refInFor:true,"; } // pre if (el.pre) { data += "pre:true,"; } // record original tag name for components using "is" attribute if (el.component) { data += "tag:\"" + (el.tag) + "\","; } // module data generation functions for (var i = 0; i < state.dataGenFns.length; i++) { data += state.dataGenFns[i](el); } // attributes if (el.attrs) { data += "attrs:{" + (genProps(el.attrs)) + "},"; } // DOM props if (el.props) { data += "domProps:{" + (genProps(el.props)) + "},"; } // event handlers if (el.events) { data += (genHandlers(el.events, false, state.warn)) + ","; } if (el.nativeEvents) { data += (genHandlers(el.nativeEvents, true, state.warn)) + ","; } // slot target // only for non-scoped slots if (el.slotTarget && !el.slotScope) { data += "slot:" + (el.slotTarget) + ","; } // scoped slots if (el.scopedSlots) { data += (genScopedSlots(el.scopedSlots, state)) + ","; } // component v-model if (el.model) { data += "model:{value:" + (el.model.value) + ",callback:" + (el.model.callback) + ",expression:" + (el.model.expression) + "},"; } // inline-template if (el.inlineTemplate) { var inlineTemplate = genInlineTemplate(el, state); if (inlineTemplate) { data += inlineTemplate + ","; } } data = data.replace(/,$/, '') + '}'; // v-bind data wrap if (el.wrapData) { data = el.wrapData(data); } // v-on data wrap if (el.wrapListeners) { data = el.wrapListeners(data); } return data } function genDirectives (el, state) { var dirs = el.directives; if (!dirs) { return } var res = 'directives:['; var hasRuntime = false; var i, l, dir, needRuntime; for (i = 0, l = dirs.length; i < l; i++) { dir = dirs[i]; needRuntime = true; var gen = state.directives[dir.name]; if (gen) { // compile-time directive that manipulates AST. // returns true if it also needs a runtime counterpart. needRuntime = !!gen(el, dir, state.warn); } if (needRuntime) { hasRuntime = true; res += "{name:\"" + (dir.name) + "\",rawName:\"" + (dir.rawName) + "\"" + (dir.value ? (",value:(" + (dir.value) + "),expression:" + (JSON.stringify(dir.value))) : '') + (dir.arg ? (",arg:\"" + (dir.arg) + "\"") : '') + (dir.modifiers ? (",modifiers:" + (JSON.stringify(dir.modifiers))) : '') + "},"; } } if (hasRuntime) { return res.slice(0, -1) + ']' } } function genInlineTemplate (el, state) { var ast = el.children[0]; if (process.env.NODE_ENV !== 'production' && ( el.children.length !== 1 || ast.type !== 1 )) { state.warn('Inline-template components must have exactly one child element.'); } if (ast.type === 1) { var inlineRenderFns = generate(ast, state.options); return ("inlineTemplate:{render:function(){" + (inlineRenderFns.render) + "},staticRenderFns:[" + (inlineRenderFns.staticRenderFns.map(function (code) { return ("function(){" + code + "}"); }).join(',')) + "]}") } } function genScopedSlots ( slots, state ) { return ("scopedSlots:_u([" + (Object.keys(slots).map(function (key) { return genScopedSlot(key, slots[key], state) }).join(',')) + "])") } function genScopedSlot ( key, el, state ) { if (el.for && !el.forProcessed) { return genForScopedSlot(key, el, state) } var fn = "function(" + (String(el.slotScope)) + "){" + "return " + (el.tag === 'template' ? el.if ? ((el.if) + "?" + (genChildren(el, state) || 'undefined') + ":undefined") : genChildren(el, state) || 'undefined' : genElement(el, state)) + "}"; return ("{key:" + key + ",fn:" + fn + "}") } function genForScopedSlot ( key, el, state ) { var exp = el.for; var alias = el.alias; var iterator1 = el.iterator1 ? ("," + (el.iterator1)) : ''; var iterator2 = el.iterator2 ? ("," + (el.iterator2)) : ''; el.forProcessed = true; // avoid recursion return "_l((" + exp + ")," + "function(" + alias + iterator1 + iterator2 + "){" + "return " + (genScopedSlot(key, el, state)) + '})' } function genChildren ( el, state, checkSkip, altGenElement, altGenNode ) { var children = el.children; if (children.length) { var el$1 = children[0]; // optimize single v-for if (children.length === 1 && el$1.for && el$1.tag !== 'template' && el$1.tag !== 'slot' ) { return (altGenElement || genElement)(el$1, state) } var normalizationType = checkSkip ? getNormalizationType(children, state.maybeComponent) : 0; var gen = altGenNode || genNode; return ("[" + (children.map(function (c) { return gen(c, state); }).join(',')) + "]" + (normalizationType ? ("," + normalizationType) : '')) } } // determine the normalization needed for the children array. // 0: no normalization needed // 1: simple normalization needed (possible 1-level deep nested array) // 2: full normalization needed function getNormalizationType ( children, maybeComponent ) { var res = 0; for (var i = 0; i < children.length; i++) { var el = children[i]; if (el.type !== 1) { continue } if (needsNormalization(el) || (el.ifConditions && el.ifConditions.some(function (c) { return needsNormalization(c.block); }))) { res = 2; break } if (maybeComponent(el) || (el.ifConditions && el.ifConditions.some(function (c) { return maybeComponent(c.block); }))) { res = 1; } } return res } function needsNormalization (el) { return el.for !== undefined || el.tag === 'template' || el.tag === 'slot' } function genNode (node, state) { if (node.type === 1) { return genElement(node, state) } if (node.type === 3 && node.isComment) { return genComment(node) } else { return genText(node) } } function genText (text) { return ("_v(" + (text.type === 2 ? text.expression // no need for () because already wrapped in _s() : transformSpecialNewlines(JSON.stringify(text.text))) + ")") } function genComment (comment) { return ("_e(" + (JSON.stringify(comment.text)) + ")") } function genSlot (el, state) { var slotName = el.slotName || '"default"'; var children = genChildren(el, state); var res = "_t(" + slotName + (children ? ("," + children) : ''); var attrs = el.attrs && ("{" + (el.attrs.map(function (a) { return ((camelize(a.name)) + ":" + (a.value)); }).join(',')) + "}"); var bind$$1 = el.attrsMap['v-bind']; if ((attrs || bind$$1) && !children) { res += ",null"; } if (attrs) { res += "," + attrs; } if (bind$$1) { res += (attrs ? '' : ',null') + "," + bind$$1; } return res + ')' } // componentName is el.component, take it as argument to shun flow's pessimistic refinement function genComponent ( componentName, el, state ) { var children = el.inlineTemplate ? null : genChildren(el, state, true); return ("_c(" + componentName + "," + (genData$2(el, state)) + (children ? ("," + children) : '') + ")") } function genProps (props) { var res = ''; for (var i = 0; i < props.length; i++) { var prop = props[i]; /* istanbul ignore if */ { res += "\"" + (prop.name) + "\":" + (transformSpecialNewlines(prop.value)) + ","; } } return res.slice(0, -1) } // #3895, #4268 function transformSpecialNewlines (text) { return text .replace(/\u2028/g, '\\u2028') .replace(/\u2029/g, '\\u2029') } /* */ // these keywords should not appear inside expressions, but operators like // typeof, instanceof and in are allowed var prohibitedKeywordRE = new RegExp('\\b' + ( 'do,if,for,let,new,try,var,case,else,with,await,break,catch,class,const,' + 'super,throw,while,yield,delete,export,import,return,switch,default,' + 'extends,finally,continue,debugger,function,arguments' ).split(',').join('\\b|\\b') + '\\b'); // these unary operators should not be used as property/method names var unaryOperatorsRE = new RegExp('\\b' + ( 'delete,typeof,void' ).split(',').join('\\s*\\([^\\)]*\\)|\\b') + '\\s*\\([^\\)]*\\)'); // strip strings in expressions var stripStringRE = /'(?:[^'\\]|\\.)*'|"(?:[^"\\]|\\.)*"|`(?:[^`\\]|\\.)*\$\{|\}(?:[^`\\]|\\.)*`|`(?:[^`\\]|\\.)*`/g; // detect problematic expressions in a template function detectErrors (ast) { var errors = []; if (ast) { checkNode(ast, errors); } return errors } function checkNode (node, errors) { if (node.type === 1) { for (var name in node.attrsMap) { if (dirRE.test(name)) { var value = node.attrsMap[name]; if (value) { if (name === 'v-for') { checkFor(node, ("v-for=\"" + value + "\""), errors); } else if (onRE.test(name)) { checkEvent(value, (name + "=\"" + value + "\""), errors); } else { checkExpression(value, (name + "=\"" + value + "\""), errors); } } } } if (node.children) { for (var i = 0; i < node.children.length; i++) { checkNode(node.children[i], errors); } } } else if (node.type === 2) { checkExpression(node.expression, node.text, errors); } } function checkEvent (exp, text, errors) { var stipped = exp.replace(stripStringRE, ''); var keywordMatch = stipped.match(unaryOperatorsRE); if (keywordMatch && stipped.charAt(keywordMatch.index - 1) !== '$') { errors.push( "avoid using JavaScript unary operator as property name: " + "\"" + (keywordMatch[0]) + "\" in expression " + (text.trim()) ); } checkExpression(exp, text, errors); } function checkFor (node, text, errors) { checkExpression(node.for || '', text, errors); checkIdentifier(node.alias, 'v-for alias', text, errors); checkIdentifier(node.iterator1, 'v-for iterator', text, errors); checkIdentifier(node.iterator2, 'v-for iterator', text, errors); } function checkIdentifier ( ident, type, text, errors ) { if (typeof ident === 'string') { try { new Function(("var " + ident + "=_")); } catch (e) { errors.push(("invalid " + type + " \"" + ident + "\" in expression: " + (text.trim()))); } } } function checkExpression (exp, text, errors) { try { new Function(("return " + exp)); } catch (e) { var keywordMatch = exp.replace(stripStringRE, '').match(prohibitedKeywordRE); if (keywordMatch) { errors.push( "avoid using JavaScript keyword as property name: " + "\"" + (keywordMatch[0]) + "\"\n Raw expression: " + (text.trim()) ); } else { errors.push( "invalid expression: " + (e.message) + " in\n\n" + " " + exp + "\n\n" + " Raw expression: " + (text.trim()) + "\n" ); } } } /* */ function createFunction (code, errors) { try { return new Function(code) } catch (err) { errors.push({ err: err, code: code }); return noop } } function createCompileToFunctionFn (compile) { var cache = Object.create(null); return function compileToFunctions ( template, options, vm ) { options = extend({}, options); var warn$$1 = options.warn || warn; delete options.warn; /* istanbul ignore if */ if (process.env.NODE_ENV !== 'production') { // detect possible CSP restriction try { new Function('return 1'); } catch (e) { if (e.toString().match(/unsafe-eval|CSP/)) { warn$$1( 'It seems you are using the standalone build of Vue.js in an ' + 'environment with Content Security Policy that prohibits unsafe-eval. ' + 'The template compiler cannot work in this environment. Consider ' + 'relaxing the policy to allow unsafe-eval or pre-compiling your ' + 'templates into render functions.' ); } } } // check cache var key = options.delimiters ? String(options.delimiters) + template : template; if (cache[key]) { return cache[key] } // compile var compiled = compile(template, options); // check compilation errors/tips if (process.env.NODE_ENV !== 'production') { if (compiled.errors && compiled.errors.length) { warn$$1( "Error compiling template:\n\n" + template + "\n\n" + compiled.errors.map(function (e) { return ("- " + e); }).join('\n') + '\n', vm ); } if (compiled.tips && compiled.tips.length) { compiled.tips.forEach(function (msg) { return tip(msg, vm); }); } } // turn code into functions var res = {}; var fnGenErrors = []; res.render = createFunction(compiled.render, fnGenErrors); res.staticRenderFns = compiled.staticRenderFns.map(function (code) { return createFunction(code, fnGenErrors) }); // check function generation errors. // this should only happen if there is a bug in the compiler itself. // mostly for codegen development use /* istanbul ignore if */ if (process.env.NODE_ENV !== 'production') { if ((!compiled.errors || !compiled.errors.length) && fnGenErrors.length) { warn$$1( "Failed to generate render function:\n\n" + fnGenErrors.map(function (ref) { var err = ref.err; var code = ref.code; return ((err.toString()) + " in\n\n" + code + "\n"); }).join('\n'), vm ); } } return (cache[key] = res) } } /* */ function createCompilerCreator (baseCompile) { return function createCompiler (baseOptions) { function compile ( template, options ) { var finalOptions = Object.create(baseOptions); var errors = []; var tips = []; finalOptions.warn = function (msg, tip) { (tip ? tips : errors).push(msg); }; if (options) { // merge custom modules if (options.modules) { finalOptions.modules = (baseOptions.modules || []).concat(options.modules); } // merge custom directives if (options.directives) { finalOptions.directives = extend( Object.create(baseOptions.directives || null), options.directives ); } // copy other options for (var key in options) { if (key !== 'modules' && key !== 'directives') { finalOptions[key] = options[key]; } } } var compiled = baseCompile(template, finalOptions); if (process.env.NODE_ENV !== 'production') { errors.push.apply(errors, detectErrors(compiled.ast)); } compiled.errors = errors; compiled.tips = tips; return compiled } return { compile: compile, compileToFunctions: createCompileToFunctionFn(compile) } } } /* */ // `createCompilerCreator` allows creating compilers that use alternative // parser/optimizer/codegen, e.g the SSR optimizing compiler. // Here we just export a default compiler using the default parts. var createCompiler = createCompilerCreator(function baseCompile ( template, options ) { var ast = parse(template.trim(), options); if (options.optimize !== false) { optimize(ast, options); } var code = generate(ast, options); return { ast: ast, render: code.render, staticRenderFns: code.staticRenderFns } }); /* */ var ref$1 = createCompiler(baseOptions); var compileToFunctions = ref$1.compileToFunctions; /* */ // check whether current browser encodes a char inside attribute values var div; function getShouldDecode (href) { div = div || document.createElement('div'); div.innerHTML = href ? "<a href=\"\n\"/>" : "<div a=\"\n\"/>"; return div.innerHTML.indexOf('&#10;') > 0 } // #3663: IE encodes newlines inside attribute values while other browsers don't var shouldDecodeNewlines = inBrowser ? getShouldDecode(false) : false; // #6828: chrome encodes content in a[href] var shouldDecodeNewlinesForHref = inBrowser ? getShouldDecode(true) : false; /* */ var idToTemplate = cached(function (id) { var el = query(id); return el && el.innerHTML }); var mount = Vue.prototype.$mount; Vue.prototype.$mount = function ( el, hydrating ) { el = el && query(el); /* istanbul ignore if */ if (el === document.body || el === document.documentElement) { process.env.NODE_ENV !== 'production' && warn( "Do not mount Vue to <html> or <body> - mount to normal elements instead." ); return this } var options = this.$options; // resolve template/el and convert to render function if (!options.render) { var template = options.template; if (template) { if (typeof template === 'string') { if (template.charAt(0) === '#') { template = idToTemplate(template); /* istanbul ignore if */ if (process.env.NODE_ENV !== 'production' && !template) { warn( ("Template element not found or is empty: " + (options.template)), this ); } } } else if (template.nodeType) { template = template.innerHTML; } else { if (process.env.NODE_ENV !== 'production') { warn('invalid template option:' + template, this); } return this } } else if (el) { template = getOuterHTML(el); } if (template) { /* istanbul ignore if */ if (process.env.NODE_ENV !== 'production' && config.performance && mark) { mark('compile'); } var ref = compileToFunctions(template, { shouldDecodeNewlines: shouldDecodeNewlines, shouldDecodeNewlinesForHref: shouldDecodeNewlinesForHref, delimiters: options.delimiters, comments: options.comments }, this); var render = ref.render; var staticRenderFns = ref.staticRenderFns; options.render = render; options.staticRenderFns = staticRenderFns; /* istanbul ignore if */ if (process.env.NODE_ENV !== 'production' && config.performance && mark) { mark('compile end'); measure(("vue " + (this._name) + " compile"), 'compile', 'compile end'); } } } return mount.call(this, el, hydrating) }; /** * Get outerHTML of elements, taking care * of SVG elements in IE as well. */ function getOuterHTML (el) { if (el.outerHTML) { return el.outerHTML } else { var container = document.createElement('div'); container.appendChild(el.cloneNode(true)); return container.innerHTML } } Vue.compile = compileToFunctions; export default Vue; kodo - Gogs: Go Git Service

No Description

views.py 24KB

    # -*- coding: utf-8 -*- from __future__ import division from curtail_uuid import CurtailUUID from django.conf import settings from django.db import connection, transaction from django_response import response from logit import logit from paginator import pagination from rest_framework import viewsets from TimeConvert import TimeConvert as tc from account.models import UserInfo from group.models import GroupInfo, GroupPhotoInfo, GroupUserInfo, PhotoCommentInfo, PhotoThumbUpInfo from group.serializers import GroupInfoSerializer, GroupPhotoInfoSerializer, GroupUserInfoSerializer from message.models import UserMessageInfo from utils.error.errno_utils import GroupPhotoStatusCode, GroupStatusCode, GroupUserStatusCode, UserStatusCode from utils.group_photo_utils import get_current_photos from utils.price_utils import get_group_photo_price from utils.qiniucdn import qiniu_file_url from utils.redis.connect import r from utils.redis.rgroup import (del_group_photo_thumbup_flag, get_group_info, get_group_photo_comment_list, get_group_photo_data, get_group_photo_thumbup_flag, get_group_photo_thumbup_list, get_group_photo_watchers, get_group_users_info, set_group_info, set_group_info_by_id, set_group_photo_comment_list, set_group_photo_data, set_group_photo_thumbup_flag, set_group_photo_thumbup_list, set_group_users_info) from utils.redis.rkeys import GROUP_LAST_PHOTO_PK, GROUP_PHOTO_WATCHER_SET, GROUP_USERS_PASSED_SET from utils.redis.rlock import upload_lock from utils.redis.rorder import get_lensman_order_record from utils.sql.raw import PAI2_HOME_API, PAI2_HOME_WX_API from utils.storage_qiniu_utils import file_save from utils.time_utils import origin_expired_stamps from utils.url_utils import share_url @logit @transaction.atomic def group_create_api(request): """ 群组创建 """ user_id = request.POST.get('user_id', '') group_name = request.POST.get('group_name', '') group_default_avatar = int(request.POST.get('group_default_avatar', 0)) # 用户校验 try: user = UserInfo.objects.get(user_id=user_id) except UserInfo.DoesNotExist: return response(UserStatusCode.USER_NOT_FOUND) # 群组唯一标识 group_id = CurtailUUID.uuid(GroupInfo, 'group_id') # 群组记录创建 group = GroupInfo.objects.create( group_id=group_id, admin_id=user_id, group_name=group_name, group_default_avatar=group_default_avatar, group_from=GroupInfo.APP_GROUP, ) # Redis 群组数据缓存 group_info = set_group_info(group) # 群组用户记录创建 GroupUserInfo.objects.create( group_id=group_id, user_id=user_id, nickname=user.final_nickname, avatar=user.avatar, admin=True, user_status=GroupUserInfo.PASSED, passed_at=tc.utc_datetime(), ) # Redis 群组用户数据缓存 group_users = set_group_users_info(group) # Redis 群组通过集合缓存 r.sadd(GROUP_USERS_PASSED_SET % group_id, user_id) return response(200, 'Create Group Success', u'群组创建成功', { 'group_id': group_id, 'group': group_info, 'users': group_users, }) @logit def group_detail_api(request): """ 群组详情 """ group_id = request.POST.get('group_id', '') user_id = request.POST.get('user_id', '') return response(200, 'Get Group Detail Info Success', u'获取群组详情成功', { 'group_id': group_id, 'group': get_group_info(group_id), 'users': get_group_users_info(group_id, user_id), }) @logit def group_update_api(request): """ 群组更新 """ group_id = request.POST.get('group_id', '') admin_id = request.POST.get('admin_id', '') or request.POST.get('user_id', '') group_name = request.POST.get('group_name', '') group_desc = request.POST.get('group_desc', '') group_avatar = request.FILES.get('group_avatar', '') # 群组校验 try: group = GroupInfo.objects.get(group_id=group_id) except GroupInfo.DoesNotExist: return response(GroupStatusCode.GROUP_NOT_FOUND) # 权限校验 if group.admin_id != admin_id: return response(GroupStatusCode.NOT_GROUP_ADMIN) # 群组名称更新 if group_name: group.group_name = group_name # 群组描述更新 if group_desc: group.group_desc = group_desc # 群组头像更新 if group_avatar: group.group_avatar = file_save(group_avatar, prefix='group', ext='.jpeg').photo_path group.save() # Redis 群组数据缓存更新 group_info = set_group_info(group) return response(200, 'Update Group Success', u'群组更新成功', { 'group_id': group_id, 'group': group_info, 'users': get_group_users_info(group_id, admin_id), }) @logit def group_delete_api(request): """ 群组删除 """ group_id = request.POST.get('group_id', '') admin_id = request.POST.get('admin_id', '') or request.POST.get('user_id', '') # 群组校验 try: group = GroupInfo.objects.get(group_id=group_id) except GroupInfo.DoesNotExist: return response(GroupStatusCode.GROUP_NOT_FOUND) # 权限校验 if group.admin_id != admin_id: return response(GroupStatusCode.NOT_GROUP_ADMIN) # 照片数量校验 if GroupPhotoInfo.objects.filter(group_id=group_id, status=True).count(): return response(GroupStatusCode.GROUP_PHOTO_NOT_EMPTY) # 删除群组 group.status = False group.save() # 删除群组用户 GroupUserInfo.objects.filter(group_id=group_id).update(status=False) return response(200, 'Delete Group Success', u'群组删除成功') @logit def group_list_api(request): """ 群组列表 """ user_id = request.POST.get('user_id', '') page = int(request.POST.get('page', 1)) num = int(request.POST.get('num', settings.GROUP_NUM_PER_PAGE)) group_users = GroupUserInfo.objects.filter(user_id=user_id, user_status=GroupUserInfo.PASSED, status=True).order_by('-pk') group_users, left = pagination(group_users, page, num) groups = [] for group_user in group_users: group_info = get_group_info(group_user.group_id) groups.append(group_info) if group_info else None return response(200, 'Get Group List Success', u'获取群组列表成功', { 'groups': groups, 'left': left, }) @logit def group_lock_api(request): """ 群组锁定 """ group_id = request.POST.get('group_id', '') admin_id = request.POST.get('admin_id', '') or request.POST.get('user_id', '') # 群组校验 try: group = GroupInfo.objects.get(group_id=group_id) except GroupInfo.DoesNotExist: return response(GroupStatusCode.GROUP_NOT_FOUND) # 权限校验 if group.admin_id != admin_id: return response(GroupStatusCode.NOT_GROUP_ADMIN) # 群组锁定 group.group_lock = True group.save() # Redis 群组数据缓存更新 set_group_info(group) return response(200, 'Lock Success', u'锁定成功') @logit def group_unlock_api(request): """ 群组解锁 """ group_id = request.POST.get('group_id', '') admin_id = request.POST.get('admin_id', '') or request.POST.get('user_id', '') # 群组校验 try: group = GroupInfo.objects.get(group_id=group_id) except GroupInfo.DoesNotExist: return response(GroupStatusCode.GROUP_NOT_FOUND) # 权限校验 if group.admin_id != admin_id: return response(GroupStatusCode.NOT_GROUP_ADMIN) # 群组解锁 group.group_lock = False group.save() # Redis 群组数据缓存更新 set_group_info(group) return response(200, 'Unlock Success', u'解锁成功') @logit def group_data_api(request): """ 群组数据,评论数,点赞数 """ group_id = request.POST.get('group_id', '') return response(200, 'Get Group Data Success', u'获取群组数据成功', { 'photo_datas': get_group_photo_data(group_id), }) @logit(body=settings.LOGIT_BODY_FLAG, res=settings.LOGIT_RES_FLAG) def flyimg_upload_api(request): """ 飞图上传 """ group_id = request.POST.get('group_id', '') user_id = request.POST.get('user_id', '') nickname = request.POST.get('nickname', '') photo = request.FILES.get('photo', '') current_id = int(request.POST.get('current_id', -1)) # 用户校验 try: user = UserInfo.objects.get(user_id=user_id) except UserInfo.DoesNotExist: return response(UserStatusCode.USER_NOT_FOUND) # 群组用户校验 try: group_user = GroupUserInfo.objects.get(group_id=group_id, user_id=user_id, user_status=GroupUserInfo.PASSED) except GroupUserInfo.DoesNotExist: return response(GroupUserStatusCode.GROUP_USER_NOT_FOUND) if photo and upload_lock(group_id, user_id, photo): photo_info = file_save(photo, prefix='fly', ext='.jpeg', thumbnail=True) # 群组照片记录创建 group_photo, created = GroupPhotoInfo.objects.get_or_create( group_id=group_id, user_id=user_id, photo_md5=photo_info.photo_md5, defaults={ 'nickname': nickname or user.final_nickname, 'avatar': user.avatar, 'photo_path': photo_info.photo_path, 'has_watermark': False, 'photo_w': photo_info.photo_w, 'photo_h': photo_info.photo_h, 'photo_thumbnail_path': photo_info.photo_thumbnail_path, 'photo_thumbnail_w': photo_info.photo_thumbnail_w, 'photo_thumbnail_h': photo_info.photo_thumbnail_h, 'photo_thumbnail2_path': photo_info.photo_thumbnail2_path, 'photo_thumbnail2_w': photo_info.photo_thumbnail2_w, 'photo_thumbnail2_h': photo_info.photo_thumbnail2_h, } ) if created: # 设置群组最后一张照片PK r.set(GROUP_LAST_PHOTO_PK % group_id, group_photo.pk) # Redis 群组数据缓存 set_group_info_by_id(group_id) curinfo = get_current_photos(group_id, user_id, max(current_id, group_user.current_id), request=request) return response(200, 'Flyimg Upload Success', u'飞图上传成功', curinfo) @logit def flyimg_list_api(request): """ 飞图列表 """ group_id = request.POST.get('group_id', '') user_id = request.POST.get('user_id', '') current_id = int(request.POST.get('current_id', -1)) # 群组用户校验 try: group_user = GroupUserInfo.objects.get(group_id=group_id, user_id=user_id, user_status=GroupUserInfo.PASSED) except GroupUserInfo.DoesNotExist: return response(GroupUserStatusCode.GROUP_USER_NOT_FOUND) curinfo = get_current_photos(group_id, user_id, max(current_id, group_user.current_id), request=request) return response(200, 'Get Flyimg List Success', u'获取飞图上传成功', curinfo) @logit def flyimg_detail_api(request): user_id = request.POST.get('user_id', '') photo_id = request.POST.get('photo_id', '') # 群组照片校验 try: group_photo = GroupPhotoInfo.objects.get(photo_id=photo_id) except GroupPhotoInfo.DoesNotExist: return response(GroupPhotoStatusCode.GROUP_PHOTO_NOT_FOUND) return response(200, 'Get Flyimg Detail Success', u'获取飞图详情成功', { 'photo_info': group_photo.photo_info(user_id), 'comments': get_group_photo_comment_list(photo_id), 'thumbup': get_group_photo_thumbup_flag(photo_id, user_id), # user_id 是否点赞 photo_id 'thumbups': get_group_photo_thumbup_list(photo_id), # 群组照片点赞列表 }) @logit def comment_submit_api(request): """ 飞图评论提交 """ group_id = request.POST.get('group_id', '') user_id = request.POST.get('user_id', '') to_uid = request.POST.get('to_uid', '') photo_id = request.POST.get('photo_id', '') comment = request.POST.get('comment', '') # 群组用户校验 try: group_user = GroupUserInfo.objects.get(group_id=group_id, user_id=user_id, user_status=GroupUserInfo.PASSED) except GroupUserInfo.DoesNotExist: return response(GroupUserStatusCode.GROUP_USER_NOT_FOUND) # 群组照片校验 try: group_photo = GroupPhotoInfo.objects.get(photo_id=photo_id) except GroupPhotoInfo.DoesNotExist: return response(GroupPhotoStatusCode.GROUP_PHOTO_NOT_FOUND) # 评论内容校验 if not comment: return response(GroupPhotoStatusCode.COMMENT_CONTENT_EMPTY) # 群组照片评论记录创建 PhotoCommentInfo.objects.create( photo_id=photo_id, user_id=user_id, nickname=group_user.nickname, avatar=group_user.avatar, to_uid=to_uid, comment=comment, ) # 群组照片评论数更新 group_photo.comment_num += 1 group_photo.save() # Redis 群组照片数据缓存 set_group_photo_data(group_id) # Redis 群组照片评论列表缓存刷新 set_group_photo_comment_list(photo_id) r.sadd(GROUP_PHOTO_WATCHER_SET % photo_id, user_id) # 判断群组照片发布者是否已经被管理员移除/主动退出,如若移除/退出,则不给发布者提醒 if r.sismember(GROUP_USERS_PASSED_SET % group_photo.group_id, group_photo.user_id): UserMessageInfo.objects.create( from_uid=user_id, from_nickname=group_user.nickname, from_avatar=group_user.avatar, to_uid=group_photo.user_id, group_id=group_photo.group_id, photo_id=group_photo.photo_id, msg_type=UserMessageInfo.COMMENT, msg_title=u'评论', msg_content=comment, ) # 给所有关注者(评论/点赞)发送提醒,移除(评论/点赞)者和照片所有者 watchers = get_group_photo_watchers(photo_id, [user_id, group_photo.user_id]) for watcher in watchers: UserMessageInfo.objects.create( from_uid=user_id, from_nickname=group_user.nickname, from_avatar=group_user.avatar, to_uid=watcher, group_id=group_photo.group_id, photo_id=group_photo.photo_id, msg_type=UserMessageInfo.COMMENT, msg_title=u'评论', msg_content=comment, ) return response(200, 'Comment Success', u'评论成功', { 'comments': get_group_photo_comment_list(photo_id), }) @logit def comment_list_api(request): """ 飞图评论列表 """ photo_id = request.POST.get('photo_id', '') # 群组照片校验 if not GroupPhotoInfo.objects.filter(photo_id=photo_id).exists(): return response(GroupPhotoStatusCode.GROUP_PHOTO_NOT_FOUND) return response(200, 'Get Comment List Success', u'获取评论列表成功', { 'comments': get_group_photo_comment_list(photo_id), }) @logit def thumbup_submit_api(request): """ 飞图点赞提交 """ group_id = request.POST.get('group_id', '') user_id = request.POST.get('user_id', '') photo_id = request.POST.get('photo_id', '') # 群组用户校验 try: group_user = GroupUserInfo.objects.get(group_id=group_id, user_id=user_id, user_status=GroupUserInfo.PASSED) except GroupUserInfo.DoesNotExist: return response(GroupUserStatusCode.GROUP_USER_NOT_FOUND) # 群组照片校验 try: group_photo = GroupPhotoInfo.objects.get(photo_id=photo_id) except GroupPhotoInfo.DoesNotExist: return response(GroupPhotoStatusCode.GROUP_PHOTO_NOT_FOUND) # user_id 是否点赞 photo_id if get_group_photo_thumbup_flag(photo_id, user_id): return response(GroupPhotoStatusCode.DUPLICATE_THUMB_UP) # 群组照片点赞记录创建/更新 photo_thumbup, created = PhotoThumbUpInfo.objects.get_or_create( photo_id=photo_id, user_id=user_id, ) photo_thumbup.nickname = group_user.nickname photo_thumbup.avatar = group_user.avatar photo_thumbup.thumbup = True photo_thumbup.save() # Redis 群组照片点赞数据缓存 set_group_photo_thumbup_flag(photo_id, user_id) # 群组照片点赞数更新 group_photo.thumbup_num += 1 group_photo.save() # Redis 群组照片数据缓存 set_group_photo_data(group_id) # Redis 群组照片点赞列表缓存刷新 set_group_photo_thumbup_list(photo_id) r.sadd(GROUP_PHOTO_WATCHER_SET % photo_id, user_id) # 判断群组照片发布者是否已经被管理员移除/主动退出,如若移除/退出,则不给发布者提醒 if r.sismember(GROUP_USERS_PASSED_SET % group_photo.group_id, group_photo.user_id): UserMessageInfo.objects.create( from_uid=user_id, from_nickname=group_user.nickname, from_avatar=group_user.avatar, to_uid=group_photo.user_id, group_id=group_photo.group_id, photo_id=group_photo.photo_id, msg_type=UserMessageInfo.THUMBUP, msg_title=u'点赞', msg_content=u'点赞', ) # 给所有关注者(评论/点赞)发送提醒,移除(评论/点赞)者和照片所有者 watchers = get_group_photo_watchers(photo_id, [user_id, group_photo.user_id]) for watcher in watchers: UserMessageInfo.objects.create( from_uid=user_id, from_nickname=group_user.nickname, from_avatar=group_user.avatar, to_uid=watcher, group_id=group_photo.group_id, photo_id=group_photo.photo_id, msg_type=UserMessageInfo.THUMBUP, msg_title=u'点赞', msg_content=u'点赞', ) return response(200, 'Thumbup Success', u'点赞提交成功', { 'thumbup': True, 'thumbups': get_group_photo_thumbup_list(photo_id), }) @logit def thumbup_list_api(request): """ 飞图点赞列表 """ user_id = request.POST.get('user_id', '') photo_id = request.POST.get('photo_id', '') return response(200, 'Get Thumbup List Success', u'获取点赞列表成功', { 'thumbup': get_group_photo_thumbup_flag(photo_id, user_id), # user_id 是否点赞 photo_id 'thumbups': get_group_photo_thumbup_list(photo_id), # 群组照片点赞列表 }) @logit def thumbup_cancel_api(request): """ 飞图点赞取消 """ group_id = request.POST.get('group_id', '') user_id = request.POST.get('user_id', '') photo_id = request.POST.get('photo_id', '') # 群组用户校验 try: group_user = GroupUserInfo.objects.get(group_id=group_id, user_id=user_id, user_status=GroupUserInfo.PASSED) except GroupUserInfo.DoesNotExist: return response(GroupUserStatusCode.GROUP_USER_NOT_FOUND) # 群组照片校验 try: group_photo = GroupPhotoInfo.objects.get(photo_id=photo_id) except GroupPhotoInfo.DoesNotExist: return response(GroupPhotoStatusCode.GROUP_PHOTO_NOT_FOUND) # user_id 是否点赞 photo_id if not get_group_photo_thumbup_flag(photo_id, user_id): return response(GroupPhotoStatusCode.THUMB_UP_NOT_FOUND) # 群组照片点赞取消 photo_thumbup, created = PhotoThumbUpInfo.objects.get_or_create( photo_id=photo_id, user_id=user_id, ) photo_thumbup.thumbup = False photo_thumbup.save() # Redis 群组照片点赞数据移除 del_group_photo_thumbup_flag(photo_id, user_id) # 群组照片点赞数更新 group_photo.thumbup_num -= 1 group_photo.save() # Redis 群组照片数据缓存 set_group_photo_data(group_id) # Redis 群组照片点赞列表缓存刷新 set_group_photo_thumbup_list(photo_id) # 判断群组照片发布者是否已经被管理员移除/主动退出,如若移除/退出,则不给发布者提醒 if r.sismember(GROUP_USERS_PASSED_SET % group_photo.group_id, group_photo.user_id): UserMessageInfo.objects.create( from_uid=user_id, from_nickname=group_user.nickname, from_avatar=group_user.avatar, to_uid=group_photo.user_id, group_id=group_photo.group_id, photo_id=group_photo.photo_id, msg_type=UserMessageInfo.THUMBUP, msg_title=u'取消点赞', msg_content=u'取消点赞', ) # 群组照片点赞列表 photo_thumbups = PhotoThumbUpInfo.objects.filter(photo_id=photo_id, thumbup=True, status=True) return response(200, 'Thumbup Cancel Success', u'点赞取消成功', { 'thumbup': False, 'thumbups': [thumbup.thumbup_info for thumbup in photo_thumbups], }) @logit def pai2_home_api(request): """ 首页照片信息 """ user_id = request.POST.get('user_id', '') page = int(request.POST.get('page', 1)) num = int(request.POST.get('num', settings.PAI2_HOME_PER_PAGE)) # 执行原生 SQL 语句,获取首页照片列表 cursor = connection.cursor() cursor.execute((PAI2_HOME_WX_API if request.weixin else PAI2_HOME_API).format( user_id=user_id, offset=0, rows=settings.PAI2_HOME_MAX_ROWS, )) rows = cursor.fetchall() # 首页照片分页 rows, left = pagination(rows, page, num) # 首页照片信息 rows = [{ 'group_id': row[0], 'group_name': row[1], 'group_default_avatar': row[2], 'group_avatar': row[3], 'group_from': row[4], 'photo_id': row[5], 'photo_url': qiniu_file_url(row[6], bucket='watermark' if row[7] else 'photo'), 'photo_w': row[8], 'photo_h': row[9], 'photo_thumbnail_url': qiniu_file_url(row[10], bucket='thumbnail'), 'photo_thumbnail_w': row[11], 'photo_thumbnail_h': row[12], 'photo_thumbnail2_url': qiniu_file_url(row[13], bucket='thumbnail2'), 'photo_thumbnail2_w': row[14], 'photo_thumbnail2_h': row[15], 'photo_share_url': share_url(row[5]), # Warning: Index of This Line is 5 'user_id': row[16], 'nickname': row[17], 'avatar': row[18], 'comment_num': row[19], 'thumbup_num': row[20], 'photo_from': row[21], 'session_id': row[22], 'nomark': row[23], 'origin': row[24], 'created_at': row[25], 'origin_expired_stamps': origin_expired_stamps(row[25], row[16]), 'thumbup': get_group_photo_thumbup_flag(row[5], user_id), 'porder': get_lensman_order_record(row[5], user_id) if row[21] == GroupPhotoInfo.SESSION_GROUP else {}, 'display_payment_btn': row[21] == GroupPhotoInfo.SESSION_GROUP and row[26] not in [GroupPhotoInfo.OUTTAKE], } for row in rows] return response(200, 'Get Home Data Success', u'获取首页数据成功', { 'photos': rows, 'left': left, }) @logit def lensman_photo_price(request): """ 摄影师照片价格获取 """ user_id = request.POST.get('user_id', '') photo_id = request.POST.get('photo_id', '') photo_type = request.POST.get('photo_type', 'nomark') # nomark for 去除水印, origin for 获取高清图 # 群组照片校验 try: group_photo = GroupPhotoInfo.objects.get(photo_id=photo_id) except GroupPhotoInfo.DoesNotExist: return response(GroupPhotoStatusCode.GROUP_PHOTO_NOT_FOUND) return response(200, 'Get Price Success', u'获取价格成功', { 'price': get_group_photo_price(group_photo, photo_type) }) @logit def lensman_photo_bought(request): """ 摄影师照片已购买 """ user_id = request.POST.get('user_id', '') photo_id = request.POST.get('photo_id', '') return response(200, 'Get Bought Data Success', u'获取购买数据成功', { 'porder': get_lensman_order_record(photo_id, user_id) }) class GroupInfoViewSet(viewsets.ModelViewSet): queryset = GroupInfo.objects.all().order_by('-pk') serializer_class = GroupInfoSerializer class GroupUserInfoViewSet(viewsets.ModelViewSet): queryset = GroupUserInfo.objects.all().order_by('-pk') serializer_class = GroupUserInfoSerializer class GroupPhotoInfoViewSet(viewsets.ModelViewSet): queryset = GroupPhotoInfo.objects.all().order_by('-pk') serializer_class = GroupPhotoInfoSerializer