File: query.js

package info (click to toggle)
trac 0.10.3-1
  • links: PTS
  • area: main
  • in suites: etch-m68k
  • size: 2,692 kB
  • ctags: 2,972
  • sloc: python: 22,683; cs: 3,174; sh: 30; makefile: 10
file content (271 lines) | stat: -rw-r--r-- 9,321 bytes parent folder | download | duplicates (2)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
function initializeFilters() {

  // Bail early for Konqueror and IE5.2/Mac, which don't fully support dynamic
  // creation of form controls
  try {
    var test = document.createElement("input");
    test.type = "button";
    if (test.type != "button") throw Error();
  } catch (e) {
    return;
  }

  // Removes an existing row from the filters table
  function removeRow(button, propertyName) {
    var tr = getAncestorByTagName(button, "tr");

    var mode = null;
    var selects = tr.getElementsByTagName("select");
    for (var i = 0; i < selects.length; i++) {
      if (selects[i].name == propertyName + "_mode") {
        mode = selects[i];
        break;
      }
    }
    if (mode && (getAncestorByTagName(mode, "tr") == tr)) {
      // Check whether there are more 'or' rows for this filter
      var next = tr.nextSibling;
      if (next && (next.className == propertyName)) {
        function getChildElementAt(e, idx) {
          e = e.firstChild;
          var cur = 0;
          while (cur <= idx) {
            while (e && e.nodeType != 1) e = e.nextSibling;
            if (cur++ == idx) break;
            e = e.nextSibling;
          }
          return e;
        }

        var thisTh = getChildElementAt(tr, 0);
        var nextTh = getChildElementAt(next, 0);
        next.insertBefore(thisTh, nextTh);
        nextTh.colSpan = 1;

        thisTd = getChildElementAt(tr, 0);
        nextTd = getChildElementAt(next, 1);
        next.replaceChild(thisTd, nextTd);
      }
    }

    var tBody = tr.parentNode;
    tBody.deleteRow(tr.sectionRowIndex);
    if (!tBody.rows.length) {
        tBody.parentNode.removeChild(tBody);
    }
    
    if (propertyName) {
      var select = document.forms["query"].elements["add_filter"];
      for (var i = 0; i < select.options.length; i++) {
        var option = select.options[i];
        if (option.value == propertyName) option.disabled = false;
      }
    }
  }

  // Initializes a filter row, the 'input' parameter is the submit
  // button for removing the filter
  function initializeFilter(input) {
    var removeButton = document.createElement("input");
    removeButton.type = "button";
    removeButton.value = input.value;
    if (input.name.substr(0, 10) == "rm_filter_") {
      removeButton.onclick = function() {
        var endIndex = input.name.search(/_\d+$/);
        if (endIndex < 0) endIndex = input.name.length;
        removeRow(removeButton, input.name.substring(10, endIndex));
        return false;
      }
    } else {
      removeButton.onclick = function() {
        removeRow(removeButton);
        return false;
      }
    }
    input.parentNode.replaceChild(removeButton, input);
  }

  // Make the submit buttons for removing filters client-side triggers
  var filters = document.getElementById("filters");
  var inputs = filters.getElementsByTagName("input");
  for (var i = 0; i < inputs.length; i++) {
    var input = inputs[i];
    if (input.type == "submit" && input.name
     && input.name.match(/^rm_filter_/)) {
      initializeFilter(input);
    }
  }

  // Make the drop-down menu for adding a filter a client-side trigger
  var addButton = document.forms["query"].elements["add"];
  addButton.parentNode.removeChild(addButton);
  var select = document.getElementById("add_filter");
  select.onchange = function() {
    if (select.selectedIndex < 1) return;

    if (select.options[select.selectedIndex].disabled) {
      // Neither IE nor Safari supported disabled options at the time this was
      // written, so alert the user
      alert("A filter already exists for that property");
      return;
    }

    // Convenience function for creating a <label>
    function createLabel(text, htmlFor) {
      var label = document.createElement("label");
      if (text) label.appendChild(document.createTextNode(text));
      if (htmlFor) label.htmlFor = htmlFor;
      return label;
    }

    // Convenience function for creating an <input type="checkbox">
    function createCheckbox(name, value, id) {
      var input = document.createElement("input");
      input.type = "checkbox";
      if (name) input.name = name;
      if (value) input.value = value;
      if (id) input.id = id;
      return input;
    }

    // Convenience function for creating an <input type="radio">
    function createRadio(name, value, id) {
      var input = document.createElement("input");
      input.type = "radio";
      if (name) input.name = name;
      if (value) input.value = value;
      if (id) input.id = id;
      return input;
    }

    // Convenience function for creating a <select>
    function createSelect(name, options, optional) {
      var e = document.createElement("select");
      if (name) e.name = name;
      if (optional) e.options[0] = new Option();
      if (options) {
        for (var i = 0; i < options.length; i++) {
          var option;
          if (typeof(options[i]) == "object") {
            option = new Option(options[i].text, options[i].value);
          } else {
            option = new Option(options[i], options[i]);
          }
          e.options[e.options.length] = option;
        }
      }
      return e;
    }

    var propertyName = select.options[select.selectedIndex].value;
    var property = properties[propertyName];
    var table = document.getElementById("filters").getElementsByTagName("table")[0];
    var tr = document.createElement("tr");
    tr.className = propertyName;

    var alreadyPresent = false;
    for (var i = 0; i < table.rows.length; i++) {
      if (table.rows[i].className == propertyName) {
        var existingTBody = table.rows[i].parentNode;
        alreadyPresent = true;
        break;
      }
    }

    // Add the row header
    var th = document.createElement("th");
    th.scope = "row";
    if (!alreadyPresent) {
      th.appendChild(createLabel(property.label));
    } else {
      th.colSpan = 2;
      th.appendChild(createLabel("or"));
    }
    tr.appendChild(th);

    var td = document.createElement("td");
    if (property.type == "radio" || property.type == "checkbox") {
      td.colSpan = 2;
      td.className = "filter";
      if (property.type == "radio") {
        for (var i = 0; i < property.options.length; i++) {
          var option = property.options[i];
          td.appendChild(createCheckbox(propertyName, option,
            propertyName + "_" + option));
          td.appendChild(document.createTextNode(" "));
          td.appendChild(createLabel(option ? option : "none",
            propertyName + "_" + option));
        }
      } else {
        td.appendChild(createRadio(propertyName, "1", propertyName + "_on"));
        td.appendChild(document.createTextNode(" "));
        td.appendChild(createLabel("yes", propertyName + "_on"));
        td.appendChild(createRadio(propertyName, "!1", propertyName + "_off"));
        td.appendChild(document.createTextNode(" "));
        td.appendChild(createLabel("no", propertyName + "_off"));
      }
      tr.appendChild(td);
    } else {
      if (!alreadyPresent) {
        // Add the mode selector
        td.className = "mode";
        var modeSelect = createSelect(propertyName + "_mode",
                                      modes[property.type]);
        td.appendChild(modeSelect);
        tr.appendChild(td);
      }

      // Add the selector or text input for the actual filter value
      td = document.createElement("td");
      td.className = "filter";
      if (property.type == "select") {
        var element = createSelect(propertyName, property.options, true);
      } else if (property.type == "text") {
        var element = document.createElement("input");
        element.type = "text";
        element.name = propertyName;
        element.size = 42;
      }
      td.appendChild(element);
      element.focus();
      tr.appendChild(td);
    }

    // Add the add and remove buttons
    td = document.createElement("td");
    td.className = "actions";
    var removeButton = document.createElement("input");
    removeButton.type = "button";
    removeButton.value = "-";
    removeButton.onclick = function() { removeRow(removeButton, propertyName) };
    td.appendChild(removeButton);
    tr.appendChild(td);

    if (alreadyPresent) {
      existingTBody.appendChild(tr);
    } else {
      // Find the insertion point for the new row. We try to keep the filter rows
      // in the same order as the options in the 'Add filter' drop-down, because
      // that's the order they'll appear in when submitted.
      var insertionPoint = getAncestorByTagName(select, "tbody");
      outer: for (var i = select.selectedIndex + 1; i < select.options.length; i++) {
        for (var j = 0; j < table.tBodies.length; j++) {
          if (table.tBodies[j].rows[0].className == select.options[i].value) {
            insertionPoint = table.tBodies[j];
            break outer;
          }
        }
      }
      // Finally add the new row to the table
      var tbody = document.createElement("tbody");
      tbody.appendChild(tr);
      insertionPoint.parentNode.insertBefore(tbody, insertionPoint);
    }

    // Disable the add filter in the drop-down list
    if (property.type == "radio" || property.type == "checkbox") {
      select.options[select.selectedIndex].disabled = true;
    }
    select.selectedIndex = 0;
  }
}