home *** CD-ROM | disk | FTP | other *** search
/ Chip 2002 January / 01_02.iso / software / netscape62win / browser.xpi / bin / chrome / comm.jar / content / navigator / metadata.js < prev    next >
Encoding:
Text File  |  2001-08-15  |  15.7 KB  |  518 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 Mozilla 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/MPL/
  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 this file as it was released on
  14.  * January 3, 2001.
  15.  *
  16.  * The Initial Developer of the Original Code is Jonas Sicking.
  17.  * Portions created by Jonas Sicking are Copyright (C) 2000
  18.  * Jonas Sicking.  All Rights Reserved.
  19.  *
  20.  * Contributor(s):
  21.  *   Jonas Sicking <sicking@bigfoot.com> (Original Author)
  22.  *   Gervase Markham <gerv@gerv.net>
  23.  *   Heikki Toivonen <heikki@netscape.com>
  24.  *
  25.  * Alternatively, the contents of this file may be used under the
  26.  * terms of the GNU General Public License Version 2 or later (the
  27.  * "GPL"), in which case the provisions of the GPL are applicable
  28.  * instead of those above.  If you wish to allow use of your
  29.  * version of this file only under the terms of the GPL and not to
  30.  * allow others to use your version of this file under the MPL,
  31.  * indicate your decision by deleting the provisions above and
  32.  * replace them with the notice and other provisions required by
  33.  * the GPL.  If you do not delete the provisions above, a recipient
  34.  * may use your version of this file under either the MPL or the
  35.  * GPL.
  36.  *
  37.  */
  38.  
  39. const XLinkNS = "http://www.w3.org/1999/xlink";
  40. const XULNS = "http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul";
  41. const XMLNS = "http://www.w3.org/XML/1998/namespace";
  42. const XHTMLNS = "http://www.w3.org/1999/xhtml";
  43. var gMetadataBundle;
  44. var gLangBundle;
  45. var gRegionBundle;
  46. var nodeView;
  47. var htmlMode = false;
  48.  
  49. var onLink   = false;
  50. var onImage  = false;
  51. var onInsDel = false;
  52. var onQuote  = false;
  53. var onMisc   = false;
  54. var onTable  = false;
  55. var onTitle  = false;
  56. var onLang   = false;
  57.  
  58. function onLoad()
  59. {
  60.     gMetadataBundle = document.getElementById("bundle_metadata");
  61.     gLangBundle = document.getElementById("bundle_languages");
  62.     gRegionBundle = document.getElementById("bundle_regions");
  63.     
  64.     showMetadataFor(window.arguments[0]);
  65.  
  66.     nodeView = window.arguments[0].ownerDocument.defaultView;
  67. }
  68.  
  69. function showMetadataFor(elem)
  70. {
  71.     // skip past non-element nodes
  72.     while (elem && elem.nodeType != Node.ELEMENT_NODE)
  73.         elem = elem.parentNode;
  74.  
  75.     if (!elem) {
  76.         alert(gMetadataBundle.getString("unableToShowProps"));
  77.         window.close();
  78.     }
  79.  
  80.     if (elem.ownerDocument.getElementsByName && !elem.ownerDocument.namespaceURI)
  81.         htmlMode = true;
  82.     
  83.     // htmllocalname is "" if it's not an html tag, or the name of the tag if it is.
  84.     var htmllocalname = "";
  85.     if (isHTMLElement(elem,"")) { 
  86.         htmllocalname = elem.localName.toLowerCase();
  87.     }
  88.     
  89.     // We only look for images once
  90.     checkForImage(elem, htmllocalname);
  91.     
  92.     // Walk up the tree, looking for elements of interest.
  93.     // Each of them could be at a different level in the tree, so they each
  94.     // need their own boolean to tell us to stop looking.
  95.     while (elem && elem.nodeType == Node.ELEMENT_NODE) {
  96.         if (!onLink)   checkForLink(elem, htmllocalname);
  97.         if (!onInsDel) checkForInsDel(elem, htmllocalname);
  98.         if (!onQuote)  checkForQuote(elem, htmllocalname);
  99.         if (!onTable)  checkForTable(elem, htmllocalname);
  100.         if (!onTitle)  checkForTitle(elem, htmllocalname);
  101.         if (!onLang)   checkForLang(elem, htmllocalname);
  102.           
  103.         elem = elem.parentNode;
  104.  
  105.         htmllocalname = "";
  106.         if (isHTMLElement(elem,"")) { 
  107.             htmllocalname = elem.localName.toLowerCase();
  108.         }
  109.     }
  110.     
  111.     // Decide which sections to show
  112.     var onMisc = onTable || onTitle || onLang;
  113.     if (!onMisc)   hideNode("misc-sec");
  114.     if (!onLink)   hideNode("link-sec");
  115.     if (!onImage)  hideNode("image-sec");
  116.     if (!onInsDel) hideNode("insdel-sec");
  117.     if (!onQuote)  hideNode("quote-sec");
  118.  
  119.     // Fix the Misc section visibilities
  120.     if (onMisc) {
  121.         if (!onTable) hideNode("misc-tblsummary");
  122.         if (!onLang)  hideNode("misc-lang");
  123.         if (!onTitle) hideNode("misc-title");
  124.     }
  125.  
  126.     // Get rid of the "No properties" message. This is a backstop -
  127.     // it should really never show, as long as nsContextMenu.js's
  128.     // checking doesn't get broken.
  129.     if (onLink || onImage || onInsDel || onQuote || onMisc)
  130.         hideNode("no-properties")
  131. }
  132.  
  133.  
  134. function checkForImage(elem, htmllocalname)
  135. {
  136.     var img;
  137.     var imgType;   // "img" = <img>
  138.                    // "object" = <object>
  139.                    // "input" = <input type=image>
  140.                    // "background" = css background (to be added later)
  141.  
  142.     if (htmllocalname === "img") {
  143.         img = elem;
  144.         imgType = "img";
  145.  
  146.     } else if (htmllocalname === "object" &&
  147.                elem.type.substring(0,6) == "image/" &&
  148.                elem.data) {
  149.         img = elem;
  150.         imgType = "object";
  151.  
  152.     } else if (htmllocalname === "input" &&
  153.                elem.type.toUpperCase() == "IMAGE") {
  154.         img = elem;
  155.         imgType = "input";
  156.  
  157.     } else if (htmllocalname === "area" || htmllocalname === "a") {
  158.  
  159.         // Clicked in image map?
  160.         var map = elem;
  161.         while (map && map.nodeType == Node.ELEMENT_NODE && !isHTMLElement(map,"map") )
  162.             map = map.parentNode;
  163.  
  164.         if (map && map.nodeType == Node.ELEMENT_NODE)
  165.             img = getImageForMap(map);
  166.     }
  167.  
  168.     if (img) {
  169.         setInfo("image-url", img.src);
  170.         if ("width" in img) {
  171.             setInfo("image-width", img.width);
  172.             setInfo("image-height", img.height);
  173.         }
  174.     else {
  175.         setInfo("image-width", "");
  176.         setInfo("image-height", "");
  177.     }    
  178.      
  179.         if (imgType == "img") {
  180.             setInfo("image-desc", getAbsoluteURL(img.longDesc, img));
  181.         } else {
  182.             setInfo("image-desc", "");
  183.         }
  184.         
  185.         onImage = true;
  186.     }
  187. }
  188.  
  189. function checkForLink(elem, htmllocalname)
  190. {
  191.     if ((htmllocalname === "a" && elem.href != "") ||
  192.         htmllocalname === "area") {
  193.  
  194.         setInfo("link-lang", convertLanguageCode(elem.getAttribute("hreflang")));
  195.         setInfo("link-url",  elem.href);
  196.         setInfo("link-type", elem.getAttribute("type"));
  197.         setInfo("link-rel",  elem.getAttribute("rel"));
  198.         setInfo("link-rev",  elem.getAttribute("rev"));
  199.  
  200.         target = elem.target;
  201.  
  202.         switch (target) {
  203.         case "_top":
  204.             setInfo("link-target", gMetadataBundle.getString("sameWindowText"));
  205.             break;
  206.         case "_parent":
  207.             setInfo("link-target", gMetadataBundle.getString("parentFrameText"));
  208.             break;
  209.         case "_blank":
  210.             setInfo("link-target", gMetadataBundle.getString("newWindowText"));
  211.             break;
  212.         case "":
  213.         case "_self":
  214.             if (elem.ownerDocument != elem.ownerDocument.defaultView._content.document)
  215.                 setInfo("link-target", gMetadataBundle.getString("sameFrameText"));
  216.             else
  217.                 setInfo("link-target", gMetadataBundle.getString("sameWindowText"));
  218.             break;
  219.         default:
  220.             setInfo("link-target", "\"" + target + "\"");
  221.         }
  222.         
  223.         onLink = true;
  224.     }
  225.  
  226.     else if (elem.getAttributeNS(XLinkNS,"href") != "") {
  227.         setInfo("link-url", getAbsoluteURL(elem.getAttributeNS(XLinkNS,"href"),elem));
  228.         setInfo("link-lang", "");
  229.         setInfo("link-type", "");
  230.         setInfo("link-rel", "");
  231.         setInfo("link-rev", "");
  232.  
  233.         switch (elem.getAttributeNS(XLinkNS,"show")) {
  234.         case "embed":
  235.             setInfo("link-target", gMetadataBundle.getString("embeddedText"));
  236.             break;
  237.         case "new":
  238.             setInfo("link-target", gMetadataBundle.getString("newWindowText"));
  239.             break;
  240.         case "":
  241.         case "replace":
  242.             if (elem.ownerDocument != elem.ownerDocument.defaultView._content.document)
  243.                 setInfo("link-target", gMetadataBundle.getString("sameFrameText"));
  244.             else
  245.                 setInfo("link-target", gMetadataBundle.getString("sameWindowText"));
  246.             break;
  247.         default:
  248.             setInfo("link-target", "");
  249.             break;
  250.         }
  251.         
  252.         onLink = true;
  253.     }
  254. }
  255.  
  256. function checkForInsDel(elem, htmllocalname)
  257. {
  258.     if ((htmllocalname === "ins" || htmllocalname === "del") &&
  259.         (elem.cite || elem.dateTime)) {
  260.         setInfo("insdel-cite", getAbsoluteURL(elem.cite, elem));
  261.         setInfo("insdel-date", elem.dateTime);
  262.         onInsDel = true;
  263.     } 
  264. }
  265.  
  266.  
  267. function checkForQuote(elem, htmllocalname)
  268. {
  269.     if ((htmllocalname === "q" || htmllocalname === "blockquote") && elem.cite) {
  270.         setInfo("quote-cite", getAbsoluteURL(elem.cite, elem));
  271.         onQuote = true;
  272.     } 
  273. }
  274.  
  275. function checkForTable(elem, htmllocalname)
  276. {
  277.     if (htmllocalname === "table" && elem.summary) {
  278.         setInfo("misc-tblsummary", elem.summary);
  279.         onTable = true;
  280.     }
  281. }
  282.  
  283. function checkForLang(elem, htmllocalname)
  284. {
  285.     if ((htmllocalname && elem.lang) || elem.getAttributeNS(XMLNS, "lang")) {
  286.         var abbr;
  287.         if (htmllocalname && elem.lang)
  288.             abbr = elem.lang;
  289.         else
  290.             abbr = elem.getAttributeNS(XMLNS, "lang");
  291.             
  292.         setInfo("misc-lang", convertLanguageCode(abbr));
  293.         onLang = true;
  294.     }
  295. }
  296.     
  297. function checkForTitle(elem, htmllocalname)
  298. {
  299.     if (htmllocalname && elem.title) {
  300.         setInfo("misc-title", elem.title);
  301.         onTitle = true;
  302.     }    
  303. }
  304.  
  305. /*
  306.  * Set text of node id to value
  307.  * if value="" the node with specified id is hidden.
  308.  * Node should be have one of these forms
  309.  * <xul:text id="id-text" value=""/>
  310.  * <xul:html id="id-text"/>
  311.  */
  312. function setInfo(id, value)
  313. {
  314.     if (value == "") {
  315.         hideNode(id);
  316.         return;
  317.     }
  318.  
  319.     var node = document.getElementById(id+"-text");
  320.  
  321.     if (node.namespaceURI == XULNS && node.localName == "text") {
  322.         node.setAttribute("value",value);
  323.  
  324.     } else if (node.namespaceURI == XULNS && node.localName == "html") {
  325.         while (node.hasChildNodes())
  326.             node.removeChild(node.firstChild);
  327.         node.appendChild(node.ownerDocument.createTextNode(value));
  328.     }
  329. }
  330.  
  331. // Hide node with specified id
  332. function hideNode(id)
  333. {
  334.     var style = document.getElementById(id).getAttribute("style");
  335.     document.getElementById(id).setAttribute("style", "display:none;" + style);
  336. }
  337.  
  338. // opens the link contained in the node's "value" attribute.
  339. function openLink(node)
  340. {
  341.     var url = node.getAttribute("value");
  342.     nodeView._content.document.location = url;
  343.     window.close();
  344. }
  345.  
  346. /*
  347.  * Find <img> or <object> which uses an imagemap.
  348.  * If more then one object is found we can't determine which one
  349.  * was clicked.
  350.  *
  351.  * This code has to be changed once bug 1882 is fixed.
  352.  * Once bug 72527 is fixed this code should use the .images collection.
  353.  */
  354. function getImageForMap(map)
  355. {
  356.     var mapuri = "#" + map.getAttribute("name");
  357.     var multipleFound = false;
  358.     var img;
  359.  
  360.     var list = getHTMLElements(map.ownerDocument, "img");
  361.     for (var i=0; i < list.length; i++) {
  362.         if (list.item(i).getAttribute("usemap") == mapuri) {
  363.             if (img) {
  364.                 multipleFound = true;
  365.                 break;
  366.             } else {
  367.                 img = list.item(i);
  368.                 imgType = "img";
  369.             }
  370.         }
  371.     }
  372.  
  373.     list = getHTMLElements(map.ownerDocument, "object");
  374.     for (i = 0; i < list.length; i++) {
  375.         if (list.item(i).getAttribute("usemap") == mapuri) {
  376.             if (img) {
  377.               multipleFound = true;
  378.               break;
  379.             } else {
  380.               img = list.item(i);
  381.               imgType = "object";
  382.             }
  383.         }
  384.     }
  385.  
  386.     if (multipleFound)
  387.         img = null;
  388.  
  389.     return img;
  390. }
  391.  
  392. /*
  393.  * Takes care of XMLBase and <base>
  394.  * url is the possibly relative url.
  395.  * node is the node where the url was given (needed for XMLBase)
  396.  *
  397.  * This function is called in many places as a workaround for bug 72524
  398.  * Once bug 72522 is fixed this code should use the Node.baseURI attribute
  399.  *
  400.  * for node==null or url=="", empty string is returned
  401.  */
  402. function getAbsoluteURL(url, node)
  403. {
  404.     if (!url || !node)
  405.         return "";
  406.  
  407.     var urlArr = new Array(url);
  408.     var doc = node.ownerDocument;
  409.  
  410.     if (node.nodeType == Node.ATTRIBUTE_NODE)
  411.         node = node.ownerElement;
  412.  
  413.     while (node && node.nodeType == Node.ELEMENT_NODE) {
  414.         if (node.getAttributeNS(XMLNS, "base") != "")
  415.             urlArr.unshift(node.getAttributeNS(XMLNS, "base"));
  416.  
  417.         node = node.parentNode;
  418.     }
  419.  
  420.     // Look for a <base>.
  421.     var baseTags = getHTMLElements(doc,"base");
  422.     if (baseTags && baseTags.length) {
  423.         urlArr.unshift(baseTags[baseTags.length - 1].getAttribute("href"));
  424.     }
  425.  
  426.     // resolve everything from bottom up, starting with document location
  427.     var ioService = Components.classes["@mozilla.org/network/io-service;1"]
  428.                   .getService(Components.interfaces.nsIIOService);
  429.     var URL = ioService.newURI(doc.location.href, null);
  430.     for (var i=0; i<urlArr.length; i++) {
  431.         URL.spec = URL.resolve(urlArr[i]);
  432.     }
  433.  
  434.     return URL.spec;
  435. }
  436.  
  437. function getHTMLElements(node, name)
  438. {
  439.     if (htmlMode)
  440.         return node.getElementsByTagName(name);
  441.     return node.getElementsByTagNameNS(XHTMLNS, name);
  442. }
  443.  
  444. // name should be in lower case
  445. function isHTMLElement(node, name)
  446. {
  447.     if (node.nodeType != Node.ELEMENT_NODE)
  448.         return false;
  449.  
  450.     if (htmlMode)
  451.         return !name || node.localName.toLowerCase() == name;
  452.  
  453.     return (!name || node.localName == name) && node.namespaceURI == XHTMLNS;
  454. }
  455.  
  456. // This function coded according to the spec at:
  457. // http://www.bath.ac.uk/~py8ieh/internet/discussion/metadata.txt
  458. function convertLanguageCode(abbr)
  459. {
  460.     var result;
  461.  
  462.     var tokens = abbr.split("-");
  463.  
  464.     if (tokens[0] === "x" || tokens[0] === "i")
  465.     {
  466.         // x and i prefixes mean unofficial ones. So we upper-case the first
  467.         // word and leave the rest.
  468.         tokens.shift();
  469.  
  470.         if (tokens[0])
  471.         {
  472.             // Upper-case first letter
  473.             result = tokens[0].substr(0, 1).toUpperCase() + tokens[0].substr(1);
  474.             tokens.shift();
  475.  
  476.             if (tokens[0])
  477.             {
  478.                 // Add on the rest as space-separated strings inside the brackets
  479.                 result += " (" + tokens.join(" ") + ")";
  480.             }
  481.         }
  482.     }
  483.     else
  484.     {
  485.         // Otherwise we treat the first as a lang, the second as a region
  486.         // and the rest as strings.
  487.         try
  488.         {
  489.             result = gLangBundle.getString(tokens[0]);
  490.         }
  491.         catch (e) 
  492.         {
  493.             // Language not present in lang bundle
  494.             result = tokens[0]; 
  495.         }
  496.  
  497.         tokens.shift();
  498.  
  499.         if (tokens[0])
  500.         {
  501.             try
  502.             {
  503.                 // We don't add it on to the result immediately
  504.                 // because we want to get the spacing right.
  505.                 tokens[0] = gRegionBundle.getString(tokens[0].toLowerCase());
  506.             }
  507.             catch (e) 
  508.             {
  509.                 // Region not present in region bundle
  510.             }
  511.  
  512.             result += " (" + tokens.join(" ") + ")";
  513.         }
  514.     }
  515.  
  516.     return result;
  517. }
  518.