2 * Copyright (C) 2007, 2008, 2010 Apple Inc. All rights reserved.
3 * Copyright (C) 2009 Joseph Pecoraro
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
15 * its contributors may be used to endorse or promote products derived
16 * from this software without specific prior written permission.
18 * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
19 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
20 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
21 * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
22 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
23 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
24 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
25 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
27 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32 * @extends {WebInspector.Panel}
34 WebInspector.ResourcesPanel = function(database)
36 WebInspector.Panel.call(this, "resources");
37 this.registerRequiredCSS("resourcesPanel.css");
39 WebInspector.settings.resourcesLastSelectedItem = WebInspector.settings.createSetting("resourcesLastSelectedItem", {});
41 this.createSplitViewWithSidebarTree();
42 this.sidebarElement.addStyleClass("outline-disclosure");
43 this.sidebarElement.addStyleClass("filter-all");
44 this.sidebarElement.addStyleClass("children");
45 this.sidebarElement.addStyleClass("small");
47 this.sidebarTreeElement.removeStyleClass("sidebar-tree");
49 this.resourcesListTreeElement = new WebInspector.StorageCategoryTreeElement(this, WebInspector.UIString("Frames"), "Frames", ["frame-storage-tree-item"]);
50 this.sidebarTree.appendChild(this.resourcesListTreeElement);
52 this.databasesListTreeElement = new WebInspector.StorageCategoryTreeElement(this, WebInspector.UIString("Databases"), "Databases", ["database-storage-tree-item"]);
53 this.sidebarTree.appendChild(this.databasesListTreeElement);
55 this.localStorageListTreeElement = new WebInspector.StorageCategoryTreeElement(this, WebInspector.UIString("Local Storage"), "LocalStorage", ["domstorage-storage-tree-item", "local-storage"]);
56 this.sidebarTree.appendChild(this.localStorageListTreeElement);
58 this.sessionStorageListTreeElement = new WebInspector.StorageCategoryTreeElement(this, WebInspector.UIString("Session Storage"), "SessionStorage", ["domstorage-storage-tree-item", "session-storage"]);
59 this.sidebarTree.appendChild(this.sessionStorageListTreeElement);
61 this.cookieListTreeElement = new WebInspector.StorageCategoryTreeElement(this, WebInspector.UIString("Cookies"), "Cookies", ["cookie-storage-tree-item"]);
62 this.sidebarTree.appendChild(this.cookieListTreeElement);
64 this.applicationCacheListTreeElement = new WebInspector.StorageCategoryTreeElement(this, WebInspector.UIString("Application Cache"), "ApplicationCache", ["application-cache-storage-tree-item"]);
65 this.sidebarTree.appendChild(this.applicationCacheListTreeElement);
67 this.storageViews = this.splitView.mainElement;
68 this.storageViews.addStyleClass("diff-container");
70 this.storageViewStatusBarItemsContainer = document.createElement("div");
71 this.storageViewStatusBarItemsContainer.className = "status-bar-items";
74 this._domStorage = [];
75 this._cookieViews = {};
79 this.sidebarElement.addEventListener("mousemove", this._onmousemove.bind(this), false);
80 this.sidebarElement.addEventListener("mouseout", this._onmouseout.bind(this), false);
84 return this.visibleView;
86 WebInspector.GoToLineDialog.install(this, viewGetter.bind(this));
88 WebInspector.resourceTreeModel.addEventListener(WebInspector.ResourceTreeModel.EventTypes.OnLoad, this._onLoadEventFired, this);
89 WebInspector.resourceTreeModel.addEventListener(WebInspector.ResourceTreeModel.EventTypes.CachedResourcesLoaded, this._cachedResourcesLoaded, this);
90 WebInspector.resourceTreeModel.addEventListener(WebInspector.ResourceTreeModel.EventTypes.WillLoadCachedResources, this._resetWithFrames, this);
93 WebInspector.ResourcesPanel.prototype = {
94 get toolbarItemLabel()
96 return WebInspector.UIString("Resources");
101 return [this.storageViewStatusBarItemsContainer];
106 WebInspector.Panel.prototype.wasShown.call(this);
110 _initialize: function()
112 if (!this._initialized && this.isShowing() && this._cachedResourcesWereLoaded) {
113 this._populateResourceTree();
114 this._populateApplicationCacheTree();
115 this._initDefaultSelection();
116 this._initialized = true;
120 _onLoadEventFired: function()
122 this._initDefaultSelection();
125 _initDefaultSelection: function()
127 if (!this._initialized)
130 var itemURL = WebInspector.settings.resourcesLastSelectedItem.get();
132 for (var treeElement = this.sidebarTree.children[0]; treeElement; treeElement = treeElement.traverseNextTreeElement(false, this.sidebarTree, true)) {
133 if (treeElement.itemURL === itemURL) {
134 treeElement.revealAndSelect(true);
140 var mainResource = WebInspector.inspectedPageURL && this.resourcesListTreeElement && this.resourcesListTreeElement.expanded && WebInspector.resourceTreeModel.resourceForURL(WebInspector.inspectedPageURL);
142 this.showResource(mainResource);
145 _resetWithFrames: function()
147 this.resourcesListTreeElement.removeChildren();
148 this._treeElementForFrameId = {};
156 for (var i = 0; i < this._databases.length; ++i) {
157 var database = this._databases[i];
158 delete database._tableViews;
159 if (database._queryView)
160 database._queryView.removeEventListener(WebInspector.DatabaseQueryView.Events.SchemaUpdated, this._updateDatabaseTables, this);
161 delete database._queryView;
163 this._databases = [];
165 var domStorageLength = this._domStorage.length;
166 for (var i = 0; i < this._domStorage.length; ++i) {
167 var domStorage = this._domStorage[i];
168 delete domStorage._domStorageView;
170 this._domStorage = [];
172 this._cookieViews = {};
174 this.databasesListTreeElement.removeChildren();
175 this.localStorageListTreeElement.removeChildren();
176 this.sessionStorageListTreeElement.removeChildren();
177 this.cookieListTreeElement.removeChildren();
179 if (this.visibleView)
180 this.visibleView.detach();
182 this.storageViewStatusBarItemsContainer.removeChildren();
184 if (this.sidebarTree.selectedTreeElement)
185 this.sidebarTree.selectedTreeElement.deselect();
188 _populateResourceTree: function()
190 this._treeElementForFrameId = {};
191 WebInspector.resourceTreeModel.addEventListener(WebInspector.ResourceTreeModel.EventTypes.FrameAdded, this._frameAdded, this);
192 WebInspector.resourceTreeModel.addEventListener(WebInspector.ResourceTreeModel.EventTypes.FrameNavigated, this._frameNavigated, this);
193 WebInspector.resourceTreeModel.addEventListener(WebInspector.ResourceTreeModel.EventTypes.FrameDetached, this._frameDetached, this);
194 WebInspector.resourceTreeModel.addEventListener(WebInspector.ResourceTreeModel.EventTypes.ResourceAdded, this._resourceAdded, this);
196 function populateFrame(frame)
198 this._frameAdded({data:frame});
199 for (var i = 0; i < frame.childFrames.length; ++i)
200 populateFrame.call(this, frame.childFrames[i]);
202 var resources = frame.resources();
203 for (var i = 0; i < resources.length; ++i)
204 this._resourceAdded({data:resources[i]});
206 populateFrame.call(this, WebInspector.resourceTreeModel.mainFrame);
209 _frameAdded: function(event)
211 var frame = event.data;
212 var parentFrame = frame.parentFrame;
214 var parentTreeElement = parentFrame ? this._treeElementForFrameId[parentFrame.id] : this.resourcesListTreeElement;
215 if (!parentTreeElement) {
216 console.warn("No frame to route " + frame.url + " to.")
220 var frameTreeElement = new WebInspector.FrameTreeElement(this, frame);
221 this._treeElementForFrameId[frame.id] = frameTreeElement;
222 parentTreeElement.appendChild(frameTreeElement);
225 _frameDetached: function(event)
227 var frame = event.data;
228 var frameTreeElement = this._treeElementForFrameId[frame.id];
229 if (!frameTreeElement)
232 delete this._treeElementForFrameId[frame.id];
233 if (frameTreeElement.parent)
234 frameTreeElement.parent.removeChild(frameTreeElement);
237 _resourceAdded: function(event)
239 var resource = event.data;
240 var frameId = resource.frameId;
242 if (resource.statusCode >= 301 && resource.statusCode <= 303)
245 var frameTreeElement = this._treeElementForFrameId[frameId];
246 if (!frameTreeElement) {
247 // This is a frame's main resource, it will be retained
248 // and re-added by the resource manager;
252 frameTreeElement.appendResource(resource);
255 _frameNavigated: function(event)
257 var frame = event.data;
259 if (!frame.parentFrame)
262 var frameId = frame.id;
263 var frameTreeElement = this._treeElementForFrameId[frameId];
264 if (frameTreeElement)
265 frameTreeElement.frameNavigated(frame);
267 var applicationCacheFrameTreeElement = this._applicationCacheFrameElements[frameId];
268 if (applicationCacheFrameTreeElement)
269 applicationCacheFrameTreeElement.frameNavigated(frame);
272 _cachedResourcesLoaded: function()
274 this._cachedResourcesWereLoaded = true;
278 addDatabase: function(database)
280 this._databases.push(database);
282 var databaseTreeElement = new WebInspector.DatabaseTreeElement(this, database);
283 database._databasesTreeElement = databaseTreeElement;
284 this.databasesListTreeElement.appendChild(databaseTreeElement);
287 addDocumentURL: function(url)
289 var parsedURL = url.asParsedURL();
293 var domain = parsedURL.host;
294 if (!this._domains[domain]) {
295 this._domains[domain] = true;
297 var cookieDomainTreeElement = new WebInspector.CookieTreeElement(this, domain);
298 this.cookieListTreeElement.appendChild(cookieDomainTreeElement);
302 addDOMStorage: function(domStorage)
304 this._domStorage.push(domStorage);
305 var domStorageTreeElement = new WebInspector.DOMStorageTreeElement(this, domStorage, (domStorage.isLocalStorage ? "local-storage" : "session-storage"));
306 domStorage._domStorageTreeElement = domStorageTreeElement;
307 if (domStorage.isLocalStorage)
308 this.localStorageListTreeElement.appendChild(domStorageTreeElement);
310 this.sessionStorageListTreeElement.appendChild(domStorageTreeElement);
313 selectDatabase: function(databaseId)
316 for (var i = 0, len = this._databases.length; i < len; ++i) {
317 database = this._databases[i];
318 if (database.id === databaseId) {
319 this.showDatabase(database);
320 database._databasesTreeElement.select();
326 selectDOMStorage: function(storageId)
328 var domStorage = this._domStorageForId(storageId);
330 this.showDOMStorage(domStorage);
331 domStorage._domStorageTreeElement.select();
335 canShowAnchorLocation: function(anchor)
337 return !!WebInspector.resourceForURL(anchor.href);
340 showAnchorLocation: function(anchor)
342 var resource = WebInspector.resourceForURL(anchor.href);
343 var lineNumber = anchor.hasAttribute("line_number") ? parseInt(anchor.getAttribute("line_number"), 10) : undefined;
344 this.showResource(resource, lineNumber);
348 * @param {number=} line
350 showResource: function(resource, line)
352 var resourceTreeElement = this._findTreeElementForResource(resource);
353 if (resourceTreeElement)
354 resourceTreeElement.revealAndSelect();
356 if (typeof line === "number") {
357 var view = this._resourceViewForResource(resource);
358 if (view.canHighlightLine())
359 view.highlightLine(line);
364 _showResourceView: function(resource)
366 var view = this._resourceViewForResource(resource);
368 this.visibleView.detach();
371 if (view.searchCanceled)
372 view.searchCanceled();
373 this._fetchAndApplyDiffMarkup(view, resource);
374 this._innerShowView(view);
377 _resourceViewForResource: function(resource)
379 if (WebInspector.ResourceView.hasTextContent(resource)) {
380 var treeElement = this._findTreeElementForResource(resource);
383 return treeElement.sourceView();
385 return WebInspector.ResourceView.nonSourceViewForResource(resource);
388 _showRevisionView: function(revision)
390 var view = this._sourceViewForRevision(revision);
391 this._fetchAndApplyDiffMarkup(view, revision.resource, revision);
392 this._innerShowView(view);
395 _sourceViewForRevision: function(revision)
397 var treeElement = this._findTreeElementForRevision(revision);
398 return treeElement.sourceView();
402 * @param {WebInspector.ResourceRevision=} revision
404 _fetchAndApplyDiffMarkup: function(view, resource, revision)
406 var baseRevision = resource.history[0];
409 if (!(view instanceof WebInspector.SourceFrame))
412 baseRevision.requestContent(step1.bind(this));
414 function step1(baseContent)
416 (revision ? revision : resource).requestContent(step2.bind(this, baseContent));
419 function step2(baseContent, revisionContent)
421 this._applyDiffMarkup(view, baseContent, revisionContent);
425 _applyDiffMarkup: function(view, baseContent, newContent)
427 var diffData = TextDiff.compute(baseContent, newContent);
428 view.markDiff(diffData);
432 * @param {string=} tableName
434 showDatabase: function(database, tableName)
441 if (!("_tableViews" in database))
442 database._tableViews = {};
443 view = database._tableViews[tableName];
445 view = new WebInspector.DatabaseTableView(database, tableName);
446 database._tableViews[tableName] = view;
449 view = database._queryView;
451 view = new WebInspector.DatabaseQueryView(database);
452 database._queryView = view;
453 view.addEventListener(WebInspector.DatabaseQueryView.Events.SchemaUpdated, this._updateDatabaseTables, this);
457 this._innerShowView(view);
460 showDOMStorage: function(domStorage)
466 view = domStorage._domStorageView;
468 view = new WebInspector.DOMStorageItemsView(domStorage);
469 domStorage._domStorageView = view;
472 this._innerShowView(view);
475 showCookies: function(treeElement, cookieDomain)
477 var view = this._cookieViews[cookieDomain];
479 view = new WebInspector.CookieItemsView(treeElement, cookieDomain);
480 this._cookieViews[cookieDomain] = view;
483 this._innerShowView(view);
486 showApplicationCache: function(frameId)
488 if (!this._applicationCacheViews[frameId])
489 this._applicationCacheViews[frameId] = new WebInspector.ApplicationCacheItemsView(this._applicationCacheModel, frameId);
491 this._innerShowView(this._applicationCacheViews[frameId]);
494 showCategoryView: function(categoryName)
496 if (!this._categoryView)
497 this._categoryView = new WebInspector.StorageCategoryView();
498 this._categoryView.setText(categoryName);
499 this._innerShowView(this._categoryView);
502 _innerShowView: function(view)
504 if (this.visibleView)
505 this.visibleView.detach();
507 view.show(this.storageViews);
508 this.visibleView = view;
510 this.storageViewStatusBarItemsContainer.removeChildren();
511 var statusBarItems = view.statusBarItems || [];
512 for (var i = 0; i < statusBarItems.length; ++i)
513 this.storageViewStatusBarItemsContainer.appendChild(statusBarItems[i]);
516 closeVisibleView: function()
518 if (!this.visibleView)
520 this.visibleView.detach();
521 delete this.visibleView;
524 _updateDatabaseTables: function(event)
526 var database = event.data;
528 if (!database || !database._databasesTreeElement)
531 database._databasesTreeElement.shouldRefreshChildren = true;
533 if (!("_tableViews" in database))
536 var tableNamesHash = {};
538 function tableNamesCallback(tableNames)
540 var tableNamesLength = tableNames.length;
541 for (var i = 0; i < tableNamesLength; ++i)
542 tableNamesHash[tableNames[i]] = true;
544 for (var tableName in database._tableViews) {
545 if (!(tableName in tableNamesHash)) {
546 if (self.visibleView === database._tableViews[tableName])
547 self.closeVisibleView();
548 delete database._tableViews[tableName];
552 database.getTableNames(tableNamesCallback);
555 updateDOMStorage: function(storageId)
557 var domStorage = this._domStorageForId(storageId);
561 var view = domStorage._domStorageView;
562 if (this.visibleView && view === this.visibleView)
563 domStorage._domStorageView.update();
566 _populateApplicationCacheTree: function()
568 this._applicationCacheModel = new WebInspector.ApplicationCacheModel();
570 this._applicationCacheViews = {};
571 this._applicationCacheFrameElements = {};
572 this._applicationCacheManifestElements = {};
574 this._applicationCacheModel.addEventListener(WebInspector.ApplicationCacheModel.EventTypes.FrameManifestAdded, this._applicationCacheFrameManifestAdded, this);
575 this._applicationCacheModel.addEventListener(WebInspector.ApplicationCacheModel.EventTypes.FrameManifestRemoved, this._applicationCacheFrameManifestRemoved, this);
577 this._applicationCacheModel.addEventListener(WebInspector.ApplicationCacheModel.EventTypes.FrameManifestStatusUpdated, this._applicationCacheFrameManifestStatusChanged, this);
578 this._applicationCacheModel.addEventListener(WebInspector.ApplicationCacheModel.EventTypes.NetworkStateChanged, this._applicationCacheNetworkStateChanged, this);
581 _applicationCacheFrameManifestAdded: function(event)
583 var frameId = event.data;
584 var manifestURL = this._applicationCacheModel.frameManifestURL(frameId);
585 var status = this._applicationCacheModel.frameManifestStatus(frameId)
587 var manifestTreeElement = this._applicationCacheManifestElements[manifestURL]
588 if (!manifestTreeElement) {
589 manifestTreeElement = new WebInspector.ApplicationCacheManifestTreeElement(this, manifestURL);
590 this.applicationCacheListTreeElement.appendChild(manifestTreeElement);
591 this._applicationCacheManifestElements[manifestURL] = manifestTreeElement;
594 var frameTreeElement = new WebInspector.ApplicationCacheFrameTreeElement(this, frameId, manifestURL);
595 manifestTreeElement.appendChild(frameTreeElement);
596 manifestTreeElement.expand();
597 this._applicationCacheFrameElements[frameId] = frameTreeElement;
600 _applicationCacheFrameManifestRemoved: function(event)
602 var frameId = event.data;
603 var frameTreeElement = this._applicationCacheFrameElements[frameId];
604 if (!frameTreeElement)
607 var manifestURL = frameTreeElement.manifestURL;
608 delete this._applicationCacheFrameElements[frameId];
609 delete this._applicationCacheViews[frameId];
610 frameTreeElement.parent.removeChild(frameTreeElement);
612 var manifestTreeElement = this._applicationCacheManifestElements[manifestURL];
613 if (manifestTreeElement.children.length !== 0)
616 delete this._applicationCacheManifestElements[manifestURL];
617 manifestTreeElement.parent.removeChild(manifestTreeElement);
620 _applicationCacheFrameManifestStatusChanged: function(event)
622 var frameId = event.data;
623 var status = this._applicationCacheModel.frameManifestStatus(frameId)
625 if (this._applicationCacheViews[frameId])
626 this._applicationCacheViews[frameId].updateStatus(status);
629 _applicationCacheNetworkStateChanged: function(event)
631 var isNowOnline = event.data;
633 for (var manifestURL in this._applicationCacheViews)
634 this._applicationCacheViews[manifestURL].updateNetworkState(isNowOnline);
637 _domStorageForId: function(storageId)
639 if (!this._domStorage)
641 var domStorageLength = this._domStorage.length;
642 for (var i = 0; i < domStorageLength; ++i) {
643 var domStorage = this._domStorage[i];
644 if (domStorage.id == storageId)
650 sidebarResized: function(event)
652 var width = event.data;
653 this.storageViewStatusBarItemsContainer.style.left = width + "px";
656 performSearch: function(query)
658 this._resetSearchResults();
659 var regex = WebInspector.SourceFrame.createSearchRegex(query);
660 var totalMatchesCount = 0;
662 function searchInEditedResource(treeElement)
664 var resource = treeElement.representedObject;
665 if (resource.history.length == 0)
667 var matchesCount = countRegexMatches(regex, resource.content)
668 treeElement.searchMatchesFound(matchesCount);
669 totalMatchesCount += matchesCount;
672 function callback(error, result)
675 for (var i = 0; i < result.length; i++) {
676 var searchResult = result[i];
677 var frameTreeElement = this._treeElementForFrameId[searchResult.frameId];
678 if (!frameTreeElement)
680 var resource = frameTreeElement.resourceByURL(searchResult.url);
682 // FIXME: When the same script is used in several frames and this script contains at least
683 // one search result then some search results can not be matched with a resource on panel.
684 // https://bugs.webkit.org/show_bug.cgi?id=66005
688 if (resource.history.length > 0)
689 continue; // Skip edited resources.
690 this._findTreeElementForResource(resource).searchMatchesFound(searchResult.matchesCount);
691 totalMatchesCount += searchResult.matchesCount;
695 WebInspector.searchController.updateSearchMatchesCount(totalMatchesCount, this);
696 this._searchController = new WebInspector.ResourcesSearchController(this.resourcesListTreeElement, totalMatchesCount);
698 if (this.sidebarTree.selectedTreeElement && this.sidebarTree.selectedTreeElement.searchMatchesCount)
699 this.jumpToNextSearchResult();
702 this._forAllResourceTreeElements(searchInEditedResource.bind(this));
703 PageAgent.searchInResources(regex.source, !regex.ignoreCase, true, callback.bind(this));
706 _ensureViewSearchPerformed: function(callback)
708 function viewSearchPerformedCallback(searchId)
710 if (searchId !== this._lastViewSearchId)
711 return; // Search is obsolete.
712 this._viewSearchInProgress = false;
716 if (!this._viewSearchInProgress) {
717 if (!this.visibleView.hasSearchResults()) {
718 // We give id to each search, so that we can skip callbacks for obsolete searches.
719 this._lastViewSearchId = this._lastViewSearchId ? this._lastViewSearchId + 1 : 0;
720 this._viewSearchInProgress = true;
721 this.visibleView.performSearch(this.currentQuery, viewSearchPerformedCallback.bind(this, this._lastViewSearchId));
727 _showSearchResult: function(searchResult)
729 this._lastSearchResultIndex = searchResult.index;
730 this._lastSearchResultTreeElement = searchResult.treeElement;
732 // At first show view for treeElement.
733 if (searchResult.treeElement !== this.sidebarTree.selectedTreeElement) {
734 this.showResource(searchResult.treeElement.representedObject);
735 WebInspector.searchController.focusSearchField();
738 function callback(searchId)
740 if (this.sidebarTree.selectedTreeElement !== this._lastSearchResultTreeElement)
741 return; // User has selected another view while we were searching.
742 if (this._lastSearchResultIndex != -1)
743 this.visibleView.jumpToSearchResult(this._lastSearchResultIndex);
744 WebInspector.searchController.updateCurrentMatchIndex(searchResult.currentMatchIndex - 1, this);
747 // Then run SourceFrame search if needed and jump to search result index when done.
748 this._ensureViewSearchPerformed(callback.bind(this));
751 _resetSearchResults: function()
753 function callback(resourceTreeElement)
755 resourceTreeElement._resetSearchResults();
758 this._forAllResourceTreeElements(callback);
759 if (this.visibleView && this.visibleView.searchCanceled)
760 this.visibleView.searchCanceled();
762 this._lastSearchResultTreeElement = null;
763 this._lastSearchResultIndex = -1;
764 this._viewSearchInProgress = false;
767 searchCanceled: function()
769 function callback(resourceTreeElement)
771 resourceTreeElement._updateErrorsAndWarningsBubbles();
774 WebInspector.searchController.updateSearchMatchesCount(0, this);
775 this._resetSearchResults();
776 this._forAllResourceTreeElements(callback);
779 jumpToNextSearchResult: function()
781 if (!this.currentSearchMatches)
783 var currentTreeElement = this.sidebarTree.selectedTreeElement;
784 var nextSearchResult = this._searchController.nextSearchResult(currentTreeElement);
785 this._showSearchResult(nextSearchResult);
788 jumpToPreviousSearchResult: function()
790 if (!this.currentSearchMatches)
792 var currentTreeElement = this.sidebarTree.selectedTreeElement;
793 var previousSearchResult = this._searchController.previousSearchResult(currentTreeElement);
794 this._showSearchResult(previousSearchResult);
797 _forAllResourceTreeElements: function(callback)
800 for (var treeElement = this.resourcesListTreeElement; !stop && treeElement; treeElement = treeElement.traverseNextTreeElement(false, this.resourcesListTreeElement, true)) {
801 if (treeElement instanceof WebInspector.FrameResourceTreeElement)
802 stop = callback(treeElement);
806 _findTreeElementForResource: function(resource)
808 function isAncestor(ancestor, object)
810 // Redirects, XHRs do not belong to the tree, it is fine to silently return false here.
814 function getParent(object)
816 // Redirects, XHRs do not belong to the tree, it is fine to silently return false here.
820 return this.sidebarTree.findTreeElement(resource, isAncestor, getParent);
823 _findTreeElementForRevision: function(revision)
825 function isAncestor(ancestor, object)
830 function getParent(object)
835 return this.sidebarTree.findTreeElement(revision, isAncestor, getParent);
838 showView: function(view)
841 this.showResource(view.resource);
844 _onmousemove: function(event)
846 var nodeUnderMouse = document.elementFromPoint(event.pageX, event.pageY);
850 var listNode = nodeUnderMouse.enclosingNodeOrSelfWithNodeName("li");
854 var element = listNode.treeElement;
855 if (this._previousHoveredElement === element)
858 if (this._previousHoveredElement) {
859 this._previousHoveredElement.hovered = false;
860 delete this._previousHoveredElement;
863 if (element instanceof WebInspector.FrameTreeElement) {
864 this._previousHoveredElement = element;
865 element.hovered = true;
869 _onmouseout: function(event)
871 if (this._previousHoveredElement) {
872 this._previousHoveredElement.hovered = false;
873 delete this._previousHoveredElement;
878 WebInspector.ResourcesPanel.prototype.__proto__ = WebInspector.Panel.prototype;
882 * @extends {TreeElement}
883 * @param {boolean=} hasChildren
884 * @param {boolean=} noIcon
886 WebInspector.BaseStorageTreeElement = function(storagePanel, representedObject, title, iconClasses, hasChildren, noIcon)
888 TreeElement.call(this, "", representedObject, hasChildren);
889 this._storagePanel = storagePanel;
890 this._titleText = title;
891 this._iconClasses = iconClasses;
892 this._noIcon = noIcon;
895 WebInspector.BaseStorageTreeElement.prototype = {
898 this.listItemElement.removeChildren();
899 if (this._iconClasses) {
900 for (var i = 0; i < this._iconClasses.length; ++i)
901 this.listItemElement.addStyleClass(this._iconClasses[i]);
904 var selectionElement = document.createElement("div");
905 selectionElement.className = "selection";
906 this.listItemElement.appendChild(selectionElement);
909 this.imageElement = document.createElement("img");
910 this.imageElement.className = "icon";
911 this.listItemElement.appendChild(this.imageElement);
914 this.titleElement = document.createElement("div");
915 this.titleElement.className = "base-storage-tree-element-title";
916 this._titleTextNode = document.createTextNode("");
917 this.titleElement.appendChild(this._titleTextNode);
919 this._updateSubtitle();
920 this.listItemElement.appendChild(this.titleElement);
925 return this._displayName;
928 _updateDisplayName: function()
930 this._displayName = this._titleText || "";
931 if (this._subtitleText)
932 this._displayName += " (" + this._subtitleText + ")";
935 _updateTitle: function()
937 this._updateDisplayName();
939 if (!this.titleElement)
942 this._titleTextNode.textContent = this._titleText || "";
945 _updateSubtitle: function()
947 this._updateDisplayName();
949 if (!this.titleElement)
952 if (this._subtitleText) {
953 if (!this._subtitleElement) {
954 this._subtitleElement = document.createElement("span");
955 this._subtitleElement.className = "base-storage-tree-element-subtitle";
956 this.titleElement.appendChild(this._subtitleElement);
958 this._subtitleElement.textContent = "(" + this._subtitleText + ")";
959 } else if (this._subtitleElement) {
960 this.titleElement.removeChild(this._subtitleElement);
961 delete this._subtitleElement;
967 var itemURL = this.itemURL;
969 WebInspector.settings.resourcesLastSelectedItem.set(itemURL);
974 if (this.listItemElement)
975 this.listItemElement.scrollIntoViewIfNeeded(false);
980 return this._titleText;
983 set titleText(titleText)
985 this._titleText = titleText;
991 return this._subtitleText;
994 set subtitleText(subtitleText)
996 this._subtitleText = subtitleText;
997 this._updateSubtitle();
1000 get searchMatchesCount()
1006 WebInspector.BaseStorageTreeElement.prototype.__proto__ = TreeElement.prototype;
1010 * @extends {WebInspector.BaseStorageTreeElement}
1011 * @param {boolean=} noIcon
1013 WebInspector.StorageCategoryTreeElement = function(storagePanel, categoryName, settingsKey, iconClasses, noIcon)
1015 WebInspector.BaseStorageTreeElement.call(this, storagePanel, null, categoryName, iconClasses, true, noIcon);
1016 this._expandedSettingKey = "resources" + settingsKey + "Expanded";
1017 WebInspector.settings[this._expandedSettingKey] = WebInspector.settings.createSetting(this._expandedSettingKey, settingsKey === "Frames");
1018 this._categoryName = categoryName;
1021 WebInspector.StorageCategoryTreeElement.prototype = {
1024 return "category://" + this._categoryName;
1027 onselect: function()
1029 WebInspector.BaseStorageTreeElement.prototype.onselect.call(this);
1030 this._storagePanel.showCategoryView(this._categoryName);
1033 onattach: function()
1035 WebInspector.BaseStorageTreeElement.prototype.onattach.call(this);
1036 if (WebInspector.settings[this._expandedSettingKey].get())
1040 onexpand: function()
1042 WebInspector.settings[this._expandedSettingKey].set(true);
1045 oncollapse: function()
1047 WebInspector.settings[this._expandedSettingKey].set(false);
1051 WebInspector.StorageCategoryTreeElement.prototype.__proto__ = WebInspector.BaseStorageTreeElement.prototype;
1055 * @extends {WebInspector.BaseStorageTreeElement}
1057 WebInspector.FrameTreeElement = function(storagePanel, frame)
1059 WebInspector.BaseStorageTreeElement.call(this, storagePanel, null, "", ["frame-storage-tree-item"]);
1060 this._frame = frame;
1061 this.frameNavigated(frame);
1064 WebInspector.FrameTreeElement.prototype = {
1065 frameNavigated: function(frame)
1067 this.removeChildren();
1068 this._frameId = frame.id;
1070 this.titleText = frame.name;
1071 this.subtitleText = WebInspector.Resource.displayName(frame.url);
1073 this._categoryElements = {};
1074 this._treeElementForResource = {};
1076 this._storagePanel.addDocumentURL(frame.url);
1081 return "frame://" + encodeURI(this.displayName);
1084 onselect: function()
1086 WebInspector.BaseStorageTreeElement.prototype.onselect.call(this);
1087 this._storagePanel.showCategoryView(this.displayName);
1089 this.listItemElement.removeStyleClass("hovered");
1090 DOMAgent.hideHighlight();
1093 set hovered(hovered)
1096 this.listItemElement.addStyleClass("hovered");
1097 DOMAgent.highlightFrame(this._frameId, WebInspector.Color.PageHighlight.Content.toProtocolRGBA(), WebInspector.Color.PageHighlight.ContentOutline.toProtocolRGBA());
1099 this.listItemElement.removeStyleClass("hovered");
1100 DOMAgent.hideHighlight();
1104 appendResource: function(resource)
1106 var categoryName = resource.category.name;
1107 var categoryElement = resource.category === WebInspector.resourceCategories.documents ? this : this._categoryElements[categoryName];
1108 if (!categoryElement) {
1109 categoryElement = new WebInspector.StorageCategoryTreeElement(this._storagePanel, resource.category.title, categoryName, null, true);
1110 this._categoryElements[resource.category.name] = categoryElement;
1111 this._insertInPresentationOrder(this, categoryElement);
1113 var resourceTreeElement = new WebInspector.FrameResourceTreeElement(this._storagePanel, resource);
1114 this._insertInPresentationOrder(categoryElement, resourceTreeElement);
1115 resourceTreeElement._populateRevisions();
1117 this._treeElementForResource[resource.url] = resourceTreeElement;
1120 resourceByURL: function(url)
1122 var treeElement = this._treeElementForResource[url];
1123 return treeElement ? treeElement.representedObject : null;
1126 appendChild: function(treeElement)
1128 this._insertInPresentationOrder(this, treeElement);
1131 _insertInPresentationOrder: function(parentTreeElement, childTreeElement)
1133 // Insert in the alphabetical order, first frames, then resources. Document resource goes last.
1134 function typeWeight(treeElement)
1136 if (treeElement instanceof WebInspector.StorageCategoryTreeElement)
1138 if (treeElement instanceof WebInspector.FrameTreeElement)
1143 function compare(treeElement1, treeElement2)
1145 var typeWeight1 = typeWeight(treeElement1);
1146 var typeWeight2 = typeWeight(treeElement2);
1149 if (typeWeight1 > typeWeight2)
1151 else if (typeWeight1 < typeWeight2)
1154 var title1 = treeElement1.displayName || treeElement1.titleText;
1155 var title2 = treeElement2.displayName || treeElement2.titleText;
1156 result = title1.localeCompare(title2);
1161 var children = parentTreeElement.children;
1163 for (i = 0; i < children.length; ++i) {
1164 if (compare(childTreeElement, children[i]) < 0)
1167 parentTreeElement.insertChild(childTreeElement, i);
1171 WebInspector.FrameTreeElement.prototype.__proto__ = WebInspector.BaseStorageTreeElement.prototype;
1175 * @extends {WebInspector.BaseStorageTreeElement}
1177 WebInspector.FrameResourceTreeElement = function(storagePanel, resource)
1179 WebInspector.BaseStorageTreeElement.call(this, storagePanel, resource, resource.displayName, ["resource-sidebar-tree-item", "resources-category-" + resource.category.name]);
1180 this._resource = resource;
1181 this._resource.addEventListener(WebInspector.Resource.Events.MessageAdded, this._consoleMessageAdded, this);
1182 this._resource.addEventListener(WebInspector.Resource.Events.MessagesCleared, this._consoleMessagesCleared, this);
1183 this._resource.addEventListener(WebInspector.Resource.Events.RevisionAdded, this._revisionAdded, this);
1184 this.tooltip = resource.url;
1187 WebInspector.FrameResourceTreeElement.prototype = {
1190 return this._resource.url;
1193 onselect: function()
1195 WebInspector.BaseStorageTreeElement.prototype.onselect.call(this);
1196 this._storagePanel._showResourceView(this._resource);
1199 ondblclick: function(event)
1201 PageAgent.open(this._resource.url, true);
1204 onattach: function()
1206 WebInspector.BaseStorageTreeElement.prototype.onattach.call(this);
1208 if (this._resource.category === WebInspector.resourceCategories.images) {
1209 var previewImage = document.createElement("img");
1210 previewImage.className = "image-resource-icon-preview";
1211 this._resource.populateImageSource(previewImage);
1213 var iconElement = document.createElement("div");
1214 iconElement.className = "icon";
1215 iconElement.appendChild(previewImage);
1216 this.listItemElement.replaceChild(iconElement, this.imageElement);
1219 this._statusElement = document.createElement("div");
1220 this._statusElement.className = "status";
1221 this.listItemElement.insertBefore(this._statusElement, this.titleElement);
1223 this.listItemElement.draggable = true;
1224 this.listItemElement.addEventListener("dragstart", this._ondragstart.bind(this), false);
1225 this.listItemElement.addEventListener("contextmenu", this._handleContextMenuEvent.bind(this), true);
1227 this._updateErrorsAndWarningsBubbles();
1230 _ondragstart: function(event)
1232 event.dataTransfer.setData("text/plain", this._resource.content);
1233 event.dataTransfer.effectAllowed = "copy";
1237 _handleContextMenuEvent: function(event)
1239 var contextMenu = new WebInspector.ContextMenu();
1240 contextMenu.appendItem(WebInspector.openLinkExternallyLabel(), WebInspector.openResource.bind(WebInspector, this._resource.url, false));
1241 this._appendOpenInNetworkPanelAction(contextMenu, event);
1242 WebInspector.populateResourceContextMenu(contextMenu, this._resource.url);
1243 this._appendSaveAsAction(contextMenu, event);
1244 contextMenu.show(event);
1247 _appendOpenInNetworkPanelAction: function(contextMenu, event)
1249 if (!this._resource.requestId)
1252 contextMenu.appendItem(WebInspector.openInNetworkPanelLabel(), WebInspector.openRequestInNetworkPanel.bind(WebInspector, this._resource));
1255 _appendSaveAsAction: function(contextMenu, event)
1257 if (!Preferences.saveAsAvailable)
1260 if (this._resource.type !== WebInspector.Resource.Type.Document &&
1261 this._resource.type !== WebInspector.Resource.Type.Stylesheet &&
1262 this._resource.type !== WebInspector.Resource.Type.Script)
1267 var fileName = this._resource.displayName;
1268 this._resource.requestContent(InspectorFrontendHost.saveAs.bind(InspectorFrontendHost, fileName));
1271 contextMenu.appendSeparator();
1272 contextMenu.appendItem(WebInspector.UIString(WebInspector.useLowerCaseMenuTitles() ? "Save as..." : "Save As..."), save.bind(this));
1275 _setBubbleText: function(x)
1277 if (!this._bubbleElement) {
1278 this._bubbleElement = document.createElement("div");
1279 this._bubbleElement.className = "bubble";
1280 this._statusElement.appendChild(this._bubbleElement);
1283 this._bubbleElement.textContent = x;
1286 _resetBubble: function()
1288 if (this._bubbleElement) {
1289 this._bubbleElement.textContent = "";
1290 this._bubbleElement.removeStyleClass("search-matches");
1291 this._bubbleElement.removeStyleClass("warning");
1292 this._bubbleElement.removeStyleClass("error");
1296 _resetSearchResults: function()
1298 this._resetBubble();
1299 this._searchMatchesCount = 0;
1302 get searchMatchesCount()
1304 return this._searchMatchesCount;
1307 searchMatchesFound: function(matchesCount)
1309 this._resetSearchResults();
1311 this._searchMatchesCount = matchesCount;
1312 this._setBubbleText(matchesCount);
1313 this._bubbleElement.addStyleClass("search-matches");
1315 // Expand, do not scroll into view.
1316 var currentAncestor = this.parent;
1317 while (currentAncestor && !currentAncestor.root) {
1318 if (!currentAncestor.expanded)
1319 currentAncestor.expand();
1320 currentAncestor = currentAncestor.parent;
1324 _updateErrorsAndWarningsBubbles: function()
1326 if (this._storagePanel.currentQuery)
1329 this._resetBubble();
1331 if (this._resource.warnings || this._resource.errors)
1332 this._setBubbleText(this._resource.warnings + this._resource.errors);
1334 if (this._resource.warnings)
1335 this._bubbleElement.addStyleClass("warning");
1337 if (this._resource.errors)
1338 this._bubbleElement.addStyleClass("error");
1341 _consoleMessagesCleared: function()
1343 // FIXME: move to the SourceFrame.
1344 if (this._sourceView)
1345 this._sourceView.clearMessages();
1347 this._updateErrorsAndWarningsBubbles();
1350 _consoleMessageAdded: function(event)
1352 var msg = event.data;
1353 if (this._sourceView)
1354 this._sourceView.addMessage(msg);
1355 this._updateErrorsAndWarningsBubbles();
1358 _populateRevisions: function()
1360 for (var i = 0; i < this._resource.history.length; ++i)
1361 this._appendRevision(this._resource.history[i]);
1364 _revisionAdded: function(event)
1366 this._appendRevision(event.data);
1369 _appendRevision: function(revision)
1371 this.insertChild(new WebInspector.ResourceRevisionTreeElement(this._storagePanel, revision), 0);
1372 var oldView = this._sourceView;
1374 // This is needed when resource content was changed from scripts panel.
1375 var newView = this._recreateSourceView();
1376 if (oldView === this._storagePanel.visibleView)
1377 this._storagePanel._showResourceView(this._resource);
1381 sourceView: function()
1383 if (!this._sourceView) {
1384 this._sourceView = this._createSourceView();
1385 if (this._resource.messages) {
1386 for (var i = 0; i < this._resource.messages.length; i++)
1387 this._sourceView.addMessage(this._resource.messages[i]);
1390 return this._sourceView;
1393 _createSourceView: function()
1395 return new WebInspector.EditableResourceSourceFrame(this._resource);
1398 _recreateSourceView: function()
1400 var oldView = this._sourceView;
1401 var newView = this._createSourceView();
1403 var oldViewParentNode = oldView.isShowing() ? oldView.element.parentNode : null;
1404 newView.inheritScrollPositions(oldView);
1406 this._sourceView.detach();
1407 this._sourceView = newView;
1409 if (oldViewParentNode)
1410 newView.show(oldViewParentNode);
1416 WebInspector.FrameResourceTreeElement.prototype.__proto__ = WebInspector.BaseStorageTreeElement.prototype;
1420 * @extends {WebInspector.BaseStorageTreeElement}
1422 WebInspector.DatabaseTreeElement = function(storagePanel, database)
1424 WebInspector.BaseStorageTreeElement.call(this, storagePanel, null, database.name, ["database-storage-tree-item"], true);
1425 this._database = database;
1428 WebInspector.DatabaseTreeElement.prototype = {
1431 return "database://" + encodeURI(this._database.name);
1434 onselect: function()
1436 WebInspector.BaseStorageTreeElement.prototype.onselect.call(this);
1437 this._storagePanel.showDatabase(this._database);
1440 oncollapse: function()
1442 // Request a refresh after every collapse so the next
1443 // expand will have an updated table list.
1444 this.shouldRefreshChildren = true;
1447 onpopulate: function()
1449 this.removeChildren();
1451 function tableNamesCallback(tableNames)
1453 var tableNamesLength = tableNames.length;
1454 for (var i = 0; i < tableNamesLength; ++i)
1455 this.appendChild(new WebInspector.DatabaseTableTreeElement(this._storagePanel, this._database, tableNames[i]));
1457 this._database.getTableNames(tableNamesCallback.bind(this));
1461 WebInspector.DatabaseTreeElement.prototype.__proto__ = WebInspector.BaseStorageTreeElement.prototype;
1465 * @extends {WebInspector.BaseStorageTreeElement}
1467 WebInspector.DatabaseTableTreeElement = function(storagePanel, database, tableName)
1469 WebInspector.BaseStorageTreeElement.call(this, storagePanel, null, tableName, ["database-storage-tree-item"]);
1470 this._database = database;
1471 this._tableName = tableName;
1474 WebInspector.DatabaseTableTreeElement.prototype = {
1477 return "database://" + encodeURI(this._database.name) + "/" + encodeURI(this._tableName);
1480 onselect: function()
1482 WebInspector.BaseStorageTreeElement.prototype.onselect.call(this);
1483 this._storagePanel.showDatabase(this._database, this._tableName);
1486 WebInspector.DatabaseTableTreeElement.prototype.__proto__ = WebInspector.BaseStorageTreeElement.prototype;
1490 * @extends {WebInspector.BaseStorageTreeElement}
1492 WebInspector.DOMStorageTreeElement = function(storagePanel, domStorage, className)
1494 WebInspector.BaseStorageTreeElement.call(this, storagePanel, null, domStorage.domain ? domStorage.domain : WebInspector.UIString("Local Files"), ["domstorage-storage-tree-item", className]);
1495 this._domStorage = domStorage;
1498 WebInspector.DOMStorageTreeElement.prototype = {
1501 return "storage://" + this._domStorage.domain + "/" + (this._domStorage.isLocalStorage ? "local" : "session");
1504 onselect: function()
1506 WebInspector.BaseStorageTreeElement.prototype.onselect.call(this);
1507 this._storagePanel.showDOMStorage(this._domStorage);
1510 WebInspector.DOMStorageTreeElement.prototype.__proto__ = WebInspector.BaseStorageTreeElement.prototype;
1514 * @extends {WebInspector.BaseStorageTreeElement}
1516 WebInspector.CookieTreeElement = function(storagePanel, cookieDomain)
1518 WebInspector.BaseStorageTreeElement.call(this, storagePanel, null, cookieDomain ? cookieDomain : WebInspector.UIString("Local Files"), ["cookie-storage-tree-item"]);
1519 this._cookieDomain = cookieDomain;
1522 WebInspector.CookieTreeElement.prototype = {
1525 return "cookies://" + this._cookieDomain;
1528 onselect: function()
1530 WebInspector.BaseStorageTreeElement.prototype.onselect.call(this);
1531 this._storagePanel.showCookies(this, this._cookieDomain);
1534 WebInspector.CookieTreeElement.prototype.__proto__ = WebInspector.BaseStorageTreeElement.prototype;
1538 * @extends {WebInspector.BaseStorageTreeElement}
1540 WebInspector.ApplicationCacheManifestTreeElement = function(storagePanel, manifestURL)
1542 var title = WebInspector.Resource.displayName(manifestURL);
1543 WebInspector.BaseStorageTreeElement.call(this, storagePanel, null, title, ["application-cache-storage-tree-item"]);
1544 this.tooltip = manifestURL;
1545 this._manifestURL = manifestURL;
1548 WebInspector.ApplicationCacheManifestTreeElement.prototype = {
1551 return "appcache://" + this._manifestURL;
1556 return this._manifestURL;
1559 onselect: function()
1561 WebInspector.BaseStorageTreeElement.prototype.onselect.call(this);
1562 this._storagePanel.showCategoryView(this._manifestURL);
1565 WebInspector.ApplicationCacheManifestTreeElement.prototype.__proto__ = WebInspector.BaseStorageTreeElement.prototype;
1569 * @extends {WebInspector.BaseStorageTreeElement}
1571 WebInspector.ApplicationCacheFrameTreeElement = function(storagePanel, frameId, manifestURL)
1573 WebInspector.BaseStorageTreeElement.call(this, storagePanel, null, "", ["frame-storage-tree-item"]);
1574 this._frameId = frameId;
1575 this._manifestURL = manifestURL;
1576 this._refreshTitles();
1579 WebInspector.ApplicationCacheFrameTreeElement.prototype = {
1582 return "appcache://" + this._manifestURL + "/" + encodeURI(this.displayName);
1587 return this._frameId;
1592 return this._manifestURL;
1595 _refreshTitles: function()
1597 var frame = WebInspector.resourceTreeModel.frameForId(this._frameId);
1599 this.subtitleText = WebInspector.UIString("new frame");
1602 this.titleText = frame.name;
1603 this.subtitleText = WebInspector.Resource.displayName(frame.url);
1606 frameNavigated: function()
1608 this._refreshTitles();
1611 onselect: function()
1613 WebInspector.BaseStorageTreeElement.prototype.onselect.call(this);
1614 this._storagePanel.showApplicationCache(this._frameId);
1617 WebInspector.ApplicationCacheFrameTreeElement.prototype.__proto__ = WebInspector.BaseStorageTreeElement.prototype;
1621 * @extends {WebInspector.BaseStorageTreeElement}
1623 WebInspector.ResourceRevisionTreeElement = function(storagePanel, revision)
1625 var title = revision.timestamp ? revision.timestamp.toLocaleTimeString() : WebInspector.UIString("(original)");
1626 WebInspector.BaseStorageTreeElement.call(this, storagePanel, revision, title, ["resource-sidebar-tree-item", "resources-category-" + revision.resource.category.name]);
1627 if (revision.timestamp)
1628 this.tooltip = revision.timestamp.toLocaleString();
1629 this._revision = revision;
1632 WebInspector.ResourceRevisionTreeElement.prototype = {
1635 return this._revision.resource.url;
1638 onattach: function()
1640 WebInspector.BaseStorageTreeElement.prototype.onattach.call(this);
1641 this.listItemElement.draggable = true;
1642 this.listItemElement.addEventListener("dragstart", this._ondragstart.bind(this), false);
1643 this.listItemElement.addEventListener("contextmenu", this._handleContextMenuEvent.bind(this), true);
1646 onselect: function()
1648 WebInspector.BaseStorageTreeElement.prototype.onselect.call(this);
1649 this._storagePanel._showRevisionView(this._revision);
1652 _ondragstart: function(event)
1654 if (this._revision.content) {
1655 event.dataTransfer.setData("text/plain", this._revision.content);
1656 event.dataTransfer.effectAllowed = "copy";
1661 _handleContextMenuEvent: function(event)
1663 var contextMenu = new WebInspector.ContextMenu();
1664 contextMenu.appendItem(WebInspector.UIString("Revert to this revision"), this._revision.revertToThis.bind(this._revision));
1666 if (Preferences.saveAsAvailable) {
1669 var fileName = this._revision.resource.displayName;
1670 this._revision.requestContent(InspectorFrontendHost.saveAs.bind(InspectorFrontendHost, fileName));
1672 contextMenu.appendSeparator();
1673 contextMenu.appendItem(WebInspector.UIString(WebInspector.useLowerCaseMenuTitles() ? "Save as..." : "Save As..."), save.bind(this));
1676 contextMenu.show(event);
1679 sourceView: function()
1681 if (!this._sourceView)
1682 this._sourceView = new WebInspector.ResourceRevisionSourceFrame(this._revision);
1683 return this._sourceView;
1687 WebInspector.ResourceRevisionTreeElement.prototype.__proto__ = WebInspector.BaseStorageTreeElement.prototype;
1691 * @extends {WebInspector.View}
1693 WebInspector.StorageCategoryView = function()
1695 WebInspector.View.call(this);
1697 this.element.addStyleClass("storage-view");
1698 this._emptyView = new WebInspector.EmptyView("");
1699 this._emptyView.show(this.element);
1702 WebInspector.StorageCategoryView.prototype = {
1703 setText: function(text)
1705 this._emptyView.text = text;
1709 WebInspector.StorageCategoryView.prototype.__proto__ = WebInspector.View.prototype;
1713 * @param {WebInspector.BaseStorageTreeElement} rootElement
1714 * @param {number} matchesCount
1716 WebInspector.ResourcesSearchController = function(rootElement, matchesCount)
1718 this._root = rootElement;
1719 this._matchesCount = matchesCount;
1720 this._traverser = new WebInspector.SearchResultsTreeElementsTraverser(rootElement);
1721 this._lastTreeElement = null;
1722 this._lastIndex = -1;
1725 WebInspector.ResourcesSearchController.prototype = {
1727 * @param {WebInspector.BaseStorageTreeElement} currentTreeElement
1729 nextSearchResult: function(currentTreeElement)
1731 if (!currentTreeElement)
1732 return this._searchResult(this._traverser.first(), 0, 1);
1734 if (!currentTreeElement.searchMatchesCount)
1735 return this._searchResult(this._traverser.next(currentTreeElement), 0);
1737 if (this._lastTreeElement !== currentTreeElement || this._lastIndex === -1)
1738 return this._searchResult(currentTreeElement, 0);
1740 if (this._lastIndex == currentTreeElement.searchMatchesCount - 1)
1741 return this._searchResult(this._traverser.next(currentTreeElement), 0, this._currentMatchIndex % this._matchesCount + 1);
1743 return this._searchResult(currentTreeElement, this._lastIndex + 1, this._currentMatchIndex + 1);
1747 * @param {WebInspector.BaseStorageTreeElement} currentTreeElement
1749 previousSearchResult: function(currentTreeElement)
1751 if (!currentTreeElement) {
1752 var treeElement = this._traverser.last();
1753 return this._searchResult(treeElement, treeElement.searchMatchesCount - 1, this._matchesCount);
1756 if (currentTreeElement.searchMatchesCount && this._lastTreeElement === currentTreeElement) {
1757 if (this._lastIndex > 0)
1758 return this._searchResult(currentTreeElement, this._lastIndex - 1, this._currentMatchIndex - 1);
1760 var treeElement = this._traverser.previous(currentTreeElement);
1761 var currentMatchIndex = this._currentMatchIndex - 1 ? this._currentMatchIndex - 1 : this._matchesCount;
1762 return this._searchResult(treeElement, treeElement.searchMatchesCount - 1, currentMatchIndex);
1766 var treeElement = this._traverser.previous(currentTreeElement)
1767 return this._searchResult(treeElement, treeElement.searchMatchesCount - 1);
1771 * @param {WebInspector.BaseStorageTreeElement} treeElement
1772 * @param {number} index
1773 * @param {number=} currentMatchIndex
1776 _searchResult: function(treeElement, index, currentMatchIndex)
1778 this._lastTreeElement = treeElement;
1779 this._lastIndex = index;
1780 if (!currentMatchIndex)
1781 currentMatchIndex = this._traverser.matchIndex(treeElement, index);
1782 this._currentMatchIndex = currentMatchIndex;
1783 return {treeElement: treeElement, index: index, currentMatchIndex: currentMatchIndex};
1789 * @param {WebInspector.BaseStorageTreeElement} rootElement
1791 WebInspector.SearchResultsTreeElementsTraverser = function(rootElement)
1793 this._root = rootElement;
1796 WebInspector.SearchResultsTreeElementsTraverser.prototype = {
1798 * @return {WebInspector.BaseStorageTreeElement}
1802 return this.next(this._root);
1806 * @return {WebInspector.BaseStorageTreeElement}
1810 return this.previous(this._root);
1814 * @param {WebInspector.BaseStorageTreeElement} startTreeElement
1815 * @return {WebInspector.BaseStorageTreeElement}
1817 next: function(startTreeElement)
1819 var treeElement = startTreeElement;
1821 treeElement = this._traverseNext(treeElement) || this._root;
1822 } while (treeElement != startTreeElement && !this._elementSearchMatchesCount(treeElement));
1827 * @param {WebInspector.BaseStorageTreeElement} startTreeElement
1828 * @return {WebInspector.BaseStorageTreeElement}
1830 previous: function(startTreeElement)
1832 var treeElement = startTreeElement;
1834 treeElement = this._traversePrevious(treeElement) || this._lastTreeElement();
1835 } while (treeElement != startTreeElement && !this._elementSearchMatchesCount(treeElement));
1840 * @param {WebInspector.BaseStorageTreeElement} startTreeElement
1841 * @param {number} index
1844 matchIndex: function(startTreeElement, index)
1847 var treeElement = this._root;
1848 while (treeElement != startTreeElement) {
1849 matchIndex += this._elementSearchMatchesCount(treeElement);
1850 treeElement = this._traverseNext(treeElement) || this._root;
1851 if (treeElement === this._root)
1854 return matchIndex + index;
1858 * @param {WebInspector.BaseStorageTreeElement} treeElement
1861 _elementSearchMatchesCount: function(treeElement)
1863 return treeElement.searchMatchesCount;
1867 * @param {WebInspector.BaseStorageTreeElement} treeElement
1868 * @return {WebInspector.BaseStorageTreeElement}
1870 _traverseNext: function(treeElement)
1872 return /** @type {WebInspector.BaseStorageTreeElement} */ treeElement.traverseNextTreeElement(false, this._root, true);
1876 * @param {WebInspector.BaseStorageTreeElement} treeElement
1877 * @return {WebInspector.BaseStorageTreeElement}
1879 _traversePrevious: function(treeElement)
1881 return /** @type {WebInspector.BaseStorageTreeElement} */ treeElement.traversePreviousTreeElement(false, true);
1885 * @return {WebInspector.BaseStorageTreeElement}
1887 _lastTreeElement: function()
1889 var treeElement = this._root;
1890 var nextTreeElement;
1891 while (nextTreeElement = this._traverseNext(treeElement))
1892 treeElement = nextTreeElement;