source: sandbox/jabberit_messenger/trophy/strophejs/doc/javascript/main.js @ 2271

Revision 2271, 24.8 KB checked in by alexandrecorreia, 14 years ago (diff)

Ticket #986 - Reimplementar interface mais leve para o IM, sem a necessidades de plugins adicionais.

  • Property svn:executable set to *
Line 
1// This file is part of Natural Docs, which is Copyright (C) 2003-2008 Greg Valure
2// Natural Docs is licensed under the GPL
3
4
5//
6//  Browser Styles
7// ____________________________________________________________________________
8
9var agt=navigator.userAgent.toLowerCase();
10var browserType;
11var browserVer;
12
13if (agt.indexOf("opera") != -1)
14    {
15    browserType = "Opera";
16
17    if (agt.indexOf("opera 7") != -1 || agt.indexOf("opera/7") != -1)
18        {  browserVer = "Opera7";  }
19    else if (agt.indexOf("opera 8") != -1 || agt.indexOf("opera/8") != -1)
20        {  browserVer = "Opera8";  }
21    else if (agt.indexOf("opera 9") != -1 || agt.indexOf("opera/9") != -1)
22        {  browserVer = "Opera9";  }
23    }
24
25else if (agt.indexOf("applewebkit") != -1)
26    {
27    browserType = "Safari";
28
29    if (agt.indexOf("version/3") != -1)
30        {  browserVer = "Safari3";  }
31    else if (agt.indexOf("safari/4") != -1)
32        {  browserVer = "Safari2";  }
33    }
34
35else if (agt.indexOf("khtml") != -1)
36    {
37    browserType = "Konqueror";
38    }
39
40else if (agt.indexOf("msie") != -1)
41    {
42    browserType = "IE";
43
44    if (agt.indexOf("msie 6") != -1)
45        {  browserVer = "IE6";  }
46    else if (agt.indexOf("msie 7") != -1)
47        {  browserVer = "IE7";  }
48    }
49
50else if (agt.indexOf("gecko") != -1)
51    {
52    browserType = "Firefox";
53
54    if (agt.indexOf("rv:1.7") != -1)
55        {  browserVer = "Firefox1";  }
56    else if (agt.indexOf("rv:1.8)") != -1 || agt.indexOf("rv:1.8.0") != -1)
57        {  browserVer = "Firefox15";  }
58    else if (agt.indexOf("rv:1.8.1") != -1)
59        {  browserVer = "Firefox2";  }
60    }
61
62
63//
64//  Support Functions
65// ____________________________________________________________________________
66
67
68function GetXPosition(item)
69    {
70    var position = 0;
71
72    if (item.offsetWidth != null)
73        {
74        while (item != document.body && item != null)
75            {
76            position += item.offsetLeft;
77            item = item.offsetParent;
78            };
79        };
80
81    return position;
82    };
83
84
85function GetYPosition(item)
86    {
87    var position = 0;
88
89    if (item.offsetWidth != null)
90        {
91        while (item != document.body && item != null)
92            {
93            position += item.offsetTop;
94            item = item.offsetParent;
95            };
96        };
97
98    return position;
99    };
100
101
102function MoveToPosition(item, x, y)
103    {
104    // Opera 5 chokes on the px extension, so it can use the Microsoft one instead.
105
106    if (item.style.left != null)
107        {
108        item.style.left = x + "px";
109        item.style.top = y + "px";
110        }
111    else if (item.style.pixelLeft != null)
112        {
113        item.style.pixelLeft = x;
114        item.style.pixelTop = y;
115        };
116    };
117
118
119//
120//  Menu
121// ____________________________________________________________________________
122
123
124function ToggleMenu(id)
125    {
126    if (!window.document.getElementById)
127        {  return;  };
128
129    var display = window.document.getElementById(id).style.display;
130
131    if (display == "none")
132        {  display = "block";  }
133    else
134        {  display = "none";  }
135
136    window.document.getElementById(id).style.display = display;
137    }
138
139function HideAllBut(ids, max)
140    {
141    if (document.getElementById)
142        {
143        ids.sort( function(a,b) { return a - b; } );
144        var number = 1;
145
146        while (number < max)
147            {
148            if (ids.length > 0 && number == ids[0])
149                {  ids.shift();  }
150            else
151                {
152                document.getElementById("MGroupContent" + number).style.display = "none";
153                };
154
155            number++;
156            };
157        };
158    }
159
160
161//
162//  Tooltips
163// ____________________________________________________________________________
164
165
166var tooltipTimer = 0;
167
168function ShowTip(event, tooltipID, linkID)
169    {
170    if (tooltipTimer)
171        {  clearTimeout(tooltipTimer);  };
172
173    var docX = event.clientX + window.pageXOffset;
174    var docY = event.clientY + window.pageYOffset;
175
176    var showCommand = "ReallyShowTip('" + tooltipID + "', '" + linkID + "', " + docX + ", " + docY + ")";
177
178    tooltipTimer = setTimeout(showCommand, 1000);
179    }
180
181function ReallyShowTip(tooltipID, linkID, docX, docY)
182    {
183    tooltipTimer = 0;
184
185    var tooltip;
186    var link;
187
188    if (document.getElementById)
189        {
190        tooltip = document.getElementById(tooltipID);
191        link = document.getElementById(linkID);
192        }
193/*    else if (document.all)
194        {
195        tooltip = eval("document.all['" + tooltipID + "']");
196        link = eval("document.all['" + linkID + "']");
197        }
198*/
199    if (tooltip)
200        {
201        var left = GetXPosition(link);
202        var top = GetYPosition(link);
203        top += link.offsetHeight;
204
205
206        // The fallback method is to use the mouse X and Y relative to the document.  We use a separate if and test if its a number
207        // in case some browser snuck through the above if statement but didn't support everything.
208
209        if (!isFinite(top) || top == 0)
210            {
211            left = docX;
212            top = docY;
213            }
214
215        // Some spacing to get it out from under the cursor.
216
217        top += 10;
218
219        // Make sure the tooltip doesnt get smushed by being too close to the edge, or in some browsers, go off the edge of the
220        // page.  We do it here because Konqueror does get offsetWidth right even if it doesnt get the positioning right.
221
222        if (tooltip.offsetWidth != null)
223            {
224            var width = tooltip.offsetWidth;
225            var docWidth = document.body.clientWidth;
226
227            if (left + width > docWidth)
228                {  left = docWidth - width - 1;  }
229
230            // If there's a horizontal scroll bar we could go past zero because it's using the page width, not the window width.
231            if (left < 0)
232                {  left = 0;  };
233            }
234
235        MoveToPosition(tooltip, left, top);
236        tooltip.style.visibility = "visible";
237        }
238    }
239
240function HideTip(tooltipID)
241    {
242    if (tooltipTimer)
243        {
244        clearTimeout(tooltipTimer);
245        tooltipTimer = 0;
246        }
247
248    var tooltip;
249
250    if (document.getElementById)
251        {  tooltip = document.getElementById(tooltipID); }
252    else if (document.all)
253        {  tooltip = eval("document.all['" + tooltipID + "']");  }
254
255    if (tooltip)
256        {  tooltip.style.visibility = "hidden";  }
257    }
258
259
260//
261//  Blockquote fix for IE
262// ____________________________________________________________________________
263
264
265function NDOnLoad()
266    {
267    if (browserVer == "IE6")
268        {
269        var scrollboxes = document.getElementsByTagName('blockquote');
270
271        if (scrollboxes.item(0))
272            {
273            NDDoResize();
274            window.onresize=NDOnResize;
275            };
276        };
277    };
278
279
280var resizeTimer = 0;
281
282function NDOnResize()
283    {
284    if (resizeTimer != 0)
285        {  clearTimeout(resizeTimer);  };
286
287    resizeTimer = setTimeout(NDDoResize, 250);
288    };
289
290
291function NDDoResize()
292    {
293    var scrollboxes = document.getElementsByTagName('blockquote');
294
295    var i;
296    var item;
297
298    i = 0;
299    while (item = scrollboxes.item(i))
300        {
301        item.style.width = 100;
302        i++;
303        };
304
305    i = 0;
306    while (item = scrollboxes.item(i))
307        {
308        item.style.width = item.parentNode.offsetWidth;
309        i++;
310        };
311
312    clearTimeout(resizeTimer);
313    resizeTimer = 0;
314    }
315
316
317
318/* ________________________________________________________________________________________________________
319
320    Class: SearchPanel
321    ________________________________________________________________________________________________________
322
323    A class handling everything associated with the search panel.
324
325    Parameters:
326
327        name - The name of the global variable that will be storing this instance.  Is needed to be able to set timeouts.
328        mode - The mode the search is going to work in.  Pass <NaturalDocs::Builder::Base->CommandLineOption()>, so the
329                   value will be something like "HTML" or "FramedHTML".
330
331    ________________________________________________________________________________________________________
332*/
333
334
335function SearchPanel(name, mode, resultsPath)
336    {
337    if (!name || !mode || !resultsPath)
338        {  alert("Incorrect parameters to SearchPanel.");  };
339
340
341    // Group: Variables
342    // ________________________________________________________________________
343
344    /*
345        var: name
346        The name of the global variable that will be storing this instance of the class.
347    */
348    this.name = name;
349
350    /*
351        var: mode
352        The mode the search is going to work in, such as "HTML" or "FramedHTML".
353    */
354    this.mode = mode;
355
356    /*
357        var: resultsPath
358        The relative path from the current HTML page to the results page directory.
359    */
360    this.resultsPath = resultsPath;
361
362    /*
363        var: keyTimeout
364        The timeout used between a keystroke and when a search is performed.
365    */
366    this.keyTimeout = 0;
367
368    /*
369        var: keyTimeoutLength
370        The length of <keyTimeout> in thousandths of a second.
371    */
372    this.keyTimeoutLength = 500;
373
374    /*
375        var: lastSearchValue
376        The last search string executed, or an empty string if none.
377    */
378    this.lastSearchValue = "";
379
380    /*
381        var: lastResultsPage
382        The last results page.  The value is only relevant if <lastSearchValue> is set.
383    */
384    this.lastResultsPage = "";
385
386    /*
387        var: deactivateTimeout
388
389        The timeout used between when a control is deactivated and when the entire panel is deactivated.  Is necessary
390        because a control may be deactivated in favor of another control in the same panel, in which case it should stay
391        active.
392    */
393    this.deactivateTimout = 0;
394
395    /*
396        var: deactivateTimeoutLength
397        The length of <deactivateTimeout> in thousandths of a second.
398    */
399    this.deactivateTimeoutLength = 200;
400
401
402
403
404    // Group: DOM Elements
405    // ________________________________________________________________________
406
407
408    // Function: DOMSearchField
409    this.DOMSearchField = function()
410        {  return document.getElementById("MSearchField");  };
411
412    // Function: DOMSearchType
413    this.DOMSearchType = function()
414        {  return document.getElementById("MSearchType");  };
415
416    // Function: DOMPopupSearchResults
417    this.DOMPopupSearchResults = function()
418        {  return document.getElementById("MSearchResults");  };
419
420    // Function: DOMPopupSearchResultsWindow
421    this.DOMPopupSearchResultsWindow = function()
422        {  return document.getElementById("MSearchResultsWindow");  };
423
424    // Function: DOMSearchPanel
425    this.DOMSearchPanel = function()
426        {  return document.getElementById("MSearchPanel");  };
427
428
429
430
431    // Group: Event Handlers
432    // ________________________________________________________________________
433
434
435    /*
436        Function: OnSearchFieldFocus
437        Called when focus is added or removed from the search field.
438    */
439    this.OnSearchFieldFocus = function(isActive)
440        {
441        this.Activate(isActive);
442        };
443
444
445    /*
446        Function: OnSearchFieldChange
447        Called when the content of the search field is changed.
448    */
449    this.OnSearchFieldChange = function()
450        {
451        if (this.keyTimeout)
452            {
453            clearTimeout(this.keyTimeout);
454            this.keyTimeout = 0;
455            };
456
457        var searchValue = this.DOMSearchField().value.replace(/ +/g, "");
458
459        if (searchValue != this.lastSearchValue)
460            {
461            if (searchValue != "")
462                {
463                this.keyTimeout = setTimeout(this.name + ".Search()", this.keyTimeoutLength);
464                }
465            else
466                {
467                if (this.mode == "HTML")
468                    {  this.DOMPopupSearchResultsWindow().style.display = "none";  };
469                this.lastSearchValue = "";
470                };
471            };
472        };
473
474
475    /*
476        Function: OnSearchTypeFocus
477        Called when focus is added or removed from the search type.
478    */
479    this.OnSearchTypeFocus = function(isActive)
480        {
481        this.Activate(isActive);
482        };
483
484
485    /*
486        Function: OnSearchTypeChange
487        Called when the search type is changed.
488    */
489    this.OnSearchTypeChange = function()
490        {
491        var searchValue = this.DOMSearchField().value.replace(/ +/g, "");
492
493        if (searchValue != "")
494            {
495            this.Search();
496            };
497        };
498
499
500
501    // Group: Action Functions
502    // ________________________________________________________________________
503
504
505    /*
506        Function: CloseResultsWindow
507        Closes the results window.
508    */
509    this.CloseResultsWindow = function()
510        {
511        this.DOMPopupSearchResultsWindow().style.display = "none";
512        this.Activate(false, true);
513        };
514
515
516    /*
517        Function: Search
518        Performs a search.
519    */
520    this.Search = function()
521        {
522        this.keyTimeout = 0;
523
524        var searchValue = this.DOMSearchField().value.replace(/^ +/, "");
525        var searchTopic = this.DOMSearchType().value;
526
527        var pageExtension = searchValue.substr(0,1);
528
529        if (pageExtension.match(/^[a-z]/i))
530            {  pageExtension = pageExtension.toUpperCase();  }
531        else if (pageExtension.match(/^[0-9]/))
532            {  pageExtension = 'Numbers';  }
533        else
534            {  pageExtension = "Symbols";  };
535
536        var resultsPage;
537        var resultsPageWithSearch;
538        var hasResultsPage;
539
540        // indexSectionsWithContent is defined in searchdata.js
541        if (indexSectionsWithContent[searchTopic][pageExtension] == true)
542            {
543            resultsPage = this.resultsPath + '/' + searchTopic + pageExtension + '.html';
544            resultsPageWithSearch = resultsPage+'?'+escape(searchValue);
545            hasResultsPage = true;
546            }
547        else
548            {
549            resultsPage = this.resultsPath + '/NoResults.html';
550            resultsPageWithSearch = resultsPage;
551            hasResultsPage = false;
552            };
553
554        var resultsFrame;
555        if (this.mode == "HTML")
556            {  resultsFrame = window.frames.MSearchResults;  }
557        else if (this.mode == "FramedHTML")
558            {  resultsFrame = window.top.frames['Content'];  };
559
560
561        if (resultsPage != this.lastResultsPage ||
562
563            // Bug in IE.  If everything becomes hidden in a run, none of them will be able to be reshown in the next for some
564            // reason.  It counts the right number of results, and you can even read the display as "block" after setting it, but it
565            // just doesn't work in IE 6 or IE 7.  So if we're on the right page but the previous search had no results, reload the
566            // page anyway to get around the bug.
567            (browserType == "IE" && hasResultsPage &&
568                (!resultsFrame.searchResults || resultsFrame.searchResults.lastMatchCount == 0)) )
569
570            {
571            resultsFrame.location.href = resultsPageWithSearch;
572            }
573
574        // So if the results page is right and there's no IE bug, reperform the search on the existing page.  We have to check if there
575        // are results because NoResults.html doesn't have any JavaScript, and it would be useless to do anything on that page even
576        // if it did.
577        else if (hasResultsPage)
578            {
579            // We need to check if this exists in case the frame is present but didn't finish loading.
580            if (resultsFrame.searchResults)
581                {  resultsFrame.searchResults.Search(searchValue);  }
582
583            // Otherwise just reload instead of waiting.
584            else
585                {  resultsFrame.location.href = resultsPageWithSearch;  };
586            };
587
588
589        var domPopupSearchResultsWindow = this.DOMPopupSearchResultsWindow();
590
591        if (this.mode == "HTML" && domPopupSearchResultsWindow.style.display != "block")
592            {
593            var domSearchType = this.DOMSearchType();
594
595            var left = GetXPosition(domSearchType);
596            var top = GetYPosition(domSearchType) + domSearchType.offsetHeight;
597
598            MoveToPosition(domPopupSearchResultsWindow, left, top);
599            domPopupSearchResultsWindow.style.display = 'block';
600            };
601
602
603        this.lastSearchValue = searchValue;
604        this.lastResultsPage = resultsPage;
605        };
606
607
608
609    // Group: Activation Functions
610    // Functions that handle whether the entire panel is active or not.
611    // ________________________________________________________________________
612
613
614    /*
615        Function: Activate
616
617        Activates or deactivates the search panel, resetting things to their default values if necessary.  You can call this on every
618        control's OnBlur() and it will handle not deactivating the entire panel when focus is just switching between them transparently.
619
620        Parameters:
621
622            isActive - Whether you're activating or deactivating the panel.
623            ignoreDeactivateDelay - Set if you're positive the action will deactivate the panel and thus want to skip the delay.
624    */
625    this.Activate = function(isActive, ignoreDeactivateDelay)
626        {
627        // We want to ignore isActive being false while the results window is open.
628        if (isActive || (this.mode == "HTML" && this.DOMPopupSearchResultsWindow().style.display == "block"))
629            {
630            if (this.inactivateTimeout)
631                {
632                clearTimeout(this.inactivateTimeout);
633                this.inactivateTimeout = 0;
634                };
635
636            this.DOMSearchPanel().className = 'MSearchPanelActive';
637
638            var searchField = this.DOMSearchField();
639
640            if (searchField.value == 'Search')
641                 {  searchField.value = "";  }
642            }
643        else if (!ignoreDeactivateDelay)
644            {
645            this.inactivateTimeout = setTimeout(this.name + ".InactivateAfterTimeout()", this.inactivateTimeoutLength);
646            }
647        else
648            {
649            this.InactivateAfterTimeout();
650            };
651        };
652
653
654    /*
655        Function: InactivateAfterTimeout
656
657        Called by <inactivateTimeout>, which is set by <Activate()>.  Inactivation occurs on a timeout because a control may
658        receive OnBlur() when focus is really transferring to another control in the search panel.  In this case we don't want to
659        actually deactivate the panel because not only would that cause a visible flicker but it could also reset the search value.
660        So by doing it on a timeout instead, there's a short period where the second control's OnFocus() can cancel the deactivation.
661    */
662    this.InactivateAfterTimeout = function()
663        {
664        this.inactivateTimeout = 0;
665
666        this.DOMSearchPanel().className = 'MSearchPanelInactive';
667        this.DOMSearchField().value = "Search";
668
669            this.lastSearchValue = "";
670            this.lastResultsPage = "";
671        };
672    };
673
674
675
676
677/* ________________________________________________________________________________________________________
678
679   Class: SearchResults
680   _________________________________________________________________________________________________________
681
682   The class that handles everything on the search results page.
683   _________________________________________________________________________________________________________
684*/
685
686
687function SearchResults(name, mode)
688    {
689    /*
690        var: mode
691        The mode the search is going to work in, such as "HTML" or "FramedHTML".
692    */
693    this.mode = mode;
694
695    /*
696        var: lastMatchCount
697        The number of matches from the last run of <Search()>.
698    */
699    this.lastMatchCount = 0;
700
701
702    /*
703        Function: Toggle
704        Toggles the visibility of the passed element ID.
705    */
706    this.Toggle = function(id)
707        {
708        if (this.mode == "FramedHTML")
709            {  return;  };
710
711        var parentElement = document.getElementById(id);
712
713        var element = parentElement.firstChild;
714
715        while (element && element != parentElement)
716            {
717            if (element.nodeName == 'DIV' && element.className == 'ISubIndex')
718                {
719                if (element.style.display == 'block')
720                    {  element.style.display = "none";  }
721                else
722                    {  element.style.display = 'block';  }
723                };
724
725            if (element.nodeName == 'DIV' && element.hasChildNodes())
726                {  element = element.firstChild;  }
727            else if (element.nextSibling)
728                {  element = element.nextSibling;  }
729            else
730                {
731                do
732                    {
733                    element = element.parentNode;
734                    }
735                while (element && element != parentElement && !element.nextSibling);
736
737                if (element && element != parentElement)
738                    {  element = element.nextSibling;  };
739                };
740            };
741        };
742
743
744    /*
745        Function: Search
746
747        Searches for the passed string.  If there is no parameter, it takes it from the URL query.
748
749        Always returns true, since other documents may try to call it and that may or may not be possible.
750    */
751    this.Search = function(search)
752        {
753        if (!search)
754            {
755            search = window.location.search;
756            search = search.substring(1);  // Remove the leading ?
757            search = unescape(search);
758            };
759
760        search = search.replace(/^ +/, "");
761        search = search.replace(/ +$/, "");
762        search = search.toLowerCase();
763
764        if (search.match(/[^a-z0-9]/)) // Just a little speedup so it doesn't have to go through the below unnecessarily.
765            {
766            search = search.replace(/\_/g, "_und");
767            search = search.replace(/\ +/gi, "_spc");
768            search = search.replace(/\~/g, "_til");
769            search = search.replace(/\!/g, "_exc");
770            search = search.replace(/\@/g, "_att");
771            search = search.replace(/\#/g, "_num");
772            search = search.replace(/\$/g, "_dol");
773            search = search.replace(/\%/g, "_pct");
774            search = search.replace(/\^/g, "_car");
775            search = search.replace(/\&/g, "_amp");
776            search = search.replace(/\*/g, "_ast");
777            search = search.replace(/\(/g, "_lpa");
778            search = search.replace(/\)/g, "_rpa");
779            search = search.replace(/\-/g, "_min");
780            search = search.replace(/\+/g, "_plu");
781            search = search.replace(/\=/g, "_equ");
782            search = search.replace(/\{/g, "_lbc");
783            search = search.replace(/\}/g, "_rbc");
784            search = search.replace(/\[/g, "_lbk");
785            search = search.replace(/\]/g, "_rbk");
786            search = search.replace(/\:/g, "_col");
787            search = search.replace(/\;/g, "_sco");
788            search = search.replace(/\"/g, "_quo");
789            search = search.replace(/\'/g, "_apo");
790            search = search.replace(/\</g, "_lan");
791            search = search.replace(/\>/g, "_ran");
792            search = search.replace(/\,/g, "_com");
793            search = search.replace(/\./g, "_per");
794            search = search.replace(/\?/g, "_que");
795            search = search.replace(/\//g, "_sla");
796            search = search.replace(/[^a-z0-9\_]i/gi, "_zzz");
797            };
798
799        var resultRows = document.getElementsByTagName("div");
800        var matches = 0;
801
802        var i = 0;
803        while (i < resultRows.length)
804            {
805            var row = resultRows.item(i);
806
807            if (row.className == "SRResult")
808                {
809                var rowMatchName = row.id.toLowerCase();
810                rowMatchName = rowMatchName.replace(/^sr\d*_/, '');
811
812                if (search.length <= rowMatchName.length && rowMatchName.substr(0, search.length) == search)
813                    {
814                    row.style.display = "block";
815                    matches++;
816                    }
817                else
818                    {  row.style.display = "none";  };
819                };
820
821            i++;
822            };
823
824        document.getElementById("Searching").style.display="none";
825
826        if (matches == 0)
827            {  document.getElementById("NoMatches").style.display="block";  }
828        else
829            {  document.getElementById("NoMatches").style.display="none";  }
830
831        this.lastMatchCount = matches;
832
833        return true;
834        };
835    };
836
Note: See TracBrowser for help on using the repository browser.