mourningdove/htdocs/js/6alib/selectable_table.js

180 lines
6.4 KiB
JavaScript
Raw Normal View History

2026-05-24 01:03:05 +00:00
/*
This is a datasource you can attach to a table. It will enable
the selection of rows or cells in the table.
The data in the datasource is elements that are selected.
$id:$
*/
SelectableTable = new Class(DataSource, {
// options:
// table: what table element to attach to
// selectableClass: if you only want elements with a certain class to be selectable,
// specifiy this class with selectableClass
// multiple: can more than one thing be selected at once? default is true
// selectedClass: class to apply to selected elements
// checkboxClass: since there are frequently checkboxes associated with selectable elements,
// you can specify the class of your checkboxes to make them stay in sync
// selectableItem: What type of elements can be selected. Values are "cell" or "row"
init: function (opts) {
if ( SelectableTable.superClass.init )
SelectableTable.superClass.init.apply(this, []);
var table = opts.table;
var selectableClass = opts.selectableClass;
var multiple = opts.multiple;
var selectedClass = opts.selectedClass
var checkboxClass = opts.checkboxClass
var selectableItem = opts.selectableItem;
selectableItem = selectableItem == "cell" ? "cell" : "row";
if (!defined(multiple)) multiple = true;
this.table = table;
this.selectableClass = selectableClass;
this.multiple = multiple;
this.selectedClass = opts.selectedClass;
this.checkboxClass = opts.checkboxClass;
this.selectedElements = [];
// if it's not a table, die
if (!table || !table.tagName || table.tagName.toLowerCase() != "table") return null;
// get selectable items
var tableElements = table.getElementsByTagName("*");
var selectableElements;
if (selectableItem == "cell") {
selectableElements = DOM.filterElementsByTagName(tableElements, "td");
} else {
selectableElements = DOM.filterElementsByTagName(tableElements, "tr");
}
var self = this;
selectableElements.forEach(function(ele) {
// if selectableClass is defined and this element doesn't have the class, skip it
if (selectableClass && !DOM.hasClassName(ele, selectableClass)) return;
// attach click handler to every element inside the element
var itemElements = ele.getElementsByTagName("*");
for (var i = 0; i < itemElements.length; i++) {
self.attachClickHandler(itemElements[i], ele);
}
// attach click handler to the element itself
self.attachClickHandler(ele, ele);
});
},
// stop our handling of this event
stopHandlingEvent: function (evt) {
if (!evt) return;
// w3c
if (evt.stopPropagation)
evt.stopPropagation();
// ie
try {
event.cancelBubble = true;
} catch(e) {}
},
// attach a click handler to this element
attachClickHandler: function (ele, parent) {
if (!ele) return;
var self = this;
var rowClicked = function (evt) {
// if it was a control-click or a command-click
// they're probably trying to open a new tab or something.
// let's not handle it
if (evt && (evt.ctrlKey || evt.metaKey)) return false;
var tagName = ele.tagName.toLowerCase();
// if this is a link or has an onclick handler,
// return true and tell other events to return true
if ((ele.href && tagName != "img") || ele.onclick) {
self.stopHandlingEvent(evt);
return true;
}
// if this is the child of a link, propagate the event up
var ancestors = DOM.getAncestors(ele, true);
for (var i = 0; i < ancestors.length; i++) {
var ancestor = ancestors[i];
if (ancestor.href && ancestor.tagName.toLowerCase() != "img") {
return true;
}
}
// if this is an input or select element, skip it
if ((tagName == "select" || tagName == "input") && parent.checkbox != ele) {
self.stopHandlingEvent(evt);
return true;
}
// toggle selection of this parent element
if (self.selectedElements.indexOf(parent) != -1) {
if (self.selectedClass) DOM.removeClassName(parent, self.selectedClass);
self.selectedElements.remove(parent);
} else {
if (self.selectedClass) DOM.addClassName(parent, self.selectedClass);
if (self.multiple) {
self.selectedElements.push(parent);
} else {
if (self.selectedClass && self.selectedElements.length > 0) {
var oldParent = self.selectedElements[0];
if (oldParent) {
DOM.removeClassName(oldParent, self.selectedClass);
if (oldParent.checkbox) oldParent.checkbox.checked = "";
}
}
self.selectedElements = [parent];
}
}
// update our data
self.setData(self.selectedElements);
// if there's a checkbox associated with this parent, set it's value
// to the parent selected value
if (parent.checkbox) parent.checkbox.checked = (self.selectedElements.indexOf(parent) != -1) ? "on" : '';
if (parent.checkbox == ele) { self.stopHandlingEvent(evt); return true; }
// always? not sure
if (evt)
Event.stop(evt);
}
// if this is a checkbox we need to keep in sync, set up its event handler
if (this.checkboxClass && ele.tagName.toLowerCase() == "input"
&& ele.type == "checkbox" && DOM.hasClassName(ele, this.checkboxClass)) {
parent.checkbox = ele;
// override default event handler for the checkbox
DOM.addEventListener(ele, "click", function (evt) {
return true;
});
}
// attach a method to the row so other people can programatically
// select it.
ele.rowClicked = rowClicked;
DOM.addEventListener(ele, "click", rowClicked);
}
});