mirror of
https://github.com/ExactTarget/fuelux.git
synced 2026-01-09 22:47:54 -05:00
1030 lines
35 KiB
JavaScript
Executable File
1030 lines
35 KiB
JavaScript
Executable File
/* global jQuery:true */
|
|
|
|
/*
|
|
* Fuel UX Repeater - List View Plugin
|
|
* 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/repeater', 'fuelux/checkbox'], factory);
|
|
} else if (typeof exports === 'object') {
|
|
// Node/CommonJS
|
|
module.exports = factory(require('jquery'), require('./repeater'), require('./checkbox'));
|
|
} else {
|
|
// OR use browser globals if AMD is not present
|
|
factory(jQuery);
|
|
}
|
|
}(function repeaterListWrapper ($) {
|
|
// -- END UMD WRAPPER PREFACE --
|
|
|
|
// -- BEGIN MODULE CODE HERE --
|
|
|
|
if ($.fn.repeater) {
|
|
// ADDITIONAL METHODS
|
|
$.fn.repeater.Constructor.prototype.list_clearSelectedItems = function listClearSelectedItems () {
|
|
this.$canvas.find('.repeater-list-check').remove();
|
|
this.$canvas.find('.repeater-list table tbody tr.selected').removeClass('selected');
|
|
};
|
|
|
|
$.fn.repeater.Constructor.prototype.list_highlightColumn = function listHighlightColumn (index, force) {
|
|
var tbody = this.$canvas.find('.repeater-list-wrapper > table tbody');
|
|
if (this.viewOptions.list_highlightSortedColumn || force) {
|
|
tbody.find('td.sorted').removeClass('sorted');
|
|
tbody.find('tr').each(function eachTR () {
|
|
var col = $(this).find('td:nth-child(' + (index + 1) + ')').filter(function filterChildren () { return !$(this).parent().hasClass('empty'); });
|
|
col.addClass('sorted');
|
|
});
|
|
}
|
|
};
|
|
|
|
$.fn.repeater.Constructor.prototype.list_getSelectedItems = function listGetSelectedItems () {
|
|
var selected = [];
|
|
this.$canvas.find('.repeater-list .repeater-list-wrapper > table tbody tr.selected').each(function eachSelectedTR () {
|
|
var $item = $(this);
|
|
selected.push({
|
|
data: $item.data('item_data'),
|
|
element: $item
|
|
});
|
|
});
|
|
return selected;
|
|
};
|
|
|
|
$.fn.repeater.Constructor.prototype.getValue = $.fn.repeater.Constructor.prototype.list_getSelectedItems;
|
|
|
|
$.fn.repeater.Constructor.prototype.list_positionHeadings = function listPositionHeadings () {
|
|
var $wrapper = this.$element.find('.repeater-list-wrapper');
|
|
var offsetLeft = $wrapper.offset().left;
|
|
var scrollLeft = $wrapper.scrollLeft();
|
|
if (scrollLeft > 0) {
|
|
$wrapper.find('.repeater-list-heading').each(function eachListHeading () {
|
|
var $heading = $(this);
|
|
var left = ($heading.parents('th:first').offset().left - offsetLeft) + 'px';
|
|
$heading.addClass('shifted').css('left', left);
|
|
});
|
|
} else {
|
|
$wrapper.find('.repeater-list-heading').each(function eachListHeading () {
|
|
$(this).removeClass('shifted').css('left', '');
|
|
});
|
|
}
|
|
};
|
|
|
|
$.fn.repeater.Constructor.prototype.list_setSelectedItems = function listSetSelectedItems (itms, force) {
|
|
var selectable = this.viewOptions.list_selectable;
|
|
var self = this;
|
|
var data;
|
|
var i;
|
|
var $item;
|
|
var length;
|
|
|
|
var items = itms;
|
|
if (!$.isArray(items)) {
|
|
items = [items];
|
|
}
|
|
|
|
// this function is necessary because lint yells when a function is in a loop
|
|
var checkIfItemMatchesValue = function checkIfItemMatchesValue (rowIndex) {
|
|
$item = $(this);
|
|
|
|
data = $item.data('item_data') || {};
|
|
if (data[items[i].property] === items[i].value) {
|
|
selectItem($item, items[i].selected, rowIndex);
|
|
}
|
|
};
|
|
|
|
var selectItem = function selectItem ($itm, slct, index) {
|
|
var $frozenCols;
|
|
|
|
var select = (slct !== undefined) ? slct : true;
|
|
if (select) {
|
|
if (!force && selectable !== 'multi') {
|
|
self.list_clearSelectedItems();
|
|
}
|
|
|
|
if (!$itm.hasClass('selected')) {
|
|
$itm.addClass('selected');
|
|
|
|
if (self.viewOptions.list_frozenColumns || self.viewOptions.list_selectable === 'multi') {
|
|
$frozenCols = self.$element.find('.frozen-column-wrapper tr:nth-child(' + (index + 1) + ')');
|
|
|
|
$frozenCols.addClass('selected');
|
|
$frozenCols.find('.repeater-select-checkbox').addClass('checked');
|
|
}
|
|
|
|
if (self.viewOptions.list_actions) {
|
|
self.$element.find('.actions-column-wrapper tr:nth-child(' + (index + 1) + ')').addClass('selected');
|
|
}
|
|
|
|
$itm.find('td:first').prepend('<div class="repeater-list-check"><span class="glyphicon glyphicon-ok"></span></div>');
|
|
}
|
|
} else {
|
|
if (self.viewOptions.list_frozenColumns) {
|
|
$frozenCols = self.$element.find('.frozen-column-wrapper tr:nth-child(' + (index + 1) + ')');
|
|
|
|
$frozenCols.addClass('selected');
|
|
$frozenCols.find('.repeater-select-checkbox').removeClass('checked');
|
|
}
|
|
|
|
if (self.viewOptions.list_actions) {
|
|
self.$element.find('.actions-column-wrapper tr:nth-child(' + (index + 1) + ')').removeClass('selected');
|
|
}
|
|
|
|
$itm.find('.repeater-list-check').remove();
|
|
$itm.removeClass('selected');
|
|
}
|
|
};
|
|
|
|
if (force === true || selectable === 'multi') {
|
|
length = items.length;
|
|
} else if (selectable) {
|
|
length = (items.length > 0) ? 1 : 0;
|
|
} else {
|
|
length = 0;
|
|
}
|
|
|
|
for (i = 0; i < length; i++) {
|
|
if (items[i].index !== undefined) {
|
|
$item = this.$canvas.find('.repeater-list .repeater-list-wrapper > table tbody tr:nth-child(' + (items[i].index + 1) + ')');
|
|
if ($item.length > 0) {
|
|
selectItem($item, items[i].selected, items[i].index);
|
|
}
|
|
} else if (items[i].property !== undefined && items[i].value !== undefined) {
|
|
this.$canvas.find('.repeater-list .repeater-list-wrapper > table tbody tr').each(checkIfItemMatchesValue);
|
|
}
|
|
}
|
|
};
|
|
|
|
$.fn.repeater.Constructor.prototype.list_sizeHeadings = function listSizeHeadings () {
|
|
var $table = this.$element.find('.repeater-list table');
|
|
$table.find('thead th').each(function eachTH () {
|
|
var $th = $(this);
|
|
var $heading = $th.find('.repeater-list-heading');
|
|
$heading.css({ height: $th.outerHeight() });
|
|
$heading.outerWidth($heading.data('forced-width') || $th.outerWidth());
|
|
});
|
|
};
|
|
|
|
$.fn.repeater.Constructor.prototype.list_setFrozenColumns = function listSetFrozenColumns () {
|
|
var frozenTable = this.$canvas.find('.table-frozen');
|
|
var $wrapper = this.$element.find('.repeater-canvas');
|
|
var $table = this.$element.find('.repeater-list .repeater-list-wrapper > table');
|
|
var repeaterWrapper = this.$element.find('.repeater-list');
|
|
var numFrozenColumns = this.viewOptions.list_frozenColumns;
|
|
var self = this;
|
|
|
|
if (this.viewOptions.list_selectable === 'multi') {
|
|
numFrozenColumns = numFrozenColumns + 1;
|
|
$wrapper.addClass('multi-select-enabled');
|
|
}
|
|
|
|
if (frozenTable.length < 1) {
|
|
// setup frozen column markup
|
|
// main wrapper and remove unneeded columns
|
|
var $frozenColumnWrapper = $('<div class="frozen-column-wrapper"></div>').insertBefore($table);
|
|
var $frozenColumn = $table.clone().addClass('table-frozen');
|
|
$frozenColumn.find('th:not(:lt(' + numFrozenColumns + '))').remove();
|
|
$frozenColumn.find('td:not(:nth-child(n+0):nth-child(-n+' + numFrozenColumns + '))').remove();
|
|
|
|
// need to set absolute heading for vertical scrolling
|
|
var $frozenThead = $frozenColumn.clone().removeClass('table-frozen');
|
|
$frozenThead.find('tbody').remove();
|
|
var $frozenTheadWrapper = $('<div class="frozen-thead-wrapper"></div>').append($frozenThead);
|
|
|
|
// this gets a little messy with all the cloning. We need to make sure the ID and FOR
|
|
// attribs are unique for the 'top most' cloned checkbox
|
|
var $checkboxLabel = $frozenTheadWrapper.find('th label.checkbox-custom.checkbox-inline');
|
|
$checkboxLabel.attr('id', $checkboxLabel.attr('id') + '_cloned');
|
|
|
|
$frozenColumnWrapper.append($frozenColumn);
|
|
repeaterWrapper.append($frozenTheadWrapper);
|
|
this.$canvas.addClass('frozen-enabled');
|
|
}
|
|
|
|
this.list_sizeFrozenColumns();
|
|
|
|
$('.frozen-thead-wrapper .repeater-list-heading').on('click', function onClickHeading () {
|
|
var index = $(this).parent('th').index();
|
|
index = index + 1;
|
|
self.$element.find('.repeater-list-wrapper > table thead th:nth-child(' + index + ') .repeater-list-heading')[0].click();
|
|
});
|
|
};
|
|
|
|
$.fn.repeater.Constructor.prototype.list_positionColumns = function listPositionColumns () {
|
|
var $wrapper = this.$element.find('.repeater-canvas');
|
|
var scrollTop = $wrapper.scrollTop();
|
|
var scrollLeft = $wrapper.scrollLeft();
|
|
var frozenEnabled = this.viewOptions.list_frozenColumns || this.viewOptions.list_selectable === 'multi';
|
|
var actionsEnabled = this.viewOptions.list_actions;
|
|
|
|
var canvasWidth = this.$element.find('.repeater-canvas').outerWidth();
|
|
var tableWidth = this.$element.find('.repeater-list .repeater-list-wrapper > table').outerWidth();
|
|
|
|
var actionsWidth = this.$element.find('.table-actions') ? this.$element.find('.table-actions').outerWidth() : 0;
|
|
|
|
var shouldScroll = (tableWidth - (canvasWidth - actionsWidth)) >= scrollLeft;
|
|
|
|
|
|
if (scrollTop > 0) {
|
|
$wrapper.find('.repeater-list-heading').css('top', scrollTop);
|
|
} else {
|
|
$wrapper.find('.repeater-list-heading').css('top', '0');
|
|
}
|
|
|
|
if (scrollLeft > 0) {
|
|
if (frozenEnabled) {
|
|
$wrapper.find('.frozen-thead-wrapper').css('left', scrollLeft);
|
|
$wrapper.find('.frozen-column-wrapper').css('left', scrollLeft);
|
|
}
|
|
if (actionsEnabled && shouldScroll) {
|
|
$wrapper.find('.actions-thead-wrapper').css('right', -scrollLeft);
|
|
$wrapper.find('.actions-column-wrapper').css('right', -scrollLeft);
|
|
}
|
|
} else {
|
|
if (frozenEnabled) {
|
|
$wrapper.find('.frozen-thead-wrapper').css('left', '0');
|
|
$wrapper.find('.frozen-column-wrapper').css('left', '0');
|
|
}
|
|
if (actionsEnabled) {
|
|
$wrapper.find('.actions-thead-wrapper').css('right', '0');
|
|
$wrapper.find('.actions-column-wrapper').css('right', '0');
|
|
}
|
|
}
|
|
};
|
|
|
|
$.fn.repeater.Constructor.prototype.list_createItemActions = function listCreateItemActions () {
|
|
var actionsHtml = '';
|
|
var self = this;
|
|
var i;
|
|
var length;
|
|
var $table = this.$element.find('.repeater-list .repeater-list-wrapper > table');
|
|
var $actionsTable = this.$canvas.find('.table-actions');
|
|
|
|
for (i = 0, length = this.viewOptions.list_actions.items.length; i < length; i++) {
|
|
var action = this.viewOptions.list_actions.items[i];
|
|
var html = action.html;
|
|
|
|
actionsHtml += '<li><a href="#" data-action="' + action.name + '" class="action-item"> ' + html + '</a></li>';
|
|
}
|
|
|
|
var actionsDropdown = '<div class="btn-group">' +
|
|
'<button type="button" class="btn btn-xs btn-default dropdown-toggle repeater-actions-button" data-toggle="dropdown" data-flip="auto" aria-expanded="false">' +
|
|
'<span class="caret"></span>' +
|
|
'</button>' +
|
|
'<ul class="dropdown-menu dropdown-menu-right" role="menu">' +
|
|
actionsHtml +
|
|
'</ul></div>';
|
|
|
|
if ($actionsTable.length < 1) {
|
|
var $actionsColumnWrapper = $('<div class="actions-column-wrapper" style="width: ' + this.list_actions_width + 'px"></div>').insertBefore($table);
|
|
var $actionsColumn = $table.clone().addClass('table-actions');
|
|
$actionsColumn.find('th:not(:last-child)').remove();
|
|
$actionsColumn.find('tr td:not(:last-child)').remove();
|
|
|
|
// Dont show actions dropdown in header if not multi select
|
|
if (this.viewOptions.list_selectable === 'multi' || this.viewOptions.list_selectable === 'action') {
|
|
$actionsColumn.find('thead tr').html('<th><div class="repeater-list-heading">' + actionsDropdown + '</div></th>');
|
|
|
|
if (this.viewOptions.list_selectable !== 'action') {
|
|
// disable the header dropdown until an item is selected
|
|
$actionsColumn.find('thead .btn').attr('disabled', 'disabled');
|
|
}
|
|
} else {
|
|
var label = this.viewOptions.list_actions.label || '<span class="actions-hidden">a</span>';
|
|
$actionsColumn.find('thead tr').addClass('empty-heading').html('<th>' + label + '<div class="repeater-list-heading">' + label + '</div></th>');
|
|
}
|
|
|
|
// Create Actions dropdown for each cell in actions table
|
|
var $actionsCells = $actionsColumn.find('td');
|
|
|
|
$actionsCells.each(function addActionsDropdown (rowNumber) {
|
|
$(this).html(actionsDropdown);
|
|
$(this).find('a').attr('data-row', rowNumber + 1);
|
|
});
|
|
|
|
$actionsColumnWrapper.append($actionsColumn);
|
|
|
|
this.$canvas.addClass('actions-enabled');
|
|
}
|
|
|
|
this.list_sizeActionsTable();
|
|
|
|
// row level actions click
|
|
this.$element.find('.table-actions tbody .action-item').on('click', function onBodyActionItemClick (e) {
|
|
if (!self.isDisabled) {
|
|
var actionName = $(this).data('action');
|
|
var row = $(this).data('row');
|
|
var selected = {
|
|
actionName: actionName,
|
|
rows: [row]
|
|
};
|
|
self.list_getActionItems(selected, e);
|
|
}
|
|
});
|
|
// bulk actions click
|
|
this.$element.find('.table-actions thead .action-item').on('click', function onHeadActionItemClick (e) {
|
|
if (!self.isDisabled) {
|
|
var actionName = $(this).data('action');
|
|
var selected = {
|
|
actionName: actionName,
|
|
rows: []
|
|
};
|
|
var selector = '.repeater-list-wrapper > table .selected';
|
|
|
|
if ( self.viewOptions.list_selectable === 'action' ) {
|
|
selector = '.repeater-list-wrapper > table tr';
|
|
}
|
|
self.$element.find(selector).each(function eachSelector (selectorIndex) {
|
|
selected.rows.push(selectorIndex + 1);
|
|
});
|
|
|
|
self.list_getActionItems(selected, e);
|
|
}
|
|
});
|
|
};
|
|
|
|
$.fn.repeater.Constructor.prototype.list_getActionItems = function listGetActionItems (selected, e) {
|
|
var selectedObj = [];
|
|
var actionObj = $.grep(this.viewOptions.list_actions.items, function matchedActions (actions) {
|
|
return actions.name === selected.actionName;
|
|
})[0];
|
|
for (var i = 0, selectedRowsL = selected.rows.length; i < selectedRowsL; i++) {
|
|
var clickedRow = this.$canvas.find('.repeater-list-wrapper > table tbody tr:nth-child(' + selected.rows[i] + ')');
|
|
selectedObj.push({
|
|
item: clickedRow,
|
|
rowData: clickedRow.data('item_data')
|
|
});
|
|
}
|
|
if (selectedObj.length === 1) {
|
|
selectedObj = selectedObj[0];
|
|
}
|
|
|
|
if (actionObj.clickAction) {
|
|
var callback = function noop () {};// for backwards compatibility. No idea why this was originally here...
|
|
actionObj.clickAction(selectedObj, callback, e);
|
|
}
|
|
};
|
|
|
|
$.fn.repeater.Constructor.prototype.list_sizeActionsTable = function listSizeActionsTable () {
|
|
var $actionsTable = this.$element.find('.repeater-list table.table-actions');
|
|
var $actionsTableHeader = $actionsTable.find('thead tr th');
|
|
var $table = this.$element.find('.repeater-list-wrapper > table');
|
|
|
|
$actionsTableHeader.outerHeight($table.find('thead tr th').outerHeight());
|
|
$actionsTableHeader.find('.repeater-list-heading').outerHeight($actionsTableHeader.outerHeight());
|
|
$actionsTable.find('tbody tr td:first-child').each(function eachFirstChild (i) {
|
|
$(this).outerHeight($table.find('tbody tr:eq(' + i + ') td').outerHeight());
|
|
});
|
|
};
|
|
|
|
$.fn.repeater.Constructor.prototype.list_sizeFrozenColumns = function listSizeFrozenColumns () {
|
|
var $table = this.$element.find('.repeater-list .repeater-list-wrapper > table');
|
|
|
|
this.$element.find('.repeater-list table.table-frozen tr').each(function eachTR (i) {
|
|
$(this).height($table.find('tr:eq(' + i + ')').height());
|
|
});
|
|
|
|
var columnWidth = $table.find('td:eq(0)').outerWidth();
|
|
this.$element.find('.frozen-column-wrapper, .frozen-thead-wrapper').width(columnWidth);
|
|
};
|
|
|
|
$.fn.repeater.Constructor.prototype.list_frozenOptionsInitialize = function listFrozenOptionsInitialize () {
|
|
var $checkboxes = this.$element.find('.frozen-column-wrapper .checkbox-inline');
|
|
var $headerCheckbox = this.$element.find('.header-checkbox .checkbox-custom');
|
|
var $everyTable = this.$element.find('.repeater-list table');
|
|
var self = this;
|
|
|
|
// Make sure if row is hovered that it is shown in frozen column as well
|
|
this.$element.find('tr.selectable').on('mouseover mouseleave', function onMouseEvents (e) {
|
|
var index = $(this).index();
|
|
index = index + 1;
|
|
if (e.type === 'mouseover') {
|
|
$everyTable.find('tbody tr:nth-child(' + index + ')').addClass('hovered');
|
|
} else {
|
|
$everyTable.find('tbody tr:nth-child(' + index + ')').removeClass('hovered');
|
|
}
|
|
});
|
|
|
|
$headerCheckbox.checkbox();
|
|
$checkboxes.checkbox();
|
|
|
|
// Row checkboxes
|
|
var $rowCheckboxes = this.$element.find('.table-frozen tbody .checkbox-inline');
|
|
var $checkAll = this.$element.find('.frozen-thead-wrapper thead .checkbox-inline input');
|
|
$rowCheckboxes.on('change', function onChangeRowCheckboxes (e) {
|
|
e.preventDefault();
|
|
|
|
if (!self.list_revertingCheckbox) {
|
|
if (self.isDisabled) {
|
|
revertCheckbox($(e.currentTarget));
|
|
} else {
|
|
var row = $(this).attr('data-row');
|
|
row = parseInt(row, 10) + 1;
|
|
self.$element.find('.repeater-list-wrapper > table tbody tr:nth-child(' + row + ')').click();
|
|
|
|
var numSelected = self.$element.find('.table-frozen tbody .checkbox-inline.checked').length;
|
|
if (numSelected === 0) {
|
|
$checkAll.prop('checked', false);
|
|
$checkAll.prop('indeterminate', false);
|
|
} else if (numSelected === $rowCheckboxes.length) {
|
|
$checkAll.prop('checked', true);
|
|
$checkAll.prop('indeterminate', false);
|
|
} else {
|
|
$checkAll.prop('checked', false);
|
|
$checkAll.prop('indeterminate', true);
|
|
}
|
|
}
|
|
}
|
|
});
|
|
|
|
// "Check All" checkbox
|
|
$checkAll.on('change', function onChangeCheckAll (e) {
|
|
if (!self.list_revertingCheckbox) {
|
|
if (self.isDisabled) {
|
|
revertCheckbox($(e.currentTarget));
|
|
} else if ($(this).is(':checked')) {
|
|
self.$element.find('.repeater-list-wrapper > table tbody tr:not(.selected)').click();
|
|
self.$element.trigger('selected.fu.repeaterList', $checkboxes);
|
|
} else {
|
|
self.$element.find('.repeater-list-wrapper > table tbody tr.selected').click();
|
|
self.$element.trigger('deselected.fu.repeaterList', $checkboxes);
|
|
}
|
|
}
|
|
});
|
|
|
|
function revertCheckbox ($checkbox) {
|
|
self.list_revertingCheckbox = true;
|
|
$checkbox.checkbox('toggle');
|
|
delete self.list_revertingCheckbox;
|
|
}
|
|
};
|
|
|
|
// ADDITIONAL DEFAULT OPTIONS
|
|
$.fn.repeater.defaults = $.extend({}, $.fn.repeater.defaults, {
|
|
list_columnRendered: null,
|
|
list_columnSizing: true,
|
|
list_columnSyncing: true,
|
|
list_highlightSortedColumn: true,
|
|
list_infiniteScroll: false,
|
|
list_noItemsHTML: 'no items found',
|
|
list_selectable: false,
|
|
list_sortClearing: false,
|
|
list_rowRendered: null,
|
|
list_frozenColumns: 0,
|
|
list_actions: false
|
|
});
|
|
|
|
// EXTENSION DEFINITION
|
|
$.fn.repeater.viewTypes.list = {
|
|
cleared: function cleared () {
|
|
if (this.viewOptions.list_columnSyncing) {
|
|
this.list_sizeHeadings();
|
|
}
|
|
},
|
|
dataOptions: function dataOptions (options) {
|
|
if (this.list_sortDirection) {
|
|
options.sortDirection = this.list_sortDirection;
|
|
}
|
|
if (this.list_sortProperty) {
|
|
options.sortProperty = this.list_sortProperty;
|
|
}
|
|
return options;
|
|
},
|
|
enabled: function enabled (helpers) {
|
|
if (this.viewOptions.list_actions) {
|
|
if (!helpers.status) {
|
|
this.$canvas.find('.repeater-actions-button').attr('disabled', 'disabled');
|
|
} else {
|
|
this.$canvas.find('.repeater-actions-button').removeAttr('disabled');
|
|
toggleActionsHeaderButton.call(this);
|
|
}
|
|
}
|
|
},
|
|
initialize: function initialize (helpers, callback) {
|
|
this.list_sortDirection = null;
|
|
this.list_sortProperty = null;
|
|
this.list_specialBrowserClass = specialBrowserClass();
|
|
this.list_actions_width = (this.viewOptions.list_actions.width !== undefined) ? this.viewOptions.list_actions.width : 37;
|
|
this.list_noItems = false;
|
|
callback();
|
|
},
|
|
resize: function resize () {
|
|
sizeColumns.call(this, this.$element.find('.repeater-list-wrapper > table thead tr'));
|
|
if (this.viewOptions.list_actions) {
|
|
this.list_sizeActionsTable();
|
|
}
|
|
if (this.viewOptions.list_frozenColumns || this.viewOptions.list_selectable === 'multi') {
|
|
this.list_sizeFrozenColumns();
|
|
}
|
|
if (this.viewOptions.list_columnSyncing) {
|
|
this.list_sizeHeadings();
|
|
}
|
|
},
|
|
selected: function selected () {
|
|
var infScroll = this.viewOptions.list_infiniteScroll;
|
|
var opts;
|
|
|
|
this.list_firstRender = true;
|
|
this.$loader.addClass('noHeader');
|
|
|
|
if (infScroll) {
|
|
opts = (typeof infScroll === 'object') ? infScroll : {};
|
|
this.infiniteScrolling(true, opts);
|
|
}
|
|
},
|
|
before: function before (helpers) {
|
|
var $listContainer = helpers.container.find('.repeater-list');
|
|
var self = this;
|
|
var $table;
|
|
|
|
// this is a patch, it was pulled out of `renderThead`
|
|
if (helpers.data.count > 0) {
|
|
this.list_noItems = false;
|
|
} else {
|
|
this.list_noItems = true;
|
|
}
|
|
|
|
if ($listContainer.length < 1) {
|
|
$listContainer = $('<div class="repeater-list ' + this.list_specialBrowserClass + '" data-preserve="shallow"><div class="repeater-list-wrapper" data-infinite="true" data-preserve="shallow"><table aria-readonly="true" class="table" data-preserve="shallow" role="grid"></table></div></div>');
|
|
$listContainer.find('.repeater-list-wrapper').on('scroll.fu.repeaterList', function onScrollRepeaterList () {
|
|
if (self.viewOptions.list_columnSyncing) {
|
|
self.list_positionHeadings();
|
|
}
|
|
});
|
|
if (self.viewOptions.list_frozenColumns || self.viewOptions.list_actions || self.viewOptions.list_selectable === 'multi') {
|
|
helpers.container.on('scroll.fu.repeaterList', function onScrollRepeaterList () {
|
|
self.list_positionColumns();
|
|
});
|
|
}
|
|
|
|
helpers.container.append($listContainer);
|
|
}
|
|
helpers.container.removeClass('actions-enabled actions-enabled multi-select-enabled');
|
|
|
|
$table = $listContainer.find('table');
|
|
renderThead.call(this, $table, helpers.data);
|
|
renderTbody.call(this, $table, helpers.data);
|
|
|
|
return false;
|
|
},
|
|
renderItem: function renderItem (helpers) {
|
|
renderRow.call(this, helpers.container, helpers.subset, helpers.index);
|
|
return false;
|
|
},
|
|
after: function after () {
|
|
var $sorted;
|
|
|
|
if ((this.viewOptions.list_frozenColumns || this.viewOptions.list_selectable === 'multi') && !this.list_noItems) {
|
|
this.list_setFrozenColumns();
|
|
}
|
|
|
|
if (this.viewOptions.list_actions && !this.list_noItems) {
|
|
this.list_createItemActions();
|
|
this.list_sizeActionsTable();
|
|
}
|
|
|
|
if ((this.viewOptions.list_frozenColumns || this.viewOptions.list_actions || this.viewOptions.list_selectable === 'multi') && !this.list_noItems) {
|
|
this.list_positionColumns();
|
|
this.list_frozenOptionsInitialize();
|
|
}
|
|
|
|
if (this.viewOptions.list_columnSyncing) {
|
|
this.list_sizeHeadings();
|
|
this.list_positionHeadings();
|
|
}
|
|
|
|
$sorted = this.$canvas.find('.repeater-list-wrapper > table .repeater-list-heading.sorted');
|
|
if ($sorted.length > 0) {
|
|
this.list_highlightColumn($sorted.data('fu_item_index'));
|
|
}
|
|
|
|
return false;
|
|
}
|
|
};
|
|
}
|
|
|
|
// ADDITIONAL METHODS
|
|
var areDifferentColumns = function areDifferentColumns (oldCols, newCols) {
|
|
if (!newCols) {
|
|
return false;
|
|
}
|
|
if (!oldCols || (newCols.length !== oldCols.length)) {
|
|
return true;
|
|
}
|
|
for (var i = 0, newColsL = newCols.length; i < newColsL; i++) {
|
|
if (!oldCols[i]) {
|
|
return true;
|
|
}
|
|
|
|
for (var j in newCols[i]) {
|
|
if (newCols[i].hasOwnProperty(j) && oldCols[i][j] !== newCols[i][j]) {
|
|
return true;
|
|
}
|
|
}
|
|
}
|
|
return false;
|
|
};
|
|
|
|
var renderColumn = function renderColumn ($row, rows, rowIndex, columns, columnIndex) {
|
|
var className = columns[columnIndex].className;
|
|
var content = rows[rowIndex][columns[columnIndex].property];
|
|
var $col = $('<td></td>');
|
|
var width = columns[columnIndex]._auto_width;
|
|
|
|
var property = columns[columnIndex].property;
|
|
if (this.viewOptions.list_actions !== false && property === '@_ACTIONS_@') {
|
|
content = '<div class="repeater-list-actions-placeholder" style="width: ' + this.list_actions_width + 'px"></div>';
|
|
}
|
|
|
|
content = (content !== undefined) ? content : '';
|
|
|
|
$col.addClass(((className !== undefined) ? className : '')).append(content);
|
|
if (width !== undefined) {
|
|
$col.outerWidth(width);
|
|
}
|
|
|
|
$row.append($col);
|
|
|
|
if (this.viewOptions.list_selectable === 'multi' && columns[columnIndex].property === '@_CHECKBOX_@') {
|
|
var checkBoxMarkup = '<label data-row="' + rowIndex + '" class="checkbox-custom checkbox-inline body-checkbox repeater-select-checkbox">' +
|
|
'<input class="sr-only" type="checkbox"></label>';
|
|
|
|
$col.html(checkBoxMarkup);
|
|
}
|
|
|
|
return $col;
|
|
};
|
|
|
|
var renderHeader = function renderHeader ($tr, columns, index) {
|
|
var chevDown = 'glyphicon-chevron-down';
|
|
var chevron = '.glyphicon.rlc:first';
|
|
var chevUp = 'glyphicon-chevron-up';
|
|
var $div = $('<div class="repeater-list-heading"><span class="glyphicon rlc"></span></div>');
|
|
var checkAllID = (this.$element.attr('id') + '_' || '') + 'checkall';
|
|
|
|
var checkBoxMarkup = '<div class="repeater-list-heading header-checkbox">' +
|
|
'<label id="' + checkAllID + '" class="checkbox-custom checkbox-inline">' +
|
|
'<input class="sr-only" type="checkbox" value="">' +
|
|
'<span class="checkbox-label"> </span>' +
|
|
'</label>' +
|
|
'</div>';
|
|
|
|
var $header = $('<th></th>');
|
|
var self = this;
|
|
var $both;
|
|
var className;
|
|
var sortable;
|
|
var $span;
|
|
var $spans;
|
|
|
|
$div.data('fu_item_index', index);
|
|
$div.prepend(columns[index].label);
|
|
$header.html($div.html()).find('[id]').removeAttr('id');
|
|
|
|
if (columns[index].property !== '@_CHECKBOX_@') {
|
|
$header.append($div);
|
|
} else {
|
|
$header.append(checkBoxMarkup);
|
|
}
|
|
|
|
$both = $header.add($div);
|
|
$span = $div.find(chevron);
|
|
$spans = $span.add($header.find(chevron));
|
|
|
|
if (this.viewOptions.list_actions && columns[index].property === '@_ACTIONS_@') {
|
|
var width = this.list_actions_width;
|
|
$header.css('width', width);
|
|
$div.css('width', width);
|
|
}
|
|
|
|
className = columns[index].className;
|
|
if (className !== undefined) {
|
|
$both.addClass(className);
|
|
}
|
|
|
|
sortable = columns[index].sortable;
|
|
if (sortable) {
|
|
$both.addClass('sortable');
|
|
$div.on('click.fu.repeaterList', function onClickRepeaterList () {
|
|
if (!self.isDisabled) {
|
|
self.list_sortProperty = (typeof sortable === 'string') ? sortable : columns[index].property;
|
|
if ($div.hasClass('sorted')) {
|
|
if ($span.hasClass(chevUp)) {
|
|
$spans.removeClass(chevUp).addClass(chevDown);
|
|
self.list_sortDirection = 'desc';
|
|
} else if (!self.viewOptions.list_sortClearing) {
|
|
$spans.removeClass(chevDown).addClass(chevUp);
|
|
self.list_sortDirection = 'asc';
|
|
} else {
|
|
$both.removeClass('sorted');
|
|
$spans.removeClass(chevDown);
|
|
self.list_sortDirection = null;
|
|
self.list_sortProperty = null;
|
|
}
|
|
} else {
|
|
$tr.find('th, .repeater-list-heading').removeClass('sorted');
|
|
$spans.removeClass(chevDown).addClass(chevUp);
|
|
self.list_sortDirection = 'asc';
|
|
$both.addClass('sorted');
|
|
}
|
|
|
|
self.render({
|
|
clearInfinite: true,
|
|
pageIncrement: null
|
|
});
|
|
}
|
|
});
|
|
}
|
|
|
|
if (columns[index].sortDirection === 'asc' || columns[index].sortDirection === 'desc') {
|
|
$tr.find('th, .repeater-list-heading').removeClass('sorted');
|
|
$both.addClass('sortable sorted');
|
|
if (columns[index].sortDirection === 'asc') {
|
|
$spans.addClass(chevUp);
|
|
this.list_sortDirection = 'asc';
|
|
} else {
|
|
$spans.addClass(chevDown);
|
|
this.list_sortDirection = 'desc';
|
|
}
|
|
|
|
this.list_sortProperty = (typeof sortable === 'string') ? sortable : columns[index].property;
|
|
}
|
|
|
|
$tr.append($header);
|
|
};
|
|
|
|
var onClickRowRepeaterList = function onClickRowRepeaterList (repeater) {
|
|
var isMulti = repeater.viewOptions.list_selectable === 'multi';
|
|
var isActions = repeater.viewOptions.list_actions;
|
|
var $repeater = repeater.$element;
|
|
|
|
if (!repeater.isDisabled) {
|
|
var $item = $(this);
|
|
var index = $(this).index() + 1;
|
|
var $frozenRow = $repeater.find('.frozen-column-wrapper tr:nth-child(' + index + ')');
|
|
var $actionsRow = $repeater.find('.actions-column-wrapper tr:nth-child(' + index + ')');
|
|
var $checkBox = $repeater.find('.frozen-column-wrapper tr:nth-child(' + index + ') .checkbox-inline');
|
|
|
|
if ($item.is('.selected')) {
|
|
$item.removeClass('selected');
|
|
if (isMulti) {
|
|
$checkBox.click();
|
|
$frozenRow.removeClass('selected');
|
|
if (isActions) {
|
|
$actionsRow.removeClass('selected');
|
|
}
|
|
} else {
|
|
$item.find('.repeater-list-check').remove();
|
|
}
|
|
|
|
$repeater.trigger('deselected.fu.repeaterList', $item);
|
|
} else {
|
|
if (!isMulti) {
|
|
repeater.$canvas.find('.repeater-list-check').remove();
|
|
repeater.$canvas.find('.repeater-list tbody tr.selected').each(function deslectRow () {
|
|
$(this).removeClass('selected');
|
|
$repeater.trigger('deselected.fu.repeaterList', $(this));
|
|
});
|
|
$item.find('td:first').prepend('<div class="repeater-list-check"><span class="glyphicon glyphicon-ok"></span></div>');
|
|
$item.addClass('selected');
|
|
$frozenRow.addClass('selected');
|
|
} else {
|
|
$checkBox.click();
|
|
$item.addClass('selected');
|
|
$frozenRow.addClass('selected');
|
|
if (isActions) {
|
|
$actionsRow.addClass('selected');
|
|
}
|
|
}
|
|
$repeater.trigger('selected.fu.repeaterList', $item);
|
|
}
|
|
|
|
toggleActionsHeaderButton.call(repeater);
|
|
}
|
|
};
|
|
|
|
var renderRow = function renderRow ($tbody, rows, index) {
|
|
var $row = $('<tr></tr>');
|
|
|
|
if (this.viewOptions.list_selectable) {
|
|
$row.data('item_data', rows[index]);
|
|
|
|
if (this.viewOptions.list_selectable !== 'action') {
|
|
$row.addClass('selectable');
|
|
$row.attr('tabindex', 0); // allow items to be tabbed to / focused on
|
|
|
|
var repeater = this;
|
|
$row.on('click.fu.repeaterList', function callOnClickRowRepeaterList() {
|
|
onClickRowRepeaterList.call(this, repeater);
|
|
});
|
|
|
|
// allow selection via enter key
|
|
$row.keyup(function onRowKeyup (e) {
|
|
if (e.keyCode === 13) {
|
|
// triggering a standard click event to be caught by the row click handler above
|
|
$row.trigger('click.fu.repeaterList');
|
|
}
|
|
});
|
|
}
|
|
}
|
|
|
|
if (this.viewOptions.list_actions && !this.viewOptions.list_selectable) {
|
|
$row.data('item_data', rows[index]);
|
|
}
|
|
|
|
var columns = [];
|
|
for (var i = 0, length = this.list_columns.length; i < length; i++) {
|
|
columns.push(renderColumn.call(this, $row, rows, index, this.list_columns, i));
|
|
}
|
|
|
|
$tbody.append($row);
|
|
|
|
if (this.viewOptions.list_columnRendered) {
|
|
for (var columnIndex = 0, colLength = columns.length; columnIndex < colLength; columnIndex++) {
|
|
if (!(this.list_columns[columnIndex].property === '@_CHECKBOX_@' || this.list_columns[columnIndex].property === '@_ACTIONS_@')) {
|
|
this.viewOptions.list_columnRendered({
|
|
container: $row,
|
|
columnAttr: this.list_columns[columnIndex].property,
|
|
item: columns[columnIndex],
|
|
rowData: rows[index]
|
|
}, function noop () {});
|
|
}
|
|
}
|
|
}
|
|
|
|
if (this.viewOptions.list_rowRendered) {
|
|
this.viewOptions.list_rowRendered({
|
|
container: $tbody,
|
|
item: $row,
|
|
rowData: rows[index]
|
|
}, function noop () {});
|
|
}
|
|
};
|
|
|
|
var renderTbody = function renderTbody ($table, data) {
|
|
var $tbody = $table.find('tbody');
|
|
var $empty;
|
|
|
|
if ($tbody.length < 1) {
|
|
$tbody = $('<tbody data-container="true"></tbody>');
|
|
$table.append($tbody);
|
|
}
|
|
|
|
if (typeof data.error === 'string' && data.error.length > 0) {
|
|
$empty = $('<tr class="empty text-danger"><td colspan="' + this.list_columns.length + '"></td></tr>');
|
|
$empty.find('td').append(data.error);
|
|
$tbody.append($empty);
|
|
} else if (data.items && data.items.length < 1) {
|
|
$empty = $('<tr class="empty"><td colspan="' + this.list_columns.length + '"></td></tr>');
|
|
$empty.find('td').append(this.viewOptions.list_noItemsHTML);
|
|
$tbody.append($empty);
|
|
}
|
|
};
|
|
|
|
var renderThead = function renderThead ($table, data) {
|
|
var columns = data.columns || [];
|
|
var $thead = $table.find('thead');
|
|
var i;
|
|
var length;
|
|
var $tr;
|
|
|
|
if (this.list_firstRender || areDifferentColumns(this.list_columns, columns) || $thead.length === 0) {
|
|
$thead.remove();
|
|
|
|
// list_noItems is set in `before` method
|
|
|
|
if (this.viewOptions.list_selectable === 'multi' && !this.list_noItems) {
|
|
var checkboxColumn = {
|
|
label: 'c',
|
|
property: '@_CHECKBOX_@',
|
|
sortable: false
|
|
};
|
|
columns.splice(0, 0, checkboxColumn);
|
|
}
|
|
|
|
this.list_columns = columns;
|
|
this.list_firstRender = false;
|
|
this.$loader.removeClass('noHeader');
|
|
|
|
// keep action column header even when empty, you'll need it later....
|
|
if (this.viewOptions.list_actions) {
|
|
var actionsColumn = {
|
|
label: this.viewOptions.list_actions.label || '<span class="actions-hidden">a</span>',
|
|
property: '@_ACTIONS_@',
|
|
sortable: false,
|
|
width: this.list_actions_width
|
|
};
|
|
columns.push(actionsColumn);
|
|
}
|
|
|
|
|
|
$thead = $('<thead data-preserve="deep"><tr></tr></thead>');
|
|
$tr = $thead.find('tr');
|
|
for (i = 0, length = columns.length; i < length; i++) {
|
|
renderHeader.call(this, $tr, columns, i);
|
|
}
|
|
$table.prepend($thead);
|
|
|
|
if (this.viewOptions.list_selectable === 'multi' && !this.list_noItems) {
|
|
// after checkbox column is created need to get width of checkbox column from
|
|
// its css class
|
|
var checkboxWidth = this.$element.find('.repeater-list-wrapper .header-checkbox').outerWidth();
|
|
var selectColumn = $.grep(columns, function grepColumn (column) {
|
|
return column.property === '@_CHECKBOX_@';
|
|
})[0];
|
|
selectColumn.width = checkboxWidth;
|
|
}
|
|
sizeColumns.call(this, $tr);
|
|
}
|
|
};
|
|
|
|
var sizeColumns = function sizeColumns ($tr) {
|
|
var automaticallyGeneratedWidths = [];
|
|
var self = this;
|
|
var i;
|
|
var length;
|
|
var newWidth;
|
|
var widthTaken;
|
|
|
|
if (this.viewOptions.list_columnSizing) {
|
|
i = 0;
|
|
widthTaken = 0;
|
|
$tr.find('th').each(function eachTH () {
|
|
var $th = $(this);
|
|
var width;
|
|
if (self.list_columns[i].width !== undefined) {
|
|
width = self.list_columns[i].width;
|
|
$th.outerWidth(width);
|
|
widthTaken += $th.outerWidth();
|
|
self.list_columns[i]._auto_width = width;
|
|
} else {
|
|
var outerWidth = $th.find('.repeater-list-heading').outerWidth();
|
|
automaticallyGeneratedWidths.push({
|
|
col: $th,
|
|
index: i,
|
|
minWidth: outerWidth
|
|
});
|
|
}
|
|
|
|
i++;
|
|
});
|
|
|
|
length = automaticallyGeneratedWidths.length;
|
|
if (length > 0) {
|
|
var canvasWidth = this.$canvas.find('.repeater-list-wrapper').outerWidth();
|
|
newWidth = Math.floor((canvasWidth - widthTaken) / length);
|
|
for (i = 0; i < length; i++) {
|
|
if (automaticallyGeneratedWidths[i].minWidth > newWidth) {
|
|
newWidth = automaticallyGeneratedWidths[i].minWidth;
|
|
}
|
|
automaticallyGeneratedWidths[i].col.outerWidth(newWidth);
|
|
this.list_columns[automaticallyGeneratedWidths[i].index]._auto_width = newWidth;
|
|
}
|
|
}
|
|
}
|
|
};
|
|
|
|
var specialBrowserClass = function specialBrowserClass () {
|
|
var ua = window.navigator.userAgent;
|
|
var msie = ua.indexOf('MSIE ');
|
|
var firefox = ua.indexOf('Firefox');
|
|
|
|
if (msie > 0 ) {
|
|
return 'ie-' + parseInt(ua.substring(msie + 5, ua.indexOf('.', msie)), 10);
|
|
} else if (firefox > 0) {
|
|
return 'firefox';
|
|
}
|
|
|
|
return '';
|
|
};
|
|
|
|
var toggleActionsHeaderButton = function toggleActionsHeaderButton () {
|
|
var selectedSelector = '.repeater-list-wrapper > table .selected';
|
|
var $actionsColumn = this.$element.find('.table-actions');
|
|
var $selected;
|
|
|
|
if (this.viewOptions.list_selectable === 'action') {
|
|
selectedSelector = '.repeater-list-wrapper > table tr';
|
|
}
|
|
|
|
$selected = this.$canvas.find( selectedSelector );
|
|
|
|
if ($selected.length > 0) {
|
|
$actionsColumn.find('thead .btn').removeAttr('disabled');
|
|
} else {
|
|
$actionsColumn.find('thead .btn').attr('disabled', 'disabled');
|
|
}
|
|
};
|
|
|
|
// -- BEGIN UMD WRAPPER AFTERWORD --
|
|
}));
|
|
// -- END UMD WRAPPER AFTERWORD --
|