diff --git a/administrator/components/com_media/layouts/toolbar/create-folder.php b/administrator/components/com_media/layouts/toolbar/create-folder.php new file mode 100644 index 0000000000..241b962767 --- /dev/null +++ b/administrator/components/com_media/layouts/toolbar/create-folder.php @@ -0,0 +1,14 @@ + + diff --git a/administrator/components/com_media/layouts/toolbar/delete.php b/administrator/components/com_media/layouts/toolbar/delete.php new file mode 100644 index 0000000000..408926a490 --- /dev/null +++ b/administrator/components/com_media/layouts/toolbar/delete.php @@ -0,0 +1,14 @@ + + \ No newline at end of file diff --git a/administrator/components/com_media/layouts/toolbar/upload.php b/administrator/components/com_media/layouts/toolbar/upload.php new file mode 100644 index 0000000000..10de2bee10 --- /dev/null +++ b/administrator/components/com_media/layouts/toolbar/upload.php @@ -0,0 +1,14 @@ + + \ No newline at end of file diff --git a/administrator/components/com_media/resources/scripts/components/app.vue b/administrator/components/com_media/resources/scripts/components/app.vue index f0609e0856..be9230672f 100644 --- a/administrator/components/com_media/resources/scripts/components/app.vue +++ b/administrator/components/com_media/resources/scripts/components/app.vue @@ -1,45 +1,35 @@ \ No newline at end of file diff --git a/administrator/components/com_media/resources/scripts/components/breadcrumb/breadcrumb.vue b/administrator/components/com_media/resources/scripts/components/breadcrumb/breadcrumb.vue index 4c68881cc5..fcc261db07 100644 --- a/administrator/components/com_media/resources/scripts/components/breadcrumb/breadcrumb.vue +++ b/administrator/components/com_media/resources/scripts/components/breadcrumb/breadcrumb.vue @@ -1,13 +1,12 @@ \ No newline at end of file diff --git a/administrator/components/com_media/resources/scripts/mediamanager.js b/administrator/components/com_media/resources/scripts/mediamanager.js index 0cc7565a7c..b53db1b96b 100644 --- a/administrator/components/com_media/resources/scripts/mediamanager.js +++ b/administrator/components/com_media/resources/scripts/mediamanager.js @@ -24,6 +24,10 @@ Vue.component('media-browser-item', BrowserItem); Vue.component('media-modal', MediaModal); Vue.component('create-folder-modal', CreateFolderModal); +// Toolbar components +window.MediaManager = window.MediaManager || {}; +window.MediaManager.Event = new Vue(); + // Create the root Vue instance document.addEventListener("DOMContentLoaded", (e) => new Vue({ diff --git a/administrator/components/com_media/resources/styles/mediamanager.scss b/administrator/components/com_media/resources/styles/mediamanager.scss index a2a80a8cc7..6626659d38 100644 --- a/administrator/components/com_media/resources/styles/mediamanager.scss +++ b/administrator/components/com_media/resources/styles/mediamanager.scss @@ -3,114 +3,27 @@ $sidebar-width: 16.666666%; /* General layout */ .media-container { - height: 100%; - flex-direction: column; - margin-top: -57px; - margin-left: -15px; - margin-right: -15px; } .media-main { - min-height: 100%; - background: rgba(0,0,0,.03); - flex-grow: 1; - display: flex; } .media-sidebar { - width: $sidebar-width; - background: #f2f2f2; - border-right: 1px solid #e1e1e1; - padding-bottom: 50px; } -/* Media toolbar */ +/* Media breadcrumb */ .media-toolbar { - background-color: #f2f2f2; - border-bottom: 1px solid transparent; - box-shadow: 0 2px 4px rgba(0, 0, 0, .2); - padding: 15px; - position: relative; - display: flex; -} - -.media-toolbar-create { - width: $sidebar-width; - - .btn-success:not(.dropdown-toggle) { - width: 140px; - color: #fefefe; - background-color: #48b848; - border-color: rgba(0,0,0,.2); - } - .btn-success.dropdown-toggle { - background: #368c36; - border-color: #368c36; + .breadcrumb { + margin: 0; + padding: 0 7.5px; + background: transparent; + & > li > a { + cursor: pointer; + } + & > li:last-child a { + font-weight: bold; + } } - .btn-sm { - padding: 0 10px; - line-height: 1.8rem; - } -} - -/* Media breadcrumb */ -.media-breadcrumb { - margin: 0; - padding: 0 7.5px; - list-style: none; - flex-grow: 1; -} - -.media-breadcrumb > li { - display: inline-block; - font-size: 16px; - line-height: 27px; -} - -.media-breadcrumb > li > a { - cursor: pointer; - color: #555; - text-decoration: none; -} - -.media-breadcrumb > li > .divider { - display: inline-block; - padding: 0 3px; - color: #7d7d7d; -} - -.media-breadcrumb > li:last-child a { - font-weight: bold; -} - -/* Media tools */ -.media-tools { - display: flex; - justify-content: flex-end; - margin: 0; - padding: 0; - margin-left: 15px; - list-style: none; -} - -.media-tools a { - display: inline-block; - padding: 0 10px; - color: #7d7d7d; - text-decoration: none; - font-size: 20px; -} - -.media-tools a:hover { - color: #333; -} - -.media-tools-divider { - border-right: 1px solid #e5e5e5; - display: inline-block; - height: 53px; - margin: -10.5px 8px; - vertical-align: middle; } /* Media Tree */ @@ -179,19 +92,14 @@ ul.media-tree ul { } /* Media browser */ -.media-browser { - width: 83.5%; -} - .media-browser-items { - padding: 15px; display: flex; flex-wrap: wrap; } .media-browser-item { position: relative; - margin-top: 15px; + margin-bottom: 15px; margin-right: 15px; width: calc(25% - 15px); -moz-user-select: none; @@ -267,5 +175,3 @@ ul.media-tree ul { transform: translateY(-10px); opacity: 0; } -body { - background: red; } diff --git a/administrator/components/com_media/views/media/tmpl/default_texts.php b/administrator/components/com_media/views/media/tmpl/default_texts.php index a499e08c2e..0aecccc7bd 100644 --- a/administrator/components/com_media/views/media/tmpl/default_texts.php +++ b/administrator/components/com_media/views/media/tmpl/default_texts.php @@ -8,11 +8,7 @@ */ defined('_JEXEC') or die; -JText::script('COM_MEDIA_CREATE_FOLDER', true); JText::script('COM_MEDIA_CREATE_NEW_FOLDER', true); JText::script('COM_MEDIA_FOLDER', true); -JText::script('COM_MEDIA_NEW', true); -JText::script('COM_MEDIA_UPLOAD_FILE', true); -JText::script('COM_MEDIA_UPLOAD_FOLDER', true); JText::script('JCANCEL', true); JText::script('JAPPLY', true); diff --git a/administrator/components/com_media/views/media/view.html.php b/administrator/components/com_media/views/media/view.html.php index 75b0f02d96..5defeba75d 100644 --- a/administrator/components/com_media/views/media/view.html.php +++ b/administrator/components/com_media/views/media/view.html.php @@ -43,7 +43,45 @@ public function display($tpl = null) */ protected function prepareToolbar() { + // Get the toolbar object instance + $bar = JToolbar::getInstance('toolbar'); + $user = JFactory::getUser(); + // Set the title JToolbarHelper::title(JText::_('COM_MEDIA'), 'images mediamanager'); + + // Add the upload and create folder buttons + if ($user->authorise('core.create', 'com_media')) + { + // Add the upload button + $layout = new JLayoutFile('toolbar.upload', JPATH_COMPONENT_ADMINISTRATOR . '/legacy/layouts'); + + $bar->appendButton('Custom', $layout->render(array()), 'upload'); + JToolbarHelper::divider(); + + // Add the create folder button + $layout = new JLayoutFile('toolbar.create-folder', JPATH_COMPONENT_ADMINISTRATOR . '/legacy/layouts'); + + $bar->appendButton('Custom', $layout->render(array()), 'new'); + JToolbarHelper::divider(); + } + + // Add a delete button + if ($user->authorise('core.delete', 'com_media')) + { + // Instantiate a new JLayoutFile instance and render the layout + $layout = new JLayoutFile('toolbar.delete', JPATH_COMPONENT_ADMINISTRATOR . '/legacy/layouts'); + $bar->appendButton('Custom', $layout->render(array()), 'upload'); + JToolbarHelper::divider(); + } + + // Add the preferences button + if ($user->authorise('core.admin', 'com_media') || $user->authorise('core.options', 'com_media')) + { + JToolbarHelper::preferences('com_media'); + JToolbarHelper::divider(); + } + + JToolbarHelper::help('JHELP_CONTENT_MEDIA_MANAGER'); } } diff --git a/media/com_media/css/mediamanager.css b/media/com_media/css/mediamanager.css index 63dd214cd8..a4d30a8427 100644 --- a/media/com_media/css/mediamanager.css +++ b/media/com_media/css/mediamanager.css @@ -1,96 +1,13 @@ /* General layout */ -.media-container { - height: 100%; - flex-direction: column; - margin-top: -57px; - margin-left: -15px; - margin-right: -15px; } - -.media-main { - min-height: 100%; - background: rgba(0, 0, 0, 0.03); - flex-grow: 1; - display: flex; } - -.media-sidebar { - width: 16.66667%; - background: #f2f2f2; - border-right: 1px solid #e1e1e1; - padding-bottom: 50px; } - -/* Media toolbar */ -.media-toolbar { - background-color: #f2f2f2; - border-bottom: 1px solid transparent; - box-shadow: 0 2px 4px rgba(0, 0, 0, 0.2); - padding: 15px; - position: relative; - display: flex; } - -.media-toolbar-create { - width: 16.66667%; } - .media-toolbar-create .btn-success:not(.dropdown-toggle) { - width: 140px; - color: #fefefe; - background-color: #48b848; - border-color: rgba(0, 0, 0, 0.2); } - .media-toolbar-create .btn-success.dropdown-toggle { - background: #368c36; - border-color: #368c36; } - .media-toolbar-create .btn-sm { - padding: 0 10px; - line-height: 1.8rem; } - /* Media breadcrumb */ -.media-breadcrumb { +.media-toolbar .breadcrumb { margin: 0; padding: 0 7.5px; - list-style: none; - flex-grow: 1; } - -.media-breadcrumb > li { - display: inline-block; - font-size: 16px; - line-height: 27px; } - -.media-breadcrumb > li > a { - cursor: pointer; - color: #555; - text-decoration: none; } - -.media-breadcrumb > li > .divider { - display: inline-block; - padding: 0 3px; - color: #7d7d7d; } - -.media-breadcrumb > li:last-child a { - font-weight: bold; } - -/* Media tools */ -.media-tools { - display: flex; - justify-content: flex-end; - margin: 0; - padding: 0; - margin-left: 15px; - list-style: none; } - -.media-tools a { - display: inline-block; - padding: 0 10px; - color: #7d7d7d; - text-decoration: none; - font-size: 20px; } - -.media-tools a:hover { - color: #333; } - -.media-tools-divider { - border-right: 1px solid #e5e5e5; - display: inline-block; - height: 53px; - margin: -10.5px 8px; - vertical-align: middle; } + background: transparent; } + .media-toolbar .breadcrumb > li > a { + cursor: pointer; } + .media-toolbar .breadcrumb > li:last-child a { + font-weight: bold; } /* Media Tree */ ul.media-tree { @@ -148,17 +65,13 @@ ul.media-tree ul { font-weight: bold; } /* Media browser */ -.media-browser { - width: 83.5%; } - .media-browser-items { - padding: 15px; display: flex; flex-wrap: wrap; } .media-browser-item { position: relative; - margin-top: 15px; + margin-bottom: 15px; margin-right: 15px; width: calc(25% - 15px); -moz-user-select: none; @@ -220,6 +133,3 @@ ul.media-tree ul { .slide-fade-enter, .slide-fade-leave-to { transform: translateY(-10px); opacity: 0; } - -body { - background: red; } diff --git a/media/com_media/js/mediamanager.js b/media/com_media/js/mediamanager.js index ed8e77037d..7dac5a69aa 100644 --- a/media/com_media/js/mediamanager.js +++ b/media/com_media/js/mediamanager.js @@ -409,10 +409,136 @@ process.chdir = function (dir) { process.umask = function() { return 0; }; },{}],3:[function(require,module,exports){ +var Vue // late bind +var map = window.__VUE_HOT_MAP__ = Object.create(null) +var installed = false +var isBrowserify = false +var initHookName = 'beforeCreate' + +exports.install = function (vue, browserify) { + if (installed) return + installed = true + + Vue = vue + isBrowserify = browserify + + // compat with < 2.0.0-alpha.7 + if (Vue.config._lifecycleHooks.indexOf('init') > -1) { + initHookName = 'init' + } + + exports.compatible = Number(Vue.version.split('.')[0]) >= 2 + if (!exports.compatible) { + console.warn( + '[HMR] You are using a version of vue-hot-reload-api that is ' + + 'only compatible with Vue.js core ^2.0.0.' + ) + return + } +} + +/** + * Create a record for a hot module, which keeps track of its constructor + * and instances + * + * @param {String} id + * @param {Object} options + */ + +exports.createRecord = function (id, options) { + var Ctor = null + if (typeof options === 'function') { + Ctor = options + options = Ctor.options + } + makeOptionsHot(id, options) + map[id] = { + Ctor: Vue.extend(options), + instances: [] + } +} + +/** + * Make a Component options object hot. + * + * @param {String} id + * @param {Object} options + */ + +function makeOptionsHot (id, options) { + injectHook(options, initHookName, function () { + map[id].instances.push(this) + }) + injectHook(options, 'beforeDestroy', function () { + var instances = map[id].instances + instances.splice(instances.indexOf(this), 1) + }) +} + +/** + * Inject a hook to a hot reloadable component so that + * we can keep track of it. + * + * @param {Object} options + * @param {String} name + * @param {Function} hook + */ + +function injectHook (options, name, hook) { + var existing = options[name] + options[name] = existing + ? Array.isArray(existing) + ? existing.concat(hook) + : [existing, hook] + : [hook] +} + +function tryWrap (fn) { + return function (id, arg) { + try { fn(id, arg) } catch (e) { + console.error(e) + console.warn('Something went wrong during Vue component hot-reload. Full reload required.') + } + } +} + +exports.rerender = tryWrap(function (id, fns) { + var record = map[id] + record.Ctor.options.render = fns.render + record.Ctor.options.staticRenderFns = fns.staticRenderFns + record.instances.slice().forEach(function (instance) { + instance.$options.render = fns.render + instance.$options.staticRenderFns = fns.staticRenderFns + instance._staticTrees = [] // reset static trees + instance.$forceUpdate() + }) +}) + +exports.reload = tryWrap(function (id, options) { + makeOptionsHot(id, options) + var record = map[id] + record.Ctor.extendOptions = options + var newCtor = Vue.extend(options) + record.Ctor.options = newCtor.options + record.Ctor.cid = newCtor.cid + if (newCtor.release) { + // temporary global mixin strategy used in < 2.0.0-alpha.6 + newCtor.release() + } + record.instances.slice().forEach(function (instance) { + if (instance.$vnode && instance.$vnode.context) { + instance.$vnode.context.$forceUpdate() + } else { + console.warn('Root or manually mounted instance modified. Full reload required.') + } + }) +}) + +},{}],4:[function(require,module,exports){ (function (process,global){ /*! - * Vue.js v2.1.10 - * (c) 2014-2017 Evan You + * Vue.js v2.1.8 + * (c) 2014-2016 Evan You * Released under the MIT License. */ 'use strict'; @@ -435,8 +561,8 @@ function _toString (val) { * If the conversion fails, return original string. */ function toNumber (val) { - var n = parseFloat(val); - return isNaN(n) ? val : n + var n = parseFloat(val, 10); + return (n || n === 0) ? n : val } /** @@ -501,7 +627,7 @@ function cached (fn) { } /** - * Camelize a hyphen-delimited string. + * Camelize a hyphen-delmited string. */ var camelizeRE = /-(\w)/g; var camelize = cached(function (str) { @@ -1911,953 +2037,808 @@ if (process.env.NODE_ENV !== 'production') { /* */ -var VNode = function VNode ( - tag, - data, - children, - text, - elm, - context, - componentOptions -) { - this.tag = tag; - this.data = data; - this.children = children; - this.text = text; - this.elm = elm; - this.ns = undefined; - this.context = context; - this.functionalContext = undefined; - this.key = data && data.key; - this.componentOptions = componentOptions; - this.componentInstance = undefined; - this.parent = undefined; - this.raw = false; - this.isStatic = false; - this.isRootInsert = true; - this.isComment = false; - this.isCloned = false; - this.isOnce = false; -}; - -var prototypeAccessors = { child: {} }; - -// DEPRECATED: alias for componentInstance for backwards compat. -/* istanbul ignore next */ -prototypeAccessors.child.get = function () { - return this.componentInstance -}; - -Object.defineProperties( VNode.prototype, prototypeAccessors ); - -var createEmptyVNode = function () { - var node = new VNode(); - node.text = ''; - node.isComment = true; - return node -}; - -function createTextVNode (val) { - return new VNode(undefined, undefined, undefined, String(val)) -} -// optimized shallow clone -// used for static nodes and slot nodes because they may be reused across -// multiple renders, cloning them avoids errors when DOM manipulations rely -// on their elm reference. -function cloneVNode (vnode) { - var cloned = new VNode( - vnode.tag, - vnode.data, - vnode.children, - vnode.text, - vnode.elm, - vnode.context, - vnode.componentOptions - ); - cloned.ns = vnode.ns; - cloned.isStatic = vnode.isStatic; - cloned.key = vnode.key; - cloned.isCloned = true; - return cloned -} +var queue = []; +var has$1 = {}; +var circular = {}; +var waiting = false; +var flushing = false; +var index = 0; -function cloneVNodes (vnodes) { - var res = new Array(vnodes.length); - for (var i = 0; i < vnodes.length; i++) { - res[i] = cloneVNode(vnodes[i]); +/** + * Reset the scheduler's state. + */ +function resetSchedulerState () { + queue.length = 0; + has$1 = {}; + if (process.env.NODE_ENV !== 'production') { + circular = {}; } - return res + waiting = flushing = false; } -/* */ +/** + * Flush both queues and run the watchers. + */ +function flushSchedulerQueue () { + flushing = true; -var hooks = { init: init, prepatch: prepatch, insert: insert, destroy: destroy$1 }; -var hooksToMerge = Object.keys(hooks); + // Sort queue before flush. + // This ensures that: + // 1. Components are updated from parent to child. (because parent is always + // created before the child) + // 2. A component's user watchers are run before its render watcher (because + // user watchers are created before the render watcher) + // 3. If a component is destroyed during a parent component's watcher run, + // its watchers can be skipped. + queue.sort(function (a, b) { return a.id - b.id; }); -function createComponent ( - Ctor, - data, - context, - children, - tag -) { - if (!Ctor) { - return + // do not cache length because more watchers might be pushed + // as we run existing watchers + for (index = 0; index < queue.length; index++) { + var watcher = queue[index]; + var id = watcher.id; + has$1[id] = null; + watcher.run(); + // in dev build, check and stop circular updates. + if (process.env.NODE_ENV !== 'production' && has$1[id] != null) { + circular[id] = (circular[id] || 0) + 1; + if (circular[id] > config._maxUpdateCount) { + warn( + 'You may have an infinite update loop ' + ( + watcher.user + ? ("in watcher with expression \"" + (watcher.expression) + "\"") + : "in a component render function." + ), + watcher.vm + ); + break + } + } } - var baseCtor = context.$options._base; - if (isObject(Ctor)) { - Ctor = baseCtor.extend(Ctor); + // devtool hook + /* istanbul ignore if */ + if (devtools && config.devtools) { + devtools.emit('flush'); } - if (typeof Ctor !== 'function') { - if (process.env.NODE_ENV !== 'production') { - warn(("Invalid Component definition: " + (String(Ctor))), context); - } - return - } + resetSchedulerState(); +} - // async component - if (!Ctor.cid) { - if (Ctor.resolved) { - Ctor = Ctor.resolved; +/** + * Push a watcher into the watcher queue. + * Jobs with duplicate IDs will be skipped unless it's + * pushed when the queue is being flushed. + */ +function queueWatcher (watcher) { + var id = watcher.id; + if (has$1[id] == null) { + has$1[id] = true; + if (!flushing) { + queue.push(watcher); } else { - Ctor = resolveAsyncComponent(Ctor, baseCtor, function () { - // it's ok to queue this on every render because - // $forceUpdate is buffered by the scheduler. - context.$forceUpdate(); - }); - if (!Ctor) { - // return nothing if this is indeed an async component - // wait for the callback to trigger parent update. - return + // if already flushing, splice the watcher based on its id + // if already past its id, it will be run next immediately. + var i = queue.length - 1; + while (i >= 0 && queue[i].id > watcher.id) { + i--; } + queue.splice(Math.max(i, index) + 1, 0, watcher); + } + // queue the flush + if (!waiting) { + waiting = true; + nextTick(flushSchedulerQueue); } } +} - // resolve constructor options in case global mixins are applied after - // component constructor creation - resolveConstructorOptions(Ctor); - - data = data || {}; - - // extract props - var propsData = extractProps(data, Ctor); - - // functional component - if (Ctor.options.functional) { - return createFunctionalComponent(Ctor, propsData, data, context, children) - } - - // extract listeners, since these needs to be treated as - // child component listeners instead of DOM listeners - var listeners = data.on; - // replace with listeners with .native modifier - data.on = data.nativeOn; - - if (Ctor.options.abstract) { - // abstract components do not keep anything - // other than props & listeners - data = {}; - } - - // merge component management hooks onto the placeholder node - mergeHooks(data); +/* */ - // return a placeholder vnode - var name = Ctor.options.name || tag; - var vnode = new VNode( - ("vue-component-" + (Ctor.cid) + (name ? ("-" + name) : '')), - data, undefined, undefined, undefined, context, - { Ctor: Ctor, propsData: propsData, listeners: listeners, tag: tag, children: children } - ); - return vnode -} +var uid$2 = 0; -function createFunctionalComponent ( - Ctor, - propsData, - data, - context, - children +/** + * A watcher parses an expression, collects dependencies, + * and fires callback when the expression value changes. + * This is used for both the $watch() api and directives. + */ +var Watcher = function Watcher ( + vm, + expOrFn, + cb, + options ) { - var props = {}; - var propOptions = Ctor.options.props; - if (propOptions) { - for (var key in propOptions) { - props[key] = validateProp(key, propOptions, propsData); - } + this.vm = vm; + vm._watchers.push(this); + // options + if (options) { + this.deep = !!options.deep; + this.user = !!options.user; + this.lazy = !!options.lazy; + this.sync = !!options.sync; + } else { + this.deep = this.user = this.lazy = this.sync = false; } - // ensure the createElement function in functional components - // gets a unique context - this is necessary for correct named slot check - var _context = Object.create(context); - var h = function (a, b, c, d) { return createElement(_context, a, b, c, d, true); }; - var vnode = Ctor.options.render.call(null, h, { - props: props, - data: data, - parent: context, - children: children, - slots: function () { return resolveSlots(children, context); } - }); - if (vnode instanceof VNode) { - vnode.functionalContext = context; - if (data.slot) { - (vnode.data || (vnode.data = {})).slot = data.slot; + this.cb = cb; + this.id = ++uid$2; // uid for batching + this.active = true; + this.dirty = this.lazy; // for lazy watchers + this.deps = []; + this.newDeps = []; + this.depIds = new _Set(); + this.newDepIds = new _Set(); + this.expression = process.env.NODE_ENV !== 'production' + ? expOrFn.toString() + : ''; + // parse expression for getter + if (typeof expOrFn === 'function') { + this.getter = expOrFn; + } else { + this.getter = parsePath(expOrFn); + if (!this.getter) { + this.getter = function () {}; + process.env.NODE_ENV !== 'production' && warn( + "Failed watching path: \"" + expOrFn + "\" " + + 'Watcher only accepts simple dot-delimited paths. ' + + 'For full control, use a function instead.', + vm + ); } } - return vnode -} + this.value = this.lazy + ? undefined + : this.get(); +}; -function createComponentInstanceForVnode ( - vnode, // we know it's MountedComponentVNode but flow doesn't - parent, // activeInstance in lifecycle state - parentElm, - refElm -) { - var vnodeComponentOptions = vnode.componentOptions; - var options = { - _isComponent: true, - parent: parent, - propsData: vnodeComponentOptions.propsData, - _componentTag: vnodeComponentOptions.tag, - _parentVnode: vnode, - _parentListeners: vnodeComponentOptions.listeners, - _renderChildren: vnodeComponentOptions.children, - _parentElm: parentElm || null, - _refElm: refElm || null - }; - // check inline-template render functions - var inlineTemplate = vnode.data.inlineTemplate; - if (inlineTemplate) { - options.render = inlineTemplate.render; - options.staticRenderFns = inlineTemplate.staticRenderFns; +/** + * Evaluate the getter, and re-collect dependencies. + */ +Watcher.prototype.get = function get () { + pushTarget(this); + var value = this.getter.call(this.vm, this.vm); + // "touch" every property so they are all tracked as + // dependencies for deep watching + if (this.deep) { + traverse(value); } - return new vnodeComponentOptions.Ctor(options) -} + popTarget(); + this.cleanupDeps(); + return value +}; -function init ( - vnode, - hydrating, - parentElm, - refElm -) { - if (!vnode.componentInstance || vnode.componentInstance._isDestroyed) { - var child = vnode.componentInstance = createComponentInstanceForVnode( - vnode, - activeInstance, - parentElm, - refElm - ); - child.$mount(hydrating ? vnode.elm : undefined, hydrating); - } else if (vnode.data.keepAlive) { - // kept-alive components, treat as a patch - var mountedNode = vnode; // work around flow - prepatch(mountedNode, mountedNode); +/** + * Add a dependency to this directive. + */ +Watcher.prototype.addDep = function addDep (dep) { + var id = dep.id; + if (!this.newDepIds.has(id)) { + this.newDepIds.add(id); + this.newDeps.push(dep); + if (!this.depIds.has(id)) { + dep.addSub(this); + } } -} +}; -function prepatch ( - oldVnode, - vnode -) { - var options = vnode.componentOptions; - var child = vnode.componentInstance = oldVnode.componentInstance; - child._updateFromParent( - options.propsData, // updated props - options.listeners, // updated listeners - vnode, // new parent vnode - options.children // new children - ); -} +/** + * Clean up for dependency collection. + */ +Watcher.prototype.cleanupDeps = function cleanupDeps () { + var this$1 = this; -function insert (vnode) { - if (!vnode.componentInstance._isMounted) { - vnode.componentInstance._isMounted = true; - callHook(vnode.componentInstance, 'mounted'); - } - if (vnode.data.keepAlive) { - vnode.componentInstance._inactive = false; - callHook(vnode.componentInstance, 'activated'); + var i = this.deps.length; + while (i--) { + var dep = this$1.deps[i]; + if (!this$1.newDepIds.has(dep.id)) { + dep.removeSub(this$1); + } } -} - -function destroy$1 (vnode) { - if (!vnode.componentInstance._isDestroyed) { - if (!vnode.data.keepAlive) { - vnode.componentInstance.$destroy(); - } else { - vnode.componentInstance._inactive = true; - callHook(vnode.componentInstance, 'deactivated'); - } - } -} + var tmp = this.depIds; + this.depIds = this.newDepIds; + this.newDepIds = tmp; + this.newDepIds.clear(); + tmp = this.deps; + this.deps = this.newDeps; + this.newDeps = tmp; + this.newDeps.length = 0; +}; -function resolveAsyncComponent ( - factory, - baseCtor, - cb -) { - if (factory.requested) { - // pool callbacks - factory.pendingCallbacks.push(cb); +/** + * Subscriber interface. + * Will be called when a dependency changes. + */ +Watcher.prototype.update = function update () { + /* istanbul ignore else */ + if (this.lazy) { + this.dirty = true; + } else if (this.sync) { + this.run(); } else { - factory.requested = true; - var cbs = factory.pendingCallbacks = [cb]; - var sync = true; + queueWatcher(this); + } +}; - var resolve = function (res) { - if (isObject(res)) { - res = baseCtor.extend(res); - } - // cache resolved - factory.resolved = res; - // invoke callbacks only if this is not a synchronous resolve - // (async resolves are shimmed as synchronous during SSR) - if (!sync) { - for (var i = 0, l = cbs.length; i < l; i++) { - cbs[i](res); +/** + * Scheduler job interface. + * Will be called by the scheduler. + */ +Watcher.prototype.run = function run () { + if (this.active) { + var value = this.get(); + if ( + value !== this.value || + // Deep watchers and watchers on Object/Arrays should fire even + // when the value is the same, because the value may + // have mutated. + isObject(value) || + this.deep + ) { + // set new value + var oldValue = this.value; + this.value = value; + if (this.user) { + try { + this.cb.call(this.vm, value, oldValue); + } catch (e) { + /* istanbul ignore else */ + if (config.errorHandler) { + config.errorHandler.call(null, e, this.vm); + } else { + process.env.NODE_ENV !== 'production' && warn( + ("Error in watcher \"" + (this.expression) + "\""), + this.vm + ); + throw e + } } + } else { + this.cb.call(this.vm, value, oldValue); } - }; - - var reject = function (reason) { - process.env.NODE_ENV !== 'production' && warn( - "Failed to resolve async component: " + (String(factory)) + - (reason ? ("\nReason: " + reason) : '') - ); - }; + } + } +}; - var res = factory(resolve, reject); +/** + * Evaluate the value of the watcher. + * This only gets called for lazy watchers. + */ +Watcher.prototype.evaluate = function evaluate () { + this.value = this.get(); + this.dirty = false; +}; - // handle promise - if (res && typeof res.then === 'function' && !factory.resolved) { - res.then(resolve, reject); - } +/** + * Depend on all deps collected by this watcher. + */ +Watcher.prototype.depend = function depend () { + var this$1 = this; - sync = false; - // return in case resolved synchronously - return factory.resolved + var i = this.deps.length; + while (i--) { + this$1.deps[i].depend(); } -} +}; -function extractProps (data, Ctor) { - // we are only extracting raw values here. - // validation and default values are handled in the child - // component itself. - var propOptions = Ctor.options.props; - if (!propOptions) { - return - } - var res = {}; - var attrs = data.attrs; - var props = data.props; - var domProps = data.domProps; - if (attrs || props || domProps) { - for (var key in propOptions) { - var altKey = hyphenate(key); - checkProp(res, props, key, altKey, true) || - checkProp(res, attrs, key, altKey) || - checkProp(res, domProps, key, altKey); - } - } - return res -} +/** + * Remove self from all dependencies' subscriber list. + */ +Watcher.prototype.teardown = function teardown () { + var this$1 = this; -function checkProp ( - res, - hash, - key, - altKey, - preserve -) { - if (hash) { - if (hasOwn(hash, key)) { - res[key] = hash[key]; - if (!preserve) { - delete hash[key]; - } - return true - } else if (hasOwn(hash, altKey)) { - res[key] = hash[altKey]; - if (!preserve) { - delete hash[altKey]; - } - return true + if (this.active) { + // remove self from vm's watcher list + // this is a somewhat expensive operation so we skip it + // if the vm is being destroyed. + if (!this.vm._isBeingDestroyed) { + remove$1(this.vm._watchers, this); + } + var i = this.deps.length; + while (i--) { + this$1.deps[i].removeSub(this$1); } + this.active = false; } - return false -} +}; -function mergeHooks (data) { - if (!data.hook) { - data.hook = {}; - } - for (var i = 0; i < hooksToMerge.length; i++) { - var key = hooksToMerge[i]; - var fromParent = data.hook[key]; - var ours = hooks[key]; - data.hook[key] = fromParent ? mergeHook$1(ours, fromParent) : ours; - } +/** + * Recursively traverse an object to evoke all converted + * getters, so that every nested property inside the object + * is collected as a "deep" dependency. + */ +var seenObjects = new _Set(); +function traverse (val) { + seenObjects.clear(); + _traverse(val, seenObjects); } -function mergeHook$1 (one, two) { - return function (a, b, c, d) { - one(a, b, c, d); - two(a, b, c, d); +function _traverse (val, seen) { + var i, keys; + var isA = Array.isArray(val); + if ((!isA && !isObject(val)) || !Object.isExtensible(val)) { + return } -} - -/* */ - -function mergeVNodeHook (def, hookKey, hook, key) { - key = key + hookKey; - var injectedHash = def.__injected || (def.__injected = {}); - if (!injectedHash[key]) { - injectedHash[key] = true; - var oldHook = def[hookKey]; - if (oldHook) { - def[hookKey] = function () { - oldHook.apply(this, arguments); - hook.apply(this, arguments); - }; - } else { - def[hookKey] = hook; + if (val.__ob__) { + var depId = val.__ob__.dep.id; + if (seen.has(depId)) { + return } + seen.add(depId); + } + if (isA) { + i = val.length; + while (i--) { _traverse(val[i], seen); } + } else { + keys = Object.keys(val); + i = keys.length; + while (i--) { _traverse(val[keys[i]], seen); } } } /* */ -var normalizeEvent = cached(function (name) { - var once = name.charAt(0) === '~'; // Prefixed last, checked first - name = once ? name.slice(1) : name; - var capture = name.charAt(0) === '!'; - name = capture ? name.slice(1) : name; - return { - name: name, - once: once, - capture: capture +function initState (vm) { + vm._watchers = []; + var opts = vm.$options; + if (opts.props) { initProps(vm, opts.props); } + if (opts.methods) { initMethods(vm, opts.methods); } + if (opts.data) { + initData(vm); + } else { + observe(vm._data = {}, true /* asRootData */); } -}); + if (opts.computed) { initComputed(vm, opts.computed); } + if (opts.watch) { initWatch(vm, opts.watch); } +} -function createEventHandle (fn) { - var handle = { - fn: fn, - invoker: function () { - var arguments$1 = arguments; +var isReservedProp = { key: 1, ref: 1, slot: 1 }; - var fn = handle.fn; - if (Array.isArray(fn)) { - for (var i = 0; i < fn.length; i++) { - fn[i].apply(null, arguments$1); - } - } else { - fn.apply(null, arguments); +function initProps (vm, props) { + var propsData = vm.$options.propsData || {}; + var keys = vm.$options._propKeys = Object.keys(props); + var isRoot = !vm.$parent; + // root instance props should be converted + observerState.shouldConvert = isRoot; + var loop = function ( i ) { + var key = keys[i]; + /* istanbul ignore else */ + if (process.env.NODE_ENV !== 'production') { + if (isReservedProp[key]) { + warn( + ("\"" + key + "\" is a reserved attribute and cannot be used as component prop."), + vm + ); } + defineReactive$$1(vm, key, validateProp(key, props, propsData, vm), function () { + if (vm.$parent && !observerState.isSettingProps) { + warn( + "Avoid mutating a prop directly since the value will be " + + "overwritten whenever the parent component re-renders. " + + "Instead, use a data or computed property based on the prop's " + + "value. Prop being mutated: \"" + key + "\"", + vm + ); + } + }); + } else { + defineReactive$$1(vm, key, validateProp(key, props, propsData, vm)); } }; - return handle + + for (var i = 0; i < keys.length; i++) loop( i ); + observerState.shouldConvert = true; } -function updateListeners ( - on, - oldOn, - add, - remove$$1, - vm -) { - var name, cur, old, event; - for (name in on) { - cur = on[name]; - old = oldOn[name]; - event = normalizeEvent(name); - if (!cur) { +function initData (vm) { + var data = vm.$options.data; + data = vm._data = typeof data === 'function' + ? data.call(vm) + : data || {}; + if (!isPlainObject(data)) { + data = {}; + process.env.NODE_ENV !== 'production' && warn( + 'data functions should return an object:\n' + + 'https://vuejs.org/v2/guide/components.html#data-Must-Be-a-Function', + vm + ); + } + // proxy data on instance + var keys = Object.keys(data); + var props = vm.$options.props; + var i = keys.length; + while (i--) { + if (props && hasOwn(props, keys[i])) { process.env.NODE_ENV !== 'production' && warn( - "Invalid handler for event \"" + (event.name) + "\": got " + String(cur), + "The data property \"" + (keys[i]) + "\" is already declared as a prop. " + + "Use prop default value instead.", vm ); - } else if (!old) { - if (!cur.invoker) { - cur = on[name] = createEventHandle(cur); - } - add(event.name, cur.invoker, event.once, event.capture); - } else if (cur !== old) { - old.fn = cur; - on[name] = old; - } - } - for (name in oldOn) { - if (!on[name]) { - event = normalizeEvent(name); - remove$$1(event.name, oldOn[name].invoker, event.capture); + } else { + proxy(vm, keys[i]); } } + // observe data + observe(data, true /* asRootData */); } -/* */ +var computedSharedDefinition = { + enumerable: true, + configurable: true, + get: noop, + set: noop +}; -// The template compiler attempts to minimize the need for normalization by -// statically analyzing the template at compile time. -// -// For plain HTML markup, normalization can be completely skipped because the -// generated render function is guaranteed to return Array. There are -// two cases where extra normalization is needed: +function initComputed (vm, computed) { + for (var key in computed) { + /* istanbul ignore if */ + if (process.env.NODE_ENV !== 'production' && key in vm) { + warn( + "existing instance property \"" + key + "\" will be " + + "overwritten by a computed property with the same name.", + vm + ); + } + var userDef = computed[key]; + if (typeof userDef === 'function') { + computedSharedDefinition.get = makeComputedGetter(userDef, vm); + computedSharedDefinition.set = noop; + } else { + computedSharedDefinition.get = userDef.get + ? userDef.cache !== false + ? makeComputedGetter(userDef.get, vm) + : bind$1(userDef.get, vm) + : noop; + computedSharedDefinition.set = userDef.set + ? bind$1(userDef.set, vm) + : noop; + } + Object.defineProperty(vm, key, computedSharedDefinition); + } +} -// 1. When the children contains components - because a functional component -// may return an Array instead of a single root. In this case, just a simple -// nomralization is needed - if any child is an Array, we flatten the whole -// thing with Array.prototype.concat. It is guaranteed to be only 1-level deep -// because functional components already normalize their own children. -function simpleNormalizeChildren (children) { - for (var i = 0; i < children.length; i++) { - if (Array.isArray(children[i])) { - return Array.prototype.concat.apply([], children) +function makeComputedGetter (getter, owner) { + var watcher = new Watcher(owner, getter, noop, { + lazy: true + }); + return function computedGetter () { + if (watcher.dirty) { + watcher.evaluate(); + } + if (Dep.target) { + watcher.depend(); } + return watcher.value } - return children } -// 2. When the children contains constrcuts that always generated nested Arrays, -// e.g.