1 | // © 2009â2010 EPFL/LAMP |
---|
2 | // code by Gilles Dubochet with contributions by Johannes Rudolph and "spiros" |
---|
3 | |
---|
4 | var topLevelTemplates = undefined; |
---|
5 | var topLevelPackages = undefined; |
---|
6 | |
---|
7 | var scheduler = undefined; |
---|
8 | |
---|
9 | var kindFilterState = undefined; |
---|
10 | var focusFilterState = undefined; |
---|
11 | |
---|
12 | var title = $(document).attr('title'); |
---|
13 | |
---|
14 | var lastHash = ""; |
---|
15 | |
---|
16 | $(document).ready(function() { |
---|
17 | $('body').layout({ west__size: '20%' }); |
---|
18 | $('#browser').layout({ |
---|
19 | center__paneSelector: ".ui-west-center" |
---|
20 | //,center__initClosed:true |
---|
21 | ,north__paneSelector: ".ui-west-north" |
---|
22 | }); |
---|
23 | $('iframe').bind("load", function(){ |
---|
24 | var subtitle = $(this).contents().find('title').text(); |
---|
25 | $(document).attr('title', (title ? title + " - " : "") + subtitle); |
---|
26 | |
---|
27 | setUrlFragmentFromFrameSrc(); |
---|
28 | }); |
---|
29 | |
---|
30 | // workaround for IE's iframe sizing lack of smartness |
---|
31 | if($.browser.msie) { |
---|
32 | function fixIFrame() { |
---|
33 | $('iframe').height($(window).height() ) |
---|
34 | } |
---|
35 | $('iframe').bind("load",fixIFrame) |
---|
36 | $('iframe').bind("resize",fixIFrame) |
---|
37 | } |
---|
38 | |
---|
39 | scheduler = new Scheduler(); |
---|
40 | scheduler.addLabel("init", 1); |
---|
41 | scheduler.addLabel("focus", 2); |
---|
42 | scheduler.addLabel("filter", 4); |
---|
43 | |
---|
44 | prepareEntityList(); |
---|
45 | |
---|
46 | configureTextFilter(); |
---|
47 | configureKindFilter(); |
---|
48 | configureEntityList(); |
---|
49 | |
---|
50 | setFrameSrcFromUrlFragment(); |
---|
51 | |
---|
52 | // If the url fragment changes, adjust the src of iframe "template". |
---|
53 | $(window).bind('hashchange', function() { |
---|
54 | if(lastFragment != window.location.hash) { |
---|
55 | lastFragment = window.location.hash; |
---|
56 | setFrameSrcFromUrlFragment(); |
---|
57 | } |
---|
58 | }); |
---|
59 | }); |
---|
60 | |
---|
61 | // Set the iframe's src according to the fragment of the current url. |
---|
62 | // fragment = "#scala.Either" => iframe url = "scala/Either.html" |
---|
63 | // fragment = "#scala.Either@isRight:Boolean" => iframe url = "scala/Either.html#isRight:Boolean" |
---|
64 | function setFrameSrcFromUrlFragment() { |
---|
65 | var fragment = location.hash.slice(1); |
---|
66 | if(fragment) { |
---|
67 | var loc = fragment.split("@")[0].replace(/\./g, "/"); |
---|
68 | if(loc.indexOf(".html") < 0) loc += ".html"; |
---|
69 | if(fragment.indexOf('@') > 0) loc += ("#" + fragment.split("@", 2)[1]); |
---|
70 | frames["template"].location.replace(loc); |
---|
71 | } |
---|
72 | else |
---|
73 | frames["template"].location.replace("package.html"); |
---|
74 | } |
---|
75 | |
---|
76 | // Set the url fragment according to the src of the iframe "template". |
---|
77 | // iframe url = "scala/Either.html" => url fragment = "#scala.Either" |
---|
78 | // iframe url = "scala/Either.html#isRight:Boolean" => url fragment = "#scala.Either@isRight:Boolean" |
---|
79 | function setUrlFragmentFromFrameSrc() { |
---|
80 | try { |
---|
81 | var commonLength = location.pathname.lastIndexOf("/"); |
---|
82 | var frameLocation = frames["template"].location; |
---|
83 | var relativePath = frameLocation.pathname.slice(commonLength + 1); |
---|
84 | |
---|
85 | if(!relativePath || frameLocation.pathname.indexOf("/") < 0) |
---|
86 | return; |
---|
87 | |
---|
88 | // Add #, remove ".html" and replace "/" with "." |
---|
89 | fragment = "#" + relativePath.replace(/\.html$/, "").replace(/\//g, "."); |
---|
90 | |
---|
91 | // Add the frame's hash after an @ |
---|
92 | if(frameLocation.hash) fragment += ("@" + frameLocation.hash.slice(1)); |
---|
93 | |
---|
94 | // Use replace to not add history items |
---|
95 | lastFragment = fragment; |
---|
96 | location.replace(fragment); |
---|
97 | } |
---|
98 | catch(e) { |
---|
99 | // Chrome doesn't allow reading the iframe's location when |
---|
100 | // used on the local file system. |
---|
101 | } |
---|
102 | } |
---|
103 | |
---|
104 | var Index = {}; |
---|
105 | |
---|
106 | (function (ns) { |
---|
107 | function openLink(t, type) { |
---|
108 | var href; |
---|
109 | if (type == 'object') { |
---|
110 | href = t['object']; |
---|
111 | } else { |
---|
112 | href = t['class'] || t['trait'] || t['case class']; |
---|
113 | } |
---|
114 | return [ |
---|
115 | '<a class="tplshow" target="template" href="', |
---|
116 | href, |
---|
117 | '"><img width="13" height="13" class="', |
---|
118 | type, |
---|
119 | ' icon" src="lib/', |
---|
120 | type, |
---|
121 | '.png" />' |
---|
122 | ].join(''); |
---|
123 | } |
---|
124 | |
---|
125 | function createPackageHeader(pack) { |
---|
126 | return [ |
---|
127 | '<li class="pack">', |
---|
128 | '<a class="packfocus">focus</a><a class="packhide">hide</a>', |
---|
129 | '<a class="tplshow" target="template" href="', |
---|
130 | pack.replace(/\./g, '/'), |
---|
131 | '/package.html">', |
---|
132 | pack, |
---|
133 | '</a></li>' |
---|
134 | ].join(''); |
---|
135 | }; |
---|
136 | |
---|
137 | function createListItem(template) { |
---|
138 | var inner = ''; |
---|
139 | |
---|
140 | |
---|
141 | if (template.object) { |
---|
142 | inner += openLink(template, 'object'); |
---|
143 | } |
---|
144 | |
---|
145 | if (template['class'] || template['trait'] || template['case class']) { |
---|
146 | inner += (inner == '') ? |
---|
147 | '<div class="placeholder" />' : '</a>'; |
---|
148 | inner += openLink(template, template['trait'] ? 'trait' : 'class'); |
---|
149 | } else { |
---|
150 | inner += '<div class="placeholder"/>'; |
---|
151 | } |
---|
152 | |
---|
153 | return [ |
---|
154 | '<li>', |
---|
155 | inner, |
---|
156 | '<span class="tplLink">', |
---|
157 | template.name.replace(/^.*\./, ''), |
---|
158 | '</span></a></li>' |
---|
159 | ].join(''); |
---|
160 | } |
---|
161 | |
---|
162 | |
---|
163 | ns.createPackageTree = function (pack, matched, focused) { |
---|
164 | var html = $.map(matched, function (child, i) { |
---|
165 | return createListItem(child); |
---|
166 | }).join(''); |
---|
167 | |
---|
168 | var header; |
---|
169 | if (focused && pack == focused) { |
---|
170 | header = ''; |
---|
171 | } else { |
---|
172 | header = createPackageHeader(pack); |
---|
173 | } |
---|
174 | |
---|
175 | return [ |
---|
176 | '<ol class="packages">', |
---|
177 | header, |
---|
178 | '<ol class="templates">', |
---|
179 | html, |
---|
180 | '</ol></ol>' |
---|
181 | ].join(''); |
---|
182 | } |
---|
183 | |
---|
184 | ns.keys = function (obj) { |
---|
185 | var result = []; |
---|
186 | var key; |
---|
187 | for (key in obj) { |
---|
188 | result.push(key); |
---|
189 | } |
---|
190 | return result; |
---|
191 | } |
---|
192 | |
---|
193 | var hiddenPackages = {}; |
---|
194 | |
---|
195 | function subPackages(pack) { |
---|
196 | return $.grep($('#tpl ol.packages'), function (element, index) { |
---|
197 | var pack = $('li.pack > .tplshow', element).text(); |
---|
198 | return pack.indexOf(pack + '.') == 0; |
---|
199 | }); |
---|
200 | } |
---|
201 | |
---|
202 | ns.hidePackage = function (ol) { |
---|
203 | var selected = $('li.pack > .tplshow', ol).text(); |
---|
204 | hiddenPackages[selected] = true; |
---|
205 | |
---|
206 | $('ol.templates', ol).hide(); |
---|
207 | |
---|
208 | $.each(subPackages(selected), function (index, element) { |
---|
209 | $(element).hide(); |
---|
210 | }); |
---|
211 | } |
---|
212 | |
---|
213 | ns.showPackage = function (ol, state) { |
---|
214 | var selected = $('li.pack > .tplshow', ol).text(); |
---|
215 | hiddenPackages[selected] = false; |
---|
216 | |
---|
217 | $('ol.templates', ol).show(); |
---|
218 | |
---|
219 | $.each(subPackages(selected), function (index, element) { |
---|
220 | $(element).show(); |
---|
221 | |
---|
222 | // When the filter is in "packs" state, |
---|
223 | // we don't want to show the `.templates` |
---|
224 | var key = $('li.pack > .tplshow', element).text(); |
---|
225 | if (hiddenPackages[key] || state == 'packs') { |
---|
226 | $('ol.templates', element).hide(); |
---|
227 | } |
---|
228 | }); |
---|
229 | } |
---|
230 | |
---|
231 | })(Index); |
---|
232 | |
---|
233 | function configureEntityList() { |
---|
234 | kindFilterSync(); |
---|
235 | configureHideFilter(); |
---|
236 | configureFocusFilter(); |
---|
237 | textFilter(); |
---|
238 | } |
---|
239 | |
---|
240 | /* Updates the list of entities (i.e. the content of the #tpl element) from the raw form generated by Scaladoc to a |
---|
241 | form suitable for display. In particular, it adds class and object etc. icons, and it configures links to open in |
---|
242 | the right frame. Furthermore, it sets the two reference top-level entities lists (topLevelTemplates and |
---|
243 | topLevelPackages) to serve as reference for resetting the list when needed. |
---|
244 | Be advised: this function should only be called once, on page load. */ |
---|
245 | function prepareEntityList() { |
---|
246 | var classIcon = $("#library > img.class"); |
---|
247 | var traitIcon = $("#library > img.trait"); |
---|
248 | var objectIcon = $("#library > img.object"); |
---|
249 | var packageIcon = $("#library > img.package"); |
---|
250 | |
---|
251 | $('#tpl li.pack > a.tplshow').attr("target", "template"); |
---|
252 | $('#tpl li.pack').each(function () { |
---|
253 | $("span.class", this).each(function() { $(this).replaceWith(classIcon.clone()); }); |
---|
254 | $("span.trait", this).each(function() { $(this).replaceWith(traitIcon.clone()); }); |
---|
255 | $("span.object", this).each(function() { $(this).replaceWith(objectIcon.clone()); }); |
---|
256 | $("span.package", this).each(function() { $(this).replaceWith(packageIcon.clone()); }); |
---|
257 | }); |
---|
258 | $('#tpl li.pack') |
---|
259 | .prepend("<a class='packhide'>hide</a>") |
---|
260 | .prepend("<a class='packfocus'>focus</a>"); |
---|
261 | } |
---|
262 | |
---|
263 | /* Configures the text filter */ |
---|
264 | function configureTextFilter() { |
---|
265 | scheduler.add("init", function() { |
---|
266 | $("#filter").append("<div id='textfilter'><span class='pre'/><span class='input'><input type='text' accesskey='/'/></span><span class='post'/></div>"); |
---|
267 | printAlphabet(); |
---|
268 | var input = $("#textfilter input"); |
---|
269 | resizeFilterBlock(); |
---|
270 | input.bind("keyup", function(event) { |
---|
271 | if (event.keyCode == 27) { // escape |
---|
272 | input.attr("value", ""); |
---|
273 | } |
---|
274 | textFilter(); |
---|
275 | }); |
---|
276 | input.focus(function(event) { input.select(); }); |
---|
277 | }); |
---|
278 | scheduler.add("init", function() { |
---|
279 | $("#textfilter > .post").click(function(){ |
---|
280 | $("#textfilter input").attr("value", ""); |
---|
281 | textFilter(); |
---|
282 | }); |
---|
283 | }); |
---|
284 | } |
---|
285 | |
---|
286 | function compilePattern(query) { |
---|
287 | var escaped = query.replace(/([\.\*\+\?\|\(\)\[\]\\])/g, '\\$1'); |
---|
288 | |
---|
289 | if (query.toLowerCase() != query) { |
---|
290 | // Regexp that matches CamelCase subbits: "BiSe" is |
---|
291 | // "[a-z]*Bi[a-z]*Se" and matches "BitSet", "ABitSet", ... |
---|
292 | return new RegExp(escaped.replace(/([A-Z])/g,"[a-z]*$1")); |
---|
293 | } |
---|
294 | else { // if query is all lower case make a normal case insensitive search |
---|
295 | return new RegExp(escaped, "i"); |
---|
296 | } |
---|
297 | } |
---|
298 | |
---|
299 | // Filters all focused templates and packages. This function should be made less-blocking. |
---|
300 | // @param query The string of the query |
---|
301 | function textFilter() { |
---|
302 | scheduler.clear("filter"); |
---|
303 | |
---|
304 | $('#tpl').html(''); |
---|
305 | |
---|
306 | var query = $("#textfilter input").attr("value") || ''; |
---|
307 | var queryRegExp = compilePattern(query); |
---|
308 | |
---|
309 | var index = 0; |
---|
310 | |
---|
311 | var searchLoop = function () { |
---|
312 | var packages = Index.keys(Index.PACKAGES).sort(); |
---|
313 | |
---|
314 | while (packages[index]) { |
---|
315 | var pack = packages[index]; |
---|
316 | var children = Index.PACKAGES[pack]; |
---|
317 | index++; |
---|
318 | |
---|
319 | if (focusFilterState) { |
---|
320 | if (pack == focusFilterState || |
---|
321 | pack.indexOf(focusFilterState + '.') == 0) { |
---|
322 | ; |
---|
323 | } else { |
---|
324 | continue; |
---|
325 | } |
---|
326 | } |
---|
327 | |
---|
328 | var matched = $.grep(children, function (child, i) { |
---|
329 | return queryRegExp.test(child.name); |
---|
330 | }); |
---|
331 | |
---|
332 | if (matched.length > 0) { |
---|
333 | $('#tpl').append(Index.createPackageTree(pack, matched, |
---|
334 | focusFilterState)); |
---|
335 | scheduler.add('filter', searchLoop); |
---|
336 | return; |
---|
337 | } |
---|
338 | } |
---|
339 | |
---|
340 | $('#tpl a.packfocus').click(function () { |
---|
341 | focusFilter($(this).parent().parent()); |
---|
342 | }); |
---|
343 | configureHideFilter(); |
---|
344 | }; |
---|
345 | |
---|
346 | scheduler.add('filter', searchLoop); |
---|
347 | } |
---|
348 | |
---|
349 | /* Configures the hide tool by adding the hide link to all packages. */ |
---|
350 | function configureHideFilter() { |
---|
351 | $('#tpl li.pack a.packhide').click(function () { |
---|
352 | var packhide = $(this) |
---|
353 | var action = packhide.text(); |
---|
354 | |
---|
355 | var ol = $(this).parent().parent(); |
---|
356 | |
---|
357 | if (action == "hide") { |
---|
358 | Index.hidePackage(ol); |
---|
359 | packhide.text("show"); |
---|
360 | } |
---|
361 | else { |
---|
362 | Index.showPackage(ol, kindFilterState); |
---|
363 | packhide.text("hide"); |
---|
364 | } |
---|
365 | return false; |
---|
366 | }); |
---|
367 | } |
---|
368 | |
---|
369 | /* Configures the focus tool by adding the focus bar in the filter box (initially hidden), and by adding the focus |
---|
370 | link to all packages. */ |
---|
371 | function configureFocusFilter() { |
---|
372 | scheduler.add("init", function() { |
---|
373 | focusFilterState = null; |
---|
374 | if ($("#focusfilter").length == 0) { |
---|
375 | $("#filter").append("<div id='focusfilter'>focused on <span class='focuscoll'></span> <a class='focusremove'><img class='icon' src='lib/remove.png'/></a></div>"); |
---|
376 | $("#focusfilter > .focusremove").click(function(event) { |
---|
377 | textFilter(); |
---|
378 | |
---|
379 | $("#focusfilter").hide(); |
---|
380 | $("#kindfilter").show(); |
---|
381 | resizeFilterBlock(); |
---|
382 | focusFilterState = null; |
---|
383 | }); |
---|
384 | $("#focusfilter").hide(); |
---|
385 | resizeFilterBlock(); |
---|
386 | } |
---|
387 | }); |
---|
388 | scheduler.add("init", function() { |
---|
389 | $('#tpl li.pack a.packfocus').click(function () { |
---|
390 | focusFilter($(this).parent()); |
---|
391 | return false; |
---|
392 | }); |
---|
393 | }); |
---|
394 | } |
---|
395 | |
---|
396 | /* Focuses the entity index on a specific package. To do so, it will copy the sub-templates and sub-packages of the |
---|
397 | focuses package into the top-level templates and packages position of the index. The original top-level |
---|
398 | @param package The <li> element that corresponds to the package in the entity index */ |
---|
399 | function focusFilter(package) { |
---|
400 | scheduler.clear("filter"); |
---|
401 | |
---|
402 | var currentFocus = $('li.pack > .tplshow', package).text(); |
---|
403 | $("#focusfilter > .focuscoll").empty(); |
---|
404 | $("#focusfilter > .focuscoll").append(currentFocus); |
---|
405 | |
---|
406 | $("#focusfilter").show(); |
---|
407 | $("#kindfilter").hide(); |
---|
408 | resizeFilterBlock(); |
---|
409 | focusFilterState = currentFocus; |
---|
410 | kindFilterSync(); |
---|
411 | |
---|
412 | textFilter(); |
---|
413 | } |
---|
414 | |
---|
415 | function configureKindFilter() { |
---|
416 | scheduler.add("init", function() { |
---|
417 | kindFilterState = "all"; |
---|
418 | $("#filter").append("<div id='kindfilter'><a>display packages only</a></div>"); |
---|
419 | $("#kindfilter > a").click(function(event) { kindFilter("packs"); }); |
---|
420 | resizeFilterBlock(); |
---|
421 | }); |
---|
422 | } |
---|
423 | |
---|
424 | function kindFilter(kind) { |
---|
425 | if (kind == "packs") { |
---|
426 | kindFilterState = "packs"; |
---|
427 | kindFilterSync(); |
---|
428 | $("#kindfilter > a").replaceWith("<a>display all entities</a>"); |
---|
429 | $("#kindfilter > a").click(function(event) { kindFilter("all"); }); |
---|
430 | } |
---|
431 | else { |
---|
432 | kindFilterState = "all"; |
---|
433 | kindFilterSync(); |
---|
434 | $("#kindfilter > a").replaceWith("<a>display packages only</a>"); |
---|
435 | $("#kindfilter > a").click(function(event) { kindFilter("packs"); }); |
---|
436 | } |
---|
437 | } |
---|
438 | |
---|
439 | /* Applies the kind filter. */ |
---|
440 | function kindFilterSync() { |
---|
441 | if (kindFilterState == "all" || focusFilterState != null) { |
---|
442 | $("#tpl a.packhide").text('hide'); |
---|
443 | $("#tpl ol.templates").show(); |
---|
444 | } else { |
---|
445 | $("#tpl a.packhide").text('show'); |
---|
446 | $("#tpl ol.templates").hide(); |
---|
447 | } |
---|
448 | } |
---|
449 | |
---|
450 | function resizeFilterBlock() { |
---|
451 | $("#tpl").css("top", $("#filter").outerHeight(true)); |
---|
452 | } |
---|
453 | |
---|
454 | function printAlphabet() { |
---|
455 | $("#filter").append("<div id='letters'><a target='template' href='index/index-%23.html'>#</a><a target='template' href='index/index-a.html'>A</a><a target='template' href='index/index-b.html'>B</a><a target='template' href='index/index-c.html'>C</a><a target='template' href='index/index-d.html'>D</a><a target='template' href='index/index-e.html'>E</a><a target='template' href='index/index-f.html'>F</a><a target='template' href='index/index-g.html'>G</a><a target='template' href='index/index-h.html'>H</a><a target='template' href='index/index-i.html'>I</a><a target='template' href='index/index-j.html'>J</a><a target='template' href='index/index-k.html'>K</a><a target='template' href='index/index-l.html'>L</a><a target='template' href='index/index-m.html'>M</a><a target='template' href='index/index-n.html'>N</a><a target='template' href='index/index-o.html'>O</a><a target='template' href='index/index-p.html'>P</a><a target='template' href='index/index-q.html'>Q</a><a target='template' href='index/index-r.html'>R</a><a target='template' href='index/index-s.html'>S</a><a target='template' href='index/index-t.html'>T</a><a target='template' href='index/index-u.html'>U</a><a target='template' href='index/index-v.html'>V</a><a target='template' href='index/index-w.html'>W</a><a target='template' href='index/index-x.html'>X</a><a target='template' href='index/index-y.html'>Y</a><a target='template' href='index/index-z.html'>Z</a></div>"); |
---|
456 | } |
---|
457 | |
---|