diff --git a/README.md b/README.md index 486c654..92ae1f7 100644 --- a/README.md +++ b/README.md @@ -84,6 +84,7 @@ When an image is uploaded successfully, a 200 HTTP Status code response must be | `save-request-headers` | Object | `{}` | (OPTIONAL) If you need to pass any additional HTTP headers, you may do so by providing the header names and values in this object | | `allow-photo-pane` | Boolean | false | (OPTIONAL) When this attribute is true, clicking on an image in the gallery will show a larger version of the image in a Photo pane, along with any additional image information. | | `allow-delete` | Boolean | false | (OPTIONAL) Whether or not to provide a provision for deleting an image in Photo Pane view. If this is true, delete button will be shown and a `deleted` event will be generated | +| `allow-rename` | Boolean | false | (OPTIONAL) Whether or not to provide a provision for renaming an image in Photo Pane view. If this is true, rename input with button will be shown and a `renamed` event will be generated | | `allow-choose` | Boolean | false | (OPTIONAL) Whether or not to provide a provision for chosing the image inside Photo Pane view. If this is true, a "Choose" button will be displayed and a `chosen` event will be generated | | `allow-copy` | Boolean | true | (OPTIONAL) Whether or not to provide a provision for copying the image URL in the Photo Pane View. If this is true, a `Copy Link` button will be shown and image `url` will be copied to clipboard | | `captionable` | Boolean | false | (OPTIONAL) Whether or not to provide a provision for specifying the image caption after selecting an image. If this is true, a prompt will be shown for image caption when users select an image | @@ -103,7 +104,7 @@ Following events are generated when performing various interactions with the ima | `chosen` | Object | image | This event is generated when users select an image. The image is passed to the event handler. | | `saved` | Object | image | This event is generated when users successfully upload an image. The image is passed to the event handler. | | `deleted` | Object | image | This event is generated when users delete an image. The image is passed to the event handler. | - +| `renamed` | Object, String | image, new name | This event is generated when users rename an image. The image and the new name are passed to the event handler. | ## Example @@ -125,6 +126,7 @@ Following events are generated when performing various interactions with the ima @chosen="onChoose" @saved="onSave" @deleted="onDelete" + @renamed="onRename" @searched="onSearch" > @@ -174,6 +176,11 @@ export default { } }, + onRename(image, newName) { + console.log('on rename : image -> ', image) + console.log('on rename : new name -> ', newName) + }, + onSelect(image) { console.log('on select', image) }, diff --git a/dist/vue-image-browser.esm.js b/dist/vue-image-browser.esm.js index 465f07e..0dbeed2 100644 --- a/dist/vue-image-browser.esm.js +++ b/dist/vue-image-browser.esm.js @@ -227,6 +227,27 @@ // // // +// +// +// +// +// +// +// +// +// +// +// +// +// +// +// +// +// +// +// +// +// var script = { name: 'vue-image-browser', @@ -266,6 +287,11 @@ var script = { default: false, }, + allowRename: { + type: Boolean, + default: false, + }, + allowPhotoPane: { type: Boolean, default: false, @@ -301,6 +327,7 @@ var script = { return { message: null, query: '', + renameQuery: '', searchResult: null, pane: 'gallery', selectedPhoto: {}, @@ -337,12 +364,18 @@ var script = { 'w-full w-1/' + xs + ' md:w-1/' + md + ' lg:w-1/' + lg + ' xl:w-1/' + xl ) }, + + isRenameDisabled: function isRenameDisabled() { + return this.selectedPhoto.name === this.renameQuery + }, }, methods: { select: function select(photo) { this.selectedPhoto = photo; + this.renameQuery = photo.name; + this.allowPhotoPane && (this.pane = 'photo'); this.captionable && (this.selectedPhoto['caption'] = this.getCaption()); @@ -456,6 +489,13 @@ var script = { this.pane = 'gallery'; }, + renameSelected: function renameSelected() { + if (this.renameQuery.length <= 0) + { return; } + + this.$emit('renamed', this.selectedPhoto, this.renameQuery); + }, + doDelayedSearch: function doDelayedSearch() { var p = this; @@ -512,132 +552,132 @@ var script = { }, }; -function normalizeComponent(template, style, script, scopeId, isFunctionalTemplate, moduleIdentifier /* server only */, shadowMode, createInjector, createInjectorSSR, createInjectorShadow) { - if (typeof shadowMode !== 'boolean') { - createInjectorSSR = createInjector; - createInjector = shadowMode; - shadowMode = false; - } - // Vue.extend constructor export interop. - var options = typeof script === 'function' ? script.options : script; - // render functions - if (template && template.render) { - options.render = template.render; - options.staticRenderFns = template.staticRenderFns; - options._compiled = true; - // functional template - if (isFunctionalTemplate) { - options.functional = true; - } - } - // scopedId - if (scopeId) { - options._scopeId = scopeId; - } - var hook; - if (moduleIdentifier) { - // server build - hook = function (context) { - // 2.3 injection - context = - context || // cached call - (this.$vnode && this.$vnode.ssrContext) || // stateful - (this.parent && this.parent.$vnode && this.parent.$vnode.ssrContext); // functional - // 2.2 with runInNewContext: true - if (!context && typeof __VUE_SSR_CONTEXT__ !== 'undefined') { - context = __VUE_SSR_CONTEXT__; - } - // inject component styles - if (style) { - style.call(this, createInjectorSSR(context)); - } - // register component module identifier for async chunk inference - if (context && context._registeredComponents) { - context._registeredComponents.add(moduleIdentifier); - } - }; - // used by ssr in case component is cached and beforeCreate - // never gets called - options._ssrRegister = hook; - } - else if (style) { - hook = shadowMode - ? function (context) { - style.call(this, createInjectorShadow(context, this.$root.$options.shadowRoot)); - } - : function (context) { - style.call(this, createInjector(context)); - }; - } - if (hook) { - if (options.functional) { - // register for functional component in vue file - var originalRender = options.render; - options.render = function renderWithStyleInjection(h, context) { - hook.call(context); - return originalRender(h, context); - }; - } - else { - // inject component registration as beforeCreate hook - var existing = options.beforeCreate; - options.beforeCreate = existing ? [].concat(existing, hook) : [hook]; - } - } - return script; +function normalizeComponent(template, style, script, scopeId, isFunctionalTemplate, moduleIdentifier /* server only */, shadowMode, createInjector, createInjectorSSR, createInjectorShadow) { + if (typeof shadowMode !== 'boolean') { + createInjectorSSR = createInjector; + createInjector = shadowMode; + shadowMode = false; + } + // Vue.extend constructor export interop. + var options = typeof script === 'function' ? script.options : script; + // render functions + if (template && template.render) { + options.render = template.render; + options.staticRenderFns = template.staticRenderFns; + options._compiled = true; + // functional template + if (isFunctionalTemplate) { + options.functional = true; + } + } + // scopedId + if (scopeId) { + options._scopeId = scopeId; + } + var hook; + if (moduleIdentifier) { + // server build + hook = function (context) { + // 2.3 injection + context = + context || // cached call + (this.$vnode && this.$vnode.ssrContext) || // stateful + (this.parent && this.parent.$vnode && this.parent.$vnode.ssrContext); // functional + // 2.2 with runInNewContext: true + if (!context && typeof __VUE_SSR_CONTEXT__ !== 'undefined') { + context = __VUE_SSR_CONTEXT__; + } + // inject component styles + if (style) { + style.call(this, createInjectorSSR(context)); + } + // register component module identifier for async chunk inference + if (context && context._registeredComponents) { + context._registeredComponents.add(moduleIdentifier); + } + }; + // used by ssr in case component is cached and beforeCreate + // never gets called + options._ssrRegister = hook; + } + else if (style) { + hook = shadowMode + ? function (context) { + style.call(this, createInjectorShadow(context, this.$root.$options.shadowRoot)); + } + : function (context) { + style.call(this, createInjector(context)); + }; + } + if (hook) { + if (options.functional) { + // register for functional component in vue file + var originalRender = options.render; + options.render = function renderWithStyleInjection(h, context) { + hook.call(context); + return originalRender(h, context); + }; + } + else { + // inject component registration as beforeCreate hook + var existing = options.beforeCreate; + options.beforeCreate = existing ? [].concat(existing, hook) : [hook]; + } + } + return script; } -var isOldIE = typeof navigator !== 'undefined' && - /msie [6-9]\\b/.test(navigator.userAgent.toLowerCase()); -function createInjector(context) { - return function (id, style) { return addStyle(id, style); }; -} -var HEAD; -var styles = {}; -function addStyle(id, css) { - var group = isOldIE ? css.media || 'default' : id; - var style = styles[group] || (styles[group] = { ids: new Set(), styles: [] }); - if (!style.ids.has(id)) { - style.ids.add(id); - var code = css.source; - if (css.map) { - // https://developer.chrome.com/devtools/docs/javascript-debugging - // this makes source maps inside style tags work properly in Chrome - code += '\n/*# sourceURL=' + css.map.sources[0] + ' */'; - // http://stackoverflow.com/a/26603875 - code += - '\n/*# sourceMappingURL=data:application/json;base64,' + - btoa(unescape(encodeURIComponent(JSON.stringify(css.map)))) + - ' */'; - } - if (!style.element) { - style.element = document.createElement('style'); - style.element.type = 'text/css'; - if (css.media) - { style.element.setAttribute('media', css.media); } - if (HEAD === undefined) { - HEAD = document.head || document.getElementsByTagName('head')[0]; - } - HEAD.appendChild(style.element); - } - if ('styleSheet' in style.element) { - style.styles.push(code); - style.element.styleSheet.cssText = style.styles - .filter(Boolean) - .join('\n'); - } - else { - var index = style.ids.size - 1; - var textNode = document.createTextNode(code); - var nodes = style.element.childNodes; - if (nodes[index]) - { style.element.removeChild(nodes[index]); } - if (nodes.length) - { style.element.insertBefore(textNode, nodes[index]); } - else - { style.element.appendChild(textNode); } - } - } +var isOldIE = typeof navigator !== 'undefined' && + /msie [6-9]\\b/.test(navigator.userAgent.toLowerCase()); +function createInjector(context) { + return function (id, style) { return addStyle(id, style); }; +} +var HEAD; +var styles = {}; +function addStyle(id, css) { + var group = isOldIE ? css.media || 'default' : id; + var style = styles[group] || (styles[group] = { ids: new Set(), styles: [] }); + if (!style.ids.has(id)) { + style.ids.add(id); + var code = css.source; + if (css.map) { + // https://developer.chrome.com/devtools/docs/javascript-debugging + // this makes source maps inside style tags work properly in Chrome + code += '\n/*# sourceURL=' + css.map.sources[0] + ' */'; + // http://stackoverflow.com/a/26603875 + code += + '\n/*# sourceMappingURL=data:application/json;base64,' + + btoa(unescape(encodeURIComponent(JSON.stringify(css.map)))) + + ' */'; + } + if (!style.element) { + style.element = document.createElement('style'); + style.element.type = 'text/css'; + if (css.media) + { style.element.setAttribute('media', css.media); } + if (HEAD === undefined) { + HEAD = document.head || document.getElementsByTagName('head')[0]; + } + HEAD.appendChild(style.element); + } + if ('styleSheet' in style.element) { + style.styles.push(code); + style.element.styleSheet.cssText = style.styles + .filter(Boolean) + .join('\n'); + } + else { + var index = style.ids.size - 1; + var textNode = document.createTextNode(code); + var nodes = style.element.childNodes; + if (nodes[index]) + { style.element.removeChild(nodes[index]); } + if (nodes.length) + { style.element.insertBefore(textNode, nodes[index]); } + else + { style.element.appendChild(textNode); } + } + } } /* script */ @@ -921,21 +961,79 @@ var __vue_render__ = function() { 0 ), _vm._v(" "), - _vm.allowDelete - ? _c( - "button", - { - staticClass: - "text-red-500 border m-4 mt-6 px-4 text-sm py-1 hover:border border-red-500 hover:text-white hover:bg-red-500 rounded cursor-pointer", - on: { - click: function($event) { - return _vm.deleteSelected() - } - } - }, - [_vm._v("\n Delete\n ")] - ) - : _vm._e() + _c( + "div", + { + staticClass: + "w-full mx-auto py-4 bg-transparent my-4 flex items-center flex-no-wrap" + }, + [ + _c("div", { staticClass: "flex-none px-3" }, [ + _vm.allowDelete + ? _c( + "button", + { + staticClass: + "text-red-500 border px-4 text-sm py-2 hover:border border-red-500 hover:text-white hover:bg-red-500 rounded cursor-pointer", + on: { + click: function($event) { + return _vm.deleteSelected() + } + } + }, + [_vm._v("\n Delete\n ")] + ) + : _vm._e() + ]), + _vm._v(" "), + _vm.allowRename + ? _c("div", { staticClass: "flex-grow flex px-3" }, [ + _c("input", { + directives: [ + { + name: "model", + rawName: "v-model", + value: _vm.renameQuery, + expression: "renameQuery" + } + ], + staticClass: + "p-2 w-full rounded-l-lg rounded-r-lg sm:rounded-r-none border sm:border-r-0 border-gray-300 bg-white outline-none", + attrs: { type: "text" }, + domProps: { value: _vm.renameQuery }, + on: { + input: function($event) { + if ($event.target.composing) { + return + } + _vm.renameQuery = $event.target.value; + } + } + }), + _vm._v(" "), + _c("div", { staticClass: "flex relative" }, [ + _c( + "button", + { + staticClass: + "text-blue-500 px-4 text-sm py-1 hover:border hover:border-blue-500 hover:text-white hover:bg-blue-500 rounded-r-lg border-r border-t border-b border-gray-300 cursor-pointer", + class: _vm.isRenameDisabled + ? "opacity-50 cursor-not-allowed" + : "", + attrs: { disabled: _vm.isRenameDisabled }, + on: { + click: function($event) { + return _vm.renameSelected() + } + } + }, + [_vm._v("\n Rename\n ")] + ) + ]) + ]) + : _vm._e() + ] + ) ]) ]) : _vm._e(), @@ -1147,7 +1245,7 @@ __vue_render__._withStripped = true; /* style */ var __vue_inject_styles__ = function (inject) { if (!inject) { return } - inject("data-v-5b2da7ca_0", { source: "\n@media only screen and (min-width: 640px) {\n.thumbnail {\n height: 300px;\n overflow: hidden;\n}\n}\n@media only screen and (min-width: 768px) {\n.thumbnail {\n height: 250px;\n overflow: hidden;\n}\n}\n@media only screen and (min-width: 1024px) {\n.thumbnail {\n height: 200px;\n overflow: hidden;\n}\n}\n@media only screen and (min-width: 1280px) {\n.thumbnail {\n height: 120px;\n overflow: hidden;\n}\n}\n.mg-photo {\n width: 100%;\n height: 100%;\n object-fit: cover;\n}\n", map: {"version":3,"sources":["/Users/akash/code/vue-image-browser/src/vue-image-browser.vue"],"names":[],"mappings":";AAggBA;AACA;IACA,aAAA;IACA,gBAAA;AACA;AACA;AACA;AACA;IACA,aAAA;IACA,gBAAA;AACA;AACA;AACA;AACA;IACA,aAAA;IACA,gBAAA;AACA;AACA;AACA;AACA;IACA,aAAA;IACA,gBAAA;AACA;AACA;AAEA;EACA,WAAA;EACA,YAAA;EACA,iBAAA;AACA","file":"vue-image-browser.vue","sourcesContent":["\n\n\n\n\n"]}, media: undefined }); + inject("data-v-962f8ec2_0", { source: "\n@media only screen and (min-width: 640px) {\n.thumbnail {\r\n height: 300px;\r\n overflow: hidden;\n}\n}\n@media only screen and (min-width: 768px) {\n.thumbnail {\r\n height: 250px;\r\n overflow: hidden;\n}\n}\n@media only screen and (min-width: 1024px) {\n.thumbnail {\r\n height: 200px;\r\n overflow: hidden;\n}\n}\n@media only screen and (min-width: 1280px) {\n.thumbnail {\r\n height: 120px;\r\n overflow: hidden;\n}\n}\n.mg-photo {\r\n width: 100%;\r\n height: 100%;\r\n object-fit: cover;\n}\r\n", map: {"version":3,"sources":["C:\\laragon\\www\\vue-image-browser\\src\\vue-image-browser.vue"],"names":[],"mappings":";AAwiBA;AACA;IACA,aAAA;IACA,gBAAA;AACA;AACA;AACA;AACA;IACA,aAAA;IACA,gBAAA;AACA;AACA;AACA;AACA;IACA,aAAA;IACA,gBAAA;AACA;AACA;AACA;AACA;IACA,aAAA;IACA,gBAAA;AACA;AACA;AAEA;EACA,WAAA;EACA,YAAA;EACA,iBAAA;AACA","file":"vue-image-browser.vue","sourcesContent":["\r\n\r\n\r\n\r\n\r\n"]}, media: undefined }); }; /* scoped */ diff --git a/dist/vue-image-browser.min.js b/dist/vue-image-browser.min.js index f4e39e2..493384a 100644 --- a/dist/vue-image-browser.min.js +++ b/dist/vue-image-browser.min.js @@ -230,6 +230,27 @@ var VueImageBrowser = (function (exports) { // // // + // + // + // + // + // + // + // + // + // + // + // + // + // + // + // + // + // + // + // + // + // var script = { name: 'vue-image-browser', @@ -269,6 +290,11 @@ var VueImageBrowser = (function (exports) { default: false, }, + allowRename: { + type: Boolean, + default: false, + }, + allowPhotoPane: { type: Boolean, default: false, @@ -304,6 +330,7 @@ var VueImageBrowser = (function (exports) { return { message: null, query: '', + renameQuery: '', searchResult: null, pane: 'gallery', selectedPhoto: {}, @@ -340,12 +367,18 @@ var VueImageBrowser = (function (exports) { 'w-full w-1/' + xs + ' md:w-1/' + md + ' lg:w-1/' + lg + ' xl:w-1/' + xl ) }, + + isRenameDisabled: function isRenameDisabled() { + return this.selectedPhoto.name === this.renameQuery + }, }, methods: { select: function select(photo) { this.selectedPhoto = photo; + this.renameQuery = photo.name; + this.allowPhotoPane && (this.pane = 'photo'); this.captionable && (this.selectedPhoto['caption'] = this.getCaption()); @@ -459,6 +492,13 @@ var VueImageBrowser = (function (exports) { this.pane = 'gallery'; }, + renameSelected: function renameSelected() { + if (this.renameQuery.length <= 0) + { return; } + + this.$emit('renamed', this.selectedPhoto, this.renameQuery); + }, + doDelayedSearch: function doDelayedSearch() { var p = this; @@ -515,132 +555,132 @@ var VueImageBrowser = (function (exports) { }, }; - function normalizeComponent(template, style, script, scopeId, isFunctionalTemplate, moduleIdentifier /* server only */, shadowMode, createInjector, createInjectorSSR, createInjectorShadow) { - if (typeof shadowMode !== 'boolean') { - createInjectorSSR = createInjector; - createInjector = shadowMode; - shadowMode = false; - } - // Vue.extend constructor export interop. - var options = typeof script === 'function' ? script.options : script; - // render functions - if (template && template.render) { - options.render = template.render; - options.staticRenderFns = template.staticRenderFns; - options._compiled = true; - // functional template - if (isFunctionalTemplate) { - options.functional = true; - } - } - // scopedId - if (scopeId) { - options._scopeId = scopeId; - } - var hook; - if (moduleIdentifier) { - // server build - hook = function (context) { - // 2.3 injection - context = - context || // cached call - (this.$vnode && this.$vnode.ssrContext) || // stateful - (this.parent && this.parent.$vnode && this.parent.$vnode.ssrContext); // functional - // 2.2 with runInNewContext: true - if (!context && typeof __VUE_SSR_CONTEXT__ !== 'undefined') { - context = __VUE_SSR_CONTEXT__; - } - // inject component styles - if (style) { - style.call(this, createInjectorSSR(context)); - } - // register component module identifier for async chunk inference - if (context && context._registeredComponents) { - context._registeredComponents.add(moduleIdentifier); - } - }; - // used by ssr in case component is cached and beforeCreate - // never gets called - options._ssrRegister = hook; - } - else if (style) { - hook = shadowMode - ? function (context) { - style.call(this, createInjectorShadow(context, this.$root.$options.shadowRoot)); - } - : function (context) { - style.call(this, createInjector(context)); - }; - } - if (hook) { - if (options.functional) { - // register for functional component in vue file - var originalRender = options.render; - options.render = function renderWithStyleInjection(h, context) { - hook.call(context); - return originalRender(h, context); - }; - } - else { - // inject component registration as beforeCreate hook - var existing = options.beforeCreate; - options.beforeCreate = existing ? [].concat(existing, hook) : [hook]; - } - } - return script; + function normalizeComponent(template, style, script, scopeId, isFunctionalTemplate, moduleIdentifier /* server only */, shadowMode, createInjector, createInjectorSSR, createInjectorShadow) { + if (typeof shadowMode !== 'boolean') { + createInjectorSSR = createInjector; + createInjector = shadowMode; + shadowMode = false; + } + // Vue.extend constructor export interop. + var options = typeof script === 'function' ? script.options : script; + // render functions + if (template && template.render) { + options.render = template.render; + options.staticRenderFns = template.staticRenderFns; + options._compiled = true; + // functional template + if (isFunctionalTemplate) { + options.functional = true; + } + } + // scopedId + if (scopeId) { + options._scopeId = scopeId; + } + var hook; + if (moduleIdentifier) { + // server build + hook = function (context) { + // 2.3 injection + context = + context || // cached call + (this.$vnode && this.$vnode.ssrContext) || // stateful + (this.parent && this.parent.$vnode && this.parent.$vnode.ssrContext); // functional + // 2.2 with runInNewContext: true + if (!context && typeof __VUE_SSR_CONTEXT__ !== 'undefined') { + context = __VUE_SSR_CONTEXT__; + } + // inject component styles + if (style) { + style.call(this, createInjectorSSR(context)); + } + // register component module identifier for async chunk inference + if (context && context._registeredComponents) { + context._registeredComponents.add(moduleIdentifier); + } + }; + // used by ssr in case component is cached and beforeCreate + // never gets called + options._ssrRegister = hook; + } + else if (style) { + hook = shadowMode + ? function (context) { + style.call(this, createInjectorShadow(context, this.$root.$options.shadowRoot)); + } + : function (context) { + style.call(this, createInjector(context)); + }; + } + if (hook) { + if (options.functional) { + // register for functional component in vue file + var originalRender = options.render; + options.render = function renderWithStyleInjection(h, context) { + hook.call(context); + return originalRender(h, context); + }; + } + else { + // inject component registration as beforeCreate hook + var existing = options.beforeCreate; + options.beforeCreate = existing ? [].concat(existing, hook) : [hook]; + } + } + return script; } - var isOldIE = typeof navigator !== 'undefined' && - /msie [6-9]\\b/.test(navigator.userAgent.toLowerCase()); - function createInjector(context) { - return function (id, style) { return addStyle(id, style); }; - } - var HEAD; - var styles = {}; - function addStyle(id, css) { - var group = isOldIE ? css.media || 'default' : id; - var style = styles[group] || (styles[group] = { ids: new Set(), styles: [] }); - if (!style.ids.has(id)) { - style.ids.add(id); - var code = css.source; - if (css.map) { - // https://developer.chrome.com/devtools/docs/javascript-debugging - // this makes source maps inside style tags work properly in Chrome - code += '\n/*# sourceURL=' + css.map.sources[0] + ' */'; - // http://stackoverflow.com/a/26603875 - code += - '\n/*# sourceMappingURL=data:application/json;base64,' + - btoa(unescape(encodeURIComponent(JSON.stringify(css.map)))) + - ' */'; - } - if (!style.element) { - style.element = document.createElement('style'); - style.element.type = 'text/css'; - if (css.media) - { style.element.setAttribute('media', css.media); } - if (HEAD === undefined) { - HEAD = document.head || document.getElementsByTagName('head')[0]; - } - HEAD.appendChild(style.element); - } - if ('styleSheet' in style.element) { - style.styles.push(code); - style.element.styleSheet.cssText = style.styles - .filter(Boolean) - .join('\n'); - } - else { - var index = style.ids.size - 1; - var textNode = document.createTextNode(code); - var nodes = style.element.childNodes; - if (nodes[index]) - { style.element.removeChild(nodes[index]); } - if (nodes.length) - { style.element.insertBefore(textNode, nodes[index]); } - else - { style.element.appendChild(textNode); } - } - } + var isOldIE = typeof navigator !== 'undefined' && + /msie [6-9]\\b/.test(navigator.userAgent.toLowerCase()); + function createInjector(context) { + return function (id, style) { return addStyle(id, style); }; + } + var HEAD; + var styles = {}; + function addStyle(id, css) { + var group = isOldIE ? css.media || 'default' : id; + var style = styles[group] || (styles[group] = { ids: new Set(), styles: [] }); + if (!style.ids.has(id)) { + style.ids.add(id); + var code = css.source; + if (css.map) { + // https://developer.chrome.com/devtools/docs/javascript-debugging + // this makes source maps inside style tags work properly in Chrome + code += '\n/*# sourceURL=' + css.map.sources[0] + ' */'; + // http://stackoverflow.com/a/26603875 + code += + '\n/*# sourceMappingURL=data:application/json;base64,' + + btoa(unescape(encodeURIComponent(JSON.stringify(css.map)))) + + ' */'; + } + if (!style.element) { + style.element = document.createElement('style'); + style.element.type = 'text/css'; + if (css.media) + { style.element.setAttribute('media', css.media); } + if (HEAD === undefined) { + HEAD = document.head || document.getElementsByTagName('head')[0]; + } + HEAD.appendChild(style.element); + } + if ('styleSheet' in style.element) { + style.styles.push(code); + style.element.styleSheet.cssText = style.styles + .filter(Boolean) + .join('\n'); + } + else { + var index = style.ids.size - 1; + var textNode = document.createTextNode(code); + var nodes = style.element.childNodes; + if (nodes[index]) + { style.element.removeChild(nodes[index]); } + if (nodes.length) + { style.element.insertBefore(textNode, nodes[index]); } + else + { style.element.appendChild(textNode); } + } + } } /* script */ @@ -924,21 +964,79 @@ var VueImageBrowser = (function (exports) { 0 ), _vm._v(" "), - _vm.allowDelete - ? _c( - "button", - { - staticClass: - "text-red-500 border m-4 mt-6 px-4 text-sm py-1 hover:border border-red-500 hover:text-white hover:bg-red-500 rounded cursor-pointer", - on: { - click: function($event) { - return _vm.deleteSelected() - } - } - }, - [_vm._v("\n Delete\n ")] - ) - : _vm._e() + _c( + "div", + { + staticClass: + "w-full mx-auto py-4 bg-transparent my-4 flex items-center flex-no-wrap" + }, + [ + _c("div", { staticClass: "flex-none px-3" }, [ + _vm.allowDelete + ? _c( + "button", + { + staticClass: + "text-red-500 border px-4 text-sm py-2 hover:border border-red-500 hover:text-white hover:bg-red-500 rounded cursor-pointer", + on: { + click: function($event) { + return _vm.deleteSelected() + } + } + }, + [_vm._v("\n Delete\n ")] + ) + : _vm._e() + ]), + _vm._v(" "), + _vm.allowRename + ? _c("div", { staticClass: "flex-grow flex px-3" }, [ + _c("input", { + directives: [ + { + name: "model", + rawName: "v-model", + value: _vm.renameQuery, + expression: "renameQuery" + } + ], + staticClass: + "p-2 w-full rounded-l-lg rounded-r-lg sm:rounded-r-none border sm:border-r-0 border-gray-300 bg-white outline-none", + attrs: { type: "text" }, + domProps: { value: _vm.renameQuery }, + on: { + input: function($event) { + if ($event.target.composing) { + return + } + _vm.renameQuery = $event.target.value; + } + } + }), + _vm._v(" "), + _c("div", { staticClass: "flex relative" }, [ + _c( + "button", + { + staticClass: + "text-blue-500 px-4 text-sm py-1 hover:border hover:border-blue-500 hover:text-white hover:bg-blue-500 rounded-r-lg border-r border-t border-b border-gray-300 cursor-pointer", + class: _vm.isRenameDisabled + ? "opacity-50 cursor-not-allowed" + : "", + attrs: { disabled: _vm.isRenameDisabled }, + on: { + click: function($event) { + return _vm.renameSelected() + } + } + }, + [_vm._v("\n Rename\n ")] + ) + ]) + ]) + : _vm._e() + ] + ) ]) ]) : _vm._e(), @@ -1150,7 +1248,7 @@ var VueImageBrowser = (function (exports) { /* style */ var __vue_inject_styles__ = function (inject) { if (!inject) { return } - inject("data-v-5b2da7ca_0", { source: "\n@media only screen and (min-width: 640px) {\n.thumbnail {\n height: 300px;\n overflow: hidden;\n}\n}\n@media only screen and (min-width: 768px) {\n.thumbnail {\n height: 250px;\n overflow: hidden;\n}\n}\n@media only screen and (min-width: 1024px) {\n.thumbnail {\n height: 200px;\n overflow: hidden;\n}\n}\n@media only screen and (min-width: 1280px) {\n.thumbnail {\n height: 120px;\n overflow: hidden;\n}\n}\n.mg-photo {\n width: 100%;\n height: 100%;\n object-fit: cover;\n}\n", map: {"version":3,"sources":["/Users/akash/code/vue-image-browser/src/vue-image-browser.vue"],"names":[],"mappings":";AAggBA;AACA;IACA,aAAA;IACA,gBAAA;AACA;AACA;AACA;AACA;IACA,aAAA;IACA,gBAAA;AACA;AACA;AACA;AACA;IACA,aAAA;IACA,gBAAA;AACA;AACA;AACA;AACA;IACA,aAAA;IACA,gBAAA;AACA;AACA;AAEA;EACA,WAAA;EACA,YAAA;EACA,iBAAA;AACA","file":"vue-image-browser.vue","sourcesContent":["\n\n\n\n\n"]}, media: undefined }); + inject("data-v-962f8ec2_0", { source: "\n@media only screen and (min-width: 640px) {\n.thumbnail {\r\n height: 300px;\r\n overflow: hidden;\n}\n}\n@media only screen and (min-width: 768px) {\n.thumbnail {\r\n height: 250px;\r\n overflow: hidden;\n}\n}\n@media only screen and (min-width: 1024px) {\n.thumbnail {\r\n height: 200px;\r\n overflow: hidden;\n}\n}\n@media only screen and (min-width: 1280px) {\n.thumbnail {\r\n height: 120px;\r\n overflow: hidden;\n}\n}\n.mg-photo {\r\n width: 100%;\r\n height: 100%;\r\n object-fit: cover;\n}\r\n", map: {"version":3,"sources":["C:\\laragon\\www\\vue-image-browser\\src\\vue-image-browser.vue"],"names":[],"mappings":";AAwiBA;AACA;IACA,aAAA;IACA,gBAAA;AACA;AACA;AACA;AACA;IACA,aAAA;IACA,gBAAA;AACA;AACA;AACA;AACA;IACA,aAAA;IACA,gBAAA;AACA;AACA;AACA;AACA;IACA,aAAA;IACA,gBAAA;AACA;AACA;AAEA;EACA,WAAA;EACA,YAAA;EACA,iBAAA;AACA","file":"vue-image-browser.vue","sourcesContent":["\r\n\r\n\r\n\r\n\r\n"]}, media: undefined }); }; /* scoped */ diff --git a/dist/vue-image-browser.umd.js b/dist/vue-image-browser.umd.js index 0e7daca..10909bb 100644 --- a/dist/vue-image-browser.umd.js +++ b/dist/vue-image-browser.umd.js @@ -233,6 +233,27 @@ // // // + // + // + // + // + // + // + // + // + // + // + // + // + // + // + // + // + // + // + // + // + // var script = { name: 'vue-image-browser', @@ -272,6 +293,11 @@ default: false, }, + allowRename: { + type: Boolean, + default: false, + }, + allowPhotoPane: { type: Boolean, default: false, @@ -307,6 +333,7 @@ return { message: null, query: '', + renameQuery: '', searchResult: null, pane: 'gallery', selectedPhoto: {}, @@ -343,12 +370,18 @@ 'w-full w-1/' + xs + ' md:w-1/' + md + ' lg:w-1/' + lg + ' xl:w-1/' + xl ) }, + + isRenameDisabled: function isRenameDisabled() { + return this.selectedPhoto.name === this.renameQuery + }, }, methods: { select: function select(photo) { this.selectedPhoto = photo; + this.renameQuery = photo.name; + this.allowPhotoPane && (this.pane = 'photo'); this.captionable && (this.selectedPhoto['caption'] = this.getCaption()); @@ -462,6 +495,13 @@ this.pane = 'gallery'; }, + renameSelected: function renameSelected() { + if (this.renameQuery.length <= 0) + { return; } + + this.$emit('renamed', this.selectedPhoto, this.renameQuery); + }, + doDelayedSearch: function doDelayedSearch() { var p = this; @@ -518,132 +558,132 @@ }, }; - function normalizeComponent(template, style, script, scopeId, isFunctionalTemplate, moduleIdentifier /* server only */, shadowMode, createInjector, createInjectorSSR, createInjectorShadow) { - if (typeof shadowMode !== 'boolean') { - createInjectorSSR = createInjector; - createInjector = shadowMode; - shadowMode = false; - } - // Vue.extend constructor export interop. - var options = typeof script === 'function' ? script.options : script; - // render functions - if (template && template.render) { - options.render = template.render; - options.staticRenderFns = template.staticRenderFns; - options._compiled = true; - // functional template - if (isFunctionalTemplate) { - options.functional = true; - } - } - // scopedId - if (scopeId) { - options._scopeId = scopeId; - } - var hook; - if (moduleIdentifier) { - // server build - hook = function (context) { - // 2.3 injection - context = - context || // cached call - (this.$vnode && this.$vnode.ssrContext) || // stateful - (this.parent && this.parent.$vnode && this.parent.$vnode.ssrContext); // functional - // 2.2 with runInNewContext: true - if (!context && typeof __VUE_SSR_CONTEXT__ !== 'undefined') { - context = __VUE_SSR_CONTEXT__; - } - // inject component styles - if (style) { - style.call(this, createInjectorSSR(context)); - } - // register component module identifier for async chunk inference - if (context && context._registeredComponents) { - context._registeredComponents.add(moduleIdentifier); - } - }; - // used by ssr in case component is cached and beforeCreate - // never gets called - options._ssrRegister = hook; - } - else if (style) { - hook = shadowMode - ? function (context) { - style.call(this, createInjectorShadow(context, this.$root.$options.shadowRoot)); - } - : function (context) { - style.call(this, createInjector(context)); - }; - } - if (hook) { - if (options.functional) { - // register for functional component in vue file - var originalRender = options.render; - options.render = function renderWithStyleInjection(h, context) { - hook.call(context); - return originalRender(h, context); - }; - } - else { - // inject component registration as beforeCreate hook - var existing = options.beforeCreate; - options.beforeCreate = existing ? [].concat(existing, hook) : [hook]; - } - } - return script; + function normalizeComponent(template, style, script, scopeId, isFunctionalTemplate, moduleIdentifier /* server only */, shadowMode, createInjector, createInjectorSSR, createInjectorShadow) { + if (typeof shadowMode !== 'boolean') { + createInjectorSSR = createInjector; + createInjector = shadowMode; + shadowMode = false; + } + // Vue.extend constructor export interop. + var options = typeof script === 'function' ? script.options : script; + // render functions + if (template && template.render) { + options.render = template.render; + options.staticRenderFns = template.staticRenderFns; + options._compiled = true; + // functional template + if (isFunctionalTemplate) { + options.functional = true; + } + } + // scopedId + if (scopeId) { + options._scopeId = scopeId; + } + var hook; + if (moduleIdentifier) { + // server build + hook = function (context) { + // 2.3 injection + context = + context || // cached call + (this.$vnode && this.$vnode.ssrContext) || // stateful + (this.parent && this.parent.$vnode && this.parent.$vnode.ssrContext); // functional + // 2.2 with runInNewContext: true + if (!context && typeof __VUE_SSR_CONTEXT__ !== 'undefined') { + context = __VUE_SSR_CONTEXT__; + } + // inject component styles + if (style) { + style.call(this, createInjectorSSR(context)); + } + // register component module identifier for async chunk inference + if (context && context._registeredComponents) { + context._registeredComponents.add(moduleIdentifier); + } + }; + // used by ssr in case component is cached and beforeCreate + // never gets called + options._ssrRegister = hook; + } + else if (style) { + hook = shadowMode + ? function (context) { + style.call(this, createInjectorShadow(context, this.$root.$options.shadowRoot)); + } + : function (context) { + style.call(this, createInjector(context)); + }; + } + if (hook) { + if (options.functional) { + // register for functional component in vue file + var originalRender = options.render; + options.render = function renderWithStyleInjection(h, context) { + hook.call(context); + return originalRender(h, context); + }; + } + else { + // inject component registration as beforeCreate hook + var existing = options.beforeCreate; + options.beforeCreate = existing ? [].concat(existing, hook) : [hook]; + } + } + return script; } - var isOldIE = typeof navigator !== 'undefined' && - /msie [6-9]\\b/.test(navigator.userAgent.toLowerCase()); - function createInjector(context) { - return function (id, style) { return addStyle(id, style); }; - } - var HEAD; - var styles = {}; - function addStyle(id, css) { - var group = isOldIE ? css.media || 'default' : id; - var style = styles[group] || (styles[group] = { ids: new Set(), styles: [] }); - if (!style.ids.has(id)) { - style.ids.add(id); - var code = css.source; - if (css.map) { - // https://developer.chrome.com/devtools/docs/javascript-debugging - // this makes source maps inside style tags work properly in Chrome - code += '\n/*# sourceURL=' + css.map.sources[0] + ' */'; - // http://stackoverflow.com/a/26603875 - code += - '\n/*# sourceMappingURL=data:application/json;base64,' + - btoa(unescape(encodeURIComponent(JSON.stringify(css.map)))) + - ' */'; - } - if (!style.element) { - style.element = document.createElement('style'); - style.element.type = 'text/css'; - if (css.media) - { style.element.setAttribute('media', css.media); } - if (HEAD === undefined) { - HEAD = document.head || document.getElementsByTagName('head')[0]; - } - HEAD.appendChild(style.element); - } - if ('styleSheet' in style.element) { - style.styles.push(code); - style.element.styleSheet.cssText = style.styles - .filter(Boolean) - .join('\n'); - } - else { - var index = style.ids.size - 1; - var textNode = document.createTextNode(code); - var nodes = style.element.childNodes; - if (nodes[index]) - { style.element.removeChild(nodes[index]); } - if (nodes.length) - { style.element.insertBefore(textNode, nodes[index]); } - else - { style.element.appendChild(textNode); } - } - } + var isOldIE = typeof navigator !== 'undefined' && + /msie [6-9]\\b/.test(navigator.userAgent.toLowerCase()); + function createInjector(context) { + return function (id, style) { return addStyle(id, style); }; + } + var HEAD; + var styles = {}; + function addStyle(id, css) { + var group = isOldIE ? css.media || 'default' : id; + var style = styles[group] || (styles[group] = { ids: new Set(), styles: [] }); + if (!style.ids.has(id)) { + style.ids.add(id); + var code = css.source; + if (css.map) { + // https://developer.chrome.com/devtools/docs/javascript-debugging + // this makes source maps inside style tags work properly in Chrome + code += '\n/*# sourceURL=' + css.map.sources[0] + ' */'; + // http://stackoverflow.com/a/26603875 + code += + '\n/*# sourceMappingURL=data:application/json;base64,' + + btoa(unescape(encodeURIComponent(JSON.stringify(css.map)))) + + ' */'; + } + if (!style.element) { + style.element = document.createElement('style'); + style.element.type = 'text/css'; + if (css.media) + { style.element.setAttribute('media', css.media); } + if (HEAD === undefined) { + HEAD = document.head || document.getElementsByTagName('head')[0]; + } + HEAD.appendChild(style.element); + } + if ('styleSheet' in style.element) { + style.styles.push(code); + style.element.styleSheet.cssText = style.styles + .filter(Boolean) + .join('\n'); + } + else { + var index = style.ids.size - 1; + var textNode = document.createTextNode(code); + var nodes = style.element.childNodes; + if (nodes[index]) + { style.element.removeChild(nodes[index]); } + if (nodes.length) + { style.element.insertBefore(textNode, nodes[index]); } + else + { style.element.appendChild(textNode); } + } + } } /* script */ @@ -927,21 +967,79 @@ 0 ), _vm._v(" "), - _vm.allowDelete - ? _c( - "button", - { - staticClass: - "text-red-500 border m-4 mt-6 px-4 text-sm py-1 hover:border border-red-500 hover:text-white hover:bg-red-500 rounded cursor-pointer", - on: { - click: function($event) { - return _vm.deleteSelected() - } - } - }, - [_vm._v("\n Delete\n ")] - ) - : _vm._e() + _c( + "div", + { + staticClass: + "w-full mx-auto py-4 bg-transparent my-4 flex items-center flex-no-wrap" + }, + [ + _c("div", { staticClass: "flex-none px-3" }, [ + _vm.allowDelete + ? _c( + "button", + { + staticClass: + "text-red-500 border px-4 text-sm py-2 hover:border border-red-500 hover:text-white hover:bg-red-500 rounded cursor-pointer", + on: { + click: function($event) { + return _vm.deleteSelected() + } + } + }, + [_vm._v("\n Delete\n ")] + ) + : _vm._e() + ]), + _vm._v(" "), + _vm.allowRename + ? _c("div", { staticClass: "flex-grow flex px-3" }, [ + _c("input", { + directives: [ + { + name: "model", + rawName: "v-model", + value: _vm.renameQuery, + expression: "renameQuery" + } + ], + staticClass: + "p-2 w-full rounded-l-lg rounded-r-lg sm:rounded-r-none border sm:border-r-0 border-gray-300 bg-white outline-none", + attrs: { type: "text" }, + domProps: { value: _vm.renameQuery }, + on: { + input: function($event) { + if ($event.target.composing) { + return + } + _vm.renameQuery = $event.target.value; + } + } + }), + _vm._v(" "), + _c("div", { staticClass: "flex relative" }, [ + _c( + "button", + { + staticClass: + "text-blue-500 px-4 text-sm py-1 hover:border hover:border-blue-500 hover:text-white hover:bg-blue-500 rounded-r-lg border-r border-t border-b border-gray-300 cursor-pointer", + class: _vm.isRenameDisabled + ? "opacity-50 cursor-not-allowed" + : "", + attrs: { disabled: _vm.isRenameDisabled }, + on: { + click: function($event) { + return _vm.renameSelected() + } + } + }, + [_vm._v("\n Rename\n ")] + ) + ]) + ]) + : _vm._e() + ] + ) ]) ]) : _vm._e(), @@ -1153,7 +1251,7 @@ /* style */ var __vue_inject_styles__ = function (inject) { if (!inject) { return } - inject("data-v-5b2da7ca_0", { source: "\n@media only screen and (min-width: 640px) {\n.thumbnail {\n height: 300px;\n overflow: hidden;\n}\n}\n@media only screen and (min-width: 768px) {\n.thumbnail {\n height: 250px;\n overflow: hidden;\n}\n}\n@media only screen and (min-width: 1024px) {\n.thumbnail {\n height: 200px;\n overflow: hidden;\n}\n}\n@media only screen and (min-width: 1280px) {\n.thumbnail {\n height: 120px;\n overflow: hidden;\n}\n}\n.mg-photo {\n width: 100%;\n height: 100%;\n object-fit: cover;\n}\n", map: {"version":3,"sources":["/Users/akash/code/vue-image-browser/src/vue-image-browser.vue"],"names":[],"mappings":";AAggBA;AACA;IACA,aAAA;IACA,gBAAA;AACA;AACA;AACA;AACA;IACA,aAAA;IACA,gBAAA;AACA;AACA;AACA;AACA;IACA,aAAA;IACA,gBAAA;AACA;AACA;AACA;AACA;IACA,aAAA;IACA,gBAAA;AACA;AACA;AAEA;EACA,WAAA;EACA,YAAA;EACA,iBAAA;AACA","file":"vue-image-browser.vue","sourcesContent":["\n\n\n\n\n"]}, media: undefined }); + inject("data-v-962f8ec2_0", { source: "\n@media only screen and (min-width: 640px) {\n.thumbnail {\r\n height: 300px;\r\n overflow: hidden;\n}\n}\n@media only screen and (min-width: 768px) {\n.thumbnail {\r\n height: 250px;\r\n overflow: hidden;\n}\n}\n@media only screen and (min-width: 1024px) {\n.thumbnail {\r\n height: 200px;\r\n overflow: hidden;\n}\n}\n@media only screen and (min-width: 1280px) {\n.thumbnail {\r\n height: 120px;\r\n overflow: hidden;\n}\n}\n.mg-photo {\r\n width: 100%;\r\n height: 100%;\r\n object-fit: cover;\n}\r\n", map: {"version":3,"sources":["C:\\laragon\\www\\vue-image-browser\\src\\vue-image-browser.vue"],"names":[],"mappings":";AAwiBA;AACA;IACA,aAAA;IACA,gBAAA;AACA;AACA;AACA;AACA;IACA,aAAA;IACA,gBAAA;AACA;AACA;AACA;AACA;IACA,aAAA;IACA,gBAAA;AACA;AACA;AACA;AACA;IACA,aAAA;IACA,gBAAA;AACA;AACA;AAEA;EACA,WAAA;EACA,YAAA;EACA,iBAAA;AACA","file":"vue-image-browser.vue","sourcesContent":["\r\n\r\n\r\n\r\n\r\n"]}, media: undefined }); }; /* scoped */ diff --git a/package-lock.json b/package-lock.json index c83982b..1f57945 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "@akashmitra/vue-image-browser", - "version": "1.2.1", + "version": "1.2.3", "lockfileVersion": 1, "requires": true, "dependencies": { diff --git a/package.json b/package.json index 594511d..47ba175 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@akashmitra/vue-image-browser", - "version": "1.2.2", + "version": "1.2.3", "description": "A VueJS Image Browser Component with options to upload, browse, delete and select images", "main": "/dist/vue-image-browser.umd.js", "module": "dist/vue-image-browser.esm.js", diff --git a/src/vue-image-browser.vue b/src/vue-image-browser.vue index 3fede8a..25b1df4 100644 --- a/src/vue-image-browser.vue +++ b/src/vue-image-browser.vue @@ -118,13 +118,34 @@ - +
+
+ +
+
+ +
+ +
+
+
+ @@ -266,6 +287,11 @@ export default { default: false, }, + allowRename: { + type: Boolean, + default: false, + }, + allowPhotoPane: { type: Boolean, default: false, @@ -301,6 +327,7 @@ export default { return { message: null, query: '', + renameQuery: '', searchResult: null, pane: 'gallery', selectedPhoto: {}, @@ -337,12 +364,18 @@ export default { 'w-full w-1/' + xs + ' md:w-1/' + md + ' lg:w-1/' + lg + ' xl:w-1/' + xl ) }, + + isRenameDisabled() { + return this.selectedPhoto.name === this.renameQuery + }, }, methods: { select(photo) { this.selectedPhoto = photo + this.renameQuery = photo.name + this.allowPhotoPane && (this.pane = 'photo') this.captionable && (this.selectedPhoto['caption'] = this.getCaption()) @@ -452,6 +485,13 @@ export default { this.pane = 'gallery' }, + renameSelected() { + if (this.renameQuery.length <= 0) + return; + + this.$emit('renamed', this.selectedPhoto, this.renameQuery) + }, + doDelayedSearch() { let p = this