home *** CD-ROM | disk | FTP | other *** search
/ Mac Easy 2010 May / Mac Life Ubuntu.iso / casper / filesystem.squashfs / usr / lib / firefox-3.0.14 / chrome / browser.jar / content / browser / pageinfo / pageInfo.js < prev    next >
Encoding:
JavaScript  |  2008-03-24  |  37.4 KB  |  1,134 lines

  1. //@line 42 "/build/buildd/firefox-3.0-3.0.14+build2+nobinonly/build-tree/mozilla/browser/base/content/pageinfo/pageInfo.js"
  2.  
  3. //******** define a js object to implement nsITreeView
  4. function pageInfoTreeView(columnids, copycol)
  5. {
  6.   // columnids is an array of strings indicating the names of the columns, in order
  7.   this.columnids = columnids;
  8.   this.colcount = columnids.length;
  9.  
  10.   // copycol is the index number for the column that we want to add to
  11.   // the copy-n-paste buffer when the user hits accel-c
  12.   this.copycol = copycol;
  13.   this.rows = 0;
  14.   this.tree = null;
  15.   this.data = [ ];
  16.   this.selection = null;
  17.   this.sortcol = null;
  18.   this.sortdir = 0;
  19. }
  20.  
  21. pageInfoTreeView.prototype = {
  22.   set rowCount(c) { throw "rowCount is a readonly property"; },
  23.   get rowCount() { return this.rows; },
  24.  
  25.   setTree: function(tree)
  26.   {
  27.     this.tree = tree;
  28.   },
  29.  
  30.   getCellText: function(row, column)
  31.   {
  32.     // row can be null, but js arrays are 0-indexed.
  33.     // colidx cannot be null, but can be larger than the number
  34.     // of columns in the array (when column is a string not in
  35.     // this.columnids.) In this case it's the fault of
  36.     // whoever typoed while calling this function.
  37.     return this.data[row][column.index] || "";
  38.   },
  39.  
  40.   setCellValue: function(row, column, value)
  41.   {
  42.   },
  43.  
  44.   setCellText: function(row, column, value)
  45.   {
  46.     this.data[row][column.index] = value;
  47.   },
  48.  
  49.   addRow: function(row)
  50.   {
  51.     this.rows = this.data.push(row);
  52.     this.rowCountChanged(this.rows - 1, 1);
  53.   },
  54.  
  55.   rowCountChanged: function(index, count)
  56.   {
  57.     this.tree.rowCountChanged(index, count);
  58.   },
  59.  
  60.   invalidate: function()
  61.   {
  62.     this.tree.invalidate();
  63.   },
  64.  
  65.   clear: function()
  66.   {
  67.     if (this.tree)
  68.       this.tree.rowCountChanged(0, -this.rows);
  69.     this.rows = 0;
  70.     this.data = [ ];
  71.   },
  72.  
  73.   handleCopy: function(row)
  74.   {
  75.     return (row < 0 || this.copycol < 0) ? "" : (this.data[row][this.copycol] || "");
  76.   },
  77.  
  78.   performActionOnRow: function(action, row)
  79.   {
  80.     if (action == "copy") {
  81.       var data = this.handleCopy(row)
  82.       this.tree.treeBody.parentNode.setAttribute("copybuffer", data);
  83.     }
  84.   },
  85.  
  86.   getRowProperties: function(row, prop) { },
  87.   getCellProperties: function(row, column, prop) { },
  88.   getColumnProperties: function(column, prop) { },
  89.   isContainer: function(index) { return false; },
  90.   isContainerOpen: function(index) { return false; },
  91.   isSeparator: function(index) { return false; },
  92.   isSorted: function() { },
  93.   canDrop: function(index, orientation) { return false; },
  94.   drop: function(row, orientation) { return false; },
  95.   getParentIndex: function(index) { return 0; },
  96.   hasNextSibling: function(index, after) { return false; },
  97.   getLevel: function(index) { return 0; },
  98.   getImageSrc: function(row, column) { },
  99.   getProgressMode: function(row, column) { },
  100.   getCellValue: function(row, column) { },
  101.   toggleOpenState: function(index) { },
  102.   cycleHeader: function(col) { },
  103.   selectionChanged: function() { },
  104.   cycleCell: function(row, column) { },
  105.   isEditable: function(row, column) { return false; },
  106.   isSelectable: function(row, column) { return false; },
  107.   performAction: function(action) { },
  108.   performActionOnCell: function(action, row, column) { }
  109. };
  110.  
  111. // mmm, yummy. global variables.
  112. var gWindow = null;
  113. var gDocument = null;
  114.  
  115. // column number to help using the data array
  116. const COL_IMAGE_ADDRESS = 0;
  117. const COL_IMAGE_TYPE    = 1;
  118. const COL_IMAGE_SIZE    = 2;
  119. const COL_IMAGE_ALT     = 3;
  120. const COL_IMAGE_COUNT   = 4;
  121. const COL_IMAGE_NODE    = 5;
  122. const COL_IMAGE_BG      = 6;
  123.  
  124. // column number to copy from, second argument to pageInfoTreeView's constructor
  125. const COPYCOL_NONE = -1;
  126. const COPYCOL_META_CONTENT = 1;
  127. const COPYCOL_IMAGE = COL_IMAGE_ADDRESS;
  128.  
  129. // one nsITreeView for each tree in the window
  130. var gMetaView = new pageInfoTreeView(["meta-name","meta-content"], COPYCOL_META_CONTENT);
  131. var gImageView = new pageInfoTreeView(["image-address","image-type","image-size",
  132.                                        "image-alt","image-count","image-node","image-bg"],
  133.                                       COPYCOL_IMAGE);
  134.  
  135. gImageView.getCellProperties = function(row, col, props) {
  136.   var aserv = Components.classes[ATOM_CONTRACTID]
  137.                         .getService(Components.interfaces.nsIAtomService);
  138.  
  139.   if (gImageView.data[row][COL_IMAGE_SIZE] == gStrings.unknown &&
  140.       !/^https:/.test(gImageView.data[row][COL_IMAGE_ADDRESS]))
  141.     props.AppendElement(aserv.getAtom("broken"));
  142. };
  143.  
  144. var gImageHash = { };
  145.  
  146. // localized strings (will be filled in when the document is loaded)
  147. // this isn't all of them, these are just the ones that would otherwise have been loaded inside a loop
  148. var gStrings = { };
  149. var gBundle;
  150.  
  151. const DRAGSERVICE_CONTRACTID    = "@mozilla.org/widget/dragservice;1";
  152. const TRANSFERABLE_CONTRACTID   = "@mozilla.org/widget/transferable;1";
  153. const ARRAY_CONTRACTID          = "@mozilla.org/supports-array;1";
  154. const STRING_CONTRACTID         = "@mozilla.org/supports-string;1";
  155. const PERMISSION_CONTRACTID     = "@mozilla.org/permissionmanager;1";
  156. const PREFERENCES_CONTRACTID    = "@mozilla.org/preferences-service;1";
  157. const ATOM_CONTRACTID           = "@mozilla.org/atom-service;1";
  158.  
  159. // a number of services I'll need later
  160. // the cache services
  161. const nsICacheService = Components.interfaces.nsICacheService;
  162. const ACCESS_READ     = Components.interfaces.nsICache.ACCESS_READ;
  163. const cacheService = Components.classes["@mozilla.org/network/cache-service;1"].getService(nsICacheService);
  164. var httpCacheSession = cacheService.createSession("HTTP", 0, true);
  165. httpCacheSession.doomEntriesIfExpired = false;
  166. var ftpCacheSession = cacheService.createSession("FTP", 0, true);
  167. ftpCacheSession.doomEntriesIfExpired = false;
  168.  
  169. const nsICookiePermission  = Components.interfaces.nsICookiePermission;
  170. const nsIPermissionManager = Components.interfaces.nsIPermissionManager;
  171.  
  172. const nsICertificateDialogs = Components.interfaces.nsICertificateDialogs;
  173. const CERTIFICATEDIALOGS_CONTRACTID = "@mozilla.org/nsCertificateDialogs;1"
  174.  
  175. // clipboard helper
  176. try {
  177.   const gClipboardHelper = Components.classes["@mozilla.org/widget/clipboardhelper;1"].getService(Components.interfaces.nsIClipboardHelper);
  178. }
  179. catch(e) {
  180.   // do nothing, later code will handle the error
  181. }
  182.  
  183. // Interface for image loading content
  184. const nsIImageLoadingContent = Components.interfaces.nsIImageLoadingContent;
  185.  
  186. // namespaces, don't need all of these yet...
  187. const XLinkNS  = "http://www.w3.org/1999/xlink";
  188. const XULNS    = "http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul";
  189. const XMLNS    = "http://www.w3.org/XML/1998/namespace";
  190. const XHTMLNS  = "http://www.w3.org/1999/xhtml";
  191. const XHTML2NS = "http://www.w3.org/2002/06/xhtml2"
  192.  
  193. const XHTMLNSre  = "^http\:\/\/www\.w3\.org\/1999\/xhtml$";
  194. const XHTML2NSre = "^http\:\/\/www\.w3\.org\/2002\/06\/xhtml2$";
  195. const XHTMLre = RegExp(XHTMLNSre + "|" + XHTML2NSre, "");
  196.  
  197. /* Overlays register functions here.
  198.  * These arrays are used to hold callbacks that Page Info will call at
  199.  * various stages. Use them by simply appending a function to them.
  200.  * For example, add a function to onLoadRegistry by invoking
  201.  *   "onLoadRegistry.push(XXXLoadFunc);"
  202.  * The XXXLoadFunc should be unique to the overlay module, and will be
  203.  * invoked as "XXXLoadFunc();"
  204.  */
  205.  
  206. // These functions are called to build the data displayed in the Page
  207. // Info window. The global variables gDocument and gWindow are set.
  208. var onLoadRegistry = [ ];
  209.  
  210. // These functions are called to remove old data still displayed in
  211. // the window when the document whose information is displayed
  212. // changes. For example, at this time, the list of images of the Media
  213. // tab is cleared.
  214. var onResetRegistry = [ ];
  215.  
  216. // These are called once for each subframe of the target document and
  217. // the target document itself. The frame is passed as an argument.
  218. var onProcessFrame = [ ];
  219.  
  220. // These functions are called once for each element (in all subframes, if any)
  221. // in the target document. The element is passed as an argument.
  222. var onProcessElement = [ ];
  223.  
  224. // These functions are called once when all the elements in all of the target
  225. // document (and all of it's subframes, if any) have been processed
  226. var onFinished = [ ];
  227.  
  228. // These functions are called once when the Page Info window is closed.
  229. var onUnloadRegistry = [ ];
  230.  
  231.  
  232. /* Called when PageInfo window is loaded.  Arguments are:
  233.  *  window.arguments[0] - (optional) an object consisting of
  234.  *                         - doc: (optional) document to use for source. if not provided,
  235.  *                                the calling window's document will be used
  236.  *                         - initialTab: (optional) id of the inital tab to display
  237.  */
  238. function onLoadPageInfo()
  239. {
  240.   gBundle = document.getElementById("pageinfobundle");
  241.   gStrings.unknown = gBundle.getString("unknown");
  242.   gStrings.notSet = gBundle.getString("notset");
  243.   gStrings.mediaImg = gBundle.getString("mediaImg");
  244.   gStrings.mediaBGImg = gBundle.getString("mediaBGImg");
  245.   gStrings.mediaObject = gBundle.getString("mediaObject");
  246.   gStrings.mediaEmbed = gBundle.getString("mediaEmbed");
  247.   gStrings.mediaLink = gBundle.getString("mediaLink");
  248.   gStrings.mediaInput = gBundle.getString("mediaInput");
  249.  
  250.   if ("arguments" in window && window.arguments.length >= 1 &&
  251.        window.arguments[0] && window.arguments[0].doc) {
  252.     gDocument = window.arguments[0].doc;
  253.     gWindow = gDocument.defaultView;
  254.   }
  255.   else {
  256.     if ("gBrowser" in window.opener)
  257.       gWindow = window.opener.gBrowser.contentWindow;
  258.     else
  259.       gWindow = window.opener.frames[0];
  260.     gDocument = gWindow.document;
  261.   }
  262.  
  263.   // init media view
  264.   var imageTree = document.getElementById("imagetree");
  265.   imageTree.view = gImageView;
  266.  
  267.   // build the content
  268.   loadPageInfo();
  269.  
  270.   /* Select the requested tab, if the name is specified */
  271.   var initialTab = "generalTab";
  272.   if ("arguments" in window && window.arguments.length >= 1 &&
  273.        window.arguments[0] && window.arguments[0].initialTab)
  274.     initialTab = window.arguments[0].initialTab;
  275.   var radioGroup = document.getElementById("viewGroup");
  276.   initialTab = document.getElementById(initialTab) || document.getElementById("generalTab");
  277.   radioGroup.selectedItem = initialTab;
  278.   radioGroup.selectedItem.doCommand();
  279.   radioGroup.focus();
  280. }
  281.  
  282. function loadPageInfo()
  283. {
  284.   var titleFormat = gWindow != gWindow.top ? "pageInfo.frame.title"
  285.                                            : "pageInfo.page.title";
  286.   document.title = gBundle.getFormattedString(titleFormat, [gDocument.location]);
  287.  
  288.   document.getElementById("main-window").setAttribute("relatedUrl", gDocument.location);
  289.  
  290.   // do the easy stuff first
  291.   makeGeneralTab();
  292.  
  293.   // and then the hard stuff
  294.   makeTabs(gDocument, gWindow);
  295.  
  296.   initFeedTab();
  297.   onLoadPermission();
  298.  
  299.   /* Call registered overlay init functions */
  300.   onLoadRegistry.forEach(function(func) { func(); });
  301. }
  302.  
  303. function resetPageInfo()
  304. {
  305.   /* Reset Meta tags part */
  306.   gMetaView.clear();
  307.  
  308.   /* Reset Media tab */
  309.   var mediaTab = document.getElementById("mediaTab");
  310.   if (!mediaTab.hidden) {
  311.     var os = Components.classes["@mozilla.org/observer-service;1"]
  312.                        .getService(Components.interfaces.nsIObserverService);
  313.     os.removeObserver(imagePermissionObserver, "perm-changed");
  314.     mediaTab.hidden = true;
  315.   }
  316.   gImageView.clear();
  317.   gImageHash = {};
  318.  
  319.   /* Reset Feeds Tab */
  320.   var feedListbox = document.getElementById("feedListbox");
  321.   while (feedListbox.firstChild)
  322.     feedListbox.removeChild(feedListbox.firstChild);
  323.  
  324.   /* Call registered overlay reset functions */
  325.   onResetRegistry.forEach(function(func) { func(); });
  326.  
  327.   /* And let's rebuild the data */
  328.   loadPageInfo();
  329. }
  330.  
  331. function onUnloadPageInfo()
  332. {
  333.   if (!document.getElementById("mediaTab").hidden) {
  334.     var os = Components.classes["@mozilla.org/observer-service;1"]
  335.                        .getService(Components.interfaces.nsIObserverService);
  336.     os.removeObserver(imagePermissionObserver, "perm-changed");
  337.   }
  338.  
  339.   /* Call registered overlay unload functions */
  340.   onUnloadRegistry.forEach(function(func) { func(); });
  341. }
  342.  
  343. function doHelpButton()
  344. {
  345.   const helpTopics = {
  346.     "generalPanel":  "pageinfo_general",
  347.     "mediaPanel":    "pageinfo_media",
  348.     "feedPanel":     "pageinfo_feed",
  349.     "permPanel":     "pageinfo_permissions",
  350.     "securityPanel": "pageinfo_security"
  351.   };
  352.  
  353.   var deck  = document.getElementById("mainDeck");
  354.   var helpdoc = helpTopics[deck.selectedPanel.id] || "pageinfo_general";
  355.   openHelpLink(helpdoc);
  356. }
  357.  
  358. function showTab(id)
  359. {
  360.   var deck  = document.getElementById("mainDeck");
  361.   var pagel = document.getElementById(id + "Panel");
  362.   deck.selectedPanel = pagel;
  363. }
  364.  
  365. function onClickMore()
  366. {
  367.   var radioGrp = document.getElementById("viewGroup");
  368.   var radioElt = document.getElementById("securityTab");
  369.   radioGrp.selectedItem = radioElt;
  370.   showTab('security');
  371. }
  372.  
  373. function toggleGroupbox(id)
  374. {
  375.   var elt = document.getElementById(id);
  376.   if (elt.hasAttribute("closed")) {
  377.     elt.removeAttribute("closed");
  378.     if (elt.flexWhenOpened)
  379.       elt.flex = elt.flexWhenOpened;
  380.   }
  381.   else {
  382.     elt.setAttribute("closed", "true");
  383.     if (elt.flex) {
  384.       elt.flexWhenOpened = elt.flex;
  385.       elt.flex = 0;
  386.     }
  387.   }
  388. }
  389.  
  390. function makeGeneralTab()
  391. {
  392.   var title = (gDocument.title) ? gBundle.getFormattedString("pageTitle", [gDocument.title]) : gBundle.getString("noPageTitle");
  393.   document.getElementById("titletext").value = title;
  394.  
  395.   var url = gDocument.location.toString();
  396.   setItemValue("urltext", url);
  397.  
  398.   var referrer = ("referrer" in gDocument && gDocument.referrer);
  399.   setItemValue("refertext", referrer);
  400.  
  401.   var mode = ("compatMode" in gDocument && gDocument.compatMode == "BackCompat") ? "generalQuirksMode" : "generalStrictMode";
  402.   document.getElementById("modetext").value = gBundle.getString(mode);
  403.  
  404.   // find out the mime type
  405.   var mimeType = gDocument.contentType;
  406.   setItemValue("typetext", mimeType);
  407.  
  408.   // get the document characterset
  409.   var encoding = gDocument.characterSet;
  410.   document.getElementById("encodingtext").value = encoding;
  411.  
  412.   // get the meta tags
  413.   var metaNodes = gDocument.getElementsByTagName("meta");
  414.   var length = metaNodes.length;
  415.  
  416.   var metaGroup = document.getElementById("metaTags");
  417.   if (!length)
  418.     metaGroup.collapsed = true;
  419.   else {
  420.     var metaTagsCaption = document.getElementById("metaTagsCaption");
  421.     if (length == 1)
  422.       metaTagsCaption.label = gBundle.getString("generalMetaTag");
  423.     else
  424.       metaTagsCaption.label = gBundle.getFormattedString("generalMetaTags", [length]);
  425.     var metaTree = document.getElementById("metatree");
  426.     metaTree.treeBoxObject.view = gMetaView;
  427.  
  428.     for (var i = 0; i < length; i++)
  429.       gMetaView.addRow([metaNodes[i].name || metaNodes[i].httpEquiv, metaNodes[i].content]);
  430.  
  431.     metaGroup.collapsed = false;
  432.   }
  433.  
  434.   // get the date of last modification
  435.   var modifiedText = formatDate(gDocument.lastModified, gStrings.notSet);
  436.   document.getElementById("modifiedtext").value = modifiedText;
  437.  
  438.   // get cache info
  439.   var cacheKey = url.replace(/#.*$/, "");
  440.   try {
  441.     var cacheEntryDescriptor = httpCacheSession.openCacheEntry(cacheKey, ACCESS_READ, false);
  442.   }
  443.   catch(ex) {
  444.     try {
  445.       cacheEntryDescriptor = ftpCacheSession.openCacheEntry(cacheKey, ACCESS_READ, false);
  446.     }
  447.     catch(ex2) { }
  448.   }
  449.  
  450.   var sizeText;
  451.   if (cacheEntryDescriptor) {
  452.     var pageSize = cacheEntryDescriptor.dataSize;
  453.     var kbSize = formatNumber(Math.round(pageSize / 1024 * 100) / 100);
  454.     sizeText = gBundle.getFormattedString("generalSize", [kbSize, formatNumber(pageSize)]);
  455.   }
  456.   setItemValue("sizetext", sizeText);
  457.  
  458.   securityOnLoad();
  459. }
  460.  
  461. //******** Generic Build-a-tab
  462. // Assumes the views are empty. Only called once to build the tabs, and
  463. // does so by farming the task off to another thread via setTimeout().
  464. // The actual work is done with a TreeWalker that calls doGrab() once for
  465. // each element node in the document.
  466.  
  467. var gFrameList = [ ];
  468.  
  469. function makeTabs(aDocument, aWindow)
  470. {
  471.   goThroughFrames(aDocument, aWindow);
  472.   processFrames();
  473. }
  474.  
  475. function goThroughFrames(aDocument, aWindow)
  476. {
  477.   gFrameList.push(aDocument);
  478.   if (aWindow && aWindow.frames.length > 0) {
  479.     var num = aWindow.frames.length;
  480.     for (var i = 0; i < num; i++)
  481.       goThroughFrames(aWindow.frames[i].document, aWindow.frames[i]);  // recurse through the frames
  482.   }
  483. }
  484.  
  485. function processFrames()
  486. {
  487.   if (gFrameList.length) {
  488.     var doc = gFrameList[0];
  489.     onProcessFrame.forEach(function(func) { func(doc); });
  490.     var iterator = doc.createTreeWalker(doc, NodeFilter.SHOW_ELEMENT, grabAll, true);
  491.     gFrameList.shift();
  492.     setTimeout(doGrab, 16, iterator);
  493.   }
  494.   else
  495.     onFinished.forEach(function(func) { func(); });
  496. }
  497.  
  498. function doGrab(iterator)
  499. {
  500.   for (var i = 0; i < 50; ++i)
  501.     if (!iterator.nextNode()) {
  502.       processFrames();
  503.       return;
  504.     }
  505.   setTimeout(doGrab, 16, iterator);
  506. }
  507.  
  508. function ensureSelection(view)
  509. {
  510.   // only select something if nothing is currently selected
  511.   // and if there's anything to select
  512.   if (view.selection.count == 0 && view.rowCount)
  513.     view.selection.select(0);
  514. }
  515.  
  516. function addImage(url, type, alt, elem, isBg)
  517. {
  518.   if (!url)
  519.     return;
  520.   if (!gImageHash.hasOwnProperty(url))
  521.     gImageHash[url] = { };
  522.   if (!gImageHash[url].hasOwnProperty(type))
  523.     gImageHash[url][type] = { };
  524.   if (!gImageHash[url][type].hasOwnProperty(alt)) {
  525.     gImageHash[url][type][alt] = gImageView.data.length;
  526.     try {
  527.       // open for READ, in non-blocking mode
  528.       var cacheEntryDescriptor = httpCacheSession.openCacheEntry(url, ACCESS_READ, false);
  529.     }
  530.     catch(ex) {
  531.       try {
  532.         // open for READ, in non-blocking mode
  533.         cacheEntryDescriptor = ftpCacheSession.openCacheEntry(url, ACCESS_READ, false);
  534.       }
  535.       catch(ex2) { }
  536.     }
  537.  
  538.     var sizeText;
  539.     if (cacheEntryDescriptor) {
  540.       var pageSize = cacheEntryDescriptor.dataSize;
  541.       var kbSize = formatNumber(Math.round(pageSize / 1024 * 100) / 100);
  542.       sizeText = gBundle.getFormattedString("mediaFileSize", [kbSize]);
  543.     }
  544.     else
  545.       sizeText = gStrings.unknown;
  546.     gImageView.addRow([url, type, sizeText, alt, 1, elem, isBg]);
  547.     if (gImageView.data.length == 1) {
  548.       document.getElementById("mediaTab").hidden = false;
  549.       var os = Components.classes["@mozilla.org/observer-service;1"]
  550.                          .getService(Components.interfaces.nsIObserverService);
  551.       os.addObserver(imagePermissionObserver, "perm-changed", false);
  552.     }
  553.   }
  554.   else {
  555.     var i = gImageHash[url][type][alt];
  556.     gImageView.data[i][COL_IMAGE_COUNT]++;
  557.   }
  558. }
  559.  
  560. function grabAll(elem)
  561. {
  562.   // check for background images, any node may have one
  563.   var ComputedStyle = elem.ownerDocument.defaultView.getComputedStyle(elem, "");
  564.   var url = ComputedStyle && ComputedStyle.getPropertyCSSValue("background-image");
  565.   if (url && url.primitiveType == CSSPrimitiveValue.CSS_URI)
  566.     addImage(url.getStringValue(), gStrings.mediaBGImg, gStrings.notSet, elem, true);
  567.  
  568.   // one swi^H^H^Hif-else to rule them all
  569.   if (elem instanceof HTMLImageElement)
  570.     addImage(elem.src, gStrings.mediaImg,
  571.              (elem.hasAttribute("alt")) ? elem.alt : gStrings.notSet, elem, false);
  572. //@line 613 "/build/buildd/firefox-3.0-3.0.14+build2+nobinonly/build-tree/mozilla/browser/base/content/pageinfo/pageInfo.js"
  573.   else if (elem instanceof SVGImageElement) {
  574.     try {
  575.       // Note: makeURLAbsolute will throw if either the baseURI is not a valid URI
  576.       //       or the URI formed from the baseURI and the URL is not a valid URI
  577.       var href = makeURLAbsolute(elem.baseURI, elem.href.baseVal);
  578.       addImage(href, gStrings.mediaImg, "", elem, false);
  579.     } catch (e) { }
  580.   }
  581. //@line 622 "/build/buildd/firefox-3.0-3.0.14+build2+nobinonly/build-tree/mozilla/browser/base/content/pageinfo/pageInfo.js"
  582.   else if (elem instanceof HTMLLinkElement) {
  583.     if (elem.rel && /\bicon\b/i.test(elem.rel))
  584.       addImage(elem.href, gStrings.mediaLink, "", elem, false);
  585.   }
  586.   else if (elem instanceof HTMLInputElement || elem instanceof HTMLButtonElement) {
  587.     if (elem.type.toLowerCase() == "image")
  588.       addImage(elem.src, gStrings.mediaInput,
  589.                (elem.hasAttribute("alt")) ? elem.alt : gStrings.notSet, elem, false);
  590.   }
  591.   else if (elem instanceof HTMLObjectElement)
  592.     addImage(elem.data, gStrings.mediaObject, getValueText(elem), elem, false);
  593.   else if (elem instanceof HTMLEmbedElement)
  594.     addImage(elem.src, gStrings.mediaEmbed, "", elem, false);
  595.  
  596.   onProcessElement.forEach(function(func) { func(elem); });
  597.  
  598.   return NodeFilter.FILTER_ACCEPT;
  599. }
  600.  
  601. //******** Link Stuff
  602. function openURL(target)
  603. {
  604.   var url = target.parentNode.childNodes[2].value;
  605.   window.open(url, "_blank", "chrome");
  606. }
  607.  
  608. function onBeginLinkDrag(event,urlField,descField)
  609. {
  610.   if (event.originalTarget.localName != "treechildren")
  611.     return;
  612.  
  613.   var tree = event.target;
  614.   if (!("treeBoxObject" in tree))
  615.     tree = tree.parentNode;
  616.  
  617.   var row = tree.treeBoxObject.getRowAt(event.clientX, event.clientY);
  618.   if (row == -1)
  619.     return;
  620.  
  621.   // Getting drag-system needed services
  622.   var dragService = Components.classes[DRAGSERVICE_CONTRACTID].getService()
  623.                               .QueryInterface(Components.interfaces.nsIDragService);
  624.   var transArray = Components.classes[ARRAY_CONTRACTID]
  625.                              .createInstance(Components.interfaces.nsISupportsArray);
  626.   if (!transArray)
  627.     return;
  628.   var trans = Components.classes[TRANSFERABLE_CONTRACTID]
  629.                         .createInstance(Components.interfaces.nsITransferable);
  630.   if (!trans)
  631.     return;
  632.  
  633.   // Adding URL flavor
  634.   trans.addDataFlavor("text/x-moz-url");
  635.   var col = tree.columns[urlField];
  636.   var url = tree.view.getCellText(row, col);
  637.   col = tree.columns[descField];
  638.   var desc = tree.view.getCellText(row, col);
  639.   var stringURL = Components.classes[STRING_CONTRACTID]
  640.                             .createInstance(Components.interfaces.nsISupportsString);
  641.   stringURL.data = url + "\n" + desc;
  642.   trans.setTransferData("text/x-moz-url", stringURL, stringURL.data.length * 2 );
  643.   transArray.AppendElement(trans.QueryInterface(Components.interfaces.nsISupports));
  644.  
  645.   dragService.invokeDragSession(event.target, transArray, null, dragService.DRAGDROP_ACTION_NONE);
  646. }
  647.  
  648. //******** Image Stuff
  649. function getSelectedImage(tree)
  650. {
  651.   if (!gImageView.rowCount)
  652.     return null;
  653.  
  654.   // Only works if only one item is selected
  655.   var clickedRow = tree.currentIndex;
  656.   // image-node
  657.   return gImageView.data[clickedRow][COL_IMAGE_NODE];
  658. }
  659.  
  660. function selectSaveFolder()
  661. {
  662.   const nsILocalFile = Components.interfaces.nsILocalFile;
  663.   const nsIFilePicker = Components.interfaces.nsIFilePicker;
  664.   var fp = Components.classes["@mozilla.org/filepicker;1"]
  665.                      .createInstance(nsIFilePicker);
  666.  
  667.   var titleText = gBundle.getString("mediaSelectFolder");
  668.   fp.init(window, titleText, nsIFilePicker.modeGetFolder);
  669.   try {
  670.     var prefs = Components.classes[PREFERENCES_CONTRACTID]
  671.                           .getService(Components.interfaces.nsIPrefBranch2);
  672.  
  673.     var initialDir = prefs.getComplexValue("browser.download.dir", nsILocalFile);
  674.     if (initialDir)
  675.       fp.displayDirectory = initialDir;
  676.   }
  677.   catch (ex) { }
  678.  
  679.   fp.appendFilters(nsIFilePicker.filterAll);
  680.   var ret = fp.show();
  681.  
  682.   if (ret == nsIFilePicker.returnOK)
  683.     return fp.file.QueryInterface(nsILocalFile);
  684.   return null;
  685. }
  686.  
  687. function saveMedia()
  688. {
  689.   var tree = document.getElementById("imagetree");
  690.   var count = tree.view.selection.count;
  691.   if (count == 1) {
  692.     var item = getSelectedImage(tree);
  693.     var url = gImageView.data[tree.currentIndex][COL_IMAGE_ADDRESS];
  694.  
  695.     if (url)
  696.       saveURL(url, null, "SaveImageTitle", false, false, makeURI(item.baseURI));
  697.   }
  698.   else {
  699.     var odir  = selectSaveFolder();
  700.     var start = { };
  701.     var end   = { };
  702.     var numRanges = tree.view.selection.getRangeCount();
  703.  
  704.     var rowArray = [ ];
  705.     for (var t = 0; t < numRanges; t++) {
  706.       tree.view.selection.getRangeAt(t, start, end);
  707.       for (var v = start.value; v <= end.value; v++)
  708.         rowArray.push(v);
  709.     }
  710.  
  711.     var saveAnImage = function(aURIString, aChosenData, aBaseURI) {
  712.       internalSave(aURIString, null, null, null, null, false, "SaveImageTitle",
  713.                    aChosenData, aBaseURI);
  714.     }
  715.  
  716.     for (var i = 0; i < rowArray.length; i++) {
  717.       var v = rowArray[i];
  718.       var dir = odir.clone();
  719.       var item = gImageView.data[v][COL_IMAGE_NODE];
  720.       var uriString = gImageView.data[v][COL_IMAGE_ADDRESS];
  721.       var uri = makeURI(uriString);
  722.  
  723.       try {
  724.         uri.QueryInterface(Components.interfaces.nsIURL);
  725.         dir.append(decodeURIComponent(uri.fileName));
  726.       }
  727.       catch(ex) { /* data: uris */ }
  728.  
  729.       if (i == 0)
  730.         saveAnImage(uriString, new AutoChosen(dir, uri), makeURI(item.baseURI));
  731.       else {
  732.         // This delay is a hack which prevents the download manager
  733.         // from opening many times. See bug 377339.
  734.         setTimeout(saveAnImage, 200, uriString, new AutoChosen(dir, uri),
  735.                    makeURI(item.baseURI));
  736.       }
  737.     }
  738.   }
  739. }
  740.  
  741. function onBlockImage()
  742. {
  743.   var permissionManager = Components.classes[PERMISSION_CONTRACTID]
  744.                                     .getService(nsIPermissionManager);
  745.  
  746.   var checkbox = document.getElementById("blockImage");
  747.   var uri = makeURI(document.getElementById("imageurltext").value);
  748.   if (checkbox.checked)
  749.     permissionManager.add(uri, "image", nsIPermissionManager.DENY_ACTION);
  750.   else
  751.     permissionManager.remove(uri.host, "image");
  752. }
  753.  
  754. function onImageSelect()
  755. {
  756.   var previewBox   = document.getElementById("mediaPreviewBox");
  757.   var mediaSaveBox = document.getElementById("mediaSaveBox");
  758.   var splitter     = document.getElementById("mediaSplitter");
  759.   var tree = document.getElementById("imagetree");
  760.   var count = tree.view.selection.count;
  761.   if (count == 0) {
  762.     previewBox.collapsed   = true;
  763.     mediaSaveBox.collapsed = true;
  764.     splitter.collapsed     = true;
  765.     tree.flex = 1;
  766.   }
  767.   else if (count > 1) {
  768.     splitter.collapsed     = true;
  769.     previewBox.collapsed   = true;
  770.     mediaSaveBox.collapsed = false;
  771.     tree.flex = 1;
  772.   }
  773.   else {
  774.     mediaSaveBox.collapsed = true;
  775.     splitter.collapsed     = false;
  776.     previewBox.collapsed   = false;
  777.     tree.flex = 0;
  778.     makePreview(tree.view.selection.currentIndex);
  779.   }
  780. }
  781.  
  782. function makePreview(row)
  783. {
  784.   var imageTree = document.getElementById("imagetree");
  785.   var item = getSelectedImage(imageTree);
  786.   var url = gImageView.data[row][COL_IMAGE_ADDRESS];
  787.   var isBG = gImageView.data[row][COL_IMAGE_BG];
  788.  
  789.   setItemValue("imageurltext", url);
  790.  
  791.   var imageText;
  792.   if (!isBG &&
  793. //@line 834 "/build/buildd/firefox-3.0-3.0.14+build2+nobinonly/build-tree/mozilla/browser/base/content/pageinfo/pageInfo.js"
  794.       !(item instanceof SVGImageElement) &&
  795. //@line 836 "/build/buildd/firefox-3.0-3.0.14+build2+nobinonly/build-tree/mozilla/browser/base/content/pageinfo/pageInfo.js"
  796.       !(gDocument instanceof ImageDocument)) {
  797.     imageText = item.title || item.alt;
  798.  
  799.     if (!imageText && !(item instanceof HTMLImageElement))
  800.       imageText = getValueText(item);
  801.   }
  802.   setItemValue("imagetext", imageText);
  803.  
  804.   setItemValue("imagelongdesctext", item.longDesc);
  805.  
  806.   // get cache info
  807.   var cacheKey = url.replace(/#.*$/, "");
  808.   try {
  809.     // open for READ, in non-blocking mode
  810.     var cacheEntryDescriptor = httpCacheSession.openCacheEntry(cacheKey, ACCESS_READ, false);
  811.   }
  812.   catch(ex) {
  813.     try {
  814.       // open for READ, in non-blocking mode
  815.       cacheEntryDescriptor = ftpCacheSession.openCacheEntry(cacheKey, ACCESS_READ, false);
  816.     }
  817.     catch(ex2) { }
  818.   }
  819.  
  820.   // find out the file size
  821.   var sizeText;
  822.   if (cacheEntryDescriptor) {
  823.     var imageSize = cacheEntryDescriptor.dataSize;
  824.     var kbSize = Math.round(imageSize / 1024 * 100) / 100;
  825.     sizeText = gBundle.getFormattedString("generalSize",
  826.                                           [formatNumber(kbSize), formatNumber(imageSize)]);
  827.   }
  828.   else
  829.     sizeText = gBundle.getString("mediaUnknownNotCached");
  830.   setItemValue("imagesizetext", sizeText);
  831.  
  832.   var mimeType;
  833.   var numFrames = 1;
  834.   if (item instanceof HTMLObjectElement ||
  835.       item instanceof HTMLEmbedElement ||
  836.       item instanceof HTMLLinkElement)
  837.     mimeType = item.type;
  838.  
  839.   if (!mimeType && item instanceof nsIImageLoadingContent) {
  840.     var imageRequest = item.getRequest(nsIImageLoadingContent.CURRENT_REQUEST);
  841.     if (imageRequest) {
  842.       mimeType = imageRequest.mimeType;
  843.       var image = imageRequest.image;
  844.       if (image)
  845.         numFrames = image.numFrames;
  846.     }
  847.   }
  848.   if (!mimeType)
  849.     mimeType = getContentTypeFromHeaders(cacheEntryDescriptor);
  850.  
  851.   if (mimeType) {
  852.     // We found the type, try to display it nicely
  853.     var imageMimeType = /^image\/(.*)/.exec(mimeType);
  854.     if (imageMimeType) {
  855.       mimeType = imageMimeType[1].toUpperCase();
  856.       if (numFrames > 1)
  857.         mimeType = gBundle.getFormattedString("mediaAnimatedImageType",
  858.                                               [mimeType, numFrames]);
  859.       else
  860.         mimeType = gBundle.getFormattedString("mediaImageType", [mimeType]);
  861.     }
  862.   }
  863.   else {
  864.     // We couldn't find the type, fall back to the value in the treeview
  865.     mimeType = gImageView.data[row][COL_IMAGE_TYPE];
  866.   }
  867.   setItemValue("imagetypetext", mimeType);
  868.  
  869.   var imageContainer = document.getElementById("theimagecontainer");
  870.   var oldImage = document.getElementById("thepreviewimage");
  871.  
  872.   const regex = /^(https?|ftp|file|gopher|about|chrome|resource):/;
  873.   var isProtocolAllowed = regex.test(url);
  874.   if (/^data:/.test(url) && /^image\//.test(mimeType))
  875.     isProtocolAllowed = true;
  876.  
  877.   var newImage = new Image();
  878.   newImage.setAttribute("id", "thepreviewimage");
  879.   var physWidth = 0, physHeight = 0;
  880.   var width = 0, height = 0;
  881.  
  882.   if ((item instanceof HTMLLinkElement || item instanceof HTMLInputElement ||
  883.        item instanceof HTMLImageElement ||
  884. //@line 925 "/build/buildd/firefox-3.0-3.0.14+build2+nobinonly/build-tree/mozilla/browser/base/content/pageinfo/pageInfo.js"
  885.        item instanceof SVGImageElement ||
  886. //@line 927 "/build/buildd/firefox-3.0-3.0.14+build2+nobinonly/build-tree/mozilla/browser/base/content/pageinfo/pageInfo.js"
  887.       (item instanceof HTMLObjectElement && /^image\//.test(mimeType)) || isBG) && isProtocolAllowed) {
  888.     newImage.setAttribute("src", url);
  889.     physWidth = newImage.width || 0;
  890.     physHeight = newImage.height || 0;
  891.  
  892.     // "width" and "height" attributes must be set to newImage,
  893.     // even if there is no "width" or "height attribute in item;
  894.     // otherwise, the preview image cannot be displayed correctly.
  895.     if (!isBG) {
  896.       newImage.width = ("width" in item && item.width) || newImage.naturalWidth;
  897.       newImage.height = ("height" in item && item.height) || newImage.naturalHeight;
  898.     }
  899.     else {
  900.       // the Width and Height of an HTML tag should not be used for its background image
  901.       // (for example, "table" can have "width" or "height" attributes)
  902.       newImage.width = newImage.naturalWidth;
  903.       newImage.height = newImage.naturalHeight;
  904.     }
  905.  
  906. //@line 947 "/build/buildd/firefox-3.0-3.0.14+build2+nobinonly/build-tree/mozilla/browser/base/content/pageinfo/pageInfo.js"
  907.     if (item instanceof SVGImageElement) {
  908.       newImage.width = item.width.baseVal.value;
  909.       newImage.height = item.height.baseVal.value;
  910.     }
  911. //@line 952 "/build/buildd/firefox-3.0-3.0.14+build2+nobinonly/build-tree/mozilla/browser/base/content/pageinfo/pageInfo.js"
  912.  
  913.     width = newImage.width;
  914.     height = newImage.height;
  915.  
  916.     document.getElementById("theimagecontainer").collapsed = false
  917.     document.getElementById("brokenimagecontainer").collapsed = true;
  918.   }
  919.   else {
  920.     // fallback image for protocols not allowed (e.g., data: or javascript:)
  921.     // or elements not [yet] handled (e.g., object, embed).
  922.     document.getElementById("brokenimagecontainer").collapsed = false;
  923.     document.getElementById("theimagecontainer").collapsed = true;
  924.   }
  925.  
  926.   var imageSize = "";
  927.   if (url) {
  928.     if (width != physWidth || height != physHeight) {
  929.       imageSize = gBundle.getFormattedString("mediaDimensionsScaled",
  930.                                              [formatNumber(physWidth),
  931.                                               formatNumber(physHeight),
  932.                                               formatNumber(width),
  933.                                               formatNumber(height)]);
  934.     }
  935.     else {
  936.       imageSize = gBundle.getFormattedString("mediaDimensions",
  937.                                              [formatNumber(width),
  938.                                               formatNumber(height)]);
  939.     }
  940.   }
  941.   setItemValue("imagedimensiontext", imageSize);
  942.  
  943.   makeBlockImage(url);
  944.  
  945.   imageContainer.removeChild(oldImage);
  946.   imageContainer.appendChild(newImage);
  947. }
  948.  
  949. function makeBlockImage(url)
  950. {
  951.   var permissionManager = Components.classes[PERMISSION_CONTRACTID]
  952.                                     .getService(nsIPermissionManager);
  953.   var prefs = Components.classes[PREFERENCES_CONTRACTID]
  954.                         .getService(Components.interfaces.nsIPrefBranch2);
  955.  
  956.   var checkbox = document.getElementById("blockImage");
  957.   var imagePref = prefs.getIntPref("permissions.default.image");
  958.   if (!(/^https?:/.test(url)) || imagePref == 2)
  959.     // We can't block the images from this host because either is is not
  960.     // for http(s) or we don't load images at all
  961.     checkbox.hidden = true;
  962.   else {
  963.     var uri = makeURI(url);
  964.     if (uri.host) {
  965.       checkbox.hidden = false;
  966.       checkbox.label = gBundle.getFormattedString("mediaBlockImage", [uri.host]);
  967.       var perm = permissionManager.testPermission(uri, "image");
  968.       checkbox.checked = perm == nsIPermissionManager.DENY_ACTION;
  969.     }
  970.     else
  971.       checkbox.hidden = true;
  972.   }
  973. }
  974.  
  975. var imagePermissionObserver = {
  976.   observe: function (aSubject, aTopic, aData)
  977.   {
  978.     if (document.getElementById("mediaPreviewBox").collapsed)
  979.       return;
  980.     if (aTopic == "perm-changed") {
  981.       var permission = aSubject.QueryInterface(Components.interfaces.nsIPermission);
  982.       if (permission.type == "image") {
  983.         var imageTree = document.getElementById("imagetree");
  984.         var row = imageTree.currentIndex;
  985.         var item = gImageView.data[row][COL_IMAGE_NODE];
  986.         var url = gImageView.data[row][COL_IMAGE_ADDRESS];
  987.         if (makeURI(url).host == permission.host)
  988.           makeBlockImage(url);
  989.       }
  990.     }
  991.   }
  992. }
  993.  
  994. function getContentTypeFromHeaders(cacheEntryDescriptor)
  995. {
  996.   if (!cacheEntryDescriptor)
  997.     return null;
  998.  
  999.   return (/^Content-Type:\s*(.*?)\s*(?:\;|$)/mi
  1000.           .exec(cacheEntryDescriptor.getMetaDataElement("response-head")))[1];
  1001. }
  1002.  
  1003. //******** Other Misc Stuff
  1004. // Modified from the Links Panel v2.3, http://segment7.net/mozilla/links/links.html
  1005. // parse a node to extract the contents of the node
  1006. function getValueText(node)
  1007. {
  1008.   var valueText = "";
  1009.  
  1010.   // form input elements don't generally contain information that is useful to our callers, so return nothing
  1011.   if (node instanceof HTMLInputElement ||
  1012.       node instanceof HTMLSelectElement ||
  1013.       node instanceof HTMLTextAreaElement)
  1014.     return valueText;
  1015.  
  1016.   // otherwise recurse for each child
  1017.   var length = node.childNodes.length;
  1018.   for (var i = 0; i < length; i++) {
  1019.     var childNode = node.childNodes[i];
  1020.     var nodeType = childNode.nodeType;
  1021.  
  1022.     // text nodes are where the goods are
  1023.     if (nodeType == Node.TEXT_NODE)
  1024.       valueText += " " + childNode.nodeValue;
  1025.     // and elements can have more text inside them
  1026.     else if (nodeType == Node.ELEMENT_NODE) {
  1027.       // images are special, we want to capture the alt text as if the image weren't there
  1028.       if (childNode instanceof HTMLImageElement)
  1029.         valueText += " " + getAltText(childNode);
  1030.       else
  1031.         valueText += " " + getValueText(childNode);
  1032.     }
  1033.   }
  1034.  
  1035.   return stripWS(valueText);
  1036. }
  1037.  
  1038. // Copied from the Links Panel v2.3, http://segment7.net/mozilla/links/links.html
  1039. // traverse the tree in search of an img or area element and grab its alt tag
  1040. function getAltText(node)
  1041. {
  1042.   var altText = "";
  1043.  
  1044.   if (node.alt)
  1045.     return node.alt;
  1046.   var length = node.childNodes.length;
  1047.   for (var i = 0; i < length; i++)
  1048.     if ((altText = getAltText(node.childNodes[i]) != undefined))  // stupid js warning...
  1049.       return altText;
  1050.   return "";
  1051. }
  1052.  
  1053. // Copied from the Links Panel v2.3, http://segment7.net/mozilla/links/links.html
  1054. // strip leading and trailing whitespace, and replace multiple consecutive whitespace characters with a single space
  1055. function stripWS(text)
  1056. {
  1057.   var middleRE = /\s+/g;
  1058.   var endRE = /(^\s+)|(\s+$)/g;
  1059.  
  1060.   text = text.replace(middleRE, " ");
  1061.   return text.replace(endRE, "");
  1062. }
  1063.  
  1064. function setItemValue(id, value)
  1065. {
  1066.   var item = document.getElementById(id);
  1067.   if (value) {
  1068.     item.parentNode.collapsed = false;
  1069.     item.value = value;
  1070.   }
  1071.   else
  1072.     item.parentNode.collapsed = true;
  1073. }
  1074.  
  1075. function formatNumber(number)
  1076. {
  1077.   return (+number).toLocaleString();  // coerce number to a numeric value before calling toLocaleString()
  1078. }
  1079.  
  1080. function formatDate(datestr, unknown)
  1081. {
  1082.   // scriptable date formater, for pretty printing dates
  1083.   var dateService = Components.classes["@mozilla.org/intl/scriptabledateformat;1"]
  1084.                               .getService(Components.interfaces.nsIScriptableDateFormat);
  1085.  
  1086.   var date = new Date(datestr);
  1087.   if (!date.valueOf())
  1088.     return unknown;
  1089.  
  1090.   return dateService.FormatDateTime("", dateService.dateFormatLong,
  1091.                                     dateService.timeFormatSeconds,
  1092.                                     date.getFullYear(), date.getMonth()+1, date.getDate(),
  1093.                                     date.getHours(), date.getMinutes(), date.getSeconds());
  1094. }
  1095.  
  1096. function doCopy()
  1097. {
  1098.   if (!gClipboardHelper)
  1099.     return;
  1100.  
  1101.   var elem = document.commandDispatcher.focusedElement;
  1102.  
  1103.   if (elem && "treeBoxObject" in elem) {
  1104.     var view = elem.view;
  1105.     var selection = view.selection;
  1106.     var text = [], tmp = '';
  1107.     var min = {}, max = {};
  1108.  
  1109.     var count = selection.getRangeCount();
  1110.  
  1111.     for (var i = 0; i < count; i++) {
  1112.       selection.getRangeAt(i, min, max);
  1113.  
  1114.       for (var row = min.value; row <= max.value; row++) {
  1115.         view.performActionOnRow("copy", row);
  1116.  
  1117.         tmp = elem.getAttribute("copybuffer");
  1118.         if (tmp)
  1119.           text.push(tmp);
  1120.         elem.removeAttribute("copybuffer");
  1121.       }
  1122.     }
  1123.     gClipboardHelper.copyString(text.join("\n"));
  1124.   }
  1125. }
  1126.  
  1127. function doSelectAll()
  1128. {
  1129.   var elem = document.commandDispatcher.focusedElement;
  1130.  
  1131.   if (elem && "treeBoxObject" in elem)
  1132.     elem.view.selection.selectAll();
  1133. }
  1134.