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");
38 WebInspector.settings.resourcesLastSelectedItem = WebInspector.settings.createSetting("resourcesLastSelectedItem", {});
41 this.sidebarElement.addStyleClass("outline-disclosure");
42 this.sidebarElement.addStyleClass("filter-all");
43 this.sidebarElement.addStyleClass("children");
44 this.sidebarElement.addStyleClass("small");
45 this.sidebarTreeElement.removeStyleClass("sidebar-tree");
47 this.resourcesListTreeElement = new WebInspector.StorageCategoryTreeElement(this, WebInspector.UIString("Frames"), "Frames", ["frame-storage-tree-item"]);
48 this.sidebarTree.appendChild(this.resourcesListTreeElement);
50 this.databasesListTreeElement = new WebInspector.StorageCategoryTreeElement(this, WebInspector.UIString("Databases"), "Databases", ["database-storage-tree-item"]);
51 this.sidebarTree.appendChild(this.databasesListTreeElement);
53 this.localStorageListTreeElement = new WebInspector.StorageCategoryTreeElement(this, WebInspector.UIString("Local Storage"), "LocalStorage", ["domstorage-storage-tree-item", "local-storage"]);
54 this.sidebarTree.appendChild(this.localStorageListTreeElement);
56 this.sessionStorageListTreeElement = new WebInspector.StorageCategoryTreeElement(this, WebInspector.UIString("Session Storage"), "SessionStorage", ["domstorage-storage-tree-item", "session-storage"]);
57 this.sidebarTree.appendChild(this.sessionStorageListTreeElement);
59 this.cookieListTreeElement = new WebInspector.StorageCategoryTreeElement(this, WebInspector.UIString("Cookies"), "Cookies", ["cookie-storage-tree-item"]);
60 this.sidebarTree.appendChild(this.cookieListTreeElement);
62 this.applicationCacheListTreeElement = new WebInspector.StorageCategoryTreeElement(this, WebInspector.UIString("Application Cache"), "ApplicationCache", ["application-cache-storage-tree-item"]);
63 this.sidebarTree.appendChild(this.applicationCacheListTreeElement);
65 this.storageViews = document.createElement("div");
66 this.storageViews.id = "storage-views";
67 this.storageViews.className = "diff-container";
68 this.element.appendChild(this.storageViews);
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);
91 WebInspector.ResourcesPanel.prototype = {
92 get toolbarItemLabel()
94 return WebInspector.UIString("Resources");
99 return [this.storageViewStatusBarItemsContainer];
102 elementsToRestoreScrollPositionsFor: function()
104 return [this.sidebarElement];
109 WebInspector.Panel.prototype.show.call(this);
111 this._populateResourceTree();
114 _onLoadEventFired: function()
116 this._initDefaultSelection();
119 _initDefaultSelection: function()
121 if (!this._treeElementForFrameId)
124 var itemURL = WebInspector.settings.resourcesLastSelectedItem.get();
126 for (var treeElement = this.sidebarTree.children[0]; treeElement; treeElement = treeElement.traverseNextTreeElement(false, this.sidebarTree, true)) {
127 if (treeElement.itemURL === itemURL) {
128 treeElement.revealAndSelect(true);
134 if (WebInspector.mainResource && this.resourcesListTreeElement && this.resourcesListTreeElement.expanded)
135 this.showResource(WebInspector.mainResource);
142 for (var i = 0; i < this._databases.length; ++i) {
143 var database = this._databases[i];
144 delete database._tableViews;
145 if (database._queryView)
146 database._queryView.removeEventListener(WebInspector.DatabaseQueryView.Events.SchemaUpdated, this._updateDatabaseTables, this);
147 delete database._queryView;
149 this._databases = [];
151 var domStorageLength = this._domStorage.length;
152 for (var i = 0; i < this._domStorage.length; ++i) {
153 var domStorage = this._domStorage[i];
154 delete domStorage._domStorageView;
156 this._domStorage = [];
158 this._cookieViews = {};
160 this._applicationCacheView = null;
161 delete this._cachedApplicationCacheViewStatus;
163 this.databasesListTreeElement.removeChildren();
164 this.localStorageListTreeElement.removeChildren();
165 this.sessionStorageListTreeElement.removeChildren();
166 this.cookieListTreeElement.removeChildren();
167 this.applicationCacheListTreeElement.removeChildren();
168 this.storageViews.removeChildren();
170 this.storageViewStatusBarItemsContainer.removeChildren();
172 if (this.sidebarTree.selectedTreeElement)
173 this.sidebarTree.selectedTreeElement.deselect();
175 var childViews = this.childViews();
176 for (var i = 0; i < childViews.length; ++i)
177 this.removeChildView(childViews[i]);
180 _populateResourceTree: function()
182 if (this._treeElementForFrameId)
185 this._treeElementForFrameId = {};
186 WebInspector.resourceTreeModel.addEventListener(WebInspector.ResourceTreeModel.EventTypes.FrameAdded, this._frameAdded, this);
187 WebInspector.resourceTreeModel.addEventListener(WebInspector.ResourceTreeModel.EventTypes.FrameNavigated, this._frameNavigated, this);
188 WebInspector.resourceTreeModel.addEventListener(WebInspector.ResourceTreeModel.EventTypes.FrameDetached, this._frameDetached, this);
189 WebInspector.resourceTreeModel.addEventListener(WebInspector.ResourceTreeModel.EventTypes.ResourceAdded, this._resourceAdded, this);
190 WebInspector.resourceTreeModel.addEventListener(WebInspector.ResourceTreeModel.EventTypes.CachedResourcesLoaded, this._cachedResourcesLoaded, this);
191 WebInspector.resourceTreeModel.addEventListener(WebInspector.ResourceTreeModel.EventTypes.WillLoadCachedResources, this._resetResourcesTree, this);
193 function populateFrame(frameId)
195 var subframes = WebInspector.resourceTreeModel.subframes(frameId);
196 for (var i = 0; i < subframes.length; ++i) {
197 this._frameAdded({data:subframes[i]});
198 populateFrame.call(this, subframes[i].id);
201 var resources = WebInspector.resourceTreeModel.resources(frameId);
202 for (var i = 0; i < resources.length; ++i)
203 this._resourceAdded({data:resources[i]});
205 populateFrame.call(this, "");
207 this._initDefaultSelection();
210 _frameAdded: function(event)
212 var frame = event.data;
213 var parentFrameId = frame.parentId;
215 var parentTreeElement = parentFrameId ? this._treeElementForFrameId[parentFrameId] : this.resourcesListTreeElement;
216 if (!parentTreeElement) {
217 console.warn("No frame with id:" + parentFrameId + " to route " + frame.name + "/" + frame.url + " to.")
221 var frameTreeElement = new WebInspector.FrameTreeElement(this, frame);
222 this._treeElementForFrameId[frame.id] = frameTreeElement;
223 parentTreeElement.appendChild(frameTreeElement);
226 _frameDetached: function(event)
228 var frameId = event.data;
229 var frameTreeElement = this._treeElementForFrameId[frameId];
230 if (!frameTreeElement)
233 delete this._treeElementForFrameId[frameId];
234 if (frameTreeElement.parent)
235 frameTreeElement.parent.removeChild(frameTreeElement);
238 _resourceAdded: function(event)
240 var resource = event.data;
241 var frameId = resource.frameId;
243 if (resource.statusCode >= 301 && resource.statusCode <= 303)
246 var frameTreeElement = this._treeElementForFrameId[frameId];
247 if (!frameTreeElement) {
248 // This is a frame's main resource, it will be retained
249 // and re-added by the resource manager;
253 frameTreeElement.appendResource(resource);
256 _frameNavigated: function(event)
258 var frameId = event.data.frame.id;
259 var frameTreeElement = this._treeElementForFrameId[frameId];
260 if (frameTreeElement)
261 frameTreeElement.frameNavigated(event.data.frame);
264 _resetResourcesTree: function()
266 this.resourcesListTreeElement.removeChildren();
267 this._treeElementForFrameId = {};
271 _cachedResourcesLoaded: function()
273 this._initDefaultSelection();
276 addDatabase: function(database)
278 this._databases.push(database);
280 var databaseTreeElement = new WebInspector.DatabaseTreeElement(this, database);
281 database._databasesTreeElement = databaseTreeElement;
282 this.databasesListTreeElement.appendChild(databaseTreeElement);
285 addDocumentURL: function(url)
287 var parsedURL = url.asParsedURL();
291 var domain = parsedURL.host;
292 if (!this._domains[domain]) {
293 this._domains[domain] = true;
295 var cookieDomainTreeElement = new WebInspector.CookieTreeElement(this, domain);
296 this.cookieListTreeElement.appendChild(cookieDomainTreeElement);
298 var applicationCacheTreeElement = new WebInspector.ApplicationCacheTreeElement(this, domain);
299 this.applicationCacheListTreeElement.appendChild(applicationCacheTreeElement);
303 addDOMStorage: function(domStorage)
305 this._domStorage.push(domStorage);
306 var domStorageTreeElement = new WebInspector.DOMStorageTreeElement(this, domStorage, (domStorage.isLocalStorage ? "local-storage" : "session-storage"));
307 domStorage._domStorageTreeElement = domStorageTreeElement;
308 if (domStorage.isLocalStorage)
309 this.localStorageListTreeElement.appendChild(domStorageTreeElement);
311 this.sessionStorageListTreeElement.appendChild(domStorageTreeElement);
314 selectDatabase: function(databaseId)
317 for (var i = 0, len = this._databases.length; i < len; ++i) {
318 database = this._databases[i];
319 if (database.id === databaseId) {
320 this.showDatabase(database);
321 database._databasesTreeElement.select();
327 selectDOMStorage: function(storageId)
329 var domStorage = this._domStorageForId(storageId);
331 this.showDOMStorage(domStorage);
332 domStorage._domStorageTreeElement.select();
336 canShowAnchorLocation: function(anchor)
338 return !!WebInspector.resourceForURL(anchor.href);
341 showAnchorLocation: function(anchor)
343 var resource = WebInspector.resourceForURL(anchor.href);
344 var lineNumber = anchor.hasAttribute("line_number") ? parseInt(anchor.getAttribute("line_number"), 10) : undefined;
345 this.showResource(resource, lineNumber);
349 * @param {number=} line
351 showResource: function(resource, line)
353 var resourceTreeElement = this._findTreeElementForResource(resource);
354 if (resourceTreeElement)
355 resourceTreeElement.revealAndSelect();
357 if (typeof line === "number") {
358 var view = this._resourceViewForResource(resource);
359 if (view.canHighlightLine())
360 view.highlightLine(line);
365 _showResourceView: function(resource)
367 var view = this._resourceViewForResource(resource);
369 this.visibleView.hide();
372 if (view.searchCanceled)
373 view.searchCanceled();
374 this._fetchAndApplyDiffMarkup(view, resource);
375 this._innerShowView(view);
378 _resourceViewForResource: function(resource)
380 if (WebInspector.ResourceView.hasTextContent(resource)) {
381 var treeElement = this._findTreeElementForResource(resource);
384 return treeElement.sourceView();
386 return WebInspector.ResourceView.nonSourceViewForResource(resource);
389 _showRevisionView: function(revision)
391 var view = this._sourceViewForRevision(revision);
392 this._fetchAndApplyDiffMarkup(view, revision.resource, revision);
393 this._innerShowView(view);
396 _sourceViewForRevision: function(revision)
398 var treeElement = this._findTreeElementForRevision(revision);
399 return treeElement.sourceView();
403 * @param {WebInspector.ResourceRevision=} revision
405 _fetchAndApplyDiffMarkup: function(view, resource, revision)
407 var baseRevision = resource.history[0];
410 if (!(view instanceof WebInspector.SourceFrame))
413 baseRevision.requestContent(step1.bind(this));
415 function step1(baseContent)
417 (revision ? revision : resource).requestContent(step2.bind(this, baseContent));
420 function step2(baseContent, revisionContent)
422 this._applyDiffMarkup(view, baseContent, revisionContent);
426 _applyDiffMarkup: function(view, baseContent, newContent)
428 var diffData = TextDiff.compute(baseContent, newContent);
429 view.markDiff(diffData);
433 * @param {string=} tableName
435 showDatabase: function(database, tableName)
442 if (!("_tableViews" in database))
443 database._tableViews = {};
444 view = database._tableViews[tableName];
446 view = new WebInspector.DatabaseTableView(database, tableName);
447 database._tableViews[tableName] = view;
450 view = database._queryView;
452 view = new WebInspector.DatabaseQueryView(database);
453 database._queryView = view;
454 view.addEventListener(WebInspector.DatabaseQueryView.Events.SchemaUpdated, this._updateDatabaseTables, this);
458 this._innerShowView(view);
461 showDOMStorage: function(domStorage)
467 view = domStorage._domStorageView;
469 view = new WebInspector.DOMStorageItemsView(domStorage);
470 domStorage._domStorageView = view;
473 this._innerShowView(view);
476 showCookies: function(treeElement, cookieDomain)
478 var view = this._cookieViews[cookieDomain];
480 view = new WebInspector.CookieItemsView(treeElement, cookieDomain);
481 this._cookieViews[cookieDomain] = view;
484 this._innerShowView(view);
487 showApplicationCache: function(treeElement, appcacheDomain)
489 var view = this._applicationCacheView;
491 view = new WebInspector.ApplicationCacheItemsView(treeElement, appcacheDomain);
492 this._applicationCacheView = view;
495 this._innerShowView(view);
497 if ("_cachedApplicationCacheViewStatus" in this)
498 this._applicationCacheView.updateStatus(this._cachedApplicationCacheViewStatus);
501 showCategoryView: function(categoryName)
503 if (!this._categoryView)
504 this._categoryView = new WebInspector.StorageCategoryView();
505 this._categoryView.setText(categoryName);
506 this._innerShowView(this._categoryView);
509 _innerShowView: function(view)
511 if (this.visibleView)
512 this.visibleView.hide();
514 this.addChildView(view);
515 view.show(this.storageViews);
516 this.visibleView = view;
518 this.storageViewStatusBarItemsContainer.removeChildren();
519 var statusBarItems = view.statusBarItems || [];
520 for (var i = 0; i < statusBarItems.length; ++i)
521 this.storageViewStatusBarItemsContainer.appendChild(statusBarItems[i]);
524 closeVisibleView: function()
526 if (!this.visibleView)
528 this.visibleView.hide();
529 delete this.visibleView;
532 _updateDatabaseTables: function(event)
534 var database = event.data;
536 if (!database || !database._databasesTreeElement)
539 database._databasesTreeElement.shouldRefreshChildren = true;
541 if (!("_tableViews" in database))
544 var tableNamesHash = {};
546 function tableNamesCallback(tableNames)
548 var tableNamesLength = tableNames.length;
549 for (var i = 0; i < tableNamesLength; ++i)
550 tableNamesHash[tableNames[i]] = true;
552 for (var tableName in database._tableViews) {
553 if (!(tableName in tableNamesHash)) {
554 if (self.visibleView === database._tableViews[tableName])
555 self.closeVisibleView();
556 delete database._tableViews[tableName];
560 database.getTableNames(tableNamesCallback);
563 updateDOMStorage: function(storageId)
565 var domStorage = this._domStorageForId(storageId);
569 var view = domStorage._domStorageView;
570 if (this.visibleView && view === this.visibleView)
571 domStorage._domStorageView.update();
574 updateApplicationCacheStatus: function(status)
576 this._cachedApplicationCacheViewStatus = status;
577 if (this._applicationCacheView && this._applicationCacheView === this.visibleView)
578 this._applicationCacheView.updateStatus(status);
581 updateNetworkState: function(isNowOnline)
583 if (this._applicationCacheView && this._applicationCacheView === this.visibleView)
584 this._applicationCacheView.updateNetworkState(isNowOnline);
587 updateManifest: function(manifest)
589 if (this._applicationCacheView && this._applicationCacheView === this.visibleView)
590 this._applicationCacheView.updateManifest(manifest);
593 _domStorageForId: function(storageId)
595 if (!this._domStorage)
597 var domStorageLength = this._domStorage.length;
598 for (var i = 0; i < domStorageLength; ++i) {
599 var domStorage = this._domStorage[i];
600 if (domStorage.id == storageId)
606 updateMainViewWidth: function(width)
608 this.storageViews.style.left = width + "px";
609 this.storageViewStatusBarItemsContainer.style.left = width + "px";
612 performSearch: function(query)
614 this._resetSearchResults();
615 var regex = WebInspector.SourceFrame.createSearchRegex(query);
616 var totalMatchesCount = 0;
618 function searchInEditedResource(treeElement)
620 var resource = treeElement.representedObject;
621 if (resource.history.length == 0)
623 var matchesCount = countRegexMatches(regex, resource.content)
624 treeElement.searchMatchesFound(matchesCount);
625 totalMatchesCount += matchesCount;
628 function callback(error, result)
631 for (var i = 0; i < result.length; i++) {
632 var searchResult = result[i];
633 var frameTreeElement = this._treeElementForFrameId[searchResult.frameId];
634 if (!frameTreeElement)
636 var resource = frameTreeElement.resourceByURL(searchResult.url);
638 // FIXME: When the same script is used in several frames and this script contains at least
639 // one search result then some search results can not be matched with a resource on panel.
640 // https://bugs.webkit.org/show_bug.cgi?id=66005
644 if (resource.history.length > 0)
645 continue; // Skip edited resources.
646 this._findTreeElementForResource(resource).searchMatchesFound(searchResult.matchesCount);
647 totalMatchesCount += searchResult.matchesCount;
651 WebInspector.searchController.updateSearchMatchesCount(totalMatchesCount, this);
652 this._searchController = new WebInspector.ResourcesSearchController(this.resourcesListTreeElement);
654 if (this.sidebarTree.selectedTreeElement && this.sidebarTree.selectedTreeElement.searchMatchesCount)
655 this.jumpToNextSearchResult();
658 this._forAllResourceTreeElements(searchInEditedResource.bind(this));
659 PageAgent.searchInResources(regex.source, !regex.ignoreCase, true, callback.bind(this));
662 _ensureViewSearchPerformed: function(callback)
664 function viewSearchPerformedCallback(searchId)
666 if (searchId !== this._lastViewSearchId)
667 return; // Search is obsolete.
668 this._viewSearchInProgress = false;
672 if (!this._viewSearchInProgress) {
673 if (!this.visibleView.hasSearchResults()) {
674 // We give id to each search, so that we can skip callbacks for obsolete searches.
675 this._lastViewSearchId = this._lastViewSearchId ? this._lastViewSearchId + 1 : 0;
676 this._viewSearchInProgress = true;
677 this.visibleView.performSearch(this.currentQuery, viewSearchPerformedCallback.bind(this, this._lastViewSearchId));
683 _showSearchResult: function(searchResult)
685 this._lastSearchResultIndex = searchResult.index;
686 this._lastSearchResultTreeElement = searchResult.treeElement;
688 // At first show view for treeElement.
689 if (searchResult.treeElement !== this.sidebarTree.selectedTreeElement) {
690 this.showResource(searchResult.treeElement.representedObject);
691 WebInspector.searchController.focusSearchField();
694 function callback(searchId)
696 if (this.sidebarTree.selectedTreeElement !== this._lastSearchResultTreeElement)
697 return; // User has selected another view while we were searching.
698 if (this._lastSearchResultIndex != -1)
699 this.visibleView.jumpToSearchResult(this._lastSearchResultIndex);
702 // Then run SourceFrame search if needed and jump to search result index when done.
703 this._ensureViewSearchPerformed(callback.bind(this));
706 _resetSearchResults: function()
708 function callback(resourceTreeElement)
710 resourceTreeElement._resetSearchResults();
713 this._forAllResourceTreeElements(callback);
714 if (this.visibleView && this.visibleView.searchCanceled)
715 this.visibleView.searchCanceled();
717 this._lastSearchResultTreeElement = null;
718 this._lastSearchResultIndex = -1;
719 this._viewSearchInProgress = false;
722 searchCanceled: function()
724 function callback(resourceTreeElement)
726 resourceTreeElement._updateErrorsAndWarningsBubbles();
729 WebInspector.searchController.updateSearchMatchesCount(0, this);
730 this._resetSearchResults();
731 this._forAllResourceTreeElements(callback);
734 jumpToNextSearchResult: function()
736 if (!this.currentSearchMatches)
738 var currentTreeElement = this.sidebarTree.selectedTreeElement;
739 var nextSearchResult = this._searchController.nextSearchResult(currentTreeElement);
740 this._showSearchResult(nextSearchResult);
743 jumpToPreviousSearchResult: function()
745 if (!this.currentSearchMatches)
747 var currentTreeElement = this.sidebarTree.selectedTreeElement;
748 var previousSearchResult = this._searchController.previousSearchResult(currentTreeElement);
749 this._showSearchResult(previousSearchResult);
752 _forAllResourceTreeElements: function(callback)
755 for (var treeElement = this.resourcesListTreeElement; !stop && treeElement; treeElement = treeElement.traverseNextTreeElement(false, this.resourcesListTreeElement, true)) {
756 if (treeElement instanceof WebInspector.FrameResourceTreeElement)
757 stop = callback(treeElement);
761 _findTreeElementForResource: function(resource)
763 function isAncestor(ancestor, object)
765 // Redirects, XHRs do not belong to the tree, it is fine to silently return false here.
769 function getParent(object)
771 // Redirects, XHRs do not belong to the tree, it is fine to silently return false here.
775 return this.sidebarTree.findTreeElement(resource, isAncestor, getParent);
778 _findTreeElementForRevision: function(revision)
780 function isAncestor(ancestor, object)
785 function getParent(object)
790 return this.sidebarTree.findTreeElement(revision, isAncestor, getParent);
793 showView: function(view)
796 this.showResource(view.resource);
799 _onmousemove: function(event)
801 var nodeUnderMouse = document.elementFromPoint(event.pageX, event.pageY);
805 var listNode = nodeUnderMouse.enclosingNodeOrSelfWithNodeName("li");
809 var element = listNode.treeElement;
810 if (this._previousHoveredElement === element)
813 if (this._previousHoveredElement) {
814 this._previousHoveredElement.hovered = false;
815 delete this._previousHoveredElement;
818 if (element instanceof WebInspector.FrameTreeElement) {
819 this._previousHoveredElement = element;
820 element.hovered = true;
824 _onmouseout: function(event)
826 if (this._previousHoveredElement) {
827 this._previousHoveredElement.hovered = false;
828 delete this._previousHoveredElement;
833 WebInspector.ResourcesPanel.prototype.__proto__ = WebInspector.Panel.prototype;
837 * @extends {TreeElement}
838 * @param {boolean=} hasChildren
839 * @param {boolean=} noIcon
841 WebInspector.BaseStorageTreeElement = function(storagePanel, representedObject, title, iconClasses, hasChildren, noIcon)
843 TreeElement.call(this, "", representedObject, hasChildren);
844 this._storagePanel = storagePanel;
845 this._titleText = title;
846 this._iconClasses = iconClasses;
847 this._noIcon = noIcon;
850 WebInspector.BaseStorageTreeElement.prototype = {
853 this.listItemElement.removeChildren();
854 if (this._iconClasses) {
855 for (var i = 0; i < this._iconClasses.length; ++i)
856 this.listItemElement.addStyleClass(this._iconClasses[i]);
859 var selectionElement = document.createElement("div");
860 selectionElement.className = "selection";
861 this.listItemElement.appendChild(selectionElement);
864 this.imageElement = document.createElement("img");
865 this.imageElement.className = "icon";
866 this.listItemElement.appendChild(this.imageElement);
869 this.titleElement = document.createElement("div");
870 this.titleElement.className = "base-storage-tree-element-title";
871 this.titleElement.textContent = this._titleText;
872 this.listItemElement.appendChild(this.titleElement);
877 var itemURL = this.itemURL;
879 WebInspector.settings.resourcesLastSelectedItem.set(itemURL);
884 if (this.listItemElement)
885 this.listItemElement.scrollIntoViewIfNeeded(false);
890 return this._titleText;
893 set titleText(titleText)
895 this._titleText = titleText;
896 if (this.titleElement)
897 this.titleElement.textContent = this._titleText;
900 isEventWithinDisclosureTriangle: function(event)
902 // Override it since we use margin-left in place of treeoutline's text-indent.
903 // Hence we need to take padding into consideration. This all is needed for leading
904 // icons in the tree.
905 const paddingLeft = 14;
906 var left = this.listItemElement.totalOffsetLeft() + paddingLeft;
907 return event.pageX >= left && event.pageX <= left + this.arrowToggleWidth && this.hasChildren;
911 WebInspector.BaseStorageTreeElement.prototype.__proto__ = TreeElement.prototype;
915 * @extends {WebInspector.BaseStorageTreeElement}
916 * @param {boolean=} noIcon
918 WebInspector.StorageCategoryTreeElement = function(storagePanel, categoryName, settingsKey, iconClasses, noIcon)
920 WebInspector.BaseStorageTreeElement.call(this, storagePanel, null, categoryName, iconClasses, true, noIcon);
921 this._expandedSettingKey = "resources" + settingsKey + "Expanded";
922 WebInspector.settings[this._expandedSettingKey] = WebInspector.settings.createSetting(this._expandedSettingKey, settingsKey === "Frames");
923 this._categoryName = categoryName;
926 WebInspector.StorageCategoryTreeElement.prototype = {
929 return "category://" + this._categoryName;
934 WebInspector.BaseStorageTreeElement.prototype.onselect.call(this);
935 this._storagePanel.showCategoryView(this._categoryName);
940 WebInspector.BaseStorageTreeElement.prototype.onattach.call(this);
941 if (WebInspector.settings[this._expandedSettingKey].get())
947 WebInspector.settings[this._expandedSettingKey].set(true);
950 oncollapse: function()
952 WebInspector.settings[this._expandedSettingKey].set(false);
956 WebInspector.StorageCategoryTreeElement.prototype.__proto__ = WebInspector.BaseStorageTreeElement.prototype;
960 * @extends {WebInspector.BaseStorageTreeElement}
962 WebInspector.FrameTreeElement = function(storagePanel, frame)
964 WebInspector.BaseStorageTreeElement.call(this, storagePanel, null, "", ["frame-storage-tree-item"]);
966 this.frameNavigated(frame);
969 WebInspector.FrameTreeElement.prototype = {
970 frameNavigated: function(frame)
972 this.removeChildren();
973 this._frameId = frame.id;
975 var title = frame.name;
976 var subtitle = WebInspector.Resource.displayName(frame.url);
977 this.setTitles(title, subtitle);
979 this._categoryElements = {};
980 this._treeElementForResource = {};
982 this._storagePanel.addDocumentURL(frame.url);
987 return "frame://" + encodeURI(this._displayName);
992 WebInspector.BaseStorageTreeElement.prototype.onattach.call(this);
993 if (this._titleToSetOnAttach || this._subtitleToSetOnAttach) {
994 this.setTitles(this._titleToSetOnAttach, this._subtitleToSetOnAttach);
995 delete this._titleToSetOnAttach;
996 delete this._subtitleToSetOnAttach;
1000 onselect: function()
1002 WebInspector.BaseStorageTreeElement.prototype.onselect.call(this);
1003 this._storagePanel.showCategoryView(this._displayName);
1005 this.listItemElement.removeStyleClass("hovered");
1006 DOMAgent.hideHighlight();
1011 return this._displayName;
1014 setTitles: function(title, subtitle)
1016 this._displayName = title || "";
1018 this._displayName += " (" + subtitle + ")";
1021 this.titleElement.textContent = title || "";
1023 var subtitleElement = document.createElement("span");
1024 subtitleElement.className = "base-storage-tree-element-subtitle";
1025 subtitleElement.textContent = "(" + subtitle + ")";
1026 this.titleElement.appendChild(subtitleElement);
1029 this._titleToSetOnAttach = title;
1030 this._subtitleToSetOnAttach = subtitle;
1034 set hovered(hovered)
1037 this.listItemElement.addStyleClass("hovered");
1038 DOMAgent.highlightFrame(this._frameId, WebInspector.Color.PageHighlight.Content.toProtocolRGBA(), WebInspector.Color.PageHighlight.ContentOutline.toProtocolRGBA());
1040 this.listItemElement.removeStyleClass("hovered");
1041 DOMAgent.hideHighlight();
1045 appendResource: function(resource)
1047 var categoryName = resource.category.name;
1048 var categoryElement = resource.category === WebInspector.resourceCategories.documents ? this : this._categoryElements[categoryName];
1049 if (!categoryElement) {
1050 categoryElement = new WebInspector.StorageCategoryTreeElement(this._storagePanel, resource.category.title, categoryName, null, true);
1051 this._categoryElements[resource.category.name] = categoryElement;
1052 this._insertInPresentationOrder(this, categoryElement);
1054 var resourceTreeElement = new WebInspector.FrameResourceTreeElement(this._storagePanel, resource);
1055 this._insertInPresentationOrder(categoryElement, resourceTreeElement);
1056 resourceTreeElement._populateRevisions();
1058 this._treeElementForResource[resource.url] = resourceTreeElement;
1061 resourceByURL: function(url)
1063 var treeElement = this._treeElementForResource[url];
1064 return treeElement ? treeElement.representedObject : null;
1067 appendChild: function(treeElement)
1069 this._insertInPresentationOrder(this, treeElement);
1072 _insertInPresentationOrder: function(parentTreeElement, childTreeElement)
1074 // Insert in the alphabetical order, first frames, then resources. Document resource goes last.
1075 function typeWeight(treeElement)
1077 if (treeElement instanceof WebInspector.StorageCategoryTreeElement)
1079 if (treeElement instanceof WebInspector.FrameTreeElement)
1084 function compare(treeElement1, treeElement2)
1086 var typeWeight1 = typeWeight(treeElement1);
1087 var typeWeight2 = typeWeight(treeElement2);
1090 if (typeWeight1 > typeWeight2)
1092 else if (typeWeight1 < typeWeight2)
1095 var title1 = treeElement1.displayName || treeElement1.titleText;
1096 var title2 = treeElement2.displayName || treeElement2.titleText;
1097 result = title1.localeCompare(title2);
1102 var children = parentTreeElement.children;
1104 for (i = 0; i < children.length; ++i) {
1105 if (compare(childTreeElement, children[i]) < 0)
1108 parentTreeElement.insertChild(childTreeElement, i);
1112 WebInspector.FrameTreeElement.prototype.__proto__ = WebInspector.BaseStorageTreeElement.prototype;
1116 * @extends {WebInspector.BaseStorageTreeElement}
1118 WebInspector.FrameResourceTreeElement = function(storagePanel, resource)
1120 WebInspector.BaseStorageTreeElement.call(this, storagePanel, resource, resource.displayName, ["resource-sidebar-tree-item", "resources-category-" + resource.category.name]);
1121 this._resource = resource;
1122 this._resource.addEventListener(WebInspector.Resource.Events.MessageAdded, this._consoleMessageAdded, this);
1123 this._resource.addEventListener(WebInspector.Resource.Events.MessagesCleared, this._consoleMessagesCleared, this);
1124 this._resource.addEventListener(WebInspector.Resource.Events.RevisionAdded, this._revisionAdded, this);
1125 this.tooltip = resource.url;
1128 WebInspector.FrameResourceTreeElement.prototype = {
1131 return this._resource.url;
1134 onselect: function()
1136 WebInspector.BaseStorageTreeElement.prototype.onselect.call(this);
1137 this._storagePanel._showResourceView(this._resource);
1140 ondblclick: function(event)
1142 PageAgent.open(this._resource.url, true);
1145 onattach: function()
1147 WebInspector.BaseStorageTreeElement.prototype.onattach.call(this);
1149 if (this._resource.category === WebInspector.resourceCategories.images) {
1150 var previewImage = document.createElement("img");
1151 previewImage.className = "image-resource-icon-preview";
1152 this._resource.populateImageSource(previewImage);
1154 var iconElement = document.createElement("div");
1155 iconElement.className = "icon";
1156 iconElement.appendChild(previewImage);
1157 this.listItemElement.replaceChild(iconElement, this.imageElement);
1160 this._statusElement = document.createElement("div");
1161 this._statusElement.className = "status";
1162 this.listItemElement.insertBefore(this._statusElement, this.titleElement);
1164 this.listItemElement.draggable = true;
1165 this.listItemElement.addEventListener("dragstart", this._ondragstart.bind(this), false);
1166 this.listItemElement.addEventListener("contextmenu", this._handleContextMenuEvent.bind(this), true);
1168 this._updateErrorsAndWarningsBubbles();
1171 _ondragstart: function(event)
1173 event.dataTransfer.setData("text/plain", this._resource.content);
1174 event.dataTransfer.effectAllowed = "copy";
1178 _handleContextMenuEvent: function(event)
1180 var contextMenu = new WebInspector.ContextMenu();
1181 contextMenu.appendItem(WebInspector.openLinkExternallyLabel(), WebInspector.openResource.bind(WebInspector, this._resource.url, false));
1182 this._appendOpenInNetworkPanelAction(contextMenu, event);
1183 this._appendSaveAsAction(contextMenu, event);
1184 contextMenu.show(event);
1187 _appendOpenInNetworkPanelAction: function(contextMenu, event)
1189 if (!this._resource.requestId)
1192 contextMenu.appendItem(WebInspector.openInNetworkPanelLabel(), WebInspector.openRequestInNetworkPanel.bind(WebInspector, this._resource));
1195 _appendSaveAsAction: function(contextMenu, event)
1197 if (!Preferences.saveAsAvailable)
1200 if (this._resource.type !== WebInspector.Resource.Type.Document &&
1201 this._resource.type !== WebInspector.Resource.Type.Stylesheet &&
1202 this._resource.type !== WebInspector.Resource.Type.Script)
1207 var fileName = this._resource.displayName;
1208 this._resource.requestContent(InspectorFrontendHost.saveAs.bind(InspectorFrontendHost, fileName));
1211 contextMenu.appendSeparator();
1212 contextMenu.appendItem(WebInspector.UIString(WebInspector.useLowerCaseMenuTitles() ? "Save as..." : "Save As..."), save.bind(this));
1215 _setBubbleText: function(x)
1217 if (!this._bubbleElement) {
1218 this._bubbleElement = document.createElement("div");
1219 this._bubbleElement.className = "bubble";
1220 this._statusElement.appendChild(this._bubbleElement);
1223 this._bubbleElement.textContent = x;
1226 _resetBubble: function()
1228 if (this._bubbleElement) {
1229 this._bubbleElement.textContent = "";
1230 this._bubbleElement.removeStyleClass("search-matches");
1231 this._bubbleElement.removeStyleClass("warning");
1232 this._bubbleElement.removeStyleClass("error");
1236 _resetSearchResults: function()
1238 this._resetBubble();
1239 this._searchMatchesCount = 0;
1242 get searchMatchesCount()
1244 return this._searchMatchesCount;
1247 searchMatchesFound: function(matchesCount)
1249 this._resetSearchResults();
1251 this._searchMatchesCount = matchesCount;
1252 this._setBubbleText(matchesCount);
1253 this._bubbleElement.addStyleClass("search-matches");
1255 // Expand, do not scroll into view.
1256 var currentAncestor = this.parent;
1257 while (currentAncestor && !currentAncestor.root) {
1258 if (!currentAncestor.expanded)
1259 currentAncestor.expand();
1260 currentAncestor = currentAncestor.parent;
1264 _updateErrorsAndWarningsBubbles: function()
1266 if (this._storagePanel.currentQuery)
1269 this._resetBubble();
1271 if (this._resource.warnings || this._resource.errors)
1272 this._setBubbleText(this._resource.warnings + this._resource.errors);
1274 if (this._resource.warnings)
1275 this._bubbleElement.addStyleClass("warning");
1277 if (this._resource.errors)
1278 this._bubbleElement.addStyleClass("error");
1281 _consoleMessagesCleared: function()
1283 // FIXME: move to the SourceFrame.
1284 if (this._sourceView)
1285 this._sourceView.clearMessages();
1287 this._updateErrorsAndWarningsBubbles();
1290 _consoleMessageAdded: function(event)
1292 var msg = event.data;
1293 if (this._sourceView)
1294 this._sourceView.addMessage(msg);
1295 this._updateErrorsAndWarningsBubbles();
1298 _populateRevisions: function()
1300 for (var i = 0; i < this._resource.history.length; ++i)
1301 this._appendRevision(this._resource.history[i]);
1304 _revisionAdded: function(event)
1306 this._appendRevision(event.data);
1309 _appendRevision: function(revision)
1311 this.insertChild(new WebInspector.ResourceRevisionTreeElement(this._storagePanel, revision), 0);
1312 var oldView = this._sourceView;
1314 // This is needed when resource content was changed from scripts panel.
1315 var newView = this._recreateSourceView();
1316 if (oldView === this._storagePanel.visibleView)
1317 this._storagePanel._showResourceView(this._resource);
1321 sourceView: function()
1323 if (!this._sourceView) {
1324 this._sourceView = this._createSourceView();
1325 if (this._resource.messages) {
1326 for (var i = 0; i < this._resource.messages.length; i++)
1327 this._sourceView.addMessage(this._resource.messages[i]);
1330 return this._sourceView;
1333 _createSourceView: function()
1335 return new WebInspector.EditableResourceSourceFrame(this._resource);
1338 _recreateSourceView: function()
1340 var oldView = this._sourceView;
1341 var newView = this._createSourceView();
1343 var oldViewParentNode = oldView.visible ? oldView.element.parentNode : null;
1344 newView.inheritScrollPositions(oldView);
1346 this._storagePanel.removeChildView(this._sourceView);
1347 this._storagePanel.addChildView(newView);
1348 this._sourceView = newView;
1350 if (oldViewParentNode)
1351 newView.show(oldViewParentNode);
1357 WebInspector.FrameResourceTreeElement.prototype.__proto__ = WebInspector.BaseStorageTreeElement.prototype;
1361 * @extends {WebInspector.BaseStorageTreeElement}
1363 WebInspector.DatabaseTreeElement = function(storagePanel, database)
1365 WebInspector.BaseStorageTreeElement.call(this, storagePanel, null, database.name, ["database-storage-tree-item"], true);
1366 this._database = database;
1369 WebInspector.DatabaseTreeElement.prototype = {
1372 return "database://" + encodeURI(this._database.name);
1375 onselect: function()
1377 WebInspector.BaseStorageTreeElement.prototype.onselect.call(this);
1378 this._storagePanel.showDatabase(this._database);
1381 oncollapse: function()
1383 // Request a refresh after every collapse so the next
1384 // expand will have an updated table list.
1385 this.shouldRefreshChildren = true;
1388 onpopulate: function()
1390 this.removeChildren();
1392 function tableNamesCallback(tableNames)
1394 var tableNamesLength = tableNames.length;
1395 for (var i = 0; i < tableNamesLength; ++i)
1396 this.appendChild(new WebInspector.DatabaseTableTreeElement(this._storagePanel, this._database, tableNames[i]));
1398 this._database.getTableNames(tableNamesCallback.bind(this));
1402 WebInspector.DatabaseTreeElement.prototype.__proto__ = WebInspector.BaseStorageTreeElement.prototype;
1406 * @extends {WebInspector.BaseStorageTreeElement}
1408 WebInspector.DatabaseTableTreeElement = function(storagePanel, database, tableName)
1410 WebInspector.BaseStorageTreeElement.call(this, storagePanel, null, tableName, ["database-storage-tree-item"]);
1411 this._database = database;
1412 this._tableName = tableName;
1415 WebInspector.DatabaseTableTreeElement.prototype = {
1418 return "database://" + encodeURI(this._database.name) + "/" + encodeURI(this._tableName);
1421 onselect: function()
1423 WebInspector.BaseStorageTreeElement.prototype.onselect.call(this);
1424 this._storagePanel.showDatabase(this._database, this._tableName);
1427 WebInspector.DatabaseTableTreeElement.prototype.__proto__ = WebInspector.BaseStorageTreeElement.prototype;
1431 * @extends {WebInspector.BaseStorageTreeElement}
1433 WebInspector.DOMStorageTreeElement = function(storagePanel, domStorage, className)
1435 WebInspector.BaseStorageTreeElement.call(this, storagePanel, null, domStorage.domain ? domStorage.domain : WebInspector.UIString("Local Files"), ["domstorage-storage-tree-item", className]);
1436 this._domStorage = domStorage;
1439 WebInspector.DOMStorageTreeElement.prototype = {
1442 return "storage://" + this._domStorage.domain + "/" + (this._domStorage.isLocalStorage ? "local" : "session");
1445 onselect: function()
1447 WebInspector.BaseStorageTreeElement.prototype.onselect.call(this);
1448 this._storagePanel.showDOMStorage(this._domStorage);
1451 WebInspector.DOMStorageTreeElement.prototype.__proto__ = WebInspector.BaseStorageTreeElement.prototype;
1455 * @extends {WebInspector.BaseStorageTreeElement}
1457 WebInspector.CookieTreeElement = function(storagePanel, cookieDomain)
1459 WebInspector.BaseStorageTreeElement.call(this, storagePanel, null, cookieDomain ? cookieDomain : WebInspector.UIString("Local Files"), ["cookie-storage-tree-item"]);
1460 this._cookieDomain = cookieDomain;
1463 WebInspector.CookieTreeElement.prototype = {
1466 return "cookies://" + this._cookieDomain;
1469 onselect: function()
1471 WebInspector.BaseStorageTreeElement.prototype.onselect.call(this);
1472 this._storagePanel.showCookies(this, this._cookieDomain);
1475 WebInspector.CookieTreeElement.prototype.__proto__ = WebInspector.BaseStorageTreeElement.prototype;
1479 * @extends {WebInspector.BaseStorageTreeElement}
1481 WebInspector.ApplicationCacheTreeElement = function(storagePanel, appcacheDomain)
1483 WebInspector.BaseStorageTreeElement.call(this, storagePanel, null, appcacheDomain ? appcacheDomain : WebInspector.UIString("Local Files"), ["application-cache-storage-tree-item"]);
1484 this._appcacheDomain = appcacheDomain;
1487 WebInspector.ApplicationCacheTreeElement.prototype = {
1490 return "appcache://" + this._appcacheDomain;
1493 onselect: function()
1495 WebInspector.BaseStorageTreeElement.prototype.onselect.call(this);
1496 this._storagePanel.showApplicationCache(this, this._appcacheDomain);
1499 WebInspector.ApplicationCacheTreeElement.prototype.__proto__ = WebInspector.BaseStorageTreeElement.prototype;
1503 * @extends {WebInspector.BaseStorageTreeElement}
1505 WebInspector.ResourceRevisionTreeElement = function(storagePanel, revision)
1507 var title = revision.timestamp ? revision.timestamp.toLocaleTimeString() : WebInspector.UIString("(original)");
1508 WebInspector.BaseStorageTreeElement.call(this, storagePanel, revision, title, ["resource-sidebar-tree-item", "resources-category-" + revision.resource.category.name]);
1509 if (revision.timestamp)
1510 this.tooltip = revision.timestamp.toLocaleString();
1511 this._revision = revision;
1514 WebInspector.ResourceRevisionTreeElement.prototype = {
1517 return this._revision.resource.url;
1520 onattach: function()
1522 WebInspector.BaseStorageTreeElement.prototype.onattach.call(this);
1523 this.listItemElement.draggable = true;
1524 this.listItemElement.addEventListener("dragstart", this._ondragstart.bind(this), false);
1525 this.listItemElement.addEventListener("contextmenu", this._handleContextMenuEvent.bind(this), true);
1528 onselect: function()
1530 WebInspector.BaseStorageTreeElement.prototype.onselect.call(this);
1531 this._storagePanel._showRevisionView(this._revision);
1534 _ondragstart: function(event)
1536 if (this._revision.content) {
1537 event.dataTransfer.setData("text/plain", this._revision.content);
1538 event.dataTransfer.effectAllowed = "copy";
1543 _handleContextMenuEvent: function(event)
1545 var contextMenu = new WebInspector.ContextMenu();
1546 contextMenu.appendItem(WebInspector.UIString("Revert to this revision"), this._revision.revertToThis.bind(this._revision));
1548 if (Preferences.saveAsAvailable) {
1551 var fileName = this._revision.resource.displayName;
1552 this._revision.requestContent(InspectorFrontendHost.saveAs.bind(InspectorFrontendHost, fileName));
1554 contextMenu.appendSeparator();
1555 contextMenu.appendItem(WebInspector.UIString(WebInspector.useLowerCaseMenuTitles() ? "Save as..." : "Save As..."), save.bind(this));
1558 contextMenu.show(event);
1561 sourceView: function()
1563 if (!this._sourceView)
1564 this._sourceView = new WebInspector.ResourceRevisionSourceFrame(this._revision);
1565 return this._sourceView;
1569 WebInspector.ResourceRevisionTreeElement.prototype.__proto__ = WebInspector.BaseStorageTreeElement.prototype;
1573 * @extends {WebInspector.View}
1575 WebInspector.StorageCategoryView = function()
1577 WebInspector.View.call(this);
1579 this.element.addStyleClass("storage-view");
1580 this._emptyView = new WebInspector.EmptyView("");
1581 this._emptyView.show(this.element);
1584 WebInspector.StorageCategoryView.prototype = {
1585 setText: function(text)
1587 this._emptyView.text = text;
1591 WebInspector.StorageCategoryView.prototype.__proto__ = WebInspector.View.prototype;
1596 WebInspector.ResourcesSearchController = function(rootElement)
1598 this._root = rootElement;
1599 this._traverser = new WebInspector.SearchResultsTreeElementsTraverser(rootElement);
1600 this._lastTreeElement = null;
1601 this._lastIndex = -1;
1604 WebInspector.ResourcesSearchController.prototype = {
1605 nextSearchResult: function(currentTreeElement)
1607 if (!currentTreeElement)
1608 return this._searchResult(this._traverser.first(), 0);
1610 if (!currentTreeElement.searchMatchesCount)
1611 return this._searchResult(this._traverser.next(currentTreeElement), 0);
1613 if (this._lastTreeElement !== currentTreeElement || this._lastIndex === -1)
1614 return this._searchResult(currentTreeElement, 0);
1616 if (this._lastIndex == currentTreeElement.searchMatchesCount - 1)
1617 return this._searchResult(this._traverser.next(currentTreeElement), 0);
1619 return this._searchResult(currentTreeElement, this._lastIndex + 1);
1622 previousSearchResult: function(currentTreeElement)
1624 if (!currentTreeElement) {
1625 var treeElement = this._traverser.last();
1626 return this._searchResult(treeElement, treeElement.searchMatchesCount - 1);
1629 if (currentTreeElement.searchMatchesCount && this._lastTreeElement === currentTreeElement && this._lastIndex > 0)
1630 return this._searchResult(currentTreeElement, this._lastIndex - 1);
1632 var treeElement = this._traverser.previous(currentTreeElement)
1633 return this._searchResult(treeElement, treeElement.searchMatchesCount - 1);
1636 _searchResult: function(treeElement, index)
1638 this._lastTreeElement = treeElement;
1639 this._lastIndex = index;
1640 return {treeElement: treeElement, index: index};
1647 WebInspector.SearchResultsTreeElementsTraverser = function(rootElement)
1649 this._root = rootElement;
1652 WebInspector.SearchResultsTreeElementsTraverser.prototype = {
1655 return this.next(this._root);
1660 return this.previous(this._root);
1663 next: function(startTreeElement)
1665 var treeElement = startTreeElement;
1667 treeElement = this._traverseNext(treeElement) || this._root;
1668 } while (treeElement != startTreeElement && !this._elementHasSearchResults(treeElement));
1672 previous: function(startTreeElement)
1674 var treeElement = startTreeElement;
1676 treeElement = this._traversePrevious(treeElement) || this._lastTreeElement();
1677 } while (treeElement != startTreeElement && !this._elementHasSearchResults(treeElement));
1681 _traverseNext: function(treeElement)
1683 return treeElement.traverseNextTreeElement(false, this._root, true);
1686 _elementHasSearchResults: function(treeElement)
1688 return treeElement instanceof WebInspector.FrameResourceTreeElement && treeElement.searchMatchesCount;
1691 _traversePrevious: function(treeElement)
1693 return treeElement.traversePreviousTreeElement(false, this._root, true);
1696 _lastTreeElement: function()
1698 var treeElement = this._root;
1699 var nextTreeElement;
1700 while (nextTreeElement = this._traverseNext(treeElement))
1701 treeElement = nextTreeElement;