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 / customize.js < prev    next >
Encoding:
Text File  |  2005-07-29  |  23.8 KB  |  701 lines

  1. /* -*- Mode: Java; tab-width: 4; insert-tabs-mode: nil; c-basic-offset: 2 -*-
  2.  * The contents of this file are subject to the Netscape Public
  3.  * License Version 1.1 (the "License"); you may not use this file
  4.  * except in compliance with the License. You may obtain a copy of
  5.  * the License at http://www.mozilla.org/NPL/
  6.  *
  7.  * Software distributed under the License is distributed on an "AS
  8.  * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
  9.  * implied. See the License for the specific language governing
  10.  * rights and limitations under the License.
  11.  *
  12.  * The Original Code is Mozilla Communicator client code, released
  13.  * March 31, 1998.
  14.  *
  15.  * The Initial Developer of the Original Code is Netscape
  16.  * Communications Corporation. Portions created by Netscape are
  17.  * Copyright (C) 1998-1999 Netscape Communications Corporation. All
  18.  * Rights Reserved.
  19.  *
  20.  */
  21.  
  22. //////////////////////////////////////////////////////////////
  23. // Global variables
  24. //////////////////////////////////////////////////////////////
  25.  
  26. // Set to true for noise
  27. const CUST_DEBUG = true;
  28.  
  29. // the rdf service
  30. var RDF = '@mozilla.org/rdf/rdf-service;1'
  31. RDF = Components.classes[RDF].getService();
  32. RDF = RDF.QueryInterface(Components.interfaces.nsIRDFService);
  33.  
  34. var NC = "http://home.netscape.com/NC-rdf#";
  35.  
  36. var sidebarObj = new Object;
  37. var allPanelsObj = new Object;
  38. var original_panels = new Array();
  39.  
  40. //////////////////////////////////////////////////////////////
  41. // Sidebar Init/Destroy
  42. //////////////////////////////////////////////////////////////
  43.  
  44. function sidebar_customize_init()
  45. {
  46.   allPanelsObj.datasources = window.arguments[0];
  47.   allPanelsObj.resource    = window.arguments[1];
  48.   sidebarObj.datasource_uri     = window.arguments[2];
  49.   sidebarObj.resource           = window.arguments[3];
  50.  
  51.   debug("Init: all panels datasources = " + allPanelsObj.datasources);
  52.   debug("Init: all panels resource    = " + allPanelsObj.resource);
  53.   debug("Init: sidebarObj.datasource_uri = " + sidebarObj.datasource_uri);
  54.   debug("Init: sidebarObj.resource       = " + sidebarObj.resource);
  55.  
  56.   var all_panels   = document.getElementById('other-panels');
  57.   var current_panels = document.getElementById('current-panels');
  58.  
  59.   debug("Adding observer to all panels database.");
  60.   all_panels.database.AddObserver(panels_observer);
  61.  
  62.   allPanelsObj.datasources = allPanelsObj.datasources.replace(/^\s+/,'');
  63.   allPanelsObj.datasources = allPanelsObj.datasources.replace(/\s+$/,'');
  64.   allPanelsObj.datasources = allPanelsObj.datasources.split(/\s+/);
  65.   for (var ii = 0; ii < allPanelsObj.datasources.length; ii++) {
  66.     debug("Init: Adding "+allPanelsObj.datasources[ii]);
  67.  
  68.     // This will load the datasource, if it isn't already.
  69.     var datasource = RDF.GetDataSource(allPanelsObj.datasources[ii]);
  70.     all_panels.database.AddDataSource(datasource);
  71.   }
  72.  
  73.   // Add the datasource for current list of panels. It selects panels out
  74.   // of the other datasources.
  75.   debug("Init: Adding current panels, "+sidebarObj.datasource_uri);
  76.   sidebarObj.datasource = RDF.GetDataSource(sidebarObj.datasource_uri);
  77.  
  78.   // Root the customize dialog at the correct place.
  79.   debug("Init: reset all panels ref, "+allPanelsObj.resource);
  80.   all_panels.setAttribute('ref', allPanelsObj.resource);
  81.  
  82.   // Create a "container" wrapper around the current panels to
  83.   // manipulate the RDF:Seq more easily.
  84.   var panel_list = sidebarObj.datasource.GetTarget(RDF.GetResource(sidebarObj.resource), RDF.GetResource(NC + "panel-list"), true);
  85.   sidebarObj.container = Components.classes["@mozilla.org/rdf/container;1"].createInstance(Components.interfaces.nsIRDFContainer);
  86.   sidebarObj.container.Init(sidebarObj.datasource, panel_list);
  87.  
  88.   // Add all the current panels to the tree
  89.   current_panels = sidebarObj.container.GetElements();
  90.   while (current_panels.hasMoreElements()) {
  91.     var panel = current_panels.getNext().QueryInterface(Components.interfaces.nsIRDFResource);
  92.     if (add_node_to_current_list(sidebarObj.datasource, panel) >= 0) {
  93.       original_panels.push(panel.Value);
  94.       original_panels[panel.Value] = true;
  95.     }
  96.   }
  97.  
  98.   var links =
  99.     all_panels.database.GetSources(RDF.GetResource(NC + "haslink"),
  100.                                    RDF.GetLiteral("true"), true);
  101.  
  102.   while (links.hasMoreElements()) {
  103.     var folder = 
  104.       links.getNext().QueryInterface(Components.interfaces.nsIRDFResource);
  105.     var folder_name = folder.Value;
  106.     debug("+++ fixing up remote container " + folder_name + "\n");
  107.     fixup_remote_container(folder_name);
  108.   }
  109.  
  110.   sizeToContent();
  111. }
  112.  
  113. function sidebar_customize_destruct()
  114. {
  115.   var all_panels = document.getElementById('other-panels');
  116.   debug("Removing observer from all_panels database.");
  117.   all_panels.database.RemoveObserver(panels_observer);
  118. }
  119.  
  120.  
  121. //////////////////////////////////////////////////////////////////
  122. // Panels' RDF Datasource Observer
  123. //////////////////////////////////////////////////////////////////
  124. var panels_observer = {
  125.   onAssert : function(ds,src,prop,target) {
  126.     //debug ("observer: assert");
  127.     // "refresh" is asserted by select menu and by customize.js.
  128.     if (prop == RDF.GetResource(NC + "link")) {
  129.       setTimeout("fixup_remote_container('"+src.Value+"')",100);
  130.       //fixup_remote_container(src.Value);
  131.     }
  132.   },
  133.   onUnassert : function(ds,src,prop,target) {
  134.     //debug ("observer: unassert");
  135.   },
  136.   onChange : function(ds,src,prop,old_target,new_target) {
  137.     //debug ("observer: change");
  138.   },
  139.   onMove : function(ds,old_src,new_src,prop,target) {
  140.     //debug ("observer: move");
  141.   },
  142.   onBeginUpdateBatch : function(ds) {
  143.     //debug ("observer: onBeginUpdateBatch");
  144.   },
  145.   onEndUpdateBatch : function(ds) {
  146.     //debug ("observer: onEndUpdateBatch");
  147.   }
  148. };
  149.  
  150. function fixup_remote_container(id)
  151. {
  152.   debug('fixup_remote_container('+id+')');
  153.  
  154.   var container = document.getElementById(id);
  155.   if (container) {
  156.     container.setAttribute('container', 'true');
  157.     container.removeAttribute('open');
  158.   }
  159. }
  160.  
  161. function fixup_children(id) {
  162.   // Add container="true" on nodes with "link" attribute
  163.   var treeitem = document.getElementById(id);
  164.  
  165.   var children = treeitem.childNodes.item(1).childNodes;
  166.   for (var ii=0; ii < children.length; ii++) {
  167.     var child = children.item(ii);
  168.     if (child.getAttribute('link') != '' &&
  169.         child.getAttribute('container') != 'true') {
  170.       child.setAttribute('container', 'true');
  171.       child.removeAttribute('open');
  172.     }
  173.   }
  174. }
  175.  
  176. function get_attr(registry,service,attr_name)
  177. {
  178.   var attr = registry.GetTarget(service,
  179.                                 RDF.GetResource(NC + attr_name),
  180.                                 true);
  181.   if (attr)
  182.     attr = attr.QueryInterface(Components.interfaces.nsIRDFLiteral);
  183.   if (attr)
  184.     attr = attr.Value;
  185.   return attr;
  186. }
  187.  
  188. function SelectChangeForOtherPanels(event, target)
  189. {
  190.   enable_buttons_for_other_panels();
  191. }
  192.  
  193. function ClickOnOtherPanels(event)
  194. {
  195.   var tree = document.getElementById("other-panels");
  196.   
  197.   var rowIndex = -1;
  198.   if (event.type == "click" && event.button == 0) {
  199.     var row = {}, col = {}, obj = {};
  200.     var b = tree.treeBoxObject;
  201.     b.getCellAt(event.clientX, event.clientY, row, col, obj);
  202.  
  203.     if (obj.value == "twisty" || event.detail == 2) {
  204.       rowIndex = row.value;
  205.     }
  206.   }
  207.  
  208.   if (rowIndex < 0) return;
  209.   
  210.   var treeitem = tree.contentView.getItemAtIndex(rowIndex);
  211.   var res = RDF.GetResource(treeitem.id);
  212.   
  213.   if (treeitem.getAttribute('container') == 'true') {
  214.     if (treeitem.getAttribute('open') == 'true') {
  215.       var link = treeitem.getAttribute('link');
  216.       var loaded_link = treeitem.getAttribute('loaded_link');
  217.       if (link != '' && !loaded_link) {
  218.         debug("Has remote datasource: "+link);
  219.         add_datasource_to_other_panels(link);
  220.         treeitem.setAttribute('loaded_link', 'true');
  221.       } else {
  222.         setTimeout('fixup_children("'+ treeitem.getAttribute('id') +'")', 100);
  223.       }
  224.     }
  225.   }
  226.  
  227.   // Remove the selection in the "current" panels list
  228.   var current_panels = document.getElementById('current-panels');
  229.   current_panels.view.selection.clearSelection();
  230.   enable_buttons_for_current_panels();
  231. }
  232.  
  233. function add_datasource_to_other_panels(link) {
  234.   // Convert the |link| attribute into a URL
  235.   var url = document.location;
  236.   debug("Current URL:  " +url);
  237.   debug("Current link: " +link);
  238.  
  239.   var uri = Components.classes['@mozilla.org/network/standard-url;1'].createInstance();
  240.   uri = uri.QueryInterface(Components.interfaces.nsIURI);
  241.   uri.spec = url;
  242.   uri = uri.resolve(link);
  243.  
  244.   debug("New URL:      " +uri);
  245.  
  246.   // Add the datasource to the tree
  247.   var all_panels = document.getElementById('other-panels');
  248.   all_panels.database.AddDataSource(RDF.GetDataSource(uri));
  249.  
  250.   // XXX This is a hack to force re-display
  251.   //all_panels.setAttribute('ref', allPanelsObj.resource);
  252. }
  253.  
  254. // Handle a selection change in the current panels.
  255. function SelectChangeForCurrentPanels() {
  256.   // Remove the selection in the available panels list
  257.   var all_panels = document.getElementById('other-panels');
  258.   all_panels.view.selection.clearSelection();
  259.  
  260.   enable_buttons_for_current_panels();
  261. }
  262.  
  263. // Move the selected item up the the current panels list.
  264. function MoveUp() {
  265.   var tree = document.getElementById('current-panels');
  266.   if (tree.view.selection.count == 1) {
  267.     var index = tree.currentIndex;
  268.     var selected = tree.contentView.getItemAtIndex(index);
  269.     var before = selected.previousSibling;
  270.     if (before) {
  271.       before.parentNode.removeChild(selected);
  272.       before.parentNode.insertBefore(selected, before);
  273.       tree.view.selection.select(index-1);
  274.       tree.treeBoxObject.ensureRowIsVisible(index-1);
  275.     }
  276.   }
  277. }
  278.  
  279. // Move the selected item down the the current panels list.
  280. function MoveDown() {
  281.   var tree = document.getElementById('current-panels');
  282.   if (tree.view.selection.count == 1) {
  283.     var index = tree.currentIndex;
  284.     var selected = tree.contentView.getItemAtIndex(index);
  285.     if (selected.nextSibling) {
  286.       if (selected.nextSibling.nextSibling)
  287.         selected.parentNode.insertBefore(selected, selected.nextSibling.nextSibling);
  288.       else
  289.         selected.parentNode.appendChild(selected);
  290.       tree.view.selection.select(index+1);
  291.       tree.treeBoxObject.ensureRowIsVisible(index+1);
  292.     }
  293.   }
  294. }
  295.  
  296. function PreviewPanel()
  297. {
  298.   var tree = document.getElementById('other-panels');
  299.   var database = tree.database;
  300.   var sel = tree.view.selection;
  301.   var rangeCount = sel.getRangeCount();
  302.   for (var range = 0; range < rangeCount; ++range) {
  303.     var min = {}, max = {};
  304.     sel.getRangeAt(range, min, max);
  305.     for (var index = min.value; index <= max.value; ++index) {
  306.       var item = tree.contentView.getItemAtIndex(index);
  307.       var res = RDF.GetResource(item.id);
  308.  
  309.       var preview_name = get_attr(database, res, 'title');
  310.       var preview_URL  = get_attr(database, res, 'content');
  311.       if (!preview_URL || !preview_name) continue;
  312.  
  313.       window.openDialog("chrome://communicator/content/sidebar/preview.xul",
  314.                         "_blank", "chrome,resizable,close,dialog=no",
  315.                         preview_name, preview_URL);
  316.     }
  317.   }
  318. }
  319.  
  320. // Add the selected panel(s).
  321. function AddPanel()
  322. {
  323.   var added = -1;
  324.   
  325.   var tree = document.getElementById('other-panels');
  326.   var database = tree.database;
  327.   var sel = tree.view.selection;
  328.   var ranges = sel.getRangeCount();
  329.   for (var range = 0; range < ranges; ++range) {
  330.     var min = {}, max = {};
  331.     sel.getRangeAt(range, min, max);
  332.     for (var index = min.value; index <= max.value; ++index) {
  333.       var item = tree.contentView.getItemAtIndex(index);
  334.       if (item.getAttribute("container") != "true") {
  335.         var res = RDF.GetResource(item.id);
  336.         // Add the panel to the current list.
  337.         added = add_node_to_current_list(database, res);
  338.       }
  339.     }
  340.   }
  341.  
  342.   if (added >= 0) {
  343.     // Remove the selection in the other list.
  344.     // Selection will move to "current" list.
  345.     tree.view.selection.clearSelection();
  346.  
  347.     var current_panels = document.getElementById('current-panels');
  348.     current_panels.view.selection.select(added);
  349.     current_panels.treeBoxObject.ensureRowIsVisible(added);
  350.   }
  351. }
  352.  
  353. // Copy a panel node into a database such as the current panel list.
  354. function add_node_to_current_list(registry, service)
  355. {
  356.   debug("Adding "+service.Value);
  357.  
  358.   // Copy out the attributes we want
  359.   var option_title     = get_attr(registry, service, 'title');
  360.   var option_customize = get_attr(registry, service, 'customize');
  361.   var option_content   = get_attr(registry, service, 'content');
  362.   if (!option_title || !option_content)
  363.     return -1;
  364.  
  365.   var tree = document.getElementById('current-panels');
  366.   var tree_root = tree.lastChild;
  367.   
  368.   // Check to see if the panel already exists...
  369.   var i = 0;
  370.   for (var treeitem = tree_root.firstChild; treeitem; treeitem = treeitem.nextSibling) {
  371.     if (treeitem.id == service.Value)
  372.       // The panel is already in the current panel list.
  373.       // Avoid adding it twice.
  374.       return i;
  375.     ++i;
  376.   }
  377.  
  378.   // Create a treerow for the new panel
  379.   var item = document.createElement('treeitem');
  380.   var row  = document.createElement('treerow');
  381.   var cell = document.createElement('treecell');
  382.  
  383.   // Copy over the attributes
  384.   item.setAttribute('id', service.Value);
  385.   cell.setAttribute('label', option_title);
  386.  
  387.   // Add it to the current panels tree
  388.   item.appendChild(row);
  389.   row.appendChild(cell);
  390.   tree_root.appendChild(item);
  391.   return i;
  392. }
  393.  
  394. // Remove the selected panel(s) from the current list tree.
  395. function RemovePanel()
  396. {
  397.   var tree = document.getElementById('current-panels');
  398.   var sel = tree.view.selection;
  399.   
  400.   var nextNode = -1;
  401.   var rangeCount = sel.getRangeCount();
  402.   for (var range = rangeCount-1; range >= 0; --range) {
  403.     var min = {}, max = {};
  404.     sel.getRangeAt(range, min, max);
  405.     for (var index = max.value; index >= min.value; --index) {
  406.       var item = tree.contentView.getItemAtIndex(index);
  407.       nextNode = item.nextSibling ? index : -1;
  408.       item.parentNode.removeChild(item);
  409.     }
  410.   }
  411.  
  412.   if (nextNode >= 0)
  413.     sel.select(nextNode);
  414. }
  415.  
  416. // Bring up a new window with the customize url
  417. // for an individual panel.
  418. function CustomizePanel()
  419. {
  420.   var tree  = document.getElementById('current-panels');
  421.   var numSelected = tree.view.selection.count;
  422.  
  423.   if (numSelected == 1) {
  424.     var index = tree.currentIndex;
  425.     var selectedNode = tree.contentView.getItemAtIndex(index);
  426.     var panel_id = selectedNode.getAttribute('id');
  427.     var customize_url = selectedNode.getAttribute('customize');
  428.  
  429.     debug("url   = " + customize_url);
  430.  
  431.     if (!customize_url) return;
  432.  
  433.     window.openDialog('chrome://communicator/content/sidebar/customize-panel.xul',
  434.                       '_blank',
  435.                       'chrome,resizable,width=690,height=600,dialog=no,close',
  436.                       panel_id,
  437.                       customize_url,
  438.                       sidebarObj.datasource_uri,
  439.                       sidebarObj.resource);
  440.   }
  441. }
  442.  
  443. function BrowseMorePanels()
  444. {
  445.   var url = '';
  446.   var browser_url = "chrome://navigator/content/navigator.xul";
  447.   var locale;
  448.   try {
  449.     var prefs = Components.classes["@mozilla.org/preferences-service;1"]
  450.                           .getService(Components.interfaces.nsIPrefBranch);
  451.     url = prefs.getCharPref("sidebar.customize.more_panels.url");
  452.     var temp = prefs.getCharPref("browser.chromeURL");
  453.     if (temp) browser_url = temp;
  454.   } catch(ex) {
  455.     debug("Unable to get prefs: "+ex);
  456.   }
  457.   window.openDialog(browser_url, "_blank", "chrome,all,dialog=no", url);
  458. }
  459.  
  460. function customize_getBrowserURL()
  461. {
  462.   return url;
  463. }
  464.  
  465. // Serialize the new list of panels.
  466. function Save()
  467. {
  468.   persist_dialog_dimensions();
  469.  
  470.   var all_panels = document.getElementById('other-panels');
  471.   var current_panels = document.getElementById('current-panels');
  472.  
  473.   // See if list membership has changed
  474.   var panels = [];
  475.   var tree_root = current_panels.lastChild.childNodes;
  476.   var list_unchanged = (tree_root.length == original_panels.length);
  477.   for (var i = 0; i < tree_root.length; i++) {
  478.     var panel = tree_root[i].id;
  479.     panels.push(panel);
  480.     panels[panel] = true;
  481.     if (list_unchanged && original_panels[i] != panel)
  482.       list_unchanged = false;
  483.   }
  484.   if (list_unchanged)
  485.     return;
  486.  
  487.   // Remove all the current panels from the datasource.
  488.   current_panels = sidebarObj.container.GetElements();
  489.   while (current_panels.hasMoreElements()) {
  490.     panel = current_panels.getNext().QueryInterface(Components.interfaces.nsIRDFResource);
  491.     if (panel.Value in panels) {
  492.       // This panel will remain in the sidebar.
  493.       // Remove the resource, but keep all the other attributes.
  494.       // Removing it will allow it to be added in the correct order.
  495.       // Saving the attributes will preserve things such as the exclude state.
  496.       sidebarObj.container.RemoveElement(panel, false);
  497.     } else {
  498.       // Kiss it goodbye.
  499.       delete_resource_deeply(sidebarObj.container, panel);
  500.     }
  501.   }
  502.  
  503.   // Add the new list of panels
  504.   for (var ii = 0; ii < panels.length; ++ii) {
  505.     var id = panels[ii];
  506.     var resource = RDF.GetResource(id);
  507.     if (id in original_panels) {
  508.       sidebarObj.container.AppendElement(resource);
  509.     } else {
  510.       copy_resource_deeply(all_panels.database, resource, sidebarObj.container);
  511.     }
  512.   }
  513.   refresh_all_sidebars();
  514.  
  515.   // Write the modified panels out.
  516.   sidebarObj.datasource.QueryInterface(Components.interfaces.nsIRDFRemoteDataSource).Flush();
  517. }
  518.  
  519. // Search for an element in an array
  520. function has_element(array, element) {
  521.   for (var ii=0; ii < array.length; ii++) {
  522.     if (array[ii] == element) {
  523.       return true;
  524.     }
  525.   }
  526.   return false;
  527. }
  528.  
  529. // Search for targets from resource in datasource
  530. function has_targets(datasource, resource) {
  531.   var arcs = datasource.ArcLabelsOut(resource);
  532.   return arcs.hasMoreElements();
  533. }
  534.  
  535. // Use an assertion to pass a "refresh" event to all the sidebars.
  536. // They use observers to watch for this assertion (in sidebarOverlay.js).
  537. function refresh_all_sidebars() {
  538.   sidebarObj.datasource.Assert(RDF.GetResource(sidebarObj.resource),
  539.                                RDF.GetResource(NC + "refresh"),
  540.                                RDF.GetLiteral("true"),
  541.                                true);
  542.   sidebarObj.datasource.Unassert(RDF.GetResource(sidebarObj.resource),
  543.                                  RDF.GetResource(NC + "refresh"),
  544.                                  RDF.GetLiteral("true"));
  545. }
  546.  
  547. // Remove a resource and all the arcs out from it.
  548. function delete_resource_deeply(container, resource) {
  549.   var arcs = container.DataSource.ArcLabelsOut(resource);
  550.   while (arcs.hasMoreElements()) {
  551.     var arc = arcs.getNext();
  552.     var targets = container.DataSource.GetTargets(resource, arc, true);
  553.     while (targets.hasMoreElements()) {
  554.       var target = targets.getNext();
  555.       container.DataSource.Unassert(resource, arc, target, true);
  556.     }
  557.   }
  558.   container.RemoveElement(resource, false);
  559. }
  560.  
  561. // Copy a resource and all its arcs out to a new container.
  562. function copy_resource_deeply(source_datasource, resource, dest_container) {
  563.   var arcs = source_datasource.ArcLabelsOut(resource);
  564.   while (arcs.hasMoreElements()) {
  565.     var arc = arcs.getNext();
  566.     var targets = source_datasource.GetTargets(resource, arc, true);
  567.     while (targets.hasMoreElements()) {
  568.       var target = targets.getNext();
  569.       dest_container.DataSource.Assert(resource, arc, target, true);
  570.     }
  571.   }
  572.   dest_container.AppendElement(resource);
  573. }
  574.  
  575. function enable_buttons_for_other_panels()
  576. {
  577.   var add_button = document.getElementById('add_button');
  578.   var preview_button = document.getElementById('preview_button');
  579.   var all_panels = document.getElementById('other-panels');
  580.  
  581.   var sel = all_panels.view.selection;
  582.   var num_selected = sel ? sel.count : 0;
  583.   if (sel) {
  584.     var ranges = sel.getRangeCount();
  585.     for (var range = 0; range < ranges; ++range) {
  586.       var min = {}, max = {};
  587.       sel.getRangeAt(range, min, max);
  588.       for (var index = min; index <= max; ++index) {
  589.         var node = all_panels.contentView.getItemAtIndex(index);
  590.         if (node.getAttribute('container') != 'true') {
  591.           ++num_selected;
  592.         }
  593.       }
  594.     }
  595.   }
  596.  
  597.   if (num_selected > 0) {
  598.     add_button.removeAttribute('disabled');
  599.     preview_button.removeAttribute('disabled');
  600.   } else {
  601.     add_button.setAttribute('disabled','true');
  602.     preview_button.setAttribute('disabled','true');
  603.   }
  604. }
  605.  
  606. function enable_buttons_for_current_panels() {
  607.   var up        = document.getElementById('up');
  608.   var down      = document.getElementById('down');
  609.   var tree      = document.getElementById('current-panels');
  610.   var customize = document.getElementById('customize-button');
  611.   var remove    = document.getElementById('remove-button');
  612.  
  613.   var numSelected = tree.view.selection.count;
  614.   var canMoveUp = false, canMoveDown = false, customizeURL = '';
  615.  
  616.   if (numSelected == 1 && tree.view.selection.isSelected(tree.currentIndex)) {
  617.     var selectedNode = tree.view.getItemAtIndex(tree.currentIndex);
  618.     customizeURL = selectedNode.getAttribute('customize');
  619.     canMoveUp = selectedNode != selectedNode.parentNode.firstChild;
  620.     canMoveDown = selectedNode != selectedNode.parentNode.lastChild;
  621.   }
  622.  
  623.   up.disabled = !canMoveUp;
  624.   down.disabled = !canMoveDown;
  625.   customize.disabled = !customizeURL;
  626.   remove.disabled = !numSelected;
  627. }
  628.  
  629. function persist_dialog_dimensions() {
  630.   // Stole this code from navigator.js to
  631.   // insure the windows dimensions are saved.
  632.  
  633.   // Get the current window position/size.
  634.   var x = window.screenX;
  635.   var y = window.screenY;
  636.   var h = window.outerHeight;
  637.   var w = window.outerWidth;
  638.  
  639.   // Store these into the window attributes (for persistence).
  640.   var win = document.getElementById( "main-window" );
  641.   win.setAttribute( "x", x );
  642.   win.setAttribute( "y", y );
  643.   win.setAttribute( "height", h );
  644.   win.setAttribute( "width", w );
  645. }
  646.  
  647. ///////////////////////////////////////////////////////////////
  648. // Handy Debug Tools
  649. //////////////////////////////////////////////////////////////
  650. var debug = null;
  651. var dump_attributes = null;
  652. var dump_tree = null;
  653. var _dump_tree_recur = null;
  654.  
  655. if (!CUST_DEBUG) {
  656.   debug = function (s) {};
  657.   dump_attributes = function (node, depth) {};
  658.   dump_tree = function (node) {};
  659.   _dump_tree_recur = function (node, depth, index) {};
  660. } else {
  661.   debug = function (s) { dump("-*- sb customize: " + s + "\n"); };
  662.  
  663.   dump_attributes = function (node, depth) {
  664.     var attributes = node.attributes;
  665.     var indent = "| | | | | | | | | | | | | | | | | | | | | | | | | | | | . ";
  666.  
  667.     if (!attributes || attributes.length == 0) {
  668.       debug(indent.substr(indent.length - depth*2) + "no attributes");
  669.     }
  670.     for (var ii=0; ii < attributes.length; ii++) {
  671.       var attr = attributes.item(ii);
  672.       debug(indent.substr(indent.length - depth*2) + attr.name +
  673.             "=" + attr.value);
  674.     }
  675.   }
  676.   dump_tree = function (node) {
  677.     _dump_tree_recur(node, 0, 0);
  678.   }
  679.   _dump_tree_recur = function (node, depth, index) {
  680.     if (!node) {
  681.       debug("dump_tree: node is null");
  682.     }
  683.     var indent = "| | | | | | | | | | | | | | | | | | | | | | | | | | | | + ";
  684.     debug(indent.substr(indent.length - depth*2) + index +
  685.           " " + node.nodeName);
  686.     if (node.nodeName != "#text") {
  687.       dump_attributes(node, depth);
  688.     }
  689.     var kids = node.childNodes;
  690.     for (var ii=0; ii < kids.length; ii++) {
  691.       _dump_tree_recur(kids[ii], depth + 1, ii);
  692.     }
  693.   }
  694. }
  695.  
  696. //////////////////////////////////////////////////////////////
  697. // Install the load/unload handlers
  698. //////////////////////////////////////////////////////////////
  699. addEventListener("load", sidebar_customize_init, false);
  700. addEventListener("unload", sidebar_customize_destruct, false);
  701.