home *** CD-ROM | disk | FTP | other *** search
/ Chip 2002 January / 01_02.iso / software / netscape62win / browser.xpi / bin / chrome / comm.jar / content / navigator / personalToolbar.js < prev    next >
Encoding:
JavaScript  |  2001-05-23  |  18.0 KB  |  489 lines

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