home *** CD-ROM | disk | FTP | other *** search
/ Maximum CD 2009 October / maximum-cd-2009-10.iso / DiscContents / Firefox Setup 3.5.exe / nonlocalized / chrome / toolkit.jar / content / global / viewSource.js < prev    next >
Encoding:
Text File  |  2009-06-24  |  21.0 KB  |  736 lines

  1. //@line 39 "e:\builds\moz2_slave\win32_build\build\toolkit\components\viewsource\content\viewSource.js"
  2.  
  3. const Cc = Components.classes;
  4. const Ci = Components.interfaces;
  5. const Cr = Components.results;
  6. const pageLoaderIface = Components.interfaces.nsIWebPageDescriptor;
  7. const nsISelectionPrivate = Components.interfaces.nsISelectionPrivate;
  8. const nsISelectionController = Components.interfaces.nsISelectionController;
  9. var gBrowser = null;
  10. var gViewSourceBundle = null;
  11. var gPrefs = null;
  12.  
  13. var gLastLineFound = '';
  14. var gGoToLine = 0;
  15.  
  16. try {
  17.   var prefService = Components.classes["@mozilla.org/preferences-service;1"]
  18.                               .getService(Components.interfaces.nsIPrefService);
  19.   gPrefs = prefService.getBranch(null);
  20. } catch (ex) {
  21. }
  22.  
  23. var gSelectionListener = {
  24.   timeout: 0,
  25.   attached: false,
  26.   notifySelectionChanged: function(doc, sel, reason)
  27.   {
  28.     // Coalesce notifications within 100ms intervals.
  29.     if (!this.timeout)
  30.       this.timeout = setTimeout(updateStatusBar, 100);
  31.   }
  32. }
  33.  
  34. var gViewSourceProgressListener = {
  35.  
  36.   QueryInterface: function (aIID) {
  37.     if (aIID.equals(Ci.nsIWebProgressListener) ||
  38.         aIID.equals(Ci.nsISupportsWeakReference))
  39.       return this;
  40.     throw Cr.NS_NOINTERFACE;
  41.   },
  42.  
  43.   onStateChange: function (aWebProgress, aRequest, aStateFlags, aStatus) {
  44.   },
  45.  
  46.   onProgressChange: function (aWebProgress, aRequest,
  47.                               aCurSelfProgress, aMaxSelfProgress,
  48.                               aCurTotalProgress, aMaxTotalProgress) {
  49.   },
  50.  
  51.   onLocationChange: function (aWebProgress, aRequest, aLocationURI) {
  52.     UpdateBackForwardCommands(getBrowser().webNavigation);
  53.   },
  54.  
  55.   onStatusChange: function (aWebProgress, aRequest, aStatus, aMessage) {
  56.   },
  57.  
  58.   onSecurityChange: function (aWebProgress, aRequest, aState) {
  59.   }
  60.  
  61. }
  62.  
  63. function onLoadViewSource() 
  64. {
  65.   viewSource(window.arguments[0]);
  66.   document.commandDispatcher.focusedWindow = content;
  67.       
  68.   if (isHistoryEnabled()) {
  69.     // Attach the progress listener.
  70.     getBrowser().addProgressListener(gViewSourceProgressListener, 
  71.         Components.interfaces.nsIWebProgress.NOTIFY_ALL);
  72.   } else {
  73.     // Disable the BACK and FORWARD commands and hide the related menu items.
  74.     var viewSourceNavigation = document.getElementById("viewSourceNavigation");
  75.     viewSourceNavigation.setAttribute("disabled", "true");
  76.     viewSourceNavigation.setAttribute("hidden", "true");
  77.   }
  78. }
  79.  
  80. function onUnloadViewSource() 
  81. {
  82.   // Detach the progress listener.
  83.   if (isHistoryEnabled()) {
  84.     getBrowser().removeProgressListener(gViewSourceProgressListener);
  85.   }
  86. }
  87.  
  88. function isHistoryEnabled() {
  89.   return !getBrowser().hasAttribute("disablehistory");
  90. }
  91.  
  92. function getBrowser()
  93. {
  94.   if (!gBrowser)
  95.     gBrowser = document.getElementById("content");
  96.   return gBrowser;
  97. }
  98.  
  99. function getSelectionController()
  100. {
  101.   return getBrowser().docShell
  102.     .QueryInterface(Components.interfaces.nsIInterfaceRequestor)
  103.     .getInterface(Components.interfaces.nsISelectionDisplay)
  104.     .QueryInterface(nsISelectionController);
  105.  
  106. }
  107.  
  108. function getViewSourceBundle()
  109. {
  110.   if (!gViewSourceBundle)
  111.     gViewSourceBundle = document.getElementById("viewSourceBundle");
  112.   return gViewSourceBundle;
  113. }
  114.  
  115. function viewSource(url)
  116. {
  117.   if (!url)
  118.     return false; // throw Components.results.NS_ERROR_FAILURE;
  119.     
  120.   var viewSrcUrl = "view-source:" + url;
  121.  
  122.   getBrowser().addEventListener("unload", onUnloadContent, true);
  123.   getBrowser().addEventListener("load", onLoadContent, true);
  124.  
  125.   var loadFromURL = true;
  126.   //
  127.   // Parse the 'arguments' supplied with the dialog.
  128.   //    arg[0] - URL string.
  129.   //    arg[1] - Charset value in the form 'charset=xxx'.
  130.   //    arg[2] - Page descriptor used to load content from the cache.
  131.   //    arg[3] - Line number to go to.
  132.   //    arg[4] - Whether charset was forced by the user
  133.   //
  134.   if ("arguments" in window) {
  135.     var arg;
  136.     //
  137.     // Set the charset of the viewsource window...
  138.     //
  139.     var charset;
  140.     if (window.arguments.length >= 2) {
  141.       arg = window.arguments[1];
  142.  
  143.       try {
  144.         if (typeof(arg) == "string" && arg.indexOf('charset=') != -1) {
  145.           var arrayArgComponents = arg.split('=');
  146.           if (arrayArgComponents) {
  147.             //we should "inherit" the charset menu setting in a new window
  148.             charset = arrayArgComponents[1];
  149.             gBrowser.markupDocumentViewer.defaultCharacterSet = charset;
  150.           }
  151.         }
  152.       } catch (ex) {
  153.         // Ignore the failure and keep processing arguments...
  154.       }
  155.     }
  156.     // If the document had a forced charset, set it here also
  157.     if (window.arguments.length >= 5) {
  158.       arg = window.arguments[4];
  159.  
  160.       try {
  161.         if (arg === true) {
  162.           var docCharset = getBrowser().docShell.QueryInterface
  163.                              (Components.interfaces.nsIDocCharset);
  164.           docCharset.charset = charset;
  165.         }
  166.       } catch (ex) {
  167.         // Ignore the failure and keep processing arguments...
  168.       }
  169.     }
  170.     //
  171.     // Get any specified line to jump to.
  172.     //
  173.     if (window.arguments.length >= 4) {
  174.       arg = window.arguments[3];
  175.       gGoToLine = parseInt(arg);
  176.     }
  177.     //
  178.     // Use the page descriptor to load the content from the cache (if
  179.     // available).
  180.     //
  181.     if (window.arguments.length >= 3) {
  182.       arg = window.arguments[2];
  183.  
  184.       try {
  185.         if (typeof(arg) == "object" && arg != null) {
  186.           var PageLoader = getBrowser().webNavigation.QueryInterface(pageLoaderIface);
  187.  
  188.           //
  189.           // Load the page using the page descriptor rather than the URL.
  190.           // This allows the content to be fetched from the cache (if
  191.           // possible) rather than the network...
  192.           //
  193.           PageLoader.loadPage(arg, pageLoaderIface.DISPLAY_AS_SOURCE);
  194.  
  195.           // The content was successfully loaded.
  196.           loadFromURL = false;
  197.  
  198.           // Record the page load in the session history so <back> will work.
  199.           var shEntrySource = arg.QueryInterface(Ci.nsISHEntry);
  200.           var shEntry = Cc["@mozilla.org/browser/session-history-entry;1"].createInstance(Ci.nsISHEntry);
  201.           shEntry.setURI(makeURI(viewSrcUrl, null, null));
  202.           shEntry.setTitle(viewSrcUrl);
  203.           shEntry.loadType = Ci.nsIDocShellLoadInfo.loadHistory;
  204.           shEntry.cacheKey = shEntrySource.cacheKey;
  205.           getBrowser().webNavigation.sessionHistory
  206.                       .QueryInterface(Ci.nsISHistoryInternal)
  207.                       .addEntry(shEntry, true);
  208.         }
  209.       } catch(ex) {
  210.         // Ignore the failure.  The content will be loaded via the URL
  211.         // that was supplied in arg[0].
  212.       }
  213.     }
  214.   }
  215.  
  216.   if (loadFromURL) {
  217.     //
  218.     // Currently, an exception is thrown if the URL load fails...
  219.     //
  220.     var loadFlags = Components.interfaces.nsIWebNavigation.LOAD_FLAGS_NONE;
  221.     getBrowser().webNavigation.loadURI(viewSrcUrl, loadFlags, null, null, null);
  222.   }
  223.  
  224.   //check the view_source.wrap_long_lines pref and set the menuitem's checked attribute accordingly
  225.   if (gPrefs) {
  226.     try {
  227.       var wraplonglinesPrefValue = gPrefs.getBoolPref("view_source.wrap_long_lines");
  228.  
  229.       if (wraplonglinesPrefValue)
  230.         document.getElementById('menu_wrapLongLines').setAttribute("checked", "true");
  231.     } catch (ex) {
  232.     }
  233.     try {
  234.       document.getElementById("menu_highlightSyntax").setAttribute("checked", gPrefs.getBoolPref("view_source.syntax_highlight"));
  235.     } catch (ex) {
  236.     }
  237.   } else {
  238.     document.getElementById("menu_highlightSyntax").setAttribute("hidden", "true");
  239.   }
  240.  
  241.   window.addEventListener("AppCommand", HandleAppCommandEvent, true);
  242.   window._content.focus();
  243.  
  244.   return true;
  245. }
  246.  
  247. function onLoadContent()
  248. {
  249.   //
  250.   // If the view source was opened with a "go to line" argument.
  251.   //
  252.   if (gGoToLine > 0) {
  253.     goToLine(gGoToLine);
  254.     gGoToLine = 0;
  255.   }
  256.   document.getElementById('cmd_goToLine').removeAttribute('disabled');
  257.  
  258.   // Register a listener so that we can show the caret position on the status bar.
  259.   window._content.getSelection()
  260.    .QueryInterface(nsISelectionPrivate)
  261.    .addSelectionListener(gSelectionListener);
  262.   gSelectionListener.attached = true;
  263. }
  264.  
  265. function onUnloadContent()
  266. {
  267.   //
  268.   // Disable "go to line" while reloading due to e.g. change of charset
  269.   // or toggling of syntax highlighting.
  270.   //
  271.   document.getElementById('cmd_goToLine').setAttribute('disabled', 'true');
  272.  
  273.   // If we're not just unloading the initial "about:blank" which doesn't have
  274.   // a selection listener, get rid of it so it doesn't try to fire after the
  275.   // window has gone away.
  276.   if (gSelectionListener.attached) {
  277.     window.content.getSelection().QueryInterface(nsISelectionPrivate)
  278.           .removeSelectionListener(gSelectionListener);
  279.     gSelectionListener.attached = false;
  280.   }
  281. }
  282.  
  283. function HandleAppCommandEvent(evt)
  284. {
  285.   evt.stopPropagation();
  286.   switch (evt.command) {
  287.     case "Back":
  288.       BrowserBack();
  289.       break;
  290.     case "Forward":
  291.       BrowserForward();
  292.       break;
  293.   }
  294. }
  295.  
  296. function ViewSourceClose()
  297. {
  298.   window.close();
  299. }
  300.  
  301. function ViewSourceReload()
  302. {
  303.   const webNavigation = getBrowser().webNavigation;
  304.   webNavigation.reload(webNavigation.LOAD_FLAGS_BYPASS_PROXY | webNavigation.LOAD_FLAGS_BYPASS_CACHE);
  305. }
  306.  
  307. // Strips the |view-source:| for editPage()
  308. function ViewSourceEditPage()
  309. {
  310.   editPage(window.content.location.href.substring(12), window, false);
  311. }
  312.  
  313. // Strips the |view-source:| for saveURL()
  314. function ViewSourceSavePage()
  315. {
  316.   saveURL(window.content.location.href.substring(12), null, "SaveLinkTitle");
  317. }
  318.  
  319. function onEnterPP()
  320. {
  321.   var toolbox = document.getElementById("viewSource-toolbox");
  322.   toolbox.hidden = true;
  323. }
  324.  
  325. function onExitPP()
  326. {
  327.   var toolbox = document.getElementById("viewSource-toolbox");
  328.   toolbox.hidden = false;
  329. }
  330.  
  331. function getPPBrowser()
  332. {
  333.   return document.getElementById("content");
  334. }
  335.  
  336. function getNavToolbox()
  337. {
  338.   return document.getElementById("appcontent");
  339. }
  340.  
  341. function getWebNavigation()
  342. {
  343.   try {
  344.     return gBrowser.webNavigation;
  345.   } catch (e) {
  346.     return null;
  347.   }
  348. }
  349.  
  350. function ViewSourceGoToLine()
  351. {
  352.   var promptService = Components.classes["@mozilla.org/embedcomp/prompt-service;1"]
  353.         .getService(Components.interfaces.nsIPromptService);
  354.   var viewSourceBundle = getViewSourceBundle();
  355.  
  356.   var input = {value:gLastLineFound};
  357.   for (;;) {
  358.     var ok = promptService.prompt(
  359.         window,
  360.         viewSourceBundle.getString("goToLineTitle"),
  361.         viewSourceBundle.getString("goToLineText"),
  362.         input,
  363.         null,
  364.         {value:0});
  365.  
  366.     if (!ok) return;
  367.  
  368.     var line = parseInt(input.value);
  369.  
  370.     if (!(line > 0)) {
  371.       promptService.alert(window,
  372.           viewSourceBundle.getString("invalidInputTitle"),
  373.           viewSourceBundle.getString("invalidInputText"));
  374.   
  375.       continue;
  376.     }
  377.  
  378.     var found = goToLine(line);
  379.  
  380.     if (found) {
  381.       break;
  382.     }
  383.  
  384.     promptService.alert(window,
  385.         viewSourceBundle.getString("outOfRangeTitle"),
  386.         viewSourceBundle.getString("outOfRangeText"));
  387.   }
  388. }
  389.  
  390. function goToLine(line)
  391. {
  392.   var viewsource = window._content.document.body;
  393.  
  394.   //
  395.   // The source document is made up of a number of pre elements with
  396.   // id attributes in the format <pre id="line123">, meaning that
  397.   // the first line in the pre element is number 123.
  398.   // Do binary search to find the pre element containing the line.
  399.   //
  400.   var pre;
  401.   for (var lbound = 0, ubound = viewsource.childNodes.length; ; ) {
  402.     var middle = (lbound + ubound) >> 1;
  403.     pre = viewsource.childNodes[middle];
  404.  
  405.     var firstLine = parseInt(pre.id.substring(4));
  406.  
  407.     if (lbound == ubound - 1) {
  408.       break;
  409.     }
  410.  
  411.     if (line >= firstLine) {
  412.       lbound = middle;
  413.     } else {
  414.       ubound = middle;
  415.     }
  416.   }
  417.  
  418.   var result = {};
  419.   var found = findLocation(pre, line, null, -1, false, result);
  420.  
  421.   if (!found) {
  422.     return false;
  423.   }
  424.  
  425.   var selection = window._content.getSelection();
  426.   selection.removeAllRanges();
  427.  
  428.   // In our case, the range's startOffset is after "\n" on the previous line.
  429.   // Tune the selection at the beginning of the next line and do some tweaking
  430.   // to position the focusNode and the caret at the beginning of the line.
  431.  
  432.   selection.QueryInterface(nsISelectionPrivate)
  433.     .interlinePosition = true;
  434.  
  435.   selection.addRange(result.range);
  436.  
  437.   if (!selection.isCollapsed) {
  438.     selection.collapseToEnd();
  439.  
  440.     var offset = result.range.startOffset;
  441.     var node = result.range.startContainer;
  442.     if (offset < node.data.length) {
  443.       // The same text node spans across the "\n", just focus where we were.
  444.       selection.extend(node, offset);
  445.     }
  446.     else {
  447.       // There is another tag just after the "\n", hook there. We need
  448.       // to focus a safe point because there are edgy cases such as
  449.       // <span>...\n</span><span>...</span> vs.
  450.       // <span>...\n<span>...</span></span><span>...</span>
  451.       node = node.nextSibling ? node.nextSibling : node.parentNode.nextSibling;
  452.       selection.extend(node, 0);
  453.     }
  454.   }
  455.  
  456.   var selCon = getSelectionController();
  457.   selCon.setDisplaySelection(nsISelectionController.SELECTION_ON);
  458.   selCon.setCaretVisibilityDuringSelection(true);
  459.  
  460.   // Scroll the beginning of the line into view.
  461.   selCon.scrollSelectionIntoView(
  462.     nsISelectionController.SELECTION_NORMAL,
  463.     nsISelectionController.SELECTION_FOCUS_REGION,
  464.     true);
  465.  
  466.   gLastLineFound = line;
  467.  
  468.   document.getElementById("statusbar-line-col").label =
  469.     getViewSourceBundle().getFormattedString("statusBarLineCol", [line, 1]);
  470.  
  471.   return true;
  472. }
  473.  
  474. function updateStatusBar()
  475. {
  476.   // Reset the coalesce flag.
  477.   gSelectionListener.timeout = 0;
  478.  
  479.   var statusBarField = document.getElementById("statusbar-line-col");
  480.  
  481.   var selection = window._content.getSelection();
  482.   if (!selection.focusNode) {
  483.     statusBarField.label = '';
  484.     return;
  485.   }
  486.   if (selection.focusNode.nodeType != Node.TEXT_NODE) {
  487.     return;
  488.   }
  489.  
  490.   var selCon = getSelectionController();
  491.   selCon.setDisplaySelection(nsISelectionController.SELECTION_ON);
  492.   selCon.setCaretVisibilityDuringSelection(true);
  493.  
  494.   var interlinePosition = selection
  495.       .QueryInterface(nsISelectionPrivate).interlinePosition;
  496.  
  497.   var result = {};
  498.   findLocation(null, -1, 
  499.       selection.focusNode, selection.focusOffset, interlinePosition, result);
  500.  
  501.   statusBarField.label = getViewSourceBundle()
  502.       .getFormattedString("statusBarLineCol", [result.line, result.col]);
  503. }
  504.  
  505. //
  506. // Loops through the text lines in the pre element. The arguments are either
  507. // (pre, line) or (node, offset, interlinePosition). result is an out
  508. // argument. If (pre, line) are specified (and node == null), result.range is
  509. // a range spanning the specified line. If the (node, offset,
  510. // interlinePosition) are specified, result.line and result.col are the line
  511. // and column number of the specified offset in the specified node relative to
  512. // the whole file.
  513. //
  514. function findLocation(pre, line, node, offset, interlinePosition, result)
  515. {
  516.   if (node && !pre) {
  517.     //
  518.     // Look upwards to find the current pre element.
  519.     //
  520.     for (pre = node;
  521.          pre.nodeName != "PRE";
  522.          pre = pre.parentNode);
  523.   }
  524.  
  525.   //
  526.   // The source document is made up of a number of pre elements with
  527.   // id attributes in the format <pre id="line123">, meaning that
  528.   // the first line in the pre element is number 123.
  529.   //
  530.   var curLine = parseInt(pre.id.substring(4));
  531.  
  532.   //
  533.   // Walk through each of the text nodes and count newlines.
  534.   //
  535.   var treewalker = window._content.document
  536.       .createTreeWalker(pre, NodeFilter.SHOW_TEXT, null, false);
  537.  
  538.   //
  539.   // The column number of the first character in the current text node.
  540.   //
  541.   var firstCol = 1;
  542.  
  543.   var found = false;
  544.   for (var textNode = treewalker.firstChild();
  545.        textNode && !found;
  546.        textNode = treewalker.nextNode()) {
  547.  
  548.     //
  549.     // \r is not a valid character in the DOM, so we only check for \n.
  550.     //
  551.     var lineArray = textNode.data.split(/\n/);
  552.     var lastLineInNode = curLine + lineArray.length - 1;
  553.  
  554.     //
  555.     // Check if we can skip the text node without further inspection.
  556.     //
  557.     if (node ? (textNode != node) : (lastLineInNode < line)) {
  558.       if (lineArray.length > 1) {
  559.         firstCol = 1;
  560.       }
  561.       firstCol += lineArray[lineArray.length - 1].length;
  562.       curLine = lastLineInNode;
  563.       continue;
  564.     }
  565.  
  566.     //
  567.     // curPos is the offset within the current text node of the first
  568.     // character in the current line.
  569.     //
  570.     for (var i = 0, curPos = 0;
  571.          i < lineArray.length;
  572.          curPos += lineArray[i++].length + 1) {
  573.  
  574.       if (i > 0) {
  575.         curLine++;
  576.       }
  577.  
  578.       if (node) {
  579.         if (offset >= curPos && offset <= curPos + lineArray[i].length) {
  580.           //
  581.           // If we are right after the \n of a line and interlinePosition is
  582.           // false, the caret looks as if it were at the end of the previous
  583.           // line, so we display that line and column instead.
  584.           //
  585.           if (i > 0 && offset == curPos && !interlinePosition) {
  586.             result.line = curLine - 1;
  587.             var prevPos = curPos - lineArray[i - 1].length;
  588.             result.col = (i == 1 ? firstCol : 1) + offset - prevPos;
  589.  
  590.           } else {
  591.             result.line = curLine;
  592.             result.col = (i == 0 ? firstCol : 1) + offset - curPos;
  593.           }
  594.           found = true;
  595.  
  596.           break;
  597.         }
  598.  
  599.       } else {
  600.         if (curLine == line && !("range" in result)) {
  601.           result.range = document.createRange();
  602.           result.range.setStart(textNode, curPos);
  603.  
  604.           //
  605.           // This will always be overridden later, except when we look for
  606.           // the very last line in the file (this is the only line that does
  607.           // not end with \n).
  608.           //
  609.           result.range.setEndAfter(pre.lastChild);
  610.  
  611.         } else if (curLine == line + 1) {
  612.           result.range.setEnd(textNode, curPos - 1);
  613.           found = true;
  614.           break;
  615.         }
  616.       }
  617.     }
  618.   }
  619.  
  620.   return found || ("range" in result);
  621. }
  622.  
  623. //function to toggle long-line wrapping and set the view_source.wrap_long_lines 
  624. //pref to persist the last state
  625. function wrapLongLines()
  626. {
  627.   var myWrap = window._content.document.body;
  628.  
  629.   if (myWrap.className == '')
  630.     myWrap.className = 'wrap';
  631.   else myWrap.className = '';
  632.  
  633.   //since multiple viewsource windows are possible, another window could have 
  634.   //affected the pref, so instead of determining the new pref value via the current
  635.   //pref value, we use myWrap.className  
  636.   if (gPrefs){
  637.     try {
  638.       if (myWrap.className == '') {
  639.         gPrefs.setBoolPref("view_source.wrap_long_lines", false);
  640.       }
  641.       else {
  642.         gPrefs.setBoolPref("view_source.wrap_long_lines", true);
  643.       }
  644.     } catch (ex) {
  645.     }
  646.   }
  647. }
  648.  
  649. //function to toggle syntax highlighting and set the view_source.syntax_highlight
  650. //pref to persist the last state
  651. function highlightSyntax()
  652. {
  653.   var highlightSyntaxMenu = document.getElementById("menu_highlightSyntax");
  654.   var highlightSyntax = (highlightSyntaxMenu.getAttribute("checked") == "true");
  655.   gPrefs.setBoolPref("view_source.syntax_highlight", highlightSyntax);
  656.  
  657.   var PageLoader = getBrowser().webNavigation.QueryInterface(pageLoaderIface);
  658.   PageLoader.loadPage(PageLoader.currentDescriptor, pageLoaderIface.DISPLAY_NORMAL);
  659. }
  660.  
  661. // Fix for bug 136322: this function overrides the function in
  662. // browser.js to call PageLoader.loadPage() instead of BrowserReloadWithFlags()
  663. function BrowserSetForcedCharacterSet(aCharset)
  664. {
  665.   var docCharset = getBrowser().docShell.QueryInterface(Ci.nsIDocCharset);
  666.   docCharset.charset = aCharset;
  667.   if (isHistoryEnabled()) {
  668.     var PageLoader = getBrowser().webNavigation.QueryInterface(pageLoaderIface);
  669.     PageLoader.loadPage(PageLoader.currentDescriptor,
  670.                         pageLoaderIface.DISPLAY_NORMAL);
  671.   } else {
  672.     getBrowser().webNavigation
  673.                 .reload(Ci.nsIWebNavigation.LOAD_FLAGS_CHARSET_CHANGE);
  674.   }
  675. }
  676.  
  677. // fix for bug #229503
  678. // we need to define BrowserSetForcedDetector() so that we can
  679. // change auto-detect options in the "View | Character Encoding" menu.
  680. // As with BrowserSetForcedCharacterSet(), call PageLoader.loadPage() 
  681. // instead of BrowserReloadWithFlags()
  682. function BrowserSetForcedDetector(doReload)
  683. {
  684.   getBrowser().documentCharsetInfo.forcedDetector = true; 
  685.   if (doReload)
  686.   {
  687.     if (isHistoryEnabled()) {
  688.       var PageLoader = getBrowser().webNavigation
  689.                                    .QueryInterface(pageLoaderIface);
  690.       PageLoader.loadPage(PageLoader.currentDescriptor,
  691.                           pageLoaderIface.DISPLAY_NORMAL);
  692.     } else {
  693.       getBrowser().webNavigation
  694.                   .reload(Ci.nsIWebNavigation.LOAD_FLAGS_CHARSET_CHANGE);
  695.     }
  696.   }
  697. }
  698.  
  699. function BrowserForward(aEvent) {
  700.   try {
  701.     getBrowser().goForward();
  702.   }
  703.   catch(ex) {
  704.   }
  705. }
  706.  
  707. function BrowserBack(aEvent) {
  708.   try {
  709.     getBrowser().goBack();
  710.   }
  711.   catch(ex) {
  712.   }
  713. }
  714.  
  715. function UpdateBackForwardCommands(aWebNavigation) {
  716.   var backBroadcaster = document.getElementById("Browser:Back");
  717.   var forwardBroadcaster = document.getElementById("Browser:Forward");
  718.  
  719.   var backDisabled = backBroadcaster.hasAttribute("disabled");
  720.   var forwardDisabled = forwardBroadcaster.hasAttribute("disabled");
  721.  
  722.   if (backDisabled == aWebNavigation.canGoBack) {
  723.     if (backDisabled)
  724.       backBroadcaster.removeAttribute("disabled");
  725.     else
  726.       backBroadcaster.setAttribute("disabled", true);
  727.   }
  728.  
  729.   if (forwardDisabled == aWebNavigation.canGoForward) {
  730.     if (forwardDisabled)
  731.       forwardBroadcaster.removeAttribute("disabled");
  732.     else
  733.       forwardBroadcaster.setAttribute("disabled", true);
  734.   }
  735. }
  736.