diff --git a/.babelrc b/.babelrc deleted file mode 100644 index e60dc13..0000000 --- a/.babelrc +++ /dev/null @@ -1,6 +0,0 @@ -{ - "modules": "umd", - "loose": "all", - "compact": true, - "comments": false -} diff --git a/.editorconfig b/.editorconfig index 9c378bd..f2fd6b8 100644 --- a/.editorconfig +++ b/.editorconfig @@ -1,15 +1,17 @@ +# EditorConfig is awesome: http://EditorConfig.org + +# top-most EditorConfig file root = true +# Unix-style newlines with a newline ending every file +# Tab indent, JS style [*] -indent_style = tab end_of_line = lf -charset = utf-8 -trim_trailing_whitespace = true insert_final_newline = true +indent_size = 2 +indent_style = tab -[{package.json,.*rc,*.yml}] +# Circle YAML files need to have spaces not tabs +[*.yml] indent_style = space indent_size = 2 - -[*.md] -trim_trailing_whitespace = false diff --git a/.eslintrc.json b/.eslintrc.json new file mode 100644 index 0000000..9dfdcb9 --- /dev/null +++ b/.eslintrc.json @@ -0,0 +1,37 @@ +{ + "env": { + "browser": true, + "commonjs": true, + "es6": true, + "node": true, + "mocha": true + }, + "extends": "eslint:recommended", + "parserOptions": { + "ecmaVersion": 2017 + }, + "globals": { + "mixpanel": true, + "serverVars": true, + "avkind": true, + "kind": true, + "Stripe": true + }, + "plugins": [ + "must-use-await" + ], + "rules": { + "curly": ["error", "all"], + "indent": [ + "error", + "tab" + ], + "must-use-await/must-use-await": 1, // 1 warn, 2 error + "linebreak-style": "off", + "quotes": "off", + "no-console": "off", + "semi": "off", + "no-unused-vars": "off", + "no-debugger": "off" + } +} \ No newline at end of file diff --git a/.jshintrc b/.jshintrc deleted file mode 100644 index 7d2a047..0000000 --- a/.jshintrc +++ /dev/null @@ -1,4 +0,0 @@ -{ - "esnext": true, - "browser": true -} diff --git a/LICENSE b/LICENSE deleted file mode 100644 index 4ff8603..0000000 --- a/LICENSE +++ /dev/null @@ -1,20 +0,0 @@ -The MIT License (MIT) - -Copyright (c) 2014 Jason Miller - -Permission is hereby granted, free of charge, to any person obtaining a copy of -this software and associated documentation files (the "Software"), to deal in -the Software without restriction, including without limitation the rights to -use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of -the Software, and to permit persons to whom the Software is furnished to do so, -subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS -FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR -COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER -IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN -CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. \ No newline at end of file diff --git a/README.md b/README.md index 80381e8..ece5b22 100644 --- a/README.md +++ b/README.md @@ -1,35 +1,12 @@ -tags-input -========== +## A fork of [tags-input](https://github.com/developit/tags-input) -[![NPM Version](http://img.shields.io/npm/v/tags-input.svg?style=flat)](https://www.npmjs.org/package/tags-input) -[![Bower Version](http://img.shields.io/bower/v/tags-input.svg?style=flat)](http://bower.io/search/?q=tags-input) -[![Gitter Room](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/developit/tags-input) +Slowly refactoring this module to add: -**Features:** + - Plain CommonJS / ES2017 / SASS and eslint. + - Unminified variables, code run through [prettier](https://github.com/prettier/prettier-eslint-cli). + - Unit tests -- I said `` should be a thing. -- With full keyboard, mouse and focus support. -- Works with HTML5 `pattern` and `placeholder` attributes, too! -- 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. -- Using [preact](https://github.com/developit/preact)? (or react?) There's a wrapper called [preact-token-input](https://github.com/developit/preact-token-input) -- Works in modern browsers and IE10+ - -**Screenshot:** - -> ![screenshot](http://cl.ly/image/3M3U1h1s2y0v/tags-screenshot.png) - -[JSFiddle Demo](http://jsfiddle.net/developit/d5w4jpxq/) - ---- - - -Examples -======== - -It's easy to use! In addition to the example code, you'll also need to -include `tags-input.css` - I didn't bundle it because that's a bit gross. - -**CommonJS:** +## Usage ```js var tagsInput = require('tags-input'); @@ -44,21 +21,7 @@ document.body.appendChild(tags); tagsInput(document.querySelector('input[type="tags"]')); // or just enhance all tag inputs on the page: -[].forEach.call(document.querySelectorAll('input[type="tags"]'), tagsInput); -``` - -**HTML Example:** - -```html - - - -
- -
- - +document.querySelectorAll('input[type="tags"]').forEach(function(element){ + tagsInput(element) +}); ``` diff --git a/bower.json b/bower.json deleted file mode 100644 index 3cd2bf7..0000000 --- a/bower.json +++ /dev/null @@ -1,30 +0,0 @@ -{ - "name": "tags-input", - "version": "1.0.2", - "homepage": "https://github.com/developit/tags-input", - "authors": [ - "Jason Miller " - ], - "description": " like magic.", - "main": "tags-input.js,tags-input.css", - "moduleType": [ - "amd", - "node", - "globals" - ], - "keywords": [ - "tags", - "input", - "polyfill" - ], - "license": "MIT", - "ignore": [ - "**/.*", - "**/*.min.js", - "src", - "bower_components", - "LICENSE", - "package.json", - "README.md" - ] -} diff --git a/index.html b/index.html deleted file mode 100644 index c049cb5..0000000 --- a/index.html +++ /dev/null @@ -1,34 +0,0 @@ - - - - - - - - -
- - - - - - -
- - diff --git a/index.js b/index.js new file mode 100644 index 0000000..92d06b8 --- /dev/null +++ b/index.js @@ -0,0 +1,255 @@ +var SEPERATOR = require("./seperator.js"); + +const BACKSPACE = 8, + TAB = 9, + ENTER = 13, + LEFT = 37, + RIGHT = 39, + DELETE = 46, + COMMA = 188; + +const COPY_PROPS = [ + "placeholder", + "pattern", + "spellcheck", + "autocomplete", + "autocapitalize", + "autofocus", + "accessKey", + "accept", + "lang", + "minLength", + "maxLength", + "required" +]; + +function tagsInput(input) { + function createElement(type, name, text, attributes) { + let element = document.createElement(type); + if (name) element.className = name; + if (text) element.textContent = text; + for (let key in attributes) { + element.setAttribute(`data-${key}`, attributes[key]); + } + return element; + } + + function select(selector, all) { + if (all) { + return document.querySelectorAll(selector); + } + return document.querySelector(selector); + } + + function getValue() { + return select(".tag", true) + .map(tag => tag.textContent) + .concat(document.input.value || []) + .join(SEPERATOR); + } + + function setValue(value) { + select(".tag", true).forEach(t => document.removeChild(t)); + savePartialInput(value); + } + + function save() { + input.value = getValue(); + input.dispatchEvent(new Event("change")); + } + + // Return false if no need to add a tag + function addTag(text) { + // Add multiple tags if the user pastes in data with SEPERATOR already in it + if (text.includes(SEPERATOR)) { + text = text.split(SEPERATOR); + } + if (Array.isArray(text)) { + return text.forEach(addTag); + } + + let tag = text && text.trim(); + // Ignore if text is empty + if (!tag) { + return false; + } + + // Don't add if it's invalid (eg, for pattern=) + if (!document.input.checkValidity()) { + return false; + } + + // For duplicates, briefly highlight the existing tag + if (!input.getAttribute("duplicates")) { + let existingTag = select(`[data-tag="${tag}"]`); + if (existingTag) { + existingTag.classList.add("dupe"); + setTimeout(() => existingTag.classList.remove("dupe"), 100); + return false; + } + } + + document.insertBefore( + createElement("span", "tag", tag, { tag }), + document.input + ); + } + + function select(element) { + let selectedElements = select(".selected"); + if (selectedElements) selectedElements.classList.remove("selected"); + if (element) element.classList.add("selected"); + } + + function setInputWidth() { + let last = select(".tag", true).pop(), + width = document.offsetWidth; + if (!width) return; + document.input.style.width = + Math.max(width - (last ? last.offsetLeft + last.offsetWidth : 5) - 5, width / 4) + + "px"; + } + + function savePartialInput(value) { + if (typeof value !== "string" && !Array.isArray(value)) { + // If the document input does not contain a value, default to the original element passed + value = document.input.value; + } + if (addTag(value) !== false) { + document.input.value = ""; + save(); + setInputWidth(); + } + } + + function refocus(event) { + if (event.target.classList.contains("tag")) select(event.target); + if (event.target === document.input) return select(); + document.input.focus(); + event.preventDefault(); + return false; + } + + function caretAtStart(element) { + try { + return element.selectionStart === 0 && element.selectionEnd === 0; + } catch (event) { + return element.value === ""; + } + } + + let document = createElement("div", "tags-input"), + sib = input.nextSibling; + + input.parentNode[sib ? "insertBefore" : "appendChild"](document, sib); + + input.style.cssText = "position:absolute;left:0;top:-99px;width:1px;height:1px;opacity:0.01;"; + input.tabIndex = -1; + + let inputType = input.getAttribute("type"); + if (!inputType || inputType === "tags") { + inputType = "text"; + } + document.input = createElement("input"); + document.input.setAttribute("type", inputType); + COPY_PROPS.forEach(prop => { + if (input[prop] !== document.input[prop]) { + document.input[prop] = input[prop]; + try { + delete input[prop]; + } catch (event) {} + } + }); + document.appendChild(document.input); + + input.addEventListener("focus", () => { + document.input.focus(); + }); + + document.input.addEventListener("focus", () => { + document.classList.add("focus"); + select(); + }); + + document.input.addEventListener("blur", () => { + document.classList.remove("focus"); + select(); + savePartialInput(); + }); + + document.input.addEventListener("keydown", event => { + let element = document.input, + key = event.keyCode || event.which, + selectedTag = select(".tag.selected"), + atStart = caretAtStart(element), + last = select(".tag", true).pop(); + + setInputWidth(); + + if (key === ENTER || key === COMMA || key === TAB) { + if (!element.value && key !== COMMA) return; + savePartialInput(); + } else if (key === DELETE && selectedTag) { + if (selectedTag.nextSibling !== document.input) + select(selectedTag.nextSibling); + document.removeChild(selectedTag); + setInputWidth(); + save(); + } else if (key === BACKSPACE) { + if (selectedTag) { + select(selectedTag.previousSibling); + document.removeChild(selectedTag); + setInputWidth(); + save(); + } else if (last && atStart) { + select(last); + } else { + return; + } + } else if (key === LEFT) { + if (selectedTag) { + if (selectedTag.previousSibling) { + select(selectedTag.previousSibling); + } + } else if (!atStart) { + return; + } else { + select(last); + } + } else if (key === RIGHT) { + if (!selectedTag) return; + select(selectedTag.nextSibling); + } else { + return select(); + } + + event.preventDefault(); + return false; + }); + + // Proxy "input" (live change) events , update the first tag live as the user types + // This means that users who only want one thing don't have to enter commas + document.input.addEventListener("input", () => { + input.value = getValue(); + input.dispatchEvent(new Event("input")); + }); + + // One tick after pasting, parse pasted text as CSV: + document.input.addEventListener("paste", () => + setTimeout(savePartialInput, 0) + ); + + document.addEventListener("mousedown", refocus); + document.addEventListener("touchstart", refocus); + + document.setValue = setValue; + document.getValue = getValue; + + // Add tags for existing values + savePartialInput(input.value); +} + +// make life easier: +tagsInput.enhance = tagsInput.tagsInput = tagsInput; + +module.exports = tagsInput; diff --git a/src/tags-input.less b/index.sass similarity index 100% rename from src/tags-input.less rename to index.sass diff --git a/package.json b/package.json index eff354e..70b4e0e 100644 --- a/package.json +++ b/package.json @@ -1,28 +1,17 @@ { - "name": "tags-input", - "version": "1.1.1", - "main": "tags-input.js", - "description": " like magic.", - "scripts": { - "build": "npm run transpile && npm run less && npm run size", - "transpile": "babel src --source-root src -s -d .", - "less": "lessc --clean-css --source-map --source-map-less-inline --autoprefix=\"last 2 versions\" src/tags-input.less tags-input.css", - "size": "echo \"gzip size: $(pretty-bytes $(gzip-size $npm_package_main))\"", - "test": "jshint src/**.js", - "prepublish": "npm run build", - "release": "npm run build && git commit -am $npm_package_version && git tag $npm_package_version && git push && git push --tags && npm publish" - }, - "repository": { - "type": "git", - "url": "git://github.com/developit/tags-input.git" - }, - "devDependencies": { - "babel": "^5.8.21", - "gzip-size": "^3.0.0", - "jshint": "^2.8.0", - "less": "^2.5.1", - "less-plugin-autoprefix": "^1.4.2", - "less-plugin-clean-css": "^1.5.1", - "pretty-bytes": "^2.0.1" - } + "name": "@mikemaccana/tags-input", + "version": "2.0.1", + "main": "tags-input.js", + "description": "Refactor of @developit's tags input.", + "scripts": { + "test": "mocha" + }, + "license": "MIT", + "repository": { + "type": "git", + "url": "git://github.com/mikemaccana/tags-input.git" + }, + "devDependencies": { + "dedent-js": "^1.0.1" + } } diff --git a/seperator.js b/seperator.js new file mode 100644 index 0000000..6339ab3 --- /dev/null +++ b/seperator.js @@ -0,0 +1,4 @@ +// Either of commma, space or newline, followed by 0 or more spaces. +const SEPERATOR = /[, \n] */; + +module.exports = SEPERATOR; \ No newline at end of file diff --git a/src/tags-input.js b/src/tags-input.js deleted file mode 100644 index 4f5e07a..0000000 --- a/src/tags-input.js +++ /dev/null @@ -1,233 +0,0 @@ -const BACKSPACE = 8, - TAB = 9, - ENTER = 13, - LEFT = 37, - RIGHT = 39, - DELETE = 46, - COMMA = 188; - -const SEPERATOR = ','; - -const COPY_PROPS = 'placeholder pattern spellcheck autocomplete autocapitalize autofocus accessKey accept lang minLength maxLength required'.split(' '); - -export default function tagsInput(input) { - function createElement(type, name, text, attributes) { - let el = document.createElement(type); - if (name) el.className = name; - if (text) el.textContent = text; - for (let 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( tag => tag.textContent ) - .concat(base.input.value || []) - .join(SEPERATOR); - } - - function setValue(value) { - $('.tag', true).forEach( t => base.removeChild(t) ); - savePartialInput(value); - } - - function save() { - input.value = getValue(); - input.dispatchEvent(new Event('change')); - } - - // Return false if no need to add a tag - function addTag(text) { - // Add multiple tags if the user pastes in data with SEPERATOR already in it - if (~text.indexOf(SEPERATOR)) text = text.split(SEPERATOR); - if (Array.isArray(text)) return text.forEach(addTag); - - let tag = text && text.trim(); - // Ignore if text is empty - if (!tag) return false; - - // For duplicates, briefly highlight the existing tag - if (!input.getAttribute('duplicates')) { - let exisingTag = $(`[data-tag="${tag}"]`); - if (exisingTag) { - exisingTag.classList.add('dupe'); - setTimeout( () => exisingTag.classList.remove('dupe') , 100); - return false; - } - } - - base.insertBefore( - createElement('span', 'tag', tag, { tag }), - base.input - ); - } - - function select(el) { - let sel = $('.selected'); - if (sel) sel.classList.remove('selected'); - if (el) el.classList.add('selected'); - } - - function setInputWidth() { - let 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)) { - // If the base input does not contain a value, default to the original element passed - 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; - } - - function caretAtStart(el) { - try { - return el.selectionStart === 0 && el.selectionEnd === 0; - } - catch(e) { - return el.value === ''; - } - } - - - let 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; - - let inputType = input.getAttribute('type'); - if (!inputType || inputType === 'tags') { - inputType = 'text'; - } - base.input = createElement('input'); - base.input.setAttribute('type', inputType); - COPY_PROPS.forEach( 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', () => { - base.input.focus(); - }); - - base.input.addEventListener('focus', () => { - base.classList.add('focus'); - select(); - }); - - base.input.addEventListener('blur', () => { - base.classList.remove('focus'); - select(); - savePartialInput(); - }); - - base.input.addEventListener('keydown', e => { - let el = base.input, - key = e.keyCode || e.which, - selectedTag = $('.tag.selected'), - atStart = caretAtStart(el), - 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 && atStart) { - select(last); - } - else { - return; - } - } - else if (key===LEFT) { - if (selectedTag) { - if (selectedTag.previousSibling) { - select(selectedTag.previousSibling); - } - } - else if (!atStart) { - return; - } - else { - select(last); - } - } - else if (key===RIGHT) { - if (!selectedTag) return; - select(selectedTag.nextSibling); - } - else { - return select(); - } - - e.preventDefault(); - return false; - }); - - // Proxy "input" (live change) events , update the first tag live as the user types - // This means that users who only want one thing don't have to enter commas - base.input.addEventListener('input', () => { - input.value = getValue(); - input.dispatchEvent(new Event('input')); - }); - - // One tick after pasting, parse pasted text as CSV: - base.input.addEventListener('paste', () => setTimeout(savePartialInput, 0)); - - base.addEventListener('mousedown', refocus); - base.addEventListener('touchstart', refocus); - - base.setValue = setValue; - base.getValue = getValue; - - // Add tags for existing values - savePartialInput(input.value); -} - -// make life easier: -tagsInput.enhance = tagsInput.tagsInput = tagsInput; diff --git a/tags-input.css b/tags-input.css deleted file mode 100644 index ef4477b..0000000 --- a/tags-input.css +++ /dev/null @@ -1,2 +0,0 @@ -.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} -/*# sourceMappingURL=tags-input.css.map */ \ No newline at end of file diff --git a/tags-input.css.map b/tags-input.css.map deleted file mode 100644 index a64b6a0..0000000 --- a/tags-input.css.map +++ /dev/null @@ -1 +0,0 @@ -{"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"]} \ No newline at end of file diff --git a/tags-input.js b/tags-input.js deleted file mode 100644 index 7abf0e5..0000000 --- a/tags-input.js +++ /dev/null @@ -1,2 +0,0 @@ -(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;}); -//# sourceMappingURL=tags-input.js.map \ No newline at end of file diff --git a/tags-input.js.map b/tags-input.js.map deleted file mode 100644 index 29ab320..0000000 --- a/tags-input.js.map +++ /dev/null @@ -1 +0,0 @@ -{"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"]} \ No newline at end of file diff --git a/test/mocha.opts b/test/mocha.opts new file mode 100644 index 0000000..b1374cc --- /dev/null +++ b/test/mocha.opts @@ -0,0 +1,2 @@ +--ui tdd +--bail diff --git a/test/tests.js b/test/tests.js new file mode 100644 index 0000000..0ee6db9 --- /dev/null +++ b/test/tests.js @@ -0,0 +1,63 @@ +// Tests. Mocha TDD/assert style. See +// http://visionmedia.github.com/mocha/ +// http://nodejs.org/docs/latest/api/assert.html + +var assert = require('assert'), + SEPERATOR = require('../seperator.js'), + dedent = require('dedent-js'), + log = console.log.bind(console) + +var splitText = function(text){ + return text.split(SEPERATOR) +} + +suite('Splits strings to arrays', function(){ + this.timeout(5 * 1000); + test('cleans comma', function(){ + var input = 'one.com two.com three.com' + var actual = splitText(input) + var expected = ['one.com', 'two.com', 'three.com'] + assert.deepEqual(actual, expected) + }); + + test('cleans comma and space', function(){ + var input = 'one.com, two.com, three.com' + var actual = splitText(input) + var expected = ['one.com', 'two.com', 'three.com'] + assert.deepEqual(actual, expected) + }); + + test('cleans comma only', function(){ + var input = 'one.com,two.com,three.com' + var actual = splitText(input) + var expected = ['one.com', 'two.com', 'three.com'] + assert.deepEqual(actual, expected) + }); + + test('cleans newline', function(){ + var input = dedent(` + one.com + two.com + three.com + `) + var actual = splitText(input) + var expected = ['one.com', 'two.com', 'three.com'] + assert.deepEqual(actual, expected) + }); + + test('cleans spaces', function(){ + var input = 'one.com two.com three.com' + var actual = splitText(input) + var expected = ['one.com', 'two.com', 'three.com'] + assert.deepEqual(actual, expected) + }); + + test('cleans multiple spaces', function(){ + var input = 'one.com two.com three.com' + var actual = splitText(input) + var expected = ['one.com', 'two.com', 'three.com'] + assert.deepEqual(actual, expected) + }); + + +}); \ No newline at end of file