1b575bde4b3405bb538b2c58ac1f1c6c66ca6694
[nit.git] / share / nitdoc / scripts / js-facilities.js
1 /*
2 * JQuery Case Insensitive :icontains selector
3 */
4 $.expr[':'].icontains = function(obj, index, meta, stack){
5 return (obj.textContent.replace(/\[[0-9]+\]/g, "") || obj.innerText.replace(/\[[0-9]+\]/g, "") || jQuery(obj).text().replace(/\[[0-9]+\]/g, "") || '').toLowerCase().indexOf(meta[3].toLowerCase()) >= 0;
6 };
7
8 /*
9 * Quick Search global vars
10 */
11
12 // Current search results preview table
13 var currentTable = null;
14
15 //Hightlighted index in search result preview table
16 var currentIndex = -1;
17
18 /*
19 * Add folding and filtering facilities to class description page.
20 */
21 $(document).ready(function() {
22
23 /*
24 * Highlight the spoted element
25 */
26 highlightBlock(currentAnchor());
27
28 /*
29 * Nav block folding
30 */
31
32 // Menu nav folding
33 $(".menu nav h3")
34 .prepend(
35 $(document.createElement("a"))
36 .html("-")
37 .addClass("fold")
38 )
39 .css("cursor", "pointer")
40 .click( function() {
41 if($(this).find("a.fold").html() == "+") {
42 $(this).find("a.fold").html("-");
43 } else {
44 $(this).find("a.fold").html("+");
45 }
46 $(this).nextAll().toggle();
47 })
48
49 // Insert search field
50 $("nav.main ul")
51 .append(
52 $(document.createElement("li"))
53 .append(
54 $(document.createElement("form"))
55 .append(
56 $(document.createElement("input"))
57 .attr({
58 id: "search",
59 type: "text",
60 autocomplete: "off",
61 value: "quick search..."
62 })
63 .addClass("notUsed")
64
65 // Key management
66 .keyup(function(e) {
67 switch(e.keyCode) {
68
69 // Select previous result on "Up"
70 case 38:
71 // If already on first result, focus search input
72 if(currentIndex == 0) {
73 $("#search").val($(currentTable.find("tr")[currentIndex]).data("searchDetails").name);
74 $("#search").focus();
75 // Else select previous result
76 } else if(currentIndex > 0) {
77 $(currentTable.find("tr")[currentIndex]).removeClass("activeSearchResult");
78 currentIndex--;
79 $(currentTable.find("tr")[currentIndex]).addClass("activeSearchResult");
80 $("#search").val($(currentTable.find("tr")[currentIndex]).data("searchDetails").name);
81 $("#search").focus();
82 }
83 break;
84
85 // Select next result on "Down"
86 case 40:
87 if(currentIndex < currentTable.find("tr").length - 1) {
88 $(currentTable.find("tr")[currentIndex]).removeClass("activeSearchResult");
89 currentIndex++;
90 $(currentTable.find("tr")[currentIndex]).addClass("activeSearchResult");
91 $("#search").val($(currentTable.find("tr")[currentIndex]).data("searchDetails").name);
92 $("#search").focus();
93 }
94 break;
95 // Go to url on "Enter"
96 case 13:
97 if(currentIndex > -1) {
98 window.location = $(currentTable.find("tr")[currentIndex]).data("searchDetails").url;
99 return false;
100 }
101 if($("#search").val().length == 0)
102 return false
103
104 window.location = "full-index.html#q=" + $("#search").val();
105 if(window.location.href.indexOf("full-index.html") > -1) {
106 location.reload();
107 }
108 return false;
109 break;
110
111 // Hide results preview on "Escape"
112 case 27:
113 $(this).blur();
114 if(currentTable != null) {
115 currentTable.remove();
116 currentTable = null;
117 }
118 break;
119
120 default:
121 if($("#search").val().length == 0) {
122 return false;
123 }
124
125 // Remove previous table
126 if(currentTable != null) {
127 currentTable.remove();
128 }
129
130 // Build results table
131 currentIndex = -1;
132 currentTable = $(document.createElement("table"));
133
134 // Escape regexp related characters in query
135 var query = $("#search").val();
136 query = query.replace(/\\/gi, "\\\\");
137 query = query.replace(/\[/gi, "\\[");
138 query = query.replace(/\|/gi, "\\|");
139 query = query.replace(/\*/gi, "\\*");
140 query = query.replace(/\+/gi, "\\+");
141 query = query.replace(/\?/gi, "\\?");
142 query = query.replace(/\(/gi, "\\(");
143 query = query.replace(/\)/gi, "\\)");
144 query = query.replace(/&/gi, "&&");
145 query = query.replace(/>/gi, "&gt;");
146 query = query.replace(/</gi, "&lt;");
147
148 var index = 0;
149 var regexp = new RegExp("^" + query, "i");
150 for(var entry in entries) {
151 if(index > 10) {
152 break;
153 }
154 var result = entry.match(regexp);
155 if(result != null) {
156 for(var i = 0; i < entries[entry].length; i++) {
157 if(index > 10) {
158 break;
159 }
160 currentTable.append(
161 $(document.createElement("tr"))
162 .data("searchDetails", {name: entry, url: entries[entry][i]["url"]})
163 .data("index", index)
164 .append($(document.createElement("td")).html(entry))
165 .append(
166 $(document.createElement("td"))
167 .addClass("entryInfo")
168 .html(entries[entry][i]["txt"] + "&nbsp;&raquo;"))
169 .mouseover( function() {
170 $(currentTable.find("tr")[currentIndex]).removeClass("activeSearchResult");
171 $(this).addClass("activeSearchResult");
172 currentIndex = $(this).data("index");
173 })
174 .mouseout( function() {
175 $(this).removeClass("activeSearchResult");
176 })
177 .click( function() {
178 window.location = $(this).data("searchDetails")["url"];
179 })
180 );
181 index++;
182 }
183 }
184 }
185
186 // Initialize table properties
187 currentTable.attr("id", "searchTable");
188 currentTable.css("position", "absolute");
189 currentTable.width($("#search").outerWidth());
190 $("header").append(currentTable);
191 currentTable.offset({left: $("#search").offset().left + ($("#search").outerWidth() - currentTable.outerWidth()), top: $("#search").offset().top + $("#search").outerHeight()});
192
193 // Preselect first entry
194 if(currentTable.find("tr").length > 0) {
195 currentIndex = 0;
196 $(currentTable.find("tr")[currentIndex]).addClass("activeSearchResult");
197 $("#search").focus();
198 }
199 break;
200 }
201 })
202 .focusout(function() {
203 if($(this).val() == "") {
204 $(this).addClass("notUsed");
205 $(this).val("quick search...");
206 }
207 })
208 .focusin(function() {
209 if($(this).val() == "quick search...") {
210 $(this).removeClass("notUsed");
211 $(this).val("");
212 }
213 })
214 )
215 .submit( function() {
216 return false;
217 })
218 )
219 );
220
221 // Close quicksearch list on click
222 $(document).click(function(e) {
223 if(e.target != $("#search")[0] && e.target != $("#searchTable")[0]) {
224 if(currentTable != null) {
225 currentTable.remove();
226 currentTable = null;
227 }
228 }
229 });
230
231 // Insert filter field
232 $("article.filterable h2, nav.filterable h3")
233 .after(
234 $(document.createElement("div"))
235 .addClass("filter")
236 .append(
237 $(document.createElement("input"))
238 .attr({
239 type: "text",
240 value: "filter..."
241 })
242 .addClass("notUsed")
243 .keyup(function() {
244 $(this).parent().parent().find("ul li:not(:icontains('" + $(this).val() + "'))").addClass("hide");
245 $(this).parent().parent().find("ul li:icontains('" + $(this).val() + "')").removeClass("hide");
246 })
247 .focusout(function() {
248 if($(this).val() == "") {
249 $(this).addClass("notUsed");
250 $(this).val("filter...");
251 }
252 })
253 .focusin(function() {
254 if($(this).val() == "filter...") {
255 $(this).removeClass("notUsed");
256 $(this).val("");
257 }
258 })
259 )
260 );
261
262 // Filter toggle between H I R in nav porperties list
263 $("nav.properties.filterable .filter")
264 .append(
265 $(document.createElement("a"))
266 .html("H")
267 .attr({
268 title: "hide inherited properties"
269 })
270 .click( function() {
271 if($(this).hasClass("hidden")) {
272 $(this).parent().parent().find("li.inherit").show();
273 } else {
274 $(this).parent().parent().find("li.inherit").hide();
275 }
276
277 $(this).toggleClass("hidden");
278 })
279 )
280 .append(
281 $(document.createElement("a"))
282 .html("R")
283 .attr({
284 title: "hide redefined properties"
285 })
286 .click( function() {
287 if($(this).hasClass("hidden")) {
288 $(this).parent().parent().find("li.redef").show();
289 } else {
290 $(this).parent().parent().find("li.redef").hide();
291 }
292
293 $(this).toggleClass("hidden");
294 })
295 )
296 .append(
297 $(document.createElement("a"))
298 .html("I")
299 .attr({
300 title: "hide introduced properties"
301 })
302 .click( function() {
303 if($(this).hasClass("hidden")) {
304 $(this).parent().parent().find("li.intro").show();
305 } else {
306 $(this).parent().parent().find("li.intro").hide();
307 }
308
309 $(this).toggleClass("hidden");
310 })
311 );
312
313 // Filter toggle between I R in
314 $("article.properties.filterable .filter, article.classes.filterable .filter")
315 .append(
316 $(document.createElement("a"))
317 .html("I")
318 .attr({
319 title: "hide introduced properties"
320 })
321 .click( function() {
322 if($(this).hasClass("hidden")) {
323 $(this).parent().parent().find("li.intro").show();
324 } else {
325 $(this).parent().parent().find("li.intro").hide();
326 }
327
328 $(this).toggleClass("hidden");
329 })
330 )
331 .append(
332 $(document.createElement("a"))
333 .html("R")
334 .attr({
335 title: "hide redefined properties"
336 })
337 .click( function() {
338 if($(this).hasClass("hidden")) {
339 $(this).parent().parent().find("li.redef").show();
340 } else {
341 $(this).parent().parent().find("li.redef").hide();
342 }
343
344 $(this).toggleClass("hidden");
345 })
346 );
347
348 /*
349 * Anchors jumps
350 */
351 $("a[href*='#']").click( function() {
352 highlightBlock($(this).attr("href").split(/#/)[1]);
353 });
354
355 //Preload filter fields with query string
356 preloadFilters();
357 });
358
359 /* Parse current URL and return anchor name */
360 function currentAnchor() {
361 var index = document.location.hash.indexOf("#");
362 if (index >= 0) {
363 return document.location.hash.substring(index + 1);
364 }
365 return null;
366 }
367
368 /* Prealod filters field using search query */
369 function preloadFilters() {
370 // Parse URL and get query string
371 var search = currentAnchor();
372
373 if(search == null || search.indexOf("q=") == -1)
374 return;
375
376 search = search.substring(2, search.length);
377
378 if(search == "" || search == "undefined")
379 return;
380
381 $(":text").val(search);
382 $(".filter :text")
383 .removeClass("notUsed")
384 .trigger("keyup");
385
386 }
387
388 /* Hightlight the spoted block */
389 function highlightBlock(a) {
390 if(a == undefined) {
391 return;
392 }
393
394 $(".highlighted").removeClass("highlighted");
395
396 var target = $("#" + a);
397
398 if(target.is("article")) {
399 target.parent().addClass("highlighted");
400 }
401
402 target.addClass("highlighted");
403 target.show();
404 }