├── .gitignore ├── LICENSE ├── README.md ├── banner.tmpl ├── dist ├── vue-tagdog.js └── vue-tagdog.min.js ├── gulpfile.js ├── package.json └── src └── vue-tagdog.js /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | .idea 3 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2015 kriskbx 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-tagdog [![Tips](https://img.shields.io/gratipay/kriskbx.svg)](https://www.gittip.com/kriskbx/) [![Npm](https://img.shields.io/npm/dt/vue-tagdog.svg)](https://www.npmjs.com/package/vue-tagdog) 2 | 3 | > A Vue.js directive for [tagdog.js](https://github.com/odiumediae/tagdog.js) 4 | 5 | ## requirements 6 | 7 | * Vue.js `^0.12.0` 8 | * tagdog.js `^0.0.2` 9 | 10 | ## installation 11 | 12 | ```bash 13 | npm install vue-tagdog --save 14 | ``` 15 | 16 | ## usage 17 | 18 | With webpack or browserify: 19 | 20 | ```javascript 21 | var Vue = require('vue'); 22 | Vue.use(require('vue-tagdog')); 23 | ``` 24 | 25 | Direct HTML include: 26 | 27 | ```javascript 28 | Vue.use(window['vue-tagdog']); 29 | ``` 30 | 31 | Usage of the `v-tagdog` directive: 32 | 33 | ```html 34 |

35 | 36 | 37 |

38 | ``` 39 | 40 | ```javascript 41 | var vm = new Vue({ 42 | 43 | // ... 44 | 45 | data: { 46 | tags: 'blue,red,green', 47 | tagdogSettings: { 48 | maxTags: 4 49 | } 50 | 51 | // ... 52 | 53 | }); 54 | ``` 55 | 56 | ## demo 57 | 58 | Here on [JSFiddle](https://jsfiddle.net/kriskbx/7fomkrL7/6/). 59 | 60 | ## license 61 | 62 | MIT. 63 | 64 | -------------------------------------------------------------------------------- /banner.tmpl: -------------------------------------------------------------------------------- 1 | /** 2 | * <%= pkg.name %> v<%= pkg.version %> 3 | * 4 | * Copyright (c) <%= pkg.year %> <%= pkg.author %>, contributors. 5 | * Licensed under the <%= pkg.license %> license. 6 | */ -------------------------------------------------------------------------------- /dist/vue-tagdog.js: -------------------------------------------------------------------------------- 1 | /** 2 | * vue-tagdog v0.0.1 3 | * 4 | * Copyright (c) kriskbx , contributors. 5 | * Licensed under the MIT license. 6 | */(function(root, factory){ 7 | var vueTagdog = { 8 | 9 | twoWay: true, 10 | 11 | tagdog: null, 12 | 13 | tagdogSettings: null, 14 | 15 | tagdogProps: { 16 | destroy: function destroy() { 17 | // Remove listeners by cloning the original input 18 | this.originalInput.setAttribute('value', this.hiddenInput.getAttribute('value')); 19 | this.field.appendChild(this.originalInput.cloneNode(true)); 20 | this.field.removeChild(this.originalInput); 21 | 22 | // Remove DOM manipulations 23 | this.field.removeChild(this.hiddenInput); 24 | this.field.removeChild(this.tagContainer); 25 | } 26 | }, 27 | 28 | bind: function () { 29 | // Get and parse the settings expression 30 | var settingsExpression = this.el.getAttribute('settings'); 31 | if (settingsExpression) { 32 | this.tagdogSettings = this.vm.$eval(settingsExpression); 33 | this.vm.$watch(settingsExpression, this.settingsChange.bind(this), {deep: true}); 34 | } 35 | 36 | this.init(); 37 | }, 38 | 39 | update: function (value) { 40 | this.tagdog.resetTags(); 41 | var tags; 42 | 43 | // Parse the given value to an array of tags 44 | if (value instanceof String || typeof value == 'string') { 45 | tags = value.split(','); 46 | } else { 47 | tags = []; 48 | } 49 | 50 | // Add each tag individually 51 | tags.forEach(function (el) { 52 | if (!this.tagdog.hasTag(el) && el != '') 53 | this.tagdog.addTag(el); 54 | }.bind(this)); 55 | }, 56 | 57 | unbind: function () { 58 | this.tagdog.field.removeEventListener('change', this.updateValue.bind(this)); 59 | 60 | this.tagdog.destroy(); 61 | 62 | delete(this.tagdog); 63 | }, 64 | 65 | init: function () { 66 | // Init tagdog 67 | this.tagdog = tagdog(this.el, this.tagdogSettings, this.tagdogProps); 68 | 69 | // Add eventListener that updates the binded value 70 | this.tagdog.field.addEventListener('change', this.updateValue.bind(this)); 71 | }, 72 | 73 | updateValue: function () { 74 | this.set(this.tagdog.getTags().join(',')); 75 | }, 76 | 77 | settingsChange: function (settings) { 78 | var tags = this.tagdog.getTags(); 79 | 80 | this.tagdogSettings = settings; 81 | this.tagdog.destroy(); 82 | this.init(); 83 | 84 | tags.forEach(function (el) { 85 | if (!this.tagdog.hasTag(el) && el != '') 86 | this.tagdog.addTag(el); 87 | }.bind(this)); 88 | }, 89 | 90 | extend: function (receiver /*, emitters */) { 91 | var emitters = [].slice.call(arguments, 1), 92 | n = emitters.length, 93 | i, key, emitter; 94 | 95 | if (!n) return receiver; 96 | 97 | for (i = 0; i < n; i++) { 98 | emitter = emitters[i]; 99 | for (key in emitter) { 100 | receiver[key] = emitter[key]; 101 | } 102 | } 103 | 104 | return receiver; 105 | } 106 | 107 | }; 108 | 109 | if (typeof exports === 'object' && typeof module === 'object') { 110 | module.exports = factory(); 111 | } 112 | else if (typeof define === 'function' && define.amd) { 113 | define([], factory); 114 | } 115 | else if (typeof exports === 'object') { 116 | exports['vue-tagdog'] = factory(); 117 | } 118 | else { 119 | root['vue-tagdog'] = factory(); 120 | } 121 | 122 | function factory() { 123 | return function (Vue, options) { 124 | options = options || {}; 125 | var directiveName = options.directive || 'tagdog'; 126 | Vue.directive(directiveName, vueTagdog); 127 | }; 128 | } 129 | })(this); -------------------------------------------------------------------------------- /dist/vue-tagdog.min.js: -------------------------------------------------------------------------------- 1 | /** 2 | * vue-tagdog v0.0.1 3 | * 4 | * Copyright (c) kriskbx , contributors. 5 | * Licensed under the MIT license. 6 | */!function(t,i){function i(){return function(t,i){i=i||{};var n=i.directive||"tagdog";t.directive(n,e)}}var e={twoWay:!0,tagdog:null,tagdogSettings:null,tagdogProps:{destroy:function(){this.originalInput.setAttribute("value",this.hiddenInput.getAttribute("value")),this.field.appendChild(this.originalInput.cloneNode(!0)),this.field.removeChild(this.originalInput),this.field.removeChild(this.hiddenInput),this.field.removeChild(this.tagContainer)}},bind:function(){var t=this.el.getAttribute("settings");t&&(this.tagdogSettings=this.vm.$eval(t),this.vm.$watch(t,this.settingsChange.bind(this),{deep:!0})),this.init()},update:function(t){this.tagdog.resetTags();var i;i=t instanceof String||"string"==typeof t?t.split(","):[],i.forEach(function(t){this.tagdog.hasTag(t)||""==t||this.tagdog.addTag(t)}.bind(this))},unbind:function(){this.tagdog.field.removeEventListener("change",this.updateValue.bind(this)),this.tagdog.destroy(),delete this.tagdog},init:function(){this.tagdog=tagdog(this.el,this.tagdogSettings,this.tagdogProps),this.tagdog.field.addEventListener("change",this.updateValue.bind(this))},updateValue:function(){this.set(this.tagdog.getTags().join(","))},settingsChange:function(t){var i=this.tagdog.getTags();this.tagdogSettings=t,this.tagdog.destroy(),this.init(),i.forEach(function(t){this.tagdog.hasTag(t)||""==t||this.tagdog.addTag(t)}.bind(this))},extend:function(t){var i,e,n,g=[].slice.call(arguments,1),s=g.length;if(!s)return t;for(i=0;s>i;i++){n=g[i];for(e in n)t[e]=n[e]}return t}};"object"==typeof exports&&"object"==typeof module?module.exports=i():"function"==typeof define&&define.amd?define([],i):"object"==typeof exports?exports["vue-tagdog"]=i():t["vue-tagdog"]=i()}(this); -------------------------------------------------------------------------------- /gulpfile.js: -------------------------------------------------------------------------------- 1 | var gulp = require('gulp'), 2 | uglify = require('gulp-uglify'), 3 | header = require('gulp-header'), 4 | rename = require('gulp-rename'), 5 | pkg = require('./package.json'), 6 | del = require('del'), 7 | fs = require('fs'), 8 | bannerTemplate = fs.readFileSync('banner.tmpl', 'utf8'); 9 | 10 | gulp.task('clean', function () { 11 | return del(['dist']); 12 | }); 13 | 14 | gulp.task('default', ['clean'], function () { 15 | return gulp.src('src/*.js') 16 | .pipe(header(bannerTemplate, { pkg : pkg } )) 17 | .pipe(gulp.dest('dist')) 18 | .pipe(uglify()) 19 | .pipe(header(bannerTemplate, { pkg : pkg } )) 20 | .pipe(rename(function (path) { 21 | path.extname = '.min.js'; 22 | })) 23 | .pipe(gulp.dest('dist')); 24 | }); 25 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "vue-tagdog", 3 | "version": "0.0.2", 4 | "description": "A Vue.js directive for tagdog.js", 5 | "scripts": { 6 | "test": "echo \"Error: no test specified\" && exit 1" 7 | }, 8 | "main": "./dist/vue-tagdog.js", 9 | "keywords": [ 10 | "tags", 11 | "tagging", 12 | "forms", 13 | "fields", 14 | "components", 15 | "plugin", 16 | "vue", 17 | "directiv" 18 | ], 19 | "author": "kriskbx ", 20 | "license": "MIT", 21 | "devDependencies": { 22 | "add-banner": "^0.1.0", 23 | "del": "^2.0.2", 24 | "gulp": "^3.9.0", 25 | "gulp-header": "^1.7.1", 26 | "gulp-rename": "^1.2.2", 27 | "gulp-uglify": "^1.4.1" 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /src/vue-tagdog.js: -------------------------------------------------------------------------------- 1 | (function(root, factory){ 2 | var vueTagdog = { 3 | 4 | twoWay: true, 5 | 6 | tagdog: null, 7 | 8 | tagdogSettings: null, 9 | 10 | tagdogProps: { 11 | destroy: function destroy() { 12 | // Remove listeners by cloning the original input 13 | this.originalInput.setAttribute('value', this.hiddenInput.getAttribute('value')); 14 | this.field.appendChild(this.originalInput.cloneNode(true)); 15 | this.field.removeChild(this.originalInput); 16 | 17 | // Remove DOM manipulations 18 | this.field.removeChild(this.hiddenInput); 19 | this.field.removeChild(this.tagContainer); 20 | } 21 | }, 22 | 23 | bind: function () { 24 | // Get and parse the settings expression 25 | var settingsExpression = this.el.getAttribute('settings'); 26 | if (settingsExpression) { 27 | this.tagdogSettings = this.vm.$eval(settingsExpression); 28 | this.vm.$watch(settingsExpression, this.settingsChange.bind(this), {deep: true}); 29 | } 30 | 31 | this.init(); 32 | }, 33 | 34 | update: function (value) { 35 | this.tagdog.resetTags(); 36 | var tags; 37 | 38 | // Parse the given value to an array of tags 39 | if (value instanceof String || typeof value == 'string') { 40 | tags = value.split(','); 41 | } else { 42 | tags = []; 43 | } 44 | 45 | // Add each tag individually 46 | tags.forEach(function (el) { 47 | if (!this.tagdog.hasTag(el) && el != '') 48 | this.tagdog.addTag(el); 49 | }.bind(this)); 50 | }, 51 | 52 | unbind: function () { 53 | this.tagdog.field.removeEventListener('change', this.updateValue.bind(this)); 54 | 55 | this.tagdog.destroy(); 56 | 57 | delete(this.tagdog); 58 | }, 59 | 60 | init: function () { 61 | // Init tagdog 62 | this.tagdog = tagdog(this.el, this.tagdogSettings, this.tagdogProps); 63 | 64 | // Add eventListener that updates the binded value 65 | this.tagdog.field.addEventListener('change', this.updateValue.bind(this)); 66 | }, 67 | 68 | updateValue: function () { 69 | this.set(this.tagdog.getTags().join(',')); 70 | }, 71 | 72 | settingsChange: function (settings) { 73 | var tags = this.tagdog.getTags(); 74 | 75 | this.tagdogSettings = settings; 76 | this.tagdog.destroy(); 77 | this.init(); 78 | 79 | tags.forEach(function (el) { 80 | if (!this.tagdog.hasTag(el) && el != '') 81 | this.tagdog.addTag(el); 82 | }.bind(this)); 83 | }, 84 | 85 | extend: function (receiver /*, emitters */) { 86 | var emitters = [].slice.call(arguments, 1), 87 | n = emitters.length, 88 | i, key, emitter; 89 | 90 | if (!n) return receiver; 91 | 92 | for (i = 0; i < n; i++) { 93 | emitter = emitters[i]; 94 | for (key in emitter) { 95 | receiver[key] = emitter[key]; 96 | } 97 | } 98 | 99 | return receiver; 100 | } 101 | 102 | }; 103 | 104 | if (typeof exports === 'object' && typeof module === 'object') { 105 | module.exports = factory(); 106 | } 107 | else if (typeof define === 'function' && define.amd) { 108 | define([], factory); 109 | } 110 | else if (typeof exports === 'object') { 111 | exports['vue-tagdog'] = factory(); 112 | } 113 | else { 114 | root['vue-tagdog'] = factory(); 115 | } 116 | 117 | function factory() { 118 | return function (Vue, options) { 119 | options = options || {}; 120 | var directiveName = options.directive || 'tagdog'; 121 | Vue.directive(directiveName, vueTagdog); 122 | }; 123 | } 124 | })(this); --------------------------------------------------------------------------------