ember 0.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,22 @@
1
+ function toggleSource( id )
2
+ {
3
+ var $src = $('#' + id).toggle();
4
+ $('#l_' + id).html($src.css('display') == 'none' ? 'show' : 'hide');
5
+ }
6
+
7
+ function openCode( url )
8
+ {
9
+ window.open( url, "SOURCE_CODE", "resizable=yes,scrollbars=yes,toolbar=no,status=no,height=480,width=750" ).focus();
10
+ }
11
+
12
+
13
+ window.highlight = function(url) {
14
+ var hash = url.match(/#([^#]+)$/)
15
+ if(hash) {
16
+ $('a[name=' + hash[1] + ']').parent().effect('highlight', {}, 'slow')
17
+ }
18
+ }
19
+
20
+ $(function() {
21
+ highlight('#' + location.hash);
22
+ });
@@ -0,0 +1,605 @@
1
+ Searchdoc = {};
2
+
3
+ // navigation.js ------------------------------------------
4
+
5
+ Searchdoc.Navigation = new function() {
6
+ this.initNavigation = function() {
7
+ var _this = this;
8
+
9
+ $(document).keydown(function(e) {
10
+ _this.onkeydown(e);
11
+ }).keyup(function(e) {
12
+ _this.onkeyup(e);
13
+ });
14
+
15
+ this.navigationActive = true;
16
+ }
17
+
18
+ this.setNavigationActive = function(state) {
19
+ this.navigationActive = state;
20
+ this.clearMoveTimeout();
21
+ }
22
+
23
+
24
+ this.onkeyup = function(e) {
25
+ if (!this.navigationActive) return;
26
+ switch(e.keyCode) {
27
+ case 37: //Event.KEY_LEFT:
28
+ case 38: //Event.KEY_UP:
29
+ case 39: //Event.KEY_RIGHT:
30
+ case 40: //Event.KEY_DOWN:
31
+ this.clearMoveTimeout();
32
+ break;
33
+ }
34
+ }
35
+
36
+ this.onkeydown = function(e) {
37
+ if (!this.navigationActive) return;
38
+ switch(e.keyCode) {
39
+ case 37: //Event.KEY_LEFT:
40
+ if (this.moveLeft())
41
+ e.preventDefault();
42
+ break;
43
+ case 38: //Event.KEY_UP:
44
+ if (this.moveUp())
45
+ e.preventDefault();
46
+ this.startMoveTimeout(false);
47
+ break;
48
+ case 39: //Event.KEY_RIGHT:
49
+ if (this.moveRight())
50
+ e.preventDefault();
51
+ break;
52
+ case 40: //Event.KEY_DOWN:
53
+ if (this.moveDown())
54
+ e.preventDefault();
55
+ this.startMoveTimeout(true);
56
+ break;
57
+ case 9: //Event.KEY_TAB:
58
+ case 13: //Event.KEY_RETURN:
59
+ if (this.$current) this.select(this.$current);
60
+ break;
61
+ }
62
+ }
63
+
64
+ this.clearMoveTimeout = function() {
65
+ clearTimeout(this.moveTimeout);
66
+ this.moveTimeout = null;
67
+ }
68
+
69
+ this.startMoveTimeout = function(isDown) {
70
+ if (!$.browser.mozilla && !$.browser.opera) return;
71
+ if (this.moveTimeout) this.clearMoveTimeout();
72
+ var _this = this;
73
+
74
+ var go = function() {
75
+ if (!_this.moveTimeout) return;
76
+ _this[isDown ? 'moveDown' : 'moveUp']();
77
+ _this.moveTimout = setTimeout(go, 100);
78
+ }
79
+ this.moveTimeout = setTimeout(go, 200);
80
+ }
81
+
82
+ this.moveRight = function() {
83
+ }
84
+
85
+ this.moveLeft = function() {
86
+ }
87
+
88
+ this.move = function(isDown) {
89
+ }
90
+
91
+ this.moveUp = function() {
92
+ return this.move(false);
93
+ }
94
+
95
+ this.moveDown = function() {
96
+ return this.move(true);
97
+ }
98
+ }
99
+
100
+
101
+ // scrollIntoView.js --------------------------------------
102
+
103
+ function scrollIntoView(element, view) {
104
+ var offset, viewHeight, viewScroll, height;
105
+ offset = element.offsetTop;
106
+ height = element.offsetHeight;
107
+ viewHeight = view.offsetHeight;
108
+ viewScroll = view.scrollTop;
109
+ if (offset - viewScroll + height > viewHeight) {
110
+ view.scrollTop = offset - viewHeight + height;
111
+ }
112
+ if (offset < viewScroll) {
113
+ view.scrollTop = offset;
114
+ }
115
+ }
116
+
117
+
118
+ // searcher.js --------------------------------------------
119
+
120
+ Searchdoc.Searcher = function(data) {
121
+ this.data = data;
122
+ this.handlers = [];
123
+ }
124
+
125
+ Searchdoc.Searcher.prototype = new function() {
126
+ var CHUNK_SIZE = 1000, // search is performed in chunks of 1000 for non-bloking user input
127
+ MAX_RESULTS = 100, // do not try to find more than 100 results
128
+ huid = 1, suid = 1,
129
+ runs = 0;
130
+
131
+
132
+ this.find = function(query) {
133
+ var queries = splitQuery(query),
134
+ regexps = buildRegexps(queries),
135
+ highlighters = buildHilighters(queries),
136
+ state = { from: 0, pass: 0, limit: MAX_RESULTS, n: suid++},
137
+ _this = this;
138
+ this.currentSuid = state.n;
139
+
140
+ if (!query) return;
141
+
142
+ var run = function() {
143
+ // stop current search thread if new search started
144
+ if (state.n != _this.currentSuid) return;
145
+
146
+ var results = performSearch(_this.data, regexps, queries, highlighters, state),
147
+ hasMore = (state.limit > 0 && state.pass < 3);
148
+
149
+ triggerResults.call(_this, results, !hasMore);
150
+ if (hasMore) {
151
+ setTimeout(run, 2);
152
+ }
153
+ runs++;
154
+ };
155
+ runs = 0;
156
+
157
+ // start search thread
158
+ run();
159
+ }
160
+
161
+ /* ----- Events ------ */
162
+ this.ready = function(fn) {
163
+ fn.huid = huid;
164
+ this.handlers.push(fn);
165
+ }
166
+
167
+ /* ----- Utilities ------ */
168
+ function splitQuery(query) {
169
+ return jQuery.grep(query.split(/(\s+|\(\)?)/), function(string) { return string.match(/\S/) });
170
+ }
171
+
172
+ function buildRegexps(queries) {
173
+ return jQuery.map(queries, function(query) { return new RegExp(query.replace(/(.)/g, '([$1])([^$1]*?)'), 'i') });
174
+ }
175
+
176
+ function buildHilighters(queries) {
177
+ return jQuery.map(queries, function(query) {
178
+ return jQuery.map( query.split(''), function(l, i){ return '\u0001$' + (i*2+1) + '\u0002$' + (i*2+2) } ).join('')
179
+ });
180
+ }
181
+
182
+ // function longMatchRegexp(index, longIndex, regexps) {
183
+ // for (var i = regexps.length - 1; i >= 0; i--){
184
+ // if (!index.match(regexps[i]) && !longIndex.match(regexps[i])) return false;
185
+ // };
186
+ // return true;
187
+ // }
188
+
189
+
190
+ /* ----- Mathchers ------ */
191
+ function matchPass1(index, longIndex, queries, regexps) {
192
+ if (index.indexOf(queries[0]) != 0) return false;
193
+ for (var i=1, l = regexps.length; i < l; i++) {
194
+ if (!index.match(regexps[i]) && !longIndex.match(regexps[i])) return false;
195
+ };
196
+ return true;
197
+ }
198
+
199
+ function matchPass2(index, longIndex, queries, regexps) {
200
+ if (index.indexOf(queries[0]) == -1) return false;
201
+ for (var i=1, l = regexps.length; i < l; i++) {
202
+ if (!index.match(regexps[i]) && !longIndex.match(regexps[i])) return false;
203
+ };
204
+ return true;
205
+ }
206
+
207
+ function matchPassRegexp(index, longIndex, queries, regexps) {
208
+ if (!index.match(regexps[0])) return false;
209
+ for (var i=1, l = regexps.length; i < l; i++) {
210
+ if (!index.match(regexps[i]) && !longIndex.match(regexps[i])) return false;
211
+ };
212
+ return true;
213
+ }
214
+
215
+
216
+ /* ----- Highlighters ------ */
217
+ function highlightRegexp(info, queries, regexps, highlighters) {
218
+ var result = createResult(info);
219
+ for (var i=0, l = regexps.length; i < l; i++) {
220
+ result.title = result.title.replace(regexps[i], highlighters[i]);
221
+ if (i > 0)
222
+ result.namespace = result.namespace.replace(regexps[i], highlighters[i]);
223
+ };
224
+ return result;
225
+ }
226
+
227
+ function hltSubstring(string, pos, length) {
228
+ return string.substring(0, pos) + '\u0001' + string.substring(pos, pos + length) + '\u0002' + string.substring(pos + length);
229
+ }
230
+
231
+ function highlightQuery(info, queries, regexps, highlighters) {
232
+ var result = createResult(info), pos = 0, lcTitle = result.title.toLowerCase();
233
+ pos = lcTitle.indexOf(queries[0]);
234
+ if (pos != -1) {
235
+ result.title = hltSubstring(result.title, pos, queries[0].length);
236
+ }
237
+ for (var i=1, l = regexps.length; i < l; i++) {
238
+ result.title = result.title.replace(regexps[i], highlighters[i]);
239
+ result.namespace = result.namespace.replace(regexps[i], highlighters[i]);
240
+ };
241
+ return result;
242
+ }
243
+
244
+ function createResult(info) {
245
+ var result = {};
246
+ result.title = info[0];
247
+ result.namespace = info[1];
248
+ result.path = info[2];
249
+ result.params = info[3];
250
+ result.snippet = info[4];
251
+ result.badge = info[6];
252
+ return result;
253
+ }
254
+
255
+ /* ----- Searching ------ */
256
+ function performSearch(data, regexps, queries, highlighters, state) {
257
+ var searchIndex = data.searchIndex, // search by title first and then by source
258
+ longSearchIndex = data.longSearchIndex,
259
+ info = data.info,
260
+ result = [],
261
+ i = state.from,
262
+ l = searchIndex.length,
263
+ togo = CHUNK_SIZE,
264
+ matchFunc, hltFunc;
265
+
266
+ while (state.pass < 3 && state.limit > 0 && togo > 0) {
267
+ if (state.pass == 0) {
268
+ matchFunc = matchPass1;
269
+ hltFunc = highlightQuery;
270
+ } else if (state.pass == 1) {
271
+ matchFunc = matchPass2;
272
+ hltFunc = highlightQuery;
273
+ } else if (state.pass == 2) {
274
+ matchFunc = matchPassRegexp;
275
+ hltFunc = highlightRegexp;
276
+ }
277
+
278
+ for (; togo > 0 && i < l && state.limit > 0; i++, togo--) {
279
+ if (info[i].n == state.n) continue;
280
+ if (matchFunc(searchIndex[i], longSearchIndex[i], queries, regexps)) {
281
+ info[i].n = state.n;
282
+ result.push(hltFunc(info[i], queries, regexps, highlighters));
283
+ state.limit--;
284
+ }
285
+ };
286
+ if (searchIndex.length <= i) {
287
+ state.pass++;
288
+ i = state.from = 0;
289
+ } else {
290
+ state.from = i;
291
+ }
292
+ }
293
+ return result;
294
+ }
295
+
296
+ function triggerResults(results, isLast) {
297
+ jQuery.each(this.handlers, function(i, fn) { fn.call(this, results, isLast) })
298
+ }
299
+ }
300
+
301
+
302
+
303
+
304
+ // panel.js -----------------------------------------------
305
+
306
+ Searchdoc.Panel = function(element, data, tree, frame) {
307
+ this.$element = $(element);
308
+ this.$input = $('input', element).eq(0);
309
+ this.$result = $('.result ul', element).eq(0);
310
+ this.frame = frame;
311
+ this.$current = null;
312
+ this.$view = this.$result.parent();
313
+ this.data = data;
314
+ this.searcher = new Searchdoc.Searcher(data.index);
315
+ this.tree = new Searchdoc.Tree($('.tree', element), tree, this);
316
+ this.init();
317
+ }
318
+
319
+ Searchdoc.Panel.prototype = $.extend({}, Searchdoc.Navigation, new function() {
320
+ var suid = 1;
321
+
322
+ this.init = function() {
323
+ var _this = this;
324
+ var observer = function() {
325
+ _this.search(_this.$input[0].value);
326
+ };
327
+ this.$input.keyup(observer);
328
+ this.$input.click(observer); // mac's clear field
329
+
330
+ this.searcher.ready(function(results, isLast) {
331
+ _this.addResults(results, isLast);
332
+ })
333
+
334
+ this.$result.click(function(e) {
335
+ _this.$current.removeClass('current');
336
+ _this.$current = $(e.target).closest('li').addClass('current');
337
+ _this.select();
338
+ _this.$input.focus();
339
+ });
340
+
341
+ this.initNavigation();
342
+ this.setNavigationActive(false);
343
+ }
344
+
345
+ this.search = function(value) {
346
+ value = jQuery.trim(value).toLowerCase();
347
+ if (value) {
348
+ this.$element.removeClass('panel_tree').addClass('panel_results');
349
+ this.tree.setNavigationActive(false);
350
+ this.setNavigationActive(true);
351
+ } else {
352
+ this.$element.addClass('panel_tree').removeClass('panel_results');
353
+ this.tree.setNavigationActive(true);
354
+ this.setNavigationActive(false);
355
+ }
356
+ if (value != this.lastQuery) {
357
+ this.lastQuery = value;
358
+ this.firstRun = true;
359
+ this.searcher.find(value);
360
+ }
361
+ }
362
+
363
+ this.addResults = function(results, isLast) {
364
+ var target = this.$result.get(0);
365
+ if (this.firstRun && (results.length > 0 || isLast)) {
366
+ this.$current = null;
367
+ this.$result.empty();
368
+ }
369
+ for (var i=0, l = results.length; i < l; i++) {
370
+ target.appendChild(renderItem.call(this, results[i]));
371
+ };
372
+ if (this.firstRun && results.length > 0) {
373
+ this.firstRun = false;
374
+ this.$current = $(target.firstChild);
375
+ this.$current.addClass('current');
376
+ scrollIntoView(this.$current[0], this.$view[0])
377
+ }
378
+ if (jQuery.browser.msie) this.$element[0].className += '';
379
+ }
380
+
381
+ this.open = function(src) {
382
+ this.frame.location.href = '../' + src;
383
+ if (this.frame.highlight) this.frame.highlight(src);
384
+ }
385
+
386
+ this.select = function() {
387
+ this.open(this.$current.data('path'));
388
+ }
389
+
390
+ this.move = function(isDown) {
391
+ if (!this.$current) return;
392
+ var $next = this.$current[isDown ? 'next' : 'prev']();
393
+ if ($next.length) {
394
+ this.$current.removeClass('current');
395
+ $next.addClass('current');
396
+ scrollIntoView($next[0], this.$view[0]);
397
+ this.$current = $next;
398
+ }
399
+ return true;
400
+ }
401
+
402
+ function renderItem(result) {
403
+ var li = document.createElement('li'),
404
+ html = '', badge = result.badge;
405
+ html += '<h1>' + hlt(result.title);
406
+ if (result.params) html += '<i>' + result.params + '</i>';
407
+ html += '</h1>';
408
+ html += '<p>';
409
+ if (typeof badge != 'undefined') {
410
+ html += '<span class="badge badge_' + (badge % 6 + 1) + '">' + escapeHTML(this.data.badges[badge] || 'unknown') + '</span>';
411
+ }
412
+ html += hlt(result.namespace) + '</p>';
413
+ if (result.snippet) html += '<p class="snippet">' + escapeHTML(result.snippet) + '</p>';
414
+ li.innerHTML = html;
415
+ jQuery.data(li, 'path', result.path);
416
+ return li;
417
+ }
418
+
419
+ function hlt(html) {
420
+ return escapeHTML(html).replace(/\u0001/g, '<b>').replace(/\u0002/g, '</b>')
421
+ }
422
+
423
+ function escapeHTML(html) {
424
+ return html.replace(/[&<>]/g, function(c) {
425
+ return '&#' + c.charCodeAt(0) + ';';
426
+ });
427
+ }
428
+
429
+ });
430
+
431
+ // tree.js ------------------------------------------------
432
+
433
+ Searchdoc.Tree = function(element, tree, panel) {
434
+ this.$element = $(element);
435
+ this.$list = $('ul', element);
436
+ this.tree = tree;
437
+ this.panel = panel;
438
+ this.init();
439
+ }
440
+
441
+ Searchdoc.Tree.prototype = $.extend({}, Searchdoc.Navigation, new function() {
442
+ this.init = function() {
443
+ var stopper = document.createElement('li');
444
+ stopper.className = 'stopper';
445
+ this.$list[0].appendChild(stopper);
446
+ for (var i=0, l = this.tree.length; i < l; i++) {
447
+ buildAndAppendItem.call(this, this.tree[i], 0, stopper);
448
+ };
449
+ var _this = this;
450
+ this.$list.click(function(e) {
451
+ var $target = $(e.target),
452
+ $li = $target.closest('li');
453
+ if ($target.hasClass('icon')) {
454
+ _this.toggle($li);
455
+ } else {
456
+ _this.select($li);
457
+ }
458
+ })
459
+
460
+ this.initNavigation();
461
+ if (jQuery.browser.msie) document.body.className += '';
462
+ }
463
+
464
+ this.select = function($li) {
465
+ var path = $li[0].searchdoc_tree_data.path;
466
+ if (this.$current) this.$current.removeClass('current');
467
+ this.$current = $li.addClass('current');
468
+ if (path) this.panel.open(path);
469
+ }
470
+
471
+ this.toggle = function($li) {
472
+ var closed = !$li.hasClass('closed'),
473
+ children = $li[0].searchdoc_tree_data.children;
474
+ $li.toggleClass('closed');
475
+ for (var i=0, l = children.length; i < l; i++) {
476
+ toggleVis.call(this, $(children[i].li), !closed);
477
+ };
478
+ }
479
+
480
+ this.moveRight = function() {
481
+ if (!this.$current) {
482
+ this.select(this.$list.find('li:first'));
483
+ return;
484
+ }
485
+ if (this.$current.hasClass('closed')) {
486
+ this.toggle(this.$current);
487
+ }
488
+ }
489
+
490
+ this.moveLeft = function() {
491
+ if (!this.$current) {
492
+ this.select(this.$list.find('li:first'));
493
+ return;
494
+ }
495
+ if (!this.$current.hasClass('closed')) {
496
+ this.toggle(this.$current);
497
+ } else {
498
+ var level = this.$current[0].searchdoc_tree_data.level;
499
+ if (level == 0) return;
500
+ var $next = this.$current.prevAll('li.level_' + (level - 1) + ':visible:first');
501
+ this.$current.removeClass('current');
502
+ $next.addClass('current');
503
+ scrollIntoView($next[0], this.$element[0]);
504
+ this.$current = $next;
505
+ }
506
+ }
507
+
508
+ this.move = function(isDown) {
509
+ if (!this.$current) {
510
+ this.select(this.$list.find('li:first'));
511
+ return true;
512
+ }
513
+ var next = this.$current[0];
514
+ if (isDown) {
515
+ do {
516
+ next = next.nextSibling;
517
+ if (next && next.style && next.style.display != 'none') break;
518
+ } while(next);
519
+ } else {
520
+ do {
521
+ next = next.previousSibling;
522
+ if (next && next.style && next.style.display != 'none') break;
523
+ } while(next);
524
+ }
525
+ if (next && next.className.indexOf('stopper') == -1) {
526
+ this.$current.removeClass('current');
527
+ $(next).addClass('current');
528
+ scrollIntoView(next, this.$element[0]);
529
+ this.$current = $(next);
530
+ }
531
+ return true;
532
+ }
533
+
534
+ function toggleVis($li, show) {
535
+ var closed = $li.hasClass('closed'),
536
+ children = $li[0].searchdoc_tree_data.children;
537
+ $li.css('display', show ? '' : 'none')
538
+ if (!show && this.$current && $li[0] == this.$current[0]) {
539
+ this.$current.removeClass('current');
540
+ this.$current = null;
541
+ }
542
+ for (var i=0, l = children.length; i < l; i++) {
543
+ toggleVis.call(this, $(children[i].li), show && !closed);
544
+ };
545
+ }
546
+
547
+ function buildAndAppendItem(item, level, before) {
548
+ var li = renderItem(item, level),
549
+ list = this.$list[0];
550
+ item.li = li;
551
+ list.insertBefore(li, before);
552
+ for (var i=0, l = item[3].length; i < l; i++) {
553
+ buildAndAppendItem.call(this, item[3][i], level + 1, before);
554
+ };
555
+ return li;
556
+ }
557
+
558
+ function renderItem(item, level) {
559
+ var li = document.createElement('li'),
560
+ cnt = document.createElement('div'),
561
+ h1 = document.createElement('h1'),
562
+ p = document.createElement('p'),
563
+ icon, i;
564
+
565
+ li.appendChild(cnt);
566
+ li.style.paddingLeft = getOffset(level);
567
+ cnt.className = 'content';
568
+ if (!item[1]) li.className = 'empty ';
569
+ cnt.appendChild(h1);
570
+ // cnt.appendChild(p);
571
+ h1.appendChild(document.createTextNode(item[0]));
572
+ // p.appendChild(document.createTextNode(item[4]));
573
+ if (item[2]) {
574
+ i = document.createElement('i');
575
+ i.appendChild(document.createTextNode(item[2]));
576
+ h1.appendChild(i);
577
+ }
578
+ if (item[3].length > 0) {
579
+ icon = document.createElement('div');
580
+ icon.className = 'icon';
581
+ cnt.appendChild(icon);
582
+ }
583
+
584
+ // user direct assignement instead of $()
585
+ // it's 8x faster
586
+ // $(li).data('path', item[1])
587
+ // .data('children', item[3])
588
+ // .data('level', level)
589
+ // .css('display', level == 0 ? '' : 'none')
590
+ // .addClass('level_' + level)
591
+ // .addClass('closed');
592
+ li.searchdoc_tree_data = {
593
+ path: item[1],
594
+ children: item[3],
595
+ level: level
596
+ }
597
+ li.style.display = level == 0 ? '' : 'none';
598
+ li.className += 'level_' + level + ' closed';
599
+ return li;
600
+ }
601
+
602
+ function getOffset(level) {
603
+ return 5 + 18*level + 'px';
604
+ }
605
+ });