root/trunk/selectable_table.js

Revision 265, 6.3 kB (checked in by henrylyne, 14 months ago)

Handle case where event is not defined.

Line 
1/*
2  This is a datasource you can attach to a table. It will enable
3  the selection of rows or cells in the table.
4
5  The data in the datasource is elements that are selected.
6
7  $id:$
8*/
9
10SelectableTable = new Class(DataSource, {
11
12    // options:
13    //   table: what table element to attach to
14    //   selectableClass: if you only want elements with a certain class to be selectable,
15    //       specifiy this class with selectableClass
16    //   multiple: can more than one thing be selected at once? default is true
17    //   selectedClass: class to apply to selected elements
18    //   checkboxClass: since there are frequently checkboxes associated with selectable elements,
19    //       you can specify the class of your checkboxes to make them stay in sync
20    //   selectableItem: What type of elements can be selected. Values are "cell" or "row"
21    init: function (opts) {
22        SelectableTable.superClass.init.apply(this, []);
23
24        var table = opts.table;
25        var selectableClass = opts.selectableClass;
26        var multiple = opts.multiple;
27        var selectedClass = opts.selectedClass
28        var checkboxClass = opts.checkboxClass
29        var selectableItem = opts.selectableItem;
30
31        selectableItem = selectableItem == "cell" ? "cell" : "row";
32
33        if (!defined(multiple)) multiple = true;
34
35        this.table = table;
36        this.selectableClass = selectableClass;
37        this.multiple = multiple;
38        this.selectedClass = opts.selectedClass;
39        this.checkboxClass = opts.checkboxClass;
40
41        this.selectedElements = [];
42
43        // if it's not a table, die
44        if (!table || !table.tagName || table.tagName.toLowerCase() != "table") return null;
45
46        // get selectable items
47        var tableElements = table.getElementsByTagName("*");
48
49        var selectableElements;
50
51        if (selectableItem == "cell") {
52            selectableElements = DOM.filterElementsByTagName(tableElements, "td");
53        } else {
54            selectableElements = DOM.filterElementsByTagName(tableElements, "tr");
55        }
56
57        var self = this;
58        selectableElements.forEach(function(ele) {
59            // if selectableClass is defined and this element doesn't have the class, skip it
60            if (selectableClass && !DOM.hasClassName(ele, selectableClass)) return;
61
62            // attach click handler to every element inside the element
63            var itemElements = ele.getElementsByTagName("*");
64            for (var i = 0; i < itemElements.length; i++) {
65                self.attachClickHandler(itemElements[i], ele);
66            }
67
68            // attach click handler to the element itself
69            self.attachClickHandler(ele, ele);
70        });
71    },
72
73    // stop our handling of this event
74    stopHandlingEvent: function (evt) {
75        if (!evt) return;
76
77        // w3c
78        if (evt.stopPropagation)
79        evt.stopPropagation();
80
81        // ie
82        try {
83            event.cancelBubble = true;
84        } catch(e) {}
85    },
86
87    // attach a click handler to this element
88    attachClickHandler: function (ele, parent) {
89        if (!ele) return;
90
91        var self = this;
92
93        var rowClicked = function (evt) {
94            // if it was a control-click, they're probably trying to open a new tab or something.
95            // let's not handle it
96            if (evt && evt.ctrlKey) return false;
97
98            var tagName = ele.tagName.toLowerCase();
99
100            // if this is a link or has an onclick handler,
101            // return true and tell other events to return true
102            if ((ele.href && tagName != "img") || ele.onclick) {
103                self.stopHandlingEvent(evt);
104                return true;
105            }
106
107            // if this is the child of a link, propagate the event up
108            var ancestors = DOM.getAncestors(ele, true);
109            for (var i = 0; i < ancestors.length; i++) {
110                var ancestor = ancestors[i];
111                if (ancestor.href && ancestor.tagName.toLowerCase() != "img") {
112                    return true;
113                }
114            }
115
116            // if this is an input or select element, skip it
117            if ((tagName == "select" || tagName == "input") && parent.checkbox != ele) {
118                self.stopHandlingEvent(evt);
119                return true;
120            }
121
122            // toggle selection of this parent element
123            if (self.selectedElements.indexOf(parent) != -1) {
124                if (self.selectedClass) DOM.removeClassName(parent, self.selectedClass);
125
126                self.selectedElements.remove(parent);
127            } else {
128                if (self.selectedClass) DOM.addClassName(parent, self.selectedClass);
129
130                if (self.multiple) {
131                    self.selectedElements.push(parent);
132                } else {
133                    if (self.selectedClass && self.selectedElements.length > 0) {
134                        var oldParent = self.selectedElements[0];
135                        if (oldParent) {
136                            DOM.removeClassName(oldParent, self.selectedClass);
137                            if (oldParent.checkbox) oldParent.checkbox.checked = "";
138                        }
139                    }
140
141                    self.selectedElements = [parent];
142                }
143            }
144
145            // update our data
146            self.setData(self.selectedElements);
147
148            // if there's a checkbox associated with this parent, set it's value
149            // to the parent selected value
150            if (parent.checkbox) parent.checkbox.checked = (self.selectedElements.indexOf(parent) != -1) ? "on" : '';
151            if (parent.checkbox == ele) { self.stopHandlingEvent(evt); return true; }
152
153            // always? not sure
154            if (evt)
155                Event.stop(evt);
156        }
157
158        // if this is a checkbox we need to keep in sync, set up its event handler
159        if (this.checkboxClass && ele.tagName.toLowerCase() == "input"
160            && ele.type == "checkbox" && DOM.hasClassName(ele, this.checkboxClass)) {
161
162            parent.checkbox = ele;
163
164            // override default event handler for the checkbox
165            DOM.addEventListener(ele, "click", function (evt) {
166                return true;
167            });
168        }
169
170        // attach a method to the row so other people can programatically
171        // select it.
172        ele.rowClicked = rowClicked;
173
174        DOM.addEventListener(ele, "click", rowClicked);
175    }
176
177});
Note: See TracBrowser for help on using the browser.