home *** CD-ROM | disk | FTP | other *** search
/ GameStar 2005 October / Gamestar_77_2005-10_dvd.iso / Programy / nsb-install-8-0.exe / chrome / browser.jar / content / browser / sidebar / sidebarOverlay.js < prev    next >
Encoding:
JavaScript  |  2005-07-29  |  56.0 KB  |  1,756 lines

  1. /* -*- Mode: Java; tab-width: 4; insert-tabs-mode: nil; c-basic-offset: 2 -*-
  2.  *
  3.  * The contents of this file are subject to the Mozilla Public License
  4.  * Version 1.1 (the "License"); you may not use this file except in
  5.  * compliance with the License. You may obtain a copy of the License at
  6.  * http://www.mozilla.org/MPL/
  7.  *
  8.  * Software distributed under the License is distributed on an "AS IS"
  9.  * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
  10.  * the License for the specific language governing rights and
  11.  * limitations under the License.
  12.  *
  13.  * The Original Code is Mozilla Communicator client code, released
  14.  * March 31, 1998.
  15.  *
  16.  * The Initial Developer of the Original Code is Netscape
  17.  * Communications Corporation. Portions created by Netscape are
  18.  * Copyright (C) 1998-1999 Netscape Communications Corporation. All
  19.  * Rights Reserved.
  20.  */
  21.  
  22. // xul/id summary:
  23. //
  24. // <box> sidebar-box
  25. //    <splitter> sidebar-panels-splitter
  26. //       <box> sidebar-panels-splitter-box*
  27. //    <sidebarheader> sidebar-title-box
  28. //       <menubutton> sidebar-panel-picker*
  29. //          <menupopup> sidebar-panel-picker-popup
  30. //    <box> sidebar-panels
  31. //       <template> sidebar-template*
  32. //          <box> sidebar-iframe-no-panels
  33. // <splitter> sidebar-splitter
  34. // <menupopup> menu_View_Popup*
  35. //    <menuitem> sidebar-menu
  36.  
  37. //////////////////////////////////////////////////////////////
  38. // Global variables
  39. //////////////////////////////////////////////////////////////
  40.  
  41. var gCurFrame;
  42. var gTimeoutID = null;
  43. var gMustInit = true;
  44. var gAboutToUncollapse = false;
  45. var gCheckMissingPanels = true;
  46. var gSearchService = null;
  47. var numTries = 0;
  48.  
  49. function setBlank()
  50. {
  51.     gTimeoutID = null;
  52.     gCurFrame.setAttribute('src', 'chrome://browser/content/sidebar/PageNotFound.xul');
  53. }
  54.  
  55.  
  56. // Uncomment for debug output
  57. const SB_DEBUG = false;
  58.  
  59. // pref for limiting number of tabs in view
  60. // initialized in sidebar_overlay_init()
  61. var gNumTabsInViewPref;
  62.  
  63. // The rdf service
  64. const RDF_URI = '@mozilla.org/rdf/rdf-service;1';
  65. var RDF = Components.classes[RDF_URI].getService();
  66. RDF = RDF.QueryInterface(Components.interfaces.nsIRDFService);
  67.  
  68. const NC = "http://home.netscape.com/NC-rdf#";
  69.  
  70. // The directory services property to find panels.rdf
  71. const PANELS_RDF_FILE = "UPnls";
  72. const SIDEBAR_VERSION = "0.1";
  73.  
  74. // The default sidebar:
  75. var sidebarObj = new Object;
  76. sidebarObj.never_built = true;
  77.  
  78. //////////////////////////////////////////////////////////////////////
  79. // sbPanelList Class
  80. //
  81. // Wrapper around DOM representation of the sidebar. This UI event
  82. // handlers and the sidebar datasource observers call into this.  This
  83. // class is responsible for keeping the DOM state of the sidebar up to
  84. // date.
  85. // This class does not make any changes to the sidebar rdf datasource.
  86. //////////////////////////////////////////////////////////////////////
  87.  
  88. function sbPanelList(container_id)
  89. {
  90.   debug("sbPanelList("+container_id+")");
  91.   this.node = document.getElementById(container_id);
  92.   this.childNodes = this.node.childNodes;
  93.   this.initialized = false; // set after first display of tabs
  94. }
  95.  
  96. sbPanelList.prototype.get_panel_from_id =
  97. function (id)
  98. {
  99.   debug("get_panel_from_id(" + id + ")... "+this.node.childNodes.length+" nodes");
  100.   var index = 0;
  101.   var header = null;
  102.   if (id && id != '') {
  103.     for (var ii=2; ii < this.node.childNodes.length; ii += 2) {
  104.       header = this.node.childNodes.item(ii);
  105.       if (header.getAttribute('id') == id) {
  106.         debug("get_panel_from_id: Found at index, " + ii);
  107.         index = ii;
  108.         break;
  109.       }
  110.     }
  111.   }
  112.   if (index > 0) {
  113.     return new sbPanel(id, header, index);
  114.   } else {
  115.     return null;
  116.   }
  117. }
  118.  
  119. sbPanelList.prototype.get_panel_from_header_node =
  120. function (node)
  121. {
  122.   return this.get_panel_from_id(node.getAttribute('id'));
  123. }
  124.  
  125. sbPanelList.prototype.get_panel_from_header_index =
  126. function (index)
  127. {
  128.   return this.get_panel_from_header_node(this.node.childNodes.item(index));
  129. }
  130.  
  131. sbPanelList.prototype.find_first =
  132. function (panels)
  133. {
  134.   debug("pick_default_panel: length=" + this.node.childNodes.length);
  135.   for (var ii = 2; ii < this.node.childNodes.length; ii += 2) {
  136.     var panel = this.get_panel_from_header_index(ii);
  137.     if (!panel.is_excluded() && panel.is_in_view()) {
  138.       return panel;
  139.     }
  140.   }
  141.   return null;
  142. }
  143.  
  144. sbPanelList.prototype.find_last =
  145. function (panels)
  146. {
  147.   debug("pick_default_panel: length=" + this.node.childNodes.length);
  148.   for (var ii=(this.node.childNodes.length - 1); ii >= 2; ii -= 2) {
  149.     var panel = this.get_panel_from_header_index(ii);
  150.     if (!panel.is_excluded() && panel.is_in_view()) {
  151.       return panel;
  152.     }
  153.   }
  154.   return null;
  155. }
  156.  
  157. sbPanelList.prototype.visible_panels_exist =
  158. function ()
  159. {
  160.   var i;
  161.   var panels = this.node.childNodes;
  162.   for (i = 2; i < panels.length; i += 2)
  163.   {
  164.     if (!panels.item(i).hidden)
  165.       return true;
  166.   }
  167.   return false;
  168. }
  169.  
  170. sbPanelList.prototype.num_panels_included =
  171. function ()
  172. {
  173.   var count = 0;
  174.   var panels = this.node.childNodes;
  175.   for (var i = 2; i < panels.length; i += 2)
  176.   {
  177.     var curr = this.get_panel_from_header_index(i);
  178.     if (!curr.is_excluded())
  179.       count++;
  180.   }
  181.   return count;
  182. }
  183.  
  184. sbPanelList.prototype.num_panels_in_view =
  185. function ()
  186. {
  187.   var count = 0;
  188.   var panels = this.node.childNodes;
  189.   for (var i = 2; i < panels.length; i += 2)
  190.   {
  191.     var curr = this.get_panel_from_header_index(i);
  192.     if (curr.is_in_view())
  193.       count++;
  194.   }
  195.   return count;
  196. }
  197.  
  198. sbPanelList.prototype.select =
  199. function (panel, force_reload)
  200. {
  201.   if (!force_reload && panel.is_selected()) {
  202.     return;
  203.   }
  204.   // select(): Open this panel and possibly reload it.
  205.   if (this.node.getAttribute('last-selected-panel') != panel.id) {
  206.     // "last-selected-panel" is used as a global variable.
  207.     // this.update() will reference "last-selected-panel".
  208.     // This way the value can be persisted in localstore.rdf.
  209.     this.node.setAttribute('last-selected-panel', panel.id);
  210.   }
  211.   this.update(force_reload);
  212. }
  213.  
  214. sbPanelList.prototype.exclude =
  215. function (panel)
  216. {
  217.   if (this.node.getAttribute('last-selected-panel') == panel.id) {
  218.     this.select_default_panel();
  219.   } else {
  220.     this.update(false);
  221.   }
  222. }
  223.  
  224.  
  225. sbPanelList.prototype.select_default_panel =
  226. function ()
  227. {
  228.   var default_panel = null
  229.  
  230.   // First, check the XUL for the "defaultpanel" attribute of "sidebar-box".
  231.   var sidebar_container = document.getElementById('sidebar-box');
  232.   var content_default_id = sidebar_container.getAttribute('defaultpanel');
  233.   if (content_default_id != '') {
  234.     var content = sidebarObj.panels.get_panel_from_id(content_default_id);
  235.     if (content && !content.is_excluded() && content.is_in_view()) {
  236.       default_panel = content;
  237.     }
  238.   }
  239.  
  240.   // Second, try to use the panel persisted in 'last-selected-panel'.
  241.   if (!default_panel) {
  242.     var last_selected_id = this.node.getAttribute('last-selected-panel');
  243.     if (last_selected_id != '') {
  244.       var last = sidebarObj.panels.get_panel_from_id(last_selected_id);
  245.       if (last && !last.is_excluded() && last.is_in_view()) {
  246.         default_panel = last;
  247.       }
  248.     }
  249.   }
  250.  
  251.   // Finally, just use the last one in the list.
  252.   if (!default_panel) {
  253.     default_panel = this.find_last();
  254.   }
  255.  
  256.   if (default_panel) {
  257.     this.node.setAttribute('last-selected-panel', default_panel.id);
  258.   }
  259.   this.update(false);
  260. }
  261.  
  262. sbPanelList.prototype.refresh =
  263. function ()
  264. {
  265.   var last_selected_id = this.node.getAttribute('last-selected-panel');
  266.   var last_selected = sidebarObj.panels.get_panel_from_id(last_selected_id);
  267.   if (last_selected && last_selected.is_selected()) {
  268.     // The desired panel is already selected
  269.     this.update(false);
  270.   } else {
  271.     this.select_default_panel();
  272.   }
  273. }
  274.  
  275. // panel_loader(): called from a timer that is set in sbPanelList.update()
  276. // Removes the "Loading..." screen when the panel has finished loading.
  277. function panel_loader() {
  278.   debug("panel_loader()");
  279.  
  280.   if (gTimeoutID != null) {
  281.       clearTimeout(gTimeoutID);
  282.       gTimeoutID = null; 
  283.   }
  284.  
  285.   this.removeEventListener("load", panel_loader, true);
  286.   this.removeAttribute('collapsed');
  287.   this.setAttribute('loadstate','loaded');
  288.   this.parentNode.firstChild.setAttribute('hidden','true');
  289.  
  290.   if (this.hasAttribute('focusOnLoad')) {
  291.     var elementToFocus = this.contentDocument.documentElement.getAttribute('elementtofocus');
  292.     if (elementToFocus) {
  293.       var element = this.contentDocument.getElementById(elementToFocus);
  294.       if (element)
  295.         element.focus();
  296.       else
  297.         dump(elementToFocus + ' element was not found to focus!\n');
  298.     } else {
  299.       this.contentWindow.focus();
  300.     }
  301.     this.removeAttribute('focusOnLoad');
  302.   }
  303. }
  304. sbPanelList.prototype.update =
  305. function (force_reload)
  306. {
  307.   // This function requires that the attribute 'last-selected-panel'
  308.   // holds the id of a non-excluded panel. If it doesn't, no panel will
  309.   // be selected. The attribute is used instead of a funciton
  310.   // parameter to allow the value to be persisted in localstore.rdf.
  311.   var selected_id = this.node.getAttribute('last-selected-panel');
  312.  
  313.   if (sidebar_is_collapsed()) {
  314.     sidebarObj.collapsed = true;
  315.   } else {
  316.     sidebarObj.collapsed = false;
  317.   }
  318.  
  319.   var num_included = sidebarObj.panels.num_panels_included();
  320.  
  321.   if (num_included > gNumTabsInViewPref)
  322.     document.getElementById("nav-buttons-box").hidden = false;
  323.   else
  324.     document.getElementById("nav-buttons-box").hidden = true;
  325.  
  326.   var have_set_top = 0;
  327.   var have_set_after_selected = 0;
  328.   var is_after_selected = 0;
  329.   var last_header = 0;
  330.   var num_in_view = 0;
  331.   debug("this.initialized: " + this.initialized);
  332.   for (var ii=2; ii < this.node.childNodes.length; ii += 2) {
  333.     var header = this.node.childNodes.item(ii);
  334.     var content = this.node.childNodes.item(ii+1);
  335.     var id = header.getAttribute('id');
  336.     var panel = new sbPanel(id, header, ii);
  337.     var excluded = panel.is_excluded();
  338.     var in_view = false;
  339.     if (!this.initialized) 
  340.     {
  341.       if (num_in_view < gNumTabsInViewPref)
  342.         in_view = true;
  343.     }
  344.     else
  345.     {
  346.       if (header.getAttribute("in-view") == "true")
  347.         in_view = true;
  348.     }
  349.     if (excluded || !in_view)
  350.     {
  351.       debug("item("+ii/2+") excluded: " + excluded + 
  352.                           " in view: " + in_view);
  353.       header.setAttribute('hidden','true');
  354.       content.setAttribute('hidden','true');
  355.       if (!in_view)
  356.       {
  357.         header.setAttribute("in-view", false);
  358.         header.removeAttribute("top-panel");
  359.         header.removeAttribute("last-panel");
  360.       }
  361.     } else {
  362.       // only set if in view
  363.       if (!this.initialized || (num_in_view < gNumTabsInViewPref))
  364.         last_header = header;
  365.       header.removeAttribute('last-panel');
  366.       // only set if in view
  367.       if (!have_set_top && 
  368.           (!this.initialized || (header.getAttribute("in-view") == "true")))
  369.       {
  370.         header.setAttribute('top-panel','true');
  371.         have_set_top = 1;
  372.       } else {
  373.         header.removeAttribute('top-panel');
  374.       }
  375.       if (!have_set_after_selected && is_after_selected) {
  376.         header.setAttribute('first-panel-after-selected','true');
  377.         have_set_after_selected = 1
  378.       } else {
  379.         header.removeAttribute('first-panel-after-selected');
  380.       }
  381.       header.removeAttribute('hidden');
  382.       header.setAttribute("in-view", true);
  383.       num_in_view++;
  384.       
  385.       // (a) when we have hit the maximum number of tabs that can be in view and no tab 
  386.       //     has been selected yet
  387.       //     -or-
  388.       // (b) when we have reached the last tab we are about to display
  389.       if ( ((num_in_view == num_included) ||
  390.             (num_in_view == gNumTabsInViewPref)) &&
  391.           !is_after_selected )
  392.       {
  393.         selected_id = id;
  394.         this.node.setAttribute('last-selected-panel', id);
  395.       }
  396.  
  397.       // Pick sandboxed, or unsandboxed iframe
  398.       var iframe = panel.get_iframe();
  399.       var load_state;
  400.  
  401.       if (selected_id == id) {
  402.         is_after_selected = 1
  403.         debug("item("+ii/2+") selected");
  404.         header.setAttribute('selected', 'true');
  405.         content.removeAttribute('hidden');
  406.         content.removeAttribute('collapsed');
  407.  
  408.         if (sidebarObj.collapsed && panel.is_sandboxed()) {
  409.           if (!panel.is_persistent()) {
  410.             debug("    set src=about:blank");
  411.             iframe.setAttribute('src', 'about:blank');
  412.           }
  413.         } else {
  414.           var saved_src = iframe.getAttribute('content');
  415.           var src = iframe.getAttribute('src');
  416.           // either we have been requested to force_reload or the
  417.           // panel src has changed so we must restore the original src
  418.           if (force_reload || (saved_src != src)) {
  419.             debug("    set src="+saved_src);
  420.             iframe.setAttribute('src', saved_src);
  421.  
  422.             if (gTimeoutID != null)
  423.               clearTimeout(gTimeoutID);
  424.  
  425.             gCurFrame = iframe;
  426.             gTimeoutID = setTimeout (setBlank, 20000);
  427.           }
  428.         }
  429.  
  430.         load_state = content.getAttribute('loadstate');
  431.         if (load_state == 'stopped') {
  432.           load_state = 'never loaded';
  433.           toggleLoadarea(content);
  434.         }
  435.         if (load_state == 'never loaded') {
  436.           iframe.removeAttribute('hidden');
  437.           iframe.setAttribute('loadstate', 'loading');
  438.           iframe.addEventListener('load', panel_loader, true);
  439.         }
  440.       } else {
  441.         debug("item("+ii/2+")");
  442.         header.removeAttribute('selected');
  443.         content.setAttribute('collapsed','true');
  444.  
  445.         if (!panel.is_persistent()) {
  446.           iframe.setAttribute('src', 'about:blank');
  447.           load_state = content.getAttribute('loadstate');
  448.           if (load_state == 'loading') {
  449.             iframe.removeEventListener("load", panel_loader, true);
  450.             content.setAttribute('hidden','true');
  451.             iframe.setAttribute('loadstate', 'never loaded');
  452.           }
  453.         }
  454.         if (panel.is_sandboxed()) {
  455.           if (!panel.is_persistent())
  456.             iframe.setAttribute('src', 'about:blank');
  457.         }
  458.       }
  459.     }
  460.   }
  461.   if (last_header) {
  462.     last_header.setAttribute('last-panel','true');
  463.   }
  464.  
  465.   var no_panels_iframe = document.getElementById('sidebar-iframe-no-panels');
  466.   if (have_set_top) {
  467.       no_panels_iframe.setAttribute('hidden','true');
  468.       // The hide and show of 'sidebar-panels' should not be needed,
  469.       // but some old profiles may have this persisted as hidden (50973).
  470.       this.node.removeAttribute('hidden');
  471.   } else {
  472.       no_panels_iframe.removeAttribute('hidden');
  473.       this.node.setAttribute('hidden','true');
  474.   }
  475.  
  476.   this.initialized = true;
  477. }
  478.  
  479.  
  480. //////////////////////////////////////////////////////////////////////
  481. // sbPanel Class
  482. //
  483. // Like sbPanelList, this class is a wrapper around DOM representation
  484. // of individual panels in the sidebar. This UI event handlers and the
  485. // sidebar datasource observers call into this.  This class is
  486. // responsible for keeping the DOM state of the sidebar up to date.
  487. // This class does not make any changes to the sidebar rdf datasource.
  488. //////////////////////////////////////////////////////////////////////
  489.  
  490. function sbPanel(id, header, index)
  491. {
  492.   // This constructor should only be called by sbPanelList class.
  493.   // To create a panel instance, use the helper functions in sbPanelList:
  494.   //   sb_panel.get_panel_from_id(id)
  495.   //   sb_panel.get_panel_from_header_node(dom_node)
  496.   //   sb_panel.get_panel_from_header_index(index)
  497.   this.id = id;
  498.   this.header = header;
  499.   this.index = index;
  500.   this.parent = sidebarObj.panels;
  501. }
  502.  
  503. sbPanel.prototype.get_header =
  504. function ()
  505. {
  506.   return this.header;
  507. }
  508.  
  509. sbPanel.prototype.get_content =
  510. function ()
  511. {
  512.   return this.get_header().nextSibling;
  513. }
  514.  
  515. sbPanel.prototype.is_sandboxed =
  516. function ()
  517. {
  518.   if (typeof this.sandboxed == "undefined") {
  519.     var content = this.get_content();
  520.     var unsandboxed_iframe = content.childNodes.item(1);
  521.     this.sandboxed = !unsandboxed_iframe.getAttribute('content').match(/^chrome:/);
  522.   }
  523.   return this.sandboxed;
  524. }
  525.  
  526. sbPanel.prototype.get_iframe =
  527. function ()
  528. {
  529.   if (typeof this.iframe == "undefined") {
  530.     var content = this.get_content();
  531.     if (this.is_sandboxed()) {
  532.       var unsandboxed_iframe = content.childNodes.item(2);
  533.       this.iframe = unsandboxed_iframe;
  534.     } else {
  535.       var sandboxed_iframe = content.childNodes.item(1);
  536.       this.iframe = sandboxed_iframe;
  537.     }
  538.   }
  539.   return this.iframe;
  540. }
  541.  
  542. // This exclude function is used on panels and on the panel picker menu.
  543. // That is why it is hanging out in the global name space instead of
  544. // minding its own business in the class.
  545. function sb_panel_is_excluded(node)
  546. {
  547.   var exclude = node.getAttribute('exclude');
  548.   return ( exclude && exclude != '' &&
  549.            exclude.indexOf(sidebarObj.component) != -1 );
  550. }
  551. sbPanel.prototype.is_excluded =
  552. function ()
  553. {
  554.   return sb_panel_is_excluded(this.get_header());
  555. }
  556.  
  557. sbPanel.prototype.is_in_view =
  558. function()
  559. {
  560.   return (this.header.getAttribute("in-view") == "true");
  561. }
  562.  
  563. sbPanel.prototype.is_selected =
  564. function (panel_id)
  565. {
  566.   return 'true' == this.get_header().getAttribute('selected');
  567. }
  568.  
  569. sbPanel.prototype.is_persistent =
  570. function ()
  571. {
  572.     var rv = false;
  573.     var datasource = RDF.GetDataSource(sidebarObj.datasource_uri);
  574.     var persistNode = datasource.GetTarget(RDF.GetResource(this.id),
  575.                                            RDF.GetResource(NC + "persist"),
  576.                                            true);
  577.     if (persistNode)
  578.     {
  579.         persistNode = 
  580.           persistNode.QueryInterface(Components.interfaces.nsIRDFLiteral);
  581.         rv = persistNode.Value == 'true';
  582.     }
  583.  
  584.     return rv;
  585. }
  586.  
  587. sbPanel.prototype.select =
  588. function (force_reload)
  589. {
  590.   this.parent.select(this, force_reload);
  591. }
  592.  
  593. sbPanel.prototype.stop_load =
  594. function ()
  595. {
  596.   var iframe = this.get_iframe();
  597.   var content = this.get_content();
  598.   var load_state = iframe.getAttribute('loadstate');
  599.   if (load_state == "loading") {
  600.     debug("Stop the presses");
  601.     iframe.removeEventListener("load", panel_loader, true);
  602.     content.setAttribute("loadstate", "stopped");
  603.     iframe.setAttribute('src', 'about:blank');
  604.     toggleLoadarea(content);
  605.   }
  606. }
  607.  
  608. function toggleLoadarea(content)
  609. {
  610.   // toggle between "loading" and "load stopped" in the UI
  611.   var widgetBox = content.firstChild.firstChild;
  612.   var widgetBoxKids = widgetBox.childNodes;
  613.   var stopButton = widgetBoxKids.item(3);
  614.   var reloadButton = widgetBoxKids.item(4);
  615.   var loadingImage = widgetBox.firstChild;
  616.   var loadingText = loadingImage.nextSibling;
  617.   var loadStoppedText = loadingText.nextSibling;
  618.  
  619.   // sanity check
  620.   if (stopButton.getAttribute("type") != "stop")
  621.   {
  622.     debug("Error: Expected button of type=\"stop\" but didn't get one!");
  623.     return;
  624.   }
  625.  
  626.   if (!stopButton.hidden)
  627.   {
  628.     // change button from "stop" to "reload"
  629.     stopButton.hidden = "true";
  630.     reloadButton.removeAttribute("hidden");
  631.  
  632.     // hide the loading image and set text to "load stopped"
  633.     loadingImage.hidden = "true";
  634.     loadingText.hidden = "true";
  635.     loadStoppedText.removeAttribute("hidden");
  636.   }
  637.   else
  638.   {
  639.     // change button from "reload" to "stop"
  640.     stopButton.removeAttribute("hidden");
  641.     reloadButton.hidden = "true";
  642.  
  643.     // show the loading image and set text to "loading"
  644.     loadingImage.removeAttribute("hidden");
  645.     loadingText.removeAttribute("hidden");
  646.     loadStoppedText.hidden = "true";
  647.   }
  648. }
  649.  
  650. sbPanel.prototype.exclude =
  651. function ()
  652. {
  653.   // Exclusion is handled by the datasource,
  654.   // but we need to make sure this panel is no longer selected.
  655.   this.get_header().removeAttribute('selected');
  656.   this.parent.exclude(this);
  657. }
  658.  
  659. sbPanel.prototype.reload =
  660. function ()
  661. {
  662.   if (!this.is_excluded()) {
  663.     this.select(true);
  664.   }
  665. }
  666.  
  667. //////////////////////////////////////////////////////////////////
  668. // Panels' RDF Datasource Observer
  669. //
  670. // This observer will ensure that the Sidebar UI stays current
  671. // when the datasource changes.
  672. // - When "refresh" is asserted, the sidebar refreshed.
  673. //   Currently this happens when a panel is included/excluded or
  674. //   added/removed (the later comes from the customize dialog).
  675. // - When "refresh_panel" is asserted, the targeted panel is reloaded.
  676. //   Currently this happens when the customize panel dialog is closed.
  677. //////////////////////////////////////////////////////////////////
  678. var panel_observer = {
  679.   onAssert : function(ds,src,prop,target) {
  680.     //debug ("observer: assert");
  681.     // "refresh" is asserted by select menu and by customize.js.
  682.     if (prop == RDF.GetResource(NC + "refresh")) {
  683.       sidebarObj.panels.initialized = false; // reset so panels are put in view
  684.       sidebarObj.panels.refresh();
  685.     } else if (prop == RDF.GetResource(NC + "refresh_panel")) {
  686.       var panel_id = target.QueryInterface(Components.interfaces.nsIRDFLiteral).Value;
  687.       var panel = sidebarObj.panels.get_panel_from_id(panel_id);
  688.       panel.reload();
  689.     }
  690.   },
  691.   onUnassert : function(ds,src,prop,target) {
  692.     //debug ("observer: unassert");
  693.   },
  694.   onChange : function(ds,src,prop,old_target,new_target) {
  695.     //debug ("observer: change");
  696.   },
  697.   onMove : function(ds,old_src,new_src,prop,target) {
  698.     //debug ("observer: move");
  699.   },
  700.   onBeginUpdateBatch : function(ds) {
  701.     //debug ("observer: onBeginUpdateBatch");
  702.   },
  703.   onEndUpdateBatch : function(ds) {
  704.     //debug ("observer: onEndUpdateBatch");
  705.   }
  706. };
  707.  
  708. // Use an assertion to pass a "refresh" event to all the sidebars.
  709. // They use observers to watch for this assertion (see above).
  710. function refresh_all_sidebars() {
  711.   dump("refresh_all_sidebars()\n");
  712.   sidebarObj.datasource.Assert(RDF.GetResource(sidebarObj.resource),
  713.                                RDF.GetResource(NC + "refresh"),
  714.                                RDF.GetLiteral("true"),
  715.                                true);
  716.   sidebarObj.datasource.Unassert(RDF.GetResource(sidebarObj.resource),
  717.                                  RDF.GetResource(NC + "refresh"),
  718.                                  RDF.GetLiteral("true"));
  719. }
  720.  
  721. //////////////////////////////////////////////////////////////
  722. // Sidebar Init
  723. //////////////////////////////////////////////////////////////
  724. function sidebar_overlay_init() {
  725.   dump("sidebar_overlay_init()\n");
  726.   if (sidebar_is_collapsed() && !gAboutToUncollapse)
  727.     return;
  728.   gMustInit = false;
  729.   sidebarObj.panels = new sbPanelList('sidebar-panels');
  730.   sidebarObj.datasource_uri = get_sidebar_datasource_uri();
  731.   sidebarObj.resource = 'urn:sidebar:current-panel-list';
  732.  
  733.   sidebarObj.master_datasources = "";
  734.   sidebarObj.master_datasources = get_remote_datasource_url();
  735.   sidebarObj.master_datasources += " chrome://browser/content/sidebar/local-panels.rdf";
  736.   sidebarObj.master_resource = 'urn:sidebar:master-panel-list';
  737.   sidebarObj.component = document.firstChild.getAttribute('windowtype');
  738.   debug("sidebarObj.component is " + sidebarObj.component);
  739.  
  740.   // Initialize the display
  741.   var sidebar_element = document.getElementById('sidebar-box');
  742.   var sidebar_menuitem = document.getElementById('sidebar-menu');
  743.   if (sidebar_is_hidden()) {
  744.     if (sidebar_menuitem) {
  745.       sidebar_menuitem.setAttribute('checked', 'false');
  746.     }
  747.   } else {
  748.     if (sidebar_menuitem) {
  749.       sidebar_menuitem.setAttribute('checked', 'true');
  750.     }
  751.  
  752.     // for old profiles that don't persist the hidden attribute when splitter is not hidden.
  753.     var sidebar_splitter = document.getElementById('sidebar-splitter')
  754.     if (sidebar_splitter)
  755.       sidebar_splitter.setAttribute('hidden', 'false');
  756.     
  757.     if (sidebarObj.never_built) {
  758.       sidebarObj.never_built = false;
  759.       
  760.       debug("sidebar = " + sidebarObj);
  761.       debug("sidebarObj.resource = " + sidebarObj.resource);
  762.       debug("sidebarObj.datasource_uri = " + sidebarObj.datasource_uri);
  763.  
  764.       // Obtain the pref for limiting the number of tabs in view
  765.       try
  766.       {
  767.         var prefs = Components.classes["@mozilla.org/preferences-service;1"].
  768.                       getService(Components.interfaces.nsIPrefBranch);
  769.         gNumTabsInViewPref = prefs.getIntPref("sidebar.num_tabs_in_view");
  770.       }
  771.       catch (ex)
  772.       {
  773.         gNumTabsInViewPref = 8; // failover default
  774.       }
  775.  
  776.       // Show the header for the panels area. Use a splitter if there
  777.       // is stuff over the panels area.
  778.       var sidebar_panels_splitter = document.getElementById('sidebar-panels-splitter');
  779.       if (sidebar_element.firstChild != sidebar_panels_splitter) {
  780.         debug("Showing the panels splitter");
  781.         sidebar_panels_splitter.removeAttribute('hidden');
  782.       }
  783.     }
  784.     if (sidebar_is_collapsed()) {
  785.       sidebarObj.collapsed = true;
  786.     } else {
  787.       sidebarObj.collapsed = false;
  788.     }
  789.  
  790.     sidebar_open_default_panel(100, 0);
  791.   }
  792. }
  793.  
  794. function sidebar_overlay_destruct() {
  795.     var panels = document.getElementById('sidebar-panels');
  796.     debug("Removing observer from database.");
  797.     panels.database.RemoveObserver(panel_observer);
  798. }
  799.  
  800. var gBusyOpeningDefault = false;
  801.  
  802. function sidebar_open_default_panel(wait, tries) {
  803.   // check for making function reentrant
  804.   if (gBusyOpeningDefault)
  805.     return;
  806.   gBusyOpeningDefault = true;
  807.  
  808.   var ds = RDF.GetDataSource(sidebarObj.datasource_uri);
  809.   var currentListRes = RDF.GetResource("urn:sidebar:current-panel-list");
  810.   var panelListRes = RDF.GetResource("http://home.netscape.com/NC-rdf#panel-list");
  811.   var container = ds.GetTarget(currentListRes, panelListRes, true);
  812.   if (container) {
  813.     // Add the user's current panel choices to the template builder,
  814.     // which will aggregate it with the other datasources that describe
  815.     // the individual panel's title, customize URL, and content URL.
  816.     var panels = document.getElementById('sidebar-panels');
  817.     panels.database.AddDataSource(ds);
  818.     
  819.     debug("Adding observer to database.");
  820.     panels.database.AddObserver(panel_observer);
  821.  
  822.     // XXX This is a hack to force re-display
  823.     panels.builder.rebuild();
  824.   } else {
  825.     if (tries < 3) {
  826.       // No children yet, try again later
  827.       setTimeout('sidebar_open_default_panel(' + (wait*2) + ',' + (tries+1) + ')',wait);
  828.       gBusyOpeningDefault = false;
  829.       return;
  830.     } else {
  831.       sidebar_fixup_datasource();
  832.     }
  833.   }
  834.  
  835.   sidebarObj.panels.refresh();
  836.   gBusyOpeningDefault = false;
  837.   if (gCheckMissingPanels)
  838.     check_for_missing_panels();
  839. }
  840.  
  841. function SidebarRebuild() {
  842.   dump("SidebarRebuild()\n");
  843.   sidebarObj.panels.initialized = false; // reset so panels are brought in view
  844.   var panels = document.getElementById("sidebar-panels");
  845.   panels.builder.rebuild();
  846.   sidebar_open_default_panel(100, 0);
  847. }
  848.  
  849. const NS_ERROR_FILE_NOT_FOUND = 0x80520012;
  850.  
  851. function check_for_missing_panels() {
  852.   dump("check_for_missing_panels()\n");
  853.   var tabs = sidebarObj.panels.node.childNodes;
  854.   var currHeader;
  855.   var currTab;
  856.   for (var i = 2; i < tabs.length; i += 2) {
  857.     currHeader = tabs[i];
  858.     currTab = new sbPanel(currHeader.getAttribute("id"), currHeader, i);
  859.     if (!currTab.is_excluded()) {
  860.       if (currHeader.hasAttribute("prereq") && currHeader.getAttribute("prereq") != "") {
  861.         var prereq_file = currHeader.getAttribute("prereq");
  862.         var ioService = Components.classes["@mozilla.org/network/io-service;1"]
  863.                                   .getService(Components.interfaces.nsIIOService);      
  864.         var uri = ioService.newURI(prereq_file, null, null);
  865.         var channel = ioService.newChannelFromURI(uri);
  866.         try {
  867.           channel.open();
  868.         }
  869.         catch(ex if (ex.result == NS_ERROR_FILE_NOT_FOUND)) {
  870.           sidebarObj.datasource = RDF.GetDataSource(sidebarObj.datasource_uri);
  871.           sidebarObj.datasource.Assert(RDF.GetResource(currHeader.getAttribute("id")),
  872.                                        RDF.GetResource(NC + "exclude"),
  873.                                        RDF.GetLiteral(sidebarObj.component),
  874.                                        true);
  875.           currTab.exclude();
  876.         }        
  877.       }
  878.     }
  879.   }
  880.   gCheckMissingPanels = false;
  881. }
  882.  
  883. //////////////////////////////////////////////////////////////
  884. // Sidebar File and Datasource functions
  885. //////////////////////////////////////////////////////////////
  886.  
  887. function sidebar_get_panels_file() {
  888.   dump("sidebar_get_panels_file()\n");
  889.   try {
  890.     var locator_service = Components.classes["@mozilla.org/file/directory_service;1"].getService();
  891.     if (locator_service)
  892.       locator_service = locator_service.QueryInterface(Components.interfaces.nsIProperties);
  893.     // Use the fileLocator to look in the profile directory to find
  894.     // 'panels.rdf', which is the database of the user's currently
  895.     // selected panels.
  896.     // If <profile>/panels.rdf doesn't exist, GetFileLocation() will copy
  897.     // bin/defaults/profile/panels.rdf to <profile>/panels.rdf
  898.     var sidebar_file = locator_service.get(PANELS_RDF_FILE, Components.interfaces.nsIFile);
  899.     if (!sidebar_file.exists()) {
  900.       // This should not happen, as GetFileLocation() should copy
  901.       // defaults/panels.rdf to the users profile directory
  902.       debug("Sidebar panels file does not exist");
  903.       throw("Panels file does not exist");
  904.     }
  905.     return sidebar_file;
  906.   } catch (ex) {
  907.     // This should not happen
  908.     debug("Error: Unable to grab panels file.\n");
  909.     throw(ex);
  910.   }
  911.   return null;
  912. }
  913.  
  914. function sidebar_revert_to_default_panels() {
  915.   dump("sidebar_revert_to_default_panels()\n");
  916.   try {
  917.     var sidebar_file = sidebar_get_panels_file();
  918.  
  919.     sidebar_file.remove(false);
  920.  
  921.     // Since we just removed the panels file,
  922.     // this should copy the defaults over.
  923.     sidebar_file = sidebar_get_panels_file();
  924.  
  925.     debug("sidebar defaults reloaded");
  926.     var datasource = RDF.GetDataSource(sidebarObj.datasource_uri);
  927.     datasource.QueryInterface(Components.interfaces.nsIRDFRemoteDataSource).Refresh(true);
  928.   } catch (ex) {
  929.     debug("Error: Unable to reload panel defaults file.\n");
  930.   }
  931.   return null;
  932. }
  933.  
  934. function get_sidebar_datasource_uri() {
  935.   dump("get_sidebar_datasource_uri()\n");
  936.   try {
  937.     var sidebar_file = sidebar_get_panels_file();
  938.     
  939.     var ioService = Components.classes["@mozilla.org/network/io-service;1"].getService(Components.interfaces.nsIIOService);
  940.     var fileHandler = ioService.getProtocolHandler("file").QueryInterface(Components.interfaces.nsIFileProtocolHandler);
  941.     
  942.     return fileHandler.getURLSpecFromFile(sidebar_file);
  943.   } catch (ex) {
  944.     // This should not happen
  945.     debug("Error: Unable to load panels file.\n");
  946.   }
  947.   return null;
  948. }
  949.  
  950. // Get the template for the available panels url from preferences.
  951. // Replace variables in the url:
  952. //     %LOCALE%  -->  Application locale (e.g. en-us).
  953. //     %VERSION% --> Sidebar file format version (e.g. 0.0).
  954. function get_remote_datasource_url() {
  955.   dump("get_remote_datasource_url()\n");
  956.   var url = '';
  957.   var prefs = Components.classes["@mozilla.org/preferences-service;1"]
  958.                         .getService(Components.interfaces.nsIPrefBranch);
  959.   var locale;
  960.   try {
  961.     if (prefs.getPrefType("sidebar.customize.all_panels.url") == prefs.PREF_STRING) {
  962.         url = prefs.getCharPref("sidebar.customize.all_panels.url");
  963.         url = url.replace(/%SIDEBAR_VERSION%/g, SIDEBAR_VERSION);
  964.     }
  965.   } catch(ex) {
  966.     debug("Unable to get remote url pref. What now? "+ex);
  967.   }
  968.   try {
  969.     locale = prefs.getComplexValue("intl.content.langcode",
  970.                                    Components.interfaces.nsIPrefLocalizedString);
  971.   } catch(ex) {
  972.     try {
  973.       debug("No lang code pref, intl.content.langcode.");
  974.       debug("Use locale from user agent string instead");
  975.  
  976.       locale = prefs.getComplexValue("general.useragent.locale",
  977.                                      Components.interfaces.nsIPrefLocalizedString);
  978.   } catch(ex) {
  979.       debug("Unable to get system locale. What now? "+ex);
  980.     }
  981.   }
  982.   locale = locale.data.toLowerCase();
  983.   url = url.replace(/%LOCALE%/g, locale);
  984.  
  985.   debug("Remote url is " + url);
  986.   return url;
  987. }
  988.  
  989. function sidebar_fixup_datasource() {
  990.   dump("sidebar_fixup_datasource()\n");
  991.   var datasource = RDF.GetDataSource(sidebarObj.datasource_uri);
  992.   var resource = RDF.GetResource(sidebarObj.resource);
  993.  
  994.   var panel_list = datasource.GetTarget(resource,
  995.                                         RDF.GetResource(NC+"panel-list"),
  996.                                         true);
  997.   if (!panel_list) {
  998.     debug("Sidebar datasource is an old format or busted\n");
  999.     sidebar_revert_to_default_panels();
  1000.   } else {
  1001.     // The datasource is ok, but it just has no panels.
  1002.     // sidebar_refresh() will display some helper content.
  1003.     // Do nothing here.
  1004.   }
  1005. }
  1006.  
  1007. //////////////////////////////////////////////////////////////
  1008. // Sidebar Interface for XUL
  1009. //////////////////////////////////////////////////////////////
  1010.  
  1011. // Change the sidebar content to the selected panel.
  1012. // Called when a panel title is clicked.
  1013. function SidebarSelectPanel(header, should_popopen, should_unhide) {
  1014.   debug("SidebarSelectPanel("+header+","+should_popopen+","+should_unhide+")");
  1015.   var panel = sidebarObj.panels.get_panel_from_header_node(header);
  1016.  
  1017.   if (!panel) {
  1018.     return false;
  1019.   }
  1020.  
  1021.   var popopen = false;
  1022.   var unhide = false;
  1023.  
  1024.   if (panel.is_excluded()) {
  1025.     return false;
  1026.   }
  1027.   if (sidebar_is_hidden()) {
  1028.     if (should_unhide) {
  1029.       unhide = true;
  1030.     } else {
  1031.       return false;
  1032.     }
  1033.   }
  1034.   if (sidebar_is_collapsed()) {
  1035.     if (should_popopen) {
  1036.       popopen = true;
  1037.     } else {
  1038.       return false;
  1039.     }
  1040.   }
  1041.   if (unhide)  SidebarShowHide();
  1042.   if (popopen) SidebarExpandCollapse();
  1043.  
  1044.   try { 
  1045.     panel.get_iframe().setAttribute('focusOnLoad', true); 
  1046.   } catch (ex) { 
  1047.     // ignore exception for cases where content isn't built yet
  1048.     // e.g., auto opening search tab: we don't want to focus search field
  1049.   }
  1050.   if (!panel.is_selected()) panel.select(false);
  1051.  
  1052.   return true;
  1053. }
  1054.  
  1055. function SidebarGetLastSelectedPanel()
  1056. {
  1057.   return (sidebarObj.panels && 
  1058.           sidebarObj.panels.node.getAttribute('last-selected-panel'));
  1059. }
  1060.  
  1061. function SidebarGetRelativePanel(direction)
  1062. {
  1063.   // direction == 1 to view next panel, -1 to view prev panel
  1064.  
  1065.   if (sidebar_is_hidden())
  1066.     SidebarShowHide();
  1067.   if (sidebar_is_collapsed())
  1068.     SidebarExpandCollapse();
  1069.  
  1070.   var currentPanel = sidebarObj.panels.get_panel_from_id(SidebarGetLastSelectedPanel());
  1071.   if (!currentPanel) {
  1072.     sidebarObj.panels.select_default_panel();
  1073.     return;
  1074.   }
  1075.  
  1076.   var newPanel = currentPanel;
  1077.  
  1078.   do {
  1079.     var newPanelIndex = newPanel.index + (direction * 2);
  1080.     if (newPanelIndex < 2 || newPanelIndex >= sidebarObj.panels.node.childNodes.length)
  1081.       newPanel = (direction == 1)? sidebarObj.panels.find_first(): sidebarObj.panels.find_last();
  1082.     else 
  1083.       newPanel = sidebarObj.panels.get_panel_from_header_index(newPanelIndex);
  1084.  
  1085.     if (!newPanel)
  1086.       break;
  1087.  
  1088.     if (!newPanel.is_excluded()) {
  1089.       SidebarSelectPanel(newPanel.header, true, true);  // found a panel that's not excluded to select -- do it
  1090.       break;
  1091.     }
  1092.   } while (newPanel != currentPanel);  // keep looking for a panel, but don't loop infinitely
  1093. }
  1094.  
  1095. function SidebarStopPanelLoad(header) {
  1096.   var panel = sidebarObj.panels.get_panel_from_header_node(header);
  1097.   panel.stop_load();
  1098. }
  1099.  
  1100. function SidebarReloadPanel(header) {
  1101.   var panel = sidebarObj.panels.get_panel_from_header_node(header);
  1102.   panel.reload();
  1103. }
  1104.  
  1105. // No one is calling this right now.
  1106. function SidebarReload() {
  1107.   sidebarObj.panels.refresh();
  1108. }
  1109.  
  1110. // Set up a lame hack to avoid opening two customize
  1111. // windows on a double click.
  1112. var gDisableCustomize = false;
  1113. function enable_customize() {
  1114.   gDisableCustomize = false;
  1115. }
  1116.  
  1117. // Bring up the Sidebar customize dialog.
  1118. function SidebarCustomize() {
  1119.   // Use a single sidebar customize dialog
  1120.   var cwindowManager = Components.classes['@mozilla.org/appshell/window-mediator;1'].getService();
  1121.   var iwindowManager = Components.interfaces.nsIWindowMediator;
  1122.   var windowManager  = cwindowManager.QueryInterface(iwindowManager);
  1123.  
  1124.   var customizeWindow = windowManager.getMostRecentWindow('sidebar:customize');
  1125.  
  1126.   if (customizeWindow) {
  1127.     debug("Reuse existing customize dialog");
  1128.     customizeWindow.focus();
  1129.   } else {
  1130.     debug("Open a new customize dialog");
  1131.  
  1132.     if (false == gDisableCustomize) {
  1133.       debug("First time creating customize dialog");
  1134.       gDisableCustomize = true;
  1135.  
  1136.       var panels = document.getElementById('sidebar-panels');
  1137.  
  1138.       customizeWindow = window.openDialog(
  1139.                          'chrome://browser/content/sidebar/customize.xul',
  1140.                          '_blank','centerscreen,chrome,resizable,dialog=no,dependent',
  1141.                          sidebarObj.master_datasources,
  1142.                          sidebarObj.master_resource,
  1143.                          sidebarObj.datasource_uri,
  1144.                          sidebarObj.resource);
  1145.       setTimeout(enable_customize, 2000);
  1146.     }
  1147.   }
  1148. }
  1149.  
  1150. function BrowseMorePanels()
  1151. {
  1152.   var url = '';
  1153.   var browser_url = "chrome://browser/content/browser.xul";
  1154.   var locale;
  1155.   try {
  1156.     var prefs = Components.classes["@mozilla.org/preferences-service;1"]
  1157.                           .getService(Components.interfaces.nsIPrefBranch);
  1158.     url = prefs.getCharPref("sidebar.customize.directory.url");
  1159.     var temp = prefs.getCharPref("browser.chromeURL");
  1160.     if (temp) browser_url = temp;
  1161.   } catch(ex) {
  1162.     debug("Unable to get prefs: "+ex);
  1163.   }
  1164.   window.openDialog(browser_url, "_blank", "chrome,all,dialog=no", url);
  1165. }
  1166.  
  1167.  
  1168.  
  1169. function sidebar_is_collapsed() {
  1170.   var sidebar_splitter = document.getElementById('sidebar-splitter');
  1171.   return (sidebar_splitter &&
  1172.           sidebar_splitter.getAttribute('state') == 'collapsed');
  1173. }
  1174.  
  1175. function SidebarExpandCollapse() {
  1176.   var sidebar_splitter = document.getElementById('sidebar-splitter');
  1177.   var sidebar_box = document.getElementById('sidebar-box');
  1178.   if (sidebar_splitter.getAttribute('state') == 'collapsed') {
  1179.     if (gMustInit)
  1180.       sidebar_overlay_init();
  1181.     debug("Expanding the sidebar");
  1182.     sidebar_splitter.removeAttribute('state');
  1183.     sidebar_box.removeAttribute('collapsed');
  1184.     SidebarSetButtonOpen(true);
  1185.   } else {
  1186.     debug("Collapsing the sidebar");
  1187.     sidebar_splitter.setAttribute('state', 'collapsed');
  1188.     sidebar_box.setAttribute('collapsed', 'true');
  1189.     SidebarSetButtonOpen(false);
  1190.   }
  1191. }
  1192.  
  1193. // sidebar_is_hidden() - Helper function for SidebarShowHide().
  1194. function sidebar_is_hidden() {
  1195.   var sidebar_title = document.getElementById('sidebar-title-box');
  1196.   var sidebar_box = document.getElementById('sidebar-box');
  1197.   return sidebar_box.getAttribute('hidden') == 'true'
  1198.          || sidebar_title.getAttribute('hidden') == 'true';
  1199. }
  1200.  
  1201. // Show/Hide the entire sidebar.
  1202. // Invoked by the "View / Sidebar" menu option.
  1203. function SidebarShowHide() {
  1204.   var sidebar_box = document.getElementById('sidebar-box');
  1205.   var title_box = document.getElementById('sidebar-title-box');
  1206.   var sidebar_panels_splitter = document.getElementById('sidebar-panels-splitter');
  1207.   var sidebar_panels_splitter_box = document.getElementById('sidebar-panels-splitter-box');
  1208.   var sidebar_splitter = document.getElementById('sidebar-splitter');
  1209.   var sidebar_menu_item = document.getElementById('sidebar-menu');
  1210.   var tabs_menu = document.getElementById('sidebar-panel-picker');
  1211.  
  1212.   if (sidebar_is_hidden()) {
  1213.     debug("Showing the sidebar");
  1214.  
  1215.     // for older profiles: 
  1216.     sidebar_box.setAttribute('hidden', 'false'); 
  1217.     sidebar_panels_splitter_box.setAttribute('hidden', 'false'); 
  1218.  
  1219.     sidebar_box.removeAttribute('collapsed');
  1220.     if (sidebar_splitter.getAttribute('state') == 'collapsed')
  1221.       sidebar_splitter.removeAttribute('state');
  1222.     title_box.removeAttribute('hidden');
  1223.     sidebar_panels_splitter_box.removeAttribute('collapsed');
  1224.     sidebar_splitter.setAttribute('hidden', 'false');
  1225.     if (sidebar_box.firstChild != sidebar_panels_splitter) {
  1226.       debug("Showing the panels splitter");
  1227.       sidebar_panels_splitter.removeAttribute('hidden');
  1228.       if (sidebar_panels_splitter.getAttribute('state') == 'collapsed')
  1229.         sidebar_panels_splitter.removeAttribute('state');
  1230.     }
  1231.     sidebar_overlay_init();
  1232.     sidebar_menu_item.setAttribute('checked', 'true');
  1233.     tabs_menu.removeAttribute('hidden');
  1234.     SidebarSetButtonOpen(true);
  1235.   } else {
  1236.     debug("Hiding the sidebar");
  1237.     var hide_everything = sidebar_panels_splitter.getAttribute('hidden') == 'true';
  1238.     if (hide_everything) {
  1239.       debug("Hide everything");
  1240.       sidebar_box.setAttribute('collapsed', 'true');
  1241.       sidebar_splitter.setAttribute('hidden', 'true');
  1242.     } else {
  1243.       sidebar_panels_splitter.setAttribute('hidden', 'true');
  1244.     }
  1245.     title_box.setAttribute('hidden', 'true');
  1246.     sidebar_panels_splitter_box.setAttribute('collapsed', 'true');
  1247.     sidebar_menu_item.setAttribute('checked', 'false');
  1248.     tabs_menu.setAttribute('hidden', 'true');
  1249.     SidebarSetButtonOpen(false);
  1250.   }
  1251.   // Immediately save persistent values
  1252.   document.persist('sidebar-title-box', 'hidden');
  1253.   persist_width();
  1254.   window._content.focus();
  1255. }
  1256.  
  1257. function SidebarBuildPickerPopup() {
  1258.   var menu = document.getElementById('sidebar-panel-picker-popup');
  1259.   menu.database.AddDataSource(RDF.GetDataSource(sidebarObj.datasource_uri));
  1260.   menu.builder.rebuild();
  1261.  
  1262.   for (var ii=3; ii < menu.childNodes.length; ii++) {
  1263.     var panel_menuitem = menu.childNodes.item(ii);
  1264.     if (sb_panel_is_excluded(panel_menuitem)) {
  1265.       debug(ii+": "+panel_menuitem.getAttribute('label')+ ": excluded; uncheck.");
  1266.       panel_menuitem.removeAttribute('checked');
  1267.     } else {
  1268.       debug(ii+": "+panel_menuitem.getAttribute('label')+ ": included; check.");
  1269.       panel_menuitem.setAttribute('checked', 'true');
  1270.     }
  1271.   }
  1272. }
  1273.  
  1274. function SidebarTogglePanel(panel_menuitem) {
  1275.   // Create a "container" wrapper around the current panels to
  1276.   // manipulate the RDF:Seq more easily.
  1277.   dump("SidebarTogglePanel - panel_menuitem= " + panel_menuitem + "\n");
  1278.   sidebarObj.datasource = RDF.GetDataSource(sidebarObj.datasource_uri);
  1279.  
  1280.   var did_exclude = false;
  1281.   var panel_id = panel_menuitem.getAttribute('id');
  1282.   var panel = sidebarObj.panels.get_panel_from_id(panel_id);
  1283.   var panel_exclude = panel_menuitem.getAttribute('exclude')
  1284.   if (panel_exclude == '') {
  1285.     // Nothing excluded for this panel yet, so add this component to the list.
  1286.     debug("Excluding " + panel_id + " from " + sidebarObj.component);
  1287.     sidebarObj.datasource.Assert(RDF.GetResource(panel_id),
  1288.                                 RDF.GetResource(NC + "exclude"),
  1289.                                 RDF.GetLiteral(sidebarObj.component),
  1290.                                 true);
  1291.     panel.exclude();
  1292.     did_exclude = true;
  1293.   } else {
  1294.     // Panel has an exclude string, but it may or may not have the
  1295.     // current component listed in the string.
  1296.     debug("Current exclude string: " + panel_exclude);
  1297.     var new_exclude = panel_exclude;
  1298.     if (sb_panel_is_excluded(panel_menuitem)) {
  1299.       debug("Plucking this component out of the exclude list");
  1300.       replace_pat = new RegExp(sidebarObj.component + "\s*");
  1301.       new_exclude = new_exclude.replace(replace_pat,'');
  1302.       new_exclude = new_exclude.replace(/^\s+/,'');
  1303.       // did_exclude remains false
  1304.     } else {
  1305.       debug("Adding this component to the exclude list");
  1306.       new_exclude = new_exclude + " " + sidebarObj.component;
  1307.       panel.exclude();
  1308.       did_exclude = true;
  1309.     }
  1310.     if (new_exclude == '') {
  1311.       debug("Removing exclude list");
  1312.       sidebarObj.datasource.Unassert(RDF.GetResource(panel_id),
  1313.                                      RDF.GetResource(NC + "exclude"),
  1314.                                      RDF.GetLiteral(sidebarObj.component));
  1315.     } else {
  1316.       debug("New exclude string: " + new_exclude);
  1317.       exclude_target =
  1318.         sidebarObj.datasource.GetTarget(RDF.GetResource(panel_id),
  1319.                                         RDF.GetResource(NC + "exclude"),
  1320.                                         true);
  1321.       sidebarObj.datasource.Change(RDF.GetResource(panel_id),
  1322.                                    RDF.GetResource(NC + "exclude"),
  1323.                                    exclude_target,
  1324.                                    RDF.GetLiteral(new_exclude));
  1325.     }
  1326.   }
  1327.  
  1328.   if (did_exclude)
  1329.   {
  1330.     // if we excluded a tab in view then add another one
  1331.     var tabs = sidebarObj.panels.node.childNodes;
  1332.     if (panel.is_in_view())
  1333.     {
  1334.       // we excluded one so let's try to bring a non-excluded one into view
  1335.       var newFirst = null;
  1336.       var added = false;
  1337.       for (var i = 2; i < tabs.length ; i += 2)
  1338.       {
  1339.         var currTab = sidebarObj.panels.get_panel_from_header_index(i);
  1340.         var hasPotential = !currTab.is_excluded() && !currTab.is_in_view();
  1341.  
  1342.         // set potential new first tab in case we can't find one after the
  1343.         // tab that was just excluded
  1344.         if (!newFirst && hasPotential)
  1345.           newFirst = currTab;
  1346.  
  1347.         if (i > panel.index && hasPotential)
  1348.         {
  1349.           currTab.header.setAttribute("in-view", true);
  1350.           added = true;
  1351.           break;
  1352.         }
  1353.       }
  1354.       if (!added && newFirst)
  1355.         newFirst.header.setAttribute("in-view", true);
  1356.  
  1357.       // lose it from current view
  1358.       panel.header.setAttribute("in-view", false);
  1359.     }
  1360.   }
  1361.   else
  1362.   {
  1363.     panel.header.setAttribute("in-view", true);
  1364.     // MERC - Stevo Added missing var tabs (Bugzilla #1294)
  1365.     var tabs = sidebarObj.panels.node.childNodes;
  1366.  
  1367.     // if we have one too many tabs we better get rid of an old one
  1368.     if (sidebarObj.panels.num_panels_in_view() > gNumTabsInViewPref)
  1369.     {
  1370.       // we included a new tab so let's take the last one out of view
  1371.       for (i = 2; i < tabs.length; i += 2)
  1372.       {
  1373.         var currHeader = tabs[i];
  1374.         if (currHeader.hasAttribute("last-panel"))
  1375.           currHeader.setAttribute("in-view", false);
  1376.       }
  1377.     }
  1378.  
  1379.     panel.select(false);
  1380.   }
  1381.  
  1382.   if (did_exclude && !sidebarObj.panels.visible_panels_exist()) 
  1383.     // surrender focus to main content area
  1384.     window._content.focus();
  1385.   else
  1386.     // force all the sidebars to update
  1387.     refresh_all_sidebars();
  1388.  
  1389.   // Write the modified panels out.
  1390.   sidebarObj.datasource.QueryInterface(Components.interfaces.nsIRDFRemoteDataSource).Flush();
  1391. }
  1392.  
  1393. function SidebarNavigate(aDirection)
  1394. {
  1395.   debug("SidebarNavigate " + aDirection);
  1396.  
  1397.   var tabs = sidebarObj.panels.node.childNodes;
  1398.   var i;
  1399.   var currHeader;
  1400.   var currTab;
  1401.   // move forward a tab (down in the template)
  1402.   if (aDirection > 0)
  1403.   {
  1404.     // ensure we have a tab below the last one
  1405.     var foundLast = false; 
  1406.     var oldFirst = null;
  1407.     for (i = 2; i < tabs.length; i += 2) 
  1408.     {
  1409.       currHeader = tabs[i];
  1410.       currTab = new sbPanel(currHeader.getAttribute("id"), currHeader, i);
  1411.   
  1412.       if (!currTab.is_excluded())
  1413.       {     
  1414.         if (foundLast)
  1415.         {
  1416.           debug("toggling old first and new last");
  1417.           debug("new last:  " + currHeader.getAttribute("id"));
  1418.           debug("old first: " + oldFirst.getAttribute("id"));
  1419.           currHeader.setAttribute("in-view", true);
  1420.           oldFirst.setAttribute("in-view", false);
  1421.           
  1422.           // if old first was selected select new first instead
  1423.           if (oldFirst.getAttribute("id") == 
  1424.               sidebarObj.panels.node.getAttribute("last-selected-panel"))
  1425.           {
  1426.             sidebarObj.panels.node.setAttribute('last-selected-panel', 
  1427.               currTab.id);
  1428.           }
  1429.           
  1430.           break;
  1431.         }
  1432.  
  1433.         if (!foundLast && currHeader.hasAttribute("last-panel"))
  1434.         {
  1435.           debug("found last");
  1436.           foundLast = true;
  1437.         }
  1438.  
  1439.         // set the old first in case we find a new last below
  1440.         // the old last and need to toggle the new first's ``in-view''
  1441.         if (!oldFirst && currTab.is_in_view())
  1442.           oldFirst = currHeader;
  1443.       }
  1444.     }
  1445.   }
  1446.   
  1447.   // move back a tab (up in the template)
  1448.   else if (aDirection < 0)
  1449.   {
  1450.     var newFirst = null, newLast = null;
  1451.     var foundFirst = false;
  1452.     for (i = 2; i < tabs.length; i += 2)
  1453.     {
  1454.       currHeader = tabs[i];
  1455.       currTab = new sbPanel(currHeader.getAttribute("id"), currHeader, i);
  1456.  
  1457.       if (!currTab.is_excluded())
  1458.       {
  1459.         if (!foundFirst && currHeader.hasAttribute("top-panel"))
  1460.         {
  1461.           debug("found first");
  1462.           foundFirst = true;
  1463.         }
  1464.         if (!foundFirst)
  1465.         {
  1466.           debug("setting newFirst");
  1467.           newFirst = currHeader;
  1468.         }
  1469.  
  1470.         if (currHeader.hasAttribute("last-panel"))
  1471.         {
  1472.           debug("found last");
  1473.  
  1474.           // ensure we have a tab above the first one
  1475.           if (newFirst)
  1476.           {
  1477.             debug("toggling new first and old last");
  1478.             debug("new first: " + newFirst.getAttribute("id"));
  1479.             debug("old last:  " + currHeader.getAttribute("id"));
  1480.  
  1481.             newFirst.setAttribute("in-view", true);
  1482.             currHeader.setAttribute("in-view", false); // hide old last
  1483.           
  1484.             // if old last was selected, now select one above it
  1485.             if (sidebarObj.panels.node.getAttribute("last-selected-panel") ==
  1486.                 currTab.id)
  1487.             {
  1488.               sidebarObj.panels.node.setAttribute("last-selected-panel", 
  1489.                 newLast.getAttribute("id"));
  1490.             }
  1491.  
  1492.             break;
  1493.           }
  1494.         }
  1495.         if (currTab.is_in_view())
  1496.           newLast = currHeader;
  1497.       }
  1498.     }
  1499.   }
  1500.  
  1501.   if (aDirection)
  1502.     sidebarObj.panels.update(false);
  1503. }
  1504.  
  1505. //////////////////////////////// SEARCH ////////////////////////////////////
  1506.  
  1507. function UpdateInternetSearchResults(event)
  1508. {
  1509.   dump('UpdateInternetSearchResults()\n');
  1510.   var url = getWebNavigation().currentURI.spec;
  1511.   if (url) {
  1512.    // try {
  1513.       var autoOpenSearchPanel = 
  1514.         gPrefService.getBoolPref("browser.search.opensidebarsearchpanel");
  1515.  
  1516.       if (autoOpenSearchPanel || isSearchPanelOpen())
  1517.       {
  1518.         if (!gSearchService)
  1519.           gSearchService = Components.classes["@mozilla.org/rdf/datasource;1?name=internetsearch"]
  1520.                                          .getService(Components.interfaces.nsIInternetSearchService);
  1521.  
  1522.         var searchInProgressFlag = gSearchService.FindInternetSearchResults(url);
  1523.  
  1524.         if (searchInProgressFlag) {
  1525.           if (autoOpenSearchPanel)
  1526.             RevealSearchPanel();
  1527.         }
  1528.       }
  1529. /*
  1530.     } catch (ex) {
  1531.       dump('Exception in UpdateInternetSearchResults()\n');
  1532.     }
  1533. */
  1534.   }
  1535. }
  1536.  
  1537. function RevealSearchPanel()
  1538. {
  1539.   dump('RevealSearchPanel()\n');
  1540.   var searchPanel = document.getElementById("urn:sidebar:panel:search");
  1541.   if (searchPanel)
  1542.     SidebarSelectPanel(searchPanel, true, true); // lives in sidebarOverlay.js
  1543. }
  1544.  
  1545. function isSearchPanelOpen()
  1546. {
  1547.   dump('isSearchPanelOpen()\n');
  1548.   return ( !sidebar_is_hidden()    && 
  1549.            !sidebar_is_collapsed() && 
  1550.            SidebarGetLastSelectedPanel() == "urn:sidebar:panel:search"
  1551.          );
  1552. }
  1553.  
  1554. //////////////////////////////////////////////////////////////
  1555. // Sidebar Hacks and Work-arounds
  1556. //////////////////////////////////////////////////////////////
  1557.  
  1558. // SidebarCleanUpExpandCollapse() - Respond to grippy click.
  1559. function SidebarCleanUpExpandCollapse() {
  1560.   // XXX Mini hack. Persist isn't working too well. Force the persist,
  1561.   // but wait until the change has commited.
  1562.   if (gMustInit) {
  1563.     gAboutToUncollapse = true;
  1564.     sidebar_overlay_init();
  1565.   }
  1566.  
  1567.   setTimeout("document.persist('sidebar-box', 'collapsed');",100);
  1568.   setTimeout("sidebarObj.panels.refresh();",100);
  1569. }
  1570.  
  1571. function PersistHeight() {
  1572.   // XXX Mini hack. Persist isn't working too well. Force the persist,
  1573.   // but wait until the last drag has been committed.
  1574.   // May want to do something smarter here like only force it if the
  1575.   // height has really changed.
  1576.   setTimeout("document.persist('sidebar-panels-splitter-box','height');",100);
  1577. }
  1578.  
  1579. function persist_width() {
  1580.   // XXX Mini hack. Persist isn't working too well. Force the persist,
  1581.   // but wait until the width change has commited.
  1582.   setTimeout("document.persist('sidebar-box', 'width');",100);
  1583.  
  1584.   var is_collapsed = document.getElementById('sidebar-box').
  1585.                        getAttribute('collapsed') == 'true';
  1586.   SidebarSetButtonOpen(!is_collapsed);
  1587. }
  1588.  
  1589. function SidebarFinishClick() {
  1590.  
  1591.   // XXX Semi-hack for bug #16516.
  1592.   // If we had the proper drag event listener, we would not need this
  1593.   // timeout. The timeout makes sure the width is written to disk after
  1594.   // the sidebar-box gets the newly dragged width.
  1595.   setTimeout("persist_width()",100);
  1596.  
  1597.   var is_collapsed = document.getElementById('sidebar-box').getAttribute('collapsed') == 'true';
  1598.   debug("collapsed: " + is_collapsed);
  1599.   if (is_collapsed != sidebarObj.collapsed) {
  1600.     if (gMustInit)
  1601.       sidebar_overlay_init();
  1602.   }
  1603. }
  1604.  
  1605. function SidebarSetButtonOpen(aSidebarNowOpen)
  1606. {
  1607.   dump("SidebarSetButtonOpen("+aSidebarNowOpen+");\n");
  1608.   // change state so toolbar icon can be updated
  1609.   var tb = document.getElementById("content");
  1610.   // Don't know why, but this intermediary step seems to be required... !
  1611.   var tabs = document.getAnonymousElementByAttribute(tb, 'class', 'tabbrowser-tabs');
  1612.   var sb = document.getAnonymousElementByAttribute(tabs,'anonid','sidebar-button');
  1613.   if (sb) {
  1614.     sb.setAttribute("sidebaropen", aSidebarNowOpen);
  1615.  
  1616.     // set tooltip for toolbar icon
  1617.     var header = document.getElementById("sidebar-title-box");
  1618.     var tooltip = header.getAttribute(aSidebarNowOpen ? 
  1619.                   "tooltipclose" : "tooltipopen");
  1620.     sb.setAttribute("tooltiptext", tooltip);
  1621.   }
  1622. }
  1623.  
  1624. function SidebarInitContextMenu(aMenu, aPopupNode)
  1625. {
  1626.   var panel = sidebarObj.panels.get_panel_from_header_node(aPopupNode);
  1627.   var switchItem = document.getElementById("switch-ctx-item");
  1628.   var reloadItem = document.getElementById("reload-ctx-item");
  1629.   var stopItem = document.getElementById("stop-ctx-item");
  1630.  
  1631.   // the current panel can be reloaded, but other panels are not showing 
  1632.   // any content, so we only allow you to switch to other panels
  1633.   if (panel.is_selected()) 
  1634.   {
  1635.     switchItem.setAttribute("collapsed", "true"); 
  1636.     reloadItem.removeAttribute("disabled");
  1637.   }
  1638.   else 
  1639.   {
  1640.     switchItem.removeAttribute("collapsed");
  1641.     reloadItem.setAttribute("disabled", "true");
  1642.   }
  1643.  
  1644.   // only if a panel is currently loading enable the ``Stop'' item
  1645.   if (panel.get_iframe().getAttribute("loadstate") == "loading")
  1646.     stopItem.removeAttribute("disabled");
  1647.   else
  1648.     stopItem.setAttribute("disabled", "true");
  1649. }
  1650.  
  1651. ///////////////////////////////////////////////////////////////
  1652. // Handy Debug Tools
  1653. //////////////////////////////////////////////////////////////
  1654. var debug = null;
  1655. var dump_attributes = null;
  1656. var dump_tree = null;
  1657. if (!SB_DEBUG) {
  1658.   debug = function (s) {};
  1659.   dump_attributes = function (node, depth) {};
  1660.   dump_tree = function (node) {};
  1661.   var _dump_tree_recur = function (node, depth, index) {};
  1662. } else {
  1663.   debug = function (s) { dump("-*- sbOverlay: " + s + "\n"); };
  1664.  
  1665.   dump_attributes = function (node, depth) {
  1666.     var attributes = node.attributes;
  1667.     var indent = "| | | | | | | | | | | | | | | | | | | | | | | | | | | | . ";
  1668.  
  1669.     if (!attributes || attributes.length == 0) {
  1670.       debug(indent.substr(indent.length - depth*2) + "no attributes");
  1671.     }
  1672.     for (var ii=0; ii < attributes.length; ii++) {
  1673.       var attr = attributes.item(ii);
  1674.       debug(indent.substr(indent.length - depth*2) + attr.name +
  1675.             "=" + attr.value);
  1676.     }
  1677.   }
  1678.   dump_tree = function (node) {
  1679.     _dump_tree_recur(node, 0, 0);
  1680.   }
  1681.   _dump_tree_recur = function (node, depth, index) {
  1682.     if (!node) {
  1683.       debug("dump_tree: node is null");
  1684.     }
  1685.     var indent = "| | | | | | | | | | | | | | | | | | | | | | | | | | | | + ";
  1686.     debug(indent.substr(indent.length - depth*2) + index +
  1687.           " " + node.nodeName);
  1688.     if (node.nodeName != "#text") {
  1689.       dump_attributes(node, depth);
  1690.     }
  1691.     var kids = node.childNodes;
  1692.     for (var ii=0; ii < kids.length; ii++) {
  1693.       _dump_tree_recur(kids[ii], depth + 1, ii);
  1694.     }
  1695.   }
  1696. }
  1697.  
  1698. //////////////////////////////////////////////////////////////
  1699. // Install the load/unload handlers
  1700. //////////////////////////////////////////////////////////////
  1701. addEventListener("load", sidebar_overlay_init, false);
  1702. addEventListener("unload", sidebar_overlay_destruct, false);
  1703.  
  1704.  
  1705. //****************************************************************
  1706. // This function will activate the sidebar panel specified by
  1707. // 'panel_id'. If the panel is not already visible in the
  1708. // sidebar, it is added.  Sidebar is displayed if hidden.
  1709. // |wait| and |tries| are for re-entrant calls
  1710. //****************************************************************
  1711. function RevealPanel(panel_id, wait, tries) {
  1712.   debug('sidebarOverlay.js: RevealPanel(panel_id:'+panel_id
  1713.         +',wait:'+wait+',tries:'+tries+')');
  1714.  
  1715.   // First make sure the sidebar is open
  1716.   if (sidebar_is_hidden()) {
  1717.     SidebarShowHide();
  1718.   }
  1719.  
  1720.   // MERC: SL - give sidebar panels a bit of time to load up first
  1721.   //    time you launch browser
  1722.   // If the panel is not in the list, don't bother opening it.
  1723.   var panel = document.getElementById(panel_id);
  1724.   if (!panel) {
  1725.    dump("unable to open panel in RevealPanel " + panel_id + "\n");
  1726.    if (numTries > 2) return;
  1727.    numTries++;
  1728.   }
  1729.  
  1730.   var panelObj = sidebarObj.panels.get_panel_from_id(panel_id);
  1731.   
  1732.   if (!panelObj) {
  1733.     // The panel does not exist yet.  This probably means we need to give
  1734.     // the sidebar a bit more time to load.
  1735.     if (!wait) wait = 100;
  1736.     if (!tries) tries = 3;
  1737.     if (tries) {
  1738.       setTimeout("RevealPanel('"+panel_id+"',"+wait+","+(tries-1)+");", wait);
  1739.       return;
  1740.     }
  1741.   }
  1742.  
  1743.   var panel = document.getElementById(panel_id);
  1744.  
  1745.   // if the panel is not in the sidebar panel list, add it
  1746.   if (!panelObj.is_in_view()) {
  1747.     SidebarTogglePanel(panel);
  1748.   }
  1749.  
  1750.   // activate panel and make sidebar visible
  1751.   SidebarSelectPanel(panel, true, true);
  1752.  
  1753.   // return the panel object
  1754.   return panelObj;
  1755. }
  1756.