/* * Fuel UX Datagrid * https://github.com/ExactTarget/fuelux * * Copyright (c) 2012 ExactTarget * Licensed under the MIT license. */ define(['require','jquery'],function(require) { var $ = require('jquery'); // Relates to thead .sorted styles in datagrid.less var SORTED_HEADER_OFFSET = 22; // DATAGRID CONSTRUCTOR AND PROTOTYPE var Datagrid = function (element, options) { this.$element = $(element); this.$thead = this.$element.find('thead'); this.$tfoot = this.$element.find('tfoot'); this.$footer = this.$element.find('tfoot th'); this.$footerchildren = this.$footer.children().show().css('visibility', 'hidden'); this.$topheader = this.$element.find('thead th'); this.$searchcontrol = this.$element.find('.datagrid-search'); this.$filtercontrol = this.$element.find('.filter'); this.$pagesize = this.$element.find('.grid-pagesize'); this.$pageinput = this.$element.find('.grid-pager input'); this.$pagedropdown = this.$element.find('.grid-pager .dropdown-menu'); this.$prevpagebtn = this.$element.find('.grid-prevpage'); this.$nextpagebtn = this.$element.find('.grid-nextpage'); this.$pageslabel = this.$element.find('.grid-pages'); this.$countlabel = this.$element.find('.grid-count'); this.$startlabel = this.$element.find('.grid-start'); this.$endlabel = this.$element.find('.grid-end'); this.$tbody = $('').insertAfter(this.$thead); this.$colheader = $('').appendTo(this.$thead); this.options = $.extend(true, {}, $.fn.datagrid.defaults, options); // Shim until v3 -- account for FuelUX select or native select for page size: if (this.$pagesize.hasClass('select')) { this.options.dataOptions.pageSize = parseInt(this.$pagesize.select('selectedItem').value, 10); } else { this.options.dataOptions.pageSize = parseInt(this.$pagesize.val(), 10); } // Shim until v3 -- account for older search class: if (this.$searchcontrol.length <= 0) { this.$searchcontrol = this.$element.find('.search'); } this.columns = this.options.dataSource.columns(); this.$nextpagebtn.on('click', $.proxy(this.next, this)); this.$prevpagebtn.on('click', $.proxy(this.previous, this)); this.$searchcontrol.on('searched cleared', $.proxy(this.searchChanged, this)); this.$filtercontrol.on('changed', $.proxy(this.filterChanged, this)); this.$colheader.on('click', 'th', $.proxy(this.headerClicked, this)); if(this.$pagesize.hasClass('select')) { this.$pagesize.on('changed', $.proxy(this.pagesizeChanged, this)); } else { this.$pagesize.on('change', $.proxy(this.pagesizeChanged, this)); } this.$pageinput.on('change', $.proxy(this.pageChanged, this)); this.renderColumns(); if (this.options.stretchHeight) this.initStretchHeight(); this.renderData(); }; Datagrid.prototype = { constructor: Datagrid, renderColumns: function () { var self = this; this.$footer.attr('colspan', this.columns.length); this.$topheader.attr('colspan', this.columns.length); var colHTML = ''; $.each(this.columns, function (index, column) { colHTML += ''; }); self.$colheader.append(colHTML); }, updateColumns: function ($target, direction) { this._updateColumns(this.$colheader, $target, direction); if (this.$sizingHeader) { this._updateColumns(this.$sizingHeader, this.$sizingHeader.find('th').eq($target.index()), direction); } }, _updateColumns: function ($header, $target, direction) { var className = (direction === 'asc') ? 'icon-chevron-up' : 'icon-chevron-down'; $header.find('i.datagrid-sort').remove(); $header.find('th').removeClass('sorted'); $('').addClass(className + ' datagrid-sort').appendTo($target); $target.addClass('sorted'); }, updatePageDropdown: function (data) { var pageHTML = ''; for (var i = 1; i <= data.pages; i++) { pageHTML += '
  • ' + i + '
  • '; } this.$pagedropdown.html(pageHTML); }, updatePageButtons: function (data) { if (data.page === 1) { this.$prevpagebtn.attr('disabled', 'disabled'); } else { this.$prevpagebtn.removeAttr('disabled'); } if (data.page === data.pages) { this.$nextpagebtn.attr('disabled', 'disabled'); } else { this.$nextpagebtn.removeAttr('disabled'); } }, renderData: function () { var self = this; this.$tbody.html(this.placeholderRowHTML(this.options.loadingHTML)); this.options.dataSource.data(this.options.dataOptions, function (data) { var itemdesc = (data.count === 1) ? self.options.itemText : self.options.itemsText; var rowHTML = ''; self.$footerchildren.css('visibility', function () { return (data.count > 0) ? 'visible' : 'hidden'; }); self.$pageinput.val(data.page); self.$pageslabel.text(data.pages); self.$countlabel.text(data.count + ' ' + itemdesc); self.$startlabel.text(data.start); self.$endlabel.text(data.end); self.updatePageDropdown(data); self.updatePageButtons(data); $.each(data.data, function (index, row) { rowHTML += ''; $.each(self.columns, function (index, column) { rowHTML += '' + row[column.property] + ''; }); rowHTML += ''; }); if (!rowHTML) rowHTML = self.placeholderRowHTML('0 ' + self.options.itemsText); self.$tbody.html(rowHTML); self.stretchHeight(); self.$element.trigger('loaded'); }); }, placeholderRowHTML: function (content) { return '' + content + ''; }, headerClicked: function (e) { var $target = $(e.target); if (!$target.hasClass('sortable')) return; var direction = this.options.dataOptions.sortDirection; var sort = this.options.dataOptions.sortProperty; var property = $target.data('property'); if (sort === property) { this.options.dataOptions.sortDirection = (direction === 'asc') ? 'desc' : 'asc'; } else { this.options.dataOptions.sortDirection = 'asc'; this.options.dataOptions.sortProperty = property; } this.options.dataOptions.pageIndex = 0; this.updateColumns($target, this.options.dataOptions.sortDirection); this.renderData(); }, pagesizeChanged: function (e, pageSize) { if(pageSize) { this.options.dataOptions.pageSize = parseInt(pageSize.value, 10); } else { this.options.dataOptions.pageSize = parseInt($(e.target).val(), 10); } this.options.dataOptions.pageIndex = 0; this.renderData(); }, pageChanged: function (e) { var pageRequested = parseInt($(e.target).val(), 10); pageRequested = (isNaN(pageRequested)) ? 1 : pageRequested; var maxPages = this.$pageslabel.text(); this.options.dataOptions.pageIndex = (pageRequested > maxPages) ? maxPages - 1 : pageRequested - 1; this.renderData(); }, searchChanged: function (e, search) { this.options.dataOptions.search = search; this.options.dataOptions.pageIndex = 0; this.renderData(); }, filterChanged: function (e, filter) { this.options.dataOptions.filter = filter; this.options.dataOptions.pageIndex = 0; this.renderData(); }, previous: function () { this.$nextpagebtn.attr('disabled', 'disabled'); this.$prevpagebtn.attr('disabled', 'disabled'); this.options.dataOptions.pageIndex--; this.renderData(); }, next: function () { this.$nextpagebtn.attr('disabled', 'disabled'); this.$prevpagebtn.attr('disabled', 'disabled'); this.options.dataOptions.pageIndex++; this.renderData(); }, reload: function () { this.options.dataOptions.pageIndex = 0; this.renderData(); }, initStretchHeight: function () { this.$gridContainer = this.$element.parent(); this.$element.wrap('
    '); this.$stretchWrapper = this.$element.parent(); this.$headerTable = $('').attr('class', this.$element.attr('class')); this.$footerTable = this.$headerTable.clone(); this.$headerTable.prependTo(this.$gridContainer).addClass('datagrid-stretch-header'); this.$thead.detach().appendTo(this.$headerTable); this.$sizingHeader = this.$thead.clone(); this.$sizingHeader.find('tr:first').remove(); this.$footerTable.appendTo(this.$gridContainer).addClass('datagrid-stretch-footer'); this.$tfoot.detach().appendTo(this.$footerTable); }, stretchHeight: function () { if (!this.$gridContainer) return; this.setColumnWidths(); var targetHeight = this.$gridContainer.height(); var headerHeight = this.$headerTable.outerHeight(); var footerHeight = this.$footerTable.outerHeight(); var overhead = headerHeight + footerHeight; this.$stretchWrapper.height(targetHeight - overhead); }, setColumnWidths: function () { if (!this.$sizingHeader) return; this.$element.prepend(this.$sizingHeader); var $sizingCells = this.$sizingHeader.find('th'); var columnCount = $sizingCells.length; function matchSizingCellWidth(i, el) { if (i === columnCount - 1) return; var $el = $(el); var $sourceCell = $sizingCells.eq(i); var width = $sourceCell.width(); // TD needs extra width to match sorted column header if ($sourceCell.hasClass('sorted') && $el.prop('tagName') === 'TD') width = width + SORTED_HEADER_OFFSET; $el.width(width); } this.$colheader.find('th').each(matchSizingCellWidth); this.$tbody.find('tr:first > td').each(matchSizingCellWidth); this.$sizingHeader.detach(); } }; // DATAGRID PLUGIN DEFINITION $.fn.datagrid = function (option) { return this.each(function () { var $this = $(this); var data = $this.data('datagrid'); var options = typeof option === 'object' && option; if (!data) $this.data('datagrid', (data = new Datagrid(this, options))); if (typeof option === 'string') data[option](); }); }; $.fn.datagrid.defaults = { dataOptions: { pageIndex: 0, pageSize: 10 }, loadingHTML: '
    ', itemsText: 'items', itemText: 'item' }; $.fn.datagrid.Constructor = Datagrid; });