UNPKG

fuelux

Version:

Base Fuel UX styles and controls

1,030 lines (880 loc) 36.1 kB
/* 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">&nbsp;</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 --