1 /* 2 * Copyright (C) 2007, 2008, 2010 Apple Inc. All rights reserved. 3 * Copyright (C) 2009 Joseph Pecoraro 4 * Copyright (C) 2013 Samsung Electronics. All rights reserved. 5 * 6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that the following conditions 8 * are met: 9 * 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of 16 * its contributors may be used to endorse or promote products derived 17 * from this software without specific prior written permission. 18 * 19 * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY 20 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 21 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 22 * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY 23 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 24 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 25 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 26 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 27 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 28 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29 */ 30 31 importScript("ApplicationCacheItemsView.js"); 32 importScript("DOMStorageItemsView.js"); 33 importScript("DatabaseQueryView.js"); 34 importScript("DatabaseTableView.js"); 35 importScript("DirectoryContentView.js"); 36 importScript("IndexedDBViews.js"); 37 importScript("FileContentView.js"); 38 importScript("FileSystemView.js"); 39 40 /** 41 * @constructor 42 * @extends {WebInspector.Panel} 43 */ 44 WebInspector.ResourcesPanel = function(database) 45 { 46 WebInspector.Panel.call(this, "resources"); 47 this.registerRequiredCSS("resourcesPanel.css"); 48 49 WebInspector.settings.resourcesLastSelectedItem = WebInspector.settings.createSetting("resourcesLastSelectedItem", {}); 50 51 this.createSidebarViewWithTree(); 52 this.sidebarElement.addStyleClass("outline-disclosure"); 53 this.sidebarElement.addStyleClass("filter-all"); 54 this.sidebarElement.addStyleClass("children"); 55 this.sidebarElement.addStyleClass("small"); 56 57 this.sidebarTreeElement.removeStyleClass("sidebar-tree"); 58 59 this.resourcesListTreeElement = new WebInspector.StorageCategoryTreeElement(this, WebInspector.UIString("Frames"), "Frames", ["frame-storage-tree-item"]); 60 this.sidebarTree.appendChild(this.resourcesListTreeElement); 61 62 this.databasesListTreeElement = new WebInspector.StorageCategoryTreeElement(this, WebInspector.UIString("Web SQL"), "Databases", ["database-storage-tree-item"]); 63 this.sidebarTree.appendChild(this.databasesListTreeElement); 64 65 this.indexedDBListTreeElement = new WebInspector.IndexedDBTreeElement(this); 66 this.sidebarTree.appendChild(this.indexedDBListTreeElement); 67 68 this.localStorageListTreeElement = new WebInspector.StorageCategoryTreeElement(this, WebInspector.UIString("Local Storage"), "LocalStorage", ["domstorage-storage-tree-item", "local-storage"]); 69 this.sidebarTree.appendChild(this.localStorageListTreeElement); 70 71 this.sessionStorageListTreeElement = new WebInspector.StorageCategoryTreeElement(this, WebInspector.UIString("Session Storage"), "SessionStorage", ["domstorage-storage-tree-item", "session-storage"]); 72 this.sidebarTree.appendChild(this.sessionStorageListTreeElement); 73 74 this.cookieListTreeElement = new WebInspector.StorageCategoryTreeElement(this, WebInspector.UIString("Cookies"), "Cookies", ["cookie-storage-tree-item"]); 75 this.sidebarTree.appendChild(this.cookieListTreeElement); 76 77 this.applicationCacheListTreeElement = new WebInspector.StorageCategoryTreeElement(this, WebInspector.UIString("Application Cache"), "ApplicationCache", ["application-cache-storage-tree-item"]); 78 this.sidebarTree.appendChild(this.applicationCacheListTreeElement); 79 80 if (WebInspector.experimentsSettings.fileSystemInspection.isEnabled()) { 81 this.fileSystemListTreeElement = new WebInspector.FileSystemListTreeElement(this); 82 this.sidebarTree.appendChild(this.fileSystemListTreeElement); 83 } 84 85 this.storageViews = this.splitView.mainElement; 86 this.storageViews.addStyleClass("diff-container"); 87 88 this.storageViewStatusBarItemsContainer = document.createElement("div"); 89 this.storageViewStatusBarItemsContainer.className = "status-bar-items"; 90 91 /** @type {!Map.<!WebInspector.Database, !Object.<string, !WebInspector.DatabaseTableView>>} */ 92 this._databaseTableViews = new Map(); 93 /** @type {!Map.<!WebInspector.Database, !WebInspector.DatabaseQueryView>} */ 94 this._databaseQueryViews = new Map(); 95 /** @type {!Map.<!WebInspector.Database, !WebInspector.DatabaseTreeElement>} */ 96 this._databaseTreeElements = new Map(); 97 /** @type {!Map.<!WebInspector.DOMStorage, !WebInspector.DOMStorageItemsView>} */ 98 this._domStorageViews = new Map(); 99 /** @type {!Map.<!WebInspector.DOMStorage, !WebInspector.DOMStorageTreeElement>} */ 100 this._domStorageTreeElements = new Map(); 101 /** @type {!Object.<string, !WebInspector.CookieItemsView>} */ 102 this._cookieViews = {}; 103 /** @type {!Object.<string, boolean>} */ 104 this._domains = {}; 105 106 this.sidebarElement.addEventListener("mousemove", this._onmousemove.bind(this), false); 107 this.sidebarElement.addEventListener("mouseout", this._onmouseout.bind(this), false); 108 109 function viewGetter() 110 { 111 return this.visibleView; 112 } 113 WebInspector.GoToLineDialog.install(this, viewGetter.bind(this)); 114 115 if (WebInspector.resourceTreeModel.cachedResourcesLoaded()) 116 this._cachedResourcesLoaded(); 117 118 WebInspector.resourceTreeModel.addEventListener(WebInspector.ResourceTreeModel.EventTypes.Load, this._loadEventFired, this); 119 WebInspector.resourceTreeModel.addEventListener(WebInspector.ResourceTreeModel.EventTypes.CachedResourcesLoaded, this._cachedResourcesLoaded, this); 120 WebInspector.resourceTreeModel.addEventListener(WebInspector.ResourceTreeModel.EventTypes.WillLoadCachedResources, this._resetWithFrames, this); 121 122 WebInspector.databaseModel.databases().forEach(this._addDatabase.bind(this)); 123 WebInspector.databaseModel.addEventListener(WebInspector.DatabaseModel.Events.DatabaseAdded, this._databaseAdded, this); 124 } 125 126 WebInspector.ResourcesPanel.prototype = { 127 get statusBarItems() 128 { 129 return [this.storageViewStatusBarItemsContainer]; 130 }, 131 132 wasShown: function() 133 { 134 WebInspector.Panel.prototype.wasShown.call(this); 135 this._initialize(); 136 }, 137 138 /** 139 * @param {KeyboardEvent} event 140 */ 141 handleShortcut: function(event) 142 { 143 if (this.visibleView && typeof this.visibleView.handleShortcut === "function") 144 return this.visibleView.handleShortcut(event); 145 }, 146 147 _initialize: function() 148 { 149 if (!this._initialized && this.isShowing() && this._cachedResourcesWereLoaded) { 150 this._populateResourceTree(); 151 this._populateDOMStorageTree(); 152 this._populateApplicationCacheTree(); 153 this._initDefaultSelection(); 154 this._initialized = true; 155 } 156 }, 157 158 _loadEventFired: function() 159 { 160 this._initDefaultSelection(); 161 }, 162 163 _initDefaultSelection: function() 164 { 165 if (!this._initialized) 166 return; 167 168 var itemURL = WebInspector.settings.resourcesLastSelectedItem.get(); 169 if (itemURL) { 170 for (var treeElement = this.sidebarTree.children[0]; treeElement; treeElement = treeElement.traverseNextTreeElement(false, this.sidebarTree, true)) { 171 if (treeElement.itemURL === itemURL) { 172 treeElement.revealAndSelect(true); 173 return; 174 } 175 } 176 } 177 178 var mainResource = WebInspector.inspectedPageURL && this.resourcesListTreeElement && this.resourcesListTreeElement.expanded && WebInspector.resourceTreeModel.resourceForURL(WebInspector.inspectedPageURL); 179 if (mainResource) 180 this.showResource(mainResource); 181 }, 182 183 _resetWithFrames: function() 184 { 185 this.resourcesListTreeElement.removeChildren(); 186 this._treeElementForFrameId = {}; 187 this._reset(); 188 }, 189 190 _reset: function() 191 { 192 this._domains = {}; 193 var queryViews = this._databaseQueryViews.values(); 194 for (var i = 0; i < queryViews.length; ++i) 195 queryViews[i].removeEventListener(WebInspector.DatabaseQueryView.Events.SchemaUpdated, this._updateDatabaseTables, this); 196 this._databaseTableViews.clear(); 197 this._databaseQueryViews.clear(); 198 this._databaseTreeElements.clear(); 199 this._domStorageViews.clear(); 200 this._domStorageTreeElements.clear(); 201 this._cookieViews = {}; 202 203 this.databasesListTreeElement.removeChildren(); 204 this.localStorageListTreeElement.removeChildren(); 205 this.sessionStorageListTreeElement.removeChildren(); 206 this.cookieListTreeElement.removeChildren(); 207 208 if (this.visibleView && !(this.visibleView instanceof WebInspector.StorageCategoryView)) 209 this.visibleView.detach(); 210 211 this.storageViewStatusBarItemsContainer.removeChildren(); 212 213 if (this.sidebarTree.selectedTreeElement) 214 this.sidebarTree.selectedTreeElement.deselect(); 215 }, 216 217 _populateResourceTree: function() 218 { 219 this._treeElementForFrameId = {}; 220 WebInspector.resourceTreeModel.addEventListener(WebInspector.ResourceTreeModel.EventTypes.FrameAdded, this._frameAdded, this); 221 WebInspector.resourceTreeModel.addEventListener(WebInspector.ResourceTreeModel.EventTypes.FrameNavigated, this._frameNavigated, this); 222 WebInspector.resourceTreeModel.addEventListener(WebInspector.ResourceTreeModel.EventTypes.FrameDetached, this._frameDetached, this); 223 WebInspector.resourceTreeModel.addEventListener(WebInspector.ResourceTreeModel.EventTypes.ResourceAdded, this._resourceAdded, this); 224 225 function populateFrame(frame) 226 { 227 this._frameAdded({data:frame}); 228 for (var i = 0; i < frame.childFrames.length; ++i) 229 populateFrame.call(this, frame.childFrames[i]); 230 231 var resources = frame.resources(); 232 for (var i = 0; i < resources.length; ++i) 233 this._resourceAdded({data:resources[i]}); 234 } 235 populateFrame.call(this, WebInspector.resourceTreeModel.mainFrame); 236 }, 237 238 _frameAdded: function(event) 239 { 240 var frame = event.data; 241 var parentFrame = frame.parentFrame; 242 243 var parentTreeElement = parentFrame ? this._treeElementForFrameId[parentFrame.id] : this.resourcesListTreeElement; 244 if (!parentTreeElement) { 245 console.warn("No frame to route " + frame.url + " to.") 246 return; 247 } 248 249 var frameTreeElement = new WebInspector.FrameTreeElement(this, frame); 250 this._treeElementForFrameId[frame.id] = frameTreeElement; 251 parentTreeElement.appendChild(frameTreeElement); 252 }, 253 254 _frameDetached: function(event) 255 { 256 var frame = event.data; 257 var frameTreeElement = this._treeElementForFrameId[frame.id]; 258 if (!frameTreeElement) 259 return; 260 261 delete this._treeElementForFrameId[frame.id]; 262 if (frameTreeElement.parent) 263 frameTreeElement.parent.removeChild(frameTreeElement); 264 }, 265 266 _resourceAdded: function(event) 267 { 268 var resource = event.data; 269 var frameId = resource.frameId; 270 271 if (resource.statusCode >= 301 && resource.statusCode <= 303) 272 return; 273 274 var frameTreeElement = this._treeElementForFrameId[frameId]; 275 if (!frameTreeElement) { 276 // This is a frame's main resource, it will be retained 277 // and re-added by the resource manager; 278 return; 279 } 280 281 frameTreeElement.appendResource(resource); 282 }, 283 284 _frameNavigated: function(event) 285 { 286 var frame = event.data; 287 288 if (!frame.parentFrame) 289 this._reset(); 290 291 var frameId = frame.id; 292 var frameTreeElement = this._treeElementForFrameId[frameId]; 293 if (frameTreeElement) 294 frameTreeElement.frameNavigated(frame); 295 296 var applicationCacheFrameTreeElement = this._applicationCacheFrameElements[frameId]; 297 if (applicationCacheFrameTreeElement) 298 applicationCacheFrameTreeElement.frameNavigated(frame); 299 }, 300 301 _cachedResourcesLoaded: function() 302 { 303 this._cachedResourcesWereLoaded = true; 304 this._initialize(); 305 }, 306 307 /** 308 * @param {WebInspector.Event} event 309 */ 310 _databaseAdded: function(event) 311 { 312 var database = /** @type {WebInspector.Database} */ (event.data); 313 this._addDatabase(database); 314 }, 315 316 /** 317 * @param {WebInspector.Database} database 318 */ 319 _addDatabase: function(database) 320 { 321 var databaseTreeElement = new WebInspector.DatabaseTreeElement(this, database); 322 this._databaseTreeElements.put(database, databaseTreeElement); 323 this.databasesListTreeElement.appendChild(databaseTreeElement); 324 }, 325 326 addDocumentURL: function(url) 327 { 328 var parsedURL = url.asParsedURL(); 329 if (!parsedURL) 330 return; 331 332 var domain = parsedURL.host; 333 if (!this._domains[domain]) { 334 this._domains[domain] = true; 335 336 var cookieDomainTreeElement = new WebInspector.CookieTreeElement(this, domain); 337 this.cookieListTreeElement.appendChild(cookieDomainTreeElement); 338 } 339 }, 340 341 /** 342 * @param {WebInspector.Event} event 343 */ 344 _domStorageAdded: function(event) 345 { 346 var domStorage = /** @type {WebInspector.DOMStorage} */ (event.data); 347 this._addDOMStorage(domStorage); 348 }, 349 350 /** 351 * @param {WebInspector.DOMStorage} domStorage 352 */ 353 _addDOMStorage: function(domStorage) 354 { 355 console.assert(!this._domStorageTreeElements.get(domStorage)); 356 357 var domStorageTreeElement = new WebInspector.DOMStorageTreeElement(this, domStorage, (domStorage.isLocalStorage ? "local-storage" : "session-storage")); 358 this._domStorageTreeElements.put(domStorage, domStorageTreeElement); 359 if (domStorage.isLocalStorage) 360 this.localStorageListTreeElement.appendChild(domStorageTreeElement); 361 else 362 this.sessionStorageListTreeElement.appendChild(domStorageTreeElement); 363 }, 364 365 /** 366 * @param {WebInspector.Event} event 367 */ 368 _domStorageRemoved: function(event) 369 { 370 var domStorage = /** @type {WebInspector.DOMStorage} */ (event.data); 371 this._removeDOMStorage(domStorage); 372 }, 373 374 /** 375 * @param {WebInspector.DOMStorage} domStorage 376 */ 377 _removeDOMStorage: function(domStorage) 378 { 379 var treeElement = this._domStorageTreeElements.get(domStorage); 380 if (!treeElement) 381 return; 382 var wasSelected = treeElement.selected; 383 var parentListTreeElement = treeElement.parent; 384 parentListTreeElement.removeChild(treeElement); 385 if (wasSelected) 386 parentListTreeElement.select(); 387 this._domStorageTreeElements.remove(treeElement); 388 this._domStorageViews.remove(domStorage); 389 }, 390 391 /** 392 * @param {WebInspector.Database} database 393 */ 394 selectDatabase: function(database) 395 { 396 if (database) { 397 this._showDatabase(database); 398 this._databaseTreeElements.get(database).select(); 399 } 400 }, 401 402 /** 403 * @param {WebInspector.DOMStorage} domStorage 404 */ 405 selectDOMStorage: function(domStorage) 406 { 407 if (domStorage) { 408 this._showDOMStorage(domStorage); 409 this._domStorageTreeElements.get(domStorage).select(); 410 } 411 }, 412 413 canShowAnchorLocation: function(anchor) 414 { 415 return !!WebInspector.resourceForURL(anchor.href); 416 }, 417 418 showAnchorLocation: function(anchor) 419 { 420 var resource = WebInspector.resourceForURL(anchor.href); 421 this.showResource(resource, anchor.lineNumber); 422 }, 423 424 /** 425 * @param {WebInspector.Resource} resource 426 * @param {number=} line 427 * @param {number=} column 428 */ 429 showResource: function(resource, line, column) 430 { 431 var resourceTreeElement = this._findTreeElementForResource(resource); 432 if (resourceTreeElement) 433 resourceTreeElement.revealAndSelect(true); 434 435 if (typeof line === "number") { 436 var view = this._resourceViewForResource(resource); 437 if (view.canHighlightPosition()) 438 view.highlightPosition(line, column); 439 } 440 return true; 441 }, 442 443 _showResourceView: function(resource) 444 { 445 var view = this._resourceViewForResource(resource); 446 if (!view) { 447 this.visibleView.detach(); 448 return; 449 } 450 if (view.searchCanceled) 451 view.searchCanceled(); 452 this._innerShowView(view); 453 }, 454 455 _resourceViewForResource: function(resource) 456 { 457 if (WebInspector.ResourceView.hasTextContent(resource)) { 458 var treeElement = this._findTreeElementForResource(resource); 459 if (!treeElement) 460 return null; 461 return treeElement.sourceView(); 462 } 463 return WebInspector.ResourceView.nonSourceViewForResource(resource); 464 }, 465 466 /** 467 * @param {WebInspector.Database} database 468 * @param {string=} tableName 469 */ 470 _showDatabase: function(database, tableName) 471 { 472 if (!database) 473 return; 474 475 var view; 476 if (tableName) { 477 var tableViews = this._databaseTableViews.get(database); 478 if (!tableViews) { 479 tableViews = /** @type {!Object.<string, !WebInspector.DatabaseTableView>} */ ({}); 480 this._databaseTableViews.put(database, tableViews); 481 } 482 view = tableViews[tableName]; 483 if (!view) { 484 view = new WebInspector.DatabaseTableView(database, tableName); 485 tableViews[tableName] = view; 486 } 487 } else { 488 view = this._databaseQueryViews.get(database); 489 if (!view) { 490 view = new WebInspector.DatabaseQueryView(database); 491 this._databaseQueryViews.put(database, view); 492 view.addEventListener(WebInspector.DatabaseQueryView.Events.SchemaUpdated, this._updateDatabaseTables, this); 493 } 494 } 495 496 this._innerShowView(view); 497 }, 498 499 /** 500 * @param {WebInspector.View} view 501 */ 502 showIndexedDB: function(view) 503 { 504 this._innerShowView(view); 505 }, 506 507 /** 508 * @param {WebInspector.DOMStorage} domStorage 509 */ 510 _showDOMStorage: function(domStorage) 511 { 512 if (!domStorage) 513 return; 514 515 var view; 516 view = this._domStorageViews.get(domStorage); 517 if (!view) { 518 view = new WebInspector.DOMStorageItemsView(domStorage, WebInspector.domStorageModel); 519 this._domStorageViews.put(domStorage, view); 520 } 521 522 this._innerShowView(view); 523 }, 524 525 /** 526 * @param {!WebInspector.CookieTreeElement} treeElement 527 * @param {string} cookieDomain 528 */ 529 showCookies: function(treeElement, cookieDomain) 530 { 531 var view = this._cookieViews[cookieDomain]; 532 if (!view) { 533 view = new WebInspector.CookieItemsView(treeElement, cookieDomain); 534 this._cookieViews[cookieDomain] = view; 535 } 536 537 this._innerShowView(view); 538 }, 539 540 /** 541 * @param {string} cookieDomain 542 */ 543 clearCookies: function(cookieDomain) 544 { 545 this._cookieViews[cookieDomain].clear(); 546 }, 547 548 showApplicationCache: function(frameId) 549 { 550 if (!this._applicationCacheViews[frameId]) 551 this._applicationCacheViews[frameId] = new WebInspector.ApplicationCacheItemsView(this._applicationCacheModel, frameId); 552 553 this._innerShowView(this._applicationCacheViews[frameId]); 554 }, 555 556 /** 557 * @param {WebInspector.View} view 558 */ 559 showFileSystem: function(view) 560 { 561 this._innerShowView(view); 562 }, 563 564 showCategoryView: function(categoryName) 565 { 566 if (!this._categoryView) 567 this._categoryView = new WebInspector.StorageCategoryView(); 568 this._categoryView.setText(categoryName); 569 this._innerShowView(this._categoryView); 570 }, 571 572 _innerShowView: function(view) 573 { 574 if (this.visibleView === view) 575 return; 576 577 if (this.visibleView) 578 this.visibleView.detach(); 579 580 view.show(this.storageViews); 581 this.visibleView = view; 582 583 this.storageViewStatusBarItemsContainer.removeChildren(); 584 var statusBarItems = view.statusBarItems || []; 585 for (var i = 0; i < statusBarItems.length; ++i) 586 this.storageViewStatusBarItemsContainer.appendChild(statusBarItems[i]); 587 }, 588 589 closeVisibleView: function() 590 { 591 if (!this.visibleView) 592 return; 593 this.visibleView.detach(); 594 delete this.visibleView; 595 }, 596 597 _updateDatabaseTables: function(event) 598 { 599 var database = event.data; 600 601 if (!database) 602 return; 603 604 var databasesTreeElement = this._databaseTreeElements.get(database); 605 if (!databasesTreeElement) 606 return; 607 608 databasesTreeElement.shouldRefreshChildren = true; 609 var tableViews = this._databaseTableViews.get(database); 610 611 if (!tableViews) 612 return; 613 614 var tableNamesHash = {}; 615 var self = this; 616 function tableNamesCallback(tableNames) 617 { 618 var tableNamesLength = tableNames.length; 619 for (var i = 0; i < tableNamesLength; ++i) 620 tableNamesHash[tableNames[i]] = true; 621 622 for (var tableName in tableViews) { 623 if (!(tableName in tableNamesHash)) { 624 if (self.visibleView === tableViews[tableName]) 625 self.closeVisibleView(); 626 delete tableViews[tableName]; 627 } 628 } 629 } 630 database.getTableNames(tableNamesCallback); 631 }, 632 633 _populateDOMStorageTree: function() 634 { 635 WebInspector.domStorageModel.storages().forEach(this._addDOMStorage.bind(this)); 636 WebInspector.domStorageModel.addEventListener(WebInspector.DOMStorageModel.Events.DOMStorageAdded, this._domStorageAdded, this); 637 WebInspector.domStorageModel.addEventListener(WebInspector.DOMStorageModel.Events.DOMStorageRemoved, this._domStorageRemoved, this); 638 }, 639 640 _populateApplicationCacheTree: function() 641 { 642 this._applicationCacheModel = new WebInspector.ApplicationCacheModel(); 643 644 this._applicationCacheViews = {}; 645 this._applicationCacheFrameElements = {}; 646 this._applicationCacheManifestElements = {}; 647 648 this._applicationCacheModel.addEventListener(WebInspector.ApplicationCacheModel.EventTypes.FrameManifestAdded, this._applicationCacheFrameManifestAdded, this); 649 this._applicationCacheModel.addEventListener(WebInspector.ApplicationCacheModel.EventTypes.FrameManifestRemoved, this._applicationCacheFrameManifestRemoved, this); 650 651 this._applicationCacheModel.addEventListener(WebInspector.ApplicationCacheModel.EventTypes.FrameManifestStatusUpdated, this._applicationCacheFrameManifestStatusChanged, this); 652 this._applicationCacheModel.addEventListener(WebInspector.ApplicationCacheModel.EventTypes.NetworkStateChanged, this._applicationCacheNetworkStateChanged, this); 653 }, 654 655 _applicationCacheFrameManifestAdded: function(event) 656 { 657 var frameId = event.data; 658 var manifestURL = this._applicationCacheModel.frameManifestURL(frameId); 659 var status = this._applicationCacheModel.frameManifestStatus(frameId) 660 661 var manifestTreeElement = this._applicationCacheManifestElements[manifestURL] 662 if (!manifestTreeElement) { 663 manifestTreeElement = new WebInspector.ApplicationCacheManifestTreeElement(this, manifestURL); 664 this.applicationCacheListTreeElement.appendChild(manifestTreeElement); 665 this._applicationCacheManifestElements[manifestURL] = manifestTreeElement; 666 } 667 668 var frameTreeElement = new WebInspector.ApplicationCacheFrameTreeElement(this, frameId, manifestURL); 669 manifestTreeElement.appendChild(frameTreeElement); 670 manifestTreeElement.expand(); 671 this._applicationCacheFrameElements[frameId] = frameTreeElement; 672 }, 673 674 _applicationCacheFrameManifestRemoved: function(event) 675 { 676 var frameId = event.data; 677 var frameTreeElement = this._applicationCacheFrameElements[frameId]; 678 if (!frameTreeElement) 679 return; 680 681 var manifestURL = frameTreeElement.manifestURL; 682 delete this._applicationCacheFrameElements[frameId]; 683 delete this._applicationCacheViews[frameId]; 684 frameTreeElement.parent.removeChild(frameTreeElement); 685 686 var manifestTreeElement = this._applicationCacheManifestElements[manifestURL]; 687 if (manifestTreeElement.children.length !== 0) 688 return; 689 690 delete this._applicationCacheManifestElements[manifestURL]; 691 manifestTreeElement.parent.removeChild(manifestTreeElement); 692 }, 693 694 _applicationCacheFrameManifestStatusChanged: function(event) 695 { 696 var frameId = event.data; 697 var status = this._applicationCacheModel.frameManifestStatus(frameId) 698 699 if (this._applicationCacheViews[frameId]) 700 this._applicationCacheViews[frameId].updateStatus(status); 701 }, 702 703 _applicationCacheNetworkStateChanged: function(event) 704 { 705 var isNowOnline = event.data; 706 707 for (var manifestURL in this._applicationCacheViews) 708 this._applicationCacheViews[manifestURL].updateNetworkState(isNowOnline); 709 }, 710 711 sidebarResized: function(event) 712 { 713 var width = event.data; 714 this.storageViewStatusBarItemsContainer.style.left = width + "px"; 715 }, 716 717 /** 718 * @param {string} query 719 * @param {boolean} shouldJump 720 */ 721 performSearch: function(query, shouldJump) 722 { 723 this._resetSearchResults(); 724 var regex = WebInspector.SourceFrame.createSearchRegex(query); 725 var totalMatchesCount = 0; 726 727 /** 728 * @param {WebInspector.Resource} resource 729 * @param {number} matchesCount 730 */ 731 function addMatchesToResource(resource, matchesCount) 732 { 733 this._findTreeElementForResource(resource).searchMatchesFound(matchesCount); 734 totalMatchesCount += matchesCount; 735 } 736 737 /** 738 * @param {?Protocol.Error} error 739 * @param {Array.<PageAgent.SearchResult>} result 740 */ 741 function searchInResourcesCallback(error, result) 742 { 743 if (error) 744 return; 745 746 for (var i = 0; i < result.length; i++) { 747 var searchResult = result[i]; 748 var frameTreeElement = this._treeElementForFrameId[searchResult.frameId]; 749 if (!frameTreeElement) 750 continue; 751 var resource = frameTreeElement.resourceByURL(searchResult.url); 752 753 // FIXME: When the same script is used in several frames and this script contains at least 754 // one search result then some search results can not be matched with a resource on panel. 755 // https://bugs.webkit.org/show_bug.cgi?id=66005 756 if (!resource) 757 continue; 758 759 addMatchesToResource.call(this, resource, searchResult.matchesCount) 760 } 761 if (!--callbacksLeft) 762 searchFinished.call(this); 763 } 764 765 /** 766 * @param {WebInspector.Resource} resource 767 * @param {Array.<WebInspector.ContentProvider.SearchMatch>} result 768 */ 769 function searchInContentCallback(resource, result) 770 { 771 addMatchesToResource.call(this, resource, result.length); 772 if (!--callbacksLeft) 773 searchFinished.call(this); 774 } 775 776 function searchFinished() 777 { 778 WebInspector.searchController.updateSearchMatchesCount(totalMatchesCount, this); 779 this._searchController = new WebInspector.ResourcesSearchController(this.resourcesListTreeElement, totalMatchesCount); 780 781 if (shouldJump && this.sidebarTree.selectedTreeElement && this.sidebarTree.selectedTreeElement.searchMatchesCount) 782 this.jumpToNextSearchResult(); 783 } 784 785 var frames = WebInspector.resourceTreeModel.frames(); 786 var callbacksLeft = 1 + frames.length; 787 for (var i = 0; i < frames.length; ++i) { 788 var mainResource = frames[i].mainResource; 789 mainResource.searchInContent(regex.source, !regex.ignoreCase, true, searchInContentCallback.bind(this, mainResource)); 790 } 791 PageAgent.searchInResources(regex.source, !regex.ignoreCase, true, searchInResourcesCallback.bind(this)); 792 }, 793 794 _ensureViewSearchPerformed: function(callback) 795 { 796 function viewSearchPerformedCallback(searchId) 797 { 798 if (searchId !== this._lastViewSearchId) 799 return; // Search is obsolete. 800 this._viewSearchInProgress = false; 801 callback(); 802 } 803 804 if (!this._viewSearchInProgress) { 805 if (!this.visibleView.hasSearchResults()) { 806 // We give id to each search, so that we can skip callbacks for obsolete searches. 807 this._lastViewSearchId = this._lastViewSearchId ? this._lastViewSearchId + 1 : 0; 808 this._viewSearchInProgress = true; 809 this.visibleView.performSearch(this.currentQuery, false, viewSearchPerformedCallback.bind(this, this._lastViewSearchId)); 810 } else 811 callback(); 812 } 813 }, 814 815 _showSearchResult: function(searchResult) 816 { 817 this._lastSearchResultIndex = searchResult.index; 818 this._lastSearchResultTreeElement = searchResult.treeElement; 819 820 // At first show view for treeElement. 821 if (searchResult.treeElement !== this.sidebarTree.selectedTreeElement) 822 this.showResource(searchResult.treeElement.representedObject); 823 824 function callback(searchId) 825 { 826 if (this.sidebarTree.selectedTreeElement !== this._lastSearchResultTreeElement) 827 return; // User has selected another view while we were searching. 828 if (this._lastSearchResultIndex != -1) 829 this.visibleView.jumpToSearchResult(this._lastSearchResultIndex); 830 WebInspector.searchController.updateCurrentMatchIndex(searchResult.currentMatchIndex - 1, this); 831 } 832 833 // Then run SourceFrame search if needed and jump to search result index when done. 834 this._ensureViewSearchPerformed(callback.bind(this)); 835 }, 836 837 _resetSearchResults: function() 838 { 839 function callback(resourceTreeElement) 840 { 841 resourceTreeElement._resetSearchResults(); 842 } 843 844 this._forAllResourceTreeElements(callback); 845 if (this.visibleView && this.visibleView.searchCanceled) 846 this.visibleView.searchCanceled(); 847 848 this._lastSearchResultTreeElement = null; 849 this._lastSearchResultIndex = -1; 850 this._viewSearchInProgress = false; 851 }, 852 853 searchCanceled: function() 854 { 855 function callback(resourceTreeElement) 856 { 857 resourceTreeElement._updateErrorsAndWarningsBubbles(); 858 } 859 860 WebInspector.searchController.updateSearchMatchesCount(0, this); 861 this._resetSearchResults(); 862 this._forAllResourceTreeElements(callback); 863 }, 864 865 jumpToNextSearchResult: function() 866 { 867 if (!this.currentSearchMatches) 868 return; 869 var currentTreeElement = this.sidebarTree.selectedTreeElement; 870 var nextSearchResult = this._searchController.nextSearchResult(currentTreeElement); 871 this._showSearchResult(nextSearchResult); 872 }, 873 874 jumpToPreviousSearchResult: function() 875 { 876 if (!this.currentSearchMatches) 877 return; 878 var currentTreeElement = this.sidebarTree.selectedTreeElement; 879 var previousSearchResult = this._searchController.previousSearchResult(currentTreeElement); 880 this._showSearchResult(previousSearchResult); 881 }, 882 883 _forAllResourceTreeElements: function(callback) 884 { 885 var stop = false; 886 for (var treeElement = this.resourcesListTreeElement; !stop && treeElement; treeElement = treeElement.traverseNextTreeElement(false, this.resourcesListTreeElement, true)) { 887 if (treeElement instanceof WebInspector.FrameResourceTreeElement) 888 stop = callback(treeElement); 889 } 890 }, 891 892 _findTreeElementForResource: function(resource) 893 { 894 function isAncestor(ancestor, object) 895 { 896 // Redirects, XHRs do not belong to the tree, it is fine to silently return false here. 897 return false; 898 } 899 900 function getParent(object) 901 { 902 // Redirects, XHRs do not belong to the tree, it is fine to silently return false here. 903 return null; 904 } 905 906 return this.sidebarTree.findTreeElement(resource, isAncestor, getParent); 907 }, 908 909 showView: function(view) 910 { 911 if (view) 912 this.showResource(view.resource); 913 }, 914 915 _onmousemove: function(event) 916 { 917 var nodeUnderMouse = document.elementFromPoint(event.pageX, event.pageY); 918 if (!nodeUnderMouse) 919 return; 920 921 var listNode = nodeUnderMouse.enclosingNodeOrSelfWithNodeName("li"); 922 if (!listNode) 923 return; 924 925 var element = listNode.treeElement; 926 if (this._previousHoveredElement === element) 927 return; 928 929 if (this._previousHoveredElement) { 930 this._previousHoveredElement.hovered = false; 931 delete this._previousHoveredElement; 932 } 933 934 if (element instanceof WebInspector.FrameTreeElement) { 935 this._previousHoveredElement = element; 936 element.hovered = true; 937 } 938 }, 939 940 _onmouseout: function(event) 941 { 942 if (this._previousHoveredElement) { 943 this._previousHoveredElement.hovered = false; 944 delete this._previousHoveredElement; 945 } 946 }, 947 948 __proto__: WebInspector.Panel.prototype 949 } 950 951 /** 952 * @constructor 953 * @extends {TreeElement} 954 * @param {boolean=} hasChildren 955 * @param {boolean=} noIcon 956 */ 957 WebInspector.BaseStorageTreeElement = function(storagePanel, representedObject, title, iconClasses, hasChildren, noIcon) 958 { 959 TreeElement.call(this, "", representedObject, hasChildren); 960 this._storagePanel = storagePanel; 961 this._titleText = title; 962 this._iconClasses = iconClasses; 963 this._noIcon = noIcon; 964 } 965 966 WebInspector.BaseStorageTreeElement.prototype = { 967 onattach: function() 968 { 969 this.listItemElement.removeChildren(); 970 if (this._iconClasses) { 971 for (var i = 0; i < this._iconClasses.length; ++i) 972 this.listItemElement.addStyleClass(this._iconClasses[i]); 973 } 974 975 var selectionElement = document.createElement("div"); 976 selectionElement.className = "selection"; 977 this.listItemElement.appendChild(selectionElement); 978 979 if (!this._noIcon) { 980 this.imageElement = document.createElement("img"); 981 this.imageElement.className = "icon"; 982 this.listItemElement.appendChild(this.imageElement); 983 } 984 985 this.titleElement = document.createElement("div"); 986 this.titleElement.className = "base-storage-tree-element-title"; 987 this._titleTextNode = document.createTextNode(""); 988 this.titleElement.appendChild(this._titleTextNode); 989 this._updateTitle(); 990 this._updateSubtitle(); 991 this.listItemElement.appendChild(this.titleElement); 992 }, 993 994 get displayName() 995 { 996 return this._displayName; 997 }, 998 999 _updateDisplayName: function() 1000 { 1001 this._displayName = this._titleText || ""; 1002 if (this._subtitleText) 1003 this._displayName += " (" + this._subtitleText + ")"; 1004 }, 1005 1006 _updateTitle: function() 1007 { 1008 this._updateDisplayName(); 1009 1010 if (!this.titleElement) 1011 return; 1012 1013 this._titleTextNode.textContent = this._titleText || ""; 1014 }, 1015 1016 _updateSubtitle: function() 1017 { 1018 this._updateDisplayName(); 1019 1020 if (!this.titleElement) 1021 return; 1022 1023 if (this._subtitleText) { 1024 if (!this._subtitleElement) { 1025 this._subtitleElement = document.createElement("span"); 1026 this._subtitleElement.className = "base-storage-tree-element-subtitle"; 1027 this.titleElement.appendChild(this._subtitleElement); 1028 } 1029 this._subtitleElement.textContent = "(" + this._subtitleText + ")"; 1030 } else if (this._subtitleElement) { 1031 this.titleElement.removeChild(this._subtitleElement); 1032 delete this._subtitleElement; 1033 } 1034 }, 1035 1036 onselect: function(selectedByUser) 1037 { 1038 if (!selectedByUser) 1039 return; 1040 var itemURL = this.itemURL; 1041 if (itemURL) 1042 WebInspector.settings.resourcesLastSelectedItem.set(itemURL); 1043 }, 1044 1045 onreveal: function() 1046 { 1047 if (this.listItemElement) 1048 this.listItemElement.scrollIntoViewIfNeeded(false); 1049 }, 1050 1051 get titleText() 1052 { 1053 return this._titleText; 1054 }, 1055 1056 set titleText(titleText) 1057 { 1058 this._titleText = titleText; 1059 this._updateTitle(); 1060 }, 1061 1062 get subtitleText() 1063 { 1064 return this._subtitleText; 1065 }, 1066 1067 set subtitleText(subtitleText) 1068 { 1069 this._subtitleText = subtitleText; 1070 this._updateSubtitle(); 1071 }, 1072 1073 get searchMatchesCount() 1074 { 1075 return 0; 1076 }, 1077 1078 __proto__: TreeElement.prototype 1079 } 1080 1081 /** 1082 * @constructor 1083 * @extends {WebInspector.BaseStorageTreeElement} 1084 * @param {boolean=} noIcon 1085 */ 1086 WebInspector.StorageCategoryTreeElement = function(storagePanel, categoryName, settingsKey, iconClasses, noIcon) 1087 { 1088 WebInspector.BaseStorageTreeElement.call(this, storagePanel, null, categoryName, iconClasses, true, noIcon); 1089 this._expandedSettingKey = "resources" + settingsKey + "Expanded"; 1090 WebInspector.settings[this._expandedSettingKey] = WebInspector.settings.createSetting(this._expandedSettingKey, settingsKey === "Frames"); 1091 this._categoryName = categoryName; 1092 } 1093 1094 WebInspector.StorageCategoryTreeElement.prototype = { 1095 get itemURL() 1096 { 1097 return "category://" + this._categoryName; 1098 }, 1099 1100 onselect: function(selectedByUser) 1101 { 1102 WebInspector.BaseStorageTreeElement.prototype.onselect.call(this, selectedByUser); 1103 this._storagePanel.showCategoryView(this._categoryName); 1104 }, 1105 1106 onattach: function() 1107 { 1108 WebInspector.BaseStorageTreeElement.prototype.onattach.call(this); 1109 if (WebInspector.settings[this._expandedSettingKey].get()) 1110 this.expand(); 1111 }, 1112 1113 onexpand: function() 1114 { 1115 WebInspector.settings[this._expandedSettingKey].set(true); 1116 }, 1117 1118 oncollapse: function() 1119 { 1120 WebInspector.settings[this._expandedSettingKey].set(false); 1121 }, 1122 1123 __proto__: WebInspector.BaseStorageTreeElement.prototype 1124 } 1125 1126 /** 1127 * @constructor 1128 * @extends {WebInspector.BaseStorageTreeElement} 1129 */ 1130 WebInspector.FrameTreeElement = function(storagePanel, frame) 1131 { 1132 WebInspector.BaseStorageTreeElement.call(this, storagePanel, null, "", ["frame-storage-tree-item"]); 1133 this._frame = frame; 1134 this.frameNavigated(frame); 1135 } 1136 1137 WebInspector.FrameTreeElement.prototype = { 1138 frameNavigated: function(frame) 1139 { 1140 this.removeChildren(); 1141 this._frameId = frame.id; 1142 1143 this.titleText = frame.name; 1144 this.subtitleText = new WebInspector.ParsedURL(frame.url).displayName; 1145 1146 this._categoryElements = {}; 1147 this._treeElementForResource = {}; 1148 1149 this._storagePanel.addDocumentURL(frame.url); 1150 }, 1151 1152 get itemURL() 1153 { 1154 return "frame://" + encodeURI(this.displayName); 1155 }, 1156 1157 onselect: function(selectedByUser) 1158 { 1159 WebInspector.BaseStorageTreeElement.prototype.onselect.call(this, selectedByUser); 1160 this._storagePanel.showCategoryView(this.displayName); 1161 1162 this.listItemElement.removeStyleClass("hovered"); 1163 DOMAgent.hideHighlight(); 1164 }, 1165 1166 set hovered(hovered) 1167 { 1168 if (hovered) { 1169 this.listItemElement.addStyleClass("hovered"); 1170 DOMAgent.highlightFrame(this._frameId, WebInspector.Color.PageHighlight.Content.toProtocolRGBA(), WebInspector.Color.PageHighlight.ContentOutline.toProtocolRGBA()); 1171 } else { 1172 this.listItemElement.removeStyleClass("hovered"); 1173 DOMAgent.hideHighlight(); 1174 } 1175 }, 1176 1177 appendResource: function(resource) 1178 { 1179 if (resource.isHidden()) 1180 return; 1181 var categoryName = resource.type.name(); 1182 var categoryElement = resource.type === WebInspector.resourceTypes.Document ? this : this._categoryElements[categoryName]; 1183 if (!categoryElement) { 1184 categoryElement = new WebInspector.StorageCategoryTreeElement(this._storagePanel, resource.type.categoryTitle(), categoryName, null, true); 1185 this._categoryElements[resource.type.name()] = categoryElement; 1186 this._insertInPresentationOrder(this, categoryElement); 1187 } 1188 var resourceTreeElement = new WebInspector.FrameResourceTreeElement(this._storagePanel, resource); 1189 this._insertInPresentationOrder(categoryElement, resourceTreeElement); 1190 this._treeElementForResource[resource.url] = resourceTreeElement; 1191 }, 1192 1193 resourceByURL: function(url) 1194 { 1195 var treeElement = this._treeElementForResource[url]; 1196 return treeElement ? treeElement.representedObject : null; 1197 }, 1198 1199 appendChild: function(treeElement) 1200 { 1201 this._insertInPresentationOrder(this, treeElement); 1202 }, 1203 1204 _insertInPresentationOrder: function(parentTreeElement, childTreeElement) 1205 { 1206 // Insert in the alphabetical order, first frames, then resources. Document resource goes last. 1207 function typeWeight(treeElement) 1208 { 1209 if (treeElement instanceof WebInspector.StorageCategoryTreeElement) 1210 return 2; 1211 if (treeElement instanceof WebInspector.FrameTreeElement) 1212 return 1; 1213 return 3; 1214 } 1215 1216 function compare(treeElement1, treeElement2) 1217 { 1218 var typeWeight1 = typeWeight(treeElement1); 1219 var typeWeight2 = typeWeight(treeElement2); 1220 1221 var result; 1222 if (typeWeight1 > typeWeight2) 1223 result = 1; 1224 else if (typeWeight1 < typeWeight2) 1225 result = -1; 1226 else { 1227 var title1 = treeElement1.displayName || treeElement1.titleText; 1228 var title2 = treeElement2.displayName || treeElement2.titleText; 1229 result = title1.localeCompare(title2); 1230 } 1231 return result; 1232 } 1233 1234 var children = parentTreeElement.children; 1235 var i; 1236 for (i = 0; i < children.length; ++i) { 1237 if (compare(childTreeElement, children[i]) < 0) 1238 break; 1239 } 1240 parentTreeElement.insertChild(childTreeElement, i); 1241 }, 1242 1243 __proto__: WebInspector.BaseStorageTreeElement.prototype 1244 } 1245 1246 /** 1247 * @constructor 1248 * @extends {WebInspector.BaseStorageTreeElement} 1249 */ 1250 WebInspector.FrameResourceTreeElement = function(storagePanel, resource) 1251 { 1252 WebInspector.BaseStorageTreeElement.call(this, storagePanel, resource, resource.displayName, ["resource-sidebar-tree-item", "resources-type-" + resource.type.name()]); 1253 this._resource = resource; 1254 this._resource.addEventListener(WebInspector.Resource.Events.MessageAdded, this._consoleMessageAdded, this); 1255 this._resource.addEventListener(WebInspector.Resource.Events.MessagesCleared, this._consoleMessagesCleared, this); 1256 this.tooltip = resource.url; 1257 } 1258 1259 WebInspector.FrameResourceTreeElement.prototype = { 1260 get itemURL() 1261 { 1262 return this._resource.url; 1263 }, 1264 1265 onselect: function(selectedByUser) 1266 { 1267 WebInspector.BaseStorageTreeElement.prototype.onselect.call(this, selectedByUser); 1268 this._storagePanel._showResourceView(this._resource); 1269 }, 1270 1271 ondblclick: function(event) 1272 { 1273 InspectorFrontendHost.openInNewTab(this._resource.url); 1274 }, 1275 1276 onattach: function() 1277 { 1278 WebInspector.BaseStorageTreeElement.prototype.onattach.call(this); 1279 1280 if (this._resource.type === WebInspector.resourceTypes.Image) { 1281 var previewImage = document.createElement("img"); 1282 previewImage.className = "image-resource-icon-preview"; 1283 this._resource.populateImageSource(previewImage); 1284 1285 var iconElement = document.createElement("div"); 1286 iconElement.className = "icon"; 1287 iconElement.appendChild(previewImage); 1288 this.listItemElement.replaceChild(iconElement, this.imageElement); 1289 } 1290 1291 this._statusElement = document.createElement("div"); 1292 this._statusElement.className = "status"; 1293 this.listItemElement.insertBefore(this._statusElement, this.titleElement); 1294 1295 this.listItemElement.draggable = true; 1296 this.listItemElement.addEventListener("dragstart", this._ondragstart.bind(this), false); 1297 this.listItemElement.addEventListener("contextmenu", this._handleContextMenuEvent.bind(this), true); 1298 1299 this._updateErrorsAndWarningsBubbles(); 1300 }, 1301 1302 _ondragstart: function(event) 1303 { 1304 event.dataTransfer.setData("text/plain", this._resource.content); 1305 event.dataTransfer.effectAllowed = "copy"; 1306 return true; 1307 }, 1308 1309 _handleContextMenuEvent: function(event) 1310 { 1311 var contextMenu = new WebInspector.ContextMenu(event); 1312 contextMenu.appendApplicableItems(this._resource); 1313 if (this._resource.request) 1314 contextMenu.appendApplicableItems(this._resource.request); 1315 contextMenu.show(); 1316 }, 1317 1318 _setBubbleText: function(x) 1319 { 1320 if (!this._bubbleElement) { 1321 this._bubbleElement = document.createElement("div"); 1322 this._bubbleElement.className = "bubble"; 1323 this._statusElement.appendChild(this._bubbleElement); 1324 } 1325 1326 this._bubbleElement.textContent = x; 1327 }, 1328 1329 _resetBubble: function() 1330 { 1331 if (this._bubbleElement) { 1332 this._bubbleElement.textContent = ""; 1333 this._bubbleElement.removeStyleClass("search-matches"); 1334 this._bubbleElement.removeStyleClass("warning"); 1335 this._bubbleElement.removeStyleClass("error"); 1336 } 1337 }, 1338 1339 _resetSearchResults: function() 1340 { 1341 this._resetBubble(); 1342 this._searchMatchesCount = 0; 1343 }, 1344 1345 get searchMatchesCount() 1346 { 1347 return this._searchMatchesCount; 1348 }, 1349 1350 searchMatchesFound: function(matchesCount) 1351 { 1352 this._resetSearchResults(); 1353 1354 this._searchMatchesCount = matchesCount; 1355 this._setBubbleText(matchesCount); 1356 this._bubbleElement.addStyleClass("search-matches"); 1357 1358 // Expand, do not scroll into view. 1359 var currentAncestor = this.parent; 1360 while (currentAncestor && !currentAncestor.root) { 1361 if (!currentAncestor.expanded) 1362 currentAncestor.expand(); 1363 currentAncestor = currentAncestor.parent; 1364 } 1365 }, 1366 1367 _updateErrorsAndWarningsBubbles: function() 1368 { 1369 if (this._storagePanel.currentQuery) 1370 return; 1371 1372 this._resetBubble(); 1373 1374 if (this._resource.warnings || this._resource.errors) 1375 this._setBubbleText(this._resource.warnings + this._resource.errors); 1376 1377 if (this._resource.warnings) 1378 this._bubbleElement.addStyleClass("warning"); 1379 1380 if (this._resource.errors) 1381 this._bubbleElement.addStyleClass("error"); 1382 }, 1383 1384 _consoleMessagesCleared: function() 1385 { 1386 // FIXME: move to the SourceFrame. 1387 if (this._sourceView) 1388 this._sourceView.clearMessages(); 1389 1390 this._updateErrorsAndWarningsBubbles(); 1391 }, 1392 1393 _consoleMessageAdded: function(event) 1394 { 1395 var msg = event.data; 1396 if (this._sourceView) 1397 this._sourceView.addMessage(msg); 1398 this._updateErrorsAndWarningsBubbles(); 1399 }, 1400 1401 sourceView: function() 1402 { 1403 if (!this._sourceView) { 1404 this._sourceView = new WebInspector.ResourceSourceFrame(this._resource); 1405 if (this._resource.messages) { 1406 for (var i = 0; i < this._resource.messages.length; i++) 1407 this._sourceView.addMessage(this._resource.messages[i]); 1408 } 1409 } 1410 return this._sourceView; 1411 }, 1412 1413 __proto__: WebInspector.BaseStorageTreeElement.prototype 1414 } 1415 1416 /** 1417 * @constructor 1418 * @extends {WebInspector.BaseStorageTreeElement} 1419 * @param {WebInspector.Database} database 1420 */ 1421 WebInspector.DatabaseTreeElement = function(storagePanel, database) 1422 { 1423 WebInspector.BaseStorageTreeElement.call(this, storagePanel, null, database.name, ["database-storage-tree-item"], true); 1424 this._database = database; 1425 } 1426 1427 WebInspector.DatabaseTreeElement.prototype = { 1428 get itemURL() 1429 { 1430 return "database://" + encodeURI(this._database.name); 1431 }, 1432 1433 onselect: function(selectedByUser) 1434 { 1435 WebInspector.BaseStorageTreeElement.prototype.onselect.call(this, selectedByUser); 1436 this._storagePanel._showDatabase(this._database); 1437 }, 1438 1439 onexpand: function() 1440 { 1441 this._updateChildren(); 1442 }, 1443 1444 _updateChildren: function() 1445 { 1446 this.removeChildren(); 1447 1448 function tableNamesCallback(tableNames) 1449 { 1450 var tableNamesLength = tableNames.length; 1451 for (var i = 0; i < tableNamesLength; ++i) 1452 this.appendChild(new WebInspector.DatabaseTableTreeElement(this._storagePanel, this._database, tableNames[i])); 1453 } 1454 this._database.getTableNames(tableNamesCallback.bind(this)); 1455 }, 1456 1457 __proto__: WebInspector.BaseStorageTreeElement.prototype 1458 } 1459 1460 /** 1461 * @constructor 1462 * @extends {WebInspector.BaseStorageTreeElement} 1463 */ 1464 WebInspector.DatabaseTableTreeElement = function(storagePanel, database, tableName) 1465 { 1466 WebInspector.BaseStorageTreeElement.call(this, storagePanel, null, tableName, ["database-storage-tree-item"]); 1467 this._database = database; 1468 this._tableName = tableName; 1469 } 1470 1471 WebInspector.DatabaseTableTreeElement.prototype = { 1472 get itemURL() 1473 { 1474 return "database://" + encodeURI(this._database.name) + "/" + encodeURI(this._tableName); 1475 }, 1476 1477 onselect: function(selectedByUser) 1478 { 1479 WebInspector.BaseStorageTreeElement.prototype.onselect.call(this, selectedByUser); 1480 this._storagePanel._showDatabase(this._database, this._tableName); 1481 }, 1482 1483 __proto__: WebInspector.BaseStorageTreeElement.prototype 1484 } 1485 1486 /** 1487 * @constructor 1488 * @extends {WebInspector.StorageCategoryTreeElement} 1489 * @param {WebInspector.ResourcesPanel} storagePanel 1490 */ 1491 WebInspector.IndexedDBTreeElement = function(storagePanel) 1492 { 1493 WebInspector.StorageCategoryTreeElement.call(this, storagePanel, WebInspector.UIString("IndexedDB"), "IndexedDB", ["indexed-db-storage-tree-item"]); 1494 } 1495 1496 WebInspector.IndexedDBTreeElement.prototype = { 1497 onexpand: function() 1498 { 1499 WebInspector.StorageCategoryTreeElement.prototype.onexpand.call(this); 1500 if (!this._indexedDBModel) 1501 this._createIndexedDBModel(); 1502 }, 1503 1504 onattach: function() 1505 { 1506 WebInspector.StorageCategoryTreeElement.prototype.onattach.call(this); 1507 this.listItemElement.addEventListener("contextmenu", this._handleContextMenuEvent.bind(this), true); 1508 }, 1509 1510 _handleContextMenuEvent: function(event) 1511 { 1512 var contextMenu = new WebInspector.ContextMenu(event); 1513 contextMenu.appendItem(WebInspector.UIString("Refresh IndexedDB"), this.refreshIndexedDB.bind(this)); 1514 contextMenu.show(); 1515 }, 1516 1517 _createIndexedDBModel: function() 1518 { 1519 this._indexedDBModel = new WebInspector.IndexedDBModel(); 1520 this._idbDatabaseTreeElements = []; 1521 this._indexedDBModel.addEventListener(WebInspector.IndexedDBModel.EventTypes.DatabaseAdded, this._indexedDBAdded, this); 1522 this._indexedDBModel.addEventListener(WebInspector.IndexedDBModel.EventTypes.DatabaseRemoved, this._indexedDBRemoved, this); 1523 this._indexedDBModel.addEventListener(WebInspector.IndexedDBModel.EventTypes.DatabaseLoaded, this._indexedDBLoaded, this); 1524 }, 1525 1526 refreshIndexedDB: function() 1527 { 1528 if (!this._indexedDBModel) { 1529 this._createIndexedDBModel(); 1530 return; 1531 } 1532 1533 this._indexedDBModel.refreshDatabaseNames(); 1534 }, 1535 1536 /** 1537 * @param {WebInspector.Event} event 1538 */ 1539 _indexedDBAdded: function(event) 1540 { 1541 var databaseId = /** @type {WebInspector.IndexedDBModel.DatabaseId} */ (event.data); 1542 1543 var idbDatabaseTreeElement = new WebInspector.IDBDatabaseTreeElement(this._storagePanel, this._indexedDBModel, databaseId); 1544 this._idbDatabaseTreeElements.push(idbDatabaseTreeElement); 1545 this.appendChild(idbDatabaseTreeElement); 1546 1547 this._indexedDBModel.refreshDatabase(databaseId); 1548 }, 1549 1550 /** 1551 * @param {WebInspector.Event} event 1552 */ 1553 _indexedDBRemoved: function(event) 1554 { 1555 var databaseId = /** @type {WebInspector.IndexedDBModel.DatabaseId} */ (event.data); 1556 1557 var idbDatabaseTreeElement = this._idbDatabaseTreeElement(databaseId) 1558 if (!idbDatabaseTreeElement) 1559 return; 1560 1561 idbDatabaseTreeElement.clear(); 1562 this.removeChild(idbDatabaseTreeElement); 1563 this._idbDatabaseTreeElements.remove(idbDatabaseTreeElement); 1564 }, 1565 1566 /** 1567 * @param {WebInspector.Event} event 1568 */ 1569 _indexedDBLoaded: function(event) 1570 { 1571 var database = /** @type {WebInspector.IndexedDBModel.Database} */ (event.data); 1572 1573 var idbDatabaseTreeElement = this._idbDatabaseTreeElement(database.databaseId) 1574 if (!idbDatabaseTreeElement) 1575 return; 1576 1577 idbDatabaseTreeElement.update(database); 1578 }, 1579 1580 /** 1581 * @param {WebInspector.IndexedDBModel.DatabaseId} databaseId 1582 * @return {WebInspector.IDBDatabaseTreeElement} 1583 */ 1584 _idbDatabaseTreeElement: function(databaseId) 1585 { 1586 var index = -1; 1587 for (var i = 0; i < this._idbDatabaseTreeElements.length; ++i) { 1588 if (this._idbDatabaseTreeElements[i]._databaseId.equals(databaseId)) { 1589 index = i; 1590 break; 1591 } 1592 } 1593 if (index !== -1) 1594 return this._idbDatabaseTreeElements[i]; 1595 return null; 1596 }, 1597 1598 __proto__: WebInspector.StorageCategoryTreeElement.prototype 1599 } 1600 1601 /** 1602 * @constructor 1603 * @extends {WebInspector.StorageCategoryTreeElement} 1604 * @param {WebInspector.ResourcesPanel} storagePanel 1605 */ 1606 WebInspector.FileSystemListTreeElement = function(storagePanel) 1607 { 1608 WebInspector.StorageCategoryTreeElement.call(this, storagePanel, WebInspector.UIString("FileSystem"), "FileSystem", ["file-system-storage-tree-item"]); 1609 } 1610 1611 WebInspector.FileSystemListTreeElement.prototype = { 1612 onexpand: function() 1613 { 1614 WebInspector.StorageCategoryTreeElement.prototype.onexpand.call(this); 1615 this._refreshFileSystem(); 1616 }, 1617 1618 onattach: function() 1619 { 1620 WebInspector.StorageCategoryTreeElement.prototype.onattach.call(this); 1621 this.listItemElement.addEventListener("contextmenu", this._handleContextMenuEvent.bind(this), true); 1622 }, 1623 1624 _handleContextMenuEvent: function(event) 1625 { 1626 var contextMenu = new WebInspector.ContextMenu(event); 1627 contextMenu.appendItem(WebInspector.UIString(WebInspector.useLowerCaseMenuTitles() ? "Refresh FileSystem list" : "Refresh FileSystem List"), this._refreshFileSystem.bind(this)); 1628 contextMenu.show(); 1629 }, 1630 1631 _fileSystemAdded: function(event) 1632 { 1633 var fileSystem = /** @type {WebInspector.FileSystemModel.FileSystem} */ (event.data); 1634 var fileSystemTreeElement = new WebInspector.FileSystemTreeElement(this._storagePanel, fileSystem); 1635 this.appendChild(fileSystemTreeElement); 1636 }, 1637 1638 _fileSystemRemoved: function(event) 1639 { 1640 var fileSystem = /** @type {WebInspector.FileSystemModel.FileSystem} */ (event.data); 1641 var fileSystemTreeElement = this._fileSystemTreeElementByName(fileSystem.name); 1642 if (!fileSystemTreeElement) 1643 return; 1644 fileSystemTreeElement.clear(); 1645 this.removeChild(fileSystemTreeElement); 1646 }, 1647 1648 _fileSystemTreeElementByName: function(fileSystemName) 1649 { 1650 for (var i = 0; i < this.children.length; ++i) { 1651 var child = /** @type {WebInspector.FileSystemTreeElement} */ (this.children[i]); 1652 if (child.fileSystemName === fileSystemName) 1653 return this.children[i]; 1654 } 1655 return null; 1656 }, 1657 1658 _refreshFileSystem: function() 1659 { 1660 if (!this._fileSystemModel) { 1661 this._fileSystemModel = new WebInspector.FileSystemModel(); 1662 this._fileSystemModel.addEventListener(WebInspector.FileSystemModel.EventTypes.FileSystemAdded, this._fileSystemAdded, this); 1663 this._fileSystemModel.addEventListener(WebInspector.FileSystemModel.EventTypes.FileSystemRemoved, this._fileSystemRemoved, this); 1664 } 1665 1666 this._fileSystemModel.refreshFileSystemList(); 1667 }, 1668 1669 __proto__: WebInspector.StorageCategoryTreeElement.prototype 1670 } 1671 1672 /** 1673 * @constructor 1674 * @extends {WebInspector.BaseStorageTreeElement} 1675 * @param {WebInspector.ResourcesPanel} storagePanel 1676 * @param {WebInspector.IndexedDBModel} model 1677 * @param {WebInspector.IndexedDBModel.DatabaseId} databaseId 1678 */ 1679 WebInspector.IDBDatabaseTreeElement = function(storagePanel, model, databaseId) 1680 { 1681 WebInspector.BaseStorageTreeElement.call(this, storagePanel, null, databaseId.name + " - " + databaseId.securityOrigin, ["indexed-db-storage-tree-item"]); 1682 this._model = model; 1683 this._databaseId = databaseId; 1684 this._idbObjectStoreTreeElements = {}; 1685 } 1686 1687 WebInspector.IDBDatabaseTreeElement.prototype = { 1688 get itemURL() 1689 { 1690 return "indexedDB://" + this._databaseId.securityOrigin + "/" + this._databaseId.name; 1691 }, 1692 1693 onattach: function() 1694 { 1695 WebInspector.BaseStorageTreeElement.prototype.onattach.call(this); 1696 this.listItemElement.addEventListener("contextmenu", this._handleContextMenuEvent.bind(this), true); 1697 }, 1698 1699 _handleContextMenuEvent: function(event) 1700 { 1701 var contextMenu = new WebInspector.ContextMenu(event); 1702 contextMenu.appendItem(WebInspector.UIString("Refresh IndexedDB"), this._refreshIndexedDB.bind(this)); 1703 contextMenu.show(); 1704 }, 1705 1706 _refreshIndexedDB: function() 1707 { 1708 this._model.refreshDatabaseNames(); 1709 }, 1710 1711 /** 1712 * @param {WebInspector.IndexedDBModel.Database} database 1713 */ 1714 update: function(database) 1715 { 1716 this._database = database; 1717 var objectStoreNames = {}; 1718 for (var objectStoreName in this._database.objectStores) { 1719 var objectStore = this._database.objectStores[objectStoreName]; 1720 objectStoreNames[objectStore.name] = true; 1721 if (!this._idbObjectStoreTreeElements[objectStore.name]) { 1722 var idbObjectStoreTreeElement = new WebInspector.IDBObjectStoreTreeElement(this._storagePanel, this._model, this._databaseId, objectStore); 1723 this._idbObjectStoreTreeElements[objectStore.name] = idbObjectStoreTreeElement; 1724 this.appendChild(idbObjectStoreTreeElement); 1725 } 1726 this._idbObjectStoreTreeElements[objectStore.name].update(objectStore); 1727 } 1728 for (var objectStoreName in this._idbObjectStoreTreeElements) { 1729 if (!objectStoreNames[objectStoreName]) 1730 this._objectStoreRemoved(objectStoreName); 1731 } 1732 1733 if (this.children.length) { 1734 this.hasChildren = true; 1735 this.expand(); 1736 } 1737 1738 if (this._view) 1739 this._view.update(database); 1740 1741 this._updateTooltip(); 1742 }, 1743 1744 _updateTooltip: function() 1745 { 1746 this.tooltip = WebInspector.UIString("Version") + ": " + this._database.version; 1747 }, 1748 1749 onselect: function(selectedByUser) 1750 { 1751 WebInspector.BaseStorageTreeElement.prototype.onselect.call(this, selectedByUser); 1752 if (!this._view) 1753 this._view = new WebInspector.IDBDatabaseView(this._database); 1754 1755 this._storagePanel.showIndexedDB(this._view); 1756 }, 1757 1758 /** 1759 * @param {string} objectStoreName 1760 */ 1761 _objectStoreRemoved: function(objectStoreName) 1762 { 1763 var objectStoreTreeElement = this._idbObjectStoreTreeElements[objectStoreName]; 1764 objectStoreTreeElement.clear(); 1765 this.removeChild(objectStoreTreeElement); 1766 delete this._idbObjectStoreTreeElements[objectStoreName]; 1767 }, 1768 1769 clear: function() 1770 { 1771 for (var objectStoreName in this._idbObjectStoreTreeElements) 1772 this._objectStoreRemoved(objectStoreName); 1773 }, 1774 1775 __proto__: WebInspector.BaseStorageTreeElement.prototype 1776 } 1777 1778 /** 1779 * @constructor 1780 * @extends {WebInspector.BaseStorageTreeElement} 1781 * @param {WebInspector.ResourcesPanel} storagePanel 1782 * @param {WebInspector.IndexedDBModel} model 1783 * @param {WebInspector.IndexedDBModel.DatabaseId} databaseId 1784 * @param {WebInspector.IndexedDBModel.ObjectStore} objectStore 1785 */ 1786 WebInspector.IDBObjectStoreTreeElement = function(storagePanel, model, databaseId, objectStore) 1787 { 1788 WebInspector.BaseStorageTreeElement.call(this, storagePanel, null, objectStore.name, ["indexed-db-object-store-storage-tree-item"]); 1789 this._model = model; 1790 this._databaseId = databaseId; 1791 this._idbIndexTreeElements = {}; 1792 } 1793 1794 WebInspector.IDBObjectStoreTreeElement.prototype = { 1795 get itemURL() 1796 { 1797 return "indexedDB://" + this._databaseId.securityOrigin + "/" + this._databaseId.name + "/" + this._objectStore.name; 1798 }, 1799 1800 onattach: function() 1801 { 1802 WebInspector.BaseStorageTreeElement.prototype.onattach.call(this); 1803 this.listItemElement.addEventListener("contextmenu", this._handleContextMenuEvent.bind(this), true); 1804 }, 1805 1806 _handleContextMenuEvent: function(event) 1807 { 1808 var contextMenu = new WebInspector.ContextMenu(event); 1809 contextMenu.appendItem(WebInspector.UIString("Clear"), this._clearObjectStore.bind(this)); 1810 contextMenu.show(); 1811 }, 1812 1813 _clearObjectStore: function() 1814 { 1815 function callback() { 1816 this.update(this._objectStore); 1817 } 1818 this._model.clearObjectStore(this._databaseId, this._objectStore.name, callback.bind(this)); 1819 }, 1820 1821 /** 1822 * @param {WebInspector.IndexedDBModel.ObjectStore} objectStore 1823 */ 1824 update: function(objectStore) 1825 { 1826 this._objectStore = objectStore; 1827 1828 var indexNames = {}; 1829 for (var indexName in this._objectStore.indexes) { 1830 var index = this._objectStore.indexes[indexName]; 1831 indexNames[index.name] = true; 1832 if (!this._idbIndexTreeElements[index.name]) { 1833 var idbIndexTreeElement = new WebInspector.IDBIndexTreeElement(this._storagePanel, this._model, this._databaseId, this._objectStore, index); 1834 this._idbIndexTreeElements[index.name] = idbIndexTreeElement; 1835 this.appendChild(idbIndexTreeElement); 1836 } 1837 this._idbIndexTreeElements[index.name].update(index); 1838 } 1839 for (var indexName in this._idbIndexTreeElements) { 1840 if (!indexNames[indexName]) 1841 this._indexRemoved(indexName); 1842 } 1843 for (var indexName in this._idbIndexTreeElements) { 1844 if (!indexNames[indexName]) { 1845 this.removeChild(this._idbIndexTreeElements[indexName]); 1846 delete this._idbIndexTreeElements[indexName]; 1847 } 1848 } 1849 1850 if (this.children.length) { 1851 this.hasChildren = true; 1852 this.expand(); 1853 } 1854 1855 if (this._view) 1856 this._view.update(this._objectStore); 1857 1858 this._updateTooltip(); 1859 }, 1860 1861 _updateTooltip: function() 1862 { 1863 1864 var keyPathString = this._objectStore.keyPathString; 1865 var tooltipString = keyPathString !== null ? (WebInspector.UIString("Key path: ") + keyPathString) : ""; 1866 if (this._objectStore.autoIncrement) 1867 tooltipString += "\n" + WebInspector.UIString("autoIncrement"); 1868 this.tooltip = tooltipString 1869 }, 1870 1871 onselect: function(selectedByUser) 1872 { 1873 WebInspector.BaseStorageTreeElement.prototype.onselect.call(this, selectedByUser); 1874 if (!this._view) 1875 this._view = new WebInspector.IDBDataView(this._model, this._databaseId, this._objectStore, null); 1876 1877 this._storagePanel.showIndexedDB(this._view); 1878 }, 1879 1880 /** 1881 * @param {string} indexName 1882 */ 1883 _indexRemoved: function(indexName) 1884 { 1885 var indexTreeElement = this._idbIndexTreeElements[indexName]; 1886 indexTreeElement.clear(); 1887 this.removeChild(indexTreeElement); 1888 delete this._idbIndexTreeElements[indexName]; 1889 }, 1890 1891 clear: function() 1892 { 1893 for (var indexName in this._idbIndexTreeElements) 1894 this._indexRemoved(indexName); 1895 if (this._view) 1896 this._view.clear(); 1897 }, 1898 1899 __proto__: WebInspector.BaseStorageTreeElement.prototype 1900 } 1901 1902 /** 1903 * @constructor 1904 * @extends {WebInspector.BaseStorageTreeElement} 1905 * @param {WebInspector.ResourcesPanel} storagePanel 1906 * @param {WebInspector.IndexedDBModel} model 1907 * @param {WebInspector.IndexedDBModel.DatabaseId} databaseId 1908 * @param {WebInspector.IndexedDBModel.ObjectStore} objectStore 1909 * @param {WebInspector.IndexedDBModel.Index} index 1910 */ 1911 WebInspector.IDBIndexTreeElement = function(storagePanel, model, databaseId, objectStore, index) 1912 { 1913 WebInspector.BaseStorageTreeElement.call(this, storagePanel, null, index.name, ["indexed-db-index-storage-tree-item"]); 1914 this._model = model; 1915 this._databaseId = databaseId; 1916 this._objectStore = objectStore; 1917 this._index = index; 1918 } 1919 1920 WebInspector.IDBIndexTreeElement.prototype = { 1921 get itemURL() 1922 { 1923 return "indexedDB://" + this._databaseId.securityOrigin + "/" + this._databaseId.name + "/" + this._objectStore.name + "/" + this._index.name; 1924 }, 1925 1926 /** 1927 * @param {WebInspector.IndexedDBModel.Index} index 1928 */ 1929 update: function(index) 1930 { 1931 this._index = index; 1932 1933 if (this._view) 1934 this._view.update(this._index); 1935 1936 this._updateTooltip(); 1937 }, 1938 1939 _updateTooltip: function() 1940 { 1941 var tooltipLines = []; 1942 var keyPathString = this._index.keyPathString; 1943 tooltipLines.push(WebInspector.UIString("Key path: ") + keyPathString); 1944 if (this._index.unique) 1945 tooltipLines.push(WebInspector.UIString("unique")); 1946 if (this._index.multiEntry) 1947 tooltipLines.push(WebInspector.UIString("multiEntry")); 1948 this.tooltip = tooltipLines.join("\n"); 1949 }, 1950 1951 onselect: function(selectedByUser) 1952 { 1953 WebInspector.BaseStorageTreeElement.prototype.onselect.call(this, selectedByUser); 1954 if (!this._view) 1955 this._view = new WebInspector.IDBDataView(this._model, this._databaseId, this._objectStore, this._index); 1956 1957 this._storagePanel.showIndexedDB(this._view); 1958 }, 1959 1960 clear: function() 1961 { 1962 if (this._view) 1963 this._view.clear(); 1964 }, 1965 1966 __proto__: WebInspector.BaseStorageTreeElement.prototype 1967 } 1968 1969 /** 1970 * @constructor 1971 * @extends {WebInspector.BaseStorageTreeElement} 1972 */ 1973 WebInspector.DOMStorageTreeElement = function(storagePanel, domStorage, className) 1974 { 1975 WebInspector.BaseStorageTreeElement.call(this, storagePanel, null, domStorage.securityOrigin ? domStorage.securityOrigin : WebInspector.UIString("Local Files"), ["domstorage-storage-tree-item", className]); 1976 this._domStorage = domStorage; 1977 } 1978 1979 WebInspector.DOMStorageTreeElement.prototype = { 1980 get itemURL() 1981 { 1982 return "storage://" + this._domStorage.securityOrigin + "/" + (this._domStorage.isLocalStorage ? "local" : "session"); 1983 }, 1984 1985 onselect: function(selectedByUser) 1986 { 1987 WebInspector.BaseStorageTreeElement.prototype.onselect.call(this, selectedByUser); 1988 this._storagePanel._showDOMStorage(this._domStorage); 1989 }, 1990 1991 __proto__: WebInspector.BaseStorageTreeElement.prototype 1992 } 1993 1994 /** 1995 * @constructor 1996 * @extends {WebInspector.BaseStorageTreeElement} 1997 */ 1998 WebInspector.CookieTreeElement = function(storagePanel, cookieDomain) 1999 { 2000 WebInspector.BaseStorageTreeElement.call(this, storagePanel, null, cookieDomain ? cookieDomain : WebInspector.UIString("Local Files"), ["cookie-storage-tree-item"]); 2001 this._cookieDomain = cookieDomain; 2002 } 2003 2004 WebInspector.CookieTreeElement.prototype = { 2005 get itemURL() 2006 { 2007 return "cookies://" + this._cookieDomain; 2008 }, 2009 2010 onattach: function() 2011 { 2012 WebInspector.BaseStorageTreeElement.prototype.onattach.call(this); 2013 this.listItemElement.addEventListener("contextmenu", this._handleContextMenuEvent.bind(this), true); 2014 }, 2015 2016 /** 2017 * @param {Event} event 2018 */ 2019 _handleContextMenuEvent: function(event) 2020 { 2021 var contextMenu = new WebInspector.ContextMenu(event); 2022 contextMenu.appendItem(WebInspector.UIString("Clear"), this._clearCookies.bind(this)); 2023 contextMenu.show(); 2024 }, 2025 2026 /** 2027 * @param {string} domain 2028 */ 2029 _clearCookies: function(domain) 2030 { 2031 this._storagePanel.clearCookies(this._cookieDomain); 2032 }, 2033 2034 onselect: function(selectedByUser) 2035 { 2036 WebInspector.BaseStorageTreeElement.prototype.onselect.call(this, selectedByUser); 2037 this._storagePanel.showCookies(this, this._cookieDomain); 2038 }, 2039 2040 __proto__: WebInspector.BaseStorageTreeElement.prototype 2041 } 2042 2043 /** 2044 * @constructor 2045 * @extends {WebInspector.BaseStorageTreeElement} 2046 */ 2047 WebInspector.ApplicationCacheManifestTreeElement = function(storagePanel, manifestURL) 2048 { 2049 var title = new WebInspector.ParsedURL(manifestURL).displayName; 2050 WebInspector.BaseStorageTreeElement.call(this, storagePanel, null, title, ["application-cache-storage-tree-item"]); 2051 this.tooltip = manifestURL; 2052 this._manifestURL = manifestURL; 2053 } 2054 2055 WebInspector.ApplicationCacheManifestTreeElement.prototype = { 2056 get itemURL() 2057 { 2058 return "appcache://" + this._manifestURL; 2059 }, 2060 2061 get manifestURL() 2062 { 2063 return this._manifestURL; 2064 }, 2065 2066 onselect: function(selectedByUser) 2067 { 2068 WebInspector.BaseStorageTreeElement.prototype.onselect.call(this, selectedByUser); 2069 this._storagePanel.showCategoryView(this._manifestURL); 2070 }, 2071 2072 __proto__: WebInspector.BaseStorageTreeElement.prototype 2073 } 2074 2075 /** 2076 * @constructor 2077 * @extends {WebInspector.BaseStorageTreeElement} 2078 */ 2079 WebInspector.ApplicationCacheFrameTreeElement = function(storagePanel, frameId, manifestURL) 2080 { 2081 WebInspector.BaseStorageTreeElement.call(this, storagePanel, null, "", ["frame-storage-tree-item"]); 2082 this._frameId = frameId; 2083 this._manifestURL = manifestURL; 2084 this._refreshTitles(); 2085 } 2086 2087 WebInspector.ApplicationCacheFrameTreeElement.prototype = { 2088 get itemURL() 2089 { 2090 return "appcache://" + this._manifestURL + "/" + encodeURI(this.displayName); 2091 }, 2092 2093 get frameId() 2094 { 2095 return this._frameId; 2096 }, 2097 2098 get manifestURL() 2099 { 2100 return this._manifestURL; 2101 }, 2102 2103 _refreshTitles: function() 2104 { 2105 var frame = WebInspector.resourceTreeModel.frameForId(this._frameId); 2106 if (!frame) { 2107 this.subtitleText = WebInspector.UIString("new frame"); 2108 return; 2109 } 2110 this.titleText = frame.name; 2111 this.subtitleText = new WebInspector.ParsedURL(frame.url).displayName; 2112 }, 2113 2114 frameNavigated: function() 2115 { 2116 this._refreshTitles(); 2117 }, 2118 2119 onselect: function(selectedByUser) 2120 { 2121 WebInspector.BaseStorageTreeElement.prototype.onselect.call(this, selectedByUser); 2122 this._storagePanel.showApplicationCache(this._frameId); 2123 }, 2124 2125 __proto__: WebInspector.BaseStorageTreeElement.prototype 2126 } 2127 2128 /** 2129 * @constructor 2130 * @extends {WebInspector.BaseStorageTreeElement} 2131 * @param {WebInspector.ResourcesPanel} storagePanel 2132 * @param {WebInspector.FileSystemModel.FileSystem} fileSystem 2133 */ 2134 WebInspector.FileSystemTreeElement = function(storagePanel, fileSystem) 2135 { 2136 var displayName = fileSystem.type + " - " + fileSystem.origin; 2137 WebInspector.BaseStorageTreeElement.call(this, storagePanel, null, displayName, ["file-system-storage-tree-item"]); 2138 this._fileSystem = fileSystem; 2139 } 2140 2141 WebInspector.FileSystemTreeElement.prototype = { 2142 get fileSystemName() 2143 { 2144 return this._fileSystem.name; 2145 }, 2146 2147 get itemURL() 2148 { 2149 return "filesystem://" + this._fileSystem.name; 2150 }, 2151 2152 onselect: function(selectedByUser) 2153 { 2154 WebInspector.BaseStorageTreeElement.prototype.onselect.call(this, selectedByUser); 2155 this._fileSystemView = new WebInspector.FileSystemView(this._fileSystem); 2156 this._storagePanel.showFileSystem(this._fileSystemView); 2157 }, 2158 2159 clear: function() 2160 { 2161 if (this.fileSystemView && this._storagePanel.visibleView === this.fileSystemView) 2162 this._storagePanel.closeVisibleView(); 2163 }, 2164 2165 __proto__: WebInspector.BaseStorageTreeElement.prototype 2166 } 2167 2168 /** 2169 * @constructor 2170 * @extends {WebInspector.View} 2171 */ 2172 WebInspector.StorageCategoryView = function() 2173 { 2174 WebInspector.View.call(this); 2175 2176 this.element.addStyleClass("storage-view"); 2177 this._emptyView = new WebInspector.EmptyView(""); 2178 this._emptyView.show(this.element); 2179 } 2180 2181 WebInspector.StorageCategoryView.prototype = { 2182 setText: function(text) 2183 { 2184 this._emptyView.text = text; 2185 }, 2186 2187 __proto__: WebInspector.View.prototype 2188 } 2189 2190 /** 2191 * @constructor 2192 * @param {WebInspector.BaseStorageTreeElement} rootElement 2193 * @param {number} matchesCount 2194 */ 2195 WebInspector.ResourcesSearchController = function(rootElement, matchesCount) 2196 { 2197 this._root = rootElement; 2198 this._matchesCount = matchesCount; 2199 this._traverser = new WebInspector.SearchResultsTreeElementsTraverser(rootElement); 2200 this._lastTreeElement = null; 2201 this._lastIndex = -1; 2202 } 2203 2204 WebInspector.ResourcesSearchController.prototype = { 2205 /** 2206 * @param {WebInspector.BaseStorageTreeElement} currentTreeElement 2207 */ 2208 nextSearchResult: function(currentTreeElement) 2209 { 2210 if (!currentTreeElement) 2211 return this._searchResult(this._traverser.first(), 0, 1); 2212 2213 if (!currentTreeElement.searchMatchesCount) 2214 return this._searchResult(this._traverser.next(currentTreeElement), 0); 2215 2216 if (this._lastTreeElement !== currentTreeElement || this._lastIndex === -1) 2217 return this._searchResult(currentTreeElement, 0); 2218 2219 if (this._lastIndex === currentTreeElement.searchMatchesCount - 1) 2220 return this._searchResult(this._traverser.next(currentTreeElement), 0, this._currentMatchIndex % this._matchesCount + 1); 2221 2222 return this._searchResult(currentTreeElement, this._lastIndex + 1, this._currentMatchIndex + 1); 2223 }, 2224 2225 /** 2226 * @param {WebInspector.BaseStorageTreeElement} currentTreeElement 2227 */ 2228 previousSearchResult: function(currentTreeElement) 2229 { 2230 if (!currentTreeElement) { 2231 var treeElement = this._traverser.last(); 2232 return this._searchResult(treeElement, treeElement.searchMatchesCount - 1, this._matchesCount); 2233 } 2234 2235 if (currentTreeElement.searchMatchesCount && this._lastTreeElement === currentTreeElement) { 2236 if (this._lastIndex > 0) 2237 return this._searchResult(currentTreeElement, this._lastIndex - 1, this._currentMatchIndex - 1); 2238 else { 2239 var treeElement = this._traverser.previous(currentTreeElement); 2240 var currentMatchIndex = this._currentMatchIndex - 1 ? this._currentMatchIndex - 1 : this._matchesCount; 2241 return this._searchResult(treeElement, treeElement.searchMatchesCount - 1, currentMatchIndex); 2242 } 2243 } 2244 2245 var treeElement = this._traverser.previous(currentTreeElement) 2246 return this._searchResult(treeElement, treeElement.searchMatchesCount - 1); 2247 }, 2248 2249 /** 2250 * @param {WebInspector.BaseStorageTreeElement} treeElement 2251 * @param {number} index 2252 * @param {number=} currentMatchIndex 2253 * @return {Object} 2254 */ 2255 _searchResult: function(treeElement, index, currentMatchIndex) 2256 { 2257 this._lastTreeElement = treeElement; 2258 this._lastIndex = index; 2259 if (!currentMatchIndex) 2260 currentMatchIndex = this._traverser.matchIndex(treeElement, index); 2261 this._currentMatchIndex = currentMatchIndex; 2262 return {treeElement: treeElement, index: index, currentMatchIndex: currentMatchIndex}; 2263 } 2264 } 2265 2266 /** 2267 * @constructor 2268 * @param {WebInspector.BaseStorageTreeElement} rootElement 2269 */ 2270 WebInspector.SearchResultsTreeElementsTraverser = function(rootElement) 2271 { 2272 this._root = rootElement; 2273 } 2274 2275 WebInspector.SearchResultsTreeElementsTraverser.prototype = { 2276 /** 2277 * @return {WebInspector.BaseStorageTreeElement} 2278 */ 2279 first: function() 2280 { 2281 return this.next(this._root); 2282 }, 2283 2284 /** 2285 * @return {WebInspector.BaseStorageTreeElement} 2286 */ 2287 last: function() 2288 { 2289 return this.previous(this._root); 2290 }, 2291 2292 /** 2293 * @param {WebInspector.BaseStorageTreeElement} startTreeElement 2294 * @return {WebInspector.BaseStorageTreeElement} 2295 */ 2296 next: function(startTreeElement) 2297 { 2298 var treeElement = startTreeElement; 2299 do { 2300 treeElement = this._traverseNext(treeElement) || this._root; 2301 } while (treeElement != startTreeElement && !this._elementSearchMatchesCount(treeElement)); 2302 return treeElement; 2303 }, 2304 2305 /** 2306 * @param {WebInspector.BaseStorageTreeElement} startTreeElement 2307 * @return {WebInspector.BaseStorageTreeElement} 2308 */ 2309 previous: function(startTreeElement) 2310 { 2311 var treeElement = startTreeElement; 2312 do { 2313 treeElement = this._traversePrevious(treeElement) || this._lastTreeElement(); 2314 } while (treeElement != startTreeElement && !this._elementSearchMatchesCount(treeElement)); 2315 return treeElement; 2316 }, 2317 2318 /** 2319 * @param {WebInspector.BaseStorageTreeElement} startTreeElement 2320 * @param {number} index 2321 * @return {number} 2322 */ 2323 matchIndex: function(startTreeElement, index) 2324 { 2325 var matchIndex = 1; 2326 var treeElement = this._root; 2327 while (treeElement != startTreeElement) { 2328 matchIndex += this._elementSearchMatchesCount(treeElement); 2329 treeElement = this._traverseNext(treeElement) || this._root; 2330 if (treeElement === this._root) 2331 return 0; 2332 } 2333 return matchIndex + index; 2334 }, 2335 2336 /** 2337 * @param {WebInspector.BaseStorageTreeElement} treeElement 2338 * @return {number} 2339 */ 2340 _elementSearchMatchesCount: function(treeElement) 2341 { 2342 return treeElement.searchMatchesCount; 2343 }, 2344 2345 /** 2346 * @param {WebInspector.BaseStorageTreeElement} treeElement 2347 * @return {WebInspector.BaseStorageTreeElement} 2348 */ 2349 _traverseNext: function(treeElement) 2350 { 2351 return /** @type {WebInspector.BaseStorageTreeElement} */ (treeElement.traverseNextTreeElement(false, this._root, true)); 2352 }, 2353 2354 /** 2355 * @param {WebInspector.BaseStorageTreeElement} treeElement 2356 * @return {WebInspector.BaseStorageTreeElement} 2357 */ 2358 _traversePrevious: function(treeElement) 2359 { 2360 return /** @type {WebInspector.BaseStorageTreeElement} */ (treeElement.traversePreviousTreeElement(false, true)); 2361 }, 2362 2363 /** 2364 * @return {WebInspector.BaseStorageTreeElement} 2365 */ 2366 _lastTreeElement: function() 2367 { 2368 var treeElement = this._root; 2369 var nextTreeElement; 2370 while (nextTreeElement = this._traverseNext(treeElement)) 2371 treeElement = nextTreeElement; 2372 return treeElement; 2373 } 2374 } 2375