39
|
1 function initializeFilters() {
|
|
2
|
|
3 // Bail early for Konqueror and IE5.2/Mac, which don't fully support dynamic
|
|
4 // creation of form controls
|
|
5 try {
|
|
6 var test = document.createElement("input");
|
|
7 test.type = "button";
|
|
8 if (test.type != "button") throw Error();
|
|
9 } catch (e) {
|
|
10 return;
|
|
11 }
|
|
12
|
|
13 // Removes an existing row from the filters table
|
|
14 function removeRow(button, propertyName) {
|
|
15 var tr = getAncestorByTagName(button, "tr");
|
|
16
|
|
17 var mode = null;
|
|
18 var selects = tr.getElementsByTagName("select");
|
|
19 for (var i = 0; i < selects.length; i++) {
|
|
20 if (selects[i].name == propertyName + "_mode") {
|
|
21 mode = selects[i];
|
|
22 break;
|
|
23 }
|
|
24 }
|
|
25 if (mode && (getAncestorByTagName(mode, "tr") == tr)) {
|
|
26 // Check whether there are more 'or' rows for this filter
|
|
27 var next = tr.nextSibling;
|
|
28 if (next && (next.className == propertyName)) {
|
|
29 function getChildElementAt(e, idx) {
|
|
30 e = e.firstChild;
|
|
31 var cur = 0;
|
|
32 while (cur <= idx) {
|
|
33 while (e && e.nodeType != 1) e = e.nextSibling;
|
|
34 if (cur++ == idx) break;
|
|
35 e = e.nextSibling;
|
|
36 }
|
|
37 return e;
|
|
38 }
|
|
39
|
|
40 var thisTh = getChildElementAt(tr, 0);
|
|
41 var nextTh = getChildElementAt(next, 0);
|
|
42 next.insertBefore(thisTh, nextTh);
|
|
43 nextTh.colSpan = 1;
|
|
44
|
|
45 thisTd = getChildElementAt(tr, 0);
|
|
46 nextTd = getChildElementAt(next, 1);
|
|
47 next.replaceChild(thisTd, nextTd);
|
|
48 }
|
|
49 }
|
|
50
|
|
51 var tBody = tr.parentNode;
|
|
52 tBody.deleteRow(tr.sectionRowIndex);
|
|
53 if (!tBody.rows.length) {
|
|
54 tBody.parentNode.removeChild(tBody);
|
|
55 }
|
|
56
|
|
57 if (propertyName) {
|
|
58 var select = document.forms["query"].elements["add_filter"];
|
|
59 for (var i = 0; i < select.options.length; i++) {
|
|
60 var option = select.options[i];
|
|
61 if (option.value == propertyName) option.disabled = false;
|
|
62 }
|
|
63 }
|
|
64 }
|
|
65
|
|
66 // Initializes a filter row, the 'input' parameter is the submit
|
|
67 // button for removing the filter
|
|
68 function initializeFilter(input) {
|
|
69 var removeButton = document.createElement("input");
|
|
70 removeButton.type = "button";
|
|
71 removeButton.value = input.value;
|
|
72 if (input.name.substr(0, 10) == "rm_filter_") {
|
|
73 removeButton.onclick = function() {
|
|
74 var endIndex = input.name.search(/_\d+$/);
|
|
75 if (endIndex < 0) endIndex = input.name.length;
|
|
76 removeRow(removeButton, input.name.substring(10, endIndex));
|
|
77 return false;
|
|
78 }
|
|
79 } else {
|
|
80 removeButton.onclick = function() {
|
|
81 removeRow(removeButton);
|
|
82 return false;
|
|
83 }
|
|
84 }
|
|
85 input.parentNode.replaceChild(removeButton, input);
|
|
86 }
|
|
87
|
|
88 // Make the submit buttons for removing filters client-side triggers
|
|
89 var filters = document.getElementById("filters");
|
|
90 var inputs = filters.getElementsByTagName("input");
|
|
91 for (var i = 0; i < inputs.length; i++) {
|
|
92 var input = inputs[i];
|
|
93 if (input.type == "submit" && input.name
|
|
94 && input.name.match(/^rm_filter_/)) {
|
|
95 initializeFilter(input);
|
|
96 }
|
|
97 }
|
|
98
|
|
99 // Make the drop-down menu for adding a filter a client-side trigger
|
|
100 var addButton = document.forms["query"].elements["add"];
|
|
101 addButton.parentNode.removeChild(addButton);
|
|
102 var select = document.getElementById("add_filter");
|
|
103 select.onchange = function() {
|
|
104 if (select.selectedIndex < 1) return;
|
|
105
|
|
106 if (select.options[select.selectedIndex].disabled) {
|
|
107 // Neither IE nor Safari supported disabled options at the time this was
|
|
108 // written, so alert the user
|
|
109 alert("A filter already exists for that property");
|
|
110 return;
|
|
111 }
|
|
112
|
|
113 // Convenience function for creating a <label>
|
|
114 function createLabel(text, htmlFor) {
|
|
115 var label = document.createElement("label");
|
|
116 if (text) label.appendChild(document.createTextNode(text));
|
|
117 if (htmlFor) label.htmlFor = htmlFor;
|
|
118 return label;
|
|
119 }
|
|
120
|
|
121 // Convenience function for creating an <input type="checkbox">
|
|
122 function createCheckbox(name, value, id) {
|
|
123 var input = document.createElement("input");
|
|
124 input.type = "checkbox";
|
|
125 if (name) input.name = name;
|
|
126 if (value) input.value = value;
|
|
127 if (id) input.id = id;
|
|
128 return input;
|
|
129 }
|
|
130
|
|
131 // Convenience function for creating an <input type="radio">
|
|
132 function createRadio(name, value, id) {
|
|
133 var input = document.createElement("input");
|
|
134 input.type = "radio";
|
|
135 if (name) input.name = name;
|
|
136 if (value) input.value = value;
|
|
137 if (id) input.id = id;
|
|
138 return input;
|
|
139 }
|
|
140
|
|
141 // Convenience function for creating a <select>
|
|
142 function createSelect(name, options, optional) {
|
|
143 var e = document.createElement("select");
|
|
144 if (name) e.name = name;
|
|
145 if (optional) e.options[0] = new Option();
|
|
146 if (options) {
|
|
147 for (var i = 0; i < options.length; i++) {
|
|
148 var option;
|
|
149 if (typeof(options[i]) == "object") {
|
|
150 option = new Option(options[i].text, options[i].value);
|
|
151 } else {
|
|
152 option = new Option(options[i], options[i]);
|
|
153 }
|
|
154 e.options[e.options.length] = option;
|
|
155 }
|
|
156 }
|
|
157 return e;
|
|
158 }
|
|
159
|
|
160 var propertyName = select.options[select.selectedIndex].value;
|
|
161 var property = properties[propertyName];
|
|
162 var table = document.getElementById("filters").getElementsByTagName("table")[0];
|
|
163 var tr = document.createElement("tr");
|
|
164 tr.className = propertyName;
|
|
165
|
|
166 var alreadyPresent = false;
|
|
167 for (var i = 0; i < table.rows.length; i++) {
|
|
168 if (table.rows[i].className == propertyName) {
|
|
169 var existingTBody = table.rows[i].parentNode;
|
|
170 alreadyPresent = true;
|
|
171 break;
|
|
172 }
|
|
173 }
|
|
174
|
|
175 // Add the row header
|
|
176 var th = document.createElement("th");
|
|
177 th.scope = "row";
|
|
178 if (!alreadyPresent) {
|
|
179 th.appendChild(createLabel(property.label));
|
|
180 } else {
|
|
181 th.colSpan = 2;
|
|
182 th.appendChild(createLabel("or"));
|
|
183 }
|
|
184 tr.appendChild(th);
|
|
185
|
|
186 var td = document.createElement("td");
|
|
187 if (property.type == "radio" || property.type == "checkbox") {
|
|
188 td.colSpan = 2;
|
|
189 td.className = "filter";
|
|
190 if (property.type == "radio") {
|
|
191 for (var i = 0; i < property.options.length; i++) {
|
|
192 var option = property.options[i];
|
|
193 td.appendChild(createCheckbox(propertyName, option,
|
|
194 propertyName + "_" + option));
|
|
195 td.appendChild(document.createTextNode(" "));
|
|
196 td.appendChild(createLabel(option ? option : "none",
|
|
197 propertyName + "_" + option));
|
|
198 }
|
|
199 } else {
|
|
200 td.appendChild(createRadio(propertyName, "1", propertyName + "_on"));
|
|
201 td.appendChild(document.createTextNode(" "));
|
|
202 td.appendChild(createLabel("yes", propertyName + "_on"));
|
|
203 td.appendChild(createRadio(propertyName, "!1", propertyName + "_off"));
|
|
204 td.appendChild(document.createTextNode(" "));
|
|
205 td.appendChild(createLabel("no", propertyName + "_off"));
|
|
206 }
|
|
207 tr.appendChild(td);
|
|
208 } else {
|
|
209 if (!alreadyPresent) {
|
|
210 // Add the mode selector
|
|
211 td.className = "mode";
|
|
212 var modeSelect = createSelect(propertyName + "_mode",
|
|
213 modes[property.type]);
|
|
214 td.appendChild(modeSelect);
|
|
215 tr.appendChild(td);
|
|
216 }
|
|
217
|
|
218 // Add the selector or text input for the actual filter value
|
|
219 td = document.createElement("td");
|
|
220 td.className = "filter";
|
|
221 if (property.type == "select") {
|
|
222 var element = createSelect(propertyName, property.options, true);
|
|
223 } else if (property.type == "text") {
|
|
224 var element = document.createElement("input");
|
|
225 element.type = "text";
|
|
226 element.name = propertyName;
|
|
227 element.size = 42;
|
|
228 }
|
|
229 td.appendChild(element);
|
|
230 element.focus();
|
|
231 tr.appendChild(td);
|
|
232 }
|
|
233
|
|
234 // Add the add and remove buttons
|
|
235 td = document.createElement("td");
|
|
236 td.className = "actions";
|
|
237 var removeButton = document.createElement("input");
|
|
238 removeButton.type = "button";
|
|
239 removeButton.value = "-";
|
|
240 removeButton.onclick = function() { removeRow(removeButton, propertyName) };
|
|
241 td.appendChild(removeButton);
|
|
242 tr.appendChild(td);
|
|
243
|
|
244 if (alreadyPresent) {
|
|
245 existingTBody.appendChild(tr);
|
|
246 } else {
|
|
247 // Find the insertion point for the new row. We try to keep the filter rows
|
|
248 // in the same order as the options in the 'Add filter' drop-down, because
|
|
249 // that's the order they'll appear in when submitted.
|
|
250 var insertionPoint = getAncestorByTagName(select, "tbody");
|
|
251 outer: for (var i = select.selectedIndex + 1; i < select.options.length; i++) {
|
|
252 for (var j = 0; j < table.tBodies.length; j++) {
|
|
253 if (table.tBodies[j].rows[0].className == select.options[i].value) {
|
|
254 insertionPoint = table.tBodies[j];
|
|
255 break outer;
|
|
256 }
|
|
257 }
|
|
258 }
|
|
259 // Finally add the new row to the table
|
|
260 var tbody = document.createElement("tbody");
|
|
261 tbody.appendChild(tr);
|
|
262 insertionPoint.parentNode.insertBefore(tbody, insertionPoint);
|
|
263 }
|
|
264
|
|
265 // Disable the add filter in the drop-down list
|
|
266 if (property.type == "radio" || property.type == "checkbox") {
|
|
267 select.options[select.selectedIndex].disabled = true;
|
|
268 }
|
|
269 select.selectedIndex = 0;
|
|
270 }
|
|
271 }
|