home *** CD-ROM | disk | FTP | other *** search
/ PC World 2005 December / PCWorld_2005-12_cd.bin / komunikace / netscape / nsb-install-8-0.exe / chrome / browser.jar / content / browser / metaData.js < prev    next >
Text File  |  2005-09-26  |  17KB  |  593 lines

  1.  
  2. const XLinkNS = "http://www.w3.org/1999/xlink";
  3. const XULNS = "http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul";
  4. const XMLNS = "http://www.w3.org/XML/1998/namespace";
  5. const XHTMLNS = "http://www.w3.org/1999/xhtml";
  6. var gMetadataBundle;
  7. var gLangBundle;
  8. var gRegionBundle;
  9. var nodeView;
  10. var htmlMode = false;
  11.  
  12. var onLink   = false;
  13. var onImage  = false;
  14. var onInsDel = false;
  15. var onQuote  = false;
  16. var onMisc   = false;
  17. var onTable  = false;
  18. var onTitle  = false;
  19. var onLang   = false;
  20.  
  21. const nsICacheService = Components.interfaces.nsICacheService;
  22. const cacheService = Components.classes["@mozilla.org/network/cache-service;1"]
  23.                      .getService(nsICacheService);
  24. var httpCacheSession = cacheService.createSession("HTTP", 0, true);
  25. httpCacheSession.doomEntriesIfExpired = false;
  26. var ftpCacheSession = cacheService.createSession("FTP", 0, true);
  27. ftpCacheSession.doomEntriesIfExpired = false;
  28.  
  29.  
  30. function onLoad()
  31. {
  32.   gMetadataBundle = document.getElementById("bundle_metadata");
  33.   gLangBundle = document.getElementById("bundle_languages");
  34.   gRegionBundle = document.getElementById("bundle_regions");
  35.   
  36.   showMetadataFor(window.arguments[0]);
  37.   nodeView = window.arguments[0].ownerDocument.defaultView;
  38. }
  39.  
  40. function showMetadataFor(elem)
  41. {
  42.   // skip past non-element nodes
  43.   while (elem && elem.nodeType != Node.ELEMENT_NODE)
  44.     elem = elem.parentNode;
  45.  
  46.   if (!elem) {
  47.     alert(gMetadataBundle.getString("unableToShowProps"));
  48.     window.close();
  49.   }
  50.  
  51.   if (elem.ownerDocument.getElementsByName && !elem.ownerDocument.namespaceURI)
  52.     htmlMode = true;
  53.   
  54.   // htmllocalname is "" if it's not an html tag, or the name of the tag if it is.
  55.   var htmllocalname = "";
  56.   if (isHTMLElement(elem,"")) { 
  57.     htmllocalname = elem.localName.toLowerCase();
  58.   }
  59.   
  60.   // We only look for images once
  61.   checkForImage(elem, htmllocalname);
  62.   
  63.   // Walk up the tree, looking for elements of interest.
  64.   // Each of them could be at a different level in the tree, so they each
  65.   // need their own boolean to tell us to stop looking.
  66.   while (elem && elem.nodeType == Node.ELEMENT_NODE) {
  67.     if (!onLink)   checkForLink(elem, htmllocalname);
  68.     if (!onInsDel) checkForInsDel(elem, htmllocalname);
  69.     if (!onQuote)  checkForQuote(elem, htmllocalname);
  70.     if (!onTable)  checkForTable(elem, htmllocalname);
  71.     if (!onTitle)  checkForTitle(elem, htmllocalname);
  72.     if (!onLang)   checkForLang(elem, htmllocalname);
  73.       
  74.     elem = elem.parentNode;
  75.  
  76.     htmllocalname = "";
  77.     if (isHTMLElement(elem,"")) { 
  78.       htmllocalname = elem.localName.toLowerCase();
  79.     }
  80.   }
  81.   
  82.   // Decide which sections to show
  83.   var onMisc = onTable || onTitle || onLang;
  84.   if (!onMisc)   hideNode("misc-sec");
  85.   if (!onLink)   hideNode("link-sec");
  86.   if (!onImage)  hideNode("image-sec");
  87.   if (!onInsDel) hideNode("insdel-sec");
  88.   if (!onQuote)  hideNode("quote-sec");
  89.  
  90.   // Fix the Misc section visibilities
  91.   if (onMisc) {
  92.     if (!onTable) hideNode("misc-tblsummary");
  93.     if (!onLang)  hideNode("misc-lang");
  94.     if (!onTitle) hideNode("misc-title");
  95.   }
  96.  
  97.   // Get rid of the "No properties" message. This is a backstop -
  98.   // it should really never show, as long as nsContextMenu.js's
  99.   // checking doesn't get broken.
  100.   if (onLink || onImage || onInsDel || onQuote || onMisc)
  101.     hideNode("no-properties")
  102. }
  103.  
  104.  
  105. function checkForImage(elem, htmllocalname)
  106. {
  107.   var img;
  108.   var imgType; // "img" = <img>
  109.                // "object" = <object>
  110.                // "input" = <input type=image>
  111.                // "background" = css background (to be added later)
  112.   var ismap = false;
  113.  
  114.   if (htmllocalname === "img") {
  115.     img = elem;
  116.     imgType = "img";
  117.  
  118.   } else if (htmllocalname === "object" &&
  119.              elem.type.substring(0,6) == "image/" &&
  120.              elem.data) {
  121.     img = elem;
  122.     imgType = "object";
  123.  
  124.   } else if (htmllocalname === "input" &&
  125.              elem.type.toUpperCase() == "IMAGE") {
  126.     img = elem;
  127.     imgType = "input";
  128.  
  129.   } else if (htmllocalname === "area" || htmllocalname === "a") {
  130.  
  131.     // Clicked in image map?
  132.     var map = elem;
  133.     ismap = true;
  134.     setAlt(map);
  135.  
  136.     while (map && map.nodeType == Node.ELEMENT_NODE && !isHTMLElement(map,"map") )
  137.       map = map.parentNode;
  138.  
  139.     if (map && map.nodeType == Node.ELEMENT_NODE) {
  140.       img = getImageForMap(map);
  141.       var imgLocalName = img && img.localName.toLowerCase();
  142.       if (imgLocalName == "img" || imgLocalName == "object")
  143.           imgType = imgLocalName;
  144.     }
  145.   }
  146.  
  147.   if (img) {
  148.  
  149.     var imgURL = imgType == "object" ? img.data : img.src;
  150.     setInfo("image-url", imgURL);
  151.     var size = getSize(imgURL);
  152.  
  153.     if (size != -1) {
  154.       var kbSize = size / 1024;
  155.       kbSize = Math.round(kbSize*100)/100;
  156.       setInfo("image-filesize", gMetadataBundle.getFormattedString("imageSize", [kbSize, size]));
  157.     } else {
  158.       setInfo("image-filesize", gMetadataBundle.getString("imageSizeUnknown"));
  159.     }
  160.     if ("width" in img && img.width != "") {
  161.       setInfo("image-width", gMetadataBundle.getFormattedString("imageWidth", [ img.width ]));
  162.       setInfo("image-height", gMetadataBundle.getFormattedString("imageHeight", [ img.height ]));
  163.     }
  164.     else {
  165.       setInfo("image-width", "");
  166.       setInfo("image-height", "");
  167.     }        
  168.      
  169.     if (imgType == "img") {
  170.       setInfo("image-desc", getAbsoluteURL(img.longDesc, img));
  171.     } else {
  172.       setInfo("image-desc", "");
  173.     }
  174.     
  175.     onImage = true;
  176.   }
  177.  
  178.   if (!ismap) {
  179.    if (imgType == "img" || imgType == "input") {
  180.      setAlt(img);
  181.    } else {
  182.      hideNode("image-alt");
  183.    }
  184.   }
  185. }
  186.  
  187. function checkForLink(elem, htmllocalname)
  188. {
  189.   if ((htmllocalname === "a" && elem.href != "") ||
  190.     htmllocalname === "area") {
  191.  
  192.     setInfo("link-lang", convertLanguageCode(elem.getAttribute("hreflang")));
  193.     setInfo("link-url",  elem.href);
  194.     setInfo("link-type", elem.getAttribute("type"));
  195.     setInfo("link-rel",  elem.getAttribute("rel"));
  196.     setInfo("link-rev",  elem.getAttribute("rev"));
  197.  
  198.     var target = elem.target;
  199.  
  200.     switch (target) {
  201.     case "_top":
  202.       setInfo("link-target", gMetadataBundle.getString("sameWindowText"));
  203.       break;
  204.     case "_parent":
  205.       setInfo("link-target", gMetadataBundle.getString("parentFrameText"));
  206.       break;
  207.     case "_blank":
  208.       setInfo("link-target", gMetadataBundle.getString("newWindowText"));
  209.       break;
  210.     case "":
  211.     case "_self":
  212.       if (elem.ownerDocument != elem.ownerDocument.defaultView._content.document)
  213.         setInfo("link-target", gMetadataBundle.getString("sameFrameText"));
  214.       else
  215.         setInfo("link-target", gMetadataBundle.getString("sameWindowText"));
  216.       break;
  217.     default:
  218.       setInfo("link-target", "\"" + target + "\"");
  219.     }
  220.     
  221.     onLink = true;
  222.   }
  223.  
  224.   else if (elem.getAttributeNS(XLinkNS,"href") != "") {
  225.     setInfo("link-url", getAbsoluteURL(elem.getAttributeNS(XLinkNS,"href"),elem));
  226.     setInfo("link-lang", "");
  227.     setInfo("link-type", "");
  228.     setInfo("link-rel", "");
  229.     setInfo("link-rev", "");
  230.  
  231.     switch (elem.getAttributeNS(XLinkNS,"show")) {
  232.     case "embed":
  233.         setInfo("link-target", gMetadataBundle.getString("embeddedText"));
  234.         break;
  235.     case "new":
  236.         setInfo("link-target", gMetadataBundle.getString("newWindowText"));
  237.         break;
  238.     case "":
  239.     case "replace":
  240.         if (elem.ownerDocument != elem.ownerDocument.defaultView._content.document)
  241.             setInfo("link-target", gMetadataBundle.getString("sameFrameText"));
  242.         else
  243.             setInfo("link-target", gMetadataBundle.getString("sameWindowText"));
  244.         break;
  245.     default:
  246.         setInfo("link-target", "");
  247.         break;
  248.     }
  249.     
  250.     onLink = true;
  251.   }
  252. }
  253.  
  254. function checkForInsDel(elem, htmllocalname)
  255. {
  256.   if ((htmllocalname === "ins" || htmllocalname === "del") &&
  257.     (elem.cite || elem.dateTime)) {
  258.     setInfo("insdel-cite", getAbsoluteURL(elem.cite, elem));
  259.     setInfo("insdel-date", elem.dateTime);
  260.     onInsDel = true;
  261.   } 
  262. }
  263.  
  264.  
  265. function checkForQuote(elem, htmllocalname)
  266. {
  267.   if ((htmllocalname === "q" || htmllocalname === "blockquote") && elem.cite) {
  268.     setInfo("quote-cite", getAbsoluteURL(elem.cite, elem));
  269.     onQuote = true;
  270.   } 
  271. }
  272.  
  273. function checkForTable(elem, htmllocalname)
  274. {
  275.   if (htmllocalname === "table" && elem.summary) {
  276.     setInfo("misc-tblsummary", elem.summary);
  277.     onTable = true;
  278.   }
  279. }
  280.  
  281. function checkForLang(elem, htmllocalname)
  282. {
  283.   if ((htmllocalname && elem.lang) || elem.getAttributeNS(XMLNS, "lang")) {
  284.     var abbr;
  285.     if (htmllocalname && elem.lang)
  286.       abbr = elem.lang;
  287.     else
  288.       abbr = elem.getAttributeNS(XMLNS, "lang");
  289.         
  290.     setInfo("misc-lang", convertLanguageCode(abbr));
  291.     onLang = true;
  292.   }
  293. }
  294.     
  295. function checkForTitle(elem, htmllocalname)
  296. {
  297.   if (htmllocalname && elem.title) {
  298.     setInfo("misc-title", elem.title);
  299.     onTitle = true;
  300.   }    
  301. }
  302.  
  303. /*
  304.  * Set text of node id to value
  305.  * if value="" the node with specified id is hidden.
  306.  * Node should be have one of these forms
  307.  * <xul:label id="id-text" value=""/>
  308.  * <xul:description id="id-text"/>
  309.  */
  310. function setInfo(id, value)
  311. {
  312.   if (!value) {
  313.     hideNode(id);
  314.     return;
  315.   }
  316.  
  317.   var node = document.getElementById(id+"-text");
  318.  
  319.   if (node.namespaceURI == XULNS && node.localName == "label" ||
  320.      (node.namespaceURI == XULNS && node.localName == "textbox")) {
  321.     node.setAttribute("value",value);
  322.  
  323.   } else if (node.namespaceURI == XULNS && node.localName == "description") {
  324.     while (node.hasChildNodes())
  325.       node.removeChild(node.firstChild);
  326.     node.appendChild(node.ownerDocument.createTextNode(value));
  327.   }
  328. }
  329.  
  330. // Hide node with specified id
  331. function hideNode(id)
  332. {
  333.     var style = document.getElementById(id).getAttribute("style");
  334.     document.getElementById(id).setAttribute("style", "display:none;" + style);
  335. }
  336.  
  337. const nsIScriptSecurityManager = Components.interfaces.nsIScriptSecurityManager;
  338.  
  339. // opens the link contained in the node's "value" attribute.
  340. function openLink(node)
  341. {
  342.   var url = node.getAttribute("value");
  343.   // Security-Critical: Only links to 'safe' protocols should be functional.
  344.   // Specifically, javascript: and data: URLs must be made non-functional
  345.   // here, because they will run with full privilege.
  346.   var safeurls = /^https?:|^file:|^chrome:|^resource:|^mailbox:|^imap:|^s?news:|^nntp:|^about:|^mailto:|^ftp:|^gopher:/i;
  347.   if (safeurls.test(url)) {
  348.     var sourceURI = Components.classes["@mozilla.org/network/standard-url;1"]
  349.                             .createInstance(Components.interfaces.nsIURI);
  350.     sourceURI.spec = nodeView._content.document.location;
  351.     var destURI = Components.classes["@mozilla.org/network/standard-url;1"]
  352.                           .createInstance(Components.interfaces.nsIURI);
  353.     destURI.spec = url;
  354.  
  355.     var secMan = Components.classes["@mozilla.org/scriptsecuritymanager;1"].getService()
  356.                            .QueryInterface(nsIScriptSecurityManager);
  357.     try {
  358.       secMan.checkLoadURI(sourceURI, destURI, nsIScriptSecurityManager.STANDARD);
  359.     } catch (e) {
  360.       return;
  361.     }
  362.     nodeView._content.document.location = url;
  363.     window.close();
  364.   }
  365. }
  366.  
  367. /*
  368.  * Find <img> or <object> which uses an imagemap.
  369.  * If more then one object is found we can't determine which one
  370.  * was clicked.
  371.  *
  372.  * This code has to be changed once bug 1882 is fixed.
  373.  * Once bug 72527 is fixed this code should use the .images collection.
  374.  */
  375. function getImageForMap(map)
  376. {
  377.   var mapuri = "#" + map.getAttribute("name");
  378.   var multipleFound = false;
  379.   var img;
  380.  
  381.   var list = getHTMLElements(map.ownerDocument, "img");
  382.   for (var i=0; i < list.length; i++) {
  383.     if (list.item(i).getAttribute("usemap") == mapuri) {
  384.       if (img) {
  385.         multipleFound = true;
  386.         break;
  387.       } else {
  388.         img = list.item(i);
  389.         imgType = "img";
  390.       }
  391.     }
  392.   }
  393.  
  394.   list = getHTMLElements(map.ownerDocument, "object");
  395.   for (i = 0; i < list.length; i++) {
  396.     if (list.item(i).getAttribute("usemap") == mapuri) {
  397.       if (img) {
  398.         multipleFound = true;
  399.         break;
  400.       } else {
  401.         img = list.item(i);
  402.         imgType = "object";
  403.       }
  404.     }
  405.   }
  406.  
  407.   if (multipleFound)
  408.     img = null;
  409.  
  410.   return img;
  411. }
  412.  
  413. /*
  414.  * Takes care of XMLBase and <base>
  415.  * url is the possibly relative url.
  416.  * node is the node where the url was given (needed for XMLBase)
  417.  *
  418.  * This function is called in many places as a workaround for bug 72524
  419.  * Once bug 72522 is fixed this code should use the Node.baseURI attribute
  420.  *
  421.  * for node==null or url=="", empty string is returned
  422.  */
  423. function getAbsoluteURL(url, node)
  424. {
  425.   if (!url || !node)
  426.     return "";
  427.  
  428.   var urlArr = new Array(url);
  429.   var doc = node.ownerDocument;
  430.  
  431.   if (node.nodeType == Node.ATTRIBUTE_NODE)
  432.     node = node.ownerElement;
  433.  
  434.   while (node && node.nodeType == Node.ELEMENT_NODE) {
  435.     if (node.getAttributeNS(XMLNS, "base") != "")
  436.       urlArr.unshift(node.getAttributeNS(XMLNS, "base"));
  437.  
  438.     node = node.parentNode;
  439.   }
  440.  
  441.   // Look for a <base>.
  442.   var baseTags = getHTMLElements(doc,"base");
  443.   if (baseTags && baseTags.length) {
  444.     urlArr.unshift(baseTags[baseTags.length - 1].getAttribute("href"));
  445.   }
  446.  
  447.   // resolve everything from bottom up, starting with document location
  448.   var ioService = Components.classes["@mozilla.org/network/io-service;1"]
  449.                             .getService(Components.interfaces.nsIIOService);
  450.   var URL = ioService.newURI(doc.location.href, null, null);
  451.   for (var i=0; i<urlArr.length; i++) {
  452.     URL.spec = URL.resolve(urlArr[i]);
  453.   }
  454.  
  455.   return URL.spec;
  456. }
  457.  
  458. function getHTMLElements(node, name)
  459. {
  460.   if (htmlMode)
  461.     return node.getElementsByTagName(name);
  462.   return node.getElementsByTagNameNS(XHTMLNS, name);
  463. }
  464.  
  465. // name should be in lower case
  466. function isHTMLElement(node, name)
  467. {
  468.   if (node.nodeType != Node.ELEMENT_NODE)
  469.     return false;
  470.  
  471.   if (htmlMode)
  472.     return !name || node.localName.toLowerCase() == name;
  473.  
  474.   return (!name || node.localName == name) && node.namespaceURI == XHTMLNS;
  475. }
  476.  
  477. // This function coded according to the spec at:
  478. // http://www.bath.ac.uk/~py8ieh/internet/discussion/metadata.txt
  479. function convertLanguageCode(abbr)
  480. {
  481.   if (!abbr) return "";
  482.   var result;
  483.   var language = "";
  484.   var region;
  485.   var is_region_set = false;
  486.   var tokens = abbr.split("-");
  487.  
  488.   if (tokens[0] === "x" || tokens[0] === "i")
  489.   {
  490.     // x and i prefixes mean unofficial ones. So we upper-case the first
  491.     // word and leave the rest.
  492.     tokens.shift();
  493.  
  494.     if (tokens[0])
  495.     {
  496.       // Upper-case first letter
  497.       language = tokens[0].substr(0, 1).toUpperCase() + tokens[0].substr(1);
  498.       tokens.shift();
  499.  
  500.       if (tokens[0])
  501.       {
  502.         // Add on the rest as space-separated strings inside the brackets
  503.         region = tokens.join(" ");
  504.         is_region_set = true;
  505.       }
  506.     }
  507.   }
  508.   else
  509.   {
  510.     // Otherwise we treat the first as a lang, the second as a region
  511.     // and the rest as strings.
  512.     try
  513.     {
  514.       language = gLangBundle.getString(tokens[0]);
  515.     }
  516.     catch (e) 
  517.     {
  518.       // Language not present in lang bundle
  519.       language = tokens[0]; 
  520.     }
  521.  
  522.     tokens.shift();
  523.  
  524.     if (tokens[0])
  525.     {
  526.       try
  527.       {
  528.         // We don't add it on to the result immediately
  529.         // because we want to get the spacing right.
  530.         region = gRegionBundle.getString(tokens[0].toLowerCase());
  531.  
  532.         tokens.shift();
  533.  
  534.         if (tokens[0])
  535.         {
  536.           // Add on the rest as space-separated strings inside the brackets
  537.           region += " " + tokens.join(" ");
  538.         }
  539.       }
  540.       catch (e) 
  541.       {
  542.         // Region not present in region bundle
  543.         region = tokens.join(" ");
  544.       }
  545.  
  546.       is_region_set = true;
  547.     }
  548.   }
  549.  
  550.   if (is_region_set) {
  551.     result = gMetadataBundle.getFormattedString("languageRegionFormat",
  552.                                                 [language, region]);
  553.   } else
  554.     result = language;
  555.  
  556.   return result;
  557. }
  558.  
  559. // Returns the size of the URL in bytes; must be cached and therefore an HTTP or FTP URL
  560. function getSize(url) {
  561.   try
  562.   {
  563.     var cacheEntryDescriptor = httpCacheSession.openCacheEntry(url, Components.interfaces.nsICache.ACCESS_READ, false);
  564.     if(cacheEntryDescriptor)
  565.       return cacheEntryDescriptor.dataSize;
  566.   }
  567.   catch(ex) {}
  568.   try
  569.   {
  570.     cacheEntryDescriptor = ftpCacheSession.openCacheEntry(url, Components.interfaces.nsICache.ACCESS_READ, false);
  571.     if (cacheEntryDescriptor)
  572.       return cacheEntryDescriptor.dataSize;
  573.   }
  574.   catch(ex) {}
  575.   return -1;
  576. }
  577.  
  578. function setAlt(elem) {
  579.   var altText = document.getElementById("image-alt-text");
  580.   if (elem.hasAttribute("alt")) {
  581.     if (elem.alt != "") {
  582.       altText.value = elem.alt;
  583.       altText.setAttribute("style","font-style:inherit");
  584.     } else {
  585.       altText.value = gMetadataBundle.getString("altTextBlank");
  586.       altText.setAttribute("style","font-style:italic");
  587.     }
  588.   } else {
  589.     altText.value = gMetadataBundle.getString("altTextMissing");
  590.     altText.setAttribute("style","font-style:italic");
  591.   }
  592. }
  593.