LoginAction/MyCourse/web/lib/datatable/zui.datatable.js

948 lines
35 KiB
JavaScript
Raw Permalink Normal View History

2023-02-07 04:17:56 +00:00
/*!
* ZUI: 数据表格 - v1.9.1 - 2019-05-10
* http://zui.sexy
* GitHub: https://github.com/easysoft/zui.git
* Copyright (c) 2019 cnezsoft.com; Licensed MIT
*/
/* ========================================================================
* ZUI: datatable.js
* http://zui.sexy
* ========================================================================
* Copyright (c) 2014-2016 cnezsoft.com; Licensed MIT
* ======================================================================== */
(function($) {
'use strict';
var name = 'zui.datatable';
var store = $.zui.store;
/**
* Datatable class
*
* @param object element DOM element or jquery element
* @param object options Datatable options
*/
var DataTable = function(element, options) {
this.name = name;
this.$ = $(element);
this.isTable = (this.$[0].tagName === 'TABLE');
this.firstShow = true;
if(this.isTable) {
this.$table = this.$;
this.id = 'datatable-' + (this.$.attr('id') || $.zui.uuid());
} else {
this.$datatable = this.$.addClass('datatable');
if(this.$.attr('id')) {
this.id = this.$.attr('id');
} else {
this.id = 'datatable-' + $.zui.uuid();
this.$.attr('id', this.id);
}
}
this.getOptions(options);
this.load();
this.callEvent('ready');
};
// default options
DataTable.DEFAULTS = {
// Check options
checkable: false, // added check icon to the head of rows
checkByClickRow: true, // change check status by click anywhere on a row
checkedClass: 'active', // apply CSS class to an checked row
checkboxName: null,
selectable: true,
// Sort options
sortable: false, // enable sorter
// storage
storage: true, // enable storage
// fixed header of columns
fixedHeader: false, // fixed header
fixedHeaderOffset: 0, // set top offset of header when fixed
fixedLeftWidth: '30%', // set left width after first render
fixedRightWidth: '30%', // set right width after first render
flexHeadDrag: true, // scroll flexarea by drag header
scrollPos: 'in', // scroll bar position: 'out' | 'in'
// hover effection
rowHover: true, // apply hover effection to row
colHover: true, // apply hover effection to head
hoverClass: 'hover',
colHoverClass: 'col-hover',
// Fix cell height
fixCellHeight: true,
// Merge rows
mergeRows: false, // Merge rows
// custom columns size
// customizable: false, // enable customizable
minColWidth: 20, // min width of columns
minFixedLeftWidth: 200, // min left width
minFixedRightWidth: 200, // min right width
minFlexAreaWidth: 200 // min flexarea width
};
// Get options
DataTable.prototype.getOptions = function(options) {
var $e = this.$;
options = $.extend({}, DataTable.DEFAULTS, this.$.data(), options);
options.tableClass = options.tableClass || '';
options.tableClass = ' ' + options.tableClass + ' table-datatable';
$.each(['bordered', 'condensed', 'striped', 'condensed', 'fixed'], function(idx, cls) {
cls = 'table-' + cls;
if($e.hasClass(cls)) options.tableClass += ' ' + cls;
});
if($e.hasClass('table-hover') || options.rowHover) {
options.tableClass += ' table-hover';
}
if(!options.checkable || !$.fn.selectable) options.selectable = false;
this.options = options;
};
// Load data form options or table dom
DataTable.prototype.load = function(data) {
var options = this.options,
cols;
if($.isFunction(data)) {
data = data(this.data, this);
data.keepSort = true;
} else if($.isPlainObject(data)) {
this.data = data;
} else if(typeof data === 'string') {
var $table = $(data);
if($table.length) {
this.$table = $table.first();
this.$table.data(name, this);
this.isTable = true;
}
data = null;
} else {
data = options.data;
}
if(!data) {
if(this.isTable) {
data = {
cols: [],
rows: []
};
cols = data.cols;
var rows = data.rows,
i,
$th, $tr, $td, row, $t = this.$table,
colSpan;
$t.children('thead').children('tr:first').children('th').each(function() {
$th = $(this);
cols.push($.extend({
text: $th.html(),
flex: false || $th.hasClass('flex-col'),
width: 'auto',
cssClass: $th.attr('class'),
css: $th.attr('style'),
type: 'string',
ignore: $th.hasClass('ignore'),
sort: !$th.hasClass('sort-disabled'),
mergeRows: $th.attr('merge-rows'),
title: $th.attr('title')
}, $th.data()));
});
$t.children('tbody').children('tr').each(function() {
$tr = $(this);
row = $.extend({
data: [],
checked: false,
cssClass: $tr.attr('class'),
css: $tr.attr('style'),
id: $tr.attr('id')
}, $tr.data());
$tr.children('td').each(function() {
$td = $(this);
colSpan = $td.attr('colspan') || 1;
row.data.push($.extend({
cssClass: $td.attr('class'),
css: $td.attr('style'),
text: $td.html(),
colSpan: colSpan,
title: $td.attr('title')
}, $td.data()));
if(colSpan > 1) {
for(i = 1; i < colSpan; i++) {
row.data.push({
empty: true
});
}
}
});
rows.push(row);
});
var $tfoot = $t.children('tfoot');
if($tfoot.length) {
data.footer = $('<table class="table' + options.tableClass + '"></table>').append($tfoot);
}
} else {
throw new Error('No data avaliable!');
}
}
data.flexStart = -1;
data.flexEnd = -1;
cols = data.cols;
data.colsLength = cols.length;
for(var i = 0; i < data.colsLength; ++i) {
var col = cols[i];
if(col.flex) {
if(data.flexStart < 0) {
data.flexStart = i;
}
data.flexEnd = i;
}
}
if(data.flexStart === 0 && data.flexEnd === data.colsLength) {
data.flexStart = -1;
data.flexEnd = -1;
}
data.flexArea = data.flexStart >= 0;
data.fixedRight = data.flexEnd >= 0 && data.flexEnd < (data.colsLength - 1);
data.fixedLeft = data.flexStart > 0;
if(data.flexStart < 0 && data.flexEnd < 0) {
data.fixedLeft = true;
data.flexStart = data.colsLength;
data.flexEnd = data.colsLength;
}
this.data = data;
this.callEvent('afterLoad', {
data: data
});
this.render();
};
// Render datatable
DataTable.prototype.render = function() {
var that = this;
var $datatable = that.$datatable || (that.isTable ? $('<div class="datatable" id="' + that.id + '"/>') : that.$datatable),
options = that.options,
data = that.data,
cols = that.data.cols,
rows = that.data.rows;
var checkable = options.checkable,
$left,
i,
$right,
$flex,
dataRowSpan = '<div class="datatable-rows-span datatable-span"><div class="datatable-wrapper"><table class="table"></table></div></div>',
dataHeadSpan = '<div class="datatable-head-span datatable-span"><div class="datatable-wrapper"><table class="table"><thead></thead></table></div></div>';
$datatable.children('.datatable-head, .datatable-rows, .scroll-wrapper').remove();
// Set css class to datatable by options
$datatable.toggleClass('sortable', options.sortable);
// $datatable.toggleClass('customizable', options.customizable);
// Head
var $head = $('<div class="datatable-head"/>'),
$tr,
$th,
col;
$left = $('<tr class="datatable-row datatable-row-left"/>');
$right = $('<tr class="datatable-row datatable-row-right"/>');
$flex = $('<tr class="datatable-row datatable-row-flex"/>');
for(i = 0; i < cols.length; i++) {
col = cols[i];
$tr = i < data.flexStart ? $left : ((i >= data.flexStart && i <= data.flexEnd) ? $flex : $right);
if(i === 0 && checkable) {
$tr.append('<th data-index="check" class="check-all check-btn"><i class="icon-check-empty"></i></th>');
}
if(col.ignore) continue;
$th = $('<th class="datatable-head-cell"/>');
// set sort class
$th.toggleClass('sort-down', col.sort === 'down')
.toggleClass('sort-up', col.sort === 'up')
.toggleClass('sort-disabled', col.sort === false);
$th.addClass(col.cssClass)
.addClass(col.colClass)
.html(col.text)
.attr({
'data-index': i,
'data-type': col.type,
style: col.css,
title: col.title,
}).css('width', col.width);
$tr.append($th);
}
var $headSpan;
if(data.fixedLeft) {
$headSpan = $(dataHeadSpan);
$headSpan.addClass('fixed-left')
// .find('.datatable-wrapper')
// .append('<div class="size-handle size-handle-head size-handle-left"></div>')
.find('table')
.addClass(options.tableClass)
.find('thead').append($left);
$head.append($headSpan);
}
if(data.flexArea) {
$headSpan = $(dataHeadSpan);
$headSpan.addClass('flexarea')
.find('.datatable-wrapper')
.append('<div class="scrolled-shadow scrolled-in-shadow"></div><div class="scrolled-shadow scrolled-out-shadow"></div>')
.find('table')
.addClass(options.tableClass)
.find('thead').append($flex);
$head.append($headSpan);
}
if(data.fixedRight) {
$headSpan = $(dataHeadSpan);
$headSpan.addClass('fixed-right')
// .find('.datatable-wrapper')
// .append('<div class="size-handle size-handle-head size-handle-right"></div>')
.find('table')
.addClass(options.tableClass)
.find('thead').append($right);
$head.append($headSpan);
}
$datatable.append($head);
// Rows
var $rows = $('<div class="datatable-rows">');
var $leftRow,
$flexRow,
$rightRow,
// $tr,
$td,
$cTd,
row,
rowLen = rows.length,
rowCol,
rowColLen;
$left = $('<tbody/>');
$right = $('<tbody/>');
$flex = $('<tbody/>');
for(var r = 0; r < rowLen; ++r) {
row = rows[r];
// format row
if(typeof row.id === 'undefined') {
row.id = r;
}
row.index = r;
$leftRow = $('<tr class="datatable-row"/>');
$leftRow.addClass(row.cssClass)
.toggleClass(options.checkedClass, !!row.checked)
.attr({
'data-index': r,
'data-id': row.id
});
$flexRow = $leftRow.clone().addClass('datatable-row-flex');
$rightRow = $leftRow.clone().addClass('datatable-row-right');
$leftRow.addClass('datatable-row-left');
rowColLen = row.data.length;
for(i = 0; i < rowColLen; ++i) {
rowCol = row.data[i];
if(i > 0 && rowCol.empty) {
continue;
}
$tr = i < data.flexStart ? $leftRow : ((i >= data.flexStart && i <= data.flexEnd) ? $flexRow : $rightRow);
if(i === 0 && checkable) {
$cTd = $('<td data-index="check" class="check-row check-btn"><i class="icon-check-empty"></i></td>');
if(options.checkboxName) {
$cTd.append('<input class="hide" type="checkbox" name="' + options.checkboxName + '" value="' + row.id + '">');
}
$tr.append($cTd);
}
if(cols[i].ignore) continue;
// format row column
if(!$.isPlainObject(rowCol)) {
rowCol = {
text: rowCol,
row: r,
index: i
};
} else {
rowCol.row = r;
rowCol.index = i;
}
row.data[i] = rowCol;
$td = $('<td class="datatable-cell"/>');
$td.html(rowCol.text)
.addClass(rowCol.cssClass)
.addClass(cols[i].colClass)
.attr('colspan', rowCol.colSpan)
.attr({
'data-row': r,
'data-index': i,
'data-flex': false,
'data-type': cols[i].type,
style: rowCol.css,
title: rowCol.title || ''
}).css('width', cols[i].width);
$tr.append($td);
}
$left.append($leftRow);
$flex.append($flexRow);
$right.append($rightRow);
}
var $rowSpan;
if(data.fixedLeft) {
$rowSpan = $(dataRowSpan);
$rowSpan.addClass('fixed-left')
.find('table')
.addClass(options.tableClass)
.append($left);
$rows.append($rowSpan);
}
if(data.flexArea) {
$rowSpan = $(dataRowSpan);
$rowSpan.addClass('flexarea')
.find('.datatable-wrapper')
.append('<div class="scrolled-shadow scrolled-in-shadow"></div><div class="scrolled-shadow scrolled-out-shadow"></div>')
.find('table')
.addClass(options.tableClass)
.append($flex);
$rows.append($rowSpan);
}
if(data.fixedRight) {
$rowSpan = $(dataRowSpan);
$rowSpan.addClass('fixed-right')
.find('table')
.addClass(options.tableClass)
.append($right);
$rows.append($rowSpan);
}
$datatable.append($rows);
if(data.flexArea) {
$datatable.append('<div class="scroll-wrapper"><div class="scroll-slide scroll-pos-' + options.scrollPos + '"><div class="bar"></div></div></div>');
}
var $oldFooter = $datatable.children('.datatable-footer').detach();
if(data.footer) {
$datatable.append($('<div class="datatable-footer"/>').append(data.footer));
data.footer = null;
} else if($oldFooter.length) {
$datatable.append($oldFooter);
}
that.$datatable = $datatable.data(name, that);
if(that.isTable && that.firstShow) {
that.$table.attr('data-datatable-id', this.id).hide().after($datatable);
that.firstShow = false;
}
that.bindEvents();
that.refreshSize();
that.callEvent('render');
};
// Bind global events
DataTable.prototype.bindEvents = function() {
var that = this,
data = this.data,
options = this.options,
$datatable = this.$datatable;
var $dataSpans = that.$dataSpans = $datatable.children('.datatable-head, .datatable-rows').find('.datatable-span');
var $rowsSpans = that.$rowsSpans = $datatable.children('.datatable-rows').children('.datatable-rows-span');
var $headSpans = that.$headSpans = $datatable.children('.datatable-head').children('.datatable-head-span');
var $cells = that.$cells = $dataSpans.find('.datatable-head-cell,.datatable-cell');
var $dataCells = that.$dataCells = $cells.filter('.datatable-cell');
that.$headCells = $cells.filter('.datatable-head-cell');
var $rows = that.$rows = that.$rowsSpans.find('.datatable-row');
// handle row hover events
if(options.rowHover) {
var hoverClass = options.hoverClass;
$rowsSpans.on('mouseenter', '.datatable-cell', function() {
$dataCells.filter('.' + hoverClass).removeClass(hoverClass);
$rows.filter('.' + hoverClass).removeClass(hoverClass);
$rows.filter('[data-index="' + $(this).addClass(hoverClass).data('row') + '"]').addClass(hoverClass);
}).on('mouseleave', '.datatable-cell', function() {
$dataCells.filter('.' + hoverClass).removeClass(hoverClass);
$rows.filter('.' + hoverClass).removeClass(hoverClass);
});
}
// handle col hover events
if(options.colHover) {
var colHoverClass = options.colHoverClass;
$headSpans.on('mouseenter', '.datatable-head-cell', function() {
$cells.filter('.' + colHoverClass).removeClass(colHoverClass);
$cells.filter('[data-index="' + $(this).data('index') + '"]').addClass(colHoverClass);
}).on('mouseleave', '.datatable-head-cell', function() {
$cells.filter('.' + colHoverClass).removeClass(colHoverClass);
});
}
// handle srcoll for flex area
if(data.flexArea) {
var $scrollbar = $datatable.find('.scroll-slide'),
$flexArea = $datatable.find('.datatable-span.flexarea'),
$fixedLeft = $datatable.find('.datatable-span.fixed-left'),
$flexTable = $datatable.find('.datatable-span.flexarea .table-datatable');
var $bar = $scrollbar.children('.bar'),
flexWidth,
scrollWidth,
tableWidth,
barLeft,
scrollOffsetStoreName = that.id + '_' + 'scrollOffset',
firtScroll,
left;
that.width = $datatable.width();
$datatable.resize(function() {
that.width = $datatable.width();
});
var srollTable = function(offset, silence) {
barLeft = Math.max(0, Math.min(flexWidth - scrollWidth, offset));
if(!silence) {
$datatable.addClass('scrolling');
}
$bar.css('left', barLeft);
left = 0 - Math.floor((tableWidth - flexWidth) * barLeft / (flexWidth - scrollWidth));
$flexTable.css('left', left);
$datatable.toggleClass('scrolled-in', barLeft > 2)
.toggleClass('scrolled-out', barLeft < flexWidth - scrollWidth - 2);
if(options.storage) store.pageSet(scrollOffsetStoreName, barLeft);
};
var resizeScrollbar = function() {
flexWidth = $flexArea.width() - 2;
$scrollbar.width(flexWidth).css('left', $fixedLeft.width());
tableWidth = 0;
$flexTable.first().find('tr:first').children('td,th').each(function() {
tableWidth += $(this).outerWidth();
});
scrollWidth = Math.floor((flexWidth * flexWidth) / tableWidth);
$bar.css('width', scrollWidth);
$flexTable.css('min-width', Math.max(flexWidth, tableWidth));
$datatable.toggleClass('show-scroll-slide', tableWidth > flexWidth);
if(!firtScroll && flexWidth !== scrollWidth) {
firtScroll = true;
srollTable(store.pageGet(scrollOffsetStoreName, 0), true); // todo: unused?
}
if($datatable.hasClass('size-changing')) {
srollTable(barLeft, true);
}
};
$flexArea.resize(resizeScrollbar);
if(options.storage) resizeScrollbar();
var dragOptions = {
move: false,
stopPropagation: true,
drag: function(e) {
srollTable($bar.position().left + e.smallOffset.x * (e.element.hasClass('bar') ? 1 : -1));
},
finish: function() {
$datatable.removeClass('scrolling');
}
};
if($.fn.draggable) {
$bar.draggable(dragOptions);
if(options.flexHeadDrag) {
$datatable.find('.datatable-head-span.flexarea').draggable(dragOptions);
}
} else {
console.error('DataTable requires draggable.js to improve UI.');
}
$scrollbar.mousedown(function(event) {
var x = event.pageX - $scrollbar.offset().left;
srollTable(x - (scrollWidth / 2));
});
}
// handle row check events
if(options.checkable) {
var checkedStatusStoreName = that.id + '_checkedStatus',
checkedClass = options.checkedClass,
rowId;
var syncChecks = function() {
var $checkRows = $rowsSpans.first().find('.datatable-row');
var $checkedRows = $checkRows.filter('.' + checkedClass);
if(options.checkboxName) $checkRows.find('.check-row input:checkbox').prop('checked', false);
var checkedStatus = {
checkedAll: $checkRows.length === $checkedRows.length && $checkedRows.length > 0,
checks: $checkedRows.map(function() {
rowId = $(this).data('id');
if(options.checkboxName) {
$(this).find('.check-row input:checkbox').prop('checked', true);
}
return rowId;
}).toArray()
};
that.checks = checkedStatus;
$.each(data.rows, function(index, value) {
value.checked = ($.inArray(value.id, checkedStatus.checks) > -1);
});
$headSpans.find('.check-all').toggleClass('checked', !!checkedStatus.checkedAll);
if(options.storage) store.pageSet(checkedStatusStoreName, checkedStatus);
that.callEvent('checksChanged', {
checks: checkedStatus
});
};
var toggleRowClass = function(ele, toggle) {
var $tr = $(ele).closest('tr');
if(toggle === undefined) toggle = !$tr.hasClass(checkedClass);
$rows.filter('[data-index="' + $tr.data('index') + '"]').toggleClass(checkedClass, !!toggle);
};
var checkEventPrefix = 'click.zui.datatable.check';
if(options.selectable) {
var selectableOptions = {
selector: '.datatable-rows .datatable-row',
trigger: '.datatable-rows',
start: function(e) {
var $checkRow = $(e.target).closest('.check-row, .check-btn');
if($checkRow.length) {
if($checkRow.is('.check-row')) {
toggleRowClass($checkRow);
syncChecks();
}
return false;
}
},
rangeFunc: function(range, targetRange) {
return Math.max(range.top, targetRange.top) < Math.min(range.top + range.height, targetRange.top + targetRange.height);
},
select: function(e) {
toggleRowClass(e.target, true);
},
unselect: function(e) {
toggleRowClass(e.target, false);
},
finish: function(e) {
syncChecks();
}
};
if($.isPlainObject(options.selectable)) {
$.extend(selectableOptions, options.selectable);
}
this.$datatable.selectable(selectableOptions);
} else {
this.$rowsSpans.off(checkEventPrefix).on(checkEventPrefix + 'row', options.checkByClickRow ? 'tr' : '.check-row', function() {
toggleRowClass(this);
syncChecks();
});
}
this.$datatable.off(checkEventPrefix).on('click.zui.datatable.check', '.check-all', function() {
$rows.toggleClass(checkedClass, $(this).toggleClass('checked').hasClass('checked'));
syncChecks();
}).on(checkEventPrefix + '.none', '.check-none', function() {
$rows.toggleClass(checkedClass, false);
syncChecks();
}).on(checkEventPrefix + '.inverse', '.check-inverse', function() {
$rows.toggleClass(checkedClass);
syncChecks();
});
if(options.storage) {
var checkedStatus = store.pageGet(checkedStatusStoreName);
if(checkedStatus) {
$headSpans.find('.check-all').toggleClass('checked', checkedStatus.checkedAll);
if(checkedStatus.checkedAll) {
$rows.addClass(checkedClass);
} else {
$rows.removeClass(checkedClass);
$.each(checkedStatus.checks, function(index, ele) {
$rows.filter('[data-id="' + ele + '"]').addClass(checkedClass);
});
}
if(checkedStatus.checks.length) {
syncChecks();
}
}
}
}
// fixed header
if(options.fixedHeader) {
var offsetTop,
height,
scrollTop,
$dataTableHead = $datatable.children('.datatable-head'),
navbarHeight = options.fixedHeaderOffset || $('.navbar.navbar-fixed-top').height() || 0;
var handleScroll = function() {
offsetTop = $datatable.offset().top;
scrollTop = $(window).scrollTop();
height = $datatable.height();
$datatable.toggleClass('head-fixed', (scrollTop + navbarHeight) > offsetTop && (scrollTop + navbarHeight) < (offsetTop + height));
if($datatable.hasClass('head-fixed')) {
$dataTableHead.css({
width: $datatable.width(),
top: navbarHeight
});
} else {
$dataTableHead.attr('style', '');
}
};
$(window).scroll(handleScroll);
handleScroll();
}
// handle sort
if(options.sortable) {
$headSpans.on('click', 'th:not(.sort-disabled, .check-btn)', function() {
if($datatable.hasClass('size-changing')) return;
that.sortTable($(this));
});
if(options.storage) that.sortTable();
} else if(options.mergeRows) {
this.mergeRows();
}
};
DataTable.prototype.mergeRows = function() {
var $cells = this.$rowsSpans.find('.datatable-cell');
var cols = this.data.cols;
for(var i = 0; i < cols.length; i++) {
var col = cols[i];
if(col.mergeRows) {
var $cs = $cells.filter('[data-index="' + i + '"]');
if($cs.length > 1) {
var $lastCell, rowspan;
$cs.each(function() {
var $cell = $(this);
if($lastCell) {
if($cell.html() === $lastCell.html()) {
rowspan = $lastCell.attr('rowspan') || 1;
if(typeof rowspan !== 'number') {
rowspan = parseInt(rowspan);
if(isNaN(rowspan)) rowspan = 1;
}
$lastCell.attr('rowspan', rowspan + 1).css('vertical-align', 'middle');
$cell.remove();
} else {
$lastCell = $cell;
}
} else {
$lastCell = $cell;
}
});
}
}
}
};
// Sort table
DataTable.prototype.sortTable = function($th) {
var store = $.zui.store,
options = this.options;
var sorterStoreName = this.id + '_datatableSorter';
var sorter = options.storage ? store.pageGet(sorterStoreName) : null;
// sort-down: desc
// sort-up: asc
if(!$th) {
if(sorter) {
$th = this.$headCells.filter('[data-index="' + sorter.index + '"]').addClass('sort-' + (sorter.type === 'up' ? 'down' : 'up'));
} else {
$th = this.$headCells.filter('.sort-up, .sort-down').first();
}
}
if(!$th.length) {
return;
}
var data = this.data;
var cols = data.cols,
rows = data.rows,
$headCells = this.$headCells,
sortUp,
type,
index;
sortUp = !$th.hasClass('sort-up');
if(data.keepSort) sortUp = !sortUp;
data.keepSort = null;
$headCells.removeClass('sort-up sort-down');
$th.addClass(sortUp ? 'sort-up' : 'sort-down');
index = $th.data('index');
$.each(cols, function(idx, col) {
if(idx != index && (col.sort === 'up' || col.sort === 'down')) {
col.sort = true;
} else if(idx == index) {
col.sort = sortUp ? 'up' : 'down';
type = col.type;
}
});
var valA, valB, result, $dataRows = this.$dataCells.filter('[data-index="' + index + '"]');
rows.sort(function(cellA, cellB) {
cellA = cellA.data[index];
cellB = cellB.data[index];
valA = $dataRows.filter('[data-row="' + cellA.row + '"]').text();
valB = $dataRows.filter('[data-row="' + cellB.row + '"]').text();
if(type === 'number') {
valA = parseFloat(valA);
valB = parseFloat(valB);
} else if(type === 'date') {
valA = Date.parse(valA);
valB = Date.parse(valB);
} else {
valA = valA.toLowerCase();
valB = valB.toLowerCase();
}
result = valA < valB ? 1 : (valA > valB ? -1 : 0);
if(sortUp) {
result = result * (-1);
}
return result;
});
var $rows = this.$rows,
lastRows = [],
$row, $lastRow, $r;
$.each(rows, function(idx, row) {
$row = $rows.filter('[data-index="' + row.index + '"]');
$row.each(function(rIdx) {
$r = $(this);
$lastRow = lastRows[rIdx];
if($lastRow) {
$lastRow.after($r);
} else {
$r.parent().prepend($r);
}
lastRows[rIdx] = $r;
});
});
sorter = {
index: index,
type: sortUp ? 'up' : 'down'
};
// save sort with local storage
if(options.storage) store.pageSet(sorterStoreName, sorter);
this.callEvent('sort', {
sorter: sorter
});
};
// Refresh size
DataTable.prototype.refreshSize = function() {
var $datatable = this.$datatable,
options = this.options,
rows = this.data.rows,
cols = this.data.cols,
i;
$datatable.find('.datatable-span.fixed-left').css('width', options.fixedLeftWidth);
$datatable.find('.datatable-span.fixed-right').css('width', options.fixedRightWidth);
if(options.fixCellHeight) {
var findMaxHeight = function($cells) {
var mx = 0,
$cell, rowSpan;
$cells.css('height', 'auto');
$cells.each(function() {
$cell = $(this);
rowSpan = $cell.attr('rowspan');
if(!rowSpan || rowSpan == 1) mx = Math.max(mx, $cell.outerHeight());
});
return mx;
};
var $dataCells = this.$dataCells,
$cells = this.$cells,
$headCells = this.$headCells;
// set height of head cells
var headMaxHeight = findMaxHeight($headCells);
$headCells.css('min-height', headMaxHeight).css('height', headMaxHeight);
// set height of data cells
var $rowCells;
for(i = 0; i < rows.length; ++i) {
$rowCells = $dataCells.filter('[data-row="' + i + '"]');
var rowMaxHeight = findMaxHeight($rowCells);
$rowCells.css('min-height', rowMaxHeight).css('height', rowMaxHeight);
}
}
};
// Call event
DataTable.prototype.callEvent = function(name, params) {
var result = this.$.callEvent(name + '.' + this.name, params, this).result;
return !(result !== undefined && (!result));
};
$.fn.datatable = function(option, newData) {
return this.each(function() {
var $this = $(this);
var data = $this.data(name);
var options = typeof option == 'object' && option;
if(!data) $this.data(name, (data = new DataTable(this, options)));
if(typeof option == 'string') {
if(option === 'load' && $.isPlainObject(newData) && (newData.keepSort === undefined || newData.keepSort === null)) newData.keepSort = true;
data[option](newData);
}
});
};
$.fn.datatable.Constructor = DataTable;
}(jQuery));