home *** CD-ROM | disk | FTP | other *** search
/ PC World 2007 March / PCWorld_2007-03_cd.bin / komunikace / nvu / nvu-1.0-cs-CZ.win32.installer.exe / chrome / toolkit.jar / content / global / viewSource.js < prev    next >
Text File  |  2004-10-27  |  17KB  |  576 lines

  1.  
  2. const pageLoaderIface = Components.interfaces.nsIWebPageDescriptor;
  3. const nsISelectionPrivate = Components.interfaces.nsISelectionPrivate;
  4. const nsISelectionController = Components.interfaces.nsISelectionController;
  5. var gBrowser = null;
  6. var gViewSourceBundle = null;
  7. var gPrefs = null;
  8.  
  9. var gLastLineFound = '';
  10. var gGoToLine = 0;
  11.  
  12. try {
  13.   var prefService = Components.classes["@mozilla.org/preferences-service;1"]
  14.                               .getService(Components.interfaces.nsIPrefService);
  15.   gPrefs = prefService.getBranch(null);
  16. } catch (ex) {
  17. }
  18.  
  19. var gSelectionListener = {
  20.   timeout: 0,
  21.   notifySelectionChanged: function(doc, sel, reason)
  22.   {
  23.     // Coalesce notifications within 100ms intervals.
  24.     if (!this.timeout)
  25.       this.timeout = setTimeout(updateStatusBar, 100);
  26.   }
  27. }
  28.  
  29. function onLoadViewSource() 
  30. {
  31.   viewSource(window.arguments[0]);
  32.   document.commandDispatcher.focusedWindow = content;
  33. }
  34.  
  35. function onUnloadViewSource()
  36. {
  37. }
  38.  
  39. function getBrowser()
  40. {
  41.   if (!gBrowser)
  42.     gBrowser = document.getElementById("content");
  43.   return gBrowser;
  44. }
  45.  
  46. function getSelectionController()
  47. {
  48.   return getBrowser().docShell
  49.     .QueryInterface(Components.interfaces.nsIInterfaceRequestor)
  50.     .getInterface(Components.interfaces.nsISelectionDisplay)
  51.     .QueryInterface(nsISelectionController);
  52.  
  53. }
  54.  
  55. function getViewSourceBundle()
  56. {
  57.   if (!gViewSourceBundle)
  58.     gViewSourceBundle = document.getElementById("viewSourceBundle");
  59.   return gViewSourceBundle;
  60. }
  61.  
  62. function viewSource(url)
  63. {
  64.   if (!url)
  65.     return false; // throw Components.results.NS_ERROR_FAILURE;
  66.  
  67.   getBrowser().addEventListener("unload", onUnloadContent, true);
  68.   getBrowser().addEventListener("load", onLoadContent, true);
  69.  
  70.   var loadFromURL = true;
  71.   //
  72.   // Parse the 'arguments' supplied with the dialog.
  73.   //    arg[0] - URL string.
  74.   //    arg[1] - Charset value in the form 'charset=xxx'.
  75.   //    arg[2] - Page descriptor used to load content from the cache.
  76.   //    arg[3] - Line number to go to.
  77.   //
  78.   if ("arguments" in window) {
  79.     var arg;
  80.     //
  81.     // Set the charset of the viewsource window...
  82.     //
  83.     if (window.arguments.length >= 2) {
  84.       arg = window.arguments[1];
  85.  
  86.       try {
  87.         if (typeof(arg) == "string" && arg.indexOf('charset=') != -1) {
  88.           var arrayArgComponents = arg.split('=');
  89.           if (arrayArgComponents) {
  90.             //we should "inherit" the charset menu setting in a new window
  91.             getMarkupDocumentViewer().defaultCharacterSet = arrayArgComponents[1];
  92.           } 
  93.         }
  94.       } catch (ex) {
  95.         // Ignore the failure and keep processing arguments...
  96.       }
  97.     }
  98.     //
  99.     // Get any specified line to jump to.
  100.     //
  101.     if (window.arguments.length >= 4) {
  102.       arg = window.arguments[3];
  103.       gGoToLine = parseInt(arg);
  104.     }
  105.     //
  106.     // Use the page descriptor to load the content from the cache (if
  107.     // available).
  108.     //
  109.     if (window.arguments.length >= 3) {
  110.       arg = window.arguments[2];
  111.  
  112.       try {
  113.         if (typeof(arg) == "object" && arg != null) {
  114.           var PageLoader = getBrowser().webNavigation.QueryInterface(pageLoaderIface);
  115.  
  116.           //
  117.           // Load the page using the page descriptor rather than the URL.
  118.           // This allows the content to be fetched from the cache (if
  119.           // possible) rather than the network...
  120.           //
  121.           PageLoader.LoadPage(arg, pageLoaderIface.DISPLAY_AS_SOURCE);
  122.           // The content was successfully loaded from the page cookie.
  123.           loadFromURL = false;
  124.         }
  125.       } catch(ex) {
  126.         // Ignore the failure.  The content will be loaded via the URL
  127.         // that was supplied in arg[0].
  128.       }
  129.     }
  130.   }
  131.  
  132.   if (loadFromURL) {
  133.     //
  134.     // Currently, an exception is thrown if the URL load fails...
  135.     //
  136.     var loadFlags = Components.interfaces.nsIWebNavigation.LOAD_FLAGS_NONE;
  137.     var viewSrcUrl = "view-source:" + url;
  138.     getBrowser().webNavigation.loadURI(viewSrcUrl, loadFlags, null, null, null);
  139.   }
  140.  
  141.   //check the view_source.wrap_long_lines pref and set the menuitem's checked attribute accordingly
  142.   if (gPrefs) {
  143.     try {
  144.       var wraplonglinesPrefValue = gPrefs.getBoolPref("view_source.wrap_long_lines");
  145.  
  146.       if (wraplonglinesPrefValue)
  147.         document.getElementById('menu_wrapLongLines').setAttribute("checked", "true");
  148.     } catch (ex) {
  149.     }
  150.     try {
  151.       document.getElementById("menu_highlightSyntax").setAttribute("checked", gPrefs.getBoolPref("view_source.syntax_highlight"));
  152.     } catch (ex) {
  153.     }
  154.   } else {
  155.     document.getElementById("menu_highlightSyntax").setAttribute("hidden", "true");
  156.   }
  157.  
  158.   window._content.focus();
  159.  
  160.   return true;
  161. }
  162.  
  163. function onLoadContent()
  164. {
  165.   //
  166.   // If the view source was opened with a "go to line" argument.
  167.   //
  168.   if (gGoToLine > 0) {
  169.     goToLine(gGoToLine);
  170.     gGoToLine = 0;
  171.   }
  172.   document.getElementById('cmd_goToLine').removeAttribute('disabled');
  173.  
  174.   // Register a listener so that we can show the caret position on the status bar.
  175.   window._content.getSelection()
  176.    .QueryInterface(nsISelectionPrivate)
  177.    .addSelectionListener(gSelectionListener);
  178. }
  179.  
  180. function onUnloadContent()
  181. {
  182.   //
  183.   // Disable "go to line" while reloading due to e.g. change of charset
  184.   // or toggling of syntax highlighting.
  185.   //
  186.   document.getElementById('cmd_goToLine').setAttribute('disabled', 'true');
  187. }
  188.  
  189. function ViewSourceClose()
  190. {
  191.   window.close();
  192. }
  193.  
  194. function BrowserReload()
  195. {
  196.   // Reload will always reload from cache which is probably not what's wanted
  197.   BrowserReloadSkipCache();
  198. }
  199.  
  200. function BrowserReloadSkipCache()
  201. {
  202.   const webNavigation = getBrowser().webNavigation;
  203.   webNavigation.reload(webNavigation.LOAD_FLAGS_BYPASS_PROXY | webNavigation.LOAD_FLAGS_BYPASS_CACHE);
  204. }
  205.  
  206. // Strips the |view-source:| for editPage()
  207. function ViewSourceEditPage()
  208. {
  209.   editPage(window.content.location.href.substring(12), window, false);
  210. }
  211.  
  212. // Strips the |view-source:| for saveURL()
  213. function ViewSourceSavePage()
  214. {
  215.   saveURL(window.content.location.href.substring(12), null, "SaveLinkTitle");
  216. }
  217.  
  218. function onEnterPP()
  219. {
  220.   var toolbox = document.getElementById("viewSource-toolbox");
  221.   toolbox.hidden = true;
  222. }
  223.  
  224. function onExitPP()
  225. {
  226.   var toolbox = document.getElementById("viewSource-toolbox");
  227.   toolbox.hidden = false;
  228. }
  229.  
  230. function ViewSourceGoToLine()
  231. {
  232.   var promptService = Components.classes["@mozilla.org/embedcomp/prompt-service;1"]
  233.         .getService(Components.interfaces.nsIPromptService);
  234.   var viewSourceBundle = getViewSourceBundle();
  235.  
  236.   var input = {value:gLastLineFound};
  237.   for (;;) {
  238.     var ok = promptService.prompt(
  239.         window,
  240.         viewSourceBundle.getString("goToLineTitle"),
  241.         viewSourceBundle.getString("goToLineText"),
  242.         input,
  243.         null,
  244.         {value:0});
  245.  
  246.     if (!ok) return;
  247.  
  248.     var line = parseInt(input.value);
  249.  
  250.     if (!(line > 0)) {
  251.       promptService.alert(window,
  252.           viewSourceBundle.getString("invalidInputTitle"),
  253.           viewSourceBundle.getString("invalidInputText"));
  254.   
  255.       continue;
  256.     }
  257.  
  258.     var found = goToLine(line);
  259.  
  260.     if (found) {
  261.       break;
  262.     }
  263.  
  264.     promptService.alert(window,
  265.         viewSourceBundle.getString("outOfRangeTitle"),
  266.         viewSourceBundle.getString("outOfRangeText"));
  267.   }
  268. }
  269.  
  270. function goToLine(line)
  271. {
  272.   var viewsource = window._content.document.body;
  273.  
  274.   //
  275.   // The source document is made up of a number of pre elements with
  276.   // id attributes in the format <pre id="line123">, meaning that
  277.   // the first line in the pre element is number 123.
  278.   // Do binary search to find the pre element containing the line.
  279.   //
  280.   var pre;
  281.   for (var lbound = 0, ubound = viewsource.childNodes.length; ; ) {
  282.     var middle = (lbound + ubound) >> 1;
  283.     pre = viewsource.childNodes[middle];
  284.  
  285.     var firstLine = parseInt(pre.id.substring(4));
  286.  
  287.     if (lbound == ubound - 1) {
  288.       break;
  289.     }
  290.  
  291.     if (line >= firstLine) {
  292.       lbound = middle;
  293.     } else {
  294.       ubound = middle;
  295.     }
  296.   }
  297.  
  298.   var result = {};
  299.   var found = findLocation(pre, line, null, -1, false, result);
  300.  
  301.   if (!found) {
  302.     return false;
  303.   }
  304.  
  305.   var selection = window._content.getSelection();
  306.   selection.removeAllRanges();
  307.  
  308.   // In our case, the range's startOffset is after "\n" on the previous line.
  309.   // Tune the selection at the beginning of the next line and do some tweaking
  310.   // to position the focusNode and the caret at the beginning of the line.
  311.  
  312.   selection.QueryInterface(nsISelectionPrivate)
  313.     .interlinePosition = true;    
  314.  
  315.   selection.addRange(result.range);
  316.  
  317.   if (!selection.isCollapsed) {
  318.     selection.collapseToEnd();
  319.  
  320.     var offset = result.range.startOffset;
  321.     var node = result.range.startContainer;
  322.     if (offset < node.data.length) {
  323.       // The same text node spans across the "\n", just focus where we were.
  324.       selection.extend(node, offset);
  325.     }
  326.     else {
  327.       // There is another tag just after the "\n", hook there. We need
  328.       // to focus a safe point because there are edgy cases such as
  329.       // <span>...\n</span><span>...</span> vs.
  330.       // <span>...\n<span>...</span></span><span>...</span>
  331.       node = node.nextSibling ? node.nextSibling : node.parentNode.nextSibling;
  332.       selection.extend(node, 0);
  333.     }
  334.   }
  335.  
  336.   var selCon = getSelectionController();
  337.   selCon.setDisplaySelection(nsISelectionController.SELECTION_ON);
  338.   selCon.setCaretEnabled(true);
  339.   selCon.setCaretVisibilityDuringSelection(true);
  340.  
  341.   // Scroll the beginning of the line into view.
  342.   selCon.scrollSelectionIntoView(
  343.     nsISelectionController.SELECTION_NORMAL,
  344.     nsISelectionController.SELECTION_FOCUS_REGION,
  345.     true);
  346.  
  347.   gLastLineFound = line;
  348.  
  349.   //pch: don't update the status bar for now
  350.   //document.getElementById("statusbar-line-col").label = getViewSourceBundle()
  351.   //    .getFormattedString("statusBarLineCol", [line, 1]);
  352.  
  353.   return true;
  354. }
  355.  
  356. function updateStatusBar()
  357. {
  358.   // Reset the coalesce flag.
  359.   gSelectionListener.timeout = 0;
  360.  
  361.   var statusBarField = document.getElementById("statusbar-line-col");
  362.  
  363.   var selection = window._content.getSelection();
  364.   if (!selection.focusNode) {
  365.     statusBarField.label = '';
  366.     return;
  367.   }
  368.   if (selection.focusNode.nodeType != Node.TEXT_NODE) {
  369.     return;
  370.   }
  371.  
  372.   var selCon = getSelectionController();
  373.   selCon.setDisplaySelection(nsISelectionController.SELECTION_ON);
  374.   selCon.setCaretEnabled(true);
  375.   selCon.setCaretVisibilityDuringSelection(true);
  376.  
  377.   var interlinePosition = selection
  378.       .QueryInterface(nsISelectionPrivate).interlinePosition;
  379.  
  380.   var result = {};
  381.   findLocation(null, -1, 
  382.       selection.focusNode, selection.focusOffset, interlinePosition, result);
  383.  
  384.   //pch no status bar for now
  385.   return;
  386.   statusBarField.label = getViewSourceBundle()
  387.       .getFormattedString("statusBarLineCol", [result.line, result.col]);
  388. }
  389.  
  390. //
  391. // Loops through the text lines in the pre element. The arguments are either
  392. // (pre, line) or (node, offset, interlinePosition). result is an out
  393. // argument. If (pre, line) are specified (and node == null), result.range is
  394. // a range spanning the specified line. If the (node, offset,
  395. // interlinePosition) are specified, result.line and result.col are the line
  396. // and column number of the specified offset in the specified node relative to
  397. // the whole file.
  398. //
  399. function findLocation(pre, line, node, offset, interlinePosition, result)
  400. {
  401.   if (node && !pre) {
  402.     //
  403.     // Look upwards to find the current pre element.
  404.     //
  405.     for (pre = node;
  406.          pre.nodeName != "PRE";
  407.          pre = pre.parentNode);
  408.   }
  409.  
  410.   //
  411.   // The source document is made up of a number of pre elements with
  412.   // id attributes in the format <pre id="line123">, meaning that
  413.   // the first line in the pre element is number 123.
  414.   //
  415.   var curLine = parseInt(pre.id.substring(4));
  416.  
  417.   //
  418.   // Walk through each of the text nodes and count newlines.
  419.   //
  420.   var treewalker = window._content.document
  421.       .createTreeWalker(pre, NodeFilter.SHOW_TEXT, null, false);
  422.  
  423.   //
  424.   // The column number of the first character in the current text node.
  425.   //
  426.   var firstCol = 1;
  427.  
  428.   var found = false;
  429.   for (var textNode = treewalker.firstChild();
  430.        textNode && !found;
  431.        textNode = treewalker.nextNode()) {
  432.  
  433.     //
  434.     // \r is not a valid character in the DOM, so we only check for \n.
  435.     //
  436.     var lineArray = textNode.data.split(/\n/);
  437.     var lastLineInNode = curLine + lineArray.length - 1;
  438.  
  439.     //
  440.     // Check if we can skip the text node without further inspection.
  441.     //
  442.     if (node ? (textNode != node) : (lastLineInNode < line)) {
  443.       if (lineArray.length > 1) {
  444.         firstCol = 1;
  445.       }
  446.       firstCol += lineArray[lineArray.length - 1].length;
  447.       curLine = lastLineInNode;
  448.       continue;
  449.     }
  450.  
  451.     //
  452.     // curPos is the offset within the current text node of the first
  453.     // character in the current line.
  454.     //
  455.     for (var i = 0, curPos = 0;
  456.          i < lineArray.length;
  457.          curPos += lineArray[i++].length + 1) {
  458.  
  459.       if (i > 0) {
  460.         curLine++;
  461.       }
  462.  
  463.       if (node) {
  464.         if (offset >= curPos && offset <= curPos + lineArray[i].length) {
  465.           //
  466.           // If we are right after the \n of a line and interlinePosition is
  467.           // false, the caret looks as if it were at the end of the previous
  468.           // line, so we display that line and column instead.
  469.           //
  470.           if (i > 0 && offset == curPos && !interlinePosition) {
  471.             result.line = curLine - 1;
  472.             var prevPos = curPos - lineArray[i - 1].length;
  473.             result.col = (i == 1 ? firstCol : 1) + offset - prevPos;
  474.  
  475.           } else {
  476.             result.line = curLine;
  477.             result.col = (i == 0 ? firstCol : 1) + offset - curPos;
  478.           }
  479.           found = true;
  480.  
  481.           break;
  482.         }
  483.  
  484.       } else {
  485.         if (curLine == line && !("range" in result)) {
  486.           result.range = document.createRange();
  487.           result.range.setStart(textNode, curPos);
  488.  
  489.           //
  490.           // This will always be overridden later, except when we look for
  491.           // the very last line in the file (this is the only line that does
  492.           // not end with \n).
  493.           //
  494.           result.range.setEndAfter(pre.lastChild);
  495.  
  496.         } else if (curLine == line + 1) {
  497.           result.range.setEnd(textNode, curPos - 1);
  498.           found = true;
  499.           break;
  500.         }
  501.       }
  502.     }
  503.   }
  504.  
  505.   return found || ("range" in result);
  506. }
  507.  
  508. //function to toggle long-line wrapping and set the view_source.wrap_long_lines 
  509. //pref to persist the last state
  510. function wrapLongLines()
  511. {
  512.   var myWrap = window._content.document.body;
  513.  
  514.   if (myWrap.className == '')
  515.     myWrap.className = 'wrap';
  516.   else myWrap.className = '';
  517.  
  518.   //since multiple viewsource windows are possible, another window could have 
  519.   //affected the pref, so instead of determining the new pref value via the current
  520.   //pref value, we use myWrap.className  
  521.   if (gPrefs){
  522.     try {
  523.       if (myWrap.className == '') {
  524.         gPrefs.setBoolPref("view_source.wrap_long_lines", false);
  525.       }
  526.       else {
  527.         gPrefs.setBoolPref("view_source.wrap_long_lines", true);
  528.       }
  529.     } catch (ex) {
  530.     }
  531.   }
  532. }
  533.  
  534. //function to toggle syntax highlighting and set the view_source.syntax_highlight
  535. //pref to persist the last state
  536. function highlightSyntax()
  537. {
  538.   var highlightSyntaxMenu = document.getElementById("menu_highlightSyntax");
  539.   var highlightSyntax = (highlightSyntaxMenu.getAttribute("checked") == "true");
  540.   gPrefs.setBoolPref("view_source.syntax_highlight", highlightSyntax);
  541.  
  542.   var PageLoader = getBrowser().webNavigation.QueryInterface(pageLoaderIface);
  543.   PageLoader.LoadPage(PageLoader.currentDescriptor, pageLoaderIface.DISPLAY_NORMAL);
  544. }
  545.  
  546. // Fix for bug 136322: this function overrides the function in
  547. // browser.js to call PageLoader.LoadPage() instead of BrowserReloadWithFlags()
  548. function BrowserSetForcedCharacterSet(aCharset)
  549. {
  550.   var docCharset = getBrowser().docShell.QueryInterface(
  551.                             Components.interfaces.nsIDocCharset);
  552.   docCharset.charset = aCharset;
  553.   var PageLoader = getBrowser().webNavigation.QueryInterface(pageLoaderIface);
  554.   PageLoader.LoadPage(PageLoader.currentDescriptor, pageLoaderIface.DISPLAY_NORMAL);
  555. }
  556.  
  557. // fix for bug #229503
  558. // we need to define BrowserSetForcedDetector() so that we can
  559. // change auto-detect options in the "View | Character Encoding" menu.
  560. // As with BrowserSetForcedCharacterSet(), call PageLoader.LoadPage() 
  561. // instead of BrowserReloadWithFlags()
  562. function BrowserSetForcedDetector(doReload)
  563. {
  564.   getBrowser().documentCharsetInfo.forcedDetector = true; 
  565.   if (doReload)
  566.   {
  567.     var PageLoader = getBrowser().webNavigation.QueryInterface(pageLoaderIface);
  568.     PageLoader.LoadPage(PageLoader.currentDescriptor, pageLoaderIface.DISPLAY_NORMAL);
  569.   }
  570. }
  571.  
  572. function getMarkupDocumentViewer()
  573. {
  574.   return gBrowser.markupDocumentViewer;
  575. }
  576.