UNPKG

arrow-admin

Version:
434 lines (392 loc) 14.1 kB
/* jshint undef: true */ /* global History */ define(['jquery', 'loader','numeral', 'history', 'datatables', 'datatables-bootstrap', 'resize-element', 'datatablesColVis'], function($) { return { /** * Creates an appcelerator style dataTable with a variety of new options (found within 'base') * @param opts * @param $container * @returns {*} */ createTable: function(opts, $container) { var base = { 'scrollY': '100%', //'scrollX': '100%', //scrollXInner = '100%', 'scrollCollapse': false, 'paging': true, 'noData': { // what to show when the table has no data 'icon': 'icon-chart-bar', 'title': 'No data available for current selection', 'description': '' }, 'noDataFilter': { // what to show when the filter has no results 'icon': 'icon-chart-bar', 'title': 'No data available for current selection', 'description': '' }, 'loadMore': true, // adds a button to the bottom of the table to load more records //'infiniteScrolling': true, // allows infinite scrolling 'pageLength': 25, 'stripeClasses': ['appc_table_odd', 'appc_table_even'], //'title': 'Logs', // adds a title to the table /*'buttons': [ // an array of buttons can be added with actions { 'text': 'New', 'icon': 'icon-plus', 'action': function(el) {console.log('new');} 'hidden': true // hides the button after creation }, { 'text': 'Advanced', 'class': '', // any extra classes to add to the button 'id': '' // the id to assign the button. by default it is appc-btn-i, where i is the index of the button 'action': function(el) {console.log('advanced');}, 'addTo': 'search' // where to append the button to. by default it is added in the top-right } ], */ 'colVis': { 'buttonText': 'Show / Hide Fields', 'restore': 'reset', 'showAll': 'all', 'showNone': 'none', 'overlayFade': 0 }//, //selectRow: true, // allow the selection of rows (also takes a function which is instigated on selection) //'advancedHeader': true // an extra header allowing for better horizontal scrolling and showing/hiding fields }; opts = overwriteKeys(base, opts); if (opts.loadMore) { opts.paging = true; } if (opts.infiniteScrolling) { opts.paging = true; opts.pageLength = 5; } if (opts.advancedHeader) { opts.scrollX = '100%'; opts.sScrollXInner = '100%'; } function isObjectAndNotArray(object) { return (typeof object === 'object' && !Array.isArray(object)); } function overwriteKeys(baseObject, overrideObject, createNew) { if (!baseObject) { baseObject = {}; } if (createNew) { baseObject = JSON.parse(JSON.stringify(baseObject)); } Object.keys(overrideObject).forEach(function(key) { if (isObjectAndNotArray(baseObject[key]) && isObjectAndNotArray(overrideObject[key])) { overwriteKeys(baseObject[key], overrideObject[key]); } else { baseObject[key] = overrideObject[key]; } }); return baseObject; } var $table = $('#appc_table'); $table.dataTable(opts); var dataTableRef = $table.DataTable(); // Do some shuffling var $tableFilter = $('#appc_table_filter'); $tableFilter // Add styling. .addClass('form-group has-feedback mg-top-m') // Add search icon and clear button. .append('<i class=\'icon-search-1 form-control-feedback icon-clr-apple icon-md2\'></i>') // Wrap in the search form (for styling purposes). .wrap('<form class=\'search\' onsubmit=\'return false\'></form>') // Remove input-sm class. .find('input.input-sm').removeClass('input-sm'); var $labelContents = $tableFilter.find('label').contents(); // Remove 'Search: ' text. $labelContents.filter(function () { return (this.nodeType === 3); }).remove(); //remove the label wrapper $labelContents.unwrap(); // We need to move some of the elements around a bit. var search = $tableFilter.parent(), pageSize = $('#appc_table_length'), pageInfo = $('#appc_table_info'), pages = $('#appc_table_paginate'); pageSize.addClass('form-inline').children().addClass('pull-right'); // make sure table background is set $('#mainContent').removeClass('panel'); $('.dataTables_scroll').addClass('panel'); var newHeader = $('' + '<div id=\'appc_table_new_header\' class=\'panel-heading panel-heading-multiline table_header\'>' + '<div class=\'pull-left\'></div>' + '<div class=\'txt-center\'></div>' + '<div class=\'pull-right txt-right pd-top-m\'></div>' + '</div>' ), newFooter = $('' + '<div id=\'appc_table_new_footer\'>' + '<div class=\'pull-left\'></div>' + '<div class=\'txt-center\'></div>' + '<div class=\'pull-right txt-right pd-top-m\'></div>' + '</div>' ); $('#appc_table_wrapper') .prepend(newHeader) .append(newFooter); /** * hides the 'load more' button if there is nothing more to load */ function hideButtonIfNoMoreData(btn) { if (dataTableRef.page.info().pages > 1) { btn.show(); } else { btn.hide(); } } // show loadMore if (opts.infiniteScrolling) { pageSize.remove(); pages.remove(); var avgPerRow = 33,//px for each row canScroll = $container.innerHeight() <= $container.prop('scrollHeight') || $container.innerHeight() <= $container.prop('scrollHeight') + 1 || $container.innerHeight() <= $container.prop('scrollHeight') - 1 ; if (canScroll && (dataTableRef.page.info().pages > 1)) { // calculate how many more records to add to fill the window var usedHeight = 125 - 40;//px for the header / footer usedHeight += avgPerRow * dataTableRef.page.info().length; var leftoverHeight = ($container.innerHeight() - usedHeight); var toAdd = (leftoverHeight/avgPerRow); if (toAdd < 0) { toAdd = 0; } dataTableRef.page.len(dataTableRef.page.len() + toAdd).draw(); } $container.scroll(function () { var maxScroll = $container.prop('scrollHeight') - $container.innerHeight(); // if the scroll bar is ~2 records from the bottom then add some more (if there are any left) if (($container.scrollTop() >= maxScroll - (avgPerRow * 2)) && (dataTableRef.page.info().pages > 1)) { dataTableRef.page.len(dataTableRef.page.len() + opts.pageLength).draw(); } }); } else if (opts.loadMore) { newFooter .addClass('dataTables_more') .find('.txt-center') .append('<button type=\'button\'>Load more</button>'); $('.dataTables_scroll').addClass('can_load_more'); // load more elements on button click var $loadMore = $('.dataTables_more').find('button'); hideButtonIfNoMoreData($loadMore); $loadMore.click(function () { dataTableRef.page.len(dataTableRef.page.len() + opts.pageLength).draw(); hideButtonIfNoMoreData($loadMore); }); dataTableRef.on('search.dt', function () { hideButtonIfNoMoreData($loadMore); }); pageSize.remove(); pages.remove(); } else if (opts.paging){ newFooter.find('> div:nth-child(3)').append(pageSize); newFooter.find('> div:nth-child(2)').append(pages); } newHeader.find('> div:nth-child(1)') .append(pageInfo) .addClass('col-md-4 col-sm-8') .removeClass('pull-left'); newHeader.find('> div:nth-child(2)') .append(search) .addClass('col-md-4 col-sm-12'); // Advanced Features // add title to the table if (opts.title) { pageInfo.parent() .addClass('has-title') .prepend('<div class=\'table-title\'>' + opts.title + '</div>'); } var $search = $('#appc_table_new_header form.search'); $search.parent().addClass('search-holder'); // add buttons to the table if (opts.buttons && opts.buttons.length) { var addButton = function(btn) { var wrapper = $('#appc_table_wrapper'), $btn = '<div class=\'btn btn-default pull-right txt-14 ' + (btn.class || '') + ' \' id=' + btn.id + '>' + (btn.icon ? '<i class=' + btn.icon + '></i>' : '') + (btn.text ? btn.text : '') + '</div>'; if (btn.addTo === 'search') { var $searchHolder = wrapper.find('.search-holder') .addClass('has-buttons col-md-6').removeClass('col-md-4'); $searchHolder.siblings('.col-md-4').addClass('col-md-3').removeClass('col-md-4'); $btn = $($btn) .prependTo($searchHolder) .addClass('btn-search'); } else { $btn = $($btn) .prependTo(wrapper) .addClass('btn-header'); } btn.hidden && $btn.hide(); return $btn.click(btn.action); }; var width = 1; // because some wierd stuff happens if the width is exactly the size of the buttons for (var i = 0, len = opts.buttons.length, btn = opts.buttons[i]; i < len; ++i, btn = opts.buttons[i]) { !(btn.id) && (btn.id = 'appc-btn-' + i); var $btn = addButton(btn); if (btn.addTo === 'search') { width += $btn.outerWidth(true); } } $search.css('padding-right', width); } var scrollBody = $('.dataTables_scrollBody'), loadColVis = true; // add advanced table options. This does the following: // - allows the user to show/hide fields // - adds better horizontal field management if (opts.advancedHeader) { $('#appc_table_wrapper .row').first(). html( '<div class=\'col-xs-12\'>' + '<div class=\'advanced-header\'</div>' + '</div>'); $('.dataTables_scroll').addClass('has-advanced-header'); var advancedHeader = $('.advanced-header'); // Add 'show/hide fields' area advancedHeader.append('<div class=\'pull-left\'></div>'); // Add the colVis button var colVis = new $.fn.dataTable.ColVis(dataTableRef, opts.colVis); $(colVis.button()) .appendTo('.advanced-header .pull-left') .find('button') .addClass('btn btn-default') .removeClass('ColVis_Button') .click(function () { if (loadColVis) { // Need to push the UI changes to the end of the call stack setTimeout(function () { $('.ColVis_collection') .prepend('<div class=\'ColVis_fields\'></div>'); $('.ColVis_collection li:not(.ColVis_Special)').each(function() { var self = $(this); self.find('input') .after(self.find('span')) .wrap('<div class=\'pull-right\'></div>') .after('<div class=\'font-checkbox\'></div>'); $('.ColVis_fields').append(self); }); loadColVis = false; }, 0); } }); // more fields area advancedHeader.append( '<div class=\'pull-right\'>' + 'More Fields' + '<div class=\'btn-group\'>' + '<div class=\'btn btn-default btn-left\'><i class=\'icon-left-open\'></i></div>' + '<div class=\'btn btn-default btn-right\'><i class=\'icon-right-open\'></i></div>' + '</div>' + '</div>'); setShiftButtons(); // recalculate scroll on resize window.addResizeListener(document.getElementById('appc_table_wrapper'), function() { setShiftButtons(); //dataTableRef.columns.adjust(false).draw(false); }); advancedHeader.find('.btn-left').click(function(){ scrollTable(scrollBody.scrollLeft() + getScrollAmountLeft()); }); advancedHeader.find('.btn-right').click(function(){ scrollTable(getScrollAmountRight()); }); } function scrollTable(amount) { scrollBody.scrollLeft(amount); setShiftButtons(); } function getScrollAmountRight() { var header = $('.dataTables_scrollHeadInner th'), headerWidths = header.map(function(){ return $(this).outerWidth(); }).get(), currentWidth = 0, i = -1; while (currentWidth < scrollBody.width() + scrollBody.scrollLeft()) { i++; currentWidth += headerWidths[i]; } // the header at i is not visible/partially visible return (currentWidth - headerWidths[i]); } function getScrollAmountLeft() { return -300; //TODO: sort out left alternative to the scroll right above. } function setShiftButtons() { var advHeader = $('.advanced-header'); var btnLeft = $('.btn-left', advHeader); // if we can scroll left if (scrollBody.scrollLeft() !== 0) { btnLeft.removeAttr('disabled'); } else { btnLeft.attr('disabled', 'disabled'); } var btnRight = $('.btn-right', advHeader); // if we can scroll right if (scrollBody.width() + scrollBody.scrollLeft() !== scrollBody.prop('scrollWidth')) { btnRight.removeAttr('disabled'); } else { btnRight.attr('disabled', 'disabled'); } } // add field selection if (opts.selectRow) { dataTableRef.on('click', 'tr', function (_event) { $(this).toggleClass('selected'); typeof opts.selectRow === 'function' && opts.selectRow(_event, this); _event.isDefaultPrevented() && $(this).toggleClass('selected'); }); } // add no-data state $('#appc_table_wrapper').append( '<div class=\'no-data txt-center\'>' + '<i class=\'' + opts.noData.icon + ' icon-xxl\'></i><div>' + '<span>' + opts.noData.title + '</span><br>' + opts.noData.description + '</div>' + '</div>'); this._handleNoData(); $table.data('loaded', true); return dataTableRef; }, replaceData: function(table, _data) { this._handleNoData(function () { table .clear() .rows.add(_data) .search('') .draw(); }); }, reloadTable: function(table, draw) { this._handleNoData(function () { table .search('') .draw(draw); }); }, _handleNoData: function(fn) { var tableWrapper = $('#appc_table_wrapper'); if (fn) { // need to do this otherwise the header will mess up tableWrapper.removeClass('wrapper-no-data'); fn(); } if ($('.dataTables_empty').length) { tableWrapper.addClass('wrapper-no-data'); } else { tableWrapper.removeClass('wrapper-no-data'); } } }; });