initial commit

This commit is contained in:
2017-12-14 10:17:13 +01:00
commit db72cb61d3
6942 changed files with 1773088 additions and 0 deletions
+333
View File
@@ -0,0 +1,333 @@
@charset "utf-8";
.footable {
width: 100%;
/** SORTING **/
/** FILTERING **/
/** EDITING BODY**/
/** EDITING FOOT**/
/** PAGINATION **/
}
.footable span.fooicon {
font-family: "Web Icons";
}
.footable.breakpoint > tbody > tr > td {
border-bottom: none;
}
.footable.breakpoint > tbody > tr > td > span.footable-toggle:before {
content: "";
}
.footable.breakpoint > tbody > tr:hover:not(.footable-row-detail) {
cursor: pointer;
}
.footable.breakpoint > tbody > tr > td.footable-cell-detail {
border-top: none;
}
.footable.breakpoint > tbody > tr > td > span.footable-toggle {
display: inline-block;
padding-right: 5px;
font-family: "Web Icons";
font-size: 14px;
font-style: normal;
font-weight: normal;
font-variant: normal;
text-transform: none;
speak: none;
-webkit-font-smoothing: antialiased;
}
.footable.breakpoint > tbody > tr > td > span.footable-toggle:before {
content: "";
}
.footable.breakpoint.toggle-circle > tbody > tr > td > span.fooicon-minus:before {
content: "";
}
.footable.breakpoint.toggle-circle > tbody > tr > td > span.fooicon-minus:before:hover {
background-color: #f3f7f9;
}
.footable.breakpoint.toggle-circle > tbody > tr > td > span.fooicon-plus:before {
content: "";
}
.footable.breakpoint.toggle-arrow > tbody > tr > td > span.fooicon-minus:before {
content: "";
}
.footable.breakpoint.toggle-arrow > tbody > tr > td > span.fooicon-minus:before:hover {
background-color: #f3f7f9;
}
.footable.breakpoint.toggle-arrow > tbody > tr > td > span.fooicon-plus:before {
content: "";
}
.footable.breakpoint.toggle-arrow-small > tbody > tr > td > span.fooicon-minus:before {
content: "";
}
.footable.breakpoint.toggle-arrow-small > tbody > tr > td > span.fooicon-minus:before:hover {
background-color: #f3f7f9;
}
.footable.breakpoint.toggle-arrow-small > tbody > tr > td > span.fooicon-plus:before {
content: "";
}
.footable.breakpoint.toggle-arrow-circle > tbody > tr > td > span.fooicon-minus:before {
content: "";
}
.footable.breakpoint.toggle-arrow-circle > tbody > tr > td > span.fooicon-minus:before:hover {
background-color: #f3f7f9;
}
.footable.breakpoint.toggle-arrow-circle > tbody > tr > td > span.fooicon-plus:before {
content: "";
}
.footable.breakpoint.toggle-arrow-tiny > tbody > tr > td > span.fooicon-minus:before {
content: "";
}
.footable.breakpoint.toggle-arrow-tiny > tbody > tr > td > span.fooicon-minus:before:hover {
background-color: #f3f7f9;
}
.footable.breakpoint.toggle-arrow-tiny > tbody > tr > td > span.fooicon-plus:before {
content: "";
}
.footable.breakpoint.toggle-medium > tbody > tr > td > span.footable-toggle {
font-size: 18px;
}
.footable.breakpoint.toggle-large > tbody > tr > td > span.footable-toggle {
font-size: 24px;
}
.footable > thead > tr > th {
-webkit-user-select: none;
-moz-user-select: -moz-none;
-ms-user-select: none;
user-select: none;
-webkit-touch-callout: none;
}
.footable > thead > tr > th.footable-sortable:hover {
cursor: pointer;
}
.footable > thead > tr > th.footable-asc > span.fooicon-sort-asc:before {
content: "";
opacity: .5;
}
.footable > thead > tr > th.footable-desc > span.fooicon-sort-desc:before {
content: "";
opacity: .5;
}
.footable > thead > tr > th > span.fooicon-sort {
display: inline-block;
padding-left: 5px;
font-family: "Web Icons";
font-style: normal;
font-weight: normal;
font-variant: normal;
text-transform: none;
speak: none;
-webkit-font-smoothing: antialiased;
}
.footable > thead > tr > th > span.fooicon-sort:before {
content: "";
opacity: .2;
}
.footable > thead > tr.footable-filtering > th .form-inline .form-group {
display: block;
}
@media (min-width: 768px) {
.footable > thead > tr.footable-filtering > th .form-inline .form-group {
display: inline-block;
}
}
.footable > thead > tr.footable-filtering > th .form-inline .form-control {
display: block;
width: 100%;
}
@media (min-width: 768px) {
.footable > thead > tr.footable-filtering > th .form-inline .form-control {
display: inline-block;
width: auto;
}
}
.footable > thead > tr.footable-filtering > th > .form-inline {
-ms-flex-pack: end;
justify-content: flex-end;
}
.footable > thead > tr.footable-filtering > th .input-group-btn {
width: 1%;
}
@media (min-width: 768px) {
.footable > thead > tr.footable-filtering > th .input-group-btn {
width: auto;
}
}
.footable > thead > tr.footable-filtering > th .input-group-btn:not(:first-child) > .btn:hover {
z-index: 2;
}
.footable > thead > tr.footable-filtering > th ul.dropdown-menu > li > a {
padding: 3px 20px;
}
.footable > thead > tr.footable-filtering > th ul.dropdown-menu > li > a.checkbox input[type="checkbox"] {
margin-top: 4px;
}
.footable > thead > tr.footable-filtering > th ul.dropdown-menu > li > a:hover {
background-color: #f3f7f9;
}
.footable > thead > tr.footable-filtering > th span.fooicon-search:before {
content: "";
}
.footable > thead > tr.footable-filtering > th span.fooicon-remove:before {
content: "";
}
.footable > tbody > tr > td span.fooicon-pencil:before {
content: "";
}
.footable > tbody > tr > td span.fooicon-trash:before {
content: "";
}
.footable > tfoot > tr > td span.fooicon-pencil:before {
content: "";
}
.footable > tfoot .pagination {
-ms-flex-pack: center;
justify-content: center;
margin: 0;
}
.footable > tfoot .pagination > li {
display: inline;
}
.footable > tfoot .pagination > li.footable-page {
display: none;
}
.footable > tfoot .pagination > li.footable-page.visible {
display: inline;
}
.footable > tfoot .pagination > li:first-child > a {
margin-left: 0;
border-top-left-radius: .215rem;
border-bottom-left-radius: .215rem;
}
.footable > tfoot .pagination > li:last-child > a {
border-top-right-radius: .215rem;
border-bottom-right-radius: .215rem;
}
.footable > tfoot .pagination > li.active > a, .footable > tfoot .pagination > li.active > a:focus, .footable > tfoot .pagination > li.active > a:hover {
z-index: 2;
color: #fff;
cursor: default;
background-color: #3e8ef7;
border-color: #3e8ef7;
}
.footable > tfoot .pagination > li.disabled > a, .footable > tfoot .pagination > li.disabled > a:focus, .footable > tfoot .pagination > li.disabled > a:hover {
color: #ccd5db;
cursor: not-allowed;
background-color: transparent;
border-color: #e4eaec;
}
.footable > tfoot .pagination a {
position: relative;
float: left;
padding: .643rem 1.072rem;
margin-left: -1px;
line-height: 1.57142857;
color: #76838f;
text-decoration: none;
background-color: transparent;
border: 1px solid #e4eaec;
}
.footable > tfoot .pagination a:focus, .footable > tfoot .pagination a:hover {
color: #589ffc;
background-color: #f3f7f9;
border-color: #e4eaec;
}
.footable.no-paging .hide-if-no-paging {
display: none;
}
.footable-row-detail-inner {
display: table;
}
.footable-row-detail-row {
display: table-row;
line-height: 1.5em;
}
.footable-row-detail-group {
display: block;
font-size: 1.2em;
font-weight: 500;
line-height: 2em;
}
.footable-row-detail-name {
display: table-cell;
padding-right: .5em;
font-weight: 500;
}
.footable-row-detail-value {
display: table-cell;
}
.footable-odd {
background-color: rgba(243, 247, 249, .3);
}
/** fix table-hover **/
.table-hover.footable tbody tr.footable-detail-row:hover {
background-color: transparent;
}
/** fix table-bordered/hover/striped style in Footable **/
.table-bordered.footable tbody tr.footable-detail-row > td, .table-hover.footable tbody tr.footable-detail-row > td, .table-striped.footable tbody tr.footable-detail-row > td {
padding: 0;
}
+3643
View File
File diff suppressed because it is too large Load Diff
File diff suppressed because one or more lines are too long
+9
View File
File diff suppressed because one or more lines are too long
+803
View File
@@ -0,0 +1,803 @@
/*
* FooTable v3 - FooTable is a jQuery plugin that aims to make HTML tables on smaller devices look awesome.
* @version 3.1.6
* @link http://fooplugins.com
* @copyright Steven Usher & Brad Vincent 2015
* @license Released under the GPLv3 license.
*/
(function($, F){
F.Editing = F.Component.extend(/** @lends FooTable.Editing */{
/**
* The editing component adds a column with edit and delete buttons to each row as well as a single add row button in the footer.
* @constructs
* @extends FooTable.Component
* @param {FooTable.Table} table - The parent {@link FooTable.Table} object for the component.
* @returns {FooTable.Editing}
*/
construct: function(table){
// call the base constructor
this._super(table, table.o.editing.enabled);
/**
* Whether or not to automatically page to a new row when it is added to the table.
* @type {boolean}
*/
this.pageToNew = table.o.editing.pageToNew;
/**
* Whether or not the editing column and add row button are always visible.
* @type {boolean}
*/
this.alwaysShow = table.o.editing.alwaysShow;
/**
* The options for the editing column. @see {@link FooTable.EditingColumn} for more info.
* @type {object}
* @prop {string} classes="footable-editing" - A space separated string of class names to apply to all cells in the column.
* @prop {string} name="editing" - The name of the column.
* @prop {string} title="" - The title displayed in the header row of the table for the column.
* @prop {boolean} filterable=false - Whether or not the column should be filterable when using the filtering component.
* @prop {boolean} sortable=false - Whether or not the column should be sortable when using the sorting component.
*/
this.column = $.extend(true, {}, table.o.editing.column, {visible: this.alwaysShow});
/**
* The position of the editing column in the table as well as the alignment of the buttons.
* @type {string}
*/
this.position = table.o.editing.position;
/**
* The text that appears in the show button. This can contain HTML.
* @type {string}
*/
this.showText = table.o.editing.showText;
/**
* The text that appears in the hide button. This can contain HTML.
* @type {string}
*/
this.hideText = table.o.editing.hideText;
/**
* The text that appears in the add button. This can contain HTML.
* @type {string}
*/
this.addText = table.o.editing.addText;
/**
* The text that appears in the edit button. This can contain HTML.
* @type {string}
*/
this.editText = table.o.editing.editText;
/**
* The text that appears in the delete button. This can contain HTML.
* @type {string}
*/
this.deleteText = table.o.editing.deleteText;
/**
* The text that appears in the view button. This can contain HTML.
* @type {string}
*/
this.viewText = table.o.editing.viewText;
/**
* Whether or not to show the Add Row button.
* @type {boolean}
*/
this.allowAdd = table.o.editing.allowAdd;
/**
* Whether or not to show the Edit Row button.
* @type {boolean}
*/
this.allowEdit = table.o.editing.allowEdit;
/**
* Whether or not to show the Delete Row button.
* @type {boolean}
*/
this.allowDelete = table.o.editing.allowDelete;
/**
* Whether or not to show the View Row button.
* @type {boolean}
*/
this.allowView = table.o.editing.allowView;
/**
* Caches the row button elements to help with performance.
* @type {(null|jQuery)}
* @private
*/
this._$buttons = null;
/**
* This object is used to contain the callbacks for the add, edit and delete row buttons.
* @type {object}
* @prop {function} addRow
* @prop {function} editRow
* @prop {function} deleteRow
* @prop {function} viewRow
*/
this.callbacks = {
addRow: F.checkFnValue(this, table.o.editing.addRow),
editRow: F.checkFnValue(this, table.o.editing.editRow),
deleteRow: F.checkFnValue(this, table.o.editing.deleteRow),
viewRow: F.checkFnValue(this, table.o.editing.viewRow)
};
},
/* PROTECTED */
/**
* Checks the supplied data and options for the editing component.
* @instance
* @protected
* @param {object} data - The jQuery data object from the parent table.
* @fires FooTable.Editing#"preinit.ft.editing"
*/
preinit: function(data){
var self = this;
/**
* The preinit.ft.editing event is raised before the UI is created and provides the tables jQuery data object for additional options parsing.
* Calling preventDefault on this event will disable the component.
* @event FooTable.Editing#"preinit.ft.editing"
* @param {jQuery.Event} e - The jQuery.Event object for the event.
* @param {FooTable.Table} ft - The instance of the plugin raising the event.
* @param {object} data - The jQuery data object of the table raising the event.
*/
this.ft.raise('preinit.ft.editing', [data]).then(function(){
if (self.ft.$el.hasClass('footable-editing'))
self.enabled = true;
self.enabled = F.is.boolean(data.editing)
? data.editing
: self.enabled;
if (!self.enabled) return;
self.pageToNew = F.is.boolean(data.editingPageToNew) ? data.editingPageToNew : self.pageToNew;
self.alwaysShow = F.is.boolean(data.editingAlwaysShow) ? data.editingAlwaysShow : self.alwaysShow;
self.position = F.is.string(data.editingPosition) ? data.editingPosition : self.position;
self.showText = F.is.string(data.editingShowText) ? data.editingShowText : self.showText;
self.hideText = F.is.string(data.editingHideText) ? data.editingHideText : self.hideText;
self.addText = F.is.string(data.editingAddText) ? data.editingAddText : self.addText;
self.editText = F.is.string(data.editingEditText) ? data.editingEditText : self.editText;
self.deleteText = F.is.string(data.editingDeleteText) ? data.editingDeleteText : self.deleteText;
self.viewText = F.is.string(data.editingViewText) ? data.editingViewText : self.viewText;
self.allowAdd = F.is.boolean(data.editingAllowAdd) ? data.editingAllowAdd : self.allowAdd;
self.allowEdit = F.is.boolean(data.editingAllowEdit) ? data.editingAllowEdit : self.allowEdit;
self.allowDelete = F.is.boolean(data.editingAllowDelete) ? data.editingAllowDelete : self.allowDelete;
self.allowView = F.is.boolean(data.editingAllowView) ? data.editingAllowView : self.allowView;
self.column = new F.EditingColumn(self.ft, self, $.extend(true, {}, self.column, data.editingColumn, {visible: self.alwaysShow}));
if (self.ft.$el.hasClass('footable-editing-left'))
self.position = 'left';
if (self.ft.$el.hasClass('footable-editing-right'))
self.position = 'right';
if (self.position === 'right'){
self.column.index = self.ft.columns.array.length;
} else {
self.column.index = 0;
for (var i = 0, len = self.ft.columns.array.length; i < len; i++){
self.ft.columns.array[i].index += 1;
}
}
self.ft.columns.array.push(self.column);
self.ft.columns.array.sort(function(a, b){ return a.index - b.index; });
self.callbacks.addRow = F.checkFnValue(self, data.editingAddRow, self.callbacks.addRow);
self.callbacks.editRow = F.checkFnValue(self, data.editingEditRow, self.callbacks.editRow);
self.callbacks.deleteRow = F.checkFnValue(self, data.editingDeleteRow, self.callbacks.deleteRow);
self.callbacks.viewRow = F.checkFnValue(self, data.editingViewRow, self.callbacks.viewRow);
}, function(){
self.enabled = false;
});
},
/**
* Initializes the editing component for the plugin using the supplied table and options.
* @instance
* @protected
* @fires FooTable.Editing#"init.ft.editing"
*/
init: function(){
/**
* The init.ft.editing event is raised before its UI is generated.
* Calling preventDefault on this event will disable the component.
* @event FooTable.Editing#"init.ft.editing"
* @param {jQuery.Event} e - The jQuery.Event object for the event.
* @param {FooTable.Table} ft - The instance of the plugin raising the event.
*/
var self = this;
this.ft.raise('init.ft.editing').then(function(){
self.$create();
}, function(){
self.enabled = false;
});
},
/**
* Destroys the editing component removing any UI generated from the table.
* @instance
* @protected
* @fires FooTable.Editing#"destroy.ft.editing"
*/
destroy: function () {
/**
* The destroy.ft.editing event is raised before its UI is removed.
* Calling preventDefault on this event will prevent the component from being destroyed.
* @event FooTable.Editing#"destroy.ft.editing"
* @param {jQuery.Event} e - The jQuery.Event object for the event.
* @param {FooTable.Table} ft - The instance of the plugin raising the event.
*/
var self = this;
this.ft.raise('destroy.ft.editing').then(function(){
self.ft.$el.removeClass('footable-editing footable-editing-always-show footable-editing-no-add footable-editing-no-edit footable-editing-no-delete footable-editing-no-view')
.off('click.ft.editing').find('tfoot > tr.footable-editing').remove();
});
},
/**
* Creates the editing UI from the current options setting the various jQuery properties of this component.
* @instance
* @protected
*/
$create: function(){
var self = this, position = self.position === 'right' ? 'footable-editing-right' : 'footable-editing-left';
self.ft.$el.addClass('footable-editing').addClass(position)
.on('click.ft.editing', '.footable-show', {self: self}, self._onShowClick)
.on('click.ft.editing', '.footable-hide', {self: self}, self._onHideClick)
.on('click.ft.editing', '.footable-edit', {self: self}, self._onEditClick)
.on('click.ft.editing', '.footable-delete', {self: self}, self._onDeleteClick)
.on('click.ft.editing', '.footable-view', {self: self}, self._onViewClick)
.on('click.ft.editing', '.footable-add', {self: self}, self._onAddClick);
self.$cell = $('<td/>').attr('colspan', self.ft.columns.visibleColspan).append(self.$buttonShow());
if (self.allowAdd){
self.$cell.append(self.$buttonAdd());
}
self.$cell.append(self.$buttonHide());
if (self.alwaysShow){
self.ft.$el.addClass('footable-editing-always-show');
}
if (!self.allowAdd) self.ft.$el.addClass('footable-editing-no-add');
if (!self.allowEdit) self.ft.$el.addClass('footable-editing-no-edit');
if (!self.allowDelete) self.ft.$el.addClass('footable-editing-no-delete');
if (!self.allowView) self.ft.$el.addClass('footable-editing-no-view');
var $tfoot = self.ft.$el.children('tfoot');
if ($tfoot.length == 0){
$tfoot = $('<tfoot/>');
self.ft.$el.append($tfoot);
}
self.$row = $('<tr/>', { 'class': 'footable-editing' }).append(self.$cell).appendTo($tfoot);
},
/**
* Creates the show button for the editing component.
* @instance
* @protected
* @returns {(string|HTMLElement|jQuery)}
*/
$buttonShow: function(){
return '<button type="button" class="btn btn-primary footable-show">' + this.showText + '</button>';
},
/**
* Creates the hide button for the editing component.
* @instance
* @protected
* @returns {(string|HTMLElement|jQuery)}
*/
$buttonHide: function(){
return '<button type="button" class="btn btn-default footable-hide">' + this.hideText + '</button>';
},
/**
* Creates the add button for the editing component.
* @instance
* @protected
* @returns {(string|HTMLElement|jQuery)}
*/
$buttonAdd: function(){
return '<button type="button" class="btn btn-primary footable-add">' + this.addText + '</button> ';
},
/**
* Creates the edit button for the editing component.
* @instance
* @protected
* @returns {(string|HTMLElement|jQuery)}
*/
$buttonEdit: function(){
return '<button type="button" class="btn btn-default footable-edit">' + this.editText + '</button> ';
},
/**
* Creates the delete button for the editing component.
* @instance
* @protected
* @returns {(string|HTMLElement|jQuery)}
*/
$buttonDelete: function(){
return '<button type="button" class="btn btn-default footable-delete">' + this.deleteText + '</button>';
},
/**
* Creates the view button for the editing component.
* @instance
* @protected
* @returns {(string|HTMLElement|jQuery)}
*/
$buttonView: function(){
return '<button type="button" class="btn btn-default footable-view">' + this.viewText + '</button> ';
},
/**
* Creates the button group for the row buttons.
* @instance
* @protected
* @returns {(string|HTMLElement|jQuery)}
*/
$rowButtons: function(){
if (F.is.jq(this._$buttons)) return this._$buttons.clone();
this._$buttons = $('<div class="btn-group btn-group-xs" role="group"></div>');
if (this.allowView) this._$buttons.append(this.$buttonView());
if (this.allowEdit) this._$buttons.append(this.$buttonEdit());
if (this.allowDelete) this._$buttons.append(this.$buttonDelete());
return this._$buttons;
},
/**
* Performs the drawing of the component.
*/
draw: function(){
this.$cell.attr('colspan', this.ft.columns.visibleColspan);
},
/**
* Handles the edit button click event.
* @instance
* @private
* @param {jQuery.Event} e - The jQuery.Event object for the event.
* @fires FooTable.Editing#"edit.ft.editing"
*/
_onEditClick: function(e){
e.preventDefault();
var self = e.data.self, row = $(this).closest('tr').data('__FooTableRow__');
if (row instanceof F.Row){
/**
* The edit.ft.editing event is raised before its callback is executed.
* Calling preventDefault on this event will prevent the callback from being executed.
* @event FooTable.Editing#"edit.ft.editing"
* @param {jQuery.Event} e - The jQuery.Event object for the event.
* @param {FooTable.Table} ft - The instance of the plugin raising the event.
* @param {FooTable.Row} row - The row to be edited.
*/
self.ft.raise('edit.ft.editing', [row]).then(function(){
self.callbacks.editRow.call(self.ft, row);
});
}
},
/**
* Handles the delete button click event.
* @instance
* @private
* @param {jQuery.Event} e - The jQuery.Event object for the event.
* @fires FooTable.Editing#"delete.ft.editing"
*/
_onDeleteClick: function(e){
e.preventDefault();
var self = e.data.self, row = $(this).closest('tr').data('__FooTableRow__');
if (row instanceof F.Row){
/**
* The delete.ft.editing event is raised before its callback is executed.
* Calling preventDefault on this event will prevent the callback from being executed.
* @event FooTable.Editing#"delete.ft.editing"
* @param {jQuery.Event} e - The jQuery.Event object for the event.
* @param {FooTable.Table} ft - The instance of the plugin raising the event.
* @param {FooTable.Row} row - The row to be deleted.
*/
self.ft.raise('delete.ft.editing', [row]).then(function(){
self.callbacks.deleteRow.call(self.ft, row);
});
}
},
/**
* Handles the view button click event.
* @instance
* @private
* @param {jQuery.Event} e - The jQuery.Event object for the event.
* @fires FooTable.Editing#"view.ft.editing"
*/
_onViewClick: function(e){
e.preventDefault();
var self = e.data.self, row = $(this).closest('tr').data('__FooTableRow__');
if (row instanceof F.Row){
/**
* The view.ft.editing event is raised before its callback is executed.
* Calling preventDefault on this event will prevent the callback from being executed.
* @event FooTable.Editing#"view.ft.editing"
* @param {jQuery.Event} e - The jQuery.Event object for the event.
* @param {FooTable.Table} ft - The instance of the plugin raising the event.
* @param {FooTable.Row} row - The row to be viewed.
*/
self.ft.raise('view.ft.editing', [row]).then(function(){
self.callbacks.viewRow.call(self.ft, row);
});
}
},
/**
* Handles the add button click event.
* @instance
* @private
* @param {jQuery.Event} e - The jQuery.Event object for the event.
* @fires FooTable.Editing#"add.ft.editing"
*/
_onAddClick: function(e){
e.preventDefault();
var self = e.data.self;
/**
* The add.ft.editing event is raised before its callback is executed.
* Calling preventDefault on this event will prevent the callback from being executed.
* @event FooTable.Editing#"add.ft.editing"
* @param {jQuery.Event} e - The jQuery.Event object for the event.
* @param {FooTable.Table} ft - The instance of the plugin raising the event.
*/
self.ft.raise('add.ft.editing').then(function(){
self.callbacks.addRow.call(self.ft);
});
},
/**
* Handles the show button click event.
* @instance
* @private
* @param {jQuery.Event} e - The jQuery.Event object for the event.
* @fires FooTable.Editing#"show.ft.editing"
*/
_onShowClick: function(e){
e.preventDefault();
var self = e.data.self;
/**
* The show.ft.editing event is raised before its callback is executed.
* Calling preventDefault on this event will prevent the callback from being executed.
* @event FooTable.Editing#"show.ft.editing"
* @param {jQuery.Event} e - The jQuery.Event object for the event.
* @param {FooTable.Table} ft - The instance of the plugin raising the event.
*/
self.ft.raise('show.ft.editing').then(function(){
self.ft.$el.addClass('footable-editing-show');
self.column.visible = true;
self.ft.draw();
});
},
/**
* Handles the hide button click event.
* @instance
* @private
* @param {jQuery.Event} e - The jQuery.Event object for the event.
* @fires FooTable.Editing#"show.ft.editing"
*/
_onHideClick: function(e){
e.preventDefault();
var self = e.data.self;
/**
* The hide.ft.editing event is raised before its callback is executed.
* Calling preventDefault on this event will prevent the callback from being executed.
* @event FooTable.Editing#"hide.ft.editing"
* @param {jQuery.Event} e - The jQuery.Event object for the event.
* @param {FooTable.Table} ft - The instance of the plugin raising the event.
*/
self.ft.raise('hide.ft.editing').then(function(){
self.ft.$el.removeClass('footable-editing-show');
self.column.visible = false;
self.ft.draw();
});
}
});
F.components.register('editing', F.Editing, 850);
})(jQuery, FooTable);
(function($, F){
F.EditingColumn = F.Column.extend(/** @lends FooTable.EditingColumn */{
/**
* The Editing column class is used to create the column containing the editing buttons.
* @constructs
* @extends FooTable.Column
* @param {FooTable.Table} instance - The parent {@link FooTable.Table} this column belongs to.
* @param {FooTable.Editing} editing - The parent {@link FooTable.Editing} component this column is used with.
* @param {object} definition - An object containing all the properties to set for the column.
* @returns {FooTable.EditingColumn}
*/
construct: function(instance, editing, definition){
this._super(instance, definition, 'editing');
this.editing = editing;
this.internal = true;
},
/**
* After the column has been defined this ensures that the $el property is a jQuery object by either creating or updating the current value.
* @instance
* @protected
* @this FooTable.Column
*/
$create: function(){
(this.$el = !this.virtual && F.is.jq(this.$el) ? this.$el : $('<th/>', {'class': 'footable-editing'})).html(this.title);
},
/**
* This is supplied either the cell value or jQuery object to parse. Any value can be returned from this method and
* will be provided to the {@link FooTable.EditingColumn#format} function
* to generate the cell contents.
* @instance
* @protected
* @param {(*|jQuery)} valueOrElement - The value or jQuery cell object.
* @returns {(jQuery)}
*/
parser: function(valueOrElement){
if (F.is.string(valueOrElement)) valueOrElement = $($.trim(valueOrElement));
if (F.is.element(valueOrElement)) valueOrElement = $(valueOrElement);
if (F.is.jq(valueOrElement)){
var tagName = valueOrElement.prop('tagName').toLowerCase();
if (tagName == 'td' || tagName == 'th') return valueOrElement.data('value') || valueOrElement.contents();
return valueOrElement;
}
return null;
},
/**
* Creates a cell to be used in the supplied row for this column.
* @param {FooTable.Row} row - The row to create the cell for.
* @returns {FooTable.Cell}
*/
createCell: function(row){
var $buttons = this.editing.$rowButtons(), $cell = $('<td/>').append($buttons);
if (F.is.jq(row.$el)){
if (this.index === 0){
$cell.prependTo(row.$el);
} else {
$cell.insertAfter(row.$el.children().eq(this.index-1));
}
}
return new F.Cell(this.ft, row, this, $cell || $cell.html());
}
});
F.columns.register('editing', F.EditingColumn);
})(jQuery, FooTable);
(function($, F) {
/**
* An object containing the editing options for the plugin. Added by the {@link FooTable.Editing} component.
* @type {object}
* @prop {boolean} enabled=false - Whether or not to allow editing on the table.
* @prop {boolean} pageToNew=true - Whether or not to automatically page to a new row when it is added to the table.
* @prop {string} position="right" - The position of the editing column in the table as well as the alignment of the buttons.
* @prop {boolean} alwaysShow=false - Whether or not the editing column and add row button are always visible.
* @prop {function} addRow - The callback function to execute when the add row button is clicked.
* @prop {function} editRow - The callback function to execute when the edit row button is clicked.
* @prop {function} deleteRow - The callback function to execute when the delete row button is clicked.
* @prop {function} viewRow - The callback function to execute when the view row button is clicked.
* @prop {string} showText - The text that appears in the show button. This can contain HTML.
* @prop {string} hideText - The text that appears in the hide button. This can contain HTML.
* @prop {string} addText - The text that appears in the add button. This can contain HTML.
* @prop {string} editText - The text that appears in the edit button. This can contain HTML.
* @prop {string} deleteText - The text that appears in the delete button. This can contain HTML.
* @prop {string} viewText - The text that appears in the view button. This can contain HTML.
* @prop {boolean} allowAdd - Whether or not to show the Add Row button.
* @prop {boolean} allowEdit - Whether or not to show the Edit Row button.
* @prop {boolean} allowDelete - Whether or not to show the Delete Row button.
* @prop {boolean} allowView - Whether or not to show the View Row button.
* @prop {object} column - The options for the editing column. @see {@link FooTable.EditingColumn} for more info.
* @prop {string} column.classes="footable-editing" - A space separated string of class names to apply to all cells in the column.
* @prop {string} column.name="editing" - The name of the column.
* @prop {string} column.title="" - The title displayed in the header row of the table for the column.
* @prop {boolean} column.filterable=false - Whether or not the column should be filterable when using the filtering component.
* @prop {boolean} column.sortable=false - Whether or not the column should be sortable when using the sorting component.
*/
F.Defaults.prototype.editing = {
enabled: false,
pageToNew: true,
position: 'right',
alwaysShow: false,
addRow: function(){},
editRow: function(row){},
deleteRow: function(row){},
viewRow: function(row){},
showText: '<span class="fooicon fooicon-pencil" aria-hidden="true"></span> Edit rows',
hideText: 'Cancel',
addText: 'New row',
editText: '<span class="fooicon fooicon-pencil" aria-hidden="true"></span>',
deleteText: '<span class="fooicon fooicon-trash" aria-hidden="true"></span>',
viewText: '<span class="fooicon fooicon-stats" aria-hidden="true"></span>',
allowAdd: true,
allowEdit: true,
allowDelete: true,
allowView: false,
column: {
classes: 'footable-editing',
name: 'editing',
title: '',
filterable: false,
sortable: false
}
};
})(jQuery, FooTable);
(function($, F){
if (F.is.defined(F.Paging)){
/**
* Holds a shallow clone of the un-paged {@link FooTable.Rows#array} value before paging occurs and superfluous rows are removed. Added by the {@link FooTable.Editing} component.
* @instance
* @public
* @type {Array<FooTable.Row>}
*/
F.Paging.prototype.unpaged = [];
// override the default predraw method with one that sets the unpaged property.
F.Paging.extend('predraw', function(){
this.unpaged = this.ft.rows.array.slice(0); // create a shallow clone for later use
this._super(); // call the original method
});
}
})(jQuery, FooTable);
(function($, F){
/**
* Adds the row to the table.
* @param {boolean} [redraw=true] - Whether or not to redraw the table, defaults to true but for bulk operations this
* can be set to false and then followed by a call to the {@link FooTable.Table#draw} method.
* @returns {jQuery.Deferred}
*/
F.Row.prototype.add = function(redraw){
redraw = F.is.boolean(redraw) ? redraw : true;
var self = this;
return $.Deferred(function(d){
var index = self.ft.rows.all.push(self) - 1;
if (redraw){
return self.ft.draw().then(function(){
d.resolve(index);
});
} else {
d.resolve(index);
}
});
};
/**
* Removes the row from the table.
* @param {boolean} [redraw=true] - Whether or not to redraw the table, defaults to true but for bulk operations this
* can be set to false and then followed by a call to the {@link FooTable.Table#draw} method.
* @returns {jQuery.Deferred}
*/
F.Row.prototype.delete = function(redraw){
redraw = F.is.boolean(redraw) ? redraw : true;
var self = this;
return $.Deferred(function(d){
var index = self.ft.rows.all.indexOf(self);
if (F.is.number(index) && index >= 0 && index < self.ft.rows.all.length){
self.ft.rows.all.splice(index, 1);
if (redraw){
return self.ft.draw().then(function(){
d.resolve(self);
});
}
}
d.resolve(self);
});
};
if (F.is.defined(F.Paging)){
// override the default add method with one that supports paging
F.Row.extend('add', function(redraw){
redraw = F.is.boolean(redraw) ? redraw : true;
var self = this,
added = this._super(redraw),
editing = self.ft.use(F.Editing),
paging;
if (editing && editing.pageToNew && (paging = self.ft.use(F.Paging)) && redraw){
return added.then(function(){
var index = paging.unpaged.indexOf(self); // find this row in the unpaged array (this array will be sorted and filtered)
var page = Math.ceil((index + 1) / paging.size); // calculate the page the new row is on
if (paging.current !== page){ // goto the page if we need to
return paging.goto(page);
}
});
}
return added;
});
}
if (F.is.defined(F.Sorting)){
// override the default val method with one that supports sorting and paging
F.Row.extend('val', function(data, redraw){
redraw = F.is.boolean(redraw) ? redraw : true;
var result = this._super(data);
if (!F.is.hash(data)){
return result;
}
var self = this;
if (redraw){
self.ft.draw().then(function(){
var editing = self.ft.use(F.Editing), paging;
if (F.is.defined(F.Paging) && editing && editing.pageToNew && (paging = self.ft.use(F.Paging))){
var index = paging.unpaged.indexOf(self); // find this row in the unpaged array (this array will be sorted and filtered)
var page = Math.ceil((index + 1) / paging.size); // calculate the page the new row is on
if (paging.current !== page){ // goto the page if we need to
return paging.goto(page);
}
}
});
}
return result;
});
}
})(jQuery, FooTable);
(function(F){
/**
* Adds a row to the underlying {@link FooTable.Rows#all} array.
* @param {(object|FooTable.Row)} dataOrRow - A hash containing the row values or an actual {@link FooTable.Row} object.
* @param {boolean} [redraw=true] - Whether or not to redraw the table, defaults to true but for bulk operations this
* can be set to false and then followed by a call to the {@link FooTable.Table#draw} method.
*/
F.Rows.prototype.add = function(dataOrRow, redraw){
var row = dataOrRow;
if (F.is.hash(dataOrRow)){
row = new FooTable.Row(this.ft, this.ft.columns.array, dataOrRow);
}
if (row instanceof FooTable.Row){
row.add(redraw);
}
};
/**
* Updates a row in the underlying {@link FooTable.Rows#all} array.
* @param {(number|FooTable.Row)} indexOrRow - The index to update or the actual {@link FooTable.Row} object.
* @param {object} data - A hash containing the new row values.
* @param {boolean} [redraw=true] - Whether or not to redraw the table, defaults to true but for bulk operations this
* can be set to false and then followed by a call to the {@link FooTable.Table#draw} method.
*/
F.Rows.prototype.update = function(indexOrRow, data, redraw){
var len = this.ft.rows.all.length,
row = indexOrRow;
if (F.is.number(indexOrRow) && indexOrRow >= 0 && indexOrRow < len){
row = this.ft.rows.all[indexOrRow];
}
if (row instanceof FooTable.Row && F.is.hash(data)){
row.val(data, redraw);
}
};
/**
* Deletes a row from the underlying {@link FooTable.Rows#all} array.
* @param {(number|FooTable.Row)} indexOrRow - The index to delete or the actual {@link FooTable.Row} object.
* @param {boolean} [redraw=true] - Whether or not to redraw the table, defaults to true but for bulk operations this
* can be set to false and then followed by a call to the {@link FooTable.Table#draw} method.
*/
F.Rows.prototype.delete = function(indexOrRow, redraw){
var len = this.ft.rows.all.length,
row = indexOrRow;
if (F.is.number(indexOrRow) && indexOrRow >= 0 && indexOrRow < len){
row = this.ft.rows.all[indexOrRow];
}
if (row instanceof FooTable.Row){
row.delete(redraw);
}
};
})(FooTable);
File diff suppressed because one or more lines are too long
+182
View File
@@ -0,0 +1,182 @@
/*
* FooTable v3 - FooTable is a jQuery plugin that aims to make HTML tables on smaller devices look awesome.
* @version 3.1.6
* @link http://fooplugins.com
* @copyright Steven Usher & Brad Vincent 2015
* @license Released under the GPLv3 license.
*/
(function($, F){
F.Export = F.Component.extend(/** @lends FooTable.Export */{
/**
* @summary This component provides some basic export functionality.
* @memberof FooTable
* @constructs Export
* @param {FooTable.Table} table - The current instance of the plugin.
*/
construct: function(table){
// call the constructor of the base class
this._super(table, true);
/**
* @summary A snapshot of the working set of rows prior to being trimmed by the paging component.
* @memberof FooTable.Export#
* @name snapshot
* @type {FooTable.Row[]}
*/
this.snapshot = [];
},
/**
* @summary Hooks into the predraw pipeline after sorting and filtering have taken place but prior to paging.
* @memberof FooTable.Export#
* @function predraw
* @description This method allows us to take a snapshot of the working set of rows before they are trimmed by the paging component and is called by the plugin instance.
*/
predraw: function(){
this.snapshot = this.ft.rows.array.slice(0);
},
/**
* @summary Return the columns as simple JavaScript objects in an array.
* @memberof FooTable.Export#
* @function columns
* @returns {Object[]}
*/
columns: function(){
var result = [];
F.arr.each(this.ft.columns.array, function(column){
if (!column.internal){
result.push({
type: column.type,
name: column.name,
title: column.title,
visible: column.visible,
hidden: column.hidden,
classes: column.classes,
style: column.style
});
}
});
return result;
},
/**
* @summary Return the rows as simple JavaScript objects in an array.
* @memberof FooTable.Export#
* @function rows
* @param {boolean} [filtered=false] - Whether or not to exclude filtered rows from the result.
* @returns {Object[]}
*/
rows: function(filtered){
filtered = F.is.boolean(filtered) ? filtered : false;
var rows = filtered ? this.ft.rows.all : this.snapshot, result = [];
F.arr.each(rows, function(row){
result.push(row.val());
});
return result;
},
/**
* @summary Return the columns and rows as a properly formatted JSON object.
* @memberof FooTable.Export#
* @function json
* @param {boolean} [filtered=false] - Whether or not to exclude filtered rows from the result.
* @returns {Object}
*/
json: function(filtered){
return JSON.parse(JSON.stringify({columns: this.columns(),rows: this.rows(filtered)}));
},
/**
* @summary Return the columns and rows as a properly formatted CSV value.
* @memberof FooTable.Export#
* @function csv
* @param {boolean} [filtered=false] - Whether or not to exclude filtered rows from the result.
* @returns {string}
*/
csv: function(filtered){
var csv = "", columns = this.columns(), value, escaped;
F.arr.each(columns, function(column, i){
escaped = '"' + column.title.replace(/"/g, '""') + '"';
csv += (i === 0 ? escaped : "," + escaped);
});
csv += "\n";
var rows = filtered ? this.ft.rows.all : this.snapshot;
F.arr.each(rows, function(row){
F.arr.each(row.cells, function(cell, i){
if (!cell.column.internal){
value = cell.column.stringify.call(cell.column, cell.value, cell.ft.o, cell.row.value);
escaped = '"' + value.replace(/"/g, '""') + '"';
csv += (i === 0 ? escaped : "," + escaped);
}
});
csv += "\n";
});
return csv;
}
});
// register the component using a priority of 490 which falls just after filtering (500) and before paging (400).
F.components.register("export", F.Export, 490);
})(jQuery, FooTable);
(function(F){
// this is used to define the filtering specific properties on column creation
F.Column.prototype.__export_define__ = function(definition){
this.stringify = F.checkFnValue(this, definition.stringify, this.stringify);
};
// overrides the public define method and replaces it with our own
F.Column.extend('define', function(definition){
this._super(definition); // call the base so we don't have to redefine any previously set properties
this.__export_define__(definition); // then call our own
});
/**
* @summary Return the supplied value as a string.
* @memberof FooTable.Column#
* @function stringify
* @returns {string}
*/
F.Column.prototype.stringify = function(value, options, rowData){
return value + "";
};
if (F.is.defined(F.DateColumn)){
// override the base method for DateColumns
F.DateColumn.prototype.stringify = function(value, options, rowData){
return F.is.object(value) && F.is.boolean(value._isAMomentObject) && value.isValid() ? value.format(this.formatString) : '';
};
}
// override the base method for ObjectColumns
F.ObjectColumn.prototype.stringify = function(value, options, rowData){
return F.is.object(value) ? JSON.stringify(value) : "";
};
// override the base method for ArrayColumns
F.ArrayColumn.prototype.stringify = function(value, options, rowData){
return F.is.array(value) ? JSON.stringify(value) : "";
};
})(FooTable);
(function(F){
/**
* @summary Return the columns and rows as a properly formatted JSON object.
* @memberof FooTable.Table#
* @function toJSON
* @param {boolean} [filtered=false] - Whether or not to exclude filtered rows from the result.
* @returns {Object}
*/
F.Table.prototype.toJSON = function(filtered){
return this.use(F.Export).json(filtered);
};
/**
* @summary Return the columns and rows as a properly formatted CSV value.
* @memberof FooTable.Table#
* @function toCSV
* @param {boolean} [filtered=false] - Whether or not to exclude filtered rows from the result.
* @returns {string}
*/
F.Table.prototype.toCSV = function(filtered){
return this.use(F.Export).csv(filtered);
};
})(FooTable);
+8
View File
@@ -0,0 +1,8 @@
/*
* FooTable v3 - FooTable is a jQuery plugin that aims to make HTML tables on smaller devices look awesome.
* @version 3.1.6
* @link http://fooplugins.com
* @copyright Steven Usher & Brad Vincent 2015
* @license Released under the GPLv3 license.
*/
!function(a,b){b.Export=b.Component.extend({construct:function(a){this._super(a,!0),this.snapshot=[]},predraw:function(){this.snapshot=this.ft.rows.array.slice(0)},columns:function(){var a=[];return b.arr.each(this.ft.columns.array,function(b){b.internal||a.push({type:b.type,name:b.name,title:b.title,visible:b.visible,hidden:b.hidden,classes:b.classes,style:b.style})}),a},rows:function(a){a=b.is["boolean"](a)?a:!1;var c=a?this.ft.rows.all:this.snapshot,d=[];return b.arr.each(c,function(a){d.push(a.val())}),d},json:function(a){return JSON.parse(JSON.stringify({columns:this.columns(),rows:this.rows(a)}))},csv:function(a){var c,d,e="",f=this.columns();b.arr.each(f,function(a,b){d='"'+a.title.replace(/"/g,'""')+'"',e+=0===b?d:","+d}),e+="\n";var g=a?this.ft.rows.all:this.snapshot;return b.arr.each(g,function(a){b.arr.each(a.cells,function(a,b){a.column.internal||(c=a.column.stringify.call(a.column,a.value,a.ft.o,a.row.value),d='"'+c.replace(/"/g,'""')+'"',e+=0===b?d:","+d)}),e+="\n"}),e}}),b.components.register("export",b.Export,490)}(jQuery,FooTable),function(a){a.Column.prototype.__export_define__=function(b){this.stringify=a.checkFnValue(this,b.stringify,this.stringify)},a.Column.extend("define",function(a){this._super(a),this.__export_define__(a)}),a.Column.prototype.stringify=function(a,b,c){return a+""},a.is.defined(a.DateColumn)&&(a.DateColumn.prototype.stringify=function(b,c,d){return a.is.object(b)&&a.is["boolean"](b._isAMomentObject)&&b.isValid()?b.format(this.formatString):""}),a.ObjectColumn.prototype.stringify=function(b,c,d){return a.is.object(b)?JSON.stringify(b):""},a.ArrayColumn.prototype.stringify=function(b,c,d){return a.is.array(b)?JSON.stringify(b):""}}(FooTable),function(a){a.Table.prototype.toJSON=function(b){return this.use(a.Export).json(b)},a.Table.prototype.toCSV=function(b){return this.use(a.Export).csv(b)}}(FooTable);
+1097
View File
File diff suppressed because it is too large Load Diff
File diff suppressed because one or more lines are too long
+7371
View File
File diff suppressed because it is too large Load Diff
+10
View File
File diff suppressed because one or more lines are too long
+810
View File
@@ -0,0 +1,810 @@
/*
* FooTable v3 - FooTable is a jQuery plugin that aims to make HTML tables on smaller devices look awesome.
* @version 3.1.6
* @link http://fooplugins.com
* @copyright Steven Usher & Brad Vincent 2015
* @license Released under the GPLv3 license.
*/
(function($, F){
F.Pager = F.Class.extend(/** @lends FooTable.Pager */{
/**
* The pager object contains the page number and direction to page to.
* @constructs
* @extends FooTable.Class
* @param {number} total - The total number of pages available.
* @param {number} current - The current page number.
* @param {number} size - The number of rows per page.
* @param {number} page - The page number to goto.
* @param {boolean} forward - A boolean indicating the direction of paging, TRUE = forward, FALSE = back.
* @returns {FooTable.Pager}
*/
construct: function(total, current, size, page, forward){
/**
* The total number of pages available.
* @type {number}
*/
this.total = total;
/**
* The current page number.
* @type {number}
*/
this.current = current;
/**
* The number of rows per page.
* @type {number}
*/
this.size = size;
/**
* The page number to goto.
* @type {number}
*/
this.page = page;
/**
* A boolean indicating the direction of paging, TRUE = forward, FALSE = back.
* @type {boolean}
*/
this.forward = forward;
}
});
})(jQuery, FooTable);
(function($, F){
F.Paging = F.Component.extend(/** @lends FooTable.Paging */{
/**
* The paging component adds a pagination control to the table allowing users to navigate table rows via pages.
* @constructs
* @extends FooTable.Component
* @param {FooTable.Table} table - The parent {@link FooTable.Table} object for the component.
* @returns {FooTable.Filtering}
*/
construct: function(table){
// call the base constructor
this._super(table, table.o.paging.enabled);
/* PROTECTED */
/**
* An object containing the strings used by the paging buttons.
* @type {{ first: string, prev: string, next: string, last: string }}
*/
this.strings = table.o.paging.strings;
/* PUBLIC */
/**
* The current page number to display.
* @instance
* @type {number}
*/
this.current = table.o.paging.current;
/**
* The number of rows to display per page.
* @instance
* @type {number}
*/
this.size = table.o.paging.size;
/**
* The maximum number of page links to display at once.
* @instance
* @type {number}
*/
this.limit = table.o.paging.limit;
/**
* The position of the pagination control within the paging rows cell.
* @instance
* @type {string}
*/
this.position = table.o.paging.position;
/**
* The format string used to generate the text displayed under the pagination control.
* @instance
* @type {string}
*/
this.countFormat = table.o.paging.countFormat;
/**
* A selector specifying where to place the paging components UI, if null the UI is displayed within a row in the foot of the table.
* @instance
* @type {string}
*/
this.container = table.o.paging.container;
/**
* The total number of pages.
* @instance
* @type {number}
*/
this.total = -1;
/**
* The number of rows in the {@link FooTable.Rows#array} before paging is applied.
* @instance
* @type {number}
*/
this.totalRows = 0;
/**
* A number indicating the previous page displayed.
* @instance
* @type {number}
*/
this.previous = -1;
/**
* The count string generated using the {@link FooTable.Filtering#countFormat} option. This value is only set after the first call to the {@link FooTable.Filtering#predraw} method.
* @instance
* @type {string}
*/
this.formattedCount = null;
/**
* The jQuery object of the element containing the entire paging UI.
* @instance
* @type {jQuery}
*/
this.$container = null;
/**
* The jQuery object of the element wrapping all the paging UI elements.
* @instance
* @type {jQuery}
*/
this.$wrapper = null;
/** +
* The jQuery row object that contains all the paging specific elements.
* @instance
* @type {jQuery}
*/
this.$row = null;
/**
* The jQuery cell object that contains the pagination control and total count.
* @instance
* @type {jQuery}
*/
this.$cell = null;
/**
* The jQuery object that contains the links for the pagination control.
* @instance
* @type {jQuery}
*/
this.$pagination = null;
/**
* The jQuery object that contains the row count.
* @instance
* @type {jQuery}
*/
this.$count = null;
/**
* Whether or not the pagination row is detached from the table.
* @instance
* @type {boolean}
*/
this.detached = true;
/* PRIVATE */
/**
* Used to hold the number of page links created.
* @instance
* @type {number}
* @private
*/
this._createdLinks = 0;
},
/* PROTECTED */
/**
* Checks the supplied data and options for the paging component.
* @instance
* @protected
* @param {object} data - The jQuery data object from the parent table.
* @fires FooTable.Paging#"preinit.ft.paging"
*/
preinit: function(data){
var self = this;
/**
* The preinit.ft.paging event is raised before the UI is created and provides the tables jQuery data object for additional options parsing.
* Calling preventDefault on this event will disable the component.
* @event FooTable.Paging#"preinit.ft.paging"
* @param {jQuery.Event} e - The jQuery.Event object for the event.
* @param {FooTable.Table} ft - The instance of the plugin raising the event.
* @param {object} data - The jQuery data object of the table raising the event.
*/
this.ft.raise('preinit.ft.paging', [data]).then(function(){
if (self.ft.$el.hasClass('footable-paging'))
self.enabled = true;
self.enabled = F.is.boolean(data.paging)
? data.paging
: self.enabled;
if (!self.enabled) return;
self.size = F.is.number(data.pagingSize)
? data.pagingSize
: self.size;
self.current = F.is.number(data.pagingCurrent)
? data.pagingCurrent
: self.current;
self.limit = F.is.number(data.pagingLimit)
? data.pagingLimit
: self.limit;
if (self.ft.$el.hasClass('footable-paging-left'))
self.position = 'left';
if (self.ft.$el.hasClass('footable-paging-center'))
self.position = 'center';
if (self.ft.$el.hasClass('footable-paging-right'))
self.position = 'right';
self.position = F.is.string(data.pagingPosition)
? data.pagingPosition
: self.position;
self.countFormat = F.is.string(data.pagingCountFormat)
? data.pagingCountFormat
: self.countFormat;
self.container = F.is.string(data.pagingContainer)
? data.pagingContainer
: self.container;
self.total = Math.ceil(self.ft.rows.all.length / self.size);
}, function(){
self.enabled = false;
});
},
/**
* Initializes the paging component for the plugin using the supplied table and options.
* @instance
* @protected
* @fires FooTable.Paging#"init.ft.paging"
*/
init: function(){
/**
* The init.ft.paging event is raised before its UI is generated.
* Calling preventDefault on this event will disable the component.
* @event FooTable.Paging#"init.ft.paging"
* @param {jQuery.Event} e - The jQuery.Event object for the event.
* @param {FooTable.Table} ft - The instance of the plugin raising the event.
*/
var self = this;
this.ft.raise('init.ft.paging').then(function(){
self.$create();
}, function(){
self.enabled = false;
});
},
/**
* Destroys the paging component removing any UI generated from the table.
* @instance
* @protected
* @fires FooTable.Paging#"destroy.ft.paging"
*/
destroy: function () {
/**
* The destroy.ft.paging event is raised before its UI is removed.
* Calling preventDefault on this event will prevent the component from being destroyed.
* @event FooTable.Paging#"destroy.ft.paging"
* @param {jQuery.Event} e - The jQuery.Event object for the event.
* @param {FooTable.Table} ft - The instance of the plugin raising the event.
*/
var self = this;
this.ft.raise('destroy.ft.paging').then(function(){
self.ft.$el.removeClass('footable-paging')
.find('tfoot > tr.footable-paging').remove();
self.detached = true;
self._createdLinks = 0;
});
},
/**
* Performs the actual paging against the {@link FooTable.Rows#current} array removing all rows that are not on the current visible page.
* @instance
* @protected
*/
predraw: function(){
this.total = Math.ceil(this.ft.rows.array.length / this.size);
this.current = this.current > this.total ? this.total : (this.current < 1 ? 1 : this.current);
this.totalRows = this.ft.rows.array.length;
if (this.totalRows > this.size){
this.ft.rows.array = this.ft.rows.array.splice((this.current - 1) * this.size, this.size);
}
this.formattedCount = this.format(this.countFormat);
},
/**
* Updates the paging UI setting the state of the pagination control.
* @instance
* @protected
*/
draw: function(){
if (this.total <= 1){
if (!this.detached){
if (this.$row){
this.$row.detach();
} else {
this.$wrapper.detach();
}
this.detached = true;
}
} else {
if (this.detached){
if (this.$row){
var $tfoot = this.ft.$el.children('tfoot');
if ($tfoot.length == 0){
$tfoot = $('<tfoot/>');
this.ft.$el.append($tfoot);
}
this.$row.appendTo($tfoot);
} else {
this.$wrapper.appendTo(this.$container);
}
this.detached = false;
}
if (F.is.jq(this.$cell)){
this.$cell.attr('colspan', this.ft.columns.visibleColspan);
}
this._createLinks();
this._setVisible(this.current, this.current > this.previous);
this._setNavigation(true);
this.$count.text(this.formattedCount);
}
},
/**
* Creates the paging UI from the current options setting the various jQuery properties of this component.
* @instance
* @protected
*/
$create: function(){
this._createdLinks = 0;
var position = 'footable-paging-center';
switch (this.position){
case 'left': position = 'footable-paging-left'; break;
case 'right': position = 'footable-paging-right'; break;
}
this.ft.$el.addClass('footable-paging').addClass(position);
this.$container = this.container === null ? null : $(this.container).first();
if (!F.is.jq(this.$container)){
var $tfoot = this.ft.$el.children('tfoot');
if ($tfoot.length == 0){
$tfoot = $('<tfoot/>');
this.ft.$el.append($tfoot);
}
// add it to a row and then populate it with the search input and column selector dropdown.
this.$row = $('<tr/>', {'class': 'footable-paging'}).prependTo($tfoot);
this.$container = this.$cell = $('<td/>').attr('colspan', this.ft.columns.visibleColspan).appendTo(this.$row);
} else {
this.$container.addClass('footable-paging-external').addClass(position);
}
this.$wrapper = $('<div/>', {'class': 'footable-pagination-wrapper'}).appendTo(this.$container);
this.$pagination = $('<ul/>', { 'class': 'pagination' }).on('click.footable', 'a.footable-page-link', { self: this }, this._onPageClicked);
this.$count = $('<span/>', { 'class': 'label label-default' });
this.$wrapper.append(this.$pagination, $('<div/>', {'class': 'divider'}), this.$count);
this.detached = false;
},
/* PUBLIC */
/**
* @summary Uses the supplied format string and replaces the placeholder strings with the current values.
* @description This method is used to generate the short description label for the pagination control. i.e. Showing X of Y records. The placeholders for this string are the following:
* * {CP} - The current page number.
* * {TP} - The total number of pages.
* * {PF} - The first row of the current page.
* * {PL} - The last row of the current page.
* * {TR} - The total rows available.
* These placeholders can be supplied in a string like; "Showing {PF} to {PL} of {TR} rows."
* @param {string} formatString - The string to be formatted with the paging specific variables.
* @returns {string}
*/
format: function(formatString){
var firstRow = (this.size * (this.current - 1)) + 1,
lastRow = this.size * this.current;
if (this.ft.rows.array.length == 0){
firstRow = 0;
lastRow = 0;
} else {
lastRow = lastRow > this.totalRows ? this.totalRows : lastRow;
}
return formatString.replace(/\{CP}/g, this.current)
.replace(/\{TP}/g, this.total)
.replace(/\{PF}/g, firstRow)
.replace(/\{PL}/g, lastRow)
.replace(/\{TR}/g, this.totalRows);
},
/**
* Pages to the first page.
* @instance
* @returns {jQuery.Promise}
* @fires FooTable.Paging#"before.ft.paging"
* @fires FooTable.Paging#"after.ft.paging"
*/
first: function(){
return this._set(1);
},
/**
* Pages to the previous page.
* @instance
* @returns {jQuery.Promise}
* @fires FooTable.Paging#"before.ft.paging"
* @fires FooTable.Paging#"after.ft.paging"
*/
prev: function(){
return this._set(this.current - 1 > 0 ? this.current - 1 : 1);
},
/**
* Pages to the next page.
* @instance
* @returns {jQuery.Promise}
* @fires FooTable.Paging#"before.ft.paging"
* @fires FooTable.Paging#"after.ft.paging"
*/
next: function(){
return this._set(this.current + 1 < this.total ? this.current + 1 : this.total);
},
/**
* Pages to the last page.
* @instance
* @returns {jQuery.Promise}
* @fires FooTable.Paging#"before.ft.paging"
* @fires FooTable.Paging#"after.ft.paging"
*/
last: function(){
return this._set(this.total);
},
/**
* Pages to the specified page.
* @instance
* @param {number} page - The page number to go to.
* @returns {jQuery.Promise}
* @fires FooTable.Paging#"before.ft.paging"
* @fires FooTable.Paging#"after.ft.paging"
*/
goto: function(page){
return this._set(page > this.total ? this.total : (page < 1 ? 1 : page));
},
/**
* Shows the previous X number of pages in the pagination control where X is the value set by the {@link FooTable.Defaults#paging} - limit option value.
* @instance
*/
prevPages: function(){
var page = this.$pagination.children('li.footable-page.visible:first').data('page') - 1;
this._setVisible(page, true);
this._setNavigation(false);
},
/**
* Shows the next X number of pages in the pagination control where X is the value set by the {@link FooTable.Defaults#paging} - limit option value.
* @instance
*/
nextPages: function(){
var page = this.$pagination.children('li.footable-page.visible:last').data('page') + 1;
this._setVisible(page, false);
this._setNavigation(false);
},
/**
* Gets or sets the current page size.
* @instance
* @param {(number|string)} [value] - The new page size to use, this value is supplied to `parseInt` so strings can be used. If not supplied or an invalid valid the current page size is returned.
* @returns {(number|undefined)}
*/
pageSize: function(value){
value = parseInt(value);
if (isNaN(value)){
return this.size;
}
this.size = value;
this.total = Math.ceil(this.ft.rows.all.length / this.size);
if (F.is.jq(this.$wrapper)){
if (this.$container.is("td")){
this.$row.remove();
} else {
this.$wrapper.remove();
}
}
this.$create();
this.ft.draw();
},
/* PRIVATE */
/**
* Performs the required steps to handle paging including the raising of the {@link FooTable.Paging#"before.ft.paging"} and {@link FooTable.Paging#"after.ft.paging"} events.
* @instance
* @private
* @param {number} page - The page to set.
* @returns {jQuery.Promise}
* @fires FooTable.Paging#"before.ft.paging"
* @fires FooTable.Paging#"after.ft.paging"
*/
_set: function(page){
var self = this,
pager = new F.Pager(self.total, self.current, self.size, page, page > self.current);
/**
* The before.ft.paging event is raised before a sort is applied and allows listeners to modify the pager or cancel it completely by calling preventDefault on the jQuery.Event object.
* @event FooTable.Paging#"before.ft.paging"
* @param {jQuery.Event} e - The jQuery.Event object for the event.
* @param {FooTable.Table} ft - The instance of the plugin raising the event.
* @param {FooTable.Pager} pager - The pager that is about to be applied.
*/
return self.ft.raise('before.ft.paging', [pager]).then(function(){
pager.page = pager.page > pager.total ? pager.total : pager.page;
pager.page = pager.page < 1 ? 1 : pager.page;
if (self.current == page) return $.when();
self.previous = self.current;
self.current = pager.page;
return self.ft.draw().then(function(){
/**
* The after.ft.paging event is raised after a pager has been applied.
* @event FooTable.Paging#"after.ft.paging"
* @param {jQuery.Event} e - The jQuery.Event object for the event.
* @param {FooTable.Table} ft - The instance of the plugin raising the event.
* @param {FooTable.Pager} pager - The pager that has been applied.
*/
self.ft.raise('after.ft.paging', [pager]);
});
});
},
/**
* Creates the pagination links using the current state of the plugin. If the total number of pages is the same as
* the last time this function was executed it does nothing.
* @instance
* @private
*/
_createLinks: function(){
if (this._createdLinks === this.total) return;
var self = this,
multiple = self.total > 1,
link = function(attr, html, klass){
return $('<li/>', {
'class': klass
}).attr('data-page', attr)
.append($('<a/>', {
'class': 'footable-page-link',
href: '#'
}).data('page', attr).html(html));
};
self.$pagination.empty();
if (multiple) {
self.$pagination.append(link('first', self.strings.first, 'footable-page-nav'));
self.$pagination.append(link('prev', self.strings.prev, 'footable-page-nav'));
if (self.limit > 0 && self.limit < self.total){
self.$pagination.append(link('prev-limit', self.strings.prevPages, 'footable-page-nav'));
}
}
for (var i = 0, $li; i < self.total; i++){
$li = link(i + 1, i + 1, 'footable-page');
self.$pagination.append($li);
}
if (multiple){
if (self.limit > 0 && self.limit < self.total){
self.$pagination.append(link('next-limit', self.strings.nextPages, 'footable-page-nav'));
}
self.$pagination.append(link('next', self.strings.next, 'footable-page-nav'));
self.$pagination.append(link('last', self.strings.last, 'footable-page-nav'));
}
self._createdLinks = self.total;
},
/**
* Sets the state for the navigation links of the pagination control and optionally sets the active class state on the current page link.
* @instance
* @private
* @param {boolean} active - Whether or not to set the active class state on the individual page links.
*/
_setNavigation: function(active){
if (this.current == 1) {
this.$pagination.children('li[data-page="first"],li[data-page="prev"]').addClass('disabled');
} else {
this.$pagination.children('li[data-page="first"],li[data-page="prev"]').removeClass('disabled');
}
if (this.current == this.total) {
this.$pagination.children('li[data-page="next"],li[data-page="last"]').addClass('disabled');
} else {
this.$pagination.children('li[data-page="next"],li[data-page="last"]').removeClass('disabled');
}
if ((this.$pagination.children('li.footable-page.visible:first').data('page') || 1) == 1) {
this.$pagination.children('li[data-page="prev-limit"]').addClass('disabled');
} else {
this.$pagination.children('li[data-page="prev-limit"]').removeClass('disabled');
}
if ((this.$pagination.children('li.footable-page.visible:last').data('page') || this.limit) == this.total) {
this.$pagination.children('li[data-page="next-limit"]').addClass('disabled');
} else {
this.$pagination.children('li[data-page="next-limit"]').removeClass('disabled');
}
if (this.limit > 0 && this.total < this.limit){
this.$pagination.children('li[data-page="prev-limit"],li[data-page="next-limit"]').css('display', 'none');
} else {
this.$pagination.children('li[data-page="prev-limit"],li[data-page="next-limit"]').css('display', '');
}
if (active){
this.$pagination.children('li.footable-page').removeClass('active').filter('li[data-page="' + this.current + '"]').addClass('active');
}
},
/**
* Sets the visible page using the supplied parameters.
* @instance
* @private
* @param {number} page - The page to make visible.
* @param {boolean} right - If set to true the supplied page will be the right most visible pagination link.
*/
_setVisible: function(page, right){
if (this.limit > 0 && this.total > this.limit){
if (!this.$pagination.children('li.footable-page[data-page="'+page+'"]').hasClass('visible')){
var start = 0, end = 0;
if (right == true){
end = page > this.total ? this.total : page;
start = end - this.limit;
} else {
start = page < 1 ? 0 : page - 1;
end = start + this.limit;
}
if (start < 0){
start = 0;
end = this.limit > this.total ? this.total : this.limit;
}
if (end > this.total){
end = this.total;
start = this.total - this.limit < 0 ? 0 : this.total - this.limit;
}
this.$pagination.children('li.footable-page').removeClass('visible').slice(start, end).addClass('visible');
}
} else {
this.$pagination.children('li.footable-page').removeClass('visible').slice(0, this.total).addClass('visible');
}
},
/**
* Handles the click event for all links in the pagination control.
* @instance
* @private
* @param {jQuery.Event} e - The event object for the event.
*/
_onPageClicked: function(e){
e.preventDefault();
if ($(e.target).closest('li').is('.active,.disabled')) return;
var self = e.data.self, page = $(this).data('page');
switch(page){
case 'first': self.first();
return;
case 'prev': self.prev();
return;
case 'next': self.next();
return;
case 'last': self.last();
return;
case 'prev-limit': self.prevPages();
return;
case 'next-limit': self.nextPages();
return;
default: self._set(page);
return;
}
}
});
F.components.register('paging', F.Paging, 400);
})(jQuery, FooTable);
(function(F){
/**
* An object containing the paging options for the plugin. Added by the {@link FooTable.Paging} component.
* @type {object}
* @prop {boolean} enabled=false - Whether or not to allow paging on the table.
* @prop {string} countFormat="{CP} of {TP}" - A string format used to generate the page count text.
* @prop {number} current=1 - The page number to display.
* @prop {number} limit=5 - The maximum number of page links to display at once.
* @prop {string} position="center" - The string used to specify the alignment of the pagination control.
* @prop {number} size=10 - The number of rows displayed per page.
* @prop {string} container=null - A selector specifying where to place the paging components UI, if null the UI is displayed within a row in the foot of the table.
* @prop {object} strings - An object containing the strings used by the paging buttons.
* @prop {string} strings.first="&laquo;" - The string used for the 'first' button.
* @prop {string} strings.prev="&lsaquo;" - The string used for the 'previous' button.
* @prop {string} strings.next="&rsaquo;" - The string used for the 'next' button.
* @prop {string} strings.last="&raquo;" - The string used for the 'last' button.
* @prop {string} strings.prevPages="..." - The string used for the 'previous X pages' button.
* @prop {string} strings.nextPages="..." - The string used for the 'next X pages' button.
*/
F.Defaults.prototype.paging = {
enabled: false,
countFormat: '{CP} of {TP}',
current: 1,
limit: 5,
position: 'center',
size: 10,
container: null,
strings: {
first: '&laquo;',
prev: '&lsaquo;',
next: '&rsaquo;',
last: '&raquo;',
prevPages: '...',
nextPages: '...'
}
};
})(FooTable);
(function(F){
/**
* Navigates to the specified page number. Added by the {@link FooTable.Paging} component.
* @instance
* @param {number} num - The page number to go to.
* @returns {jQuery.Promise}
* @fires FooTable.Paging#paging_changing
* @fires FooTable.Paging#paging_changed
* @see FooTable.Paging#goto
*/
F.Table.prototype.gotoPage = function(num){
return this.use(F.Paging).goto(num);
};
/**
* Navigates to the next page. Added by the {@link FooTable.Paging} component.
* @instance
* @returns {jQuery.Promise}
* @fires FooTable.Paging#paging_changing
* @fires FooTable.Paging#paging_changed
* @see FooTable.Paging#next
*/
F.Table.prototype.nextPage = function(){
return this.use(F.Paging).next();
};
/**
* Navigates to the previous page. Added by the {@link FooTable.Paging} component.
* @instance
* @returns {jQuery.Promise}
* @fires FooTable.Paging#paging_changing
* @fires FooTable.Paging#paging_changed
* @see FooTable.Paging#prev
*/
F.Table.prototype.prevPage = function(){
return this.use(F.Paging).prev();
};
/**
* Navigates to the first page. Added by the {@link FooTable.Paging} component.
* @instance
* @returns {jQuery.Promise}
* @fires FooTable.Paging#paging_changing
* @fires FooTable.Paging#paging_changed
* @see FooTable.Paging#first
*/
F.Table.prototype.firstPage = function(){
return this.use(F.Paging).first();
};
/**
* Navigates to the last page. Added by the {@link FooTable.Paging} component.
* @instance
* @returns {jQuery.Promise}
* @fires FooTable.Paging#paging_changing
* @fires FooTable.Paging#paging_changed
* @see FooTable.Paging#last
*/
F.Table.prototype.lastPage = function(){
return this.use(F.Paging).last();
};
/**
* Shows the next X number of pages in the pagination control where X is the value set by the {@link FooTable.Defaults#paging} - limit.size option value. Added by the {@link FooTable.Paging} component.
* @instance
* @see FooTable.Paging#nextPages
*/
F.Table.prototype.nextPages = function(){
return this.use(F.Paging).nextPages();
};
/**
* Shows the previous X number of pages in the pagination control where X is the value set by the {@link FooTable.Defaults#paging} - limit.size option value. Added by the {@link FooTable.Paging} component.
* @instance
* @see FooTable.Paging#prevPages
*/
F.Table.prototype.prevPages = function(){
return this.use(F.Paging).prevPages();
};
/**
* Gets or sets the current page size
* @instance
* @param {number} [value] - The new page size to use.
* @returns {(number|undefined)}
* @see FooTable.Paging#pageSize
*/
F.Table.prototype.pageSize = function(value){
return this.use(F.Paging).pageSize(value);
};
})(FooTable);
File diff suppressed because one or more lines are too long
+515
View File
@@ -0,0 +1,515 @@
/*
* FooTable v3 - FooTable is a jQuery plugin that aims to make HTML tables on smaller devices look awesome.
* @version 3.1.6
* @link http://fooplugins.com
* @copyright Steven Usher & Brad Vincent 2015
* @license Released under the GPLv3 license.
*/
(function($, F){
F.Sorter = F.Class.extend(/** @lends FooTable.Sorter */{
/**
* The sorter object contains the column and direction to sort by.
* @constructs
* @extends FooTable.Class
* @param {FooTable.Column} column - The column to sort.
* @param {string} direction - The direction to sort by.
* @returns {FooTable.Sorter}
*/
construct: function(column, direction){
/**
* The column to sort.
* @type {FooTable.Column}
*/
this.column = column;
/**
* The direction to sort by.
* @type {string}
*/
this.direction = direction;
}
});
})(jQuery, FooTable);
(function ($, F) {
F.Sorting = F.Component.extend(/** @lends FooTable.Sorting */{
/**
* The sorting component adds a small sort button to specified column headers allowing users to sort those columns in the table.
* @constructs
* @extends FooTable.Component
* @param {FooTable.Table} table - The parent {@link FooTable.Table} object for the component.
* @returns {FooTable.Sorting}
*/
construct: function (table) {
// call the constructor of the base class
this._super(table, table.o.sorting.enabled);
/* PROTECTED */
/**
* This provides a shortcut to the {@link FooTable.Table#options}.[sorting]{@link FooTable.Defaults#sorting} object.
* @instance
* @protected
* @type {object}
*/
this.o = table.o.sorting;
/**
* The current sorted column.
* @instance
* @type {FooTable.Column}
*/
this.column = null;
/**
* Whether or not to allow sorting to occur, should be set using the {@link FooTable.Sorting#toggleAllowed} method.
* @instance
* @type {boolean}
*/
this.allowed = true;
/**
* The initial sort state of the table, this value is used for determining if the sorting has occurred or to reset the state to default.
* @instance
* @type {{isset: boolean, rows: Array.<FooTable.Row>, column: string, direction: ?string}}
*/
this.initial = null;
},
/* PROTECTED */
/**
* Checks the supplied data and options for the sorting component.
* @instance
* @protected
* @param {object} data - The jQuery data object from the parent table.
* @fires FooTable.Sorting#"preinit.ft.sorting"
* @this FooTable.Sorting
*/
preinit: function(data){
var self = this;
/**
* The preinit.ft.sorting event is raised before the UI is created and provides the tables jQuery data object for additional options parsing.
* Calling preventDefault on this event will disable the component.
* @event FooTable.Sorting#"preinit.ft.sorting"
* @param {jQuery.Event} e - The jQuery.Event object for the event.
* @param {FooTable.Table} ft - The instance of the plugin raising the event.
* @param {object} data - The jQuery data object of the table raising the event.
*/
this.ft.raise('preinit.ft.sorting', [data]).then(function(){
if (self.ft.$el.hasClass('footable-sorting'))
self.enabled = true;
self.enabled = F.is.boolean(data.sorting)
? data.sorting
: self.enabled;
if (!self.enabled) return;
self.column = F.arr.first(self.ft.columns.array, function(col){ return col.sorted; });
}, function(){
self.enabled = false;
});
},
/**
* Initializes the sorting component for the plugin using the supplied table and options.
* @instance
* @protected
* @fires FooTable.Sorting#"init.ft.sorting"
* @this FooTable.Sorting
*/
init: function () {
/**
* The init.ft.sorting event is raised before its UI is generated.
* Calling preventDefault on this event will disable the component.
* @event FooTable.Sorting#"init.ft.sorting"
* @param {jQuery.Event} e - The jQuery.Event object for the event.
* @param {FooTable.Table} ft - The instance of the plugin raising the event.
*/
var self = this;
this.ft.raise('init.ft.sorting').then(function(){
if (!self.initial){
var isset = !!self.column;
self.initial = {
isset: isset,
// grab a shallow copy of the rows array prior to sorting - allows us to reset without an initial sort
rows: self.ft.rows.all.slice(0),
// if there is a sorted column store its name and direction
column: isset ? self.column.name : null,
direction: isset ? self.column.direction : null
}
}
F.arr.each(self.ft.columns.array, function(col){
if (col.sortable){
col.$el.addClass('footable-sortable').append($('<span/>', {'class': 'fooicon fooicon-sort'}));
}
});
self.ft.$el.on('click.footable', '.footable-sortable', { self: self }, self._onSortClicked);
}, function(){
self.enabled = false;
});
},
/**
* Destroys the sorting component removing any UI generated from the table.
* @instance
* @protected
* @fires FooTable.Sorting#"destroy.ft.sorting"
*/
destroy: function () {
/**
* The destroy.ft.sorting event is raised before its UI is removed.
* Calling preventDefault on this event will prevent the component from being destroyed.
* @event FooTable.Sorting#"destroy.ft.sorting"
* @param {jQuery.Event} e - The jQuery.Event object for the event.
* @param {FooTable.Table} ft - The instance of the plugin raising the event.
*/
var self = this;
this.ft.raise('destroy.ft.paging').then(function(){
self.ft.$el.off('click.footable', '.footable-sortable', self._onSortClicked);
self.ft.$el.children('thead').children('tr.footable-header')
.children('.footable-sortable').removeClass('footable-sortable footable-asc footable-desc')
.find('span.fooicon').remove();
});
},
/**
* Performs the actual sorting against the {@link FooTable.Rows#current} array.
* @instance
* @protected
*/
predraw: function () {
if (!this.column) return;
var self = this, col = self.column;
self.ft.rows.array.sort(function (a, b) {
return col.direction == 'DESC'
? col.sorter(b.cells[col.index].sortValue, a.cells[col.index].sortValue)
: col.sorter(a.cells[col.index].sortValue, b.cells[col.index].sortValue);
});
},
/**
* Updates the sorting UI setting the state of the sort buttons.
* @instance
* @protected
*/
draw: function () {
if (!this.column) return;
var self = this,
$sortable = self.ft.$el.find('thead > tr > .footable-sortable'),
$active = self.column.$el;
$sortable.removeClass('footable-asc footable-desc').children('.fooicon').removeClass('fooicon-sort fooicon-sort-asc fooicon-sort-desc');
$sortable.not($active).children('.fooicon').addClass('fooicon-sort');
$active.addClass(self.column.direction == 'DESC' ? 'footable-desc' : 'footable-asc')
.children('.fooicon').addClass(self.column.direction == 'DESC' ? 'fooicon-sort-desc' : 'fooicon-sort-asc');
},
/* PUBLIC */
/**
* Sets the sorting options and calls the {@link FooTable.Table#draw} method to perform the actual sorting.
* @instance
* @param {(string|number|FooTable.Column)} column - The column name, index or the actual {@link FooTable.Column} object to sort by.
* @param {string} [direction="ASC"] - The direction to sort by, either ASC or DESC.
* @returns {jQuery.Promise}
* @fires FooTable.Sorting#"before.ft.sorting"
* @fires FooTable.Sorting#"after.ft.sorting"
*/
sort: function(column, direction){
return this._sort(column, direction);
},
/**
* Toggles whether or not sorting is currently allowed.
* @param {boolean} [state] - You can optionally specify the state you want it to be, if not supplied the current value is flipped.
*/
toggleAllowed: function(state){
state = F.is.boolean(state) ? state : !this.allowed;
this.allowed = state;
this.ft.$el.toggleClass('footable-sorting-disabled', !this.allowed);
},
/**
* Checks whether any sorting has occurred for the table.
* @returns {boolean}
*/
hasChanged: function(){
return !(!this.initial || !this.column ||
(this.column.name === this.initial.column &&
(this.column.direction === this.initial.direction || (this.initial.direction === null && this.column.direction === 'ASC')))
);
},
/**
* Resets the table sorting to the initial state recorded in the components init method.
*/
reset: function(){
if (!!this.initial){
if (this.initial.isset){
// if the initial value specified a column, sort by it
this.sort(this.initial.column, this.initial.direction);
} else {
// if there was no initial column then we need to reset the rows to there original order
if (!!this.column){
// if there is a currently sorted column remove the asc/desc classes and set it to null.
this.column.$el.removeClass('footable-asc footable-desc');
this.column = null;
}
// replace the current all rows array with the one stored in the initial value
this.ft.rows.all = this.initial.rows;
// force the table to redraw itself using the updated rows array
this.ft.draw();
}
}
},
/* PRIVATE */
/**
* Performs the required steps to handle sorting including the raising of the {@link FooTable.Sorting#"before.ft.sorting"} and {@link FooTable.Sorting#"after.ft.sorting"} events.
* @instance
* @private
* @param {(string|number|FooTable.Column)} column - The column name, index or the actual {@link FooTable.Column} object to sort by.
* @param {string} [direction="ASC"] - The direction to sort by, either ASC or DESC.
* @returns {jQuery.Promise}
* @fires FooTable.Sorting#"before.ft.sorting"
* @fires FooTable.Sorting#"after.ft.sorting"
*/
_sort: function(column, direction){
if (!this.allowed) return $.Deferred().reject('sorting disabled');
var self = this;
var sorter = new F.Sorter(self.ft.columns.get(column), F.Sorting.dir(direction));
/**
* The before.ft.sorting event is raised before a sort is applied and allows listeners to modify the sorter or cancel it completely by calling preventDefault on the jQuery.Event object.
* @event FooTable.Sorting#"before.ft.sorting"
* @param {jQuery.Event} e - The jQuery.Event object for the event.
* @param {FooTable.Table} ft - The instance of the plugin raising the event.
* @param {FooTable.Sorter} sorter - The sorter that is about to be applied.
*/
return self.ft.raise('before.ft.sorting', [sorter]).then(function(){
F.arr.each(self.ft.columns.array, function(col){
if (col != self.column) col.direction = null;
});
self.column = self.ft.columns.get(sorter.column);
if (self.column) self.column.direction = F.Sorting.dir(sorter.direction);
return self.ft.draw().then(function(){
/**
* The after.ft.sorting event is raised after a sorter has been applied.
* @event FooTable.Sorting#"after.ft.sorting"
* @param {jQuery.Event} e - The jQuery.Event object for the event.
* @param {FooTable.Table} ft - The instance of the plugin raising the event.
* @param {FooTable.Sorter} sorter - The sorter that has been applied.
*/
self.ft.raise('after.ft.sorting', [sorter]);
});
});
},
/**
* Handles the sort button clicked event.
* @instance
* @private
* @param {jQuery.Event} e - The event object for the event.
*/
_onSortClicked: function (e) {
var self = e.data.self, $header = $(this).closest('th,td'),
direction = $header.is('.footable-asc, .footable-desc')
? ($header.hasClass('footable-desc') ? 'ASC' : 'DESC')
: 'ASC';
self._sort($header.index(), direction);
}
});
/**
* Checks the supplied string is a valid direction and if not returns ASC as default.
* @static
* @protected
* @param {string} str - The string to check.
*/
F.Sorting.dir = function(str){
return F.is.string(str) && (str == 'ASC' || str == 'DESC') ? str : 'ASC';
};
F.components.register('sorting', F.Sorting, 600);
})(jQuery, FooTable);
(function(F){
/**
* The value used by the sorting component during sort operations. Can be set using the data-sort-value attribute on the cell itself.
* If this is not supplied it is set to the result of the toString method called on the value for the cell. Added by the {@link FooTable.Sorting} component.
* @type {string}
* @default null
*/
F.Cell.prototype.sortValue = null;
// this is used to define the sorting specific properties on cell creation
F.Cell.prototype.__sorting_define__ = function(valueOrElement){
this.sortValue = this.column.sortValue.call(this.column, valueOrElement);
};
// this is used to update the sortValue property whenever the cell value is changed
F.Cell.prototype.__sorting_val__ = function(value){
if (F.is.defined(value)){
// set only
this.sortValue = this.column.sortValue.call(this.column, value);
}
};
// overrides the public define method and replaces it with our own
F.Cell.extend('define', function(valueOrElement){
this._super(valueOrElement);
this.__sorting_define__(valueOrElement);
});
// overrides the public val method and replaces it with our own
F.Cell.extend('val', function(value, redraw, redrawSelf){
var val = this._super(value, redraw, redrawSelf);
this.__sorting_val__(value);
return val;
});
})(FooTable);
(function($, F){
/**
* The direction to sort if the {@link FooTable.Column#sorted} property is set to true. Can be "ASC", "DESC" or NULL. Added by the {@link FooTable.Sorting} component.
* @type {string}
* @default null
*/
F.Column.prototype.direction = null;
/**
* Whether or not the column can be sorted. Added by the {@link FooTable.Sorting} component.
* @type {boolean}
* @default true
*/
F.Column.prototype.sortable = true;
/**
* Whether or not the column is sorted. Added by the {@link FooTable.Sorting} component.
* @type {boolean}
* @default false
*/
F.Column.prototype.sorted = false;
/**
* This is supplied two values from the column for a comparison to be made and the result returned. Added by the {@link FooTable.Sorting} component.
* @param {*} a - The first value to be compared.
* @param {*} b - The second value to compare to the first.
* @returns {number}
* @example <caption>This example shows using pseudo code what a sort function would look like.</caption>
* "sorter": function(a, b){
* if (a is less than b by some ordering criterion) {
* return -1;
* }
* if (a is greater than b by the ordering criterion) {
* return 1;
* }
* // a must be equal to b
* return 0;
* }
*/
F.Column.prototype.sorter = function(a, b){
if (typeof a === 'string') a = a.toLowerCase();
if (typeof b === 'string') b = b.toLowerCase();
if (a === b) return 0;
if (a < b) return -1;
return 1;
};
/**
* This is supplied either the cell value or jQuery object to parse. A value must be returned from this method and will be used during sorting operations.
* @param {(*|jQuery)} valueOrElement - The value or jQuery cell object.
* @returns {*}
* @this FooTable.Column
*/
F.Column.prototype.sortValue = function(valueOrElement){
// if we have an element or a jQuery object use jQuery to get the value
if (F.is.element(valueOrElement) || F.is.jq(valueOrElement)){
var data = $(valueOrElement).data('sortValue');
return F.is.defined(data) ? data : this.parser(valueOrElement);
}
// if options are supplied with the value
if (F.is.hash(valueOrElement) && F.is.hash(valueOrElement.options)){
if (F.is.string(valueOrElement.options.sortValue)) return valueOrElement.options.sortValue;
if (F.is.defined(valueOrElement.value)) valueOrElement = valueOrElement.value;
}
if (F.is.defined(valueOrElement) && valueOrElement != null) return valueOrElement;
return null;
};
// this is used to define the sorting specific properties on column creation
F.Column.prototype.__sorting_define__ = function(definition){
this.sorter = F.checkFnValue(this, definition.sorter, this.sorter);
this.direction = F.is.type(definition.direction, 'string') ? F.Sorting.dir(definition.direction) : null;
this.sortable = F.is.boolean(definition.sortable) ? definition.sortable : true;
this.sorted = F.is.boolean(definition.sorted) ? definition.sorted : false;
this.sortValue = F.checkFnValue(this, definition.sortValue, this.sortValue);
};
// overrides the public define method and replaces it with our own
F.Column.extend('define', function(definition){
this._super(definition);
this.__sorting_define__(definition);
});
})(jQuery, FooTable);
(function(F){
/**
* An object containing the sorting options for the plugin. Added by the {@link FooTable.Sorting} component.
* @type {object}
* @prop {boolean} enabled=false - Whether or not to allow sorting on the table.
*/
F.Defaults.prototype.sorting = {
enabled: false
};
})(FooTable);
(function($, F){
F.HTMLColumn.extend('__sorting_define__', function(definition){
this._super(definition);
this.sortUse = F.is.string(definition.sortUse) && $.inArray(definition.sortUse, ['html','text']) !== -1 ? definition.sortUse : 'html';
});
/**
* This is supplied either the cell value or jQuery object to parse. A value must be returned from this method and will be used during sorting operations.
* @param {(*|jQuery)} valueOrElement - The value or jQuery cell object.
* @returns {*}
* @this FooTable.HTMLColumn
*/
F.HTMLColumn.prototype.sortValue = function(valueOrElement){
// if we have an element or a jQuery object use jQuery to get the data value or pass it off to the parser
if (F.is.element(valueOrElement) || F.is.jq(valueOrElement)){
var data = $(valueOrElement).data('sortValue');
return F.is.defined(data) ? data : this.parser(valueOrElement);
}
// if options are supplied with the value
if (F.is.hash(valueOrElement) && F.is.hash(valueOrElement.options)){
if (F.is.string(valueOrElement.options.sortValue)) return valueOrElement.options.sortValue;
if (F.is.defined(valueOrElement.value)) valueOrElement = valueOrElement.value;
}
if (F.is.defined(valueOrElement) && valueOrElement != null) return valueOrElement;
return null;
};
})(jQuery, FooTable);
(function($, F){
/**
* This is supplied either the cell value or jQuery object to parse. A value must be returned from this method and will be used during sorting operations.
* @param {(*|jQuery)} valueOrElement - The value or jQuery cell object.
* @returns {*}
*/
F.NumberColumn.prototype.sortValue = function(valueOrElement){
// if we have an element or a jQuery object use jQuery to get the data value or pass it off to the parser
if (F.is.element(valueOrElement) || F.is.jq(valueOrElement)){
var data = $(valueOrElement).data('sortValue');
return F.is.number(data) ? data : this.parser(valueOrElement);
}
// if options are supplied with the value
if (F.is.hash(valueOrElement) && F.is.hash(valueOrElement.options)){
if (F.is.string(valueOrElement.options.sortValue)) return this.parser(valueOrElement);
if (F.is.number(valueOrElement.options.sortValue)) return valueOrElement.options.sortValue;
if (F.is.number(valueOrElement.value)) return valueOrElement.value;
}
if (F.is.string(valueOrElement)) return this.parser(valueOrElement);
if (F.is.number(valueOrElement)) return valueOrElement;
return null;
};
})(jQuery, FooTable);
(function(F){
/**
* Sort the table using the specified column and direction. Added by the {@link FooTable.Sorting} component.
* @instance
* @param {(string|number|FooTable.Column)} column - The column name, index or the actual {@link FooTable.Column} object to sort by.
* @param {string} [direction="ASC"] - The direction to sort by, either ASC or DESC.
* @returns {jQuery.Promise}
* @fires FooTable.Sorting#"change.ft.sorting"
* @fires FooTable.Sorting#"changed.ft.sorting"
* @see FooTable.Sorting#sort
*/
F.Table.prototype.sort = function(column, direction){
return this.use(F.Sorting).sort(column, direction);
};
})(FooTable);
File diff suppressed because one or more lines are too long
+362
View File
@@ -0,0 +1,362 @@
/*
* FooTable v3 - FooTable is a jQuery plugin that aims to make HTML tables on smaller devices look awesome.
* @version 3.1.6
* @link http://fooplugins.com
* @copyright Steven Usher & Brad Vincent 2015
* @license Released under the GPLv3 license.
*/
(function($, F){
// global int to use if the table has no ID
var _uid = 0,
// a hash value for the current url
_url_hash = (function(str){
var i, l, hval = 0x811c9dc5;
for (i = 0, l = str.length; i < l; i++) {
hval ^= str.charCodeAt(i);
hval += (hval << 1) + (hval << 4) + (hval << 7) + (hval << 8) + (hval << 24);
}
return hval >>> 0;
})(location.origin + location.pathname);
F.State = F.Component.extend(/** @lends FooTable.State */{
/**
* The state component adds the ability for the table to remember its basic state for filtering, paging and sorting.
* @constructs
* @extends FooTable.Component
* @param {FooTable.Table} table - The parent {@link FooTable.Table} object for the component.
* @returns {FooTable.State}
*/
construct: function(table){
// call the constructor of the base class
this._super(table, table.o.state.enabled);
// Change this value if an update to this component requires any stored data to be reset
this._key = '1';
/**
* The key to use to store the state for this table.
* @type {(null|string)}
*/
this.key = this._key + (F.is.string(table.o.state.key) ? table.o.state.key : this._uid());
/**
* Whether or not to allow the filtering component to store it's state.
* @type {boolean}
*/
this.filtering = F.is.boolean(table.o.state.filtering) ? table.o.state.filtering : true;
/**
* Whether or not to allow the paging component to store it's state.
* @type {boolean}
*/
this.paging = F.is.boolean(table.o.state.paging) ? table.o.state.paging : true;
/**
* Whether or not to allow the sorting component to store it's state.
* @type {boolean}
*/
this.sorting = F.is.boolean(table.o.state.sorting) ? table.o.state.sorting : true;
},
/* PROTECTED */
/**
* Checks the supplied data and options for the state component.
* @instance
* @protected
* @param {object} data - The jQuery data object from the parent table.
* @fires FooTable.State#"preinit.ft.state"
* @this FooTable.State
*/
preinit: function(data){
var self = this;
/**
* The preinit.ft.state event is raised before the UI is created and provides the tables jQuery data object for additional options parsing.
* Calling preventDefault on this event will disable the component.
* @event FooTable.State#"preinit.ft.state"
* @param {jQuery.Event} e - The jQuery.Event object for the event.
* @param {FooTable.Table} ft - The instance of the plugin raising the event.
* @param {object} data - The jQuery data object of the table raising the event.
*/
this.ft.raise('preinit.ft.state', [data]).then(function(){
self.enabled = F.is.boolean(data.state)
? data.state
: self.enabled;
if (!self.enabled) return;
self.key = self._key + (F.is.string(data.stateKey) ? data.stateKey : self.key);
self.filtering = F.is.boolean(data.stateFiltering) ? data.stateFiltering : self.filtering;
self.paging = F.is.boolean(data.statePaging) ? data.statePaging : self.paging;
self.sorting = F.is.boolean(data.stateSorting) ? data.stateSorting : self.sorting;
}, function(){
self.enabled = false;
});
},
/**
* Gets the state value for the specified key for this table.
* @instance
* @param {string} key - The key to get the value for.
* @returns {(*|null)}
*/
get: function(key){
return JSON.parse(localStorage.getItem(this.key + ':' + key));
},
/**
* Sets the state value for the specified key for this table.
* @instance
* @param {string} key - The key to set the value for.
* @param {*} data - The value to store for the key. This value must be JSON.stringify friendly.
*/
set: function(key, data){
localStorage.setItem(this.key + ':' + key, JSON.stringify(data));
},
/**
* Clears the state value for the specified key for this table.
* @instance
* @param {string} key - The key to clear the value for.
*/
remove: function(key){
localStorage.removeItem(this.key + ':' + key);
},
/**
* Executes the {@link FooTable.Component#readState} function on all components.
* @instance
*/
read: function(){
this.ft.execute(false, true, 'readState');
},
/**
* Executes the {@link FooTable.Component#writeState} function on all components.
* @instance
*/
write: function(){
this.ft.execute(false, true, 'writeState');
},
/**
* Executes the {@link FooTable.Component#clearState} function on all components.
* @instance
*/
clear: function(){
this.ft.execute(false, true, 'clearState');
},
/**
* Generates a unique identifier for the current {@link FooTable.Table} if one is not supplied through the options.
* This value is a combination of the url hash and either the element ID or an incremented global int value.
* @instance
* @returns {*}
* @private
*/
_uid: function(){
var id = this.ft.$el.attr('id');
return _url_hash + '_' + (F.is.string(id) ? id : ++_uid);
}
});
F.components.register('state', F.State, 700);
})(jQuery, FooTable);
(function(F){
/**
* This method is called from the {@link FooTable.State#read} method and allows a component to retrieve its' stored state.
* @instance
* @protected
* @function
*/
F.Component.prototype.readState = function(){};
/**
* This method is called from the {@link FooTable.State#write} method and allows a component to write its' current state to the store.
* @instance
* @protected
* @function
*/
F.Component.prototype.writeState = function(){};
/**
* This method is called from the {@link FooTable.State#clear} method and allows a component to clear any stored state.
* @instance
* @protected
* @function
*/
F.Component.prototype.clearState = function(){};
})(FooTable);
(function(F){
/**
* An object containing the state options for the plugin. Added by the {@link FooTable.State} component.
* @type {object}
* @prop {boolean} enabled=false - Whether or not to allow state to be stored for the table. This overrides the individual component enable options.
* @prop {boolean} filtering=true - Whether or not to allow the filtering state to be stored.
* @prop {boolean} paging=true - Whether or not to allow the filtering state to be stored.
* @prop {boolean} sorting=true - Whether or not to allow the filtering state to be stored.
* @prop {string} key=null - The unique key to use to store the table's data.
*/
F.Defaults.prototype.state = {
enabled: false,
filtering: true,
paging: true,
sorting: true,
key: null
};
})(FooTable);
(function(F){
if (!F.Filtering) return;
/**
* Allows the filtering component to retrieve its' stored state.
*/
F.Filtering.prototype.readState = function(){
if (this.ft.state.filtering){
var state = this.ft.state.get('filtering');
if (F.is.hash(state) && !F.is.emptyArray(state.filters)){
this.filters = this.ensure(state.filters);
}
}
};
/**
* Allows the filtering component to write its' current state to the store.
*/
F.Filtering.prototype.writeState = function(){
if (this.ft.state.filtering) {
var filters = F.arr.map(this.filters, function (f) {
return {
name: f.name,
query: f.query instanceof F.Query ? f.query.val() : f.query,
columns: F.arr.map(f.columns, function (c) {
return c.name;
}),
hidden: f.hidden,
space: f.space,
connectors: f.connectors,
ignoreCase: f.ignoreCase
};
});
this.ft.state.set('filtering', {filters: filters});
}
};
/**
* Allows the filtering component to clear any stored state.
*/
F.Filtering.prototype.clearState = function(){
if (this.ft.state.filtering) {
this.ft.state.remove('filtering');
}
};
})(FooTable);
(function(F){
if (!F.Paging) return;
/**
* Allows the paging component to retrieve its' stored state.
*/
F.Paging.prototype.readState = function(){
if (this.ft.state.paging) {
var state = this.ft.state.get('paging');
if (F.is.hash(state)) {
this.current = state.current;
this.size = state.size;
}
}
};
/**
* Allows the paging component to write its' current state to the store.
*/
F.Paging.prototype.writeState = function(){
if (this.ft.state.paging) {
this.ft.state.set('paging', {
current: this.current,
size: this.size
});
}
};
/**
* Allows the paging component to clear any stored state.
*/
F.Paging.prototype.clearState = function(){
if (this.ft.state.paging) {
this.ft.state.remove('paging');
}
};
})(FooTable);
(function(F){
if (!F.Sorting) return;
/**
* Allows the sorting component to retrieve its' stored state.
*/
F.Sorting.prototype.readState = function(){
if (this.ft.state.sorting) {
var state = this.ft.state.get('sorting');
if (F.is.hash(state)) {
var column = this.ft.columns.get(state.column);
if (column instanceof F.Column) {
this.column = column;
this.column.direction = state.direction;
}
}
}
};
/**
* Allows the sorting component to write its' current state to the store.
*/
F.Sorting.prototype.writeState = function(){
if (this.ft.state.sorting && this.column instanceof F.Column){
this.ft.state.set('sorting', {
column: this.column.name,
direction: this.column.direction
});
}
};
/**
* Allows the sorting component to clear any stored state.
*/
F.Sorting.prototype.clearState = function(){
if (this.ft.state.sorting) {
this.ft.state.remove('sorting');
}
};
})(FooTable);
(function(F){
// hook into the _construct method so we can add the state property to the table.
F.Table.extend('_construct', function(ready){
this.state = this.use(FooTable.State);
return this._super(ready);
});
// hook into the _preinit method so we can trigger a plugin wide read state operation.
F.Table.extend('_preinit', function(){
var self = this;
return self._super().then(function(){
if (self.state.enabled){
self.state.read();
}
});
});
// hook into the draw method so we can trigger a plugin wide write state operation.
F.Table.extend('draw', function(){
var self = this;
return self._super().then(function(){
if (self.state.enabled){
self.state.write();
}
});
});
})(FooTable);
+8
View File
@@ -0,0 +1,8 @@
/*
* FooTable v3 - FooTable is a jQuery plugin that aims to make HTML tables on smaller devices look awesome.
* @version 3.1.6
* @link http://fooplugins.com
* @copyright Steven Usher & Brad Vincent 2015
* @license Released under the GPLv3 license.
*/
!function(a,b){var c=0,d=function(a){var b,c,d=2166136261;for(b=0,c=a.length;c>b;b++)d^=a.charCodeAt(b),d+=(d<<1)+(d<<4)+(d<<7)+(d<<8)+(d<<24);return d>>>0}(location.origin+location.pathname);b.State=b.Component.extend({construct:function(a){this._super(a,a.o.state.enabled),this._key="1",this.key=this._key+(b.is.string(a.o.state.key)?a.o.state.key:this._uid()),this.filtering=b.is["boolean"](a.o.state.filtering)?a.o.state.filtering:!0,this.paging=b.is["boolean"](a.o.state.paging)?a.o.state.paging:!0,this.sorting=b.is["boolean"](a.o.state.sorting)?a.o.state.sorting:!0},preinit:function(a){var c=this;this.ft.raise("preinit.ft.state",[a]).then(function(){c.enabled=b.is["boolean"](a.state)?a.state:c.enabled,c.enabled&&(c.key=c._key+(b.is.string(a.stateKey)?a.stateKey:c.key),c.filtering=b.is["boolean"](a.stateFiltering)?a.stateFiltering:c.filtering,c.paging=b.is["boolean"](a.statePaging)?a.statePaging:c.paging,c.sorting=b.is["boolean"](a.stateSorting)?a.stateSorting:c.sorting)},function(){c.enabled=!1})},get:function(a){return JSON.parse(localStorage.getItem(this.key+":"+a))},set:function(a,b){localStorage.setItem(this.key+":"+a,JSON.stringify(b))},remove:function(a){localStorage.removeItem(this.key+":"+a)},read:function(){this.ft.execute(!1,!0,"readState")},write:function(){this.ft.execute(!1,!0,"writeState")},clear:function(){this.ft.execute(!1,!0,"clearState")},_uid:function(){var a=this.ft.$el.attr("id");return d+"_"+(b.is.string(a)?a:++c)}}),b.components.register("state",b.State,700)}(jQuery,FooTable),function(a){a.Component.prototype.readState=function(){},a.Component.prototype.writeState=function(){},a.Component.prototype.clearState=function(){}}(FooTable),function(a){a.Defaults.prototype.state={enabled:!1,filtering:!0,paging:!0,sorting:!0,key:null}}(FooTable),function(a){a.Filtering&&(a.Filtering.prototype.readState=function(){if(this.ft.state.filtering){var b=this.ft.state.get("filtering");a.is.hash(b)&&!a.is.emptyArray(b.filters)&&(this.filters=this.ensure(b.filters))}},a.Filtering.prototype.writeState=function(){if(this.ft.state.filtering){var b=a.arr.map(this.filters,function(b){return{name:b.name,query:b.query instanceof a.Query?b.query.val():b.query,columns:a.arr.map(b.columns,function(a){return a.name}),hidden:b.hidden,space:b.space,connectors:b.connectors,ignoreCase:b.ignoreCase}});this.ft.state.set("filtering",{filters:b})}},a.Filtering.prototype.clearState=function(){this.ft.state.filtering&&this.ft.state.remove("filtering")})}(FooTable),function(a){a.Paging&&(a.Paging.prototype.readState=function(){if(this.ft.state.paging){var b=this.ft.state.get("paging");a.is.hash(b)&&(this.current=b.current,this.size=b.size)}},a.Paging.prototype.writeState=function(){this.ft.state.paging&&this.ft.state.set("paging",{current:this.current,size:this.size})},a.Paging.prototype.clearState=function(){this.ft.state.paging&&this.ft.state.remove("paging")})}(FooTable),function(a){a.Sorting&&(a.Sorting.prototype.readState=function(){if(this.ft.state.sorting){var b=this.ft.state.get("sorting");if(a.is.hash(b)){var c=this.ft.columns.get(b.column);c instanceof a.Column&&(this.column=c,this.column.direction=b.direction)}}},a.Sorting.prototype.writeState=function(){this.ft.state.sorting&&this.column instanceof a.Column&&this.ft.state.set("sorting",{column:this.column.name,direction:this.column.direction})},a.Sorting.prototype.clearState=function(){this.ft.state.sorting&&this.ft.state.remove("sorting")})}(FooTable),function(a){a.Table.extend("_construct",function(a){return this.state=this.use(FooTable.State),this._super(a)}),a.Table.extend("_preinit",function(){var a=this;return a._super().then(function(){a.state.enabled&&a.state.read()})}),a.Table.extend("draw",function(){var a=this;return a._super().then(function(){a.state.enabled&&a.state.write()})})}(FooTable);