home *** CD-ROM | disk | FTP | other *** search
/ ftp.swcp.com / ftp.swcp.com.zip / ftp.swcp.com / mac / mozilla-macos9-1.3.1.sea.bin / Mozilla1.3.1 / Chrome / comm.jar / content / navigator / personalToolbar.js < prev    next >
Text File  |  2003-06-08  |  20KB  |  514 lines

  1. /* -*- Mode: Java; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
  2. /* ***** BEGIN LICENSE BLOCK *****
  3.  * Version: NPL 1.1/GPL 2.0/LGPL 2.1
  4.  *
  5.  * The contents of this file are subject to the Netscape Public License
  6.  * Version 1.1 (the "License"); you may not use this file except in
  7.  * compliance with the License. You may obtain a copy of the License at
  8.  * http://www.mozilla.org/NPL/
  9.  *
  10.  * Software distributed under the License is distributed on an "AS IS" basis,
  11.  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
  12.  * for the specific language governing rights and limitations under the
  13.  * License.
  14.  *
  15.  * The Original Code is mozilla.org code.
  16.  *
  17.  * The Initial Developer of the Original Code is 
  18.  * Netscape Communications Corporation.
  19.  * Portions created by the Initial Developer are Copyright (C) 1998
  20.  * the Initial Developer. All Rights Reserved.
  21.  *
  22.  * Contributor(s):
  23.  *   Ben Goodger <ben@netscape.com> (Original Author)
  24.  *
  25.  * Alternatively, the contents of this file may be used under the terms of
  26.  * either the GNU General Public License Version 2 or later (the "GPL"), or 
  27.  * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
  28.  * in which case the provisions of the GPL or the LGPL are applicable instead
  29.  * of those above. If you wish to allow use of your version of this file only
  30.  * under the terms of either the GPL or the LGPL, and not to allow others to
  31.  * use your version of this file under the terms of the NPL, indicate your
  32.  * decision by deleting the provisions above and replace them with the notice
  33.  * and other provisions required by the GPL or the LGPL. If you do not delete
  34.  * the provisions above, a recipient may use your version of this file under
  35.  * the terms of any one of the NPL, the GPL or the LGPL.
  36.  *
  37.  * ***** END LICENSE BLOCK ***** */
  38.  
  39. var gBookmarksShell = null;
  40.  
  41. ///////////////////////////////////////////////////////////////////////////////
  42. // Class which defines methods for a bookmarks UI implementation based around
  43. // a toolbar. Subclasses BookmarksBase in bookmarksOverlay.js. Some methods
  44. // are required by the base class, others are for event handling. Window specific
  45. // glue code should go into the BookmarksWindow class in bookmarks.js
  46. function BookmarksToolbar (aID)
  47. {
  48.   this.id = aID;
  49. }
  50.  
  51. BookmarksToolbar.prototype = {
  52.   __proto__: BookmarksUIElement.prototype,
  53.  
  54.   /////////////////////////////////////////////////////////////////////////////
  55.   // Personal Toolbar Specific Stuff
  56.   
  57.   get db ()
  58.   {
  59.     return this.element.database;
  60.   },
  61.  
  62.   get element ()
  63.   {
  64.     return document.getElementById(this.id);
  65.   },
  66.  
  67.   /////////////////////////////////////////////////////////////////////////////
  68.   // This method constructs a menuitem for a context menu for the given command.
  69.   // This is implemented by the client so that it can intercept menuitem naming
  70.   // as appropriate.
  71.   createMenuItem: function (aDisplayName, aCommandName, aItemNode)
  72.   {
  73.     const kXULNS = "http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul";
  74.     var xulElement = document.createElementNS(kXULNS, "menuitem");
  75.     xulElement.setAttribute("cmd", aCommandName);
  76.     var cmd = "cmd_" + aCommandName.substring(NC_NS_CMD.length)
  77.     xulElement.setAttribute("command", cmd);
  78.     
  79.     switch (aCommandName) {
  80.     case NC_NS_CMD + "bm_open":
  81.       xulElement.setAttribute("label", aDisplayName);
  82.       xulElement.setAttribute("default", "true");
  83.       break;
  84.     case NC_NS_CMD + "bm_openfolder":
  85.       xulElement.setAttribute("default", "true");
  86.       if (aItemNode.localName == "hbox") 
  87.         // Don't show an "Open Folder" item for clicks on the toolbar itself.
  88.         return null;
  89.     default:
  90.       xulElement.setAttribute("label", aDisplayName);
  91.       break;
  92.     }
  93.     return xulElement;
  94.   },
  95.  
  96.   // Command implementation
  97.   commands: {
  98.     openFolder: function (aSelectedItem)
  99.     {
  100.       var mbo = aSelectedItem.boxObject.QueryInterface(Components.interfaces.nsIMenuBoxObject);
  101.       setTimeout(mbo.openMenu, 0, true);
  102.     },
  103.  
  104.     editCell: function (aSelectedItem, aXXXLameAssIndex)
  105.     {
  106.       goDoCommand("cmd_bm_properties");
  107.       return; // Disable Inline Edit for now. See bug 77125 for why this is being disabled
  108.               // on the personal toolbar for the moment. 
  109.  
  110.       if (aSelectedItem.getAttribute("editable") != "true")
  111.         return;
  112.       var property = "http://home.netscape.com/NC-rdf#Name";
  113.       aSelectedItem.setMode("edit");
  114.       aSelectedItem.addObserver(this.postModifyCallback, "accept", 
  115.                                 [gBookmarksShell, aSelectedItem, property]);
  116.     },
  117.  
  118.     ///////////////////////////////////////////////////////////////////////////
  119.     // Called after an inline-edit cell has left inline-edit mode, and data
  120.     // needs to be modified in the datasource.
  121.     postModifyCallback: function (aParams)
  122.     {
  123.       aParams[0].propertySet(aParams[1].id, aParams[2], aParams[3]);
  124.     },
  125.  
  126.     ///////////////////////////////////////////////////////////////////////////
  127.     // Creates a dummy item that can be placed in edit mode to retrieve data
  128.     // to create new bookmarks/folders.
  129.     createBookmarkItem: function (aMode, aSelectedItem)
  130.     {
  131.       /////////////////////////////////////////////////////////////////////////
  132.       // HACK HACK HACK HACK HACK         
  133.       // Disable Inline-Edit for now and just use a dialog. 
  134.       
  135.       // XXX - most of this is just copy-pasted from the other two folder
  136.       //       creation functions. Yes it's ugly, but it'll do the trick for 
  137.       //       now as this is in no way intended to be a long-term solution.
  138.  
  139.       const kPromptSvcContractID = "@mozilla.org/embedcomp/prompt-service;1";
  140.       const kPromptSvcIID = Components.interfaces.nsIPromptService;
  141.       const kPromptSvc = Components.classes[kPromptSvcContractID].getService(kPromptSvcIID);
  142.       
  143.       var defaultValue  = BookmarksUtils.getLocaleString("ile_newfolder");
  144.       var dialogTitle   = BookmarksUtils.getLocaleString("newfolder_dialog_title");
  145.       var dialogMsg     = BookmarksUtils.getLocaleString("newfolder_dialog_msg");
  146.       var stringValue   = { value: defaultValue };
  147.       if (kPromptSvc.prompt(window, dialogTitle, dialogMsg, stringValue, null, { value: 0 })) {
  148.         var relativeNode = aSelectedItem || gBookmarksShell.element;
  149.         var parentNode = relativeNode ? gBookmarksShell.findRDFNode(relativeNode, false) : gBookmarksShell.element;
  150.  
  151.         var args = [{ property: NC_NS + "parent",
  152.                       resource: parentNode.id },
  153.                     { property: NC_NS + "Name",
  154.                       literal:  stringValue.value }];
  155.         
  156.         const kBMDS = gBookmarksShell.RDF.GetDataSource("rdf:bookmarks");
  157.         var relId = relativeNode ? relativeNode.id : "NC:PersonalToolbarFolder";
  158.         BookmarksUtils.doBookmarksCommand(relId, NC_NS_CMD + "newfolder", args);
  159.       }
  160.       
  161.       return; 
  162.       
  163.       // HACK HACK HACK HACK HACK         
  164.       /////////////////////////////////////////////////////////////////////////
  165.       
  166.       const kXULNS = "http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul";
  167.       var dummyButton = document.createElementNS(kXULNS, "menubutton");
  168.       dummyButton = gBookmarksShell.createBookmarkFolderDecorations(dummyButton);
  169.       dummyButton.setAttribute("class", "button-toolbar bookmark-item");
  170.  
  171.       dummyButton.setAttribute("label", BookmarksUtils.getLocaleString("ile_newfolder") + "  ");
  172.       // By default, create adjacent to the selected button. If there is no button after
  173.       // the selected button, or the target is the toolbar itself, just append. 
  174.       var bIsButton = aSelectedItem.localName == "button" || aSelectedItem.localName == "menubutton";
  175.       if (aSelectedItem.nextSibling && bIsButton)
  176.         aSelectedItem.parentNode.insertBefore(dummyButton, aSelectedItem.nextSibling);
  177.       else
  178.         (bIsButton ? aSelectedItem.parentNode : aSelectedItem).appendChild(dummyButton);
  179.  
  180.       gBookmarksShell._focusElt = document.commandDispatcher.focusedElement;
  181.       dummyButton.setMode("edit");
  182.       // |aSelectedItem| will be the node we create the new folder relative to. 
  183.       dummyButton.addObserver(this.onEditFolderName, "accept", 
  184.                               [dummyButton, aSelectedItem, dummyButton]);
  185.       dummyButton.addObserver(this.onEditFolderName, "reject", 
  186.                               [dummyButton, aSelectedItem, dummyButton]);
  187.     },
  188.  
  189.     ///////////////////////////////////////////////////////////////////////////
  190.     // Edit folder name & update the datasource if name is valid
  191.     onEditFolderName: function (aParams, aTopic)
  192.     {
  193.       // Because the toolbar has no concept of selection, this function
  194.       // is much simpler than the one in bookmarksTree.js. However it may
  195.       // become more complex if pink ever lets me put context menus on menus ;) 
  196.       var name = aParams[3];
  197.       var dummyButton = aParams[2];
  198.       var relativeNode = aParams[1];
  199.       var parentNode = gBookmarksShell.findRDFNode(relativeNode, false);
  200.  
  201.       dummyButton.parentNode.removeChild(dummyButton);
  202.  
  203.       if (!gBookmarksShell.commands.validateNameAndTopic(name, aTopic, relativeNode, dummyButton))
  204.         return;
  205.  
  206.       parentNode = relativeNode.parentNode;
  207.       if (relativeNode.localName == "hbox") {
  208.         parentNode = relativeNode;
  209.         relativeNode = (gBookmarksShell.commands.nodeIsValidType(relativeNode) && 
  210.                         relativeNode.lastChild) || relativeNode;
  211.       }
  212.  
  213.       var args = [{ property: NC_NS + "parent",
  214.                     resource: parentNode.id },
  215.                   { property: NC_NS + "Name",
  216.                     literal:  name }];
  217.  
  218.       BookmarksUtils.doBookmarksCommand(relativeNode.id, NC_NS_CMD + "newfolder", args);
  219.       // We need to do this because somehow focus shifts and no commands 
  220.       // operate any more. 
  221.       //gBookmarksShell._focusElt.focus();
  222.     },
  223.  
  224.     nodeIsValidType: function (aNode)
  225.     {
  226.       switch (aNode.localName) {
  227.       case "button":
  228.       case "menubutton":
  229.       // case "menu":
  230.       // case "menuitem":
  231.         return true;
  232.       }
  233.       return false;
  234.     },
  235.  
  236.     ///////////////////////////////////////////////////////////////////////////
  237.     // Performs simple validation on what the user has entered:
  238.     //  1) prevents entering an empty string
  239.     //  2) in the case of a canceled operation, remove the dummy item and
  240.     //     restore selection.
  241.     validateNameAndTopic: function (aName, aTopic, aOldSelectedItem, aDummyItem)
  242.     {
  243.       // Don't allow user to enter an empty string "";
  244.       if (!aName) return false;
  245.  
  246.       // If the user hit escape, go no further.
  247.       return !(aTopic == "reject");
  248.     }
  249.   },
  250.  
  251.   _focusElt: null,
  252.  
  253.   /////////////////////////////////////////////////////////////////////////////
  254.   // Evaluates an event to determine whether or not it affords opening a tree
  255.   // item. Typically, this is when the left mouse button is used, and provided
  256.   // the click-rate matches that specified by our owning tree class. For example,
  257.   // some trees open an item when double clicked (bookmarks/history windows) and
  258.   // others on a single click (sidebar panels).
  259.   isValidOpenEvent: function (aEvent)
  260.   {
  261.     return !(aEvent.type == "click" &&
  262.              (aEvent.button != 0 || aEvent.detail != this.openClickCount))
  263.   },
  264.  
  265.   /////////////////////////////////////////////////////////////////////////////
  266.   // For the given selection, selects the best adjacent element. This method is
  267.   // useful when an action such as a cut or a deletion is performed on a
  268.   // selection, and focus/selection needs to be restored after the operation
  269.   // is performed.
  270.   getNextElement: function (aElement)
  271.   {
  272.     if (aElement.nextSibling)
  273.       return aElement.nextSibling;
  274.     else if (aElement.previousSibling)
  275.       return aElement.previousSibling;
  276.     else
  277.       return aElement.parentNode;
  278.   },
  279.  
  280.   selectElement: function (aElement)
  281.   {
  282.   },
  283.  
  284.   //////////////////////////////////////////////////////////////////////////////
  285.   // Add the treeitem element specified by aURI to the tree's current selection.
  286.   addItemToSelection: function (aURI)
  287.   {
  288.   },
  289.  
  290.   /////////////////////////////////////////////////////////////////////////////
  291.   // Return a set of DOM nodes that represents the current item in the Bookmarks
  292.   // Toolbar. This is always |document.popupNode|.
  293.   getSelection: function ()
  294.   {
  295.     return [document.popupNode];
  296.   },
  297.  
  298.   /////////////////////////////////////////////////////////////////////////////
  299.   // Return a set of DOM nodes that represent the selection in the tree widget.
  300.   // This method is takes a node parameter which is the popupNode for the
  301.   // document. If the popupNode is not contained by the selection, the
  302.   // popupNode is selected and the new selection returned.
  303.   getContextSelection: function (aItemNode)
  304.   {
  305.     return [aItemNode];
  306.   },
  307.  
  308.   getSelectedFolder: function ()
  309.   {
  310.     return "NC:PersonalToolbarFolder";
  311.   },
  312.  
  313.   /////////////////////////////////////////////////////////////////////////////
  314.   // For a given start DOM element, find the enclosing DOM element that contains
  315.   // the template builder RDF resource decorations (id, ref, etc). In the 
  316.   // Toolbar case, this is always the popup node (until we're proven wrong ;)
  317.   findRDFNode: function (aStartNode, aIncludeStartNodeFlag)
  318.   {
  319.     var temp = aStartNode;
  320.     while (temp && temp.localName != (aIncludeStartNodeFlag ? "toolbarbutton" : "hbox")) 
  321.       temp = temp.parentNode;
  322.     return temp || this.element;
  323.   },
  324.  
  325.   selectFolderItem: function (aFolderURI, aItemURI, aAdditiveFlag)
  326.   {
  327.     var folder = document.getElementById(aFolderURI);
  328.     var kids = ContentUtils.childByLocalName(folder, "treechildren");
  329.     if (!kids) return;
  330.  
  331.     var item = kids.firstChild;
  332.     while (item) {
  333.       if (item.id == aItemURI) break;
  334.       item = item.nextSibling;
  335.     }
  336.     if (!item) return;
  337.  
  338.     this.tree[aAdditiveFlag ? "addItemToSelection" : "selectItem"](item);
  339.   },
  340.  
  341.   /////////////////////////////////////////////////////////////////////////////
  342.   // Command handling & Updating.
  343.   controller: {
  344.     supportsCommand: function (aCommand)
  345.     {
  346.       switch(aCommand) {
  347.       case "cmd_bm_undo":
  348.       case "cmd_bm_redo":
  349.         return false;
  350.       case "cmd_bm_cut":
  351.       case "cmd_bm_copy":
  352.       case "cmd_bm_paste":
  353.       case "cmd_bm_delete":
  354.       case "cmd_bm_selectAll":
  355.       case "cmd_bm_open":
  356.       case "cmd_bm_openfolder":
  357.       case "cmd_bm_openinnewwindow":
  358.       case "cmd_bm_openinnewtab":
  359.       case "cmd_bm_newbookmark":
  360.       case "cmd_bm_newfolder":
  361.       case "cmd_bm_newseparator":
  362.       case "cmd_bm_find":
  363.       case "cmd_bm_properties":
  364.       case "cmd_bm_rename":
  365.       case "cmd_bm_setnewbookmarkfolder":
  366.       case "cmd_bm_setpersonaltoolbarfolder":
  367.       case "cmd_bm_setnewsearchfolder":
  368.       case "cmd_bm_import":
  369.       case "cmd_bm_export":
  370.       case "cmd_bm_fileBookmark":
  371.         return true;
  372.       default:
  373.         return false;
  374.       }
  375.     },
  376.  
  377.     isCommandEnabled: function (aCommand)
  378.     {
  379.       switch(aCommand) {
  380.       case "cmd_bm_undo":
  381.       case "cmd_bm_redo":
  382.         return false;
  383.       case "cmd_bm_paste":
  384.         var cp = gBookmarksShell.canPaste();
  385.         return cp;
  386.       case "cmd_bm_cut":
  387.       case "cmd_bm_copy":
  388.       case "cmd_bm_delete":
  389.         return document.popupNode && document.popupNode.id != "NC:PersonalToolbarFolder";
  390.       case "cmd_bm_selectAll":
  391.         return false;
  392.       case "cmd_bm_open":
  393.         var seln = gBookmarksShell.getSelection();
  394.         return document.popupNode != null && seln[0].getAttributeNS(RDF_NS, "type") == NC_NS + "Bookmark";
  395.       case "cmd_bm_openfolder":
  396.         seln = gBookmarksShell.getSelection();
  397.         return document.popupNode != null && seln[0].getAttributeNS(RDF_NS, "type") == NC_NS + "Folder";
  398.       case "cmd_bm_openinnewwindow":
  399.         return true;
  400.       case "cmd_bm_openinnewtab":
  401.         return ("getBrowser" in window && getBrowser().localName == "tabbrowser");
  402.       case "cmd_bm_find":
  403.       case "cmd_bm_newbookmark":
  404.       case "cmd_bm_newfolder":
  405.       case "cmd_bm_newseparator":
  406.       case "cmd_bm_import":
  407.       case "cmd_bm_export":
  408.         return true;
  409.       case "cmd_bm_properties":
  410.       case "cmd_bm_rename":
  411.         return document.popupNode != null;
  412.       case "cmd_bm_setnewbookmarkfolder":
  413.         seln = gBookmarksShell.getSelection();
  414.         if (!seln.length) return false;
  415.         var folderType = seln[0].getAttributeNS(RDF_NS, "type") == (NC_NS + "Folder");
  416.         return document.popupNode && seln[0].id != "NC:NewBookmarkFolder" && folderType;
  417.       case "cmd_bm_setpersonaltoolbarfolder":
  418.         seln = gBookmarksShell.getSelection();
  419.         if (!seln.length) return false;
  420.         folderType = seln[0].getAttributeNS(RDF_NS, "type") == (NC_NS + "Folder");
  421.         return document.popupNode && seln[0].id != "NC:PersonalToolbarFolder" && folderType;
  422.       case "cmd_bm_setnewsearchfolder":
  423.         seln = gBookmarksShell.getSelection();
  424.         if (!seln.length) return false;
  425.         folderType = seln[0].getAttributeNS(RDF_NS, "type") == (NC_NS + "Folder");
  426.         return document.popupNode && seln[0].id != "NC:NewSearchFolder" && folderType;
  427.       case "cmd_bm_fileBookmark":
  428.         seln = gBookmarksShell.getSelection();
  429.         return seln.length > 0;
  430.       default:
  431.         return false;
  432.       }
  433.     },
  434.  
  435.     doCommand: function (aCommand)
  436.     {
  437.       switch(aCommand) {
  438.       case "cmd_bm_undo":
  439.       case "cmd_bm_redo":
  440.         break;
  441.       case "cmd_bm_paste":
  442.       case "cmd_bm_copy":
  443.       case "cmd_bm_cut":
  444.       case "cmd_bm_delete":
  445.       case "cmd_bm_newbookmark":
  446.       case "cmd_bm_newfolder":
  447.       case "cmd_bm_newseparator":
  448.       case "cmd_bm_properties":
  449.       case "cmd_bm_rename":
  450.       case "cmd_bm_open":
  451.       case "cmd_bm_openfolder":
  452.       case "cmd_bm_openinnewwindow":
  453.       case "cmd_bm_openinnewtab":
  454.       case "cmd_bm_setnewbookmarkfolder":
  455.       case "cmd_bm_setpersonaltoolbarfolder":
  456.       case "cmd_bm_setnewsearchfolder":
  457.       case "cmd_bm_find":
  458.       case "cmd_bm_import":
  459.       case "cmd_bm_export":
  460.       case "cmd_bm_fileBookmark":
  461.         gBookmarksShell.execCommand(aCommand.substring("cmd_".length));
  462.         break;
  463.       case "cmd_bm_selectAll":
  464.         break;
  465.       }
  466.     },
  467.  
  468.     onEvent: function (aEvent)
  469.     {
  470.     },
  471.  
  472.     onCommandUpdate: function ()
  473.     {
  474.     }
  475.   },
  476.  
  477.   doFocus: function ()
  478.   {
  479.     document.getElementById("PersonalToolbar").focus();
  480.   }
  481.  
  482. };
  483.  
  484. function BM_navigatorLoad(aEvent)
  485. {
  486.   if (!gBookmarksShell) {
  487.     gBookmarksShell = new BookmarksToolbar("NC:PersonalToolbarFolder");
  488.     controllers.appendController(gBookmarksShell.controller);
  489.     removeEventListener("load", BM_navigatorLoad, false);
  490.   }
  491. }
  492.  
  493.  
  494. // An interim workaround for 101131 - Bookmarks Toolbar button nonfunctional.
  495. // This simply checks to see if the bookmark menu is empty (aside from static
  496. // items) when it is opened and if it is, prompts a rebuild. 
  497. // The best fix for this is more time consuming, and relies on document
  498. // <template>s without content (referencing a remote <template/> by id) 
  499. // be noted as 'waiting' for a template to load from somewhere. When the 
  500. // ::Merge function in nsXULDocument is called and a template node inserted, 
  501. // the id of the template to be inserted is looked up in the map of waiting
  502. // references, and then the template builder hooked up. 
  503. function checkBookmarksMenuTemplateBuilder()
  504. {
  505.   var lastStaticSeparator = document.getElementById("lastStaticSeparator");
  506.   if (!lastStaticSeparator.nextSibling) {
  507.     var button = document.getElementById("bookmarks-button");
  508.     button.builder.rebuild();
  509.   }
  510. }
  511.  
  512. addEventListener("load", BM_navigatorLoad, false);
  513.  
  514.