Browse Source

Added infinite scrolling support for AJAX

Kevin Brown 10 years ago
parent
commit
5e3b63289c

+ 1 - 1
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}}();
+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}}();

+ 107 - 3
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 = $(
+      '<li class="option load-more" role="treeitem"></li>'
+    );
+
+    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;
 

+ 107 - 3
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 = $(
+      '<li class="option load-more" role="treeitem"></li>'
+    );
+
+    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;
 

+ 107 - 3
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 = $(
+      '<li class="option load-more" role="treeitem"></li>'
+    );
+
+    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;
 

File diff suppressed because it is too large
+ 0 - 0
dist/js/select2.full.min.js


+ 107 - 3
dist/js/select2.js

@@ -1979,6 +1979,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 = $(
+      '<li class="option load-more" role="treeitem"></li>'
+    );
+
+    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) {
@@ -1992,6 +2072,9 @@ define('select2/i18n/en',[],function () {
 
       return message;
     },
+    loadingMore: function () {
+      return 'Loading more results…';
+    },
     noResults: function () {
       return 'No results found';
     }
@@ -2018,13 +2101,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();
@@ -2034,9 +2118,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;
@@ -2058,6 +2142,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,
@@ -2367,6 +2458,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);
 
@@ -2404,6 +2499,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;
 

File diff suppressed because it is too large
+ 0 - 0
dist/js/select2.min.js


+ 1 - 0
docs/examples.html

@@ -453,6 +453,7 @@ $.fn.select2.amd.require(["select2/core", "select2/utils"], function (Select2, U
       data: function (params) {
         return {
           q: params.term, // search term
+          page: params.page
         };
       },
       processResults: function (data, page) {

+ 13 - 0
src/js/select2/core.js

@@ -195,6 +195,10 @@ define([
   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);
 
@@ -232,6 +236,15 @@ define([
       });
     });
 
+    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;
 

+ 11 - 3
src/js/select2/defaults.js

@@ -18,13 +18,14 @@ define([
   './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();
@@ -34,9 +35,9 @@ define([
     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;
@@ -58,6 +59,13 @@ define([
     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,

+ 79 - 0
src/js/select2/dropdown/infiniteScroll.js

@@ -0,0 +1,79 @@
+define([
+  '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 = $(
+      '<li class="option load-more" role="treeitem"></li>'
+    );
+
+    var message = this.options.get('translations').get('loadingMore');
+
+    $option.html(message(this.lastParams));
+
+    return $option;
+  };
+
+  return InfiniteScroll;
+});

+ 3 - 0
src/js/select2/i18n/en.js

@@ -11,6 +11,9 @@ define(function () {
 
       return message;
     },
+    loadingMore: function () {
+      return 'Loading more results…';
+    },
     noResults: function () {
       return 'No results found';
     }

Some files were not shown because too many files changed in this diff