Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(307)

Side by Side Diff: third_party/WebKit/Source/devtools/front_end/network/XMLView.js

Issue 1942683006: [Devtools] XMLView now searchable (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@FIND_IN_JSON_FINAL
Patch Set: Fixed nit Created 4 years, 7 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « third_party/WebKit/Source/devtools/front_end/network/RequestPreviewView.js ('k') | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright 2014 The Chromium Authors. All rights reserved. 1 // Copyright 2014 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 /** 5 /**
6 * @constructor 6 * @constructor
7 * @extends {WebInspector.Widget} 7 * @extends {WebInspector.Widget}
8 * @implements {WebInspector.Searchable}
8 * @param {!Document} parsedXML 9 * @param {!Document} parsedXML
9 */ 10 */
10 WebInspector.XMLView = function(parsedXML) 11 WebInspector.XMLView = function(parsedXML)
11 { 12 {
12 WebInspector.Widget.call(this, true); 13 WebInspector.Widget.call(this, true);
13 this.registerRequiredCSS("network/xmlView.css"); 14 this.registerRequiredCSS("network/xmlView.css");
14 this.contentElement.classList.add("shadow-xml-view", "source-code"); 15 this.contentElement.classList.add("shadow-xml-view", "source-code");
15 var treeOutline = new TreeOutline(); 16 this._treeOutline = new TreeOutline();
16 this.contentElement.appendChild(treeOutline.element); 17 this.contentElement.appendChild(this._treeOutline.element);
17 WebInspector.XMLView.Node.populate(treeOutline, parsedXML); 18
19 /** @type {?WebInspector.SearchableView} */
20 this._searchableView;
21 /** @type {number} */
22 this._currentSearchFocusIndex = 0;
23 /** @type {!Array.<!TreeElement>} */
24 this._currentSearchTreeElements = [];
25 /** @type {?WebInspector.SearchableView.SearchConfig} */
26 this._searchConfig;
27
28 WebInspector.XMLView.Node.populate(this._treeOutline, parsedXML, this);
18 } 29 }
19 30
20 /** 31 /**
32 * @param {!Document} parsedXML
33 * @return {!WebInspector.SearchableView}
34 */
35 WebInspector.XMLView.createSearchableView = function(parsedXML)
36 {
37 var xmlView = new WebInspector.XMLView(parsedXML);
38 var searchableView = new WebInspector.SearchableView(xmlView);
39 searchableView.setPlaceholder(WebInspector.UIString("Find"));
40 xmlView._searchableView = searchableView;
41 xmlView.show(searchableView.element);
42 xmlView.contentElement.setAttribute("tabIndex", 0);
43 return searchableView;
44 }
45
46 /**
21 * @param {string} text 47 * @param {string} text
22 * @param {string} mimeType 48 * @param {string} mimeType
23 * @return {?Document} 49 * @return {?Document}
24 */ 50 */
25 WebInspector.XMLView.parseXML = function(text, mimeType) 51 WebInspector.XMLView.parseXML = function(text, mimeType)
26 { 52 {
27 var parsedXML; 53 var parsedXML;
28 try { 54 try {
29 parsedXML = (new DOMParser()).parseFromString(text, mimeType); 55 parsedXML = (new DOMParser()).parseFromString(text, mimeType);
30 } catch (e) { 56 } catch (e) {
31 return null; 57 return null;
32 } 58 }
33 if (parsedXML.body) 59 if (parsedXML.body)
34 return null; 60 return null;
35 return parsedXML; 61 return parsedXML;
36 } 62 }
37 63
38 WebInspector.XMLView.prototype = { 64 WebInspector.XMLView.prototype = {
65 /**
66 * @param {number} index
67 * @param {boolean} shouldJump
68 */
69 _jumpToMatch: function(index, shouldJump)
70 {
71 if (!this._searchConfig)
72 return;
73 var regex = this._searchConfig.toSearchRegex(true);
74 var previousFocusElement = this._currentSearchTreeElements[this._current SearchFocusIndex];
75 if (previousFocusElement)
76 previousFocusElement.setSearchRegex(regex);
77
78 var newFocusElement = this._currentSearchTreeElements[index];
79 if (newFocusElement) {
80 this._updateSearchIndex(index);
81 if (shouldJump)
82 newFocusElement.reveal(true);
83 newFocusElement.setSearchRegex(regex, WebInspector.highlightedCurren tSearchResultClassName);
84 } else {
85 this._updateSearchIndex(0);
86 }
87 },
88
89 /**
90 * @param {number} count
91 */
92 _updateSearchCount: function(count)
93 {
94 if (!this._searchableView)
95 return;
96 this._searchableView.updateSearchMatchesCount(count);
97 },
98
99 /**
100 * @param {number} index
101 */
102 _updateSearchIndex: function(index)
103 {
104 this._currentSearchFocusIndex = index;
105 if (!this._searchableView)
106 return;
107 this._searchableView.updateCurrentMatchIndex(index);
108 },
109
110 /**
111 * @param {boolean} shouldJump
112 * @param {boolean=} jumpBackwards
113 */
114 _innerPerformSearch: function(shouldJump, jumpBackwards)
115 {
116 if (!this._searchConfig)
117 return;
118 var newIndex = this._currentSearchFocusIndex;
119 var previousSearchFocusElement = this._currentSearchTreeElements[newInde x];
120 this._innerSearchCanceled();
121 this._currentSearchTreeElements = [];
122 var regex = this._searchConfig.toSearchRegex(true);
123
124 for (var element = this._treeOutline.rootElement(); element; element = e lement.traverseNextTreeElement(false)) {
125 if (!(element instanceof WebInspector.XMLView.Node))
126 continue;
127 var hasMatch = element.setSearchRegex(regex);
128 if (hasMatch)
129 this._currentSearchTreeElements.push(element);
130 if (previousSearchFocusElement === element) {
131 var currentIndex = this._currentSearchTreeElements.length - 1;
132 if (hasMatch || jumpBackwards)
133 newIndex = currentIndex;
134 else
135 newIndex = currentIndex + 1;
136 }
137 }
138 this._updateSearchCount(this._currentSearchTreeElements.length);
139
140 if (!this._currentSearchTreeElements.length) {
141 this._updateSearchIndex(0);
142 return;
143 }
144 newIndex = mod(newIndex, this._currentSearchTreeElements.length);
145
146 this._jumpToMatch(newIndex, shouldJump);
147 },
148
149 _innerSearchCanceled: function()
150 {
151 for (var element = this._treeOutline.rootElement(); element; element = e lement.traverseNextTreeElement(false)) {
152 if (!(element instanceof WebInspector.XMLView.Node))
153 continue;
154 element.revertHighlightChanges();
155 }
156 this._updateSearchCount(0);
157 this._updateSearchIndex(0);
158 },
159
160 /**
161 * @override
162 */
163 searchCanceled: function()
164 {
165 this._searchConfig = null;
166 this._currentSearchTreeElements = [];
167 this._innerSearchCanceled();
168 },
169
170 /**
171 * @override
172 * @param {!WebInspector.SearchableView.SearchConfig} searchConfig
173 * @param {boolean} shouldJump
174 * @param {boolean=} jumpBackwards
175 */
176 performSearch: function(searchConfig, shouldJump, jumpBackwards)
177 {
178 this._searchConfig = searchConfig;
179 this._innerPerformSearch(shouldJump, jumpBackwards);
180 },
181
182 /**
183 * @override
184 */
185 jumpToNextSearchResult: function()
186 {
187 if (!this._currentSearchTreeElements.length)
188 return;
189
190 var newIndex = mod(this._currentSearchFocusIndex + 1, this._currentSearc hTreeElements.length);
191 this._jumpToMatch(newIndex, true);
192 },
193
194 /**
195 * @override
196 */
197 jumpToPreviousSearchResult: function()
198 {
199 if (!this._currentSearchTreeElements.length)
200 return;
201
202 var newIndex = mod(this._currentSearchFocusIndex - 1, this._currentSearc hTreeElements.length);
203 this._jumpToMatch(newIndex, true);
204 },
205
206 /**
207 * @override
208 * @return {boolean}
209 */
210 supportsCaseSensitiveSearch: function()
211 {
212 return true;
213 },
214
215 /**
216 * @override
217 * @return {boolean}
218 */
219 supportsRegexSearch: function()
220 {
221 return true;
222 },
223
39 __proto__: WebInspector.Widget.prototype 224 __proto__: WebInspector.Widget.prototype
40 } 225 }
41 226
42 /** 227 /**
43 * @constructor 228 * @constructor
44 * @extends {TreeElement} 229 * @extends {TreeElement}
45 * @param {!Node} node 230 * @param {!Node} node
46 * @param {boolean} closeTag 231 * @param {boolean} closeTag
232 * @param {!WebInspector.XMLView} xmlView
47 */ 233 */
48 WebInspector.XMLView.Node = function(node, closeTag) 234 WebInspector.XMLView.Node = function(node, closeTag, xmlView)
49 { 235 {
50 TreeElement.call(this, "", !closeTag && !!node.childElementCount); 236 TreeElement.call(this, "", !closeTag && !!node.childElementCount);
51 this._node = node; 237 this._node = node;
52 this._closeTag = closeTag; 238 this._closeTag = closeTag;
53 this.selectable = false; 239 this.selectable = false;
240 /** @type {!Array.<!Object>} */
241 this._highlightChanges = [];
242 this._xmlView = xmlView;
54 this._updateTitle(); 243 this._updateTitle();
55 } 244 }
56 245
57 /** 246 /**
58 * @param {!TreeOutline|!TreeElement} root 247 * @param {!TreeOutline|!TreeElement} root
59 * @param {!Node} xmlNode 248 * @param {!Node} xmlNode
249 * @param {!WebInspector.XMLView} xmlView
60 */ 250 */
61 WebInspector.XMLView.Node.populate = function(root, xmlNode) 251 WebInspector.XMLView.Node.populate = function(root, xmlNode, xmlView)
62 { 252 {
63 var node = xmlNode.firstChild; 253 var node = xmlNode.firstChild;
64 while (node) { 254 while (node) {
65 var currentNode = node; 255 var currentNode = node;
66 node = node.nextSibling; 256 node = node.nextSibling;
67 var nodeType = currentNode.nodeType; 257 var nodeType = currentNode.nodeType;
68 // ignore empty TEXT 258 // ignore empty TEXT
69 if (nodeType === 3 && currentNode.nodeValue.match(/\s+/)) 259 if (nodeType === 3 && currentNode.nodeValue.match(/\s+/))
70 continue; 260 continue;
71 // ignore ATTRIBUTE, ENTITY_REFERENCE, ENTITY, DOCUMENT, DOCUMENT_TYPE, DOCUMENT_FRAGMENT, NOTATION 261 // ignore ATTRIBUTE, ENTITY_REFERENCE, ENTITY, DOCUMENT, DOCUMENT_TYPE, DOCUMENT_FRAGMENT, NOTATION
72 if ((nodeType !== 1) && (nodeType !== 3) && (nodeType !== 4) && (nodeTyp e !== 7) && (nodeType !== 8)) 262 if ((nodeType !== 1) && (nodeType !== 3) && (nodeType !== 4) && (nodeTyp e !== 7) && (nodeType !== 8))
73 continue; 263 continue;
74 root.appendChild(new WebInspector.XMLView.Node(currentNode, false)); 264 root.appendChild(new WebInspector.XMLView.Node(currentNode, false, xmlVi ew));
75 } 265 }
76 } 266 }
77 267
78 WebInspector.XMLView.Node.prototype = { 268 WebInspector.XMLView.Node.prototype = {
269 /**
270 * @param {?RegExp} regex
271 * @param {string=} additionalCssClassName
272 * @return {boolean}
273 */
274 setSearchRegex: function(regex, additionalCssClassName) {
275 this.revertHighlightChanges();
276 if (!regex)
277 return false;
278 if (this._closeTag && this.parent && !this.parent.expanded)
279 return false;
280 regex.lastIndex = 0;
281 var cssClasses = WebInspector.highlightedSearchResultClassName;
282 if (additionalCssClassName)
283 cssClasses += " " + additionalCssClassName;
284 var content = this.listItemElement.textContent.replace(/\xA0/g, " ");
285 var match = regex.exec(content);
286 var ranges = [];
287 while (match) {
288 ranges.push(new WebInspector.SourceRange(match.index, match[0].lengt h));
289 match = regex.exec(content);
290 }
291 if (ranges.length)
292 WebInspector.highlightRangesWithStyleClass(this.listItemElement, ran ges, cssClasses, this._highlightChanges);
293 return !!this._highlightChanges.length;
294 },
295
296 revertHighlightChanges: function()
297 {
298 WebInspector.revertDomChanges(this._highlightChanges);
299 this._highlightChanges = [];
300 },
301
79 _updateTitle: function() 302 _updateTitle: function()
80 { 303 {
81 var node = this._node; 304 var node = this._node;
82 switch (node.nodeType) { 305 switch (node.nodeType) {
83 case 1: // ELEMENT 306 case 1: // ELEMENT
84 var tag = node.tagName; 307 var tag = node.tagName;
85 if (this._closeTag) { 308 if (this._closeTag) {
86 this._setTitle(["</" + tag + ">", "shadow-xml-view-tag"]); 309 this._setTitle(["</" + tag + ">", "shadow-xml-view-tag"]);
87 return; 310 return;
88 } 311 }
(...skipping 46 matching lines...) Expand 10 before | Expand all | Expand 10 after
135 358
136 /** 359 /**
137 * @param {!Array.<string>} items 360 * @param {!Array.<string>} items
138 */ 361 */
139 _setTitle: function(items) 362 _setTitle: function(items)
140 { 363 {
141 var titleFragment = createDocumentFragment(); 364 var titleFragment = createDocumentFragment();
142 for (var i = 0; i < items.length; i += 2) 365 for (var i = 0; i < items.length; i += 2)
143 titleFragment.createChild("span", items[i + 1]).textContent = items[ i]; 366 titleFragment.createChild("span", items[i + 1]).textContent = items[ i];
144 this.title = titleFragment; 367 this.title = titleFragment;
368 this._xmlView._innerPerformSearch(false, false);
145 }, 369 },
146 370
147 onattach: function() 371 onattach: function()
148 { 372 {
149 this.listItemElement.classList.toggle("shadow-xml-view-close-tag", this. _closeTag); 373 this.listItemElement.classList.toggle("shadow-xml-view-close-tag", this. _closeTag);
150 }, 374 },
151 375
152 onexpand: function() 376 onexpand: function()
153 { 377 {
154 this._updateTitle(); 378 this._updateTitle();
155 }, 379 },
156 380
157 oncollapse: function() 381 oncollapse: function()
158 { 382 {
159 this._updateTitle(); 383 this._updateTitle();
160 }, 384 },
161 385
162 onpopulate: function() 386 onpopulate: function()
163 { 387 {
164 WebInspector.XMLView.Node.populate(this, this._node); 388 WebInspector.XMLView.Node.populate(this, this._node, this._xmlView);
165 this.appendChild(new WebInspector.XMLView.Node(this._node, true)); 389 this.appendChild(new WebInspector.XMLView.Node(this._node, true, this._x mlView));
166 }, 390 },
167 391
168 __proto__: TreeElement.prototype 392 __proto__: TreeElement.prototype
169 } 393 }
OLDNEW
« no previous file with comments | « third_party/WebKit/Source/devtools/front_end/network/RequestPreviewView.js ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698