home *** CD-ROM | disk | FTP | other *** search
/ PC World 2005 July & August / PCWorld_2005-07-08_cd.bin / komunikace / netscape / nsb-install-8-0.exe / chrome / toolkit.jar / content / global / findBar.js < prev    next >
Text File  |  2005-05-04  |  17KB  |  613 lines

  1.  
  2. const FIND_NORMAL = 0;
  3. const FIND_TYPEAHEAD = 1;
  4. const FIND_LINKS = 2;
  5.  
  6. // Global find variables
  7. var gFindMode = FIND_NORMAL;
  8. var gQuickFindTimeout = null;
  9. var gQuickFindTimeoutLength = 0;
  10. var gHighlightTimeout = null;
  11. var gUseTypeAheadFind = false;
  12. var gWrappedToTopStr = "";
  13. var gWrappedToBottomStr = "";
  14. var gNotFoundStr = "";
  15. var gTypeAheadFindBuffer = "";
  16. var gIsBack = true;
  17. var gBackProtectBuffer = 3;
  18. var gFlashFindBar = 0;
  19. var gFlashFindBarCount = 6;
  20. var gFlashFindBarTimeout = null;
  21. var gLastHighlightString = "";
  22. var gTypeAheadLinksOnly = false;
  23.  
  24. // DOMRange used during highlighting
  25. var searchRange;
  26. var startPt;
  27. var endPt;
  28.  
  29. var gTypeAheadFind = {
  30.   useTAFPref: "accessibility.typeaheadfind",
  31.   searchLinksPref: "accessibility.typeaheadfind.linksonly",
  32.   
  33.   observe: function(aSubject, aTopic, aPrefName)
  34.   {
  35.     if (aTopic != "nsPref:changed" || (aPrefName != this.useTAFPref && aPrefName != this.searchLinksPref))
  36.       return;
  37.  
  38.     var prefService = Components.classes["@mozilla.org/preferences-service;1"]
  39.                                 .getService(Components.interfaces.nsIPrefBranch);
  40.       
  41.     gUseTypeAheadFind = prefService.getBoolPref("accessibility.typeaheadfind");
  42.     gTypeAheadLinksOnly = gPrefService.getBoolPref("accessibility.typeaheadfind.linksonly");
  43.   }
  44. };
  45.  
  46. function initFindBar()
  47. {
  48.   getBrowser().addEventListener("keypress", onBrowserKeyPress, false);
  49.   getBrowser().addEventListener("mousedown", onBrowserMouseDown, false);
  50.   
  51.   var prefService = Components.classes["@mozilla.org/preferences-service;1"]
  52.                               .getService(Components.interfaces.nsIPrefBranch);
  53.  
  54.   var pbi = prefService.QueryInterface(Components.interfaces.nsIPrefBranchInternal);
  55.  
  56.   gQuickFindTimeoutLength = prefService.getIntPref("accessibility.typeaheadfind.timeout");
  57.   gFlashFindBar = prefService.getIntPref("accessibility.typeaheadfind.flashBar");
  58.  
  59.   pbi.addObserver(gTypeAheadFind.useTAFPref, gTypeAheadFind, false);
  60.   pbi.addObserver(gTypeAheadFind.searchLinksPref, gTypeAheadFind, false);
  61.   gUseTypeAheadFind = prefService.getBoolPref("accessibility.typeaheadfind");
  62.   gTypeAheadLinksOnly = prefService.getBoolPref("accessibility.typeaheadfind.linksonly");
  63. }
  64.  
  65. function uninitFindBar()
  66. {
  67.    var prefService = Components.classes["@mozilla.org/preferences-service;1"]
  68.                                .getService(Components.interfaces.nsIPrefBranch);
  69.  
  70.    var pbi = prefService.QueryInterface(Components.interfaces.nsIPrefBranchInternal);
  71.    pbi.removeObserver(gTypeAheadFind.useTAFPref, gTypeAheadFind);
  72.    pbi.removeObserver(gTypeAheadFind.searchLinksPref, gTypeAheadFind);
  73.  
  74.    getBrowser().removeEventListener("keypress", onBrowserKeyPress, false);
  75.    getBrowser().removeEventListener("mousedown", onBrowserMouseDown, false);
  76. }
  77.  
  78. function toggleHighlight(aHighlight)
  79. {
  80.   var word = document.getElementById("find-field").value;
  81.   if (aHighlight) {
  82.     highlightDoc('yellow', word);
  83.   } else {
  84.     highlightDoc(null, null);
  85.     gLastHighlightString = null;
  86.   }
  87. }
  88.  
  89. function highlightDoc(color, word, win)
  90. {
  91.   if (!win)
  92.     win = window._content; 
  93.  
  94.   for (var i = 0; win.frames && i < win.frames.length; i++) {
  95.     highlightDoc(color, word, win.frames[i]);
  96.   }
  97.  
  98.   var doc = win.document;
  99.   if (!doc)
  100.     return;
  101.  
  102.   if (!("body" in doc))
  103.     return;
  104.  
  105.   var body = doc.body;
  106.   
  107.   var count = body.childNodes.length;
  108.   searchRange = doc.createRange();
  109.   startPt = doc.createRange();
  110.   endPt = doc.createRange();
  111.  
  112.   searchRange.setStart(body, 0);
  113.   searchRange.setEnd(body, count);
  114.  
  115.   startPt.setStart(body, 0);
  116.   startPt.setEnd(body, 0);
  117.   endPt.setStart(body, count);
  118.   endPt.setEnd(body, count);
  119.  
  120.   if (!color) {
  121.     // Remove highlighting.  We use the find API again rather than
  122.     // searching for our span elements by id so that we gain access to the
  123.     // anonymous content that nsIFind searches.
  124.  
  125.     if (!gLastHighlightString)
  126.       return;
  127.  
  128.     var retRange = null;
  129.     var finder = Components.classes["@mozilla.org/embedcomp/rangefind;1"].createInstance()
  130.                          .QueryInterface(Components.interfaces.nsIFind);
  131.  
  132.     while ((retRange = finder.Find(gLastHighlightString, searchRange,startPt, endPt))) {
  133.       var startContainer = retRange.startContainer;
  134.       var elem = null;
  135.       try {
  136.         elem = startContainer.parentNode;
  137.       }
  138.       catch (e) { }
  139.  
  140.       if (elem && elem.getAttribute("id") == "__firefox-findbar-search-id") {
  141.         var child = null;
  142.         var docfrag = doc.createDocumentFragment();
  143.         var next = elem.nextSibling;
  144.         var parent = elem.parentNode;
  145.  
  146.         while ((child = elem.firstChild)) {
  147.           docfrag.appendChild(child);
  148.         }
  149.  
  150.         startPt = doc.createRange();
  151.         startPt.setStartAfter(elem);
  152.  
  153.         parent.removeChild(elem);
  154.         parent.insertBefore(docfrag, next);
  155.       }
  156.       else {
  157.         // Somehow we didn't highlight this instance; just skip it.
  158.         startPt = doc.createRange();
  159.         startPt.setStart(retRange.endContainer, retRange.endOffset);
  160.       }
  161.  
  162.       startPt.collapse(true);
  163.     }
  164.     return;
  165.   }
  166.  
  167.   var baseNode = doc.createElement("span");
  168.   baseNode.setAttribute("style", "background-color: " + color + ";");
  169.   baseNode.setAttribute("id", "__firefox-findbar-search-id");
  170.  
  171.   highlightText(word, baseNode);
  172. }
  173.  
  174. function highlightText(word, baseNode)
  175. {
  176.   var retRange = null;
  177.   var finder = Components.classes["@mozilla.org/embedcomp/rangefind;1"].createInstance()
  178.                          .QueryInterface(Components.interfaces.nsIFind);
  179.  
  180.   finder.caseSensitive = document.getElementById("find-case-sensitive").checked;
  181.  
  182.   while((retRange = finder.Find(word, searchRange, startPt, endPt))) {
  183.     // Highlight
  184.     var nodeSurround = baseNode.cloneNode(true);
  185.     var node = highlight(retRange, nodeSurround);
  186.     startPt = node.ownerDocument.createRange();
  187.     startPt.setStart(node, node.childNodes.length);
  188.     startPt.setEnd(node, node.childNodes.length);
  189.   }
  190.   
  191.   gLastHighlightString = word;
  192. }
  193.  
  194. function highlight(range, node)
  195. {
  196.   var startContainer = range.startContainer;
  197.   var startOffset = range.startOffset;
  198.   var endOffset = range.endOffset;
  199.   var docfrag = range.extractContents();
  200.   var before = startContainer.splitText(startOffset);
  201.   var parent = before.parentNode;
  202.   node.appendChild(docfrag);
  203.   parent.insertBefore(node, before);
  204.   return node;
  205. }
  206.  
  207. function getSelectionControllerForFindToolbar(ds)
  208. {
  209.   var display = ds.QueryInterface(Components.interfaces.nsIInterfaceRequestor).getInterface(Components.interfaces.nsISelectionDisplay);
  210.   if (!display)
  211.     return null;
  212.   return display.QueryInterface(Components.interfaces.nsISelectionController);
  213. }
  214.  
  215. function toggleCaseSensitivity(aCaseSensitive)
  216. {
  217.   var fastFind = getBrowser().fastFind;
  218.   fastFind.caseSensitive = aCaseSensitive;
  219.   
  220.   if (gFindMode != FIND_NORMAL)
  221.     setFindCloseTimeout();
  222. }
  223.   
  224. function changeSelectionColor(aAttention)
  225. {
  226.   var ds = getBrowser().docShell;
  227.   var dsEnum = ds.getDocShellEnumerator(Components.interfaces.nsIDocShellTreeItem.typeContent,
  228.                                         Components.interfaces.nsIDocShell.ENUMERATE_FORWARDS);
  229.   while (dsEnum.hasMoreElements()) {
  230.     ds = dsEnum.getNext().QueryInterface(Components.interfaces.nsIDocShell);
  231.     var controller = getSelectionControllerForFindToolbar(ds);
  232.     if (!controller)
  233.       continue;
  234.     const selCon = Components.interfaces.nsISelectionController;
  235.     controller.setDisplaySelection(aAttention? selCon.SELECTION_ATTENTION : selCon.SELECTION_ON);
  236.   }
  237. }
  238.  
  239. function openFindBar()
  240. {
  241.   if (!gNotFoundStr || !gWrappedToTopStr || !gWrappedToBottomStr) {
  242.     var bundle = document.getElementById("bundle_findBar");
  243.     gNotFoundStr = bundle.getString("NotFound");
  244.     gWrappedToTopStr = bundle.getString("WrappedToTop");
  245.     gWrappedToBottomStr = bundle.getString("WrappedToBottom");
  246.   }
  247.  
  248.   var findToolbar = document.getElementById("FindToolbar");
  249.   if (findToolbar.hidden) {
  250.     findToolbar.hidden = false;
  251.   
  252.     var statusIcon = document.getElementById("find-status-icon");
  253.     var statusText = document.getElementById("find-status");
  254.     var findField = document.getElementById("find-field");
  255.     findField.removeAttribute("status");
  256.     statusIcon.removeAttribute("status");
  257.     statusText.value = "";
  258.  
  259.     return true;
  260.   }
  261.   return false;
  262. }
  263.  
  264. function focusFindBar()
  265. {
  266.   var findField = document.getElementById("find-field");
  267.   findField.focus();    
  268. }
  269.  
  270. function selectFindBar()
  271. {
  272.   var findField = document.getElementById("find-field");
  273.   findField.select();    
  274. }
  275.  
  276. function closeFindBar()
  277. {
  278.   var findField = document.getElementById("find-field");
  279.   var ww = Components.classes["@mozilla.org/embedcomp/window-watcher;1"]
  280.                      .getService(Components.interfaces.nsIWindowWatcher);
  281.   if (window == ww.activeWindow && document.commandDispatcher.focusedElement &&
  282.       document.commandDispatcher.focusedElement.parentNode.parentNode == findField) {
  283.     _content.focus();
  284.   }
  285.  
  286.   var findToolbar = document.getElementById("FindToolbar");
  287.   findToolbar.hidden = true;
  288.   gTypeAheadFindBuffer = "";
  289.   changeSelectionColor(false);
  290.   if (gQuickFindTimeout) {
  291.     clearTimeout(gQuickFindTimeout);
  292.     gQuickFindTimeout = null;    
  293.   } 
  294. }
  295.  
  296. function shouldFastFind(evt)
  297. {
  298.   if (evt.ctrlKey || evt.altKey || evt.metaKey || evt.getPreventDefault())
  299.     return false;
  300.     
  301.   var elt = document.commandDispatcher.focusedElement;
  302.   if (elt) {
  303.     var ln = elt.localName.toLowerCase();
  304.     if (ln == "input" || ln == "textarea" || ln == "select" || ln == "button" || ln == "isindex")
  305.       return false;
  306.   }
  307.   
  308.   var win = document.commandDispatcher.focusedWindow;
  309.   if (win && win.document.designMode == "on")
  310.     return false;
  311.   
  312.   return true;
  313. }
  314.  
  315. function onFindBarFocus()
  316. {
  317.   toggleLinkFocus(false);
  318. }
  319.  
  320. function onFindBarBlur()
  321. {
  322.   toggleLinkFocus(true);
  323.   changeSelectionColor(false);
  324. }
  325.  
  326. function onBrowserMouseDown(evt)
  327. {
  328.   var findToolbar = document.getElementById("FindToolbar");
  329.   if (!findToolbar.hidden && gFindMode != FIND_NORMAL)
  330.     closeFindBar();
  331. }
  332.  
  333. function onBrowserKeyPress(evt)
  334. {  
  335.   // Check focused elt
  336.   if (!shouldFastFind(evt))
  337.     return;
  338.   
  339.   var findField = document.getElementById("find-field");
  340.   if (gFindMode != FIND_NORMAL && gQuickFindTimeout) {    
  341.     if (evt.keyCode == 8) { // Backspace
  342.       if (findField.value) {
  343.         findField.value = findField.value.substr(0, findField.value.length - 1);
  344.         gIsBack = true;   
  345.         gBackProtectBuffer = 3;
  346.       }
  347.       else if (gBackProtectBuffer > 0) {
  348.         gBackProtectBuffer--;
  349.       }
  350.       
  351.       if (gIsBack || gBackProtectBuffer > 0)
  352.         evt.preventDefault();
  353.         
  354.       find(findField.value);
  355.     }
  356.     else if (evt.keyCode == 27) { // Escape
  357.       closeFindBar();
  358.       evt.preventDefault();
  359.     }
  360.     else if (evt.charCode) {
  361.       if (evt.charCode == 32) // Space
  362.         evt.preventDefault();
  363.         
  364.       findField.value += String.fromCharCode(evt.charCode);
  365.       find(findField.value);
  366.     }
  367.     return;
  368.   }
  369.   
  370.   if (evt.charCode == 39 /* ' */ || evt.charCode == 47 /* / */ || (gUseTypeAheadFind && evt.charCode && evt.charCode != 32)) {   
  371.     gFindMode = (evt.charCode == 39 || (gTypeAheadLinksOnly && evt.charCode != 47)) ? FIND_LINKS : FIND_TYPEAHEAD;
  372.     toggleLinkFocus(true);
  373.     if (openFindBar()) {      
  374.       setFindCloseTimeout();      
  375.       if (gUseTypeAheadFind && evt.charCode != 39 && evt.charCode != 47) {
  376.         gTypeAheadFindBuffer += String.fromCharCode(evt.charCode);        
  377.         findField.value = gTypeAheadFindBuffer;
  378.         find(findField.value);
  379.       }
  380.       else {
  381.         findField.value = "";
  382.       }
  383.     }
  384.     else {
  385.       if (gFindMode == FIND_NORMAL) {
  386.         selectFindBar();      
  387.         focusFindBar();
  388.       }
  389.       else {
  390.         findField.value = String.fromCharCode(evt.charCode);
  391.         find(findField.value);
  392.       }
  393.     }        
  394.   }
  395. }
  396.  
  397. function toggleLinkFocus(aFocusLinks)
  398. {
  399.   var fastFind = getBrowser().fastFind;
  400.   fastFind.focusLinks = aFocusLinks;
  401. }
  402.  
  403. function onBrowserKeyUp(evt)
  404. {
  405.   if (evt.keyCode == 8)
  406.     gIsBack = false;
  407. }
  408.  
  409. function onFindBarKeyPress(evt)
  410. {
  411.   if (evt.keyCode == KeyEvent.DOM_VK_RETURN) {
  412.     var findString = document.getElementById("find-field");
  413.     if (!findString.value)
  414.       return;
  415.       
  416.     if (evt.ctrlKey) {
  417.       document.getElementById("highlight").click();
  418.       return;
  419.     }
  420.     
  421.     if (evt.shiftKey)
  422.       findPrevious();
  423.     else
  424.       findNext();
  425.   }
  426.   else if (evt.keyCode == KeyEvent.DOM_VK_ESCAPE) {
  427.     closeFindBar();
  428.     evt.preventDefault();
  429.   } 
  430.   else if (evt.keyCode == KeyEvent.DOM_VK_PAGE_UP) {
  431.     window.top._content.scrollByPages(-1);
  432.     evt.preventDefault();
  433.   }
  434.   else if (evt.keyCode == KeyEvent.DOM_VK_PAGE_DOWN) {
  435.     window.top._content.scrollByPages(1);
  436.     evt.preventDefault();
  437.   }
  438.   else if (evt.keyCode == KeyEvent.DOM_VK_UP) {
  439.     window.top._content.scrollByLines(-1);
  440.     evt.preventDefault();
  441.   }
  442.   else if (evt.keyCode == KeyEvent.DOM_VK_DOWN) {
  443.     window.top._content.scrollByLines(1);
  444.     evt.preventDefault();
  445.   }
  446.  
  447.  
  448. function enableFindButtons(aEnable)
  449. {
  450.   var findNext = document.getElementById("find-next");
  451.   var findPrev = document.getElementById("find-previous");  
  452.   var highlight = document.getElementById("highlight");
  453.   findNext.disabled = findPrev.disabled = highlight.disabled = !aEnable;  
  454. }
  455.  
  456. function find(val)
  457. {
  458.   if (!val)
  459.     val = document.getElementById("find-field").value;
  460.     
  461.   enableFindButtons(val);
  462.  
  463.   var highlightBtn = document.getElementById("highlight");
  464.   if (highlightBtn.checked)
  465.     setHighlightTimeout();
  466.         
  467.   changeSelectionColor(true);
  468.   var fastFind = getBrowser().fastFind;  
  469.   var res = fastFind.find(val, gFindMode == FIND_LINKS);
  470.   updateStatus(res, true);
  471.   
  472.   if (gFindMode != FIND_NORMAL)
  473.     setFindCloseTimeout();
  474. }
  475.  
  476. function flashFindBar()
  477. {
  478.   var findToolbar = document.getElementById("FindToolbar");
  479.   if (gFlashFindBarCount-- == 0) {
  480.     clearInterval(gFlashFindBarTimeout);
  481.     findToolbar.removeAttribute("flash");
  482.     gFlashFindBarCount = 6;
  483.     return true;
  484.   }
  485.  
  486.   findToolbar.setAttribute("flash", (gFlashFindBarCount % 2 == 0) ? "false" : "true");
  487. }
  488.  
  489. function onFindCmd()
  490. {
  491.   gFindMode = FIND_NORMAL;
  492.   openFindBar();
  493.   if (gFlashFindBar) {
  494.     gFlashFindBarTimeout = setInterval(flashFindBar, 500);
  495.     var prefService = Components.classes["@mozilla.org/preferences-service;1"]
  496.                                 .getService(Components.interfaces.nsIPrefBranch);
  497.  
  498.     prefService.setIntPref("accessibility.typeaheadfind.flashBar", --gFlashFindBar);
  499.   }
  500.   selectFindBar();
  501.   focusFindBar();
  502. }
  503.  
  504. function onFindAgainCmd()
  505. {
  506.   var findString = getBrowser().findString;
  507.   if (!findString)
  508.     return onFindCmd();
  509.  
  510.   var res = findNext();
  511.   if (res == Components.interfaces.nsITypeAheadFind.FIND_NOTFOUND) {
  512.     if (openFindBar()) {
  513.       focusFindBar();
  514.       selectFindBar();
  515.       if (gFindMode != FIND_NORMAL)
  516.         setFindCloseTimeout();
  517.       
  518.       updateStatus(res, true);
  519.     }
  520.   }
  521. }
  522.  
  523. function onFindPreviousCmd()
  524. {
  525.   var findString = getBrowser().findString;
  526.   if (!findString)
  527.     return onFindCmd();
  528.  
  529.   var res = findPrevious();
  530.   if (res == Components.interfaces.nsITypeAheadFind.FIND_NOTFOUND) {
  531.     if (openFindBar()) {
  532.       focusFindBar();
  533.       selectFindBar();
  534.       if (gFindMode != FIND_NORMAL)
  535.         setFindCloseTimeout();
  536.       
  537.       updateStatus(res, false);
  538.     }
  539.   }
  540. }
  541.  
  542. function setHighlightTimeout()
  543. {
  544.   if (gHighlightTimeout)
  545.     clearTimeout(gHighlightTimeout);
  546.   gHighlightTimeout = setTimeout(function() { toggleHighlight(false); toggleHighlight(true); }, 500);  
  547. }
  548.  
  549. function isFindBarVisible()
  550. {
  551.   var findBar = document.getElementById("FindToolbar");
  552.   return !findBar.hidden;
  553. }
  554.  
  555. function findNext()
  556. {
  557.   changeSelectionColor(true);
  558.   var fastFind = getBrowser().fastFind; 
  559.   var res = fastFind.findNext();  
  560.   updateStatus(res, true);
  561.     
  562.   if (gFindMode != FIND_NORMAL && isFindBarVisible())
  563.     setFindCloseTimeout();
  564.   
  565.   return res;
  566. }
  567.  
  568. function findPrevious()
  569. {
  570.   changeSelectionColor(true);
  571.   var fastFind = getBrowser().fastFind;
  572.   var res = fastFind.findPrevious();
  573.   updateStatus(res, false);
  574.   
  575.   if (gFindMode != FIND_NORMAL && isFindBarVisible())
  576.     setFindCloseTimeout();
  577.   
  578.   return res;
  579. }
  580.  
  581. function updateStatus(res, findNext)
  582. {
  583.   var findBar = document.getElementById("FindToolbar");
  584.   var field = document.getElementById("find-field");
  585.   var statusIcon = document.getElementById("find-status-icon");
  586.   var statusText = document.getElementById("find-status");
  587.   switch(res) {
  588.     case Components.interfaces.nsITypeAheadFind.FIND_WRAPPED:
  589.       statusIcon.setAttribute("status", "wrapped");      
  590.       statusText.value = findNext ? gWrappedToTopStr : gWrappedToBottomStr;
  591.       break;
  592.     case Components.interfaces.nsITypeAheadFind.FIND_NOTFOUND:
  593.       statusIcon.setAttribute("status", "notfound");
  594.       statusText.value = gNotFoundStr;
  595.       field.setAttribute("status", "notfound");      
  596.       break;
  597.     case Components.interfaces.nsITypeAheadFind.FIND_FOUND:
  598.     default:
  599.       statusIcon.removeAttribute("status");      
  600.       statusText.value = "";
  601.       field.removeAttribute("status");
  602.       break;
  603.   }
  604. }
  605.  
  606. function setFindCloseTimeout()
  607. {
  608.   if (gQuickFindTimeout)
  609.     clearTimeout(gQuickFindTimeout);
  610.   gQuickFindTimeout = setTimeout(function() { if (gFindMode != FIND_NORMAL) closeFindBar(); }, gQuickFindTimeoutLength);
  611. }
  612.