home *** CD-ROM | disk | FTP | other *** search
/ Chip 2002 January / 01_02.iso / software / netscape62win / browser.xpi / bin / chrome / toolkit.jar / content / global / nsTreeUtils.js < prev    next >
Encoding:
JavaScript  |  2001-03-21  |  17.8 KB  |  504 lines

  1. /* -*- Mode: Java; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
  2.  *
  3.  * The contents of this file are subject to the Netscape Public
  4.  * License Version 1.1 (the "License"); you may not use this file
  5.  * except in compliance with the License. You may obtain a copy of
  6.  * the License at http://www.mozilla.org/NPL/
  7.  *
  8.  * Software distributed under the License is distributed on an "AS
  9.  * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
  10.  * implied. See the License for the specific language governing
  11.  * rights and limitations under the License.
  12.  *
  13.  * The Original Code is mozilla.org code.
  14.  *
  15.  * The Initial Developer of the Original Code is Netscape
  16.  * Communications Corporation.  Portions created by Netscape are
  17.  * Copyright (C) 1998 Netscape Communications Corporation. All
  18.  * Rights Reserved.
  19.  *
  20.  * Contributor(s):
  21.  *   Peter Annema <disttsc@bart.nl>
  22.  *   Blake Ross <blakeross@telocity.com>
  23.  *   Alec Flett <alecf@netscape.com>
  24.  */
  25.  
  26.  
  27. // utility routines for things like sorting and menus
  28. // eventually this should probably be broken up even further
  29.  
  30. function TriStateColumnSort(column_name)
  31. {
  32.     var current_column = find_sort_column();
  33.     var current_direction = find_sort_direction(current_column);
  34.     var column = document.getElementById(column_name);
  35.     if (!column) return false;
  36.     var direction = "ascending";
  37.     if (column == current_column) {
  38.         if (current_direction == "ascending") {
  39.             direction = "descending";
  40.         } else if (current_direction == "descending") {
  41.             direction = "natural";
  42.         }
  43.     }
  44.     sort_column(column, direction);
  45.     return true;
  46. }
  47.  
  48.  
  49. // Note: doSort() does NOT support natural order sorting, unless naturalOrderResource is valid,
  50. //       in which case we sort ascending on naturalOrderResource
  51.  
  52. function doSort(sortColName, naturalOrderResource)
  53. {
  54.     var node = document.getElementById(sortColName);
  55.     // determine column resource to sort on
  56.     var sortResource = node.getAttribute('resource');
  57.     if (!sortResource)
  58.         return false;
  59.  
  60.     var sortDirection="ascending";
  61.     var isSortActive = node.getAttribute('sortActive');
  62.     if (isSortActive == "true") {
  63.         sortDirection = "ascending";
  64.         var currentDirection = node.getAttribute('sortDirection');
  65.         if (currentDirection == "ascending") {
  66.             if (sortResource != naturalOrderResource)
  67.                 sortDirection = "descending";
  68.         }
  69.         else if (currentDirection == "descending") {
  70.             if (naturalOrderResource)
  71.                 sortResource = naturalOrderResource;
  72.         }
  73.     }
  74.  
  75.     try {
  76.         var isupports = Components.classes["@mozilla.org/xul/xul-sort-service;1"].getService();
  77.         var xulSortService = isupports.QueryInterface(Components.interfaces.nsIXULSortService);
  78.     }
  79.     catch(ex) {
  80.         dump(ex);
  81.         return false;
  82.     }
  83.  
  84.     try {
  85.         xulSortService.Sort(node, sortResource, sortDirection);
  86.     }
  87.     catch(ex) {
  88.     }
  89.     return true;
  90. }
  91.  
  92. // re-does a sort based on the current state
  93. function RefreshSort()
  94. {
  95.     var current_column = find_sort_column();
  96.     var current_direction = find_sort_direction(current_column);
  97.     sort_column(current_column, current_direction);
  98. }
  99.  
  100. // set the sort direction on the currently sorted column
  101. function SetSortDirection(direction)
  102. {
  103.     var current_column = find_sort_column();
  104.     var current_direction = find_sort_direction(current_column);
  105.     if (current_direction != direction) {
  106.         sort_column(current_column, direction);
  107.     }
  108. }
  109.  
  110. // set the sorted column
  111. function SetSortColumn(column_name)
  112. {
  113.     var current_column = find_sort_column();
  114.     var current_direction = find_sort_direction(current_column);
  115.     var column = document.getElementById(column_name);
  116.     if (column != current_column || current_direction == "natural") {
  117.         sort_column(column, "ascending");
  118.     }
  119. }
  120.  
  121. // actually sort given the column and direction
  122. function sort_column(column, direction)
  123. {
  124.     var isupports_uri = "@mozilla.org/xul/xul-sort-service;1";
  125.     var isupports = Components.classes[isupports_uri].getService();
  126.     if (!isupports) return false;
  127.     var xulSortService = isupports.QueryInterface(Components.interfaces.nsIXULSortService);
  128.     if (!xulSortService) return false;
  129.     try
  130.     {
  131.         var sort_resource = column.getAttribute('resource');
  132.         xulSortService.Sort(column, sort_resource, direction);
  133.     }
  134.     catch(ex)
  135.     {
  136.         dump("sort exception: " + ex + "\n");
  137.     }
  138.     update_sort_menuitems(column, direction);
  139.     return false;
  140. }
  141.  
  142. // search over the columns to find the first one with an active sort
  143. function find_sort_column() {
  144.     var columns = document.getElementById('theColumns');
  145.     var column = columns.firstChild;
  146.     while (column) {
  147.         if ("true" == column.getAttribute('sortActive')) {
  148.             return column;
  149.         }
  150.         column = column.nextSibling;
  151.     }
  152.     return columns.firstChild;
  153. }
  154.  
  155.  
  156. // get the sort direction for the given column
  157. function find_sort_direction(column) {
  158.     if ("true" == column.getAttribute('sortActive')) {
  159.         return column.getAttribute('sortDirection');
  160.     } else {
  161.         return "natural";
  162.     }
  163. }
  164.  
  165. // set up the menu items to reflect the specified sort column
  166. // and direction - put check marks next to the active ones, and clear
  167. // out the old ones
  168. // - disable ascending/descending direction if the tree isn't sorted
  169. // - disable columns that are not visible
  170. function update_sort_menuitems(column, direction)
  171. {
  172.     var unsorted_menuitem = document.getElementById("unsorted_menuitem");
  173.     var sort_ascending = document.getElementById('sort_ascending');
  174.     var sort_descending = document.getElementById('sort_descending');
  175.  
  176.     // as this function may be called from various places, including the
  177.     // bookmarks sidebar panel (which doesn't have any menu items)
  178.     // ensure that the document contains the elements
  179.     if ((!unsorted_menuitem) || (!sort_ascending) || (!sort_descending))
  180.         return;
  181.  
  182.     if (direction == "natural") {
  183.         unsorted_menuitem.setAttribute('checked','true');
  184.         sort_ascending.setAttribute('disabled','true');
  185.         sort_descending.setAttribute('disabled','true');
  186.         sort_ascending.removeAttribute('checked');
  187.         sort_descending.removeAttribute('checked');
  188.     } else {
  189.         sort_ascending.removeAttribute('disabled');
  190.         sort_descending.removeAttribute('disabled');
  191.         if (direction == "ascending") {
  192.             sort_ascending.setAttribute('checked','true');
  193.         } else {
  194.             sort_descending.setAttribute('checked','true');
  195.         }
  196.  
  197.         var columns = document.getElementById('theColumns');
  198.         var column_node = columns.firstChild;
  199.         var column_name = column.id;
  200.         var menuitem = document.getElementById('fill_after_this_node');
  201.         menuitem = menuitem.nextSibling
  202.         while (1) {
  203.             var name = menuitem.getAttribute('column_id');
  204.             if (!name) break;
  205.             if (column_name == name) {
  206.                 menuitem.setAttribute('checked', 'true');
  207.                 break;
  208.             }
  209.             menuitem = menuitem.nextSibling;
  210.             column_node = column_node.nextSibling;
  211.             if (column_node && column_node.tagName == "splitter")
  212.                 column_node = column_node.nextSibling;
  213.         }
  214.     }
  215.     enable_sort_menuitems();
  216. }
  217.  
  218. function enable_sort_menuitems() {
  219.     var columns = document.getElementById('theColumns');
  220.     var column_node = columns.firstChild;
  221.     var head = document.getElementById('headRow');
  222.     var tree_column = head.firstChild;
  223.     var skip_column = document.getElementById('popupCell');
  224.     var menuitem = document.getElementById('fill_after_this_node');
  225.     menuitem = menuitem.nextSibling
  226.     while (column_node && menuitem) {
  227.         if (skip_column != tree_column) {
  228.             if ("true" == column_node.getAttribute("hidden")) {
  229.                 menuitem.setAttribute("disabled", "true");
  230.             } else {
  231.                 menuitem.removeAttribute("disabled");
  232.             }
  233.         }
  234.         menuitem = menuitem.nextSibling;
  235.         tree_column = tree_column.nextSibling;
  236.         column_node = column_node.nextSibling;
  237.  
  238.         if (column_node && column_node.tagName == "splitter")
  239.             column_node = column_node.nextSibling;
  240.     }
  241. }
  242.  
  243.  
  244. function fillViewMenu(popup)
  245. {
  246.   var fill_after = document.getElementById('fill_after_this_node');
  247.   var fill_before = document.getElementById('fill_before_this_node');
  248.   var columns = document.getElementById('theColumns');
  249.   var head = document.getElementById('headRow');
  250.   var skip_column = document.getElementById('popupCell');
  251.  
  252.   var name_template = get_localized_string("SortMenuItem");
  253.   var tree_column = head.firstChild;
  254.   var column_node = columns.firstChild;
  255.   var popupChild = popup.firstChild.nextSibling.nextSibling;
  256.   var firstTime = (fill_after.nextSibling == fill_before);
  257.   while (tree_column) {
  258.       if (firstTime) {
  259.           if (skip_column != tree_column && tree_column.getAttribute("collapsed") != "true") {
  260.               // Construct an entry for each cell in the row.
  261.               var column_name = tree_column.getAttribute("label");
  262.               var item = document.createElement("menuitem");
  263.               item.setAttribute("type", "radio");
  264.               item.setAttribute("name", "sort_column");
  265.               if (column_name == "")
  266.                   column_name = tree_column.getAttribute("display");
  267.               var name = name_template.replace(/%NAME%/g, column_name);
  268.               var id = column_node.id;
  269.               item.setAttribute("label", name);
  270.               item.setAttribute("oncommand", "SetSortColumn('"+id+"', true);");
  271.               item.setAttribute("column_id", id);
  272.  
  273.               popup.insertBefore(item, fill_before);
  274.           }
  275.       }
  276.       else {
  277.           if (column_node.getAttribute("collapsed") == "true")
  278.               popupChild.setAttribute("hidden", "true");
  279.           else
  280.               popupChild.removeAttribute("hidden");
  281.           popupChild = popupChild.nextSibling;
  282.       }
  283.       tree_column = tree_column.nextSibling;
  284.       column_node = column_node.nextSibling;
  285.       if (column_node && column_node.tagName == "splitter")
  286.           column_node = column_node.nextSibling;
  287.   }
  288.   var sort_column = find_sort_column();
  289.   var sort_direction = find_sort_direction(sort_column);
  290.   update_sort_menuitems(sort_column, sort_direction);
  291. }
  292.  
  293. function fillContextMenu(name, treeName)
  294. {
  295.     if (!name) return false;
  296.     var popupNode = document.getElementById(name);
  297.     if (!popupNode) return false;
  298.     // remove the menu node (which tosses all of its kids);
  299.     // do this in case any old command nodes are hanging around
  300.     while (popupNode.childNodes.length)
  301.     {
  302.       popupNode.removeChild(popupNode.childNodes[0]);
  303.     }
  304.  
  305.     var treeNode = document.getElementById(treeName);
  306.     if (!treeNode) return false;
  307.     var db = treeNode.database;
  308.     if (!db) return false;
  309.  
  310.     var compositeDB = db.QueryInterface(Components.interfaces.nsIRDFDataSource);
  311.     if (!compositeDB) return false;
  312.  
  313.     var isupports_uri = "@mozilla.org/rdf/rdf-service;1";
  314.     var isupports = Components.classes[isupports_uri].getService();
  315.     if (!isupports) return false;
  316.     var rdf = isupports.QueryInterface(Components.interfaces.nsIRDFService);
  317.     if (!rdf) return false;
  318.  
  319.     var target_item = document.popupNode.parentNode.parentNode;
  320.     if (target_item && target_item.nodeName == "treeitem")
  321.     {
  322.         if (target_item.getAttribute('selected') != 'true') {
  323.           treeNode.selectItem(target_item);
  324.         }
  325.     }
  326.  
  327.     var select_list = treeNode.selectedItems;
  328.  
  329.     var separatorResource =
  330.         rdf.GetResource(NC_NS + "BookmarkSeparator");
  331.     if (!separatorResource) return false;
  332.  
  333.     // perform intersection of commands over selected nodes
  334.     var cmdArray = new Array();
  335.     var selectLength = select_list.length;
  336.     if (selectLength == 0) selectLength = 1;
  337.     for (var nodeIndex=0; nodeIndex < selectLength; nodeIndex++)
  338.     {
  339.         var id = null;
  340.  
  341.         // If nothing is selected, get commands for the "ref"
  342.         // of the bookmarks root
  343.         if (select_list.length == 0)
  344.         {
  345.             id = treeNode.getAttribute("ref");
  346.             if (!id) break;
  347.         }
  348.         else
  349.         {
  350.             var node = select_list[nodeIndex];
  351.             if (!node) break;
  352.             id = node.getAttribute("id");
  353.             if (!id) break;
  354.         }
  355.         var rdfNode = rdf.GetResource(id);
  356.         if (!rdfNode) break;
  357.         var cmdEnum = db.GetAllCmds(rdfNode);
  358.         if (!cmdEnum) break;
  359.  
  360.         var nextCmdArray = new Array();
  361.         while (cmdEnum.hasMoreElements())
  362.         {
  363.             var cmd = cmdEnum.getNext();
  364.             if (!cmd) break;
  365.  
  366.             if (nodeIndex == 0)
  367.             {
  368.                 cmdArray[cmdArray.length] = cmd;
  369.             }
  370.             else
  371.             {
  372.                 nextCmdArray[cmdArray.length] = cmd;
  373.             }
  374.         }
  375.         if (nodeIndex > 0)
  376.         {
  377.             // perform command intersection calculation
  378.             for (var cmdIndex = 0; cmdIndex < cmdArray.length; cmdIndex++)
  379.             {
  380.                 var cmdFound = false;
  381.                 for (var nextCmdIndex = 0;
  382.                      nextCmdIndex < nextCmdArray.length;
  383.                      nextCmdIndex++)
  384.                 {
  385.                     if (nextCmdArray[nextCmdIndex] == cmdArray[cmdIndex])
  386.                     {
  387.                         cmdFound = true;
  388.                         break;
  389.                     }
  390.                 }
  391.                 if ((cmdFound == false) && (cmdArray[cmdIndex]))
  392.                 {
  393.                     var cmdResource = cmdArray[cmdIndex].QueryInterface(Components.interfaces.nsIRDFResource);
  394.                     if ((cmdResource) && (cmdResource != separatorResource))
  395.                     {
  396.                         cmdArray[cmdIndex] = null;
  397.                     }
  398.                 }
  399.             }
  400.         }
  401.     }
  402.  
  403.     // need a resource to ask RDF for each command's name
  404.     var rdfNameResource = rdf.GetResource(NC_NS + "Name");
  405.     if (!rdfNameResource) return false;
  406.  
  407. /*
  408.     // build up menu items
  409.     if (cmdArray.length < 1) return false;
  410. */
  411.  
  412.     var lastWasSep = false;
  413.     for (var commandIndex = 0; commandIndex < cmdArray.length; commandIndex++)
  414.     {
  415.         cmd = cmdArray[commandIndex];
  416.         if (!cmd) continue;
  417.         cmdResource = cmd.QueryInterface(Components.interfaces.nsIRDFResource);
  418.         if (!cmdResource) break;
  419.  
  420.         // handle separators
  421.         if (cmdResource == separatorResource)
  422.         {
  423.             if (lastWasSep != true)
  424.             {
  425.                 lastWasSep = true;
  426.                     var menuItem = document.createElement("menuseparator");
  427.                     popupNode.appendChild(menuItem);
  428.             }
  429.             continue;
  430.         }
  431.  
  432.         lastWasSep = false;
  433.  
  434.         var cmdNameNode = compositeDB.GetTarget(cmdResource, rdfNameResource,
  435.                                                 true);
  436.         if (!cmdNameNode) break;
  437.         var cmdNameLiteral = cmdNameNode.QueryInterface(Components.interfaces.nsIRDFLiteral);
  438.         if (!cmdNameLiteral) break;
  439.         var cmdName = cmdNameLiteral.Value;
  440.         if (!cmdName) break;
  441.  
  442.         var newMenuItem = document.createElement("menuitem");
  443.         newMenuItem.setAttribute("label", cmdName);
  444.         popupNode.appendChild(newMenuItem);
  445.         // Work around bug #26402 by setting "oncommand" attribute
  446.         // AFTER appending menuitem
  447.         newMenuItem.setAttribute("oncommand",
  448.                               "return doContextCmd('"+cmdResource.Value+"');");
  449.     }
  450.  
  451.     // strip off leading/trailing menuseparators
  452.     while (popupNode.childNodes.length > 0)
  453.     {
  454.         if (popupNode.childNodes[0].tagName != "menuseparator")
  455.             break;
  456.         popupNode.removeChild(popupNode.childNodes[0]);
  457.     }
  458.     while (popupNode.childNodes.length > 0)
  459.     {
  460.         if (popupNode.childNodes[popupNode.childNodes.length - 1].tagName != "menuseparator")
  461.             break;
  462.         popupNode.removeChild(popupNode.childNodes[popupNode.childNodes.length - 1]);
  463.     }
  464.  
  465.     // if one and only one node is selected
  466.     if (treeNode.selectedItems.length == 1)
  467.     {
  468.         // and its a bookmark or a bookmark folder (there can be other types,
  469.         // not just separators, so check explicitly for what we allow)
  470.         var type = select_list[0].getAttribute("type");
  471.         if ((type == NC_NS + "Bookmark") ||
  472.             (type == NC_NS + "Folder"))
  473.         {
  474.             // then add a menu separator (if necessary)
  475.             if (popupNode.childNodes.length > 0)
  476.             {
  477.                 if (popupNode.childNodes[popupNode.childNodes.length - 1].tagName != "menuseparator")
  478.                 {
  479.                     var menuSep = document.createElement("menuseparator");
  480.                     popupNode.appendChild(menuSep);
  481.                 }
  482.             }
  483.  
  484.             // And then add a "Properties" menu items
  485.             var propMenuName = get_localized_string("BookmarkProperties");
  486.             var aMenuItem = document.createElement("menuitem");
  487.             aMenuItem.setAttribute("label", propMenuName);
  488.             popupNode.appendChild(aMenuItem);
  489.             // Work around bug # 26402 by setting "oncommand" attribute
  490.             // AFTER appending menuitem
  491.             aMenuItem.setAttribute("oncommand", "return BookmarkProperties();");
  492.         }
  493.     }
  494.  
  495.     return true;
  496. }
  497.  
  498. // this is really unnecessary, we should be using <stringbundle>
  499. function get_localized_string(name) {
  500.     var uri = "chrome://communicator/locale/bookmarks/bookmark.properties";
  501.     var bundle = srGetStrBundle(uri);
  502.     return bundle.GetStringFromName(name);
  503. }
  504.