home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 35 Internet / 35-Internet.zip / phoenx05.zip / phoenix / chrome / browser.jar / content / browser / pageInfo.js < prev    next >
Text File  |  2002-12-06  |  35KB  |  1,016 lines

  1. //******** define a js object to implement nsITreeView
  2. function pageInfoTreeView(columnids, copycol)
  3. {
  4.   // columnids is an array of strings indicating the names of the columns, in order
  5.   this.columnids = columnids;
  6.   this.colcount = columnids.length
  7.  
  8.   // copycol is the index number for the column that we want to add to 
  9.   // the copy-n-paste buffer when the user hits accel-c
  10.   this.copycol = copycol;
  11.   this.rows = 0;
  12.   this.tree = null;
  13.   this.data = new Array;
  14.   this.selection = null;
  15.   this.sortcol = null;
  16.   this.sortdir = 0;
  17.   this.initialized = 0; // set this to one once we fill in all the rows
  18. }
  19.  
  20. pageInfoTreeView.prototype = {
  21.   set rowCount(c) { throw "rowCount is a readonly property"; },
  22.   get rowCount() { return this.rows; },
  23.  
  24.   setTree: function(tree) 
  25.   {
  26.     this.tree = tree;
  27.   },
  28.  
  29.   getCellText: function(row, column)
  30.   {
  31.     var colidx = 0;
  32.     // loop through the list of column names to find the index to the column 
  33.     // we should be worrying about. very much a hack, but what can you do?
  34.     while(colidx < this.colcount && column != this.columnids[colidx])
  35.       colidx++;
  36.  
  37.     // row can be null, but js arrays are 0-indexed.
  38.     // colidx cannot be null, but can be larger than the number
  39.     // of columns in the array (when column is a string not in 
  40.     // this.columnids.) In this case it's the fault of
  41.     // whoever typoed while calling this function.
  42.     return this.data[row][colidx] || "";
  43.   },
  44.  
  45.   setCellText: function(row, column, value) 
  46.   {
  47.     var colidx = 0;
  48.     // loop through the list of column names to find the index 
  49.     // to the column the should be worrying about. very much a hack, but
  50.     // what can you do? 
  51.     // XXX: I think there's a better way to do this now...
  52.     while(colidx < this.colcount && column != this.columnids[colidx])
  53.       colidx++;
  54.     this.data[row][colidx] = value;
  55.   },
  56.  
  57.   addRow: function(row)
  58.   {
  59.     this.rows = this.data.push(row);
  60.   },
  61.  
  62.   addRows: function(rows)
  63.   {
  64.     var length = rows.length;
  65.     for(var i = 0; i < length; i++)
  66.       this.rows = this.data.push(rows[i]);
  67.   },
  68.  
  69.   rowCountChanged: function(index, count)
  70.   {
  71.     this.tree.rowCountChanged(index, count);
  72.   },
  73.  
  74.   invalidate: function()
  75.   {
  76.     this.tree.invalidate();
  77.   },
  78.  
  79.   clear: function()
  80.   {
  81.     this.data = new Array;
  82.     this.rows = 0;
  83.   },
  84.  
  85.   handleCopy: function(row)
  86.   {
  87.     return (row < 0 || this.copycol < 0) ? "" : (this.data[row][this.copycol] || "");
  88.   },
  89.  
  90.   performActionOnRow: function(action, row)
  91.   {
  92.     if (action == "copy")
  93.     {
  94.       var data = this.handleCopy(row)
  95.       this.tree.treeBody.parentNode.setAttribute("copybuffer", data);
  96.     }
  97.   },
  98.  
  99.   getRowProperties: function(row, column, prop) { },
  100.   getCellProperties: function(row, prop) { },
  101.   getColumnProperties: function(column, elem, prop) { },
  102.   isContainer: function(index) { return false; },
  103.   isContainerOpen: function(index) { return false; },
  104.   isSeparator: function(index) { return false; },
  105.   isSorted: function() { },
  106.   canDropOn: function(index) { return false; },
  107.   canDropBeforeAfter: function(index, before) { return false; },
  108.   drop: function(row, orientation) { return false; },
  109.   getParentIndex: function(index) { return 0; },
  110.   hasNextSibling: function(index, after) { return false; },
  111.   getLevel: function(index) { return 0; },
  112.   getImageSrc: function(row, column) { },
  113.   getProgressMode: function(row, column) { },
  114.   getCellValue: function(row, column) { },
  115.   toggleOpenState: function(index) { },
  116.   cycleHeader: function(col, elem) { },
  117.   selectionChanged: function() { },
  118.   cycleCell: function(row, column) { },
  119.   isEditable: function(row, column) { return false; },
  120.   performAction: function(action) { },
  121.   performActionOnCell: function(action, row, column) { }
  122. };
  123.  
  124. // mmm, yummy. global variables.
  125. var theWindow = null;
  126. var theDocument = null;
  127.  
  128. // column number to copy from, second argument to pageInfoTreeView's constructor
  129. const COPYCOL_NONE = -1;
  130. const COPYCOL_META_CONTENT = 1;
  131. const COPYCOL_FORM_ACTION = 2;
  132. const COPYCOL_LINK_ADDRESS = 1;
  133. const COPYCOL_IMAGE_ADDRESS = 0;
  134.  
  135. // one nsITreeView for each tree in the window
  136. var metaView = new pageInfoTreeView(["meta-name","meta-content"], COPYCOL_META_CONTENT);
  137. var formView = new pageInfoTreeView(["form-name","form-method","form-action","form-node"], COPYCOL_FORM_ACTION);
  138. var fieldView = new pageInfoTreeView(["field-label","field-field","field-type","field-value"], COPYCOL_NONE);
  139. var linkView = new pageInfoTreeView(["link-name","link-address","link-type"], COPYCOL_LINK_ADDRESS);
  140. var imageView = new pageInfoTreeView(["image-address","image-type","image-alt","image-node", "image-bg"], COPYCOL_IMAGE_ADDRESS);
  141.  
  142. // localized strings (will be filled in when the document is loaded)
  143. // this isn't all of them, these are just the ones that would otherwise have been loaded inside a loop
  144. var gStrings = {}
  145. var theBundle;
  146.  
  147. const DRAGSERVICE_CONTRACTID    = "@mozilla.org/widget/dragservice;1";
  148. const TRANSFERABLE_CONTRACTID   = "@mozilla.org/widget/transferable;1";
  149. const ARRAY_CONTRACTID          = "@mozilla.org/supports-array;1";
  150. const STRING_CONTRACTID         = "@mozilla.org/supports-string;1";
  151.  
  152. // a number of services I'll need later
  153. // the cache services
  154. const nsICacheService = Components.interfaces.nsICacheService;
  155. const cacheService = Components.classes["@mozilla.org/network/cache-service;1"].getService(nsICacheService);
  156. var httpCacheSession = cacheService.createSession("HTTP", 0, true);
  157. httpCacheSession.doomEntriesIfExpired = false;
  158. var ftpCacheSession = cacheService.createSession("FTP", 0, true);
  159. ftpCacheSession.doomEntriesIfExpired = false;
  160.  
  161. // scriptable date formater, for pretty printing dates
  162. const nsIScriptableDateFormat = Components.interfaces.nsIScriptableDateFormat;
  163. var dateService = Components.classes["@mozilla.org/intl/scriptabledateformat;1"].getService(nsIScriptableDateFormat);
  164.  
  165. // clipboard helper
  166. try
  167. {
  168.   const gClipboardHelper = Components.classes["@mozilla.org/widget/clipboardhelper;1"].getService(Components.interfaces.nsIClipboardHelper);
  169. }
  170. catch(e)
  171. {
  172.   // do nothing, later code will handle the error
  173. }
  174.  
  175. // interfaces for the different html elements
  176. const nsIAnchorElement   = Components.interfaces.nsIDOMHTMLAnchorElement
  177. const nsIImageElement    = Components.interfaces.nsIDOMHTMLImageElement
  178. const nsIAreaElement     = Components.interfaces.nsIDOMHTMLAreaElement
  179. const nsILinkElement     = Components.interfaces.nsIDOMHTMLLinkElement
  180. const nsIInputElement    = Components.interfaces.nsIDOMHTMLInputElement
  181. const nsIFormElement     = Components.interfaces.nsIDOMHTMLFormElement
  182. const nsIAppletElement   = Components.interfaces.nsIDOMHTMLAppletElement
  183. const nsIObjectElement   = Components.interfaces.nsIDOMHTMLObjectElement
  184. const nsIEmbedElement    = Components.interfaces.nsIDOMHTMLEmbedElement
  185. const nsIButtonElement   = Components.interfaces.nsIDOMHTMLButtonElement
  186. const nsISelectElement   = Components.interfaces.nsIDOMHTMLSelectElement
  187. const nsITextareaElement = Components.interfaces.nsIDOMHTMLTextAreaElement
  188.  
  189. // namespaces, don't need all of these yet...
  190. const XLinkNS  = "http://www.w3.org/1999/xlink";
  191. const XULNS    = "http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul";
  192. const XMLNS    = "http://www.w3.org/XML/1998/namespace";
  193. const XHTMLNS  = "http://www.w3.org/1999/xhtml";
  194. const XHTML2NS = "http://www.w3.org/2002/06/xhtml2"
  195.  
  196. const XHTMLNSre  = "^http\:\/\/www\.w3\.org\/1999\/xhtml$";
  197. const XHTML2NSre = "^http\:\/\/www\.w3\.org\/2002\/06\/xhtml2$";
  198. const XHTMLre = RegExp(XHTMLNSre + "|" + XHTML2NSre, "");
  199.  
  200. /* Overlays register init functions here.
  201.  *   Add functions to call by invoking "onLoadRegistry.append(XXXLoadFunc);"
  202.  *   The XXXLoadFunc should be unique to the overlay module, and will be
  203.  *   invoked as "XXXLoadFunc();"
  204.  */
  205. var onLoadRegistry = [ ];
  206.  
  207. /* Called when PageInfo window is loaded.  Arguments are:
  208.  *  window.arguments[0] - document to use for source (null=Page Info, otherwise Frame Info)
  209.  *  window.arguments[1] - tab name to display first (may be null)
  210. */
  211. function onLoadPageInfo()
  212. {
  213.   //dump("===============================================================================\n");
  214.  
  215.   theBundle = document.getElementById("pageinfobundle");
  216.   gStrings.unknown = theBundle.getString("unknown");
  217.   gStrings.notSet = theBundle.getString("notset");
  218.   gStrings.emptyString = theBundle.getString("emptystring");
  219.   gStrings.linkAnchor = theBundle.getString("linkAnchor");
  220.   gStrings.linkArea = theBundle.getString("linkArea");
  221.   gStrings.linkSubmit = theBundle.getString("linkSubmit");
  222.   gStrings.linkSubmission = theBundle.getString("linkSubmission");
  223.   gStrings.linkRel = theBundle.getString("linkRel");
  224.   gStrings.linkStylesheet = theBundle.getString("linkStylesheet");
  225.   gStrings.linkRev = theBundle.getString("linkRev");
  226.   gStrings.linkX = theBundle.getString("linkX");
  227.   gStrings.mediaImg = theBundle.getString("mediaImg");
  228.   gStrings.mediaBGImg = theBundle.getString("mediaBGImg");
  229.   gStrings.mediaApplet = theBundle.getString("mediaApplet");
  230.   gStrings.mediaObject = theBundle.getString("mediaObject");
  231.   gStrings.mediaEmbed = theBundle.getString("mediaEmbed");
  232.   gStrings.mediaLink = theBundle.getString("mediaLink");
  233.   gStrings.mediaInput = theBundle.getString("mediaInput");
  234.  
  235.   var docTitle = "";
  236.   if ("arguments" in window && window.arguments.length >= 1 && window.arguments[0])
  237.   {
  238.     theWindow = null;
  239.     theDocument = window.arguments[0];
  240.     docTitle = theBundle.getString("frameInfo.title");
  241.   } 
  242.   else 
  243.   {
  244.     if ("gBrowser" in window.opener)
  245.       theWindow = window.opener.gBrowser.contentWindow;
  246.     else
  247.       theWindow = window.opener.frames[0];
  248.     theDocument = theWindow.document;
  249.  
  250.     docTitle = theBundle.getString("pageInfo.title");
  251.   }
  252.  
  253.   document.title = docTitle;
  254.  
  255.   // do the easy stuff first
  256.   makeGeneralTab();
  257.  
  258.   /* Call registered overlay init functions */
  259.   for (x in onLoadRegistry)
  260.   {
  261.     onLoadRegistry[x]();
  262.   }
  263.  
  264.   /* Select the requested tab, if the name is specified */
  265.   if ("arguments" in window && window.arguments.length > 1)
  266.   {
  267.     var tabName = window.arguments[1];
  268.  
  269.     if (tabName)
  270.     {
  271.       var tabControl = document.getElementById("tabbox");
  272.       var tab = document.getElementById(tabName);
  273.  
  274.       if (tabControl && tab)
  275.       {
  276.         tabControl.selectedTab = tab;
  277.       }
  278.     }
  279.   }
  280. }
  281.  
  282. function doHelpButton() {
  283.   var tabControl = document.getElementById("tabbox");
  284.   switch (tabControl.selectedTab.id) {
  285.     case "generalTab":
  286.       helpdoc = "pageinfo_general";
  287.       break;
  288.     case "formsTab":
  289.       helpdoc = "pageinfo_forms";
  290.       break;
  291.     case "linksTab":
  292.       helpdoc = "pageinfo_links";
  293.       break;
  294.     case "mediaTab":
  295.       helpdoc = "pageinfo_media";
  296.       break;
  297.     case "securityTab":
  298.       helpdoc = "pageinfo_security";
  299.       break;
  300.     case "p3pTab":
  301.       helpdoc = "pageinfo_privacy";
  302.       break;
  303.     default:
  304.       helpdoc = "pageinfo_general";
  305.       break;
  306.   }
  307.   openHelp(helpdoc);  
  308. }
  309.  
  310. function makeGeneralTab()
  311. {
  312.   var title = (theDocument.title) ? theBundle.getFormattedString("pageTitle", [theDocument.title]) : theBundle.getString("noPageTitle");
  313.   document.getElementById("titletext").value = title;
  314.  
  315.   var url = theDocument.location;
  316.   document.getElementById("urltext").value = url;
  317.  
  318.   var mode = ("compatMode" in theDocument && theDocument.compatMode == "BackCompat") ? theBundle.getString("generalQuirksMode") : theBundle.getString("generalStrictMode");
  319.   document.getElementById("modetext").value = mode;
  320.  
  321.   var referrer = (theDocument.referrer) ? theDocument.referrer : theBundle.getString("generalNoReferrer");
  322.   document.getElementById('refertext').value = referrer;
  323.  
  324.   // find out the mime type
  325.   var mimeType = theDocument.contentType || gStrings.unknown;
  326.   document.getElementById("typetext").value = mimeType;
  327.   
  328.   // get the meta tags
  329.   var metaNodes = theDocument.getElementsByTagName("meta");
  330.   var metaTree = document.getElementById("metatree");
  331.  
  332.   metaTree.treeBoxObject.view = metaView;
  333.  
  334.   var length = metaNodes.length;
  335.   for (var i = 0; i < length; i++)
  336.     metaView.addRow([metaNodes[i].name || metaNodes[i].httpEquiv, metaNodes[i].content]);
  337.  
  338.   metaView.rowCountChanged(0, length);
  339.   
  340.   // get the document characterset
  341.   var encoding = theDocument.characterSet;
  342.   document.getElementById("encodingtext").value = encoding;
  343.  
  344.   // get the date of last modification
  345.   var modifiedText = formatDate(theDocument.lastModified, gStrings.notSet);
  346.   document.getElementById("modifiedtext").value = modifiedText;
  347.   
  348.   // get cache info
  349.   var sourceText = theBundle.getString("generalNotCached");
  350.   var expirationText = theBundle.getString("generalNoExpiration");
  351.   var sizeText = gStrings.unknown;
  352.  
  353.   var pageSize = 0; 
  354.   var kbSize = 0;
  355.   var expirationTime = 0;
  356.  
  357.   try
  358.   {
  359.     var cacheEntryDescriptor = httpCacheSession.openCacheEntry(url, Components.interfaces.nsICache.ACCESS_READ, false);
  360.     if (cacheEntryDescriptor)
  361.     { 
  362.       switch(cacheEntryDescriptor.deviceID)
  363.       {
  364.         case "disk":
  365.           sourceText = theBundle.getString("generalDiskCache");
  366.           break;
  367.         case "memory":
  368.           sourceText = theBundle.getString("generalMemoryCache");
  369.           break;
  370.         default:
  371.           sourceText = cacheEntryDescriptor.deviceID;
  372.           break;
  373.       }
  374.  
  375.       pageSize = cacheEntryDescriptor.dataSize;
  376.       kbSize = pageSize / 1024;
  377.       sizeText = theBundle.getFormattedString("generalSize", [Math.round(kbSize*100)/100, pageSize]);
  378.  
  379.       expirationText = formatDate(cacheEntryDescriptor.expirationTime*1000, gStrings.notSet);
  380.     }
  381.   }
  382.   catch(ex)
  383.   {
  384.     try
  385.     {
  386.       cacheEntryDescriptor = ftpCacheSession.openCacheEntry(url, Components.interfaces.nsICache.ACCESS_READ, false);
  387.       if (cacheEntryDescriptor)
  388.       {
  389.         switch(cacheEntryDescriptor.deviceID)
  390.         {
  391.           case "disk":
  392.             sourceText = theBundle.getString("generalDiskCache");
  393.             break;
  394.           case "memory":
  395.             sourceText = theBundle.getString("generalMemoryCache");
  396.             break;
  397.           default:
  398.             sourceText = cacheEntryDescriptor.deviceID;
  399.             break;
  400.         }
  401.  
  402.         pageSize = cacheEntryDescriptor.dataSize;
  403.         kbSize = pageSize / 1024;
  404.         sizeText = theBundle.getFormattedString("generalSize", [Math.round(kbSize*100)/100, pageSize]);
  405.  
  406.         expirationText = formatDate(cacheEntryDescriptor.expirationTime*1000, gStrings.notSet);
  407.       }
  408.     }
  409.     catch(ex2)
  410.     {
  411.       sourceText = theBundle.getString("generalNotCached");
  412.     }
  413.   }
  414.   document.getElementById("sourcetext").value = sourceText;
  415.   document.getElementById("expirestext").value = expirationText;
  416.   document.getElementById("sizetext").value = sizeText;
  417. }
  418.  
  419. //******** Generic Build-a-tab
  420. function makeTabs(aDocument, aWindow)
  421. {
  422.   if (formView.initialized || linkView.initialized || imageView.initialized)
  423.     return;
  424.  
  425.   if (aWindow && aWindow.frames.length > 0)
  426.   {
  427.     var num = aWindow.frames.length;
  428.     for (var i = 0; i < num; i++)
  429.       makeTabs(aWindow.frames[i].document, aWindow.frames[i]);  // recurse through the frames
  430.   }
  431.  
  432.   var formTree = document.getElementById("formtree");
  433.   var linkTree = document.getElementById("linktree");
  434.   var imageTree = document.getElementById("imagetree");
  435.  
  436.   formTree.treeBoxObject.view = formView;
  437.   linkTree.treeBoxObject.view = linkView;
  438.   imageTree.treeBoxObject.view = imageView;
  439.   
  440.   var iterator = aDocument.createTreeWalker(aDocument, NodeFilter.SHOW_ELEMENT, grabAll, true);
  441.   
  442.   while (iterator.nextNode())
  443.     ; // it'll never be executed anyway, since grabAll never 
  444.       // accepts any nodes
  445.  
  446.   formView.rowCountChanged(0, formView.rowCount);
  447.   formView.selection.select(0);
  448.   formView.initialized = 1;
  449.  
  450.   linkView.rowCountChanged(0, linkView.rowCount);
  451.   linkView.selection.select(0);
  452.   linkView.initialized = 1;
  453.  
  454.   imageView.rowCountChanged(0, imageView.rowCount);
  455.   imageView.selection.select(0);
  456.   imageView.initialized = 1;
  457. }
  458.  
  459. function grabAll(elem)
  460. {
  461.   var linktext;
  462.  
  463.   // check for background images, any node may have one
  464.   var url = elem.ownerDocument.defaultView.getComputedStyle(elem, "").getPropertyCSSValue("background-image");
  465.   if (url && url.primitiveType == CSSPrimitiveValue.CSS_URI)
  466.     imageView.addRow([url.getStringValue(), gStrings.mediaBGImg, gStrings.notSet, elem, true]);
  467.  
  468.   // one swi^H^H^Hif-else to rule them all
  469.   // XXX: these tests should use regexes to be a little more lenient wrt whitespace, see bug 177047
  470.   if (elem instanceof nsIAnchorElement)
  471.   {
  472.     linktext = getValueText(elem);
  473.     linkView.addRow([linktext, getAbsoluteURL(elem.href, elem), gStrings.linkAnchor, elem.target]);
  474.   }
  475.   else if (elem instanceof nsIImageElement)
  476.   {
  477.     imageView.addRow([getAbsoluteURL(elem.src, elem), gStrings.mediaImg, (elem.hasAttribute("alt")) ? elem.alt : gStrings.notSet, elem, false]);
  478.   }
  479.   else if (elem instanceof nsIAreaElement)
  480.   {
  481.     linkView.addRow([elem.alt, getAbsoluteURL(elem.href, elem), gStrings.linkArea, elem.target]);
  482.   }
  483.   else if (elem instanceof nsILinkElement)
  484.   {
  485.     if (elem.rel)
  486.     {
  487.       var rel = elem.rel;
  488.       if (/\bicon\b/i.test(rel))
  489.         imageView.addRow([getAbsoluteURL(elem.href, elem), gStrings.mediaLink, "", elem, false]);
  490.       else if (/\bstylesheet\b/i.test(rel))
  491.         linkView.addRow([elem.rel, getAbsoluteURL(elem.href, elem), gStrings.linkStylesheet, elem.target]);
  492.       else
  493.         linkView.addRow([elem.rel, getAbsoluteURL(elem.href, elem), gStrings.linkRel, elem.target]);
  494.     }
  495.     else
  496.       linkView.addRow([elem.rev, getAbsoluteURL(elem.href, elem), gStrings.linkRev, elem.target]);
  497.  
  498.   }
  499.   else if (elem instanceof nsIInputElement)
  500.   {
  501.     if (/^image$/i.test(elem.type))
  502.       imageView.addRow([getAbsoluteURL(elem.src, elem), gStrings.mediaInput, (elem.hasAttribute("alt")) ? elem.alt : gStrings.notSet, elem, false]);
  503.     else if (/^submit$/i.test(elem.type))
  504.       linkView.addRow([elem.value || gStrings.linkSubmit, getAbsoluteURL(elem.form.getAttribute("action"), elem), gStrings.linkSubmission, elem.form.getAttribute("target")]); // use getAttribute() due to bug 122128
  505.   }
  506.   else if (elem instanceof nsIFormElement)
  507.   {
  508.     formView.addRow([elem.name, elem.method, getAbsoluteURL(elem.getAttribute("action"), elem), elem]);  // use getAttribute() because of bug 122128
  509.   }
  510.   else if (elem instanceof nsIAppletElement)
  511.   {
  512.     //XXX When Java is enabled, the DOM model for <APPLET> is broken. Bug #59686.
  513.     // Also, some reports of a crash with Java in Media tab (bug 136535), and mixed
  514.     // content from two hosts (bug 136539) so just drop applets from Page Info when
  515.     // Java is on. For the 1.0.1 branch; get a real fix on the trunk.
  516.     if (!navigator.javaEnabled())
  517.       imageView.addRow([getAbsoluteURL(elem.code || elem.object, elem), gStrings.mediaApplet, "", elem, false]);
  518.   }
  519.   else if (elem instanceof nsIObjectElement)
  520.   {
  521.     imageView.addRow([getAbsoluteURL(elem.data, elem), gStrings.mediaObject, getValueText(elem), elem, false]);
  522.   }
  523.   else if (elem instanceof nsIEmbedElement)
  524.   {
  525.     imageView.addRow([getAbsoluteURL(elem.src, elem), gStrings.mediaEmbed, "", elem, false]);
  526.   }
  527.   else
  528.     if (elem.hasAttributeNS(XLinkNS, "href"))
  529.     {
  530.       linktext = getValueText(elem);
  531.       linkView.addRow([linktext, getAbsoluteURL(elem.href, elem), gStrings.linkX, ""]);
  532.     }
  533.  
  534.   return NodeFilter.FILTER_SKIP;
  535. }
  536.  
  537. //******** Form Stuff
  538. function onFormSelect()
  539. {
  540.   var formTree = document.getElementById("formtree");
  541.   if (!formView.rowCount) return;
  542.  
  543.   if (formView.selection.count == 1)
  544.   {
  545.     var formPreview = document.getElementById("formpreview");
  546.     fieldView.clear();
  547.     formPreview.treeBoxObject.view = fieldView;
  548.  
  549.     var clickedRow = formView.selection.currentIndex;
  550.     var form = formView.getCellText(clickedRow, "form-node");
  551.  
  552.     var ft = null;
  553.     if (form.name)
  554.       ft = theBundle.getFormattedString("formTitle", [form.name]);
  555.     else
  556.       ft = theBundle.getString("formUntitled");
  557.  
  558.     document.getElementById("formname").value = ft || theBundle.getString("formUntitled");
  559.     document.getElementById("formenctype").value = form.encoding || theBundle.getString("default");
  560.     document.getElementById("formtarget").value = form.target || theBundle.getString("formDefaultTarget");
  561.  
  562.     var formfields = findFormControls(form);
  563.  
  564.     var length = formfields.length;
  565.     var i = 0;
  566.  
  567.     var checked = theBundle.getString("formChecked");
  568.     var unchecked = theBundle.getString("formUnchecked");    
  569.  
  570.     for (i = 0; i < length; i++)
  571.     {
  572.       var elem = formfields[i], val;
  573.  
  574.       if (elem instanceof nsIButtonElement)
  575.         val = getValueText(elem);
  576.       else
  577.         val = (/^password$/i.test(elem.type)) ? theBundle.getString("formPassword") : elem.value;
  578.  
  579.       fieldView.addRow(["", elem.id || elem.name, elem.type, val]);
  580.     }
  581.  
  582.     var labels = form.getElementsByTagName("label");
  583.     var llength = labels.length;
  584.  
  585.     for (i = 0; i < llength; i++)
  586.     {
  587.       var whatfor = labels[i].hasAttribute("for") ?
  588.         theDocument.getElementById(labels[i].getAttribute("for")) :
  589.         findFirstControl(labels[i]);
  590.  
  591.       if (whatfor && (whatfor.form == form)) {
  592.         var labeltext = getValueText(labels[i]);
  593.         for (var j = 0; j < length; j++)
  594.           if (formfields[j] == whatfor)
  595.             fieldView.setCellText(j, "field-label", labeltext);
  596.       }
  597.     }
  598.  
  599.     fieldView.rowCountChanged(0, length);
  600.   }
  601. }
  602.  
  603. function FormControlFilter(node) 
  604. {
  605.   if (node instanceof nsIInputElement || node instanceof nsISelectElement ||
  606.       node instanceof nsIButtonElement || node instanceof nsITextareaElement ||
  607.       node instanceof nsIObjectElement)
  608.       return NodeFilter.FILTER_ACCEPT;
  609.     return NodeFilter.FILTER_SKIP;
  610. }
  611.  
  612. function findFirstControl(node)
  613. {
  614.   var iterator = theDocument.createTreeWalker(node, NodeFilter.SHOW_ELEMENT, FormControlFilter, true);
  615.  
  616.   return iterator.nextNode();
  617. }
  618.  
  619. function findFormControls(node)
  620. {
  621.   var iterator = theDocument.createTreeWalker(node, NodeFilter.SHOW_ELEMENT, FormControlFilter, true);
  622.  
  623.   var list = [];
  624.   while (iterator.nextNode())
  625.     list.push(iterator.currentNode);
  626.  
  627.   return list;
  628. }
  629.  
  630. //******** Link Stuff
  631. function openURL(target)
  632. {
  633.   var url = target.parentNode.childNodes[2].value;
  634.   window.open(url, "_blank", "chrome");
  635. }
  636.  
  637. function onBeginLinkDrag(event,urlField,descField)
  638. {
  639.   if (event.originalTarget.localName != "treechildren")
  640.     return;
  641.  
  642.   var tree = event.target;
  643.   if (!("treeBoxObject" in tree))
  644.     tree = tree.parentNode;
  645.  
  646.   var row = {};
  647.   var col = {};
  648.   var elt = {};
  649.   tree.treeBoxObject.getCellAt(event.clientX, event.clientY, row, col, elt);
  650.   if (row.value == -1)
  651.     return;
  652.  
  653.   // Getting drag-system needed services
  654.   var dragService = Components.classes[DRAGSERVICE_CONTRACTID].getService().QueryInterface(Components.interfaces.nsIDragService);
  655.   var transArray = Components.classes[ARRAY_CONTRACTID].createInstance(Components.interfaces.nsISupportsArray);
  656.   if (!transArray)
  657.     return;
  658.   var trans = Components.classes[TRANSFERABLE_CONTRACTID].createInstance(Components.interfaces.nsITransferable);
  659.   if (!trans)
  660.     return;
  661.   
  662.   // Adding URL flavor
  663.   trans.addDataFlavor("text/x-moz-url");
  664.   var url = tree.treeBoxObject.view.getCellText(row.value, urlField);
  665.   var desc = tree.treeBoxObject.view.getCellText(row.value, descField);
  666.   var stringURL = Components.classes[STRING_CONTRACTID].createInstance(Components.interfaces.nsISupportsString);
  667.   stringURL.data = url + "\n"+desc;
  668.   trans.setTransferData("text/x-moz-url", stringURL, stringURL.data.length * 2 );
  669.   transArray.AppendElement(trans.QueryInterface(Components.interfaces.nsISupports));
  670.  
  671.   dragService.invokeDragSession(event.target, transArray, null, dragService.DRAGDROP_ACTION_NONE);
  672. }
  673.  
  674. //******** Image Stuff
  675. function getSource(item)
  676. {
  677.   // Return the correct source without strict warnings
  678.   if (item.href != null)
  679.     return item.href;
  680.   if (item.src != null)
  681.     return item.src;
  682.   return null;
  683. }
  684.  
  685. function getSelectedImage(tree)
  686. {
  687.   if (!imageView.rowCount) return null;
  688.  
  689.   // Only works if only one item is selected
  690.   var clickedRow = tree.treeBoxObject.selection.currentIndex;
  691.   return imageView.getCellText(clickedRow, "image-node");
  692. }
  693.  
  694. function saveMedia()
  695. {
  696.   var tree = document.getElementById("imagetree");
  697.   var item = getSelectedImage(tree);
  698.   var url = getAbsoluteURL(getSource(item), item);
  699.  
  700.   if (url)
  701.     saveURL(url, null, 'SaveImageTitle', false );
  702. }
  703.  
  704. function onImageSelect()
  705. {
  706.   var tree = document.getElementById("imagetree");
  707.   var saveAsButton = document.getElementById("imagesaveasbutton");
  708.  
  709.   if (tree.treeBoxObject.selection.count == 1)
  710.   {
  711.     makePreview(tree.treeBoxObject.selection.currentIndex);
  712.     saveAsButton.setAttribute("disabled", "false");
  713.   }
  714.   else
  715.     saveAsButton.setAttribute("disabled", "true");
  716. }
  717.  
  718. function makePreview(row)
  719. {
  720.   var item = getSelectedImage(document.getElementById("imagetree"));
  721.   var url = imageView.getCellText(row, "image-address");
  722.   var isBG = imageView.getCellText(row, "image-bg");
  723.  
  724.   document.getElementById("imageurltext").value = url;
  725.   document.getElementById("imagetitletext").value = item.title || gStrings.notSet;
  726.  
  727.   var altText = null;
  728.   if (item.hasAttribute("alt") && ("alt" in item))
  729.     altText = item.alt;
  730.   else if (!isBG)
  731.     altText = getValueText(item);
  732.   if (altText == null)
  733.     altText = gStrings.notSet;
  734.   var textbox=document.getElementById("imagealttext");
  735.   
  736.   // IMO all text that is not really the value text should go in italics
  737.   // What if somebody has <img alt="Not specified">? =)
  738.   // We can't use textbox.style because of bug 7639
  739.   if (!altText) {
  740.       textbox.value = gStrings.emptyString;
  741.       textbox.setAttribute("style","font-style:italic");
  742.   } else {
  743.       textbox.value = altText;
  744.       textbox.setAttribute("style","font-style:inherit");
  745.   }
  746.   document.getElementById("imagelongdesctext").value = ("longDesc" in item && item.longDesc) || gStrings.notSet;
  747.  
  748.   // get cache info
  749.   var sourceText = theBundle.getString("generalNotCached");
  750.   var expirationText = gStrings.unknown;
  751.   var sizeText = gStrings.unknown;
  752.  
  753.   var pageSize = 0; 
  754.   var kbSize = 0;
  755.   var expirationTime = 0;
  756.   var expirationDate = null;
  757.  
  758.   try
  759.   {
  760.     var cacheEntryDescriptor = httpCacheSession.openCacheEntry(url, Components.interfaces.nsICache.ACCESS_READ, false);   // open for READ, in non-blocking mode
  761.     if (cacheEntryDescriptor)
  762.     {
  763.       switch(cacheEntryDescriptor.deviceID)
  764.       {
  765.         case "disk":
  766.           sourceText = theBundle.getString("generalDiskCache");
  767.           break;
  768.         case "memory":
  769.           sourceText = theBundle.getString("generalMemoryCache");
  770.           break;
  771.         default:
  772.           sourceText = cacheEntryDescriptor.deviceID;
  773.           break;
  774.       }
  775.     }
  776.   }
  777.   catch(ex)
  778.   {
  779.     try
  780.     {
  781.       cacheEntryDescriptor = ftpCacheSession.openCacheEntry(url, Components.interfaces.nsICache.ACCESS_READ, false);   // open for READ, in non-blocking mode
  782.       if (cacheEntryDescriptor)
  783.       {
  784.         switch(cacheEntryDescriptor.deviceID)
  785.         {
  786.           case "disk":
  787.             sourceText = theBundle.getString("generalDiskCache");
  788.             break;
  789.           case "memory":
  790.             sourceText = theBundle.getString("generalMemoryCache");
  791.             break;
  792.           default:
  793.             sourceText = cacheEntryDescriptor.deviceID;
  794.             break;
  795.         }
  796.       }
  797.     }
  798.     catch(ex2)
  799.     {
  800.       sourceText = theBundle.getString("generalNotCached");
  801.     }
  802.   }
  803.  
  804.   // find out the mime type, file size and expiration date
  805.   var mimeType = gStrings.unknown, httpType;
  806.   if (cacheEntryDescriptor)
  807.   {
  808.     var headers, match;
  809.  
  810.     pageSize = cacheEntryDescriptor.dataSize;
  811.     kbSize = pageSize / 1024;
  812.     sizeText = theBundle.getFormattedString("generalSize", [Math.round(kbSize*100)/100, pageSize]);
  813.  
  814.     expirationText = formatDate(cacheEntryDescriptor.expirationTime*1000, gStrings.notSet);
  815.  
  816.     headers = cacheEntryDescriptor.getMetaDataElement("response-head");
  817.  
  818.     match = /^Content-Type:\s*(.*?)\s*(?:\;|$)/mi.exec(headers);
  819.     if (match)
  820.       httpType = match[1];
  821.   }
  822.  
  823.   if (!(item instanceof nsIInputElement))
  824.     mimeType = ("type" in item && item.type) ||
  825.                ("codeType" in item && item.codeType) ||
  826.                ("contentType" in item && item.contentType) ||
  827.                httpType || gStrings.unknown;
  828.  
  829.   document.getElementById("imagetypetext").value = mimeType;
  830.   document.getElementById("imagesourcetext").value = sourceText;
  831.   document.getElementById("imageexpirestext").value = expirationText;
  832.   document.getElementById("imagesizetext").value = sizeText;
  833.  
  834.   var imageContainer = document.getElementById("theimagecontainer");
  835.   var oldImage = document.getElementById("thepreviewimage");
  836.  
  837.   var regex = new RegExp("^(https?|ftp|file|gopher)://");
  838.   var absoluteURL = getAbsoluteURL(url, item);
  839.   var isProtocolAllowed = regex.test(absoluteURL); 
  840.   var newImage = new Image();
  841.   newImage.setAttribute("id", "thepreviewimage");
  842.   var physWidth = 0, physHeight = 0;
  843.  
  844.   if ((item instanceof nsILinkElement || item instanceof nsIInputElement || 
  845.        item instanceof nsIImageElement || isBG) && isProtocolAllowed)  
  846.   {
  847.     newImage.src = absoluteURL;
  848.     physWidth = newImage.width;
  849.     physHeight = newImage.height;
  850.  
  851.     if ("width" in item && item.width)
  852.       newImage.width = item.width;
  853.     if ("height" in item && item.height)
  854.       newImage.height = item.height;
  855.   } 
  856.   else 
  857.   {
  858.     // fallback image for protocols not allowed (e.g., data: or javascript:) 
  859.     // or elements not [yet] handled (e.g., object, embed). XXX blank??
  860.     newImage.src = "resource:///res/loading-image.gif";
  861.     newImage.width = 40;
  862.     newImage.height = 40;
  863.   }
  864.  
  865.   var width = ("width" in item && item.width) || ("width" in newImage && newImage.width) || "0";
  866.   var height = ("height" in item && item.height) || ("height" in newImage && newImage.height) || "0";
  867.  
  868.   document.getElementById("imageSize").value = theBundle.getFormattedString("mediaSize", [width, height]);
  869.  
  870.   if (width != physWidth || height != physHeight)
  871.   {
  872.     document.getElementById("physSize").removeAttribute("hidden");
  873.     document.getElementById("physSize").value = theBundle.getFormattedString("mediaPhysSize", [physWidth, physHeight]);
  874.   }
  875.   else
  876.     document.getElementById("physSize").setAttribute("hidden", "true");
  877.  
  878.  
  879.   imageContainer.removeChild(oldImage);
  880.   imageContainer.appendChild(newImage);
  881. }
  882.  
  883.  
  884. //******** Other Misc Stuff
  885. // Modified from the Links Panel v2.3, http://segment7.net/mozilla/links/links.html
  886. // parse a node to extract the contents of the node
  887. // linkNode doesn't really _have_ to be link
  888. function getValueText(linkNode)
  889. {
  890.   var valueText = "";
  891.   
  892.   var length = linkNode.childNodes.length;
  893.   for (var i = 0; i < length; i++)
  894.   {
  895.     var childNode = linkNode.childNodes[i];
  896.     var nodeType = childNode.nodeType;
  897.     if (nodeType == Node.TEXT_NODE)
  898.       valueText += " " + childNode.nodeValue;
  899.     else if (nodeType == Node.ELEMENT_NODE)
  900.     {
  901.       if (childNode instanceof nsIImageElement)
  902.         valueText += " " + getAltText(childNode);
  903.       else
  904.         valueText += " " + getValueText(childNode);
  905.     }
  906.   }
  907.  
  908.   return stripWS(valueText);
  909. }
  910.  
  911. // Copied from the Links Panel v2.3, http://segment7.net/mozilla/links/links.html
  912. // traverse the tree in search of an img or area element and grab its alt tag
  913. function getAltText(node)
  914. {
  915.   var altText = "";
  916.   
  917.   if (node.alt)
  918.     return node.alt;
  919.   var length = node.childNodes.length;
  920.   for (var i = 0; i < length; i++)
  921.     if ((altText = getAltText(node.childNodes[i]) != undefined))  // stupid js warning...
  922.       return altText;
  923.   return "";
  924. }
  925.  
  926. // Copied from the Links Panel v2.3, http://segment7.net/mozilla/links/links.html
  927. // strip leading and trailing whitespace, and replace multiple consecutive whitespace characters with a single space
  928. function stripWS(text)
  929. {
  930.   var middleRE = /\s+/g;
  931.   var endRE = /(^\s+)|(\s+$)/g;
  932.  
  933.   text = text.replace(middleRE, " ");
  934.   return text.replace(endRE, "");
  935. }
  936.  
  937. function formatDate(datestr, unknown)
  938. {
  939.   var date = new Date(datestr);
  940.   return (date.valueOf()) ? dateService.FormatDateTime("", dateService.dateFormatLong, dateService.timeFormatSeconds, date.getFullYear(), date.getMonth()+1, date.getDate(), date.getHours(), date.getMinutes(), date.getSeconds()) : unknown;
  941. }
  942.  
  943. /*
  944.  * Takes care of XMLBase and <base>
  945.  * url is the possibly relative url.
  946.  * node is the node where the url was given (needed for XMLBase)
  947.  *
  948.  * This function is called in many places as a workaround for bug 72524
  949.  * Once bug 72522 is fixed this code should use the Node.baseURI attribute
  950.  *
  951.  * for node==null or url=="", empty string is returned
  952.  *
  953.  * This is basically just copied from http://lxr.mozilla.org/seamonkey/source/xpfe/browser/resources/content/metadata.js,
  954.  * though I've modified it so that it doesn't assign to .spec
  955.  */
  956.  
  957. function getAbsoluteURL(url, node)
  958. {
  959.   if (!url || !node)
  960.     return "";
  961.   var urlArr = new Array(url);
  962.  
  963.   var doc = node.ownerDocument;
  964.   if (node.nodeType == Node.ATTRIBUTE_NODE)
  965.     node = node.ownerElement;
  966.  
  967.   while (node && node.nodeType == Node.ELEMENT_NODE) 
  968.   {
  969.     var att = node.getAttributeNS(XMLNS, "base");
  970.     if (att != "")
  971.       urlArr.unshift(att);
  972.  
  973.     node = node.parentNode;
  974.   }
  975.  
  976.   // Look for a <base>.
  977.   var baseTags = doc.getElementsByTagNameNS(XHTMLNS, "base");
  978.  
  979.   if (baseTags && baseTags.length) 
  980.   {
  981.     urlArr.unshift(baseTags[baseTags.length - 1].getAttribute("href"));
  982.   }
  983.  
  984.   // resolve everything from bottom up, starting with document location
  985.   var ioService = Components.classes["@mozilla.org/network/io-service;1"].getService(Components.interfaces.nsIIOService);
  986.   var URL = ioService.newURI(doc.location.href, null, null);
  987.  
  988.   for (var i=0; i<urlArr.length; i++) 
  989.   {
  990.     try
  991.     {
  992.       URL = ioService.newURI(urlArr[i], URL.originCharset, URL);
  993.     }
  994.     catch (ex)
  995.     {
  996.       ; // do nothing
  997.     }
  998.   }
  999.  
  1000.   return URL.spec;
  1001. }
  1002.  
  1003. function doCopy(event)
  1004. {
  1005.   if (!gClipboardHelper) 
  1006.     return;
  1007.  
  1008.   var elem = event.originalTarget;
  1009.   if (elem && "treeBoxObject" in elem)
  1010.     elem.treeBoxObject.view.performActionOnRow("copy", elem.currentIndex);
  1011.  
  1012.   var text = elem.getAttribute("copybuffer");
  1013.   if (text) 
  1014.     gClipboardHelper.copyString(text);
  1015. }
  1016.