fuelux
Version:
Base Fuel UX styles and controls
921 lines (784 loc) • 28.5 kB
JavaScript
/* global jQuery:true */
/*
* Fuel UX Repeater
* 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/combobox', 'fuelux/infinite-scroll', 'fuelux/search', 'fuelux/selectlist'], factory);
} else if (typeof exports === 'object') {
// Node/CommonJS
module.exports = factory(require('jquery'), require('./combobox'), require('./infinite-scroll'),
require('./search'), require('./selectlist'));
} else {
// OR use browser globals if AMD is not present
factory(jQuery);
}
}(function RepeaterWrapper ($) {
// -- END UMD WRAPPER PREFACE --
// -- BEGIN MODULE CODE HERE --
var old = $.fn.repeater;
// REPEATER CONSTRUCTOR AND PROTOTYPE
var Repeater = function Repeater (element, options) {
var self = this;
var $btn;
var currentView;
this.$element = $(element);
this.$canvas = this.$element.find('.repeater-canvas');
this.$count = this.$element.find('.repeater-count');
this.$end = this.$element.find('.repeater-end');
this.$filters = this.$element.find('.repeater-filters');
this.$loader = this.$element.find('.repeater-loader');
this.$pageSize = this.$element.find('.repeater-itemization .selectlist');
this.$nextBtn = this.$element.find('.repeater-next');
this.$pages = this.$element.find('.repeater-pages');
this.$prevBtn = this.$element.find('.repeater-prev');
this.$primaryPaging = this.$element.find('.repeater-primaryPaging');
this.$search = this.$element.find('.repeater-search').find('.search');
this.$secondaryPaging = this.$element.find('.repeater-secondaryPaging');
this.$start = this.$element.find('.repeater-start');
this.$viewport = this.$element.find('.repeater-viewport');
this.$views = this.$element.find('.repeater-views');
this.currentPage = 0;
this.currentView = null;
this.isDisabled = false;
this.infiniteScrollingCallback = function noop () {};
this.infiniteScrollingCont = null;
this.infiniteScrollingEnabled = false;
this.infiniteScrollingEnd = null;
this.infiniteScrollingOptions = {};
this.lastPageInput = 0;
this.options = $.extend({}, $.fn.repeater.defaults, options);
this.pageIncrement = 0;// store direction navigated
this.resizeTimeout = {};
this.stamp = new Date().getTime() + (Math.floor(Math.random() * 100) + 1);
this.storedDataSourceOpts = null;
this.syncingViewButtonState = false;
this.viewOptions = {};
this.viewType = null;
this.$filters.selectlist();
this.$pageSize.selectlist();
this.$primaryPaging.find('.combobox').combobox();
this.$search.search({
searchOnKeyPress: this.options.searchOnKeyPress,
allowCancel: this.options.allowCancel
});
this.$filters.on('changed.fu.selectlist', function onFiltersChanged (e, value) {
self.$element.trigger('filtered.fu.repeater', value);
self.render({
clearInfinite: true,
pageIncrement: null
});
});
this.$nextBtn.on('click.fu.repeater', $.proxy(this.next, this));
this.$pageSize.on('changed.fu.selectlist', function onPageSizeChanged (e, value) {
self.$element.trigger('pageSizeChanged.fu.repeater', value);
self.render({
pageIncrement: null
});
});
this.$prevBtn.on('click.fu.repeater', $.proxy(this.previous, this));
this.$primaryPaging.find('.combobox').on('changed.fu.combobox', function onPrimaryPagingChanged (evt, data) {
self.pageInputChange(data.text, data);
});
this.$search.on('searched.fu.search cleared.fu.search', function onSearched (e, value) {
self.$element.trigger('searchChanged.fu.repeater', value);
self.render({
clearInfinite: true,
pageIncrement: null
});
});
this.$search.on('canceled.fu.search', function onSearchCanceled (e, value) {
self.$element.trigger('canceled.fu.repeater', value);
self.render({
clearInfinite: true,
pageIncrement: null
});
});
this.$secondaryPaging.on('blur.fu.repeater', function onSecondaryPagingBlur () {
self.pageInputChange(self.$secondaryPaging.val());
});
this.$secondaryPaging.on('keyup', function onSecondaryPagingKeyup (e) {
if (e.keyCode === 13) {
self.pageInputChange(self.$secondaryPaging.val());
}
});
this.$views.find('input').on('change.fu.repeater', $.proxy(this.viewChanged, this));
$(window).on('resize.fu.repeater.' + this.stamp, function onResizeRepeater () {
clearTimeout(self.resizeTimeout);
self.resizeTimeout = setTimeout(function resizeTimeout () {
self.resize();
self.$element.trigger('resized.fu.repeater');
}, 75);
});
this.$loader.loader();
this.$loader.loader('pause');
if (this.options.defaultView !== -1) {
currentView = this.options.defaultView;
} else {
$btn = this.$views.find('label.active input');
currentView = ($btn.length > 0) ? $btn.val() : 'list';
}
this.setViewOptions(currentView);
this.initViewTypes(function initViewTypes () {
self.resize();
self.$element.trigger('resized.fu.repeater');
self.render({
changeView: currentView
});
});
};
var logWarn = function logWarn (msg) {
if (window.console && window.console.warn) {
window.console.warn(msg);
}
};
var scan = function scan (cont) {
var keep = [];
cont.children().each(function eachContainerChild () {
var item = $(this);
var pres = item.attr('data-preserve');
if (pres === 'deep') {
item.detach();
keep.push(item);
} else if (pres === 'shallow') {
scan(item);
item.detach();
keep.push(item);
}
});
cont.empty();
cont.append(keep);
};
var addItem = function addItem ($parent, response) {
var action;
if (response) {
action = (response.action) ? response.action : 'append';
if (action !== 'none' && response.item !== undefined) {
var $container = (response.container !== undefined) ? $(response.container) : $parent;
$container[action](response.item);
}
}
};
var callNextInit = function callNextInit (currentViewType, viewTypes, callback) {
var nextViewType = currentViewType + 1;
if (nextViewType < viewTypes.length) {
initViewType.call(this, nextViewType, viewTypes, callback);
} else {
callback();
}
};
var initViewType = function initViewType (currentViewtype, viewTypes, callback) {
if (viewTypes[currentViewtype].initialize) {
viewTypes[currentViewtype].initialize.call(this, {}, function afterInitialize () {
callNextInit.call(this, currentViewtype, viewTypes, callback);
});
} else {
callNextInit.call(this, currentViewtype, viewTypes, callback);
}
};
// Does all of our cleanup post-render
var afterRender = function afterRender (state) {
var data = state.data || {};
if (this.infiniteScrollingEnabled) {
if (state.viewChanged || state.options.clearInfinite) {
this.initInfiniteScrolling();
}
this.infiniteScrollPaging(data, state.options);
}
this.$loader.hide().loader('pause');
this.enable();
this.$search.trigger('rendered.fu.repeater', {
data: data,
options: state.dataOptions,
renderOptions: state.options
});
this.$element.trigger('rendered.fu.repeater', {
data: data,
options: state.dataOptions,
renderOptions: state.options
});
// for maintaining support of 'loaded' event
this.$element.trigger('loaded.fu.repeater', state.dataOptions);
};
// This does the actual rendering of the repeater
var doRender = function doRender (state) {
var data = state.data || {};
if (this.infiniteScrollingEnabled) {
// pass empty object because data handled in infiniteScrollPaging method
this.infiniteScrollingCallback({});
} else {
this.itemization(data);
this.pagination(data);
}
var self = this;
this.renderItems(
state.viewTypeObj,
data,
function callAfterRender (d) {
state.data = d;
afterRender.call(self, state);
}
);
};
Repeater.prototype = {
constructor: Repeater,
clear: function clear (opts) {
var options = opts || {};
if (!options.preserve) {
// Just trash everything because preserve is false
this.$canvas.empty();
} else if (!this.infiniteScrollingEnabled || options.clearInfinite) {
// Preserve clear only if infiniteScrolling is disabled or if specifically told to do so
scan(this.$canvas);
} // Otherwise don't clear because infiniteScrolling is enabled
// If viewChanged and current viewTypeObj has a cleared function, call it
var viewChanged = (options.viewChanged !== undefined) ? options.viewChanged : false;
var viewTypeObj = $.fn.repeater.viewTypes[this.viewType] || {};
if (!viewChanged && viewTypeObj.cleared) {
viewTypeObj.cleared.call(this, {
options: options
});
}
},
clearPreservedDataSourceOptions: function clearPreservedDataSourceOptions () {
this.storedDataSourceOpts = null;
},
destroy: function destroy () {
var markup;
// set input value attrbute in markup
this.$element.find('input').each(function eachInput () {
$(this).attr('value', $(this).val());
});
// empty elements to return to original markup
this.$canvas.empty();
markup = this.$element[0].outerHTML;
// destroy components and remove leftover
this.$element.find('.combobox').combobox('destroy');
this.$element.find('.selectlist').selectlist('destroy');
this.$element.find('.search').search('destroy');
if (this.infiniteScrollingEnabled) {
$(this.infiniteScrollingCont).infinitescroll('destroy');
}
this.$element.remove();
// any external events
$(window).off('resize.fu.repeater.' + this.stamp);
return markup;
},
disable: function disable () {
var viewTypeObj = $.fn.repeater.viewTypes[this.viewType] || {};
this.$search.search('disable');
this.$filters.selectlist('disable');
this.$views.find('label, input').addClass('disabled').attr('disabled', 'disabled');
this.$pageSize.selectlist('disable');
this.$primaryPaging.find('.combobox').combobox('disable');
this.$secondaryPaging.attr('disabled', 'disabled');
this.$prevBtn.attr('disabled', 'disabled');
this.$nextBtn.attr('disabled', 'disabled');
if (viewTypeObj.enabled) {
viewTypeObj.enabled.call(this, {
status: false
});
}
this.isDisabled = true;
this.$element.addClass('disabled');
this.$element.trigger('disabled.fu.repeater');
},
enable: function enable () {
var viewTypeObj = $.fn.repeater.viewTypes[this.viewType] || {};
this.$search.search('enable');
this.$filters.selectlist('enable');
this.$views.find('label, input').removeClass('disabled').removeAttr('disabled');
this.$pageSize.selectlist('enable');
this.$primaryPaging.find('.combobox').combobox('enable');
this.$secondaryPaging.removeAttr('disabled');
if (!this.$prevBtn.hasClass('page-end')) {
this.$prevBtn.removeAttr('disabled');
}
if (!this.$nextBtn.hasClass('page-end')) {
this.$nextBtn.removeAttr('disabled');
}
// is 0 or 1 pages, if using $primaryPaging (combobox)
// if using selectlist allow user to use selectlist to select 0 or 1
if (this.$prevBtn.hasClass('page-end') && this.$nextBtn.hasClass('page-end')) {
this.$primaryPaging.combobox('disable');
}
// if there are no items
if (parseInt(this.$count.html(), 10) !== 0) {
this.$pageSize.selectlist('enable');
} else {
this.$pageSize.selectlist('disable');
}
if (viewTypeObj.enabled) {
viewTypeObj.enabled.call(this, {
status: true
});
}
this.isDisabled = false;
this.$element.removeClass('disabled');
this.$element.trigger('enabled.fu.repeater');
},
getDataOptions: function getDataOptions (opts) {
var options = opts || {};
if (options.pageIncrement !== undefined) {
if (options.pageIncrement === null) {
this.currentPage = 0;
} else {
this.currentPage += options.pageIncrement;
}
}
var dataSourceOptions = {};
if (options.dataSourceOptions) {
dataSourceOptions = options.dataSourceOptions;
if (options.preserveDataSourceOptions) {
if (this.storedDataSourceOpts) {
this.storedDataSourceOpts = $.extend(this.storedDataSourceOpts, dataSourceOptions);
} else {
this.storedDataSourceOpts = dataSourceOptions;
}
}
}
if (this.storedDataSourceOpts) {
dataSourceOptions = $.extend(this.storedDataSourceOpts, dataSourceOptions);
}
var returnOptions = {
view: this.currentView,
pageIndex: this.currentPage,
filter: {
text: 'All',
value: 'all'
}
};
if (this.$filters.length > 0) {
returnOptions.filter = this.$filters.selectlist('selectedItem');
}
if (!this.infiniteScrollingEnabled) {
returnOptions.pageSize = 25;
if (this.$pageSize.length > 0) {
returnOptions.pageSize = parseInt(this.$pageSize.selectlist('selectedItem').value, 10);
}
}
var searchValue = this.$search && this.$search.find('input') && this.$search.find('input').val();
if (searchValue !== '') {
returnOptions.search = searchValue;
}
var viewType = $.fn.repeater.viewTypes[this.viewType] || {};
var addViewTypeData = viewType.dataOptions;
if (addViewTypeData) {
returnOptions = addViewTypeData.call(this, returnOptions);
}
returnOptions = $.extend(returnOptions, dataSourceOptions);
return returnOptions;
},
infiniteScrolling: function infiniteScrolling (enable, opts) {
var footer = this.$element.find('.repeater-footer');
var viewport = this.$element.find('.repeater-viewport');
var options = opts || {};
if (enable) {
this.infiniteScrollingEnabled = true;
this.infiniteScrollingEnd = options.end;
delete options.dataSource;
delete options.end;
this.infiniteScrollingOptions = options;
viewport.css({
height: viewport.height() + (footer.outerHeight() || 0)
});
footer.hide();
} else {
var cont = this.infiniteScrollingCont;
var data = cont.data();
delete data.infinitescroll;
cont.off('scroll');
cont.removeClass('infinitescroll');
this.infiniteScrollingCont = null;
this.infiniteScrollingEnabled = false;
this.infiniteScrollingEnd = null;
this.infiniteScrollingOptions = {};
viewport.css({
height: viewport.height() - (footer.outerHeight() || 0)
});
footer.show();
}
},
infiniteScrollPaging: function infiniteScrollPaging (data) {
var end = (this.infiniteScrollingEnd !== true) ? this.infiniteScrollingEnd : undefined;
var page = data.page;
var pages = data.pages;
this.currentPage = (page !== undefined) ? page : NaN;
if (this.infiniteScrollingCont) {
if (data.end === true || (this.currentPage + 1) >= pages) {
this.infiniteScrollingCont.infinitescroll('end', end);
} else {
this.infiniteScrollingCont.infinitescroll('onScroll');
}
}
},
initInfiniteScrolling: function initInfiniteScrolling () {
var cont = this.$canvas.find('[data-infinite="true"]:first');
cont = (cont.length < 1) ? this.$canvas : cont;
if (cont.data('fu.infinitescroll')) {
cont.infinitescroll('enable');
} else {
var self = this;
var opts = $.extend({}, this.infiniteScrollingOptions);
opts.dataSource = function dataSource (helpers, callback) {
self.infiniteScrollingCallback = callback;
self.render({
pageIncrement: 1
});
};
cont.infinitescroll(opts);
this.infiniteScrollingCont = cont;
}
},
initViewTypes: function initViewTypes (callback) {
var viewTypes = [];
for (var key in $.fn.repeater.viewTypes) {
if ({}.hasOwnProperty.call($.fn.repeater.viewTypes, key)) {
viewTypes.push($.fn.repeater.viewTypes[key]);
}
}
if (viewTypes.length > 0) {
initViewType.call(this, 0, viewTypes, callback);
} else {
callback();
}
},
itemization: function itemization (data) {
this.$count.html((data.count !== undefined) ? data.count : '?');
this.$end.html((data.end !== undefined) ? data.end : '?');
this.$start.html((data.start !== undefined) ? data.start : '?');
},
next: function next () {
this.$nextBtn.attr('disabled', 'disabled');
this.$prevBtn.attr('disabled', 'disabled');
this.pageIncrement = 1;
this.$element.trigger('nextClicked.fu.repeater');
this.render({
pageIncrement: this.pageIncrement
});
},
pageInputChange: function pageInputChange (val, dataFromCombobox) {
// dataFromCombobox is a proxy for data from combobox's changed event,
// if no combobox is present data will be undefined
var pageInc;
if (val !== this.lastPageInput) {
this.lastPageInput = val;
var value = parseInt(val, 10) - 1;
pageInc = value - this.currentPage;
this.$element.trigger('pageChanged.fu.repeater', [value, dataFromCombobox]);
this.render({
pageIncrement: pageInc
});
}
},
pagination: function pagination (data) {
this.$primaryPaging.removeClass('active');
this.$secondaryPaging.removeClass('active');
var totalPages = data.pages;
this.currentPage = (data.page !== undefined) ? data.page : NaN;
// set paging to 0 if total pages is 0, otherwise use one-based index
var currenPageOutput = totalPages === 0 ? 0 : this.currentPage + 1;
if (totalPages <= this.viewOptions.dropPagingCap) {
this.$primaryPaging.addClass('active');
var dropMenu = this.$primaryPaging.find('.dropdown-menu');
dropMenu.empty();
for (var i = 0; i < totalPages; i++) {
var l = i + 1;
dropMenu.append('<li data-value="' + l + '"><a href="#">' + l + '</a></li>');
}
this.$primaryPaging.find('input.form-control').val(currenPageOutput);
} else {
this.$secondaryPaging.addClass('active');
this.$secondaryPaging.val(currenPageOutput);
}
this.lastPageInput = this.currentPage + 1 + '';
this.$pages.html('' + totalPages);
// this is not the last page
if ((this.currentPage + 1) < totalPages) {
this.$nextBtn.removeAttr('disabled');
this.$nextBtn.removeClass('page-end');
} else {
this.$nextBtn.attr('disabled', 'disabled');
this.$nextBtn.addClass('page-end');
}
// this is not the first page
if ((this.currentPage - 1) >= 0) {
this.$prevBtn.removeAttr('disabled');
this.$prevBtn.removeClass('page-end');
} else {
this.$prevBtn.attr('disabled', 'disabled');
this.$prevBtn.addClass('page-end');
}
// return focus to next/previous buttons after navigating
if (this.pageIncrement !== 0) {
if (this.pageIncrement > 0) {
if (this.$nextBtn.is(':disabled')) {
// if you can't focus, go the other way
this.$prevBtn.focus();
} else {
this.$nextBtn.focus();
}
} else if (this.$prevBtn.is(':disabled')) {
// if you can't focus, go the other way
this.$nextBtn.focus();
} else {
this.$prevBtn.focus();
}
}
},
previous: function previous () {
this.$nextBtn.attr('disabled', 'disabled');
this.$prevBtn.attr('disabled', 'disabled');
this.pageIncrement = -1;
this.$element.trigger('previousClicked.fu.repeater');
this.render({
pageIncrement: this.pageIncrement
});
},
// This functions more as a "pre-render" than a true "render"
render: function render (opts) {
this.disable();
var viewChanged = false;
var viewTypeObj = $.fn.repeater.viewTypes[this.viewType] || {};
var options = opts || {};
if (options.changeView && (this.currentView !== options.changeView)) {
var prevView = this.currentView;
this.currentView = options.changeView;
this.viewType = this.currentView.split('.')[0];
this.setViewOptions(this.currentView);
this.$element.attr('data-currentview', this.currentView);
this.$element.attr('data-viewtype', this.viewType);
viewChanged = true;
options.viewChanged = viewChanged;
this.$element.trigger('viewChanged.fu.repeater', this.currentView);
if (this.infiniteScrollingEnabled) {
this.infiniteScrolling(false);
}
viewTypeObj = $.fn.repeater.viewTypes[this.viewType] || {};
if (viewTypeObj.selected) {
viewTypeObj.selected.call(this, {
prevView: prevView
});
}
}
this.syncViewButtonState();
options.preserve = (options.preserve !== undefined) ? options.preserve : !viewChanged;
this.clear(options);
if (!this.infiniteScrollingEnabled || (this.infiniteScrollingEnabled && viewChanged)) {
this.$loader.show().loader('play');
}
var dataOptions = this.getDataOptions(options);
var beforeRender = this.viewOptions.dataSource;
var repeaterPrototypeContext = this;
beforeRender(
dataOptions,
// this serves as a bridge function to pass all required data through to the actual function
// that does the rendering for us.
function callDoRender (dataSourceReturnedData) {
doRender.call(
repeaterPrototypeContext,
{
data: dataSourceReturnedData,
dataOptions: dataOptions,
options: options,
viewChanged: viewChanged,
viewTypeObj: viewTypeObj
}
);
}
);
},
resize: function resize () {
var staticHeight = (this.viewOptions.staticHeight === -1) ? this.$element.attr('data-staticheight') : this.viewOptions.staticHeight;
var viewTypeObj = {};
var height;
var viewportMargins;
var scrubbedElements = [];
var previousProperties = [];
var $hiddenElements = this.$element.parentsUntil(':visible').addBack();
var currentHiddenElement;
var currentElementIndex = 0;
// Set parents to 'display:block' until repeater is visible again
while (currentElementIndex < $hiddenElements.length && this.$element.is(':hidden')) {
currentHiddenElement = $hiddenElements[currentElementIndex];
// Only set display property on elements that are explicitly hidden (i.e. do not inherit it from their parent)
if ($(currentHiddenElement).is(':hidden')) {
previousProperties.push(currentHiddenElement.style['display']);
currentHiddenElement.style['display'] = 'block';
scrubbedElements.push(currentHiddenElement);
}
currentElementIndex++;
}
if (this.viewType) {
viewTypeObj = $.fn.repeater.viewTypes[this.viewType] || {};
}
if (staticHeight !== undefined && staticHeight !== false && staticHeight !== 'false') {
this.$canvas.addClass('scrolling');
viewportMargins = {
bottom: this.$viewport.css('margin-bottom'),
top: this.$viewport.css('margin-top')
};
var staticHeightValue = (staticHeight === 'true' || staticHeight === true) ? this.$element.height() : parseInt(staticHeight, 10);
var headerHeight = this.$element.find('.repeater-header').outerHeight() || 0;
var footerHeight = this.$element.find('.repeater-footer').outerHeight() || 0;
var bottomMargin = (viewportMargins.bottom === 'auto') ? 0 : parseInt(viewportMargins.bottom, 10);
var topMargin = (viewportMargins.top === 'auto') ? 0 : parseInt(viewportMargins.top, 10);
height = staticHeightValue - headerHeight - footerHeight - bottomMargin - topMargin;
this.$viewport.outerHeight(height);
} else {
this.$canvas.removeClass('scrolling');
}
if (viewTypeObj.resize) {
viewTypeObj.resize.call(this, {
height: this.$element.outerHeight() || 0,
width: this.$element.outerWidth() || 0
});
}
scrubbedElements.forEach(function (element, i) {
element.style['display'] = previousProperties[i];
});
},
// e.g. "Rows" or "Thumbnails"
renderItems: function renderItems (viewTypeObj, data, callback) {
if (!viewTypeObj.render) {
if (viewTypeObj.before) {
var addBefore = viewTypeObj.before.call(this, {
container: this.$canvas,
data: data
});
addItem(this.$canvas, addBefore);
}
var $dataContainer = this.$canvas.find('[data-container="true"]:last');
var $container = ($dataContainer.length > 0) ? $dataContainer : this.$canvas;
// It appears that the following code would theoretically allow you to pass a deeply
// nested value to "repeat on" to be added to the repeater.
// eg. `data.foo.bar.items`
if (viewTypeObj.renderItem) {
var subset;
var objectAndPropsToRepeatOnString = viewTypeObj.repeat || 'data.items';
var objectAndPropsToRepeatOn = objectAndPropsToRepeatOnString.split('.');
var objectToRepeatOn = objectAndPropsToRepeatOn[0];
if (objectToRepeatOn === 'data' || objectToRepeatOn === 'this') {
subset = (objectToRepeatOn === 'this') ? this : data;
// Extracts subset from object chain (get `items` out of `foo.bar.items`). I think....
var propsToRepeatOn = objectAndPropsToRepeatOn.slice(1);
for (var prop = 0; prop < propsToRepeatOn.length; prop++) {
if (subset[propsToRepeatOn[prop]] !== undefined) {
subset = subset[propsToRepeatOn[prop]];
} else {
subset = [];
logWarn('WARNING: Repeater unable to find property to iterate renderItem on.');
break;
}
}
for (var subItemIndex = 0; subItemIndex < subset.length; subItemIndex++) {
var addSubItem = viewTypeObj.renderItem.call(this, {
container: $container,
data: data,
index: subItemIndex,
subset: subset
});
addItem($container, addSubItem);
}
} else {
logWarn('WARNING: Repeater plugin "repeat" value must start with either "data" or "this"');
}
}
if (viewTypeObj.after) {
var addAfter = viewTypeObj.after.call(this, {
container: this.$canvas,
data: data
});
addItem(this.$canvas, addAfter);
}
callback(data);
} else {
viewTypeObj.render.call(this, {
container: this.$canvas,
data: data
}, callback);
}
},
setViewOptions: function setViewOptions (curView) {
var opts = {};
var viewName = curView.split('.')[1];
if (this.options.views) {
opts = this.options.views[viewName] || this.options.views[curView] || {};
} else {
opts = {};
}
this.viewOptions = $.extend({}, this.options, opts);
},
viewChanged: function viewChanged (e) {
var $selected = $(e.target);
var val = $selected.val();
if (!this.syncingViewButtonState) {
if (this.isDisabled || $selected.parents('label:first').hasClass('disabled')) {
this.syncViewButtonState();
} else {
this.render({
changeView: val,
pageIncrement: null
});
}
}
},
syncViewButtonState: function syncViewButtonState () {
var $itemToCheck = this.$views.find('input[value="' + this.currentView + '"]');
this.syncingViewButtonState = true;
this.$views.find('input').prop('checked', false);
this.$views.find('label.active').removeClass('active');
if ($itemToCheck.length > 0) {
$itemToCheck.prop('checked', true);
$itemToCheck.parents('label:first').addClass('active');
}
this.syncingViewButtonState = false;
}
};
// For backwards compatibility.
Repeater.prototype.runRenderer = Repeater.prototype.renderItems;
// REPEATER PLUGIN DEFINITION
$.fn.repeater = function fnrepeater (option) {
var args = Array.prototype.slice.call(arguments, 1);
var methodReturn;
var $set = this.each(function eachThis () {
var $this = $(this);
var data = $this.data('fu.repeater');
var options = typeof option === 'object' && option;
if (!data) {
$this.data('fu.repeater', (data = new Repeater(this, options)));
}
if (typeof option === 'string') {
methodReturn = data[option].apply(data, args);
}
});
return (methodReturn === undefined) ? $set : methodReturn;
};
$.fn.repeater.defaults = {
dataSource: function dataSource (options, callback) {
callback({ count: 0, end: 0, items: [], page: 0, pages: 1, start: 0 });
},
defaultView: -1, // should be a string value. -1 means it will grab the active view from the view controls
dropPagingCap: 10,
staticHeight: -1, // normally true or false. -1 means it will look for data-staticheight on the element
views: null, // can be set to an object to configure multiple views of the same type,
searchOnKeyPress: false,
allowCancel: true
};
$.fn.repeater.viewTypes = {};
$.fn.repeater.Constructor = Repeater;
$.fn.repeater.noConflict = function noConflict () {
$.fn.repeater = old;
return this;
};
// -- BEGIN UMD WRAPPER AFTERWORD --
}));
// -- END UMD WRAPPER AFTERWORD --