├── .babelrc
├── .editorconfig
├── .gitignore
├── .jshintrc
├── .npmignore
├── LICENSE
├── README.md
├── bower.json
├── index.html
├── package.json
├── src
├── tags-input.js
└── tags-input.less
├── tags-input.css
├── tags-input.css.map
├── tags-input.js
└── tags-input.js.map
/.babelrc:
--------------------------------------------------------------------------------
1 | {
2 | "modules": "umd",
3 | "loose": "all",
4 | "compact": true,
5 | "comments": false
6 | }
7 |
--------------------------------------------------------------------------------
/.editorconfig:
--------------------------------------------------------------------------------
1 | root = true
2 |
3 | [*]
4 | indent_style = tab
5 | end_of_line = lf
6 | charset = utf-8
7 | trim_trailing_whitespace = true
8 | insert_final_newline = true
9 |
10 | [{package.json,.*rc,*.yml}]
11 | indent_style = space
12 | indent_size = 2
13 |
14 | [*.md]
15 | trim_trailing_whitespace = false
16 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | lib-cov
2 | *.seed
3 | *.log
4 | *.csv
5 | *.dat
6 | *.out
7 | *.pid
8 | *.gz
9 |
10 | pids
11 | logs
12 | results
13 |
14 | npm-debug.log
15 | node_modules
16 | bower_components
17 |
--------------------------------------------------------------------------------
/.jshintrc:
--------------------------------------------------------------------------------
1 | {
2 | "esnext": true,
3 | "browser": true
4 | }
5 |
--------------------------------------------------------------------------------
/.npmignore:
--------------------------------------------------------------------------------
1 | src
2 | bower.json
3 | README.md
4 | .babelrc
5 | .editorconfig
6 | .jshintrc
7 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 |
3 | Copyright (c) 2014 Jason Miller
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy of
6 | this software and associated documentation files (the "Software"), to deal in
7 | the Software without restriction, including without limitation the rights to
8 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
9 | the Software, and to permit persons to whom the Software is furnished to do so,
10 | subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | 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, FITNESS
17 | FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
18 | COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
19 | IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
20 | CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | tags-input
2 | ==========
3 |
4 | [](https://www.npmjs.org/package/tags-input)
5 | [](http://bower.io/search/?q=tags-input)
6 | [](https://gitter.im/developit/tags-input)
7 |
8 | **Features:**
9 |
10 | - I said `` should be a thing.
11 | - With full keyboard, mouse and focus support.
12 | - Works with HTML5 `pattern` and `placeholder` attributes, too!
13 | - Native [`change`](https://developer.mozilla.org/en-US/docs/Web/Events/change) and [`input`](https://developer.mozilla.org/en-US/docs/Web/Events/input) _("live" change)_ events.
14 | - Using [preact](https://github.com/developit/preact)? (or react?) There's a wrapper called [preact-token-input](https://github.com/developit/preact-token-input)
15 | - Works in modern browsers and IE10+
16 |
17 | **Screenshot:**
18 |
19 | > 
20 |
21 | [JSFiddle Demo](http://jsfiddle.net/developit/d5w4jpxq/)
22 |
23 | ---
24 |
25 |
26 | Examples
27 | ========
28 |
29 | It's easy to use! In addition to the example code, you'll also need to
30 | include `tags-input.css` - I didn't bundle it because that's a bit gross.
31 |
32 | **CommonJS:**
33 |
34 | ```js
35 | var tagsInput = require('tags-input');
36 |
37 | // create a new tag input:
38 | var tags = document.createElement('input');
39 | tags.setAttribute('type', 'tags');
40 | tagsInput(tags);
41 | document.body.appendChild(tags);
42 |
43 | // enhance an existing input:
44 | tagsInput(document.querySelector('input[type="tags"]'));
45 |
46 | // or just enhance all tag inputs on the page:
47 | [].forEach.call(document.querySelectorAll('input[type="tags"]'), tagsInput);
48 | ```
49 |
50 | **HTML Example:**
51 |
52 | ```html
53 |
54 |
55 |
56 |
62 |
63 |
64 | ```
65 |
--------------------------------------------------------------------------------
/bower.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "tags-input",
3 | "version": "1.0.2",
4 | "homepage": "https://github.com/developit/tags-input",
5 | "authors": [
6 | "Jason Miller "
7 | ],
8 | "description": " like magic.",
9 | "main": "tags-input.js,tags-input.css",
10 | "moduleType": [
11 | "amd",
12 | "node",
13 | "globals"
14 | ],
15 | "keywords": [
16 | "tags",
17 | "input",
18 | "polyfill"
19 | ],
20 | "license": "MIT",
21 | "ignore": [
22 | "**/.*",
23 | "**/*.min.js",
24 | "src",
25 | "bower_components",
26 | "LICENSE",
27 | "package.json",
28 | "README.md"
29 | ]
30 | }
31 |
--------------------------------------------------------------------------------
/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
19 |
20 |
21 |
29 |
34 |
35 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "tags-input",
3 | "version": "1.1.1",
4 | "main": "tags-input.js",
5 | "description": " like magic.",
6 | "scripts": {
7 | "build": "npm run transpile && npm run less && npm run size",
8 | "transpile": "babel src --source-root src -s -d .",
9 | "less": "lessc --clean-css --source-map --source-map-less-inline --autoprefix=\"last 2 versions\" src/tags-input.less tags-input.css",
10 | "size": "echo \"gzip size: $(pretty-bytes $(gzip-size $npm_package_main))\"",
11 | "test": "jshint src/**.js",
12 | "prepublish": "npm run build",
13 | "release": "npm run build && git commit -am $npm_package_version && git tag $npm_package_version && git push && git push --tags && npm publish"
14 | },
15 | "repository": {
16 | "type": "git",
17 | "url": "git://github.com/developit/tags-input.git"
18 | },
19 | "devDependencies": {
20 | "babel": "^5.8.21",
21 | "gzip-size": "^3.0.0",
22 | "jshint": "^2.8.0",
23 | "less": "^2.5.1",
24 | "less-plugin-autoprefix": "^1.4.2",
25 | "less-plugin-clean-css": "^1.5.1",
26 | "pretty-bytes": "^2.0.1"
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/src/tags-input.js:
--------------------------------------------------------------------------------
1 | const BACKSPACE = 8,
2 | TAB = 9,
3 | ENTER = 13,
4 | LEFT = 37,
5 | RIGHT = 39,
6 | DELETE = 46,
7 | COMMA = 188;
8 |
9 | const SEPERATOR = ',';
10 |
11 | const COPY_PROPS = 'placeholder pattern spellcheck autocomplete autocapitalize autofocus accessKey accept lang minLength maxLength required'.split(' ');
12 |
13 | export default function tagsInput(input) {
14 | function createElement(type, name, text, attributes) {
15 | let el = document.createElement(type);
16 | if (name) el.className = name;
17 | if (text) el.textContent = text;
18 | for (let key in attributes) {
19 | el.setAttribute(`data-${key}`, attributes[key]);
20 | }
21 | return el;
22 | }
23 |
24 | function $(selector, all) {
25 | return all===true ? Array.prototype.slice.call(base.querySelectorAll(selector)) : base.querySelector(selector);
26 | }
27 |
28 | function getValue() {
29 | return $('.tag', true)
30 | .map( tag => tag.textContent )
31 | .concat(base.input.value || [])
32 | .join(SEPERATOR);
33 | }
34 |
35 | function setValue(value) {
36 | $('.tag', true).forEach( t => base.removeChild(t) );
37 | savePartialInput(value);
38 | }
39 |
40 | function save() {
41 | input.value = getValue();
42 | input.dispatchEvent(new Event('change'));
43 | }
44 |
45 | // Return false if no need to add a tag
46 | function addTag(text) {
47 | // Add multiple tags if the user pastes in data with SEPERATOR already in it
48 | if (~text.indexOf(SEPERATOR)) text = text.split(SEPERATOR);
49 | if (Array.isArray(text)) return text.forEach(addTag);
50 |
51 | let tag = text && text.trim();
52 | // Ignore if text is empty
53 | if (!tag) return false;
54 |
55 | // For duplicates, briefly highlight the existing tag
56 | if (!input.getAttribute('duplicates')) {
57 | let exisingTag = $(`[data-tag="${tag}"]`);
58 | if (exisingTag) {
59 | exisingTag.classList.add('dupe');
60 | setTimeout( () => exisingTag.classList.remove('dupe') , 100);
61 | return false;
62 | }
63 | }
64 |
65 | base.insertBefore(
66 | createElement('span', 'tag', tag, { tag }),
67 | base.input
68 | );
69 | }
70 |
71 | function select(el) {
72 | let sel = $('.selected');
73 | if (sel) sel.classList.remove('selected');
74 | if (el) el.classList.add('selected');
75 | }
76 |
77 | function setInputWidth() {
78 | let last = $('.tag',true).pop(),
79 | w = base.offsetWidth;
80 | if (!w) return;
81 | base.input.style.width = Math.max(
82 | w - (last ? (last.offsetLeft+last.offsetWidth) : 5) - 5,
83 | w/4
84 | ) + 'px';
85 | }
86 |
87 | function savePartialInput(value) {
88 | if (typeof value!=='string' && !Array.isArray(value)) {
89 | // If the base input does not contain a value, default to the original element passed
90 | value = base.input.value;
91 | }
92 | if (addTag(value)!==false) {
93 | base.input.value = '';
94 | save();
95 | setInputWidth();
96 | }
97 | }
98 |
99 | function refocus(e) {
100 | if (e.target.classList.contains('tag')) select(e.target);
101 | if (e.target===base.input) return select();
102 | base.input.focus();
103 | e.preventDefault();
104 | return false;
105 | }
106 |
107 | function caretAtStart(el) {
108 | try {
109 | return el.selectionStart === 0 && el.selectionEnd === 0;
110 | }
111 | catch(e) {
112 | return el.value === '';
113 | }
114 | }
115 |
116 |
117 | let base = createElement('div', 'tags-input'),
118 | sib = input.nextSibling;
119 |
120 | input.parentNode[sib?'insertBefore':'appendChild'](base, sib);
121 |
122 | input.style.cssText = 'position:absolute;left:0;top:-99px;width:1px;height:1px;opacity:0.01;';
123 | input.tabIndex = -1;
124 |
125 | let inputType = input.getAttribute('type');
126 | if (!inputType || inputType === 'tags') {
127 | inputType = 'text';
128 | }
129 | base.input = createElement('input');
130 | base.input.setAttribute('type', inputType);
131 | COPY_PROPS.forEach( prop => {
132 | if (input[prop]!==base.input[prop]) {
133 | base.input[prop] = input[prop];
134 | try { delete input[prop]; }catch(e){}
135 | }
136 | });
137 | base.appendChild(base.input);
138 |
139 | input.addEventListener('focus', () => {
140 | base.input.focus();
141 | });
142 |
143 | base.input.addEventListener('focus', () => {
144 | base.classList.add('focus');
145 | select();
146 | });
147 |
148 | base.input.addEventListener('blur', () => {
149 | base.classList.remove('focus');
150 | select();
151 | savePartialInput();
152 | });
153 |
154 | base.input.addEventListener('keydown', e => {
155 | let el = base.input,
156 | key = e.keyCode || e.which,
157 | selectedTag = $('.tag.selected'),
158 | atStart = caretAtStart(el),
159 | last = $('.tag',true).pop();
160 |
161 | setInputWidth();
162 |
163 | if (key===ENTER || key===COMMA || key===TAB) {
164 | if (!el.value && key!==COMMA) return;
165 | savePartialInput();
166 | }
167 | else if (key===DELETE && selectedTag) {
168 | if (selectedTag.nextSibling!==base.input) select(selectedTag.nextSibling);
169 | base.removeChild(selectedTag);
170 | setInputWidth();
171 | save();
172 | }
173 | else if (key===BACKSPACE) {
174 | if (selectedTag) {
175 | select(selectedTag.previousSibling);
176 | base.removeChild(selectedTag);
177 | setInputWidth();
178 | save();
179 | }
180 | else if (last && atStart) {
181 | select(last);
182 | }
183 | else {
184 | return;
185 | }
186 | }
187 | else if (key===LEFT) {
188 | if (selectedTag) {
189 | if (selectedTag.previousSibling) {
190 | select(selectedTag.previousSibling);
191 | }
192 | }
193 | else if (!atStart) {
194 | return;
195 | }
196 | else {
197 | select(last);
198 | }
199 | }
200 | else if (key===RIGHT) {
201 | if (!selectedTag) return;
202 | select(selectedTag.nextSibling);
203 | }
204 | else {
205 | return select();
206 | }
207 |
208 | e.preventDefault();
209 | return false;
210 | });
211 |
212 | // Proxy "input" (live change) events , update the first tag live as the user types
213 | // This means that users who only want one thing don't have to enter commas
214 | base.input.addEventListener('input', () => {
215 | input.value = getValue();
216 | input.dispatchEvent(new Event('input'));
217 | });
218 |
219 | // One tick after pasting, parse pasted text as CSV:
220 | base.input.addEventListener('paste', () => setTimeout(savePartialInput, 0));
221 |
222 | base.addEventListener('mousedown', refocus);
223 | base.addEventListener('touchstart', refocus);
224 |
225 | base.setValue = setValue;
226 | base.getValue = getValue;
227 |
228 | // Add tags for existing values
229 | savePartialInput(input.value);
230 | }
231 |
232 | // make life easier:
233 | tagsInput.enhance = tagsInput.tagsInput = tagsInput;
234 |
--------------------------------------------------------------------------------
/src/tags-input.less:
--------------------------------------------------------------------------------
1 | .tags-input {
2 | display: inline-block;
3 | padding: 0 2px;
4 | background: #FFF;
5 | border: 1px solid #CCC;
6 | width: 16em;
7 | border-radius: 2px;
8 | box-shadow: inset 0 1px 2px rgba(0,0,0,0.1);
9 |
10 | .tag {
11 | display: inline-block;
12 | background: #EEE;
13 | color: #444;
14 | padding: 0 4px;
15 | margin: 2px;
16 | border: 1px solid #CCC;
17 | border-radius: 2px;
18 | font: inherit;
19 | user-select: none;
20 | cursor: pointer;
21 | transition: all 100ms ease;
22 |
23 | &.selected {
24 | background-color: #777;
25 | border-color: #777;
26 | color: #EEE;
27 | }
28 |
29 | &.dupe {
30 | transform: scale3d(1.2,1.2,1.2);
31 | background-color: #FCC;
32 | border-color: #700;
33 | }
34 | }
35 |
36 | input {
37 | appearance: none !important;
38 | display: inline-block !important;
39 | padding: 3px;
40 | margin: 0 !important;
41 | background: none !important;
42 | border: none !important;
43 | box-shadow: none !important;
44 | font: inherit !important;
45 | font-size: 100% !important;
46 | outline: none !important;
47 | }
48 |
49 | .selected ~ input {
50 | opacity: 0.3;
51 | }
52 | }
53 |
--------------------------------------------------------------------------------
/tags-input.css:
--------------------------------------------------------------------------------
1 | .tags-input{display:inline-block;padding:0 2px;background:#FFF;border:1px solid #CCC;width:16em;border-radius:2px;box-shadow:inset 0 1px 2px rgba(0,0,0,.1)}.tags-input .tag{display:inline-block;background:#EEE;color:#444;padding:0 4px;margin:2px;border:1px solid #CCC;border-radius:2px;font:inherit;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;cursor:pointer;transition:all .1s ease}.tags-input .tag.selected{background-color:#777;border-color:#777;color:#EEE}.tags-input .tag.dupe{-webkit-transform:scale3d(1.2,1.2,1.2);transform:scale3d(1.2,1.2,1.2);background-color:#FCC;border-color:#700}.tags-input input{-webkit-appearance:none!important;-moz-appearance:none!important;appearance:none!important;display:inline-block!important;padding:3px;margin:0!important;background:0 0!important;border:none!important;box-shadow:none!important;font:inherit!important;font-size:100%!important;outline:0!important}.tags-input .selected~input{opacity:.3}
2 | /*# sourceMappingURL=tags-input.css.map */
--------------------------------------------------------------------------------
/tags-input.css.map:
--------------------------------------------------------------------------------
1 | {"version":3,"sources":["src/tags-input.less"],"names":[],"mappings":"AAAA,YACC,qBACA,cACA,gBACA,sBACA,WACA,kBACA,yCAAA,CAEA,iBACC,qBACA,gBACA,WACA,cACA,WACA,sBACA,kBACA,aACA,yBACA,AADA,sBACA,AADA,qBACA,AADA,iBACA,eACA,uBAAA,CAEC,0BACA,sBACA,kBACA,UAAA,CAGA,sBACA,uCACA,AADA,+BACA,sBACA,iBAAA,CAIF,kBACC,kCACA,AADA,+BACA,AADA,0BACA,+BACA,YACA,mBACA,yBACA,sBACA,0BACA,uBACA,yBACA,mBAAA,CAGS,4BACT,UAAA,CAAA","file":"tags-input.css","sourcesContent":[".tags-input {\n\tdisplay: inline-block;\n\tpadding: 0 2px;\n\tbackground: #FFF;\n\tborder: 1px solid #CCC;\n\twidth: 16em;\n\tborder-radius: 2px;\n\tbox-shadow: inset 0 1px 2px rgba(0,0,0,0.1);\n\n\t.tag {\n\t\tdisplay: inline-block;\n\t\tbackground: #EEE;\n\t\tcolor: #444;\n\t\tpadding: 0 4px;\n\t\tmargin: 2px;\n\t\tborder: 1px solid #CCC;\n\t\tborder-radius: 2px;\n\t\tfont: inherit;\n\t\tuser-select: none;\n\t\tcursor: pointer;\n\t\ttransition: all 100ms ease;\n\n\t\t&.selected {\n\t\t\tbackground-color: #777;\n\t\t\tborder-color: #777;\n\t\t\tcolor: #EEE;\n\t\t}\n\n\t\t&.dupe {\n\t\t\ttransform: scale3d(1.2,1.2,1.2);\n\t\t\tbackground-color: #FCC;\n\t\t\tborder-color: #700;\n\t\t}\n\t}\n\n\tinput {\n\t\tappearance: none !important;\n\t\tdisplay: inline-block !important;\n\t\tpadding: 3px;\n\t\tmargin: 0 !important;\n\t\tbackground: none !important;\n\t\tborder: none !important;\n\t\tbox-shadow: none !important;\n\t\tfont: inherit !important;\n\t\tfont-size: 100% !important;\n\t\toutline: none !important;\n\t}\n\n\t.selected ~ input {\n\t\topacity: 0.3;\n\t}\n}\n"]}
--------------------------------------------------------------------------------
/tags-input.js:
--------------------------------------------------------------------------------
1 | (function(global,factory){if(typeof define === 'function' && define.amd){define(['exports','module'],factory);}else if(typeof exports !== 'undefined' && typeof module !== 'undefined'){factory(exports,module);}else {var mod={exports:{}};factory(mod.exports,mod);global.tagsInput = mod.exports;}})(this,function(exports,module){'use strict';module.exports = tagsInput;var BACKSPACE=8,TAB=9,ENTER=13,LEFT=37,RIGHT=39,DELETE=46,COMMA=188;var SEPERATOR=',';var COPY_PROPS='placeholder pattern spellcheck autocomplete autocapitalize autofocus accessKey accept lang minLength maxLength required'.split(' ');function tagsInput(input){function createElement(type,name,text,attributes){var el=document.createElement(type);if(name)el.className = name;if(text)el.textContent = text;for(var key in attributes) {el.setAttribute('data-' + key,attributes[key]);}return el;}function $(selector,all){return all === true?Array.prototype.slice.call(base.querySelectorAll(selector)):base.querySelector(selector);}function getValue(){return $('.tag',true).map(function(tag){return tag.textContent;}).concat(base.input.value || []).join(SEPERATOR);}function setValue(value){$('.tag',true).forEach(function(t){return base.removeChild(t);});savePartialInput(value);}function save(){input.value = getValue();input.dispatchEvent(new Event('change'));}function addTag(text){if(~text.indexOf(SEPERATOR))text = text.split(SEPERATOR);if(Array.isArray(text))return text.forEach(addTag);var tag=text && text.trim();if(!tag)return false;if(!input.getAttribute('duplicates')){var _ret=(function(){var exisingTag=$('[data-tag="' + tag + '"]');if(exisingTag){exisingTag.classList.add('dupe');setTimeout(function(){return exisingTag.classList.remove('dupe');},100);return {v:false};}})();if(typeof _ret === 'object')return _ret.v;}base.insertBefore(createElement('span','tag',tag,{tag:tag}),base.input);}function select(el){var sel=$('.selected');if(sel)sel.classList.remove('selected');if(el)el.classList.add('selected');}function setInputWidth(){var last=$('.tag',true).pop(),w=base.offsetWidth;if(!w)return;base.input.style.width = Math.max(w - (last?last.offsetLeft + last.offsetWidth:5) - 5,w / 4) + 'px';}function savePartialInput(value){if(typeof value !== 'string' && !Array.isArray(value)){value = base.input.value;}if(addTag(value) !== false){base.input.value = '';save();setInputWidth();}}function refocus(e){if(e.target.classList.contains('tag'))select(e.target);if(e.target === base.input)return select();base.input.focus();e.preventDefault();return false;}var base=createElement('div','tags-input'),sib=input.nextSibling;input.parentNode[sib?'insertBefore':'appendChild'](base,sib);input.style.cssText = 'position:absolute;left:0;top:-99px;width:1px;height:1px;opacity:0.01;';input.tabIndex = -1;base.input = createElement('input');base.input.setAttribute('type','text');COPY_PROPS.forEach(function(prop){if(input[prop] !== base.input[prop]){base.input[prop] = input[prop];try{delete input[prop];}catch(e) {}}});base.appendChild(base.input);input.addEventListener('focus',function(){base.input.focus();});base.input.addEventListener('focus',function(){base.classList.add('focus');select();});base.input.addEventListener('blur',function(){base.classList.remove('focus');select();savePartialInput();});base.input.addEventListener('keydown',function(e){var el=base.input,key=e.keyCode || e.which,selectedTag=$('.tag.selected'),pos=el.selectionStart === el.selectionEnd && el.selectionStart,last=$('.tag',true).pop();setInputWidth();if(key === ENTER || key === COMMA || key === TAB){if(!el.value && key !== COMMA)return;savePartialInput();}else if(key === DELETE && selectedTag){if(selectedTag.nextSibling !== base.input)select(selectedTag.nextSibling);base.removeChild(selectedTag);setInputWidth();save();}else if(key === BACKSPACE){if(selectedTag){select(selectedTag.previousSibling);base.removeChild(selectedTag);setInputWidth();save();}else if(last && pos === 0){select(last);}else {return;}}else if(key === LEFT){if(selectedTag){if(selectedTag.previousSibling){select(selectedTag.previousSibling);}}else if(pos !== 0){return;}else {select(last);}}else if(key === RIGHT){if(!selectedTag)return;select(selectedTag.nextSibling);}else {return select();}e.preventDefault();return false;});base.input.addEventListener('input',function(){input.value = getValue();input.dispatchEvent(new Event('input'));});base.input.addEventListener('paste',function(){return setTimeout(savePartialInput,0);});base.addEventListener('mousedown',refocus);base.addEventListener('touchstart',refocus);base.setValue = setValue;base.getValue = getValue;savePartialInput(input.value);}tagsInput.enhance = tagsInput.tagsInput = tagsInput;});
2 | //# sourceMappingURL=tags-input.js.map
--------------------------------------------------------------------------------
/tags-input.js.map:
--------------------------------------------------------------------------------
1 | {"version":3,"sources":["src/tags-input.js"],"names":[],"mappings":"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","file":"tags-input.js","sourceRoot":"src","sourcesContent":["const BACKSPACE = 8,\n\tTAB = 9,\n\tENTER = 13,\n\tLEFT = 37,\n\tRIGHT = 39,\n\tDELETE = 46,\n\tCOMMA = 188;\n\nconst SEPERATOR = ',';\n\nconst COPY_PROPS = 'placeholder pattern spellcheck autocomplete autocapitalize autofocus accessKey accept lang minLength maxLength required'.split(' ');\n\nexport default function tagsInput(input) {\n\tfunction createElement(type, name, text, attributes) {\n\t\tlet el = document.createElement(type);\n\t\tif (name) el.className = name;\n\t\tif (text) el.textContent = text;\n\t\tfor (let key in attributes) {\n\t\t\tel.setAttribute(`data-${key}`, attributes[key]);\n\t\t}\n\t\treturn el;\n\t}\n\n\tfunction $(selector, all) {\n\t\treturn all===true ? Array.prototype.slice.call(base.querySelectorAll(selector)) : base.querySelector(selector);\n\t}\n\n\tfunction getValue() {\n\t\treturn $('.tag', true)\n\t\t\t.map( tag => tag.textContent )\n\t\t\t.concat(base.input.value || [])\n\t\t\t.join(SEPERATOR);\n\t}\n\n\tfunction setValue(value) {\n\t\t$('.tag', true).forEach( t => base.removeChild(t) );\n\t\tsavePartialInput(value);\n\t}\n\n\tfunction save() {\n\t\tinput.value = getValue();\n\t\tinput.dispatchEvent(new Event('change'));\n\t}\n\n\t// Return false if no need to add a tag\n\tfunction addTag(text) {\n\t\t// Add multiple tags if the user pastes in data with SEPERATOR already in it\n\t\tif (~text.indexOf(SEPERATOR)) text = text.split(SEPERATOR);\n\t\tif (Array.isArray(text)) return text.forEach(addTag);\n\n\t\tlet tag = text && text.trim();\n\t\t// Ignore if text is empty\n\t\tif (!tag) return false;\n\n\t\t// For duplicates, briefly highlight the existing tag\n\t\tif (!input.getAttribute('duplicates')) {\n\t\t\tlet exisingTag = $(`[data-tag=\"${tag}\"]`);\n\t\t\tif (exisingTag) {\n\t\t\t\texisingTag.classList.add('dupe');\n\t\t\t\tsetTimeout( () => exisingTag.classList.remove('dupe') , 100);\n\t\t\t\treturn false;\n\t\t\t}\n\t\t}\n\n\t\tbase.insertBefore(\n\t\t\tcreateElement('span', 'tag', tag, { tag }),\n\t\t\tbase.input\n\t\t);\n\t}\n\n\tfunction select(el) {\n\t\tlet sel = $('.selected');\n\t\tif (sel) sel.classList.remove('selected');\n\t\tif (el) el.classList.add('selected');\n\t}\n\n\tfunction setInputWidth() {\n\t\tlet last = $('.tag',true).pop(),\n\t\t\tw = base.offsetWidth;\n\t\tif (!w) return;\n\t\tbase.input.style.width = Math.max(\n\t\t\tw - (last ? (last.offsetLeft+last.offsetWidth) : 5) - 5,\n\t\t\tw/4\n\t\t) + 'px';\n\t}\n\n\tfunction savePartialInput(value) {\n\t\tif (typeof value!=='string' && !Array.isArray(value)) {\n\t\t\t// If the base input does not contain a value, default to the original element passed\n\t\t\tvalue = base.input.value;\n\t\t}\n\t\tif (addTag(value)!==false) {\n\t\t\tbase.input.value = '';\n\t\t\tsave();\n\t\t\tsetInputWidth();\n\t\t}\n\t}\n\n\tfunction refocus(e) {\n\t\tif (e.target.classList.contains('tag')) select(e.target);\n\t\tif (e.target===base.input) return select();\n\t\tbase.input.focus();\n\t\te.preventDefault();\n\t\treturn false;\n\t}\n\n\tlet base = createElement('div', 'tags-input'),\n\t\tsib = input.nextSibling;\n\tinput.parentNode[sib?'insertBefore':'appendChild'](base, sib);\n\n\tinput.style.cssText = 'position:absolute;left:0;top:-99px;width:1px;height:1px;opacity:0.01;';\n\tinput.tabIndex = -1;\n\n\tbase.input = createElement('input');\n\tbase.input.setAttribute('type', 'text');\n\tCOPY_PROPS.forEach( prop => {\n\t\tif (input[prop]!==base.input[prop]) {\n\t\t\tbase.input[prop] = input[prop];\n\t\t\ttry { delete input[prop]; }catch(e){}\n\t\t}\n\t});\n\tbase.appendChild(base.input);\n\n\tinput.addEventListener('focus', () => {\n\t\tbase.input.focus();\n\t});\n\n\tbase.input.addEventListener('focus', () => {\n\t\tbase.classList.add('focus');\n\t\tselect();\n\t});\n\n\tbase.input.addEventListener('blur', () => {\n\t\tbase.classList.remove('focus');\n\t\tselect();\n\t\tsavePartialInput();\n\t});\n\n\tbase.input.addEventListener('keydown', e => {\n\t\tlet el = base.input,\n\t\t\tkey = e.keyCode || e.which,\n\t\t\tselectedTag = $('.tag.selected'),\n\t\t\tpos = el.selectionStart===el.selectionEnd && el.selectionStart,\n\t\t\tlast = $('.tag',true).pop();\n\n\t\tsetInputWidth();\n\n\t\tif (key===ENTER || key===COMMA || key===TAB) {\n\t\t\tif (!el.value && key!==COMMA) return;\n\t\t\tsavePartialInput();\n\t\t}\n\t\telse if (key===DELETE && selectedTag) {\n\t\t\tif (selectedTag.nextSibling!==base.input) select(selectedTag.nextSibling);\n\t\t\tbase.removeChild(selectedTag);\n\t\t\tsetInputWidth();\n\t\t\tsave();\n\t\t}\n\t\telse if (key===BACKSPACE) {\n\t\t\tif (selectedTag) {\n\t\t\t\tselect(selectedTag.previousSibling);\n\t\t\t\tbase.removeChild(selectedTag);\n\t\t\t\tsetInputWidth();\n\t\t\t\tsave();\n\t\t\t}\n\t\t\telse if (last && pos===0) {\n\t\t\t\tselect(last);\n\t\t\t}\n\t\t\telse {\n\t\t\t\treturn;\n\t\t\t}\n\t\t}\n\t\telse if (key===LEFT) {\n\t\t\tif (selectedTag) {\n\t\t\t\tif (selectedTag.previousSibling) {\n\t\t\t\t\tselect(selectedTag.previousSibling);\n\t\t\t\t}\n\t\t\t}\n\t\t\telse if (pos!==0) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t\telse {\n\t\t\t\tselect(last);\n\t\t\t}\n\t\t}\n\t\telse if (key===RIGHT) {\n\t\t\tif (!selectedTag) return;\n\t\t\tselect(selectedTag.nextSibling);\n\t\t}\n\t\telse {\n\t\t\treturn select();\n\t\t}\n\n\t\te.preventDefault();\n\t\treturn false;\n\t});\n\n\t// Proxy \"input\" (live change) events , update the first tag live as the user types\n\t// This means that users who only want one thing don't have to enter commas\n\tbase.input.addEventListener('input', () => {\n\t\tinput.value = getValue();\n\t\tinput.dispatchEvent(new Event('input'));\n\t});\n\n\t// One tick after pasting, parse pasted text as CSV:\n\tbase.input.addEventListener('paste', () => setTimeout(savePartialInput, 0));\n\n\tbase.addEventListener('mousedown', refocus);\n\tbase.addEventListener('touchstart', refocus);\n\n\tbase.setValue = setValue;\n\tbase.getValue = getValue;\n\n\t// Add tags for existing values\n\tsavePartialInput(input.value);\n}\n\n// make life easier:\ntagsInput.enhance = tagsInput.tagsInput = tagsInput;\n"]}
--------------------------------------------------------------------------------