home *** CD-ROM | disk | FTP | other *** search
/ PC Format (PL) 2008 February / PC_Format_022008.iso / Internet / Mozilla Thunderbird wtyczki / lightning-0.7-tb-win.xpi / chrome / lightning.jar / content / lightning / customize-toolbar.js < prev    next >
Encoding:
JavaScript  |  2007-08-30  |  13.1 KB  |  363 lines

  1. /* -*- Mode: javascript; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
  2. /* ***** BEGIN LICENSE BLOCK *****
  3.  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
  4.  *
  5.  * The contents of this file are subject to the Mozilla Public License Version
  6.  * 1.1 (the "License"); you may not use this file except in compliance with
  7.  * the License. You may obtain a copy of the License at
  8.  * http://www.mozilla.org/MPL/
  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 Communicator client code, released
  16.  * March 31, 1998.
  17.  *
  18.  * The Initial Developer of the Original Code is
  19.  * David Hyatt.
  20.  * Portions created by the Initial Developer are Copyright (C) 2002
  21.  * the Initial Developer. All Rights Reserved.
  22.  *
  23.  * Contributor(s):
  24.  *   David Hyatt (hyatt@apple.com)
  25.  *   Blake Ross (blaker@netscape.com)
  26.  *   Joe Hewitt (hewitt@netscape.com)
  27.  *   Michael Buettner <michael.buettner@sun.com>
  28.  *
  29.  * Alternatively, the contents of this file may be used under the terms of
  30.  * either the GNU General Public License Version 2 or later (the "GPL"), or
  31.  * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
  32.  * in which case the provisions of the GPL or the LGPL are applicable instead
  33.  * of those above. If you wish to allow use of your version of this file only
  34.  * under the terms of either the GPL or the LGPL, and not to allow others to
  35.  * use your version of this file under the terms of the MPL, indicate your
  36.  * decision by deleting the provisions above and replace them with the notice
  37.  * and other provisions required by the GPL or the LGPL. If you do not delete
  38.  * the provisions above, a recipient may use your version of this file under
  39.  * the terms of any one of the MPL, the GPL or the LGPL.
  40.  *
  41.  * ***** END LICENSE BLOCK ***** */
  42.  
  43. /**
  44.  * Global variables in addition to those specified in
  45.  * mail/base/content/customizeToolbar.js
  46.  */
  47. var gPreviousLocation = null;
  48. var gRepositionOnce = false;
  49. var gIsMainApplicationContext = (window.arguments[3] != null);
  50.  
  51. /**
  52.  * Since we want to 'inherit' several global functions
  53.  * we retrieve the current values in order to call them
  54.  * from their overriden version.
  55.  */
  56. var gOnLoad = onLoad;
  57. var gInitDialog = initDialog;
  58. var gOnCancel = onCancel;
  59.  
  60. /**
  61.  * initDialog() gets called from the load handler and
  62.  * is responsible for initializing global variables, etc.
  63.  */
  64. initDialog = function() {
  65.  
  66.     // Don't do any extra processing in case we're not
  67.     // customizing one of the main application toolbars.
  68.     // The customize toolbar dialog contains special features
  69.     // that don't apply in that case (location drop down, etc.).
  70.     if (gIsMainApplicationContext) {
  71.  
  72.         // remember initial toolbar location and set the
  73.         // menulist accordingly. this applies to the mode toolbar only.
  74.         gPreviousLocation = gToolbox.getAttribute("location");
  75.         document.getElementById("location-list").value = gPreviousLocation;
  76.  
  77.         // set the toolbar selection according to the current mode.
  78.         // this list allows to hop from one toolbar to another without
  79.         // leaving the customize dialog. if this feature is to be used outside
  80.         // of mail/news main application window, we detect this case and disable
  81.         // all relevant controls and stuff.
  82.         var selectorList = document.getElementById("selector-list");
  83.         selectorList.value = window.arguments[3];
  84.         if (selectorList.selectedItem.value != window.arguments[3]) {
  85.             document.getElementById("selector-container").collapsed = true;
  86.         }
  87.     }
  88.  
  89.     // now call the original initDialog() function
  90.     gInitDialog();
  91. }
  92.  
  93. /**
  94.  * onCancel() is called if the customize toolbar dialog has been canceled.
  95.  * we're returning to the previous state and discarding any changes made
  96.  * to the current toolbar. please note that this applies to the current toolbar
  97.  * only. in case we've been switched from one to another, only the changes
  98.  * made to the most recent toolbar will be discarded.
  99.  */
  100. onCancel = function() {
  101.  
  102.     // Don't do any extra processing in case we're not
  103.     // customizing one of the main application toolbars.
  104.     // The customize toolbar dialog contains special features
  105.     // that don't apply in that case (location drop down, etc.).
  106.     if (gIsMainApplicationContext) {
  107.         updateToolbarLocation(gPreviousLocation);
  108.     }
  109.  
  110.     gOnCancel();
  111. }
  112.  
  113. /**
  114.  * repositionDialog() to find a good position for the customize dialog.
  115.  * it is called during initialization and subsequently if any option has been
  116.  * altered that causes the toolbar to change size or location. we need to
  117.  * override this function to add the ability to set the position *above*
  118.  * the toolbar in question, since this is necessary for the mode toolbar
  119.  * which is set at the lower left of the application window by default.
  120.  */
  121. _repositionDialog = function() {
  122.  
  123.   // Christian said it's better to not make the dialog jump...
  124.   if (gRepositionOnce)
  125.     return;
  126.   gRepositionOnce = true;
  127.     
  128.   // Position the dialog touching the bottom of the toolbox and centered with 
  129.   // it. We must resize the window smaller first so that it is positioned properly. 
  130.   var screenX = gToolbox.boxObject.screenX + ((gToolbox.boxObject.width - kWindowWidth) / 2);
  131.   var screenY = gToolbox.boxObject.screenY + gToolbox.boxObject.height;
  132.  
  133.   var newHeight = kWindowHeight;
  134.   if (newHeight >= screen.availHeight - screenY - kVSizeSlop) {
  135.     // the customize window doesn't fit below the toolbar. first try if there's
  136.     // enough space at the top of the toolbar. if neither works, shrink the height.
  137.     if(gToolbox.boxObject.screenY - newHeight - kVSizeSlop < 0) {
  138.       newHeight = screen.availHeight - screenY - kVSizeSlop;
  139.     } else {
  140.       screenY = gToolbox.boxObject.screenY - newHeight;
  141.     }
  142.   }
  143.   
  144.   if(screenX < 0) {
  145.     screenX = 0;
  146.   }
  147.   
  148.   window.resizeTo(kWindowWidth, newHeight);
  149.   window.moveTo(screenX, screenY);
  150. }
  151.  
  152. /**
  153.  * onLoad() is called by the load event handler. we need to override
  154.  * this function to initialize the newly introduced controls.
  155.  */
  156. onLoad = function() {
  157.  
  158.     // remove the box containing all the relevant controls from
  159.     // the dom tree, we bring a new one to the table. this is necessary
  160.     // since those controls don't specify id's, so we need to override
  161.     // all of them.
  162.     var mainbox = document.getElementById("main-box");
  163.     var controlbox = document.getElementById("control-box");
  164.     mainbox.removeChild(controlbox.nextSibling);
  165.  
  166.     // Don't do any extra processing in case we're not
  167.     // customizing one of the main application toolbars.
  168.     // The customize toolbar dialog contains special features
  169.     // that don't apply in that case (location drop down, etc.).
  170.     if (gIsMainApplicationContext) {
  171.  
  172.         document.getElementById("selector-container")
  173.             .removeAttribute("collapsed");
  174.  
  175.         // show the location option (place toolbar at top or bottom)
  176.         // if this feature has been requested.
  177.         updateLocationVisibility(window.arguments[3] == 'mode');
  178.     }
  179.  
  180.     // now call the default implementation of the load handler, since
  181.     // this retrieves the toolbox element from the arguments.
  182.     gOnLoad();
  183. }
  184.  
  185. /**
  186.  * updateToolbarLocation() is called to handle a new location for
  187.  * the toolbar (top or bottom). basically, we just set the appropriate
  188.  * attribute on all customizable toolbars and rely on them intercepting
  189.  * this modification and act accordingly.
  190.  */
  191. _updateToolbarLocation = function(aLocation) {
  192.  
  193.   // since the current toolbar will change its location in
  194.   // the dom tree (most probably), we need to unwrap the toolbar items
  195.   // and reset anything that could get in the way.
  196.   removeToolboxListeners();
  197.   unwrapToolbarItems(false);
  198.  
  199.   var toolboxId = gToolbox.id;
  200.  
  201.   // set the new location on the toolbox...
  202.   setAttribute(gToolbox, "location", aLocation);
  203.   gToolboxDocument.persist(gToolbox.id, "location");
  204.   
  205.   // ...and each customizable toolbar
  206.   for (var i = 0; i < gToolbox.childNodes.length; ++i) {
  207.     var toolbar = getToolbarAt(i);
  208.     if (isCustomizableToolbar(toolbar)) {
  209.       setAttribute(toolbar, "location", aLocation);
  210.       gToolboxDocument.persist(toolbar.id, "location");
  211.     }
  212.   }
  213.  
  214.   gToolbox = gToolboxDocument.getElementById(toolboxId);
  215.   gToolboxDocument = gToolbox.ownerDocument;
  216.   
  217.   gToolbox.addEventListener("draggesture", onToolbarDragGesture, false);
  218.   gToolbox.addEventListener("dragover", onToolbarDragOver, false);
  219.   gToolbox.addEventListener("dragexit", onToolbarDragExit, false);
  220.   gToolbox.addEventListener("dragdrop", onToolbarDragDrop, false);
  221.  
  222.   // Now re-wrap the items on the toolbar, but don't clobber previousset.
  223.   wrapToolbarItems(false);
  224. }
  225.  
  226. /**
  227.  * Handler that takes care of a new toolbar being selected for customization.
  228.  */
  229. _updateToolbarSelection = function(aSelection) {
  230.  
  231.   var callback = window.arguments[2];
  232.   if(callback) {
  233.  
  234.     // first of all, we need to remove our listeners and unwrap
  235.     // the toolbar items. this is important to do first, before calling
  236.     // the outside world, since they possibly want to change those items...
  237.     removeToolboxListeners();
  238.     unwrapToolbarItems(true);
  239.     
  240.     // persist the current set of buttons in all
  241.     // customizable toolbars to localstore.    
  242.     persistCurrentSets();
  243.  
  244.     // execute the supplied callback function. we expect to receive
  245.     // the toolbox we're supposed to customize as a result.
  246.     var toolbox = callback(aSelection);
  247.  
  248.     // store some internal states in the window arguments
  249.     // since we're going to call initDialog() again...
  250.     window.arguments[0] = toolbox;
  251.     window.arguments[3] = aSelection;
  252.  
  253.     // show or hide the location menu dependend
  254.     // on the toolbar we're switching to.
  255.     updateLocationVisibility(aSelection == 'mode');
  256.  
  257.     // nothing has changed so far...
  258.     gToolboxChanged = false;
  259.  
  260.     // now just call the default load handler in order to
  261.     // initialize the dialog for a fresh start.
  262.     gOnLoad();
  263.   }
  264. }
  265.  
  266. /**
  267.  * Show or hide the location selection, this option shouldn't be always visible
  268.  */
  269. _updateLocationVisibility = function(aShow) {
  270.  
  271.   var controls = document.getElementsByAttribute("location-option", "true");
  272.   for (var i=0;i<controls.length;i++) {
  273.     if (aShow) {
  274.       controls[i].removeAttribute("collapsed");
  275.     } else {
  276.       controls[i].setAttribute("collapsed","true");
  277.     }  
  278.   }
  279. }
  280.  
  281. /**
  282.  * Builds the palette of draggable items that are not yet in a toolbar.
  283.  */
  284. _buildPalette = function() {
  285.  
  286.   // Empty the palette first.
  287.   var paletteBox = document.getElementById("palette-box");
  288.   while (paletteBox.lastChild)
  289.     paletteBox.removeChild(paletteBox.lastChild);
  290.  
  291.   var currentRow = document.createElementNS("http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul",
  292.                                             "hbox");
  293.   currentRow.setAttribute("class", "paletteRow");
  294.  
  295.   // Add the toolbar separator item.
  296.   var templateNode = document.createElementNS("http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul",
  297.                                               "toolbarseparator");
  298.   templateNode.id = "separator";
  299.   wrapPaletteItem(templateNode, currentRow, null);
  300.  
  301.   // Add the toolbar spring item.
  302.   templateNode = document.createElementNS("http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul",
  303.                                               "toolbarspring");
  304.   templateNode.id = "spring";
  305.   templateNode.flex = 1;
  306.   wrapPaletteItem(templateNode, currentRow, null);
  307.  
  308.   // Add the toolbar spacer item.
  309.   templateNode = document.createElementNS("http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul",
  310.                                               "toolbarspacer");
  311.   templateNode.id = "spacer";
  312.   templateNode.flex = 1;
  313.   wrapPaletteItem(templateNode, currentRow, null);
  314.  
  315.   var rowSlot = 3;
  316.  
  317.   var currentItems = getCurrentItemIds();
  318.   templateNode = gToolbox.palette.firstChild;
  319.   while (templateNode) {
  320.     // Check if the item is already in a toolbar before adding it to the palette.
  321.     if (!(templateNode.id in currentItems)) {
  322.  
  323.       var nodeMode = templateNode.getAttribute('mode');
  324.       if (!nodeMode)
  325.         nodeMode = 'mail';
  326.  
  327.       if (nodeMode == window.arguments[3]) {
  328.  
  329.         var paletteItem = templateNode.cloneNode(true);
  330.  
  331.         if (rowSlot == kRowMax) {
  332.           // Append the old row.
  333.           paletteBox.appendChild(currentRow);
  334.  
  335.           // Make a new row.
  336.           currentRow = document.createElementNS("http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul",
  337.                                                 "hbox");
  338.           currentRow.setAttribute("class", "paletteRow");
  339.           rowSlot = 0;
  340.         }
  341.  
  342.         ++rowSlot;
  343.         wrapPaletteItem(paletteItem, currentRow, null);
  344.       }
  345.     }
  346.     
  347.     templateNode = templateNode.nextSibling;
  348.   }
  349.  
  350.   if (currentRow) { 
  351.     fillRowWithFlex(currentRow);
  352.     paletteBox.appendChild(currentRow);
  353.   }
  354. }
  355.  
  356. if (gIsMainApplicationContext) {
  357.     repositionDialog = _repositionDialog;
  358.     updateToolbarLocation = _updateToolbarLocation;
  359.     updateToolbarSelection = _updateToolbarSelection;
  360.     updateLocationVisibility = _updateLocationVisibility;
  361.     buildPalette = _buildPalette;
  362. }
  363.