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.
30 WebInspector.ResourcesPanel = function(database)
32 WebInspector.Panel.call(this, "resources");
34 WebInspector.settings.resourcesLastSelectedItem = WebInspector.settings.createSetting("resourcesLastSelectedItem", {});
37 this.sidebarElement.addStyleClass("outline-disclosure");
38 this.sidebarElement.addStyleClass("filter-all");
39 this.sidebarElement.addStyleClass("children");
40 this.sidebarElement.addStyleClass("small");
41 this.sidebarTreeElement.removeStyleClass("sidebar-tree");
43 this.resourcesListTreeElement = new WebInspector.StorageCategoryTreeElement(this, WebInspector.UIString("Frames"), "Frames", ["frame-storage-tree-item"]);
44 this.sidebarTree.appendChild(this.resourcesListTreeElement);
46 this.databasesListTreeElement = new WebInspector.StorageCategoryTreeElement(this, WebInspector.UIString("Databases"), "Databases", ["database-storage-tree-item"]);
47 this.sidebarTree.appendChild(this.databasesListTreeElement);
49 this.localStorageListTreeElement = new WebInspector.StorageCategoryTreeElement(this, WebInspector.UIString("Local Storage"), "LocalStorage", ["domstorage-storage-tree-item", "local-storage"]);
50 this.sidebarTree.appendChild(this.localStorageListTreeElement);
52 this.sessionStorageListTreeElement = new WebInspector.StorageCategoryTreeElement(this, WebInspector.UIString("Session Storage"), "SessionStorage", ["domstorage-storage-tree-item", "session-storage"]);
53 this.sidebarTree.appendChild(this.sessionStorageListTreeElement);
55 this.cookieListTreeElement = new WebInspector.StorageCategoryTreeElement(this, WebInspector.UIString("Cookies"), "Cookies", ["cookie-storage-tree-item"]);
56 this.sidebarTree.appendChild(this.cookieListTreeElement);
58 this.applicationCacheListTreeElement = new WebInspector.StorageCategoryTreeElement(this, WebInspector.UIString("Application Cache"), "ApplicationCache", ["application-cache-storage-tree-item"]);
59 this.sidebarTree.appendChild(this.applicationCacheListTreeElement);
61 this.storageViews = document.createElement("div");
62 this.storageViews.id = "storage-views";
63 this.storageViews.className = "diff-container";
64 this.element.appendChild(this.storageViews);
66 this.storageViewStatusBarItemsContainer = document.createElement("div");
67 this.storageViewStatusBarItemsContainer.className = "status-bar-items";
70 this._domStorage = [];
71 this._cookieViews = {};
75 this.sidebarElement.addEventListener("mousemove", this._onmousemove.bind(this), false);
76 this.sidebarElement.addEventListener("mouseout", this._onmouseout.bind(this), false);
78 this.registerShortcuts();
80 WebInspector.resourceTreeModel.addEventListener(WebInspector.ResourceTreeModel.EventTypes.OnLoad, this._onLoadEventFired, this);
83 WebInspector.ResourcesPanel.prototype = {
84 get toolbarItemLabel()
86 return WebInspector.UIString("Resources");
91 return [this.storageViewStatusBarItemsContainer];
94 elementsToRestoreScrollPositionsFor: function()
96 return [this.sidebarElement];
101 WebInspector.Panel.prototype.show.call(this);
103 this._populateResourceTree();
106 _onLoadEventFired: function()
108 this._initDefaultSelection();
111 _initDefaultSelection: function()
113 if (!this._treeElementForFrameId)
116 var itemURL = WebInspector.settings.resourcesLastSelectedItem.get();
118 for (var treeElement = this.sidebarTree.children[0]; treeElement; treeElement = treeElement.traverseNextTreeElement(false, this.sidebarTree, true)) {
119 if (treeElement.itemURL === itemURL) {
120 treeElement.revealAndSelect(true);
126 if (WebInspector.mainResource && this.resourcesListTreeElement && this.resourcesListTreeElement.expanded)
127 this.showResource(WebInspector.mainResource);
134 for (var i = 0; i < this._databases.length; ++i) {
135 var database = this._databases[i];
136 delete database._tableViews;
137 delete database._queryView;
139 this._databases = [];
141 var domStorageLength = this._domStorage.length;
142 for (var i = 0; i < this._domStorage.length; ++i) {
143 var domStorage = this._domStorage[i];
144 delete domStorage._domStorageView;
146 this._domStorage = [];
148 this._cookieViews = {};
150 this._applicationCacheView = null;
151 delete this._cachedApplicationCacheViewStatus;
153 this.databasesListTreeElement.removeChildren();
154 this.localStorageListTreeElement.removeChildren();
155 this.sessionStorageListTreeElement.removeChildren();
156 this.cookieListTreeElement.removeChildren();
157 this.applicationCacheListTreeElement.removeChildren();
158 this.storageViews.removeChildren();
160 this.storageViewStatusBarItemsContainer.removeChildren();
162 if (this.sidebarTree.selectedTreeElement)
163 this.sidebarTree.selectedTreeElement.deselect();
166 _populateResourceTree: function()
168 if (this._treeElementForFrameId)
171 this._treeElementForFrameId = {};
172 WebInspector.resourceTreeModel.addEventListener(WebInspector.ResourceTreeModel.EventTypes.FrameAdded, this._frameAdded, this);
173 WebInspector.resourceTreeModel.addEventListener(WebInspector.ResourceTreeModel.EventTypes.FrameNavigated, this._frameNavigated, this);
174 WebInspector.resourceTreeModel.addEventListener(WebInspector.ResourceTreeModel.EventTypes.FrameDetached, this._frameDetached, this);
175 WebInspector.resourceTreeModel.addEventListener(WebInspector.ResourceTreeModel.EventTypes.ResourceAdded, this._resourceAdded, this);
176 WebInspector.resourceTreeModel.addEventListener(WebInspector.ResourceTreeModel.EventTypes.CachedResourcesLoaded, this._cachedResourcesLoaded, this);
177 WebInspector.resourceTreeModel.addEventListener(WebInspector.ResourceTreeModel.EventTypes.WillLoadCachedResources, this._resetResourcesTree, this);
179 function populateFrame(frameId)
181 var subframes = WebInspector.resourceTreeModel.subframes(frameId);
182 for (var i = 0; i < subframes.length; ++i) {
183 this._frameAdded({data:subframes[i]});
184 populateFrame.call(this, subframes[i].id);
187 var resources = WebInspector.resourceTreeModel.resources(frameId);
188 for (var i = 0; i < resources.length; ++i)
189 this._resourceAdded({data:resources[i]});
191 populateFrame.call(this, "");
193 this._initDefaultSelection();
196 _frameAdded: function(event)
198 var frame = event.data;
199 var parentFrameId = frame.parentId;
201 var parentTreeElement = parentFrameId ? this._treeElementForFrameId[parentFrameId] : this.resourcesListTreeElement;
202 if (!parentTreeElement) {
203 console.warn("No frame with id:" + parentFrameId + " to route " + frame.name + "/" + frame.url + " to.")
207 var frameTreeElement = new WebInspector.FrameTreeElement(this, frame);
208 this._treeElementForFrameId[frame.id] = frameTreeElement;
209 parentTreeElement.appendChild(frameTreeElement);
212 _frameDetached: function(event)
214 var frameId = event.data;
215 var frameTreeElement = this._treeElementForFrameId[frameId];
216 if (!frameTreeElement)
219 delete this._treeElementForFrameId[frameId];
220 if (frameTreeElement.parent)
221 frameTreeElement.parent.removeChild(frameTreeElement);
224 _resourceAdded: function(event)
226 var resource = event.data;
227 var frameId = resource.frameId;
229 if (resource.statusCode >= 301 && resource.statusCode <= 303)
232 var frameTreeElement = this._treeElementForFrameId[frameId];
233 if (!frameTreeElement) {
234 // This is a frame's main resource, it will be retained
235 // and re-added by the resource manager;
239 frameTreeElement.appendResource(resource);
242 _frameNavigated: function(event)
244 var frameId = event.data.frame.id;
245 var frameTreeElement = this._treeElementForFrameId[frameId];
246 if (frameTreeElement)
247 frameTreeElement.frameNavigated(event.data.frame);
250 _resetResourcesTree: function()
252 this.resourcesListTreeElement.removeChildren();
253 this._treeElementForFrameId = {};
257 _cachedResourcesLoaded: function()
259 this._initDefaultSelection();
262 addDatabase: function(database)
264 this._databases.push(database);
266 var databaseTreeElement = new WebInspector.DatabaseTreeElement(this, database);
267 database._databasesTreeElement = databaseTreeElement;
268 this.databasesListTreeElement.appendChild(databaseTreeElement);
271 addDocumentURL: function(url)
273 var parsedURL = url.asParsedURL();
277 var domain = parsedURL.host;
278 if (!this._domains[domain]) {
279 this._domains[domain] = true;
281 var cookieDomainTreeElement = new WebInspector.CookieTreeElement(this, domain);
282 this.cookieListTreeElement.appendChild(cookieDomainTreeElement);
284 var applicationCacheTreeElement = new WebInspector.ApplicationCacheTreeElement(this, domain);
285 this.applicationCacheListTreeElement.appendChild(applicationCacheTreeElement);
289 addDOMStorage: function(domStorage)
291 this._domStorage.push(domStorage);
292 var domStorageTreeElement = new WebInspector.DOMStorageTreeElement(this, domStorage, (domStorage.isLocalStorage ? "local-storage" : "session-storage"));
293 domStorage._domStorageTreeElement = domStorageTreeElement;
294 if (domStorage.isLocalStorage)
295 this.localStorageListTreeElement.appendChild(domStorageTreeElement);
297 this.sessionStorageListTreeElement.appendChild(domStorageTreeElement);
300 selectDatabase: function(databaseId)
303 for (var i = 0, len = this._databases.length; i < len; ++i) {
304 database = this._databases[i];
305 if (database.id === databaseId) {
306 this.showDatabase(database);
307 database._databasesTreeElement.select();
313 selectDOMStorage: function(storageId)
315 var domStorage = this._domStorageForId(storageId);
317 this.showDOMStorage(domStorage);
318 domStorage._domStorageTreeElement.select();
322 canShowAnchorLocation: function(anchor)
324 return !!WebInspector.resourceForURL(anchor.href);
327 showAnchorLocation: function(anchor)
329 var resource = WebInspector.resourceForURL(anchor.href);
330 if (resource.type === WebInspector.Resource.Type.XHR) {
331 // Show XHRs in the network panel only.
332 if (WebInspector.panels.network && WebInspector.panels.network.canShowAnchorLocation(anchor)) {
333 WebInspector.currentPanel = WebInspector.panels.network;
334 WebInspector.panels.network.showAnchorLocation(anchor);
338 var lineNumber = anchor.hasAttribute("line_number") ? parseInt(anchor.getAttribute("line_number")) : undefined;
339 this.showResource(resource, lineNumber);
342 showResource: function(resource, line)
344 var resourceTreeElement = this._findTreeElementForResource(resource);
345 if (resourceTreeElement)
346 resourceTreeElement.revealAndSelect();
348 if (line !== undefined) {
349 var view = this._resourceViewForResource(resource);
350 if (view.highlightLine)
351 view.highlightLine(line);
356 _showResourceView: function(resource)
358 var view = this._resourceViewForResource(resource);
360 this.visibleView.hide();
363 if (view.searchCanceled)
364 view.searchCanceled();
365 this._fetchAndApplyDiffMarkup(view, resource);
366 this._innerShowView(view);
369 _resourceViewForResource: function(resource)
371 if (WebInspector.ResourceView.hasTextContent(resource)) {
372 var treeElement = this._findTreeElementForResource(resource);
375 return treeElement.sourceView();
377 return WebInspector.ResourceView.nonSourceViewForResource(resource);
380 _showRevisionView: function(revision)
382 var view = this._sourceViewForRevision(revision);
383 this._fetchAndApplyDiffMarkup(view, revision.resource, revision);
384 this._innerShowView(view);
387 _sourceViewForRevision: function(revision)
389 var treeElement = this._findTreeElementForRevision(revision);
390 return treeElement.sourceView();
393 _fetchAndApplyDiffMarkup: function(view, resource, revision)
395 var baseRevision = resource.history[0];
398 if (!(view instanceof WebInspector.SourceFrame))
401 baseRevision.requestContent(step1.bind(this));
403 function step1(baseContent)
405 (revision ? revision : resource).requestContent(step2.bind(this, baseContent));
408 function step2(baseContent, revisionContent)
410 this._applyDiffMarkup(view, baseContent, revisionContent);
414 _applyDiffMarkup: function(view, baseContent, newContent) {
415 var oldLines = baseContent.split(/\r?\n/);
416 var newLines = newContent.split(/\r?\n/);
418 var diff = Array.diff(oldLines, newLines);
422 diffData.removed = [];
423 diffData.changed = [];
426 var right = diff.right;
427 for (var i = 0; i < right.length; ++i) {
428 if (typeof right[i] === "string") {
429 if (right.length > i + 1 && right[i + 1].row === i + 1 - offset)
430 diffData.changed.push(i);
432 diffData.added.push(i);
436 offset = i - right[i].row;
438 view.markDiff(diffData);
441 showDatabase: function(database, tableName)
448 if (!("_tableViews" in database))
449 database._tableViews = {};
450 view = database._tableViews[tableName];
452 view = new WebInspector.DatabaseTableView(database, tableName);
453 database._tableViews[tableName] = view;
456 view = database._queryView;
458 view = new WebInspector.DatabaseQueryView(database);
459 database._queryView = view;
463 this._innerShowView(view);
466 showDOMStorage: function(domStorage)
472 view = domStorage._domStorageView;
474 view = new WebInspector.DOMStorageItemsView(domStorage);
475 domStorage._domStorageView = view;
478 this._innerShowView(view);
481 showCookies: function(treeElement, cookieDomain)
483 var view = this._cookieViews[cookieDomain];
485 view = new WebInspector.CookieItemsView(treeElement, cookieDomain);
486 this._cookieViews[cookieDomain] = view;
489 this._innerShowView(view);
492 showApplicationCache: function(treeElement, appcacheDomain)
494 var view = this._applicationCacheView;
496 view = new WebInspector.ApplicationCacheItemsView(treeElement, appcacheDomain);
497 this._applicationCacheView = view;
500 this._innerShowView(view);
502 if ("_cachedApplicationCacheViewStatus" in this)
503 this._applicationCacheView.updateStatus(this._cachedApplicationCacheViewStatus);
506 showCategoryView: function(categoryName)
508 if (!this._categoryView)
509 this._categoryView = new WebInspector.StorageCategoryView();
510 this._categoryView.setText(categoryName);
511 this._innerShowView(this._categoryView);
514 _innerShowView: function(view)
516 if (this.visibleView)
517 this.visibleView.hide();
519 this.addChildView(view);
520 view.show(this.storageViews);
521 this.visibleView = view;
523 this.storageViewStatusBarItemsContainer.removeChildren();
524 var statusBarItems = view.statusBarItems || [];
525 for (var i = 0; i < statusBarItems.length; ++i)
526 this.storageViewStatusBarItemsContainer.appendChild(statusBarItems[i]);
529 closeVisibleView: function()
531 if (!this.visibleView)
533 this.visibleView.hide();
534 delete this.visibleView;
537 updateDatabaseTables: function(database)
539 if (!database || !database._databasesTreeElement)
542 database._databasesTreeElement.shouldRefreshChildren = true;
544 if (!("_tableViews" in database))
547 var tableNamesHash = {};
549 function tableNamesCallback(tableNames)
551 var tableNamesLength = tableNames.length;
552 for (var i = 0; i < tableNamesLength; ++i)
553 tableNamesHash[tableNames[i]] = true;
555 for (var tableName in database._tableViews) {
556 if (!(tableName in tableNamesHash)) {
557 if (self.visibleView === database._tableViews[tableName])
558 self.closeVisibleView();
559 delete database._tableViews[tableName];
563 database.getTableNames(tableNamesCallback);
566 dataGridForResult: function(columnNames, values)
568 var numColumns = columnNames.length;
574 for (var i = 0; i < columnNames.length; ++i) {
576 column.width = columnNames[i].length;
577 column.title = columnNames[i];
578 column.sortable = true;
580 columns[columnNames[i]] = column;
584 for (var i = 0; i < values.length / numColumns; ++i) {
586 for (var j = 0; j < columnNames.length; ++j)
587 data[columnNames[j]] = values[numColumns * i + j];
589 var node = new WebInspector.DataGridNode(data, false);
590 node.selectable = false;
594 var dataGrid = new WebInspector.DataGrid(columns);
595 var length = nodes.length;
596 for (var i = 0; i < length; ++i)
597 dataGrid.appendChild(nodes[i]);
599 dataGrid.addEventListener("sorting changed", this._sortDataGrid.bind(this, dataGrid), this);
603 _sortDataGrid: function(dataGrid)
605 var nodes = dataGrid.children.slice();
606 var sortColumnIdentifier = dataGrid.sortColumnIdentifier;
607 var sortDirection = dataGrid.sortOrder === "ascending" ? 1 : -1;
608 var columnIsNumeric = true;
610 for (var i = 0; i < nodes.length; i++) {
611 if (isNaN(Number(nodes[i].data[sortColumnIdentifier])))
612 columnIsNumeric = false;
615 function comparator(dataGridNode1, dataGridNode2)
617 var item1 = dataGridNode1.data[sortColumnIdentifier];
618 var item2 = dataGridNode2.data[sortColumnIdentifier];
621 if (columnIsNumeric) {
622 // Sort numbers based on comparing their values rather than a lexicographical comparison.
623 var number1 = parseFloat(item1);
624 var number2 = parseFloat(item2);
625 comparison = number1 < number2 ? -1 : (number1 > number2 ? 1 : 0);
627 comparison = item1 < item2 ? -1 : (item1 > item2 ? 1 : 0);
629 return sortDirection * comparison;
632 nodes.sort(comparator);
633 dataGrid.removeChildren();
634 for (var i = 0; i < nodes.length; i++)
635 dataGrid.appendChild(nodes[i]);
638 updateDOMStorage: function(storageId)
640 var domStorage = this._domStorageForId(storageId);
644 var view = domStorage._domStorageView;
645 if (this.visibleView && view === this.visibleView)
646 domStorage._domStorageView.update();
649 updateApplicationCacheStatus: function(status)
651 this._cachedApplicationCacheViewStatus = status;
652 if (this._applicationCacheView && this._applicationCacheView === this.visibleView)
653 this._applicationCacheView.updateStatus(status);
656 updateNetworkState: function(isNowOnline)
658 if (this._applicationCacheView && this._applicationCacheView === this.visibleView)
659 this._applicationCacheView.updateNetworkState(isNowOnline);
662 updateManifest: function(manifest)
664 if (this._applicationCacheView && this._applicationCacheView === this.visibleView)
665 this._applicationCacheView.updateManifest(manifest);
668 _domStorageForId: function(storageId)
670 if (!this._domStorage)
672 var domStorageLength = this._domStorage.length;
673 for (var i = 0; i < domStorageLength; ++i) {
674 var domStorage = this._domStorage[i];
675 if (domStorage.id == storageId)
681 updateMainViewWidth: function(width)
683 this.storageViews.style.left = width + "px";
684 this.storageViewStatusBarItemsContainer.style.left = width + "px";
687 performSearch: function(query)
689 this._resetSearchResults();
690 var regex = WebInspector.SourceFrame.createSearchRegex(query);
691 var totalMatchesCount = 0;
693 function searchInEditedResource(treeElement)
695 var resource = treeElement.representedObject;
696 if (resource.history.length == 0)
698 var matchesCount = countRegexMatches(regex, resource.content)
699 treeElement.searchMatchesFound(matchesCount);
700 totalMatchesCount += matchesCount;
703 function callback(error, result)
706 for (var i = 0; i < result.length; i++) {
707 var searchResult = result[i];
708 var frameTreeElement = this._treeElementForFrameId[searchResult.frameId];
709 if (!frameTreeElement)
711 var resource = frameTreeElement.resourceByURL(searchResult.url);
713 // FIXME: When the same script is used in several frames and this script contains at least
714 // one search result then some search results can not be matched with a resource on panel.
715 // https://bugs.webkit.org/show_bug.cgi?id=66005
719 if (resource.history.length > 0)
720 continue; // Skip edited resources.
721 this._findTreeElementForResource(resource).searchMatchesFound(searchResult.matchesCount);
722 totalMatchesCount += searchResult.matchesCount;
726 WebInspector.searchController.updateSearchMatchesCount(totalMatchesCount, this);
727 this._searchController = new WebInspector.ResourcesSearchController(this.resourcesListTreeElement);
729 if (this.sidebarTree.selectedTreeElement && this.sidebarTree.selectedTreeElement.searchMatchesCount)
730 this.jumpToNextSearchResult();
733 this._forAllResourceTreeElements(searchInEditedResource.bind(this));
734 PageAgent.searchInResources(regex.source, !regex.ignoreCase, true, callback.bind(this));
737 _ensureViewSearchPerformed: function(callback)
739 function viewSearchPerformedCallback(searchId)
741 if (searchId !== this._lastViewSearchId)
742 return; // Search is obsolete.
743 this._viewSearchInProgress = false;
747 if (!this._viewSearchInProgress) {
748 if (!this.visibleView.hasSearchResults()) {
749 // We give id to each search, so that we can skip callbacks for obsolete searches.
750 this._lastViewSearchId = this._lastViewSearchId ? this._lastViewSearchId + 1 : 0;
751 this._viewSearchInProgress = true;
752 this.visibleView.performSearch(this.currentQuery, viewSearchPerformedCallback.bind(this, this._lastViewSearchId));
758 _showSearchResult: function(searchResult)
760 this._lastSearchResultIndex = searchResult.index;
761 this._lastSearchResultTreeElement = searchResult.treeElement;
763 // At first show view for treeElement.
764 if (searchResult.treeElement !== this.sidebarTree.selectedTreeElement) {
765 this.showResource(searchResult.treeElement.representedObject);
766 WebInspector.searchController.focusSearchField();
769 function callback(searchId)
771 if (this.sidebarTree.selectedTreeElement !== this._lastSearchResultTreeElement)
772 return; // User has selected another view while we were searching.
773 if (this._lastSearchResultIndex != -1)
774 this.visibleView.jumpToSearchResult(this._lastSearchResultIndex);
777 // Then run SourceFrame search if needed and jump to search result index when done.
778 this._ensureViewSearchPerformed(callback.bind(this));
781 _resetSearchResults: function()
783 function callback(resourceTreeElement)
785 resourceTreeElement._resetSearchResults();
788 this._forAllResourceTreeElements(callback);
789 if (this.visibleView && this.visibleView.searchCanceled)
790 this.visibleView.searchCanceled();
792 this._lastSearchResultTreeElement = null;
793 this._lastSearchResultIndex = -1;
794 this._viewSearchInProgress = false;
797 searchCanceled: function()
799 function callback(resourceTreeElement)
801 resourceTreeElement._updateErrorsAndWarningsBubbles();
804 WebInspector.searchController.updateSearchMatchesCount(0, this);
805 this._resetSearchResults();
806 this._forAllResourceTreeElements(callback);
809 jumpToNextSearchResult: function()
811 if (!this.currentSearchMatches)
813 var currentTreeElement = this.sidebarTree.selectedTreeElement;
814 var nextSearchResult = this._searchController.nextSearchResult(currentTreeElement);
815 this._showSearchResult(nextSearchResult);
818 jumpToPreviousSearchResult: function()
820 if (!this.currentSearchMatches)
822 var currentTreeElement = this.sidebarTree.selectedTreeElement;
823 var previousSearchResult = this._searchController.previousSearchResult(currentTreeElement);
824 this._showSearchResult(previousSearchResult);
827 _forAllResourceTreeElements: function(callback)
830 for (var treeElement = this.resourcesListTreeElement; !stop && treeElement; treeElement = treeElement.traverseNextTreeElement(false, this.resourcesListTreeElement, true)) {
831 if (treeElement instanceof WebInspector.FrameResourceTreeElement)
832 stop = callback(treeElement);
836 _findTreeElementForResource: function(resource)
838 function isAncestor(ancestor, object)
840 // Redirects, XHRs do not belong to the tree, it is fine to silently return false here.
844 function getParent(object)
846 // Redirects, XHRs do not belong to the tree, it is fine to silently return false here.
850 return this.sidebarTree.findTreeElement(resource, isAncestor, getParent);
853 _findTreeElementForRevision: function(revision)
855 function isAncestor(ancestor, object)
860 function getParent(object)
865 return this.sidebarTree.findTreeElement(revision, isAncestor, getParent);
868 showView: function(view)
871 this.showResource(view.resource);
874 _onmousemove: function(event)
876 var nodeUnderMouse = document.elementFromPoint(event.pageX, event.pageY);
880 var listNode = nodeUnderMouse.enclosingNodeOrSelfWithNodeName("li");
884 var element = listNode.treeElement;
885 if (this._previousHoveredElement === element)
888 if (this._previousHoveredElement) {
889 this._previousHoveredElement.hovered = false;
890 delete this._previousHoveredElement;
893 if (element instanceof WebInspector.FrameTreeElement) {
894 this._previousHoveredElement = element;
895 element.hovered = true;
899 _onmouseout: function(event)
901 if (this._previousHoveredElement) {
902 this._previousHoveredElement.hovered = false;
903 delete this._previousHoveredElement;
908 WebInspector.ResourcesPanel.prototype.__proto__ = WebInspector.Panel.prototype;
910 WebInspector.BaseStorageTreeElement = function(storagePanel, representedObject, title, iconClasses, hasChildren, noIcon)
912 TreeElement.call(this, "", representedObject, hasChildren);
913 this._storagePanel = storagePanel;
914 this._titleText = title;
915 this._iconClasses = iconClasses;
916 this._noIcon = noIcon;
919 WebInspector.BaseStorageTreeElement.prototype = {
922 this.listItemElement.removeChildren();
923 if (this._iconClasses) {
924 for (var i = 0; i < this._iconClasses.length; ++i)
925 this.listItemElement.addStyleClass(this._iconClasses[i]);
928 var selectionElement = document.createElement("div");
929 selectionElement.className = "selection";
930 this.listItemElement.appendChild(selectionElement);
933 this.imageElement = document.createElement("img");
934 this.imageElement.className = "icon";
935 this.listItemElement.appendChild(this.imageElement);
938 this.titleElement = document.createElement("div");
939 this.titleElement.className = "base-storage-tree-element-title";
940 this.titleElement.textContent = this._titleText;
941 this.listItemElement.appendChild(this.titleElement);
946 var itemURL = this.itemURL;
948 WebInspector.settings.resourcesLastSelectedItem.set(itemURL);
953 if (this.listItemElement)
954 this.listItemElement.scrollIntoViewIfNeeded(false);
959 return this._titleText;
962 set titleText(titleText)
964 this._titleText = titleText;
965 if (this.titleElement)
966 this.titleElement.textContent = this._titleText;
969 isEventWithinDisclosureTriangle: function()
971 // Override it since we use margin-left in place of treeoutline's text-indent.
972 // Hence we need to take padding into consideration. This all is needed for leading
973 // icons in the tree.
974 const paddingLeft = 14;
975 var left = this.listItemElement.totalOffsetLeft() + paddingLeft;
976 return event.pageX >= left && event.pageX <= left + this.arrowToggleWidth && this.hasChildren;
980 WebInspector.BaseStorageTreeElement.prototype.__proto__ = TreeElement.prototype;
982 WebInspector.StorageCategoryTreeElement = function(storagePanel, categoryName, settingsKey, iconClasses, noIcon)
984 WebInspector.BaseStorageTreeElement.call(this, storagePanel, null, categoryName, iconClasses, true, noIcon);
985 this._expandedSettingKey = "resources" + settingsKey + "Expanded";
986 WebInspector.settings[this._expandedSettingKey] = WebInspector.settings.createSetting(this._expandedSettingKey, settingsKey === "Frames");
987 this._categoryName = categoryName;
990 WebInspector.StorageCategoryTreeElement.prototype = {
993 return "category://" + this._categoryName;
998 WebInspector.BaseStorageTreeElement.prototype.onselect.call(this);
999 this._storagePanel.showCategoryView(this._categoryName);
1002 onattach: function()
1004 WebInspector.BaseStorageTreeElement.prototype.onattach.call(this);
1005 if (WebInspector.settings[this._expandedSettingKey].get())
1009 onexpand: function()
1011 WebInspector.settings[this._expandedSettingKey].set(true);
1014 oncollapse: function()
1016 WebInspector.settings[this._expandedSettingKey].set(false);
1020 WebInspector.StorageCategoryTreeElement.prototype.__proto__ = WebInspector.BaseStorageTreeElement.prototype;
1022 WebInspector.FrameTreeElement = function(storagePanel, frame)
1024 WebInspector.BaseStorageTreeElement.call(this, storagePanel, null, "", ["frame-storage-tree-item"]);
1025 this._frame = frame;
1026 this.frameNavigated(frame);
1029 WebInspector.FrameTreeElement.prototype = {
1030 frameNavigated: function(frame)
1032 this.removeChildren();
1033 this._frameId = frame.id;
1035 var title = frame.name;
1036 var subtitle = new WebInspector.Resource(null, frame.url).displayName;
1037 this.setTitles(title, subtitle);
1039 this._categoryElements = {};
1040 this._treeElementForResource = {};
1042 this._storagePanel.addDocumentURL(frame.url);
1047 return "frame://" + encodeURI(this._displayName);
1050 onattach: function()
1052 WebInspector.BaseStorageTreeElement.prototype.onattach.call(this);
1053 if (this._titleToSetOnAttach || this._subtitleToSetOnAttach) {
1054 this.setTitles(this._titleToSetOnAttach, this._subtitleToSetOnAttach);
1055 delete this._titleToSetOnAttach;
1056 delete this._subtitleToSetOnAttach;
1060 onselect: function()
1062 WebInspector.BaseStorageTreeElement.prototype.onselect.call(this);
1063 this._storagePanel.showCategoryView(this._displayName);
1065 this.listItemElement.removeStyleClass("hovered");
1066 DOMAgent.hideHighlight();
1071 return this._displayName;
1074 setTitles: function(title, subtitle)
1076 this._displayName = title || "";
1078 this._displayName += " (" + subtitle + ")";
1081 this.titleElement.textContent = title || "";
1083 var subtitleElement = document.createElement("span");
1084 subtitleElement.className = "base-storage-tree-element-subtitle";
1085 subtitleElement.textContent = "(" + subtitle + ")";
1086 this.titleElement.appendChild(subtitleElement);
1089 this._titleToSetOnAttach = title;
1090 this._subtitleToSetOnAttach = subtitle;
1094 set hovered(hovered)
1097 this.listItemElement.addStyleClass("hovered");
1098 DOMAgent.highlightFrame(this._frameId, WebInspector.Color.PageHighlight.Content.toProtocolRGBA(), WebInspector.Color.PageHighlight.ContentOutline.toProtocolRGBA());
1100 this.listItemElement.removeStyleClass("hovered");
1101 DOMAgent.hideHighlight();
1105 appendResource: function(resource)
1107 var categoryName = resource.category.name;
1108 var categoryElement = resource.category === WebInspector.resourceCategories.documents ? this : this._categoryElements[categoryName];
1109 if (!categoryElement) {
1110 categoryElement = new WebInspector.StorageCategoryTreeElement(this._storagePanel, resource.category.title, categoryName, null, true);
1111 this._categoryElements[resource.category.name] = categoryElement;
1112 this._insertInPresentationOrder(this, categoryElement);
1114 var resourceTreeElement = new WebInspector.FrameResourceTreeElement(this._storagePanel, resource);
1115 this._insertInPresentationOrder(categoryElement, resourceTreeElement);
1116 resourceTreeElement._populateRevisions();
1118 this._treeElementForResource[resource.url] = resourceTreeElement;
1121 resourceByURL: function(url)
1123 var treeElement = this._treeElementForResource[url];
1124 return treeElement ? treeElement.representedObject : null;
1127 appendChild: function(treeElement)
1129 this._insertInPresentationOrder(this, treeElement);
1132 _insertInPresentationOrder: function(parentTreeElement, childTreeElement)
1134 // Insert in the alphabetical order, first frames, then resources. Document resource goes last.
1135 function typeWeight(treeElement)
1137 if (treeElement instanceof WebInspector.StorageCategoryTreeElement)
1139 if (treeElement instanceof WebInspector.FrameTreeElement)
1144 function compare(treeElement1, treeElement2)
1146 var typeWeight1 = typeWeight(treeElement1);
1147 var typeWeight2 = typeWeight(treeElement2);
1150 if (typeWeight1 > typeWeight2)
1152 else if (typeWeight1 < typeWeight2)
1155 var title1 = treeElement1.displayName || treeElement1.titleText;
1156 var title2 = treeElement2.displayName || treeElement2.titleText;
1157 result = title1.localeCompare(title2);
1162 var children = parentTreeElement.children;
1164 for (i = 0; i < children.length; ++i) {
1165 if (compare(childTreeElement, children[i]) < 0)
1168 parentTreeElement.insertChild(childTreeElement, i);
1172 WebInspector.FrameTreeElement.prototype.__proto__ = WebInspector.BaseStorageTreeElement.prototype;
1174 WebInspector.FrameResourceTreeElement = function(storagePanel, resource)
1176 WebInspector.BaseStorageTreeElement.call(this, storagePanel, resource, resource.displayName, ["resource-sidebar-tree-item", "resources-category-" + resource.category.name]);
1177 this._resource = resource;
1178 this._resource.addEventListener(WebInspector.Resource.Events.MessageAdded, this._consoleMessageAdded, this);
1179 this._resource.addEventListener(WebInspector.Resource.Events.MessagesCleared, this._consoleMessagesCleared, this);
1180 this._resource.addEventListener(WebInspector.Resource.Events.RevisionAdded, this._revisionAdded, this);
1181 this.tooltip = resource.url;
1184 WebInspector.FrameResourceTreeElement.prototype = {
1187 return this._resource.url;
1190 onselect: function()
1192 WebInspector.BaseStorageTreeElement.prototype.onselect.call(this);
1193 this._storagePanel._showResourceView(this._resource);
1196 ondblclick: function(event)
1198 PageAgent.open(this._resource.url, true);
1201 onattach: function()
1203 WebInspector.BaseStorageTreeElement.prototype.onattach.call(this);
1205 if (this._resource.category === WebInspector.resourceCategories.images) {
1206 var previewImage = document.createElement("img");
1207 previewImage.className = "image-resource-icon-preview";
1208 this._resource.populateImageSource(previewImage);
1210 var iconElement = document.createElement("div");
1211 iconElement.className = "icon";
1212 iconElement.appendChild(previewImage);
1213 this.listItemElement.replaceChild(iconElement, this.imageElement);
1216 this._statusElement = document.createElement("div");
1217 this._statusElement.className = "status";
1218 this.listItemElement.insertBefore(this._statusElement, this.titleElement);
1220 this.listItemElement.draggable = true;
1221 this.listItemElement.addEventListener("dragstart", this._ondragstart.bind(this), false);
1222 this.listItemElement.addEventListener("contextmenu", this._handleContextMenuEvent.bind(this), true);
1224 this._updateErrorsAndWarningsBubbles();
1227 _ondragstart: function(event)
1229 event.dataTransfer.setData("text/plain", this._resource.content);
1230 event.dataTransfer.effectAllowed = "copy";
1234 _handleContextMenuEvent: function(event)
1236 var contextMenu = new WebInspector.ContextMenu();
1237 contextMenu.appendItem(WebInspector.openLinkExternallyLabel(), WebInspector.openResource.bind(WebInspector, this._resource.url, false));
1238 this._appendSaveAsAction(contextMenu, event);
1239 contextMenu.show(event);
1242 _appendSaveAsAction: function(contextMenu, event)
1244 if (!Preferences.saveAsAvailable)
1247 if (this._resource.type !== WebInspector.Resource.Type.Document &&
1248 this._resource.type !== WebInspector.Resource.Type.Stylesheet &&
1249 this._resource.type !== WebInspector.Resource.Type.Script)
1254 var fileName = this._resource.displayName;
1255 this._resource.requestContent(InspectorFrontendHost.saveAs.bind(InspectorFrontendHost, fileName));
1258 contextMenu.appendSeparator();
1259 contextMenu.appendItem(WebInspector.UIString(WebInspector.useLowerCaseMenuTitles() ? "Save as..." : "Save As..."), save.bind(this));
1262 _setBubbleText: function(x)
1264 if (!this._bubbleElement) {
1265 this._bubbleElement = document.createElement("div");
1266 this._bubbleElement.className = "bubble";
1267 this._statusElement.appendChild(this._bubbleElement);
1270 this._bubbleElement.textContent = x;
1273 _resetBubble: function()
1275 if (this._bubbleElement) {
1276 this._bubbleElement.textContent = "";
1277 this._bubbleElement.removeStyleClass("search-matches");
1278 this._bubbleElement.removeStyleClass("warning");
1279 this._bubbleElement.removeStyleClass("error");
1283 _resetSearchResults: function()
1285 this._resetBubble();
1286 this._searchMatchesCount = 0;
1289 get searchMatchesCount()
1291 return this._searchMatchesCount;
1294 searchMatchesFound: function(matchesCount)
1296 this._resetSearchResults();
1298 this._searchMatchesCount = matchesCount;
1299 this._setBubbleText(matchesCount);
1300 this._bubbleElement.addStyleClass("search-matches");
1302 // Expand, do not scroll into view.
1303 var currentAncestor = this.parent;
1304 while (currentAncestor && !currentAncestor.root) {
1305 if (!currentAncestor.expanded)
1306 currentAncestor.expand();
1307 currentAncestor = currentAncestor.parent;
1311 _updateErrorsAndWarningsBubbles: function()
1313 if (this._storagePanel.currentQuery)
1316 this._resetBubble();
1318 if (this._resource.warnings || this._resource.errors)
1319 this._setBubbleText(this._resource.warnings + this._resource.errors);
1321 if (this._resource.warnings)
1322 this._bubbleElement.addStyleClass("warning");
1324 if (this._resource.errors)
1325 this._bubbleElement.addStyleClass("error");
1328 _consoleMessagesCleared: function()
1330 // FIXME: move to the SourceFrame.
1331 if (this._sourceView)
1332 this._sourceView.clearMessages();
1334 this._updateErrorsAndWarningsBubbles();
1337 _consoleMessageAdded: function(event)
1339 var msg = event.data;
1340 if (this._sourceView)
1341 this._sourceView.addMessage(msg);
1342 this._updateErrorsAndWarningsBubbles();
1345 _populateRevisions: function()
1347 for (var i = 0; i < this._resource.history.length; ++i)
1348 this._appendRevision(this._resource.history[i]);
1351 _revisionAdded: function(event)
1353 this._appendRevision(event.data);
1356 _appendRevision: function(revision)
1358 this.insertChild(new WebInspector.ResourceRevisionTreeElement(this._storagePanel, revision), 0);
1359 var oldView = this._sourceView;
1361 // This is needed when resource content was changed from scripts panel.
1362 var newView = this._recreateSourceView();
1363 if (oldView === this._storagePanel.visibleView)
1364 this._storagePanel._showResourceView(this._resource);
1368 sourceView: function()
1370 if (!this._sourceView) {
1371 this._sourceView = this._createSourceView();
1372 if (this._resource.messages) {
1373 for (var i = 0; i < this._resource.messages.length; i++)
1374 this._sourceView.addMessage(this._resource.messages[i]);
1377 return this._sourceView;
1380 _createSourceView: function()
1382 return new WebInspector.EditableResourceSourceFrame(this._resource);
1385 _recreateSourceView: function()
1387 var oldView = this._sourceView;
1388 var newView = this._createSourceView();
1390 var oldViewParentNode = oldView.visible ? oldView.element.parentNode : null;
1391 newView.inheritScrollPositions(oldView);
1393 this._storagePanel.removeChildView(this._sourceView);
1394 this._storagePanel.addChildView(newView);
1395 this._sourceView = newView;
1397 if (oldViewParentNode)
1398 newView.show(oldViewParentNode);
1404 WebInspector.FrameResourceTreeElement.prototype.__proto__ = WebInspector.BaseStorageTreeElement.prototype;
1406 WebInspector.DatabaseTreeElement = function(storagePanel, database)
1408 WebInspector.BaseStorageTreeElement.call(this, storagePanel, null, database.name, ["database-storage-tree-item"], true);
1409 this._database = database;
1412 WebInspector.DatabaseTreeElement.prototype = {
1415 return "database://" + encodeURI(this._database.name);
1418 onselect: function()
1420 WebInspector.BaseStorageTreeElement.prototype.onselect.call(this);
1421 this._storagePanel.showDatabase(this._database);
1424 oncollapse: function()
1426 // Request a refresh after every collapse so the next
1427 // expand will have an updated table list.
1428 this.shouldRefreshChildren = true;
1431 onpopulate: function()
1433 this.removeChildren();
1435 function tableNamesCallback(tableNames)
1437 var tableNamesLength = tableNames.length;
1438 for (var i = 0; i < tableNamesLength; ++i)
1439 this.appendChild(new WebInspector.DatabaseTableTreeElement(this._storagePanel, this._database, tableNames[i]));
1441 this._database.getTableNames(tableNamesCallback.bind(this));
1445 WebInspector.DatabaseTreeElement.prototype.__proto__ = WebInspector.BaseStorageTreeElement.prototype;
1447 WebInspector.DatabaseTableTreeElement = function(storagePanel, database, tableName)
1449 WebInspector.BaseStorageTreeElement.call(this, storagePanel, null, tableName, ["database-storage-tree-item"]);
1450 this._database = database;
1451 this._tableName = tableName;
1454 WebInspector.DatabaseTableTreeElement.prototype = {
1457 return "database://" + encodeURI(this._database.name) + "/" + encodeURI(this._tableName);
1460 onselect: function()
1462 WebInspector.BaseStorageTreeElement.prototype.onselect.call(this);
1463 this._storagePanel.showDatabase(this._database, this._tableName);
1466 WebInspector.DatabaseTableTreeElement.prototype.__proto__ = WebInspector.BaseStorageTreeElement.prototype;
1468 WebInspector.DOMStorageTreeElement = function(storagePanel, domStorage, className)
1470 WebInspector.BaseStorageTreeElement.call(this, storagePanel, null, domStorage.domain ? domStorage.domain : WebInspector.UIString("Local Files"), ["domstorage-storage-tree-item", className]);
1471 this._domStorage = domStorage;
1474 WebInspector.DOMStorageTreeElement.prototype = {
1477 return "storage://" + this._domStorage.domain + "/" + (this._domStorage.isLocalStorage ? "local" : "session");
1480 onselect: function()
1482 WebInspector.BaseStorageTreeElement.prototype.onselect.call(this);
1483 this._storagePanel.showDOMStorage(this._domStorage);
1486 WebInspector.DOMStorageTreeElement.prototype.__proto__ = WebInspector.BaseStorageTreeElement.prototype;
1488 WebInspector.CookieTreeElement = function(storagePanel, cookieDomain)
1490 WebInspector.BaseStorageTreeElement.call(this, storagePanel, null, cookieDomain ? cookieDomain : WebInspector.UIString("Local Files"), ["cookie-storage-tree-item"]);
1491 this._cookieDomain = cookieDomain;
1494 WebInspector.CookieTreeElement.prototype = {
1497 return "cookies://" + this._cookieDomain;
1500 onselect: function()
1502 WebInspector.BaseStorageTreeElement.prototype.onselect.call(this);
1503 this._storagePanel.showCookies(this, this._cookieDomain);
1506 WebInspector.CookieTreeElement.prototype.__proto__ = WebInspector.BaseStorageTreeElement.prototype;
1508 WebInspector.ApplicationCacheTreeElement = function(storagePanel, appcacheDomain)
1510 WebInspector.BaseStorageTreeElement.call(this, storagePanel, null, appcacheDomain ? appcacheDomain : WebInspector.UIString("Local Files"), ["application-cache-storage-tree-item"]);
1511 this._appcacheDomain = appcacheDomain;
1514 WebInspector.ApplicationCacheTreeElement.prototype = {
1517 return "appcache://" + this._appcacheDomain;
1520 onselect: function()
1522 WebInspector.BaseStorageTreeElement.prototype.onselect.call(this);
1523 this._storagePanel.showApplicationCache(this, this._appcacheDomain);
1526 WebInspector.ApplicationCacheTreeElement.prototype.__proto__ = WebInspector.BaseStorageTreeElement.prototype;
1528 WebInspector.ResourceRevisionTreeElement = function(storagePanel, revision)
1530 var title = revision.timestamp ? revision.timestamp.toLocaleTimeString() : WebInspector.UIString("(original)");
1531 WebInspector.BaseStorageTreeElement.call(this, storagePanel, revision, title, ["resource-sidebar-tree-item", "resources-category-" + revision.resource.category.name]);
1532 if (revision.timestamp)
1533 this.tooltip = revision.timestamp.toLocaleString();
1534 this._revision = revision;
1537 WebInspector.ResourceRevisionTreeElement.prototype = {
1540 return this._revision.resource.url;
1543 onattach: function()
1545 WebInspector.BaseStorageTreeElement.prototype.onattach.call(this);
1546 this.listItemElement.draggable = true;
1547 this.listItemElement.addEventListener("dragstart", this._ondragstart.bind(this), false);
1548 this.listItemElement.addEventListener("contextmenu", this._handleContextMenuEvent.bind(this), true);
1551 onselect: function()
1553 WebInspector.BaseStorageTreeElement.prototype.onselect.call(this);
1554 this._storagePanel._showRevisionView(this._revision);
1557 _ondragstart: function(event)
1559 if (this._revision.content) {
1560 event.dataTransfer.setData("text/plain", this._revision.content);
1561 event.dataTransfer.effectAllowed = "copy";
1566 _handleContextMenuEvent: function(event)
1568 var contextMenu = new WebInspector.ContextMenu();
1569 contextMenu.appendItem(WebInspector.UIString("Revert to this revision"), this._revision.revertToThis.bind(this._revision));
1571 if (Preferences.saveAsAvailable) {
1574 var fileName = this._revision.resource.displayName;
1575 this._revision.requestContent(InspectorFrontendHost.saveAs.bind(InspectorFrontendHost, fileName));
1577 contextMenu.appendSeparator();
1578 contextMenu.appendItem(WebInspector.UIString(WebInspector.useLowerCaseMenuTitles() ? "Save as..." : "Save As..."), save.bind(this));
1581 contextMenu.show(event);
1584 sourceView: function()
1586 if (!this._sourceView)
1587 this._sourceView = new WebInspector.ResourceRevisionSourceFrame(this._revision);
1588 return this._sourceView;
1592 WebInspector.ResourceRevisionTreeElement.prototype.__proto__ = WebInspector.BaseStorageTreeElement.prototype;
1594 WebInspector.StorageCategoryView = function()
1596 WebInspector.View.call(this);
1598 this.element.addStyleClass("storage-view");
1599 this._emptyView = new WebInspector.EmptyView();
1600 this._emptyView.show(this.element);
1603 WebInspector.StorageCategoryView.prototype = {
1604 setText: function(text)
1606 this._emptyView.text = text;
1610 WebInspector.StorageCategoryView.prototype.__proto__ = WebInspector.View.prototype;
1612 WebInspector.ResourcesSearchController = function(rootElement)
1614 this._root = rootElement;
1615 this._traverser = new WebInspector.SearchResultsTreeElementsTraverser(rootElement);
1616 this._lastTreeElement = null;
1617 this._lastIndex = -1;
1620 WebInspector.ResourcesSearchController.prototype = {
1621 nextSearchResult: function(currentTreeElement)
1623 if (!currentTreeElement)
1624 return this._searchResult(this._traverser.first(), 0);
1626 if (!currentTreeElement.searchMatchesCount)
1627 return this._searchResult(this._traverser.next(currentTreeElement), 0);
1629 if (this._lastTreeElement !== currentTreeElement || this._lastIndex === -1)
1630 return this._searchResult(currentTreeElement, 0);
1632 if (this._lastIndex == currentTreeElement.searchMatchesCount - 1)
1633 return this._searchResult(this._traverser.next(currentTreeElement), 0);
1635 return this._searchResult(currentTreeElement, this._lastIndex + 1);
1638 previousSearchResult: function(currentTreeElement)
1640 if (!currentTreeElement) {
1641 var treeElement = this._traverser.last();
1642 return this._searchResult(treeElement, treeElement.searchMatchesCount - 1);
1645 if (currentTreeElement.searchMatchesCount && this._lastTreeElement === currentTreeElement && this._lastIndex > 0)
1646 return this._searchResult(currentTreeElement, this._lastIndex - 1);
1648 var treeElement = this._traverser.previous(currentTreeElement)
1649 return this._searchResult(treeElement, treeElement.searchMatchesCount - 1);
1652 _searchResult: function(treeElement, index)
1654 this._lastTreeElement = treeElement;
1655 this._lastIndex = index;
1656 return {treeElement: treeElement, index: index};
1660 WebInspector.SearchResultsTreeElementsTraverser = function(rootElement)
1662 this._root = rootElement;
1665 WebInspector.SearchResultsTreeElementsTraverser.prototype = {
1668 return this.next(this._root);
1671 last: function(startTreeElement)
1673 return this.previous(this._root);
1676 next: function(startTreeElement)
1678 var treeElement = startTreeElement;
1680 treeElement = this._traverseNext(treeElement) || this._root;
1681 } while (treeElement != startTreeElement && !this._elementHasSearchResults(treeElement));
1685 previous: function(startTreeElement)
1687 var treeElement = startTreeElement;
1689 treeElement = this._traversePrevious(treeElement) || this._lastTreeElement();
1690 } while (treeElement != startTreeElement && !this._elementHasSearchResults(treeElement));
1694 _traverseNext: function(treeElement)
1696 return treeElement.traverseNextTreeElement(false, this._root, true);
1699 _elementHasSearchResults: function(treeElement)
1701 return treeElement instanceof WebInspector.FrameResourceTreeElement && treeElement.searchMatchesCount;
1704 _traversePrevious: function(treeElement)
1706 return treeElement.traversePreviousTreeElement(false, this._root, true);
1709 _lastTreeElement: function()
1711 var treeElement = this._root;
1712 var nextTreeElement;
1713 while (nextTreeElement = this._traverseNext(treeElement))
1714 treeElement = nextTreeElement;