mirror of
https://github.com/ExactTarget/fuelux.git
synced 2026-01-09 22:47:54 -05:00
196 lines
5.0 KiB
JavaScript
196 lines
5.0 KiB
JavaScript
/* global jQuery:true */
|
|
|
|
/*
|
|
* Fuel UX Infinite Scroll
|
|
* https://github.com/ExactTarget/fuelux
|
|
*
|
|
* Copyright (c) 2014 ExactTarget
|
|
* Licensed under the BSD New license.
|
|
*/
|
|
|
|
// -- BEGIN UMD WRAPPER PREFACE --
|
|
|
|
// For more information on UMD visit:
|
|
// https://github.com/umdjs/umd/blob/master/jqueryPlugin.js
|
|
|
|
(function umdFactory (factory) {
|
|
if (typeof define === 'function' && define.amd) {
|
|
// if AMD loader is available, register as an anonymous module.
|
|
define(['jquery', 'fuelux/loader'], factory);
|
|
} else if (typeof exports === 'object') {
|
|
// Node/CommonJS
|
|
module.exports = factory(require('jquery'), require('./loader'));
|
|
} else {
|
|
// OR use browser globals if AMD is not present
|
|
factory(jQuery);
|
|
}
|
|
}(function InfiniteScrollWrapper ($) {
|
|
// -- END UMD WRAPPER PREFACE --
|
|
|
|
// -- BEGIN MODULE CODE HERE --
|
|
|
|
var old = $.fn.infinitescroll;
|
|
|
|
// INFINITE SCROLL CONSTRUCTOR AND PROTOTYPE
|
|
|
|
var InfiniteScroll = function (element, options) {
|
|
this.$element = $(element);
|
|
this.$element.addClass('infinitescroll');
|
|
this.options = $.extend({}, $.fn.infinitescroll.defaults, options);
|
|
|
|
this.curScrollTop = this.$element.scrollTop();
|
|
this.curPercentage = this.getPercentage();
|
|
this.fetchingData = false;
|
|
|
|
this.$element.on('scroll.fu.infinitescroll', $.proxy(this.onScroll, this));
|
|
this.onScroll();
|
|
};
|
|
|
|
InfiniteScroll.prototype = {
|
|
|
|
constructor: InfiniteScroll,
|
|
|
|
destroy: function () {
|
|
this.$element.remove();
|
|
// any external bindings
|
|
// [none]
|
|
|
|
// empty elements to return to original markup
|
|
this.$element.empty();
|
|
|
|
return this.$element[0].outerHTML;
|
|
},
|
|
|
|
disable: function () {
|
|
this.$element.off('scroll.fu.infinitescroll');
|
|
},
|
|
|
|
enable: function () {
|
|
this.$element.on('scroll.fu.infinitescroll', $.proxy(this.onScroll, this));
|
|
},
|
|
|
|
end: function (content) {
|
|
var end = $('<div class="infinitescroll-end"></div>');
|
|
if (content) {
|
|
end.append(content);
|
|
} else {
|
|
end.append('---------');
|
|
}
|
|
|
|
this.$element.append(end);
|
|
this.disable();
|
|
},
|
|
|
|
getPercentage: function () {
|
|
var height = (this.$element.css('box-sizing') === 'border-box') ? this.$element.outerHeight() : this.$element.height();
|
|
var scrollHeight = this.$element.get(0).scrollHeight;
|
|
// If we cannot compute the height, then we end up fetching all pages (ends up #/0 = Infinity).
|
|
// This can happen if the repeater is loaded, but is not in the dom
|
|
if (scrollHeight === 0 || scrollHeight - this.curScrollTop === 0) {
|
|
return 0;
|
|
}
|
|
return (height / (scrollHeight - this.curScrollTop)) * 100;
|
|
},
|
|
|
|
fetchData: function (force) {
|
|
var load = $('<div class="infinitescroll-load"></div>');
|
|
var self = this;
|
|
var moreBtn;
|
|
|
|
var fetch = function () {
|
|
var helpers = {
|
|
percentage: self.curPercentage,
|
|
scrollTop: self.curScrollTop
|
|
};
|
|
var $loader = $('<div class="loader"></div>');
|
|
load.append($loader);
|
|
$loader.loader();
|
|
if (self.options.dataSource) {
|
|
self.options.dataSource(helpers, function (resp) {
|
|
var end;
|
|
load.remove();
|
|
if (resp.content) {
|
|
self.$element.append(resp.content);
|
|
}
|
|
|
|
if (resp.end) {
|
|
end = (resp.end !== true) ? resp.end : undefined;
|
|
self.end(end);
|
|
}
|
|
|
|
self.fetchingData = false;
|
|
});
|
|
}
|
|
};
|
|
|
|
this.fetchingData = true;
|
|
this.$element.append(load);
|
|
if (this.options.hybrid && force !== true) {
|
|
moreBtn = $('<button type="button" class="btn btn-primary"></button>');
|
|
if (typeof this.options.hybrid === 'object') {
|
|
moreBtn.append(this.options.hybrid.label);
|
|
} else {
|
|
moreBtn.append('<span class="glyphicon glyphicon-repeat"></span>');
|
|
}
|
|
|
|
moreBtn.on('click.fu.infinitescroll', function () {
|
|
moreBtn.remove();
|
|
fetch();
|
|
});
|
|
load.append(moreBtn);
|
|
} else {
|
|
fetch();
|
|
}
|
|
},
|
|
|
|
onScroll: function (e) {
|
|
this.curScrollTop = this.$element.scrollTop();
|
|
this.curPercentage = this.getPercentage();
|
|
if (!this.fetchingData && this.curPercentage >= this.options.percentage) {
|
|
this.fetchData();
|
|
}
|
|
}
|
|
};
|
|
|
|
// INFINITE SCROLL PLUGIN DEFINITION
|
|
|
|
$.fn.infinitescroll = function (option) {
|
|
var args = Array.prototype.slice.call(arguments, 1);
|
|
var methodReturn;
|
|
|
|
var $set = this.each(function () {
|
|
var $this = $(this);
|
|
var data = $this.data('fu.infinitescroll');
|
|
var options = typeof option === 'object' && option;
|
|
|
|
if (!data) {
|
|
$this.data('fu.infinitescroll', (data = new InfiniteScroll(this, options)));
|
|
}
|
|
|
|
if (typeof option === 'string') {
|
|
methodReturn = data[option].apply(data, args);
|
|
}
|
|
});
|
|
|
|
return (methodReturn === undefined) ? $set : methodReturn;
|
|
};
|
|
|
|
$.fn.infinitescroll.defaults = {
|
|
dataSource: null,
|
|
hybrid: false,//can be true or an object with structure: { 'label': (markup or jQuery obj) }
|
|
percentage: 95//percentage scrolled to the bottom before more is loaded
|
|
};
|
|
|
|
$.fn.infinitescroll.Constructor = InfiniteScroll;
|
|
|
|
$.fn.infinitescroll.noConflict = function () {
|
|
$.fn.infinitescroll = old;
|
|
return this;
|
|
};
|
|
|
|
// NO DATA-API DUE TO NEED OF DATA-SOURCE
|
|
|
|
// -- BEGIN UMD WRAPPER AFTERWORD --
|
|
}));
|
|
// -- END UMD WRAPPER AFTERWORD --
|