From 559a93bcb678a824ff423936028d96db7399822b Mon Sep 17 00:00:00 2001 From: Kevin Brown Date: Mon, 20 Oct 2014 19:15:37 -0400 Subject: [PATCH] Added basic implementation of tags Tags no longer takes an array, as pre-existing tags should already exist as options in the data adapter. A compatibility module will later be added to convert tag data that is passed in to array data. Tags allow for users to enter their own options, which will be added to the beginning of the results list. --- dist/js/select2.amd.full.js | 120 ++++++++++++++++++++++++++++------ dist/js/select2.amd.js | 120 ++++++++++++++++++++++++++++------ dist/js/select2.full.js | 120 ++++++++++++++++++++++++++++------ dist/js/select2.full.min.js | 2 +- dist/js/select2.js | 120 ++++++++++++++++++++++++++++------ dist/js/select2.min.js | 2 +- docs/examples.html | 33 ++++++++++ src/js/select2/data/array.js | 19 ------ src/js/select2/data/select.js | 31 +++++++++ src/js/select2/data/tags.js | 62 ++++++++++++++++++ src/js/select2/defaults.js | 7 +- 11 files changed, 534 insertions(+), 102 deletions(-) create mode 100644 src/js/select2/data/tags.js diff --git a/dist/js/select2.amd.full.js b/dist/js/select2.amd.full.js index 0fe22c4f..b94961a1 100644 --- a/dist/js/select2.amd.full.js +++ b/dist/js/select2.amd.full.js @@ -879,6 +879,16 @@ define('select2/data/select',[ SelectAdapter.prototype.select = function (data) { var self = this; + // Create items marked as tags + if (data._tag === true) { + // Clear the tag flag from it + delete data._tag; + + // Create and add the option + var $option = this.option(data); + this.$element.append($option); + } + if (this.$element.prop('multiple')) { this.current(function (currentData) { var val = []; @@ -901,6 +911,7 @@ define('select2/data/select',[ var val = data.id; this.$element.val(val); + this.$element.trigger('change'); } }; @@ -924,6 +935,7 @@ define('select2/data/select',[ } self.$element.val(val); + self.$element.trigger('change'); }); }; @@ -967,6 +979,25 @@ define('select2/data/select',[ callback(data); }; + SelectAdapter.prototype.option = function (data) { + var $option = $(''); + + $option.text(data.text); + $option.val(data.id); + $option.prop('disabled', data.disabled || false); + + // Get any automatically generated data values + var detectedData = this.item($option); + + // Merge it with the already present data + var combinedData = $.extend({}, data, detectedData); + + // Override the option's data with the combined data + $option.data('data', combinedData); + + return $option; + }; + SelectAdapter.prototype.item = function ($option) { var data = $option.data('data'); @@ -1074,25 +1105,6 @@ define('select2/data/array',[ ArrayAdapter.__super__.select.call(this, data); }; - ArrayAdapter.prototype.option = function (data) { - var $option = $(''); - - $option.text(data.text); - $option.val(data.id); - $option.prop('disabled', data.disabled || false); - - // Get any automatically generated data values - var detectedData = this.item($option); - - // Merge it with the already present data - var combinedData = $.extend({}, data, detectedData); - - // Override the option's data with the combined data - $option.data('data', combinedData); - - return $option; - }; - ArrayAdapter.prototype.query = function (params, callback) { var matches = []; var self = this; @@ -1157,6 +1169,69 @@ define('select2/data/ajax',[ return AjaxAdapter; }); +define('select2/data/tags',[ + +], function () { + function Tags (decorated, $element, options) { + var tags = options.get('tags'); + + decorated.call(this, $element, options); + } + + Tags.prototype.query = function (decorated, params, callback) { + var self = this; + + if (params.term == null || params.term === '' || params.page != null) { + decorated.call(this, params, callback); + return; + } + + function wrapper (data, child) { + for (var i = 0; i < data.length; i++) { + var option = data[i]; + + var checkChildren = ( + option.children != null && !wrapper(option.children, true) + ); + + var checkText = option.text === params.term; + + if (checkText || checkChildren) { + if (child) { + return false; + } + + callback(data); + + return; + } + } + + if (child) { + return true; + } + + var tag = self.createTag(params); + tag._tag = true; + + data.unshift(tag); + + callback(data); + } + + decorated.call(this, params, wrapper); + }; + + Tags.prototype.createTag = function (decorated, params) { + return { + id: params.term, + text: params.term + }; + }; + + return Tags; +}); + define('select2/dropdown',[ './utils' ], function (Utils) { @@ -1256,13 +1331,14 @@ define('select2/defaults',[ './data/select', './data/array', './data/ajax', + './data/tags', './dropdown', './dropdown/search' ], function (ResultsList, SingleSelection, MultipleSelection, Placeholder, Utils, - SelectData, ArrayData, AjaxData, + SelectData, ArrayData, AjaxData, Tags, Dropdown, Search) { function Defaults () { this.reset(); @@ -1281,6 +1357,10 @@ define('select2/defaults',[ } } + if (options.tags != null) { + options.dataAdapter = Utils.Decorate(options.dataAdapter, Tags); + } + if (options.resultsAdapter == null) { options.resultsAdapter = ResultsList; } diff --git a/dist/js/select2.amd.js b/dist/js/select2.amd.js index 0fe22c4f..b94961a1 100644 --- a/dist/js/select2.amd.js +++ b/dist/js/select2.amd.js @@ -879,6 +879,16 @@ define('select2/data/select',[ SelectAdapter.prototype.select = function (data) { var self = this; + // Create items marked as tags + if (data._tag === true) { + // Clear the tag flag from it + delete data._tag; + + // Create and add the option + var $option = this.option(data); + this.$element.append($option); + } + if (this.$element.prop('multiple')) { this.current(function (currentData) { var val = []; @@ -901,6 +911,7 @@ define('select2/data/select',[ var val = data.id; this.$element.val(val); + this.$element.trigger('change'); } }; @@ -924,6 +935,7 @@ define('select2/data/select',[ } self.$element.val(val); + self.$element.trigger('change'); }); }; @@ -967,6 +979,25 @@ define('select2/data/select',[ callback(data); }; + SelectAdapter.prototype.option = function (data) { + var $option = $(''); + + $option.text(data.text); + $option.val(data.id); + $option.prop('disabled', data.disabled || false); + + // Get any automatically generated data values + var detectedData = this.item($option); + + // Merge it with the already present data + var combinedData = $.extend({}, data, detectedData); + + // Override the option's data with the combined data + $option.data('data', combinedData); + + return $option; + }; + SelectAdapter.prototype.item = function ($option) { var data = $option.data('data'); @@ -1074,25 +1105,6 @@ define('select2/data/array',[ ArrayAdapter.__super__.select.call(this, data); }; - ArrayAdapter.prototype.option = function (data) { - var $option = $(''); - - $option.text(data.text); - $option.val(data.id); - $option.prop('disabled', data.disabled || false); - - // Get any automatically generated data values - var detectedData = this.item($option); - - // Merge it with the already present data - var combinedData = $.extend({}, data, detectedData); - - // Override the option's data with the combined data - $option.data('data', combinedData); - - return $option; - }; - ArrayAdapter.prototype.query = function (params, callback) { var matches = []; var self = this; @@ -1157,6 +1169,69 @@ define('select2/data/ajax',[ return AjaxAdapter; }); +define('select2/data/tags',[ + +], function () { + function Tags (decorated, $element, options) { + var tags = options.get('tags'); + + decorated.call(this, $element, options); + } + + Tags.prototype.query = function (decorated, params, callback) { + var self = this; + + if (params.term == null || params.term === '' || params.page != null) { + decorated.call(this, params, callback); + return; + } + + function wrapper (data, child) { + for (var i = 0; i < data.length; i++) { + var option = data[i]; + + var checkChildren = ( + option.children != null && !wrapper(option.children, true) + ); + + var checkText = option.text === params.term; + + if (checkText || checkChildren) { + if (child) { + return false; + } + + callback(data); + + return; + } + } + + if (child) { + return true; + } + + var tag = self.createTag(params); + tag._tag = true; + + data.unshift(tag); + + callback(data); + } + + decorated.call(this, params, wrapper); + }; + + Tags.prototype.createTag = function (decorated, params) { + return { + id: params.term, + text: params.term + }; + }; + + return Tags; +}); + define('select2/dropdown',[ './utils' ], function (Utils) { @@ -1256,13 +1331,14 @@ define('select2/defaults',[ './data/select', './data/array', './data/ajax', + './data/tags', './dropdown', './dropdown/search' ], function (ResultsList, SingleSelection, MultipleSelection, Placeholder, Utils, - SelectData, ArrayData, AjaxData, + SelectData, ArrayData, AjaxData, Tags, Dropdown, Search) { function Defaults () { this.reset(); @@ -1281,6 +1357,10 @@ define('select2/defaults',[ } } + if (options.tags != null) { + options.dataAdapter = Utils.Decorate(options.dataAdapter, Tags); + } + if (options.resultsAdapter == null) { options.resultsAdapter = ResultsList; } diff --git a/dist/js/select2.full.js b/dist/js/select2.full.js index b3491716..e36d3e61 100644 --- a/dist/js/select2.full.js +++ b/dist/js/select2.full.js @@ -10417,6 +10417,16 @@ define('select2/data/select',[ SelectAdapter.prototype.select = function (data) { var self = this; + // Create items marked as tags + if (data._tag === true) { + // Clear the tag flag from it + delete data._tag; + + // Create and add the option + var $option = this.option(data); + this.$element.append($option); + } + if (this.$element.prop('multiple')) { this.current(function (currentData) { var val = []; @@ -10439,6 +10449,7 @@ define('select2/data/select',[ var val = data.id; this.$element.val(val); + this.$element.trigger('change'); } }; @@ -10462,6 +10473,7 @@ define('select2/data/select',[ } self.$element.val(val); + self.$element.trigger('change'); }); }; @@ -10505,6 +10517,25 @@ define('select2/data/select',[ callback(data); }; + SelectAdapter.prototype.option = function (data) { + var $option = $(''); + + $option.text(data.text); + $option.val(data.id); + $option.prop('disabled', data.disabled || false); + + // Get any automatically generated data values + var detectedData = this.item($option); + + // Merge it with the already present data + var combinedData = $.extend({}, data, detectedData); + + // Override the option's data with the combined data + $option.data('data', combinedData); + + return $option; + }; + SelectAdapter.prototype.item = function ($option) { var data = $option.data('data'); @@ -10612,25 +10643,6 @@ define('select2/data/array',[ ArrayAdapter.__super__.select.call(this, data); }; - ArrayAdapter.prototype.option = function (data) { - var $option = $(''); - - $option.text(data.text); - $option.val(data.id); - $option.prop('disabled', data.disabled || false); - - // Get any automatically generated data values - var detectedData = this.item($option); - - // Merge it with the already present data - var combinedData = $.extend({}, data, detectedData); - - // Override the option's data with the combined data - $option.data('data', combinedData); - - return $option; - }; - ArrayAdapter.prototype.query = function (params, callback) { var matches = []; var self = this; @@ -10695,6 +10707,69 @@ define('select2/data/ajax',[ return AjaxAdapter; }); +define('select2/data/tags',[ + +], function () { + function Tags (decorated, $element, options) { + var tags = options.get('tags'); + + decorated.call(this, $element, options); + } + + Tags.prototype.query = function (decorated, params, callback) { + var self = this; + + if (params.term == null || params.term === '' || params.page != null) { + decorated.call(this, params, callback); + return; + } + + function wrapper (data, child) { + for (var i = 0; i < data.length; i++) { + var option = data[i]; + + var checkChildren = ( + option.children != null && !wrapper(option.children, true) + ); + + var checkText = option.text === params.term; + + if (checkText || checkChildren) { + if (child) { + return false; + } + + callback(data); + + return; + } + } + + if (child) { + return true; + } + + var tag = self.createTag(params); + tag._tag = true; + + data.unshift(tag); + + callback(data); + } + + decorated.call(this, params, wrapper); + }; + + Tags.prototype.createTag = function (decorated, params) { + return { + id: params.term, + text: params.term + }; + }; + + return Tags; +}); + define('select2/dropdown',[ './utils' ], function (Utils) { @@ -10794,13 +10869,14 @@ define('select2/defaults',[ './data/select', './data/array', './data/ajax', + './data/tags', './dropdown', './dropdown/search' ], function (ResultsList, SingleSelection, MultipleSelection, Placeholder, Utils, - SelectData, ArrayData, AjaxData, + SelectData, ArrayData, AjaxData, Tags, Dropdown, Search) { function Defaults () { this.reset(); @@ -10819,6 +10895,10 @@ define('select2/defaults',[ } } + if (options.tags != null) { + options.dataAdapter = Utils.Decorate(options.dataAdapter, Tags); + } + if (options.resultsAdapter == null) { options.resultsAdapter = ResultsList; } diff --git a/dist/js/select2.full.min.js b/dist/js/select2.full.min.js index c50c7c60..8fdb32df 100644 --- a/dist/js/select2.full.min.js +++ b/dist/js/select2.full.min.js @@ -1,4 +1,4 @@ var requirejs,require,define;!function(a){function b(a,b){return r.call(a,b)}function c(a,b){var c,d,e,f,g,h,i,j,k,l,m,n=b&&b.split("/"),o=p.map,q=o&&o["*"]||{};if(a&&"."===a.charAt(0))if(b){for(n=n.slice(0,n.length-1),a=a.split("/"),g=a.length-1,p.nodeIdCompat&&t.test(a[g])&&(a[g]=a[g].replace(t,"")),a=n.concat(a),k=0;k0&&(a.splice(k-1,2),k-=2)}a=a.join("/")}else 0===a.indexOf("./")&&(a=a.substring(2));if((n||q)&&o){for(c=a.split("/"),k=c.length;k>0;k-=1){if(d=c.slice(0,k).join("/"),n)for(l=n.length;l>0;l-=1)if(e=o[n.slice(0,l).join("/")],e&&(e=e[d])){f=e,h=k;break}if(f)break;!i&&q&&q[d]&&(i=q[d],j=k)}!f&&i&&(f=i,h=j),f&&(c.splice(0,h,f),a=c.join("/"))}return a}function d(b,c){return function(){return k.apply(a,s.call(arguments,0).concat([b,c]))}}function e(a){return function(b){return c(b,a)}}function f(a){return function(b){n[a]=b}}function g(c){if(b(o,c)){var d=o[c];delete o[c],q[c]=!0,j.apply(a,d)}if(!b(n,c)&&!b(q,c))throw new Error("No "+c);return n[c]}function h(a){var b,c=a?a.indexOf("!"):-1;return c>-1&&(b=a.substring(0,c),a=a.substring(c+1,a.length)),[b,a]}function i(a){return function(){return p&&p.config&&p.config[a]||{}}}var j,k,l,m,n={},o={},p={},q={},r=Object.prototype.hasOwnProperty,s=[].slice,t=/\.js$/;l=function(a,b){var d,f=h(a),i=f[0];return a=f[1],i&&(i=c(i,b),d=g(i)),i?a=d&&d.normalize?d.normalize(a,e(b)):c(a,b):(a=c(a,b),f=h(a),i=f[0],a=f[1],i&&(d=g(i))),{f:i?i+"!"+a:a,n:a,pr:i,p:d}},m={require:function(a){return d(a)},exports:function(a){var b=n[a];return"undefined"!=typeof b?b:n[a]={}},module:function(a){return{id:a,uri:"",exports:n[a],config:i(a)}}},j=function(c,e,h,i){var j,k,p,r,s,t,u=[],v=typeof h;if(i=i||c,"undefined"===v||"function"===v){for(e=!e.length&&h.length?["require","exports","module"]:e,s=0;s0&&b-1 in a}function d(a,b,c){if(ab.isFunction(b))return ab.grep(a,function(a,d){return!!b.call(a,d,a)!==c});if(b.nodeType)return ab.grep(a,function(a){return a===b!==c});if("string"==typeof b){if(hb.test(b))return ab.filter(b,a,c);b=ab.filter(b,a)}return ab.grep(a,function(a){return U.call(b,a)>=0!==c})}function e(a,b){for(;(a=a[b])&&1!==a.nodeType;);return a}function f(a){var b=ob[a]={};return ab.each(a.match(nb)||[],function(a,c){b[c]=!0}),b}function g(){$.removeEventListener("DOMContentLoaded",g,!1),a.removeEventListener("load",g,!1),ab.ready()}function h(){Object.defineProperty(this.cache={},0,{get:function(){return{}}}),this.expando=ab.expando+Math.random()}function i(a,b,c){var d;if(void 0===c&&1===a.nodeType)if(d="data-"+b.replace(ub,"-$1").toLowerCase(),c=a.getAttribute(d),"string"==typeof c){try{c="true"===c?!0:"false"===c?!1:"null"===c?null:+c+""===c?+c:tb.test(c)?ab.parseJSON(c):c}catch(e){}sb.set(a,b,c)}else c=void 0;return c}function j(){return!0}function k(){return!1}function l(){try{return $.activeElement}catch(a){}}function m(a,b){return ab.nodeName(a,"table")&&ab.nodeName(11!==b.nodeType?b:b.firstChild,"tr")?a.getElementsByTagName("tbody")[0]||a.appendChild(a.ownerDocument.createElement("tbody")):a}function n(a){return a.type=(null!==a.getAttribute("type"))+"/"+a.type,a}function o(a){var b=Kb.exec(a.type);return b?a.type=b[1]:a.removeAttribute("type"),a}function p(a,b){for(var c=0,d=a.length;d>c;c++)rb.set(a[c],"globalEval",!b||rb.get(b[c],"globalEval"))}function q(a,b){var c,d,e,f,g,h,i,j;if(1===b.nodeType){if(rb.hasData(a)&&(f=rb.access(a),g=rb.set(b,f),j=f.events)){delete g.handle,g.events={};for(e in j)for(c=0,d=j[e].length;d>c;c++)ab.event.add(b,e,j[e][c])}sb.hasData(a)&&(h=sb.access(a),i=ab.extend({},h),sb.set(b,i))}}function r(a,b){var c=a.getElementsByTagName?a.getElementsByTagName(b||"*"):a.querySelectorAll?a.querySelectorAll(b||"*"):[];return void 0===b||b&&ab.nodeName(a,b)?ab.merge([a],c):c}function s(a,b){var c=b.nodeName.toLowerCase();"input"===c&&yb.test(a.type)?b.checked=a.checked:("input"===c||"textarea"===c)&&(b.defaultValue=a.defaultValue)}function t(b,c){var d=ab(c.createElement(b)).appendTo(c.body),e=a.getDefaultComputedStyle?a.getDefaultComputedStyle(d[0]).display:ab.css(d[0],"display");return d.detach(),e}function u(a){var b=$,c=Ob[a];return c||(c=t(a,b),"none"!==c&&c||(Nb=(Nb||ab("