├── .eslintrc ├── .gitignore ├── CHANGELOG.md ├── LICENSE ├── README.md ├── build.js ├── dist ├── vue-cloudinary.common.js ├── vue-cloudinary.js └── vue-cloudinary.min.js ├── index.js └── package.json /.eslintrc: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "eslint:recommended", 3 | "rules": { 4 | "indent": [2, 2], 5 | "quotes": [2, "single"], 6 | "semi": [2, "always"], 7 | "linebreak-style": [2, "unix"], 8 | "comma-dangle": [2, "always-multiline"], 9 | "no-use-before-define": [2, "nofunc"], 10 | "no-unused-vars": [1, { "vars": "all", "args": "after-used" }] 11 | }, 12 | "env": { 13 | "node": true, 14 | "browser": true 15 | }, 16 | "ecmaFeatures": { 17 | "ecmaVersion": 6, 18 | "blockBindings": true, 19 | "modules": true 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | ## [0.1.0] - 2017-08-16 2 | 3 | Initial release 4 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2017 Diego Pamio 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in 13 | all copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | THE SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # vue-cloudinary 2 | 3 | > A [Vue.js](https://github.com/vuejs/vue) plugin that offers a reusable directive to get image from [cloudinary](https://cloudinary.com) 4 | 5 | [![npm version](https://img.shields.io/npm/v/vue-cloudinary.svg)](https://www.npmjs.com/package/vue-cloudinary) 6 | 7 | ## Overview 8 | 9 | This is a port of the angular-cloudinary library to VueJS. 10 | 11 | ## Use cases 12 | 13 | - Show image from cloudinary 14 | 15 | ## Requirements 16 | 17 | - vue: ^2.0.0 18 | 19 | If you need a version for Vue 1, sorry, you'll need to do your own. 20 | 21 | ## Install 22 | 23 | From npm: 24 | 25 | ``` sh 26 | $ npm install vue-cloudinary --save 27 | ``` 28 | 29 | ## Usage 30 | 31 | app.js: 32 | ``` javascript 33 | 34 | Vue.use(VueCloudinary, { 35 | "cloud_name": "", 36 | "api_key": "", 37 | "cdn_subdomain": true, 38 | ... (*) 39 | }); 40 | 41 | ``` 42 | 43 | (*) See [cloudinary documentation](https://cloudinary.com/documentation/solution_overview#configuration_parameters) for a complete list of the options available. 44 | 45 | index.html 46 | ```html 47 |
48 |

49 |
50 | ``` 51 | Further image manipulation options are listed in [this reference](http://cloudinary.com/documentation/image_transformations#reference). 52 | 53 | Note that the attribute names in the docs are using snake_case, however this SDK supports both snake_case and kebab-case for attribute names, e.g. both fetch_format: 'auto' and 'fetch-format': 'auto' are eventually translated to f_auto. 54 | ## License 55 | 56 | [MIT](https://opensource.org/licenses/MIT) 57 | -------------------------------------------------------------------------------- /build.js: -------------------------------------------------------------------------------- 1 | var fs = require('fs'); 2 | var path = require('path'); 3 | var mkdirp = require('mkdirp'); 4 | var uglify = require('uglify-js'); 5 | var rollup = require('rollup'); 6 | var replace = require('rollup-plugin-replace'); 7 | 8 | Promise 9 | .all([ 10 | generateCommonModule(), 11 | generateBundledDev(), 12 | generateBundledProd(), 13 | ]); 14 | 15 | function generateCommonModule() { 16 | return rollup 17 | .rollup({ 18 | entry: 'index.js', 19 | external: [ 'vue' ], 20 | }) 21 | .then(function(bundle) { 22 | return bundle.generate({ 23 | format: 'cjs', 24 | }).code; 25 | }) 26 | .then(function(code) { 27 | write('dist/vue-cloudinary.common.js', code); 28 | }); 29 | } 30 | 31 | function generateBundledDev() { 32 | return rollup 33 | .rollup({ 34 | entry: 'index.js', 35 | external: [ 'vue' ], 36 | plugins: [ 37 | replace({ 38 | 'process.env.NODE_ENV': '\'development\'', 39 | }), 40 | ], 41 | }) 42 | .then(function(bundle) { 43 | return bundle.generate({ 44 | format: 'iife', 45 | moduleName: 'VueCloudinary', 46 | globals: { vue: 'Vue' }, 47 | }).code; 48 | }) 49 | .then(function(code) { 50 | write('dist/vue-cloudinary.js', code); 51 | }); 52 | } 53 | 54 | function generateBundledProd() { 55 | return rollup 56 | .rollup({ 57 | entry: 'index.js', 58 | external: [ 'vue' ], 59 | plugins: [ 60 | replace({ 61 | 'process.env.NODE_ENV': '\'production\'', 62 | }), 63 | ], 64 | }) 65 | .then(function(bundle) { 66 | return bundle.generate({ 67 | format: 'iife', 68 | moduleName: 'VueCloudinary', 69 | globals: { vue: 'Vue' }, 70 | }).code; 71 | }) 72 | .then(function(code) { 73 | return uglify.minify(code, { 74 | fromString: true, 75 | compress: { 76 | screw_ie8: true, 77 | }, 78 | }).code; 79 | }) 80 | .then(function(code) { 81 | return write('dist/vue-cloudinary.min.js', code); 82 | }); 83 | } 84 | 85 | function write(dest, code) { 86 | return new Promise(function(resolve, reject) { 87 | mkdirp(path.dirname(dest), function(err) { 88 | if (err) return reject(err); 89 | fs.writeFile(dest, code, function(err) { 90 | if (err) return reject(err); 91 | resolve(); 92 | }); 93 | }); 94 | }); 95 | } 96 | -------------------------------------------------------------------------------- /dist/vue-cloudinary.common.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var Vue = require('vue'); 4 | Vue = 'default' in Vue ? Vue['default'] : Vue; 5 | var cloudinary = require('cloudinary-core'); 6 | cloudinary = 'default' in cloudinary ? cloudinary['default'] : cloudinary; 7 | 8 | const version = '0.1.0'; 9 | let configuration; 10 | let cloudinaryInstance; 11 | 12 | const compatible = (/^2\./).test(Vue.version); 13 | if (!compatible) { 14 | Vue.util.warn('CloudinaryImage ' + version + ' only supports Vue 2.x, and does not support Vue ' + Vue.version); 15 | } 16 | 17 | const cloudinaryAttr = function(attr){ 18 | if (attr.match(/cl[A-Z]/)) attr = attr.substring(2); 19 | return attr.replace(/([a-z])([A-Z])/g,'$1_$2').toLowerCase(); 20 | }; 21 | 22 | /** 23 | * Returns an array of attributes for cloudinary. 24 | * @function toCloudinaryAttributes 25 | * @param {Object} source - an object containing attributes 26 | * @param {(RegExp|string)} [filter] - copy only attributes whose name matches the filter 27 | * @return {Object} attributes for cloudinary functions 28 | */ 29 | const toCloudinaryAttributes = function( source, filter) { 30 | var attributes = {}; 31 | var isNamedNodeMap; 32 | if (window.NamedNodeMap) { 33 | isNamedNodeMap = source && (source.constructor.name === "NamedNodeMap" || source instanceof NamedNodeMap); 34 | } else if (window.MozNamedAttrMap) { 35 | // https://developer.mozilla.org/en-US/docs/Web/API/NamedNodeMap 36 | // https://www.fxsitecompat.com/en-CA/docs/2013/namednodemap-has-been-renamed-to-moznamedattrmap/ 37 | // In Firefox versions 22 - 33 the interface "NamedNodeMap" was called "MozNamedAttrMap" 38 | isNamedNodeMap = source && (source.constructor.name === "MozNamedAttrMap" || source instanceof MozNamedAttrMap); 39 | } 40 | Array.prototype.forEach.call(source, function(value, name){ 41 | if( isNamedNodeMap) { 42 | name = value.name; 43 | value = value.value; 44 | } 45 | if (!filter || filter.exec(name)) { 46 | attributes[cloudinaryAttr(name)] = value; 47 | } 48 | }); 49 | return attributes; 50 | }; 51 | 52 | const loadImage = function(el, value, options) { 53 | if (options.responsive === '' || options.responsive === 'true' || options.responsive === true) { 54 | options.responsive = true; 55 | } 56 | const url = cloudinaryInstance.url(value, options); 57 | if (options.responsive) { 58 | cloudinaryInstance.Util.setData(el, 'src', url); 59 | cloudinaryInstance.cloudinary_update(el, options); 60 | cloudinaryInstance.responsive(options, false); 61 | } else { 62 | el.setAttribute('src', url); 63 | } 64 | }; 65 | 66 | const clImage = { 67 | inserted: function(el, binding) { 68 | let options = toCloudinaryAttributes(el.attributes); 69 | 70 | if (el.attributes.htmlWidth) { 71 | el.setAttribute('width', el.attributes.htmlWidth); 72 | } else { 73 | el.removeAttribute('width'); 74 | } 75 | if (el.attributes.htmlHeight) { 76 | el.setAttribute('height', el.attributes.htmlHeight); 77 | } else { 78 | el.removeAttribute('height'); 79 | } 80 | loadImage(el, binding.value, options); 81 | }, 82 | 83 | componentUpdated: function(el, binding) { 84 | let options = toCloudinaryAttributes(el.attributes); 85 | loadImage(el, binding.value, options); 86 | }, 87 | }; 88 | 89 | function install(Vue, options) { 90 | configuration = new cloudinary.Configuration(options); 91 | // if (cloudinary.CloudinaryJQuery && jQuery) { 92 | // // cloudinary is attached to the global `jQuery` object 93 | // jQuery.cloudinary.config(configuration.config()); 94 | // cloudinaryInstance = jQuery.cloudinary; 95 | // } else { 96 | cloudinaryInstance = new cloudinary.Cloudinary(configuration.config()); 97 | // } 98 | cloudinary.Util.assign(cloudinaryInstance, cloudinary); // copy namespace to the service instance 99 | Vue.directive('cl-image', clImage); 100 | 101 | } 102 | 103 | exports.version = version; 104 | exports.install = install; -------------------------------------------------------------------------------- /dist/vue-cloudinary.js: -------------------------------------------------------------------------------- 1 | (function (exports,Vue,cloudinary) { 'use strict'; 2 | 3 | Vue = 'default' in Vue ? Vue['default'] : Vue; 4 | cloudinary = 'default' in cloudinary ? cloudinary['default'] : cloudinary; 5 | 6 | const version = '0.1.0'; 7 | let configuration; 8 | let cloudinaryInstance; 9 | 10 | const compatible = (/^2\./).test(Vue.version); 11 | if (!compatible) { 12 | Vue.util.warn('CloudinaryImage ' + version + ' only supports Vue 2.x, and does not support Vue ' + Vue.version); 13 | } 14 | 15 | const cloudinaryAttr = function(attr){ 16 | if (attr.match(/cl[A-Z]/)) attr = attr.substring(2); 17 | return attr.replace(/([a-z])([A-Z])/g,'$1_$2').toLowerCase(); 18 | }; 19 | 20 | /** 21 | * Returns an array of attributes for cloudinary. 22 | * @function toCloudinaryAttributes 23 | * @param {Object} source - an object containing attributes 24 | * @param {(RegExp|string)} [filter] - copy only attributes whose name matches the filter 25 | * @return {Object} attributes for cloudinary functions 26 | */ 27 | const toCloudinaryAttributes = function( source, filter) { 28 | var attributes = {}; 29 | var isNamedNodeMap; 30 | if (window.NamedNodeMap) { 31 | isNamedNodeMap = source && (source.constructor.name === "NamedNodeMap" || source instanceof NamedNodeMap); 32 | } else if (window.MozNamedAttrMap) { 33 | // https://developer.mozilla.org/en-US/docs/Web/API/NamedNodeMap 34 | // https://www.fxsitecompat.com/en-CA/docs/2013/namednodemap-has-been-renamed-to-moznamedattrmap/ 35 | // In Firefox versions 22 - 33 the interface "NamedNodeMap" was called "MozNamedAttrMap" 36 | isNamedNodeMap = source && (source.constructor.name === "MozNamedAttrMap" || source instanceof MozNamedAttrMap); 37 | } 38 | Array.prototype.forEach.call(source, function(value, name){ 39 | if( isNamedNodeMap) { 40 | name = value.name; 41 | value = value.value; 42 | } 43 | if (!filter || filter.exec(name)) { 44 | attributes[cloudinaryAttr(name)] = value; 45 | } 46 | }); 47 | return attributes; 48 | }; 49 | 50 | const loadImage = function(el, value, options) { 51 | if (options.responsive === '' || options.responsive === 'true' || options.responsive === true) { 52 | options.responsive = true; 53 | } 54 | const url = cloudinaryInstance.url(value, options); 55 | if (options.responsive) { 56 | cloudinaryInstance.Util.setData(el, 'src', url); 57 | cloudinaryInstance.cloudinary_update(el, options); 58 | cloudinaryInstance.responsive(options, false); 59 | } else { 60 | el.setAttribute('src', url); 61 | } 62 | }; 63 | 64 | const clImage = { 65 | inserted: function(el, binding) { 66 | let options = toCloudinaryAttributes(el.attributes); 67 | 68 | if (el.attributes.htmlWidth) { 69 | el.setAttribute('width', el.attributes.htmlWidth); 70 | } else { 71 | el.removeAttribute('width'); 72 | } 73 | if (el.attributes.htmlHeight) { 74 | el.setAttribute('height', el.attributes.htmlHeight); 75 | } else { 76 | el.removeAttribute('height'); 77 | } 78 | loadImage(el, binding.value, options); 79 | }, 80 | 81 | componentUpdated: function(el, binding) { 82 | let options = toCloudinaryAttributes(el.attributes); 83 | loadImage(el, binding.value, options); 84 | }, 85 | }; 86 | 87 | function install(Vue, options) { 88 | configuration = new cloudinary.Configuration(options); 89 | // if (cloudinary.CloudinaryJQuery && jQuery) { 90 | // // cloudinary is attached to the global `jQuery` object 91 | // jQuery.cloudinary.config(configuration.config()); 92 | // cloudinaryInstance = jQuery.cloudinary; 93 | // } else { 94 | cloudinaryInstance = new cloudinary.Cloudinary(configuration.config()); 95 | // } 96 | cloudinary.Util.assign(cloudinaryInstance, cloudinary); // copy namespace to the service instance 97 | Vue.directive('cl-image', clImage); 98 | 99 | } 100 | 101 | exports.version = version; 102 | exports.install = install; 103 | 104 | })((this.VueCloudinary = {}),Vue,cloudinary); -------------------------------------------------------------------------------- /dist/vue-cloudinary.min.js: -------------------------------------------------------------------------------- 1 | !function(t,e,n){"use strict";function a(t,e){o=new n.Configuration(e),i=new n.Cloudinary(o.config()),n.Util.assign(i,n),t.directive("cl-image",c)}e="default"in e?e.default:e,n="default"in n?n.default:n;var o,i;/^2\./.test(e.version)||e.util.warn("CloudinaryImage 0.1.0 only supports Vue 2.x, and does not support Vue "+e.version);var r=function(t){return t.match(/cl[A-Z]/)&&(t=t.substring(2)),t.replace(/([a-z])([A-Z])/g,"$1_$2").toLowerCase()},u=function(t,e){var n,a={};return window.NamedNodeMap?n=t&&("NamedNodeMap"===t.constructor.name||t instanceof NamedNodeMap):window.MozNamedAttrMap&&(n=t&&("MozNamedAttrMap"===t.constructor.name||t instanceof MozNamedAttrMap)),t.forEach(function(t,o){n&&(o=t.name,t=t.value),e&&!e.exec(o)||(a[r(o)]=t)}),a},c={inserted:function(t,e){t.setAttribute("src",i.url(e.value.publicId))},componentUpdated:function(t,e){t.setAttribute("src",i.url(e.value.publicId),u(t.attributes))}};t.version="0.1.0",t.install=a}(this.VueCloudinary={},Vue,cloudinary); -------------------------------------------------------------------------------- /index.js: -------------------------------------------------------------------------------- 1 | import Vue from 'vue'; 2 | import cloudinary from 'cloudinary-core'; 3 | 4 | export const version = '0.1.0'; 5 | let configuration; 6 | let cloudinaryInstance; 7 | 8 | const compatible = (/^2\./).test(Vue.version); 9 | if (!compatible) { 10 | Vue.util.warn('CloudinaryImage ' + version + ' only supports Vue 2.x, and does not support Vue ' + Vue.version); 11 | } 12 | 13 | const cloudinaryAttr = function(attr){ 14 | if (attr.match(/cl[A-Z]/)) attr = attr.substring(2); 15 | return attr.replace(/([a-z])([A-Z])/g,'$1_$2').toLowerCase(); 16 | }; 17 | 18 | /** 19 | * Returns an array of attributes for cloudinary. 20 | * @function toCloudinaryAttributes 21 | * @param {Object} source - an object containing attributes 22 | * @param {(RegExp|string)} [filter] - copy only attributes whose name matches the filter 23 | * @return {Object} attributes for cloudinary functions 24 | */ 25 | const toCloudinaryAttributes = function( source, filter) { 26 | var attributes = {}; 27 | var isNamedNodeMap; 28 | if (window.NamedNodeMap) { 29 | isNamedNodeMap = source && (source.constructor.name === "NamedNodeMap" || source instanceof NamedNodeMap); 30 | } else if (window.MozNamedAttrMap) { 31 | // https://developer.mozilla.org/en-US/docs/Web/API/NamedNodeMap 32 | // https://www.fxsitecompat.com/en-CA/docs/2013/namednodemap-has-been-renamed-to-moznamedattrmap/ 33 | // In Firefox versions 22 - 33 the interface "NamedNodeMap" was called "MozNamedAttrMap" 34 | isNamedNodeMap = source && (source.constructor.name === "MozNamedAttrMap" || source instanceof MozNamedAttrMap); 35 | } 36 | Array.prototype.forEach.call(source, function(value, name){ 37 | if( isNamedNodeMap) { 38 | name = value.name; 39 | value = value.value; 40 | } 41 | if (!filter || filter.exec(name)) { 42 | attributes[cloudinaryAttr(name)] = value; 43 | } 44 | }); 45 | return attributes; 46 | }; 47 | 48 | const loadImage = function(el, value, options) { 49 | if (options.responsive === '' || options.responsive === 'true' || options.responsive === true) { 50 | options.responsive = true; 51 | } 52 | const url = cloudinaryInstance.url(value, options); 53 | if (options.responsive) { 54 | cloudinaryInstance.Util.setData(el, 'src', url); 55 | cloudinaryInstance.cloudinary_update(el, options); 56 | cloudinaryInstance.responsive(options, false); 57 | } else { 58 | el.setAttribute('src', url); 59 | } 60 | }; 61 | 62 | const clImage = { 63 | inserted: function(el, binding) { 64 | let options = toCloudinaryAttributes(el.attributes); 65 | 66 | if (el.attributes.htmlWidth) { 67 | el.setAttribute('width', el.attributes.htmlWidth); 68 | } else { 69 | el.removeAttribute('width'); 70 | } 71 | if (el.attributes.htmlHeight) { 72 | el.setAttribute('height', el.attributes.htmlHeight); 73 | } else { 74 | el.removeAttribute('height'); 75 | } 76 | loadImage(el, binding.value, options); 77 | }, 78 | 79 | componentUpdated: function(el, binding) { 80 | let options = toCloudinaryAttributes(el.attributes); 81 | loadImage(el, binding.value, options); 82 | }, 83 | }; 84 | 85 | export function install(Vue, options) { 86 | configuration = new cloudinary.Configuration(options); 87 | // if (cloudinary.CloudinaryJQuery && jQuery) { 88 | // // cloudinary is attached to the global `jQuery` object 89 | // jQuery.cloudinary.config(configuration.config()); 90 | // cloudinaryInstance = jQuery.cloudinary; 91 | // } else { 92 | cloudinaryInstance = new cloudinary.Cloudinary(configuration.config()); 93 | // } 94 | cloudinary.Util.assign(cloudinaryInstance, cloudinary); // copy namespace to the service instance 95 | Vue.directive('cl-image', clImage); 96 | 97 | } -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "vue-cloudinary", 3 | "description": "A plugin that adds cl-image directive to Vue.js", 4 | "version": "0.2.1", 5 | "author": "Diego Pamio ", 6 | "browserify": { 7 | "transform": [ 8 | "loose-envify" 9 | ] 10 | }, 11 | "bugs": { 12 | "url": "https://github.com/diegopamio/vue-cloudinary/issues" 13 | }, 14 | "dependencies": { 15 | "cloudinary-core": "^2.3.0", 16 | "loose-envify": "^1.2.0" 17 | }, 18 | "devDependencies": { 19 | "eslint": "^1.10.3", 20 | "mkdirp": "^0.5.1", 21 | "rollup": "^0.21.2", 22 | "rollup-plugin-replace": "^1.1.0", 23 | "uglify-js": "^2.6.1" 24 | }, 25 | "files": [ 26 | "index.js", 27 | "dist" 28 | ], 29 | "homepage": "https://github.com/diegopamio/vue-cloudinary", 30 | "keywords": [ 31 | "cloudinary", 32 | "reusable", 33 | "vue", 34 | "vue-directive", 35 | "vuejs" 36 | ], 37 | "license": "MIT", 38 | "main": "dist/vue-cloudinary.common.js", 39 | "peerDependencies": { 40 | "vue": "^2.0.0" 41 | }, 42 | "repository": { 43 | "type": "git", 44 | "url": "https://github.com/diegopamio/vue-cloudinary" 45 | }, 46 | "scripts": { 47 | "lint": "./node_modules/.bin/eslint index.js build.js", 48 | "test": "echo \"Error: no test specified\" && exit 1" 49 | } 50 | } 51 | --------------------------------------------------------------------------------