META-INF.resources.org.richfaces.extendedDataTable.js Maven / Gradle / Ivy
The newest version!
/*
* JBoss, Home of Professional Open Source
* Copyright ${year}, Red Hat, Inc. and individual contributors
* by the @authors tag. See the copyright.txt in the distribution for a
* full listing of individual contributors.
*
* This is free software; you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* This software is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this software; if not, write to the Free
* Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
* 02110-1301 USA, or see the FSF site: http://www.fsf.org.
*/
(function($, rf) {
rf.utils = rf.utils || {};
rf.utils.addCSSText = function(cssText, elementId) {
var style = $("").attr({type: 'text/css', id: elementId}).appendTo("head");
try {
style.html(cssText);
} catch (e) {
//IE
style[0].styleSheet.cssText = cssText;
}
};
rf.utils.Ranges = function() {
this.ranges = [];
};
rf.utils.Ranges.prototype = {
add: function(index) {
var i = 0;
while (i < this.ranges.length && index >= this.ranges[i++][1]);
i--;
if (this.ranges[i - 1] && index == (this.ranges[i - 1][1] + 1)) {
if (index == (this.ranges[i][0] - 1)) {
this.ranges[i - 1][1] = this.ranges[i][1];
this.ranges.splice(i, 1);
} else {
this.ranges[i - 1][1]++;
}
} else {
if (this.ranges[i]) {
if (this.ranges[i] && index == (this.ranges[i][0] - 1)) {
this.ranges[i][0]--;
} else {
if (index == (this.ranges[i][1] + 1)) {
this.ranges[i][1]++;
} else {
if (index < this.ranges[i][1]) {
this.ranges.splice(i, 0, [index, index]);
} else {
this.ranges.splice(i + 1, 0, [index, index]);
}
}
}
} else {
this.ranges.splice(i, 0, [index, index]);
}
}
},
remove: function(index) {
if (!this.contains(index)) {
return;
}
var i = 0;
while (i < this.ranges.length && index > this.ranges[i++][1]);
i--;
if (this.ranges[i]) {
if (index == (this.ranges[i][1])) {
if (index == (this.ranges[i][0])) {
this.ranges.splice(i, 1);
} else {
this.ranges[i][1]--;
}
} else {
if (index == (this.ranges[i][0])) {
this.ranges[i][0]++;
} else {
this.ranges.splice(i + 1, 0, [index + 1, this.ranges[i][1]]);
this.ranges[i][1] = index - 1;
}
}
}
},
clear: function() {
this.ranges = [];
},
contains: function(index) {
var i = 0;
while (i < this.ranges.length && index >= this.ranges[i][0]) {
if (index >= this.ranges[i][0] && index <= this.ranges[i][1]) {
return true;
} else {
i++;
}
}
return false;
},
toString: function() {
var ret = new Array(this.ranges.length);
for (var i = 0; i < this.ranges.length; i++) {
ret[i] = this.ranges[i].join();
}
return ret.join(";");
}
};
var WIDTH_CLASS_NAME_BASE = "rf-edt-c-";
var DATA_ATTRIBUTE = "rf-column-name";
var MIN_WIDTH = 20;
rf.ui = rf.ui || {};
rf.ui.ExtendedDataTable = rf.BaseComponent.extendClass({
name: "ExtendedDataTable",
/**
* Backing object for rich:extendedDataTable
*
* @extends RichFaces.BaseComponent
* @memberOf! RichFaces.ui
* @constructs RichFaces.ui.ExtendedDataTable
*
* @param id
* @param rowCount
* @param ajaxFunction
* @param options
*/
init: function (id, rowCount, ajaxFunction, options) {
$super.constructor.call(this, id);
this.ranges = new rf.utils.Ranges();
this.rowCount = rowCount;
this.ajaxFunction = ajaxFunction;
this.options = options || {};
this.options.loadDelay = 400;
this.options.selectionMode = this.options.selectionMode || "multiple";
this.element = this.attachToDom();
this.newWidths = {};
this.storeDomReferences();
if (this.options['onready'] && typeof this.options['onready'] == 'function') {
rf.Event.bind(this.element, "rich:ready", this.options['onready']);
}
this.resizeEventName = "resize.rf.edt." + this.id;
$(document).ready($.proxy(this.initialize, this));
this.activateResizeListener();
var body = $(this.element).find(".rf-edt-b .rf-edt-cnt");
var delayedScroll = function(table, body) {
return function () {
// let browser scroll the element
setTimeout(function() {
table.scrollElement.scrollLeft = body.scrollLeft();
table.updateScrollPosition();
}, 0);
};
};
body.on("scroll", delayedScroll(this, body));
body.on("mousewheel", $.proxy(this.horizontalScrollHandler, this));
$(this.scrollElement).on("scroll", $.proxy(this.updateScrollPosition, this));
this.bindHeaderHandlers();
$(this.element).on("rich:onajaxcomplete", $.proxy(this.ajaxComplete, this));
this.resizeData = {};
this.idOfReorderingColumn = "";
this.timeoutId = null;
},
storeDomReferences: function() {
this.dragElement = document.getElementById(this.id + ":d");
this.reorderElement = document.getElementById(this.id + ":r");
this.reorderMarkerElement = document.getElementById(this.id + ":rm");
this.widthInput = document.getElementById(this.id + ":wi");
this.selectionInput = document.getElementById(this.id + ":si");
this.header = $(this.element).children(".rf-edt-hdr");
this.headerCells = this.header.find(".rf-edt-hdr-c");
this.footerCells = $(this.element).children(".rf-edt-ftr").find(".rf-edt-ftr-c");
this.resizerHolders = this.header.find(".rf-edt-rsz-cntr");
this.frozenHeaderPartElement = document.getElementById(this.id + ":frozenHeader");
this.frozenColumnCount = this.frozenHeaderPartElement ? this.frozenHeaderPartElement.children[0].rows[0].cells.length : 0;//TODO Richfaces.firstDescendant;
this.headerElement = document.getElementById(this.id + ":header");
this.footerElement = document.getElementById(this.id + ":footer");
this.scrollElement = document.getElementById(this.id + ":scrl");
this.scrollContentElement = document.getElementById(this.id + ":scrl-cnt");
},
getColumnPosition: function(id) {
var position;
for (var i = 0; i < this.headerCells.length; i++) {
if (id == this.headerCells[i].className.match(new RegExp(WIDTH_CLASS_NAME_BASE + "([^\\W]*)"))[1]) {
position = i;
}
}
return position;
},
setColumnPosition: function(id, position) {
var colunmsOrder = "";
var before;
for (var i = 0; i < this.headerCells.length; i++) {
var current = this.headerCells[i].className.match(new RegExp(WIDTH_CLASS_NAME_BASE + "([^\\W]*)"))[1];
if (i == position) {
if (before) {
colunmsOrder += current + "," + id + ",";
} else {
colunmsOrder += id + "," + current + ",";
}
} else {
if (id != current) {
colunmsOrder += current + ",";
} else {
before = true;
}
}
}
this.ajaxFunction(null, {"rich:columnsOrder" : colunmsOrder}); // TODO Maybe, event model should be used here.
},
setColumnWidth: function(columnId, width) {
width = width + "px";
var $table = $(document.getElementById(this.element.id));
$table.find("." + WIDTH_CLASS_NAME_BASE + columnId).parent().css('width', width);
$table.find("." + WIDTH_CLASS_NAME_BASE + columnId).css('width', width);
this.newWidths[columnId] = width;
var widthsArray = new Array();
for (var id in this.newWidths) {
if (this.newWidths.hasOwnProperty(id)) {
widthsArray.push(id + ":" + this.newWidths[id]);
}
}
this.widthInput.value = widthsArray.toString();
this.updateLayout();
this.adjustResizers();
this.ajaxFunction(); // TODO Maybe, event model should be used here.
},
/**
* Filter a table column
*
* @method
* @name RichFaces.ui.ExtendedDataTable#filter
* @param columnId {string} short column id
* @param filterValue {string} value to filter by
* @param [isClear] {boolean} whether or not to clear the previous filter, default - false
*/
filter: function(colunmId, filterValue, isClear) {
if (typeof(filterValue) == "undefined" || filterValue == null) {
filterValue = "";
}
var map = {};
map[this.id + "rich:filtering"] = colunmId + ":" + filterValue + ":" + isClear;
this.ajaxFunction(null, map); // TODO Maybe, event model should be used here.
},
/**
* Clear any filtering currently applied to the table
*
* @method
* @name RichFaces.ui.ExtendedDataTable#clearFiltering
*/
clearFiltering: function() {
this.filter("", "", true);
},
sortHandler: function(event) {
var sortHandle = $(event.data.sortHandle);
var button = sortHandle.find('.rf-edt-srt-btn');
var columnId = button.data('columnid');
var sortOrder = button.hasClass('rf-edt-srt-asc') ? 'descending' : 'ascending';
this.sort(columnId, sortOrder, false);
},
filterHandler: function(event) {
if (event.type == "keyup" && event.keyCode != 13) {
return;
}
var filterHandle = $(event.data.filterHandle);
var columnId = filterHandle.data('columnid');
var filterValue = filterHandle.val();
this.filter(columnId, filterValue, false);
},
/**
* Sort a table column
*
* @method
* @name RichFaces.ui.ExtendedDataTable#sort
* @param columnId {string} short column id
* @param [direction] {string} sort direction ("ascending", "descending", "unsorted")
* if not provided and the column is sorted the direction switches, if it's unsorted it will be sorted in ascending sirection
* @param [isClear] {boolean} whether or not to clear the previous sort, default - false
*/
sort: function(colunmId, sortOrder, isClear) {
if (typeof(sortOrder) == "string") {
sortOrder = sortOrder.toLowerCase();
}
var map = {}
map[this.id + "rich:sorting"] = colunmId + ":" + sortOrder + ":" + isClear;
this.ajaxFunction(null, map); // TODO Maybe, event model should be used here.
},
/**
* Clear any sorting currently applied to the table
*
* @method
* @name RichFaces.ui.ExtendedDataTable#clearSorting
*/
clearSorting: function() {
this.sort("", "", true);
},
destroy: function() {
$(window).off("resize", this.updateLayout);
$(rf.getDomElement(this.id + ':st')).remove();
if (this.columnControl) {
this.columnControl.destroy();
}
$super.destroy.call(this);
},
bindHeaderHandlers: function() {
this.header.find(".rf-edt-rsz").on("mousedown", $.proxy(this.beginResize, this));
this.headerCells.on("mousedown", $.proxy(this.beginReorder, this));
var self = this;
this.header.find(".rf-edt-c-srt").each(function() {
$(this).on("click", {sortHandle: this}, $.proxy(self.sortHandler, self));
});
this.header.find(".rf-edt-flt-i").each(function() {
$(this).on("blur", {filterHandle: this}, $.proxy(self.filterHandler, self));
$(this).on("keyup", {filterHandle: this}, $.proxy(self.filterHandler, self));
});
},
updateLayout: function() {
// Skip updateLayout in case the object was not properly initialize, otherwise the method will crash.
// I assume this is not too offensive as, it does not make any sense updating the layout of a non initialized object
if (!this.contentDivElement) {
return;
}
this.deActivateResizeListener();
this.headerCells.height("auto");
var headerCellHeight = 0;
this.headerCells.each(function() {
if (this.clientHeight > headerCellHeight) {
headerCellHeight = this.clientHeight;
}
});
this.headerCells.height(headerCellHeight + "px");
this.footerCells.height("auto");
var footerCellHeight = 0;
this.footerCells.each(function() {
if (this.clientHeight > footerCellHeight) {
footerCellHeight = this.clientHeight;
}
});
this.footerCells.height(footerCellHeight + "px");
this.contentDivElement.css('width', 'auto');
var offsetWidth = this.frozenHeaderPartElement ? this.frozenHeaderPartElement.offsetWidth : 0;
var width = Math.max(0, this.element.clientWidth - offsetWidth);
if (width) {
this.parts.each(function() {
this.style.width = "auto";
});
var contentWidth = this.parts.width();
if (contentWidth > width) {
this.contentDivElement.css('width', width + 'px');
}
this.contentDivElement.css('display', 'block');
// update scroller and scroll-content
if (contentWidth > width) {
this.parts.each(function() {
this.style.width = width + "px";
});
this.scrollElement.style.display = "block";
this.scrollElement.style.overflowX = "scroll";
this.scrollElement.style.width = width + "px";
this.scrollContentElement.style.width = contentWidth + "px";
this.scrollElement.scrollLeft = document.getElementById(this.id + ":scroll").value;
this.updateScrollPosition();
} else {
this.parts.each(function() {
this.style.width = "";
});
this.scrollElement.style.display = "none";
}
} else if (this.element.clientWidth != 0) {
this.contentDivElement.css('display', 'none');
}
var height = this.element.clientHeight;
var el = this.element.firstChild;
while (el && (!el.nodeName || el.nodeName.toUpperCase() != "TABLE")) {
if (el.nodeName && el.nodeName.toUpperCase() == "DIV" && el != this.bodyElement) {
height -= el.offsetHeight;
}
el = el.nextSibling;
}
if (this.bodyElement.offsetHeight != height || !this.contentElement) {
this.bodyElement.style.height = height > this.contentDivElement.height() ? "" : height + "px";
}
this.activateResizeListener();
},
adjustResizers: function() { //For IE7 only.
var scrollLeft = this.scrollElement ? this.scrollElement.scrollLeft : 0;
var clientWidth = this.element.clientWidth - 3;
var i = 0;
for (; i < this.frozenColumnCount; i++) {
if (clientWidth > 0) {
this.resizerHolders[i].style.display = "none";
this.resizerHolders[i].style.display = "";
clientWidth -= this.resizerHolders[i].offsetWidth;
}
if (clientWidth <= 0) {
this.resizerHolders[i].style.display = "none";
}
}
scrollLeft -= 3;
for (; i < this.resizerHolders.length; i++) {
if (clientWidth > 0) {
this.resizerHolders[i].style.display = "none";
if (scrollLeft > 0) {
this.resizerHolders[i].style.display = "";
scrollLeft -= this.resizerHolders[i].offsetWidth;
if (scrollLeft > 0) {
this.resizerHolders[i].style.display = "none";
} else {
clientWidth += scrollLeft;
}
} else {
this.resizerHolders[i].style.display = "";
clientWidth -= this.resizerHolders[i].offsetWidth;
}
}
if (clientWidth <= 0) {
this.resizerHolders[i].style.display = "none";
}
}
},
updateScrollPosition: function() {
if (this.scrollElement) {
var scrollLeft = this.scrollElement.scrollLeft;
this.parts.each(function() {
this.scrollLeft = scrollLeft;
});
document.getElementById(this.id + ":scroll").value = scrollLeft;
}
this.adjustResizers();
},
horizontalScrollHandler: function(event) {
var scrollDelta = event.deltaFactor * event.deltaX;
// ignore vertical scroll (deltaX = 0)
if (scrollDelta && this.scrollElement) {
this.scrollElement.scrollLeft += scrollDelta;
this.updateScrollPosition();
}
},
initialize: function() {
this.deActivateResizeListener();
if (! $(this.element).is(":visible")) {
this.showOffscreen(this.element);
}
this.bodyElement = document.getElementById(this.id + ":b");
this.bodyElement.tabIndex = -1; //TODO don't use tabIndex.
this.contentDivElement = $(this.bodyElement).find('.rf-edt-cnt');
var bodyJQuery = $(this.bodyElement);
this.contentElement = bodyJQuery.children("div:not(.rf-edt-ndt):first")[0];
if (this.contentElement) {
this.spacerElement = this.contentElement.children[0];//TODO this.marginElement = Richfaces.firstDescendant(this.contentElement);
this.dataTableElement = this.contentElement.lastChild;//TODO this.dataTableElement = Richfaces.lastDescendant(this.contentElement);
this.tbodies = $(document.getElementById(this.id + ":tbf")).add(document.getElementById(this.id + ":tbn"));
this.rows = this.tbodies[0].rows.length;
this.rowHeight = this.dataTableElement.offsetHeight / this.rows;
if (this.rowCount != this.rows) {
this.contentElement.style.height = (this.rowCount * this.rowHeight) + "px";
}
bodyJQuery.on("scroll", $.proxy(this.bodyScrollListener, this));
if (this.options.selectionMode != "none") {
this.tbodies.on("click", $.proxy(this.selectionClickListener, this));
bodyJQuery.on(window.opera ? "keypress" : "keydown", $.proxy(this.selectionKeyDownListener, this));
this.initializeSelection();
}
} else {
this.spacerElement = null;
this.dataTableElement = null;
}
var edt = this.element;
this.parts = $(this.element).find(".rf-edt-cnt, .rf-edt-ftr-cnt").filter(function() {
return $(this).parents('.rf-edt').get(0) === edt;
});
if ($(this.element).data('offscreenElements')) {
this.hideOffscreen(this.element);
}
this.activateResizeListener();
if (this.options['showColumnControl']) {
this.__addColumnControl();
}
this.updateLayout();
this.updateScrollPosition(); //TODO Restore horizontal scroll position
$(this.element).trigger("rich:ready", this);
},
showOffscreen: function(element) {
var $element = $(element);
var offscreenElements = $element.parents(":not(:visible)").addBack().toArray().reverse();
var that = this;
$.each(offscreenElements, function() {
$this = $(this);
if ($this.css('display') === 'none') {
that.showOffscreenElement($(this));
}
})
$element.data('offscreenElements', offscreenElements);
},
hideOffscreen: function(element) {
var $element = $(element);
var offscreenElements = $element.data('offscreenElements');
var that = this;
$.each(offscreenElements, function() {
$this = $(this);
if ($this.data('offscreenOldValues')) {
that.hideOffscreenElement($(this));
}
})
$element.removeData('offscreenElements');
},
showOffscreenElement: function($element) {
var offscreenOldValues = {};
offscreenOldValues.oldPosition = $element.css('position');
offscreenOldValues.oldLeft = $element.css('left');
offscreenOldValues.oldDisplay = $element.css('display');
$element.css('position', 'absolute');
$element.css('left', '-10000');
$element.css('display', 'block');
$element.data('offscreenOldValues', offscreenOldValues);
},
hideOffscreenElement: function($element) {
var offscreenOldValues = $element.data('offscreenOldValues');
$element.css('display', offscreenOldValues.oldDisplay);
$element.css('left', offscreenOldValues.oldLeft);
$element.css('position', offscreenOldValues.oldPosition);
$element.removeData('offscreenOldValues');
},
drag: function(event) {
$(this.dragElement).setPosition({left:Math.max(this.resizeData.left + MIN_WIDTH, event.pageX), top: $(this.dragElement).offset().top});
return false;
},
beginResize: function(event) {
var id = event.currentTarget.parentNode.className.match(new RegExp(WIDTH_CLASS_NAME_BASE + "([^\\W]*)"))[1];
this.resizeData = {
id : id,
left : $(event.currentTarget).parent().offset().left
};
this.dragElement.style.height = this.element.offsetHeight + "px";
$(this.dragElement).setPosition({top:$(this.element).offset().top, left:event.pageX});
this.dragElement.style.display = "block";
$(document).on("mousemove", $.proxy(this.drag, this));
$(document).one("mouseup", $.proxy(this.endResize, this));
return false;
},
endResize: function(event) {
$(document).off("mousemove", this.drag);
this.dragElement.style.display = "none";
var width = Math.max(MIN_WIDTH, event.pageX - this.resizeData.left);
this.setColumnWidth(this.resizeData.id, width);
},
reorder: function(event) {
$(this.reorderElement).setPosition(event, {offset:[5,5]});
this.reorderElement.style.display = "block";
return false;
},
beginReorder: function(event) {
if (!$(event.target).is("a, img, :input")) {
this.idOfReorderingColumn = event.currentTarget.className.match(new RegExp(WIDTH_CLASS_NAME_BASE + "([^\\W]*)"))[1];
$(document).on("mousemove", $.proxy(this.reorder, this));
this.headerCells.on("mouseover", $.proxy(this.overReorder, this));
$(document).one("mouseup", $.proxy(this.cancelReorder, this));
return false;
}
},
overReorder: function(event) {
if (this.idOfReorderingColumn != event.currentTarget.className.match(new RegExp(WIDTH_CLASS_NAME_BASE + "([^\\W]*)"))[1]) {
var eventElement = $(event.currentTarget);
var offset = eventElement.offset();
$(this.reorderMarkerElement).setPosition({top:offset.top + eventElement.height(), left:offset.left - 5});
this.reorderMarkerElement.style.display = "block";
eventElement.one("mouseout", $.proxy(this.outReorder, this));
eventElement.one("mouseup", $.proxy(this.endReorder, this));
}
},
outReorder: function(event) {
this.reorderMarkerElement.style.display = "";
$(event.currentTarget).off("mouseup", this.endReorder);
},
endReorder: function(event) {
this.reorderMarkerElement.style.display = "";
$(event.currentTarget).off("mouseout", this.outReorder);
var id = event.currentTarget.className.match(new RegExp(WIDTH_CLASS_NAME_BASE + "([^\\W]*)"))[1];
var colunmsOrder = "";
var _this = this;
this.headerCells.each(function() {
var i = this.className.match(new RegExp(WIDTH_CLASS_NAME_BASE + "([^\\W]*)"))[1];
if (i == id) {
colunmsOrder += _this.idOfReorderingColumn + "," + id + ",";
} else if (i != _this.idOfReorderingColumn) {
colunmsOrder += i + ",";
}
});
this.ajaxFunction(event, {"rich:columnsOrder" : colunmsOrder}); // TODO Maybe, event model should be used here.
},
cancelReorder: function(event) {
$(document).off("mousemove", this.reorder);
this.headerCells.off("mouseover", this.overReorder);
this.reorderElement.style.display = "none";
},
loadData: function(event) {
var clientFirst = Math.round((this.bodyElement.scrollTop + this.bodyElement.clientHeight / 2) / this.rowHeight - this.rows / 2);
if (clientFirst <= 0) {
clientFirst = 0;
} else {
clientFirst = Math.min(this.rowCount - this.rows, clientFirst);
}
this.ajaxFunction(event, {"rich:clientFirst" : clientFirst});// TODO Maybe, event model should be used here.
},
bodyScrollListener: function(event) {
if (this.timeoutId) {
window.clearTimeout(this.timeoutId);
this.timeoutId = null;
}
if (Math.max(event.currentTarget.scrollTop - this.rowHeight, 0) < this.spacerElement.offsetHeight
|| Math.min(event.currentTarget.scrollTop + this.rowHeight + event.currentTarget.clientHeight, event.currentTarget.scrollHeight) > this.spacerElement.offsetHeight + this.dataTableElement.offsetHeight) {
var _this = this;
this.timeoutId = window.setTimeout(function (event) {
_this.loadData(event)
}, this.options.loadDelay);
}
},
showActiveRow: function() {
if (this.bodyElement.scrollTop > this.activeIndex * this.rowHeight + this.spacerElement.offsetHeight) { //UP
this.bodyElement.scrollTop = Math.max(this.bodyElement.scrollTop - this.rowHeight, 0);
} else if (this.bodyElement.scrollTop + this.bodyElement.clientHeight
< (this.activeIndex + 1) * this.rowHeight + this.spacerElement.offsetHeight) { //DOWN
this.bodyElement.scrollTop = Math.min(this.bodyElement.scrollTop + this.rowHeight, this.bodyElement.scrollHeight - this.bodyElement.clientHeight);
} else if (this.activeIndex == 0) {
this.bodyElement.scrollTop -= 5; // scroll top item down to force loading
} else if (this.activeIndex + 1 == this.rows) {
this.bodyElement.scrollTop += 5; // scroll bottom up
}
},
selectRow: function(index, skipEvent) {
this.ranges.add(index);
for (var i = 0; i < this.tbodies.length; i++) {
$(this.tbodies[i].rows[index]).addClass("rf-edt-r-sel");
}
if (!skipEvent) {
this.onselectionchange({}, index, true);
}
},
/**
* Deselect a table row
*
* @method
* @name RichFaces.ui.ExtendedDataTable#deselectRow
* @param index {int} row index, 0-based
*/
deselectRow: function (index, skipEvent) {
if (!this.options.selectionMode || this.options.selectionMode == 'none'
|| !this.ranges.contains(index) || (!skipEvent && !this.onbeforeselectionchange({}))) {
return;
}
this.ranges.remove(index);
for (var i = 0; i < this.tbodies.length; i++) {
$(this.tbodies[i].rows[index]).removeClass("rf-edt-r-sel");
}
if (!skipEvent) {
this.onselectionchange({}, index, true);
}
},
setActiveRow: function (index) {
if (typeof this.activeIndex == "number") {
for (var i = 0; i < this.tbodies.length; i++) {
$(this.tbodies[i].rows[this.activeIndex]).removeClass("rf-edt-r-act");
}
}
this.activeIndex = index;
for (var i = 0; i < this.tbodies.length; i++) {
$(this.tbodies[i].rows[this.activeIndex]).addClass("rf-edt-r-act");
}
},
resetShiftRow: function () {
if (typeof this.shiftIndex == "number") {
for (var i = 0; i < this.tbodies.length; i++) {
$(this.tbodies[i].rows[this.shiftIndex]).removeClass("rf-edt-r-sht");
}
}
this.shiftIndex = null;
},
setShiftRow: function (index) {
this.resetShiftRow();
this.shiftIndex = index;
if (typeof index == "number") {
for (var i = 0; i < this.tbodies.length; i++) {
$(this.tbodies[i].rows[this.shiftIndex]).addClass("rf-edt-r-sht");
}
}
},
initializeSelection: function() {
this.ranges.clear();
var strings = this.selectionInput.value.split("|");
this.activeIndex = strings[1] || null;
this.shiftIndex = strings[2] || null;
this.selectionFlag = null;
var rows = this.tbodies[0].rows;
for (var i = 0; i < rows.length; i++) {
var row = $(rows[i]);
if (row.hasClass("rf-edt-r-sel")) {
this.ranges.add(row[0].rowIndex)
}
if (row.hasClass("rf-edt-r-act")) {
this.activeIndex = row[0].rowIndex;
}
if (row.hasClass("rf-edt-r-sht")) {
this.shiftIndex = row[0].rowIndex;
}
}
this.writeSelection();
},
writeSelection: function() {
this.selectionInput.value = [this.ranges, this.activeIndex, this.shiftIndex, this.selectionFlag].join("|");
},
/**
* Select one or more table rows
*
* @method
* @name RichFaces.ui.ExtendedDataTable#selectRow
* @param index {int|int[]} row index (2) or range ([2,5])
*/
selectRows: function(range, skipEvent) {
if (!this.options.selectionMode || this.options.selectionMode == 'none'
|| (!skipEvent && !this.onbeforeselectionchange({}))) {
return;
}
if (typeof range == "number") {
range = [range, range];
}
if (this.options.selectionMode == 'single') {
range[1] = range[0];
}
var changed;
var i = 0;
for (; i < range[0]; i++) {
if (this.ranges.contains(i)) {
this.deselectRow(i, true);
changed = true;
}
}
for (; i <= range[1]; i++) {
if (!this.ranges.contains(i)) {
this.selectRow(i, true);
changed = true;
}
}
for (; i < this.rows; i++) {
if (this.ranges.contains(i)) {
this.deselectRow(i, true);
changed = true;
}
}
this.selectionFlag = typeof this.shiftIndex == "string" ? this.shiftIndex : "x";
if (!skipEvent) {
this.onselectionchange({}, range, true);
return;
}
return changed;
},
processSlectionWithShiftKey: function(index) {
if (this.shiftIndex == null) {
this.setShiftRow(this.activeIndex != null ? this.activeIndex : index);
}
var range;
if ("u" == this.shiftIndex) {
range = [0, index];
} else if ("d" == this.shiftIndex) {
range = [index, this.rows - 1];
} else if (index >= this.shiftIndex) {
range = [this.shiftIndex, index];
} else {
range = [index, this.shiftIndex];
}
return this.selectRows(range, true);
},
onbeforeselectionchange: function (event) {
return !this.options.onbeforeselectionchange || this.options.onbeforeselectionchange.call(this.element, event) != false;
},
onselectionchange: function (event, index, changed) {
if (!event.shiftKey) {
this.resetShiftRow();
}
if (this.activeIndex != index) {
this.setActiveRow(index);
this.showActiveRow();
}
if (changed) {
this.writeSelection();
if (this.options.onselectionchange) {
this.options.onselectionchange.call(this.element, event);
}
}
},
selectionClickListener: function (event) {
if (!this.onbeforeselectionchange(event)) {
return;
}
var changed;
if (event.shiftKey || event.ctrlKey) {
if (window.getSelection) { //TODO Try to find other way.
window.getSelection().removeAllRanges();
} else if (document.selection) {
document.selection.empty();
}
}
var tr = event.target;
while (this.tbodies.index(tr.parentNode) == -1) {
tr = tr.parentNode;
}
var index = tr.rowIndex;
if (typeof(index) === 'undefined') {
return;
}
if (this.options.selectionMode == "multiple" && event.shiftKey) {
changed = this.processSlectionWithShiftKey(index);
} else if ((event.ctrlKey || this.options.selectionMode == "multipleKeyboardFree") && this.ranges.contains(index)) {
this.deselectRow(index, true);
changed = true;
} else if (this.options.selectionMode == "single" || (this.options.selectionMode == "multiple" && !event.ctrlKey)) {
changed = this.selectRows(index, true);
} else {
this.selectRow(index, true);
changed = true;
}
this.onselectionchange(event, index, changed);
},
selectionKeyDownListener: function(event) {
if (event.ctrlKey && this.options.selectionMode != "single" && (event.keyCode == 65 || event.keyCode == 97) //Ctrl-A
&& this.onbeforeselectionchange(event)) {
this.selectRows([0, this.rows], true);
this.selectionFlag = "a";
this.onselectionchange(event, this.activeIndex, true); //TODO Is there a way to know that selection haven't changed?
event.preventDefault();
} else {
var index;
if (event.keyCode == 38) { //UP
index = -1;
} else if (event.keyCode == 40) { //DOWN
index = 1;
}
if (index != null && this.onbeforeselectionchange(event)) {
if (typeof this.activeIndex == "number") {
index += this.activeIndex;
if (index >= 0 && index < this.rows) {
var changed;
if (this.options.selectionMode == "single" || (!event.shiftKey && !event.ctrlKey)) {
changed = this.selectRows(index, true);
} else if (event.shiftKey) {
changed = this.processSlectionWithShiftKey(index);
}
this.onselectionchange(event, index, changed);
}
}
event.preventDefault();
}
}
},
ajaxComplete: function (event, data) {
this.storeDomReferences();
var colStateInput = document.getElementById(this.id + ":cols"),
i = colStateInput.value.length;
while (i--) {
if (colStateInput.value[i] == "x") {
this.__hideColumn(i);
}
};
if (data.reinitializeHeader) {
this.bindHeaderHandlers();
this.updateLayout();
} else {
this.selectionInput = document.getElementById(this.id + ":si");
if (data.reinitializeBody) {
this.rowCount = data.rowCount;
this.initialize();
} else if (this.options.selectionMode != "none") {
this.initializeSelection();
}
if (this.spacerElement) {
this.spacerElement.style.height = (data.first * this.rowHeight) + "px";
}
}
// resize columns if necessary
var $table = $(document.getElementById(this.element.id)),
widthsArray = new Array();
for (var id in this.newWidths) {
if (this.newWidths.hasOwnProperty(id)) {
$table.find("." + WIDTH_CLASS_NAME_BASE + id).css('width', this.newWidths[id])
.parent().css('width', this.newWidths[id]);
widthsArray.push(id + ":" + this.newWidths[id]);
}
}
this.widthInput.value = widthsArray.toString();
this.updateLayout();
this.adjustResizers();
},
activateResizeListener: function() {
if (typeof this.resizeEventName !== "undefined") {
$(window).on(this.resizeEventName, $.proxy(this.updateLayout, this));
}
},
deActivateResizeListener: function() {
if (typeof this.resizeEventName !== "undefined") {
$(window).off(this.resizeEventName);
}
},
__getMenuSelector: function (menu) {
var selector = "[id='" + this.element.id + "'] ";
selector += (typeof menu.options.targetSelector === 'undefined')
? ".rf-edt-b td" : menu.options.targetSelector;
selector = $.trim(selector);
return selector;
},
contextMenuAttach: function (menu) {
var selector = this.__getMenuSelector(menu);
rf.Event.bind(selector, menu.options.showEvent, $.proxy(menu.__showHandler, menu), menu);
},
contextMenuDetach: function (menu) {
var selector = this.__getMenuSelector(menu);
rf.Event.unbind(selector, menu.options.showEvent);
},
contextMenuShow: function (menu, event) {
var tr = event.target;
while (this.tbodies.index(tr.parentNode) == -1) {
tr = tr.parentNode;
}
var index = tr.rowIndex;
if (! this.ranges.contains(index) ) {
this.selectionClickListener(event);
}
},
__addColumnControl: function () {
var button = $(''),
controlId = this.id + ":colctrl",
controlPopup = $('');
var tableHeader = $(this.element).find(".rf-edt-tbl-hdr");
tableHeader.append(button);
$(this.element).append(controlPopup);
var popupOptions = {
jointPoint: "RT",
positionOffset: [8,8],
visible: true,
type: "DROPDOWN",
attachToBody: true
};
this.columnControl = new RichFaces.ui.Popup(controlId, popupOptions);
this.columnControl.hide();
button.on("click", $.proxy(function(event) {
this.columnControl.visible ? this.columnControl.hide() : this.columnControl.show(event);
}, this));
var columns = $(),
column,
columnNames = this.__getColumnNames(),
patterns = {
tdClass: /rf-edt-td-\w+/,
cellClass: /rf-edt-c-\w+/,
id: /[^:]+$/
},
currSelector;
if (this.tbodies) {
this.tbodies.each(function() {
columns = columns.add($(this).children(':eq(0)').children())}
);
} else {
columns = this.headerCells.parent();
if (!columns.length) {
columns = this.footerCells.parent();
}
if (!columns.length) {
return;
}
}
this.selectors = [];
for (var i = 0; i < columns.length; i++) {
column = columns.eq(i);
currSelector = column.attr('class');
if (currSelector && currSelector.match(patterns.tdClass)) {
currSelector = '.' + currSelector.match(patterns.tdClass)[0];
} else {
currSelector = 'td:has(> .' + column.children(':eq(0)').attr('class').match(patterns.cellClass)[0] + ')';
}
this.selectors.push({
selector: currSelector,
name: column.data(DATA_ATTRIBUTE) || columnNames[i] || "#" + column.attr('id').match(patterns.id)[0]
});
}
var colStateInput = document.getElementById(this.id + ":cols"),
table = this,
$input, $label, newValue = "";
this.selectors.forEach(function(item, index) {
$input = $('');
$input.prop('checked', (!colStateInput.value || colStateInput.value[index] == 'o'));
$input.attr('onchange', "RichFaces.component('" + table.id + "').__toggleColumn('" + index + "'); RichFaces.component('" + table.id + "').updateLayout();");
$label = $('');
newValue += colStateInput.value ? colStateInput.value[index] : 'o';
controlPopup.append($label.prepend($input), $('
'));
if (newValue[newValue.length - 1] == 'x') {
table.__hideColumn(index);
}
});
colStateInput.value = newValue;
},
__getColumnNames: function () {
var names = [];
this.headerCells.each(function() {
names.push(this.children[0].textContent);
});
if (names.length) {
return names;
}
this.footerCells.each(function() {
names.push(this.children[0].textContent);
});
return names;
},
__toggleColumn: function(index) {
$(this.selectors[index].selector).toggle();
var colStateInput = document.getElementById(this.id + ":cols"),
colState = colStateInput.value;
colStateInput.value = colState.substr(0, index) + (colState[index] == "o" ? "x" : "o") + colState.substr(++index);
},
__hideColumn: function(index) {
$(this.selectors[index].selector).hide();
}
});
var $super = rf.ui.ExtendedDataTable.$super;
}(RichFaces.jQuery, window.RichFaces));
© 2015 - 2025 Weber Informatics LLC | Privacy Policy