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