From 5e3b63289cab05471bceeeac8fe8a3ed41b3dc1e Mon Sep 17 00:00:00 2001 From: Kevin Brown Date: Mon, 3 Nov 2014 19:10:36 -0500 Subject: [PATCH] Added infinite scrolling support for AJAX --- dist/js/i18n/en.js | 2 +- dist/js/select2.amd.full.js | 110 +++++++++++++++++++++- dist/js/select2.amd.js | 110 +++++++++++++++++++++- dist/js/select2.full.js | 110 +++++++++++++++++++++- dist/js/select2.full.min.js | 2 +- dist/js/select2.js | 110 +++++++++++++++++++++- dist/js/select2.min.js | 2 +- docs/examples.html | 1 + src/js/select2/core.js | 13 +++ src/js/select2/defaults.js | 14 ++- src/js/select2/dropdown/infiniteScroll.js | 79 ++++++++++++++++ src/js/select2/i18n/en.js | 3 + 12 files changed, 538 insertions(+), 18 deletions(-) create mode 100644 src/js/select2/dropdown/infiniteScroll.js diff --git a/dist/js/i18n/en.js b/dist/js/i18n/en.js index d250115b..b8d2a144 100644 --- a/dist/js/i18n/en.js +++ b/dist/js/i18n/en.js @@ -1 +1 @@ -window.$=window.$||{},function(){$&&$.fn&&$.fn.select2&&$.fn.select2.amd&&(define=$.fn.select2.amd.define,require=$.fn.select2.amd.require),define("select2/i18n/en",[],function(){return{inputTooShort:function(e){var t=e.minimum-e.input.length,n="Please enter "+t+" or more character";return t!=1&&(n+="s"),n},noResults:function(){return"No results found"}}}),require("jquery.select2"),$.fn.select2.amd={define:define,require:require}}(); \ No newline at end of file +window.$=window.$||{},function(){$&&$.fn&&$.fn.select2&&$.fn.select2.amd&&(define=$.fn.select2.amd.define,require=$.fn.select2.amd.require),define("select2/i18n/en",[],function(){return{inputTooShort:function(e){var t=e.minimum-e.input.length,n="Please enter "+t+" or more character";return t!=1&&(n+="s"),n},loadingMore:function(){return"Loading more results…"},noResults:function(){return"No results found"}}}),require("jquery.select2"),$.fn.select2.amd={define:define,require:require}}(); \ No newline at end of file diff --git a/dist/js/select2.amd.full.js b/dist/js/select2.amd.full.js index 5dec9b82..85654f47 100644 --- a/dist/js/select2.amd.full.js +++ b/dist/js/select2.amd.full.js @@ -1551,6 +1551,86 @@ define('select2/dropdown/hidePlaceholder',[ return HidePlaceholder; }); +define('select2/dropdown/infiniteScroll',[ + 'jquery' +], function ($) { + function InfiniteScroll (decorated, $element, options, dataAdapter) { + this.lastParams = {}; + + decorated.call(this, $element, options, dataAdapter); + + this.$loadingMore = this.createLoadingMore(); + this.loading = false; + } + + InfiniteScroll.prototype.append = function (decorated, data) { + this.$loadingMore.remove(); + + decorated.call(this, data); + + if (data.length > 0) { + this.$results.append(this.$loadingMore); + } + + this.loading = false; + }; + + InfiniteScroll.prototype.bind = function (decorated, container, $container) { + var self = this; + + decorated.call(this, container, $container); + + container.on('query', function (params) { + self.lastParams = params; + self.loading = true; + }); + + container.on('query:append', function (params) { + self.lastParams = params; + self.loading = true; + }); + + this.$results.on('scroll', function () { + if (self.loading) { + return; + } + + var currentOffset = self.$results.offset().top + + self.$results.outerHeight(false); + var loadingMoreOffset = self.$loadingMore.offset().top + + self.$loadingMore.outerHeight(false); + + if (currentOffset + 50 >= loadingMoreOffset) { + self.loadMore(); + } + }); + }; + + InfiniteScroll.prototype.loadMore = function () { + this.loading = true; + + var params = $.extend({}, {page: 1}, this.lastParams); + + params.page++; + + this.trigger('query:append', params); + }; + + InfiniteScroll.prototype.createLoadingMore = function () { + var $option = $( + '
  • ' + ); + + var message = this.options.get('translations').get('loadingMore'); + + $option.html(message(this.lastParams)); + + return $option; + }; + + return InfiniteScroll; +}); + define('select2/i18n/en',[],function () { return { inputTooShort: function (args) { @@ -1564,6 +1644,9 @@ define('select2/i18n/en',[],function () { return message; }, + loadingMore: function () { + return 'Loading more results…'; + }, noResults: function () { return 'No results found'; } @@ -1590,13 +1673,14 @@ define('select2/defaults',[ './dropdown', './dropdown/search', './dropdown/hidePlaceholder', + './dropdown/infiniteScroll', './i18n/en' ], function ($, ResultsList, SingleSelection, MultipleSelection, Placeholder, Utils, Translation, SelectData, ArrayData, AjaxData, Tags, MinimumInputLength, - Dropdown, Search, HidePlaceholder, + Dropdown, Search, HidePlaceholder, InfiniteScroll, EnglishTranslation) { function Defaults () { this.reset(); @@ -1606,9 +1690,9 @@ define('select2/defaults',[ options = $.extend({}, this.defaults, options); if (options.dataAdapter == null) { - if (options.ajax) { + if (options.ajax != null) { options.dataAdapter = AjaxData; - } else if (options.data) { + } else if (options.data != null) { options.dataAdapter = ArrayData; } else { options.dataAdapter = SelectData; @@ -1630,6 +1714,13 @@ define('select2/defaults',[ if (options.resultsAdapter == null) { options.resultsAdapter = ResultsList; + if (options.ajax != null) { + options.resultsAdapter = Utils.Decorate( + options.resultsAdapter, + InfiniteScroll + ); + } + if (options.placeholder != null) { options.resultsAdapter = Utils.Decorate( options.resultsAdapter, @@ -1939,6 +2030,10 @@ define('select2/core',[ Select2.prototype._registerResultsEvents = function () { var self = this; + this.results.on('query:append', function (params) { + self.trigger('query:append', params); + }); + this.results.on('selected', function (params) { self.trigger('select', params); @@ -1976,6 +2071,15 @@ define('select2/core',[ }); }); + this.on('query:append', function (params) { + this.data.query(params, function (data) { + self.trigger('results:append', { + data: data, + query: params + }); + }); + }); + this.on('keypress', function (evt) { var key = evt.which; diff --git a/dist/js/select2.amd.js b/dist/js/select2.amd.js index 5dec9b82..85654f47 100644 --- a/dist/js/select2.amd.js +++ b/dist/js/select2.amd.js @@ -1551,6 +1551,86 @@ define('select2/dropdown/hidePlaceholder',[ return HidePlaceholder; }); +define('select2/dropdown/infiniteScroll',[ + 'jquery' +], function ($) { + function InfiniteScroll (decorated, $element, options, dataAdapter) { + this.lastParams = {}; + + decorated.call(this, $element, options, dataAdapter); + + this.$loadingMore = this.createLoadingMore(); + this.loading = false; + } + + InfiniteScroll.prototype.append = function (decorated, data) { + this.$loadingMore.remove(); + + decorated.call(this, data); + + if (data.length > 0) { + this.$results.append(this.$loadingMore); + } + + this.loading = false; + }; + + InfiniteScroll.prototype.bind = function (decorated, container, $container) { + var self = this; + + decorated.call(this, container, $container); + + container.on('query', function (params) { + self.lastParams = params; + self.loading = true; + }); + + container.on('query:append', function (params) { + self.lastParams = params; + self.loading = true; + }); + + this.$results.on('scroll', function () { + if (self.loading) { + return; + } + + var currentOffset = self.$results.offset().top + + self.$results.outerHeight(false); + var loadingMoreOffset = self.$loadingMore.offset().top + + self.$loadingMore.outerHeight(false); + + if (currentOffset + 50 >= loadingMoreOffset) { + self.loadMore(); + } + }); + }; + + InfiniteScroll.prototype.loadMore = function () { + this.loading = true; + + var params = $.extend({}, {page: 1}, this.lastParams); + + params.page++; + + this.trigger('query:append', params); + }; + + InfiniteScroll.prototype.createLoadingMore = function () { + var $option = $( + '
  • ' + ); + + var message = this.options.get('translations').get('loadingMore'); + + $option.html(message(this.lastParams)); + + return $option; + }; + + return InfiniteScroll; +}); + define('select2/i18n/en',[],function () { return { inputTooShort: function (args) { @@ -1564,6 +1644,9 @@ define('select2/i18n/en',[],function () { return message; }, + loadingMore: function () { + return 'Loading more results…'; + }, noResults: function () { return 'No results found'; } @@ -1590,13 +1673,14 @@ define('select2/defaults',[ './dropdown', './dropdown/search', './dropdown/hidePlaceholder', + './dropdown/infiniteScroll', './i18n/en' ], function ($, ResultsList, SingleSelection, MultipleSelection, Placeholder, Utils, Translation, SelectData, ArrayData, AjaxData, Tags, MinimumInputLength, - Dropdown, Search, HidePlaceholder, + Dropdown, Search, HidePlaceholder, InfiniteScroll, EnglishTranslation) { function Defaults () { this.reset(); @@ -1606,9 +1690,9 @@ define('select2/defaults',[ options = $.extend({}, this.defaults, options); if (options.dataAdapter == null) { - if (options.ajax) { + if (options.ajax != null) { options.dataAdapter = AjaxData; - } else if (options.data) { + } else if (options.data != null) { options.dataAdapter = ArrayData; } else { options.dataAdapter = SelectData; @@ -1630,6 +1714,13 @@ define('select2/defaults',[ if (options.resultsAdapter == null) { options.resultsAdapter = ResultsList; + if (options.ajax != null) { + options.resultsAdapter = Utils.Decorate( + options.resultsAdapter, + InfiniteScroll + ); + } + if (options.placeholder != null) { options.resultsAdapter = Utils.Decorate( options.resultsAdapter, @@ -1939,6 +2030,10 @@ define('select2/core',[ Select2.prototype._registerResultsEvents = function () { var self = this; + this.results.on('query:append', function (params) { + self.trigger('query:append', params); + }); + this.results.on('selected', function (params) { self.trigger('select', params); @@ -1976,6 +2071,15 @@ define('select2/core',[ }); }); + this.on('query:append', function (params) { + this.data.query(params, function (data) { + self.trigger('results:append', { + data: data, + query: params + }); + }); + }); + this.on('keypress', function (evt) { var key = evt.which; diff --git a/dist/js/select2.full.js b/dist/js/select2.full.js index 9a6a9e83..20aae814 100644 --- a/dist/js/select2.full.js +++ b/dist/js/select2.full.js @@ -11086,6 +11086,86 @@ define('select2/dropdown/hidePlaceholder',[ return HidePlaceholder; }); +define('select2/dropdown/infiniteScroll',[ + 'jquery' +], function ($) { + function InfiniteScroll (decorated, $element, options, dataAdapter) { + this.lastParams = {}; + + decorated.call(this, $element, options, dataAdapter); + + this.$loadingMore = this.createLoadingMore(); + this.loading = false; + } + + InfiniteScroll.prototype.append = function (decorated, data) { + this.$loadingMore.remove(); + + decorated.call(this, data); + + if (data.length > 0) { + this.$results.append(this.$loadingMore); + } + + this.loading = false; + }; + + InfiniteScroll.prototype.bind = function (decorated, container, $container) { + var self = this; + + decorated.call(this, container, $container); + + container.on('query', function (params) { + self.lastParams = params; + self.loading = true; + }); + + container.on('query:append', function (params) { + self.lastParams = params; + self.loading = true; + }); + + this.$results.on('scroll', function () { + if (self.loading) { + return; + } + + var currentOffset = self.$results.offset().top + + self.$results.outerHeight(false); + var loadingMoreOffset = self.$loadingMore.offset().top + + self.$loadingMore.outerHeight(false); + + if (currentOffset + 50 >= loadingMoreOffset) { + self.loadMore(); + } + }); + }; + + InfiniteScroll.prototype.loadMore = function () { + this.loading = true; + + var params = $.extend({}, {page: 1}, this.lastParams); + + params.page++; + + this.trigger('query:append', params); + }; + + InfiniteScroll.prototype.createLoadingMore = function () { + var $option = $( + '
  • ' + ); + + var message = this.options.get('translations').get('loadingMore'); + + $option.html(message(this.lastParams)); + + return $option; + }; + + return InfiniteScroll; +}); + define('select2/i18n/en',[],function () { return { inputTooShort: function (args) { @@ -11099,6 +11179,9 @@ define('select2/i18n/en',[],function () { return message; }, + loadingMore: function () { + return 'Loading more results…'; + }, noResults: function () { return 'No results found'; } @@ -11125,13 +11208,14 @@ define('select2/defaults',[ './dropdown', './dropdown/search', './dropdown/hidePlaceholder', + './dropdown/infiniteScroll', './i18n/en' ], function ($, ResultsList, SingleSelection, MultipleSelection, Placeholder, Utils, Translation, SelectData, ArrayData, AjaxData, Tags, MinimumInputLength, - Dropdown, Search, HidePlaceholder, + Dropdown, Search, HidePlaceholder, InfiniteScroll, EnglishTranslation) { function Defaults () { this.reset(); @@ -11141,9 +11225,9 @@ define('select2/defaults',[ options = $.extend({}, this.defaults, options); if (options.dataAdapter == null) { - if (options.ajax) { + if (options.ajax != null) { options.dataAdapter = AjaxData; - } else if (options.data) { + } else if (options.data != null) { options.dataAdapter = ArrayData; } else { options.dataAdapter = SelectData; @@ -11165,6 +11249,13 @@ define('select2/defaults',[ if (options.resultsAdapter == null) { options.resultsAdapter = ResultsList; + if (options.ajax != null) { + options.resultsAdapter = Utils.Decorate( + options.resultsAdapter, + InfiniteScroll + ); + } + if (options.placeholder != null) { options.resultsAdapter = Utils.Decorate( options.resultsAdapter, @@ -11474,6 +11565,10 @@ define('select2/core',[ Select2.prototype._registerResultsEvents = function () { var self = this; + this.results.on('query:append', function (params) { + self.trigger('query:append', params); + }); + this.results.on('selected', function (params) { self.trigger('select', params); @@ -11511,6 +11606,15 @@ define('select2/core',[ }); }); + this.on('query:append', function (params) { + this.data.query(params, function (data) { + self.trigger('results:append', { + data: data, + query: params + }); + }); + }); + this.on('keypress', function (evt) { var key = evt.which; diff --git a/dist/js/select2.full.min.js b/dist/js/select2.full.min.js index ee2c8218..a0514629 100644 --- a/dist/js/select2.full.min.js +++ b/dist/js/select2.full.min.js @@ -1,4 +1,4 @@ window.$=window.$||{},function(){$&&$.fn&&$.fn.select2&&$.fn.select2.amd&&(c=$.fn.select2.amd.define,b=$.fn.select2.amd.require);var a,b,c;!function(d){function e(a,b){return u.call(a,b)}function f(a,b){var c,d,e,f,g,h,i,j,k,l,m,n=b&&b.split("/"),o=s.map,p=o&&o["*"]||{};if(a&&"."===a.charAt(0))if(b){for(n=n.slice(0,n.length-1),a=a.split("/"),g=a.length-1,s.nodeIdCompat&&w.test(a[g])&&(a[g]=a[g].replace(w,"")),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||p)&&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&&p&&p[d]&&(i=p[d],j=k)}!f&&i&&(f=i,h=j),f&&(c.splice(0,h,f),a=c.join("/"))}return a}function g(a,b){return function(){return n.apply(d,v.call(arguments,0).concat([a,b]))}}function h(a){return function(b){return f(b,a)}}function i(a){return function(b){q[a]=b}}function j(a){if(e(r,a)){var b=r[a];delete r[a],t[a]=!0,m.apply(d,b)}if(!e(q,a)&&!e(t,a))throw new Error("No "+a);return q[a]}function k(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 l(a){return function(){return s&&s.config&&s.config[a]||{}}}var m,n,o,p,q={},r={},s={},t={},u=Object.prototype.hasOwnProperty,v=[].slice,w=/\.js$/;o=function(a,b){var c,d=k(a),e=d[0];return a=d[1],e&&(e=f(e,b),c=j(e)),e?a=c&&c.normalize?c.normalize(a,h(b)):f(a,b):(a=f(a,b),d=k(a),e=d[0],a=d[1],e&&(c=j(e))),{f:e?e+"!"+a:a,n:a,pr:e,p:c}},p={require:function(a){return g(a)},exports:function(a){var b=q[a];return"undefined"!=typeof b?b:q[a]={}},module:function(a){return{id:a,uri:"",exports:q[a],config:l(a)}}},m=function(a,b,c,f){var h,k,l,m,n,s,u=[],v=typeof c;if(f=f||a,"undefined"===v||"function"===v){for(b=!b.length&&c.length?["require","exports","module"]:b,n=0;n0&&b-1 in a}function e(a,b,c){if(bb.isFunction(b))return bb.grep(a,function(a,d){return!!b.call(a,d,a)!==c});if(b.nodeType)return bb.grep(a,function(a){return a===b!==c});if("string"==typeof b){if(ib.test(b))return bb.filter(b,a,c);b=bb.filter(b,a)}return bb.grep(a,function(a){return V.call(b,a)>=0!==c})}function f(a,b){for(;(a=a[b])&&1!==a.nodeType;);return a}function g(a){var b=pb[a]={};return bb.each(a.match(ob)||[],function(a,c){b[c]=!0}),b}function h(){_.removeEventListener("DOMContentLoaded",h,!1),a.removeEventListener("load",h,!1),bb.ready()}function i(){Object.defineProperty(this.cache={},0,{get:function(){return{}}}),this.expando=bb.expando+Math.random()}function j(a,b,c){var d;if(void 0===c&&1===a.nodeType)if(d="data-"+b.replace(vb,"-$1").toLowerCase(),c=a.getAttribute(d),"string"==typeof c){try{c="true"===c?!0:"false"===c?!1:"null"===c?null:+c+""===c?+c:ub.test(c)?bb.parseJSON(c):c}catch(e){}tb.set(a,b,c)}else c=void 0;return c}function k(){return!0}function l(){return!1}function m(){try{return _.activeElement}catch(a){}}function n(a,b){return bb.nodeName(a,"table")&&bb.nodeName(11!==b.nodeType?b:b.firstChild,"tr")?a.getElementsByTagName("tbody")[0]||a.appendChild(a.ownerDocument.createElement("tbody")):a}function o(a){return a.type=(null!==a.getAttribute("type"))+"/"+a.type,a}function p(a){var b=Lb.exec(a.type);return b?a.type=b[1]:a.removeAttribute("type"),a}function q(a,b){for(var c=0,d=a.length;d>c;c++)sb.set(a[c],"globalEval",!b||sb.get(b[c],"globalEval"))}function r(a,b){var c,d,e,f,g,h,i,j;if(1===b.nodeType){if(sb.hasData(a)&&(f=sb.access(a),g=sb.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++)bb.event.add(b,e,j[e][c])}tb.hasData(a)&&(h=tb.access(a),i=bb.extend({},h),tb.set(b,i))}}function s(a,b){var c=a.getElementsByTagName?a.getElementsByTagName(b||"*"):a.querySelectorAll?a.querySelectorAll(b||"*"):[];return void 0===b||b&&bb.nodeName(a,b)?bb.merge([a],c):c}function t(a,b){var c=b.nodeName.toLowerCase();"input"===c&&zb.test(a.type)?b.checked=a.checked:("input"===c||"textarea"===c)&&(b.defaultValue=a.defaultValue)}function u(b,c){var d=bb(c.createElement(b)).appendTo(c.body),e=a.getDefaultComputedStyle?a.getDefaultComputedStyle(d[0]).display:bb.css(d[0],"display");return d.detach(),e}function v(a){var b=_,c=Pb[a];return c||(c=u(a,b),"none"!==c&&c||(Ob=(Ob||bb("