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 / linkToolbarHandler.js < prev    next >
Text File  |  2003-06-08  |  9KB  |  316 lines

  1. /* ***** BEGIN LICENSE BLOCK *****
  2.  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
  3.  *
  4.  * The contents of this file are subject to the Mozilla Public License Version
  5.  * 1.1 (the "License"); you may not use this file except in compliance with
  6.  * the License. You may obtain a copy of the License at
  7.  * http://www.mozilla.org/MPL/
  8.  *
  9.  * Software distributed under the License is distributed on an "AS IS" basis,
  10.  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
  11.  * for the specific language governing rights and limitations under the
  12.  * License.
  13.  *
  14.  * The Original Code is Eric Hodel's <drbrain@segment7.net> code.
  15.  *
  16.  * The Initial Developer of the Original Code is
  17.  * Eric Hodel.
  18.  * Portions created by the Initial Developer are Copyright (C) 2001
  19.  * the Initial Developer. All Rights Reserved.
  20.  *
  21.  * Contributor(s):
  22.  *      Christopher Hoess <choess@force.stwing.upenn.edu>
  23.  *      Tim Taylor <tim@tool-man.org>
  24.  *      Stuart Ballard <sballard@netreach.net>
  25.  *
  26.  * Alternatively, the contents of this file may be used under the terms of
  27.  * either the GNU General Public License Version 2 or later (the "GPL"), or
  28.  * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
  29.  * in which case the provisions of the GPL or the LGPL are applicable instead
  30.  * of those above. If you wish to allow use of your version of this file only
  31.  * under the terms of either the GPL or the LGPL, and not to allow others to
  32.  * use your version of this file under the terms of the MPL, indicate your
  33.  * decision by deleting the provisions above and replace them with the notice
  34.  * and other provisions required by the GPL or the LGPL. If you do not delete
  35.  * the provisions above, a recipient may use your version of this file under
  36.  * the terms of any one of the MPL, the GPL or the LGPL.
  37.  *
  38.  * ***** END LICENSE BLOCK ***** */
  39.  
  40. /** 
  41.  * LinkToolbarHandler is a Singleton that displays LINK elements 
  42.  * and nodeLists of LINK elements in the Link Toolbar.  It
  43.  * associates the LINK with a corresponding LinkToolbarItem based 
  44.  * on it's REL attribute and the toolbar item's ID attribute.
  45.  * LinkToolbarHandler is also a Factory and will create 
  46.  * LinkToolbarItems as necessary.
  47.  */
  48. function LinkToolbarHandler()
  49. {
  50.   this.items = new Array();
  51.   this.hasItems = false;
  52. }
  53.  
  54. LinkToolbarHandler.prototype.handle =
  55. function(element)
  56. {
  57.   // XXX: if you're going to re-enable handling of anchor elements,
  58.   //    you'll want to change this to AnchorElementDecorator
  59.   var linkElement = new LinkElementDecorator(element);
  60.  
  61.   if (linkElement.isIgnored()) return;
  62.  
  63.   if (!this.hasItems) {
  64.     this.hasItems = true;
  65.     linkToolbarUI.activate();
  66.   }
  67.  
  68.   for (var i = 0; i < linkElement.relValues.length; i++) {
  69.     var linkType = LinkToolbarHandler.getLinkType(linkElement.relValues[i]);
  70.     this.getItemForLinkType(linkType).displayLink(linkElement);
  71.   }
  72. }
  73.  
  74. LinkToolbarHandler.getLinkType =
  75. function(relAttribute)
  76. {
  77.   switch (relAttribute.toLowerCase()) {
  78.     case "home":
  79.     case "start":
  80.     case "top":
  81.     case "origin":
  82.       return "top";
  83.  
  84.     case "up":
  85.     case "parent":
  86.       return "up";
  87.  
  88.     case "begin":
  89.     case "first":
  90.       return "first";
  91.  
  92.     case "next":
  93.     case "child":
  94.       return "next";
  95.  
  96.     case "prev":
  97.     case "previous":
  98.       return "prev";
  99.  
  100.     case "end":
  101.     case "last":
  102.       return "last";
  103.  
  104.     case "author":
  105.     case "made":
  106.       return "author";
  107.  
  108.     case "contents":
  109.     case "toc":
  110.       return "toc";
  111.  
  112.     default:
  113.       return relAttribute.toLowerCase();
  114.   }
  115. }
  116.  
  117. LinkToolbarHandler.prototype.getItemForLinkType =
  118. function(linkType) {
  119.   if (!(linkType in this.items && this.items[linkType]))
  120.     this.items[linkType] = LinkToolbarHandler.createItemForLinkType(linkType);
  121.  
  122.   return this.items[linkType];
  123. }
  124.  
  125. LinkToolbarHandler.createItemForLinkType =
  126. function(linkType)
  127. {
  128.   if (!document.getElementById("link-" + linkType))
  129.     return new LinkToolbarTransientMenu(linkType);
  130.  
  131.   // XXX: replace switch with polymorphism
  132.   switch(document.getElementById("link-" + linkType).localName) {
  133.     case "toolbarbutton":
  134.       return new LinkToolbarButton(linkType);
  135.  
  136.     case "menuitem":
  137.       return new LinkToolbarItem(linkType);
  138.  
  139.     case "menu":
  140.       return new LinkToolbarMenu(linkType);
  141.  
  142.     default:
  143.       return new LinkToolbarTransientMenu(linkType);
  144.   }
  145. }
  146.  
  147. LinkToolbarHandler.prototype.clearAllItems =
  148. function()
  149. {
  150.   // Hide the 'miscellaneous' separator
  151.   document.getElementById("misc-separator").setAttribute("collapsed", "true");
  152.  
  153.   // Disable the individual items
  154.   for (var linkType in this.items)
  155.     this.items[linkType].clear();
  156.  
  157.   // Store the fact that the toolbar is empty
  158.   this.hasItems = false;
  159. }
  160.  
  161. const linkToolbarHandler = new LinkToolbarHandler();
  162.  
  163.  
  164. function LinkElementDecorator(element) {
  165.   /*
  166.    * XXX: this is an incomplete decorator, because it doesn't implement
  167.    *      the full Element interface.  If you need to use a method 
  168.    *      or member in the Element interface, just add it here and
  169.    *      have it delegate to this.element
  170.    *
  171.    * XXX: would rather add some methods to Element.prototype instead of
  172.    *    using a decorator, but Element.prototype is no longer exposed 
  173.    *      since the XPCDOM landing, see bug 83433
  174.    */
  175.  
  176.   if (!element) return; // skip the rest on foo.prototype = new ThisClass calls
  177.   
  178.   this.element = element;
  179.   
  180.   this.rel = LinkElementDecorator.convertRevMade(element.rel, element.rev);
  181.   if (this.rel)
  182.     this.relValues = this.rel.split(" ");
  183.   this.rev = element.rev;
  184.   this.title = element.title;
  185.   this.href = element.href;
  186.   this.hreflang = element.hreflang;
  187.   this.media = element.media;
  188.   this.longTitle = null;
  189. }
  190.  
  191. LinkElementDecorator.prototype.isIgnored =
  192. function()
  193. {
  194.   if (!this.rel) return true;
  195.   for (var i = 0; i < this.relValues.length; i++) {
  196.     var testVal = this.relValues[i].toLowerCase();
  197.     if ((testVal == "stylesheet") || 
  198.       (testVal == "icon") ||
  199.       (testVal == "fontdef") ||
  200.       (testVal.match(/^p3pv/)) ||
  201.       (testVal.match(/^schema./)))
  202.       return true;
  203.   }
  204.   return false;
  205. }
  206.  
  207. LinkElementDecorator.convertRevMade =
  208. function(rel, rev) 
  209. {
  210.   if (!rel && rev && LinkElementDecorator.findWord("made", rev.toLowerCase()))
  211.     return rev;
  212.   else
  213.     return rel;
  214. }
  215.  
  216. LinkElementDecorator.prototype.getTooltip =
  217. function() 
  218. {
  219.   return this.getLongTitle() != "" ? this.getLongTitle() : this.href;
  220. }
  221.  
  222. LinkElementDecorator.prototype.getLabel =
  223. function() 
  224. {
  225.   return this.getLongTitle() != "" ? this.getLongTitle() : this.rel;
  226. }
  227.  
  228. LinkElementDecorator.prototype.getLongTitle =
  229. function() 
  230. {
  231.   if (this.longTitle == null)
  232.     this.longTitle = this.makeLongTitle();
  233.  
  234.   return this.longTitle;
  235. }
  236.  
  237. LinkElementDecorator.prototype.makeLongTitle =
  238. function()
  239. {
  240.   var prefix = "";
  241.  
  242.   // XXX: lookup more meaningful and localized version of media, 
  243.   //   i.e. media="print" becomes "Printable" or some such
  244.   // XXX: use localized version of ":" separator
  245.   if (this.media 
  246.       && !LinkElementDecorator.findWord("all", this.media.toLowerCase())
  247.       && !LinkElementDecorator.findWord("screen", this.media.toLowerCase()))
  248.     prefix += this.media + ": ";
  249.   if (this.hreflang)
  250.     prefix += languageDictionary.lookupLanguageName(this.hreflang)
  251.           + ": ";
  252.  
  253.   return this.title ? prefix + this.title : prefix;
  254. }
  255.  
  256. LinkElementDecorator.findWord =
  257. function(word, string)
  258. {
  259.   var barePattern = eval("/^" + word + "$/");
  260.   var middlePattern = eval("/[-\\W]" + word + "[-\\W]/");
  261.   var startPattern = eval("/^" + word + "[-\\W]/");
  262.   var endPattern = eval("/[-\\W]" + word + "$/");
  263.  
  264.   if (string.search(barePattern) != -1)
  265.     return true;
  266.   if (string.search(middlePattern) != -1)
  267.     return true;
  268.   if (string.search(startPattern) != -1)
  269.     return true;
  270.   if (string.search(endPattern) != -1)
  271.     return true;
  272.  
  273.   return false;
  274. }
  275.  
  276.  
  277. function AnchorElementDecorator(element) {
  278.   this.constructor(element);
  279. }
  280. AnchorElementDecorator.prototype = new LinkElementDecorator;
  281.  
  282. AnchorElementDecorator.prototype.getLongTitle =
  283. function() 
  284. {
  285.   return this.title ? this.__proto__.getLongTitle.apply(this) 
  286.       : getText(this.element);
  287. }
  288.  
  289. AnchorElementDecorator.prototype.getText =
  290. function(element)
  291. {
  292.   return condenseWhitespace(getTextRecursive(element));
  293. }
  294.  
  295. AnchorElementDecorator.prototype.getTextRecursive =
  296. function(node) 
  297. {
  298.   var text = "";
  299.   node.normalize();
  300.   if (node.hasChildNodes()) {
  301.     for (var i = 0; i < node.childNodes.length; i++) {
  302.       if (node.childNodes.item(i).nodeType == Node.TEXT_NODE)
  303.         text += node.childNodes.item(i).nodeValue;
  304.       else if (node.childNodes.item(i).nodeType == Node.ELEMENT_NODE)
  305.         text += getTextRecursive(node.childNodes.item(i));
  306.     }
  307.   }
  308.  
  309.   return text;
  310. }
  311.  
  312. AnchorElementDecorator.prototype.condenseWhitespace =
  313. function(text)
  314. {
  315.   return text.replace(/\W*$/, "").replace(/^\W*/, "").replace(/\W+/g, " ");
  316. }