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

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: 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
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 WebInspector.XMLView.Node.populate(this._treeOutline, parsedXML, this);
19
20 /** @type {?WebInspector.SearchableView} */
21 this._searchableView;
22 /** @type {number} */
23 this._currentSearchFocusIndex = 0;
24 /** @type {!Array.<!TreeElement>} */
25 this._currentSearchTreeElements = [];
26 /** @type {?WebInspector.SearchableView.SearchConfig} */
27 this._lastSearchConfig;
18 } 28 }
19 29
20 /** 30 /**
31 * @param {!Document} parsedXML
32 * @return {!WebInspector.SearchableView}
33 */
34 WebInspector.XMLView.createSearchableView = function(parsedXML)
35 {
36 var xmlView = new WebInspector.XMLView(parsedXML);
37 var searchableView = new WebInspector.SearchableView(xmlView);
38 searchableView.setPlaceholder(WebInspector.UIString("Find"));
39 xmlView.setSearchableView(searchableView);
40 xmlView.show(searchableView.element);
41 xmlView.contentElement.setAttribute("tabIndex", 0);
42 return searchableView;
43 }
44
45 /**
21 * @param {string} text 46 * @param {string} text
22 * @param {string} mimeType 47 * @param {string} mimeType
23 * @return {?Document} 48 * @return {?Document}
24 */ 49 */
25 WebInspector.XMLView.parseXML = function(text, mimeType) 50 WebInspector.XMLView.parseXML = function(text, mimeType)
26 { 51 {
27 var parsedXML; 52 var parsedXML;
28 try { 53 try {
29 parsedXML = (new DOMParser()).parseFromString(text, mimeType); 54 parsedXML = (new DOMParser()).parseFromString(text, mimeType);
30 } catch (e) { 55 } catch (e) {
31 return null; 56 return null;
32 } 57 }
33 if (parsedXML.body) 58 if (parsedXML.body)
34 return null; 59 return null;
35 return parsedXML; 60 return parsedXML;
36 } 61 }
37 62
38 WebInspector.XMLView.prototype = { 63 WebInspector.XMLView.prototype = {
64 /**
65 * @param {?WebInspector.SearchableView} view
66 */
67 setSearchableView: function(view)
68 {
69 this._searchableView = view;
70 },
71
72 /**
73 * @param {number} index
74 * @param {boolean} shouldJump
75 */
76 _jumpToMatch: function(index, shouldJump)
77 {
78 if (!this._lastSearchConfig)
79 return;
80 var regex = this._lastSearchConfig.toSearchRegex(true);
81 var newFocusElement = this._currentSearchTreeElements[index];
82 var previousFocusElement = this._currentSearchTreeElements[this._current SearchFocusIndex];
83
84 if (!newFocusElement)
85 index = 0;
86
87 if (previousFocusElement)
88 previousFocusElement.setSearchRegex(regex);
89
90 this._updateSearchIndex(index);
91 if (newFocusElement) {
92 if (shouldJump)
93 newFocusElement.reveal(true);
94 newFocusElement.setSearchRegex(regex, WebInspector.highlightedCurren tSearchResultClassName);
95 }
96 },
97
98 /**
99 * @param {number} count
100 */
101 _updateSearchCount: function(count)
102 {
103 if (!this._searchableView)
104 return;
105 this._searchableView.updateSearchMatchesCount(count);
106 },
107
108 /**
109 * @param {number} index
110 */
111 _updateSearchIndex: function(index)
112 {
113 this._currentSearchFocusIndex = index;
114 if (!this._searchableView)
115 return;
116 this._searchableView.updateCurrentMatchIndex(index);
117 },
118
119 _rerunSearch: function()
lushnikov 2016/05/05 00:10:34 Let's kill this function.
allada 2016/05/05 19:17:59 Done.
120 {
121 if (this._lastSearchConfig)
122 this._innerPerformSearch(this._lastSearchConfig, false, false);
123 },
124
125 /**
126 * @param {!WebInspector.SearchableView.SearchConfig} searchConfig
127 * @param {boolean} shouldJump
128 * @param {boolean=} jumpBackwards
129 */
130 _innerPerformSearch: function(searchConfig, shouldJump, jumpBackwards)
lushnikov 2016/05/05 00:10:34 this function implicitly depends on this._lastSear
allada 2016/05/05 19:17:59 Done.
131 {
132 var newIndex = this._currentSearchFocusIndex;
133 var previousSearchFocusElement = this._currentSearchTreeElements[newInde x];
134 this.searchCanceled();
135 var regex = searchConfig.toSearchRegex(true);
136
137 for (var element = this._treeOutline.rootElement(); element; element = e lement.traverseNextTreeElement(false)) {
138 if (!(element instanceof WebInspector.XMLView.Node))
139 continue;
140 var hasMatch = element.setSearchRegex(regex);
141 if (hasMatch)
142 this._currentSearchTreeElements.push(element);
143 var currentIndex = this._currentSearchTreeElements.length - 1;
lushnikov 2016/05/05 00:10:34 let's move currentIndex declaration inside "if (pr
allada 2016/05/05 19:17:59 Done.
144 if (previousSearchFocusElement === element) {
145 if (hasMatch)
146 newIndex = currentIndex;
147 else if (jumpBackwards)
148 newIndex = currentIndex - 1;
149 else
150 newIndex = currentIndex + 1;
151 }
152 }
153 this._updateSearchCount(this._currentSearchTreeElements.length);
154
155 if (!this._currentSearchTreeElements.length) {
156 this._updateSearchIndex(0);
157 return;
158 }
159 newIndex = mod(newIndex, this._currentSearchTreeElements.length);
160
161 this._lastSearchConfig = searchConfig;
162 this._jumpToMatch(newIndex, shouldJump);
163 },
164
165 /**
166 * @override
167 */
168 searchCanceled: function()
169 {
170 this._lastSearchConfig = null;
171 this._currentSearchTreeElements = [];
172 var currentElement = this._treeOutline.rootElement();
173
174 while (currentElement) {
175 if (currentElement instanceof WebInspector.XMLView.Node)
176 currentElement.revertHighlightChanges();
177 currentElement = currentElement.traverseNextTreeElement(false);
178 }
179 this._updateSearchCount(0);
180 this._updateSearchIndex(0);
181 },
182
183 /**
184 * @override
185 * @param {!WebInspector.SearchableView.SearchConfig} searchConfig
186 * @param {boolean} shouldJump
187 * @param {boolean=} jumpBackwards
188 */
189 performSearch: function(searchConfig, shouldJump, jumpBackwards)
190 {
lushnikov 2016/05/05 00:10:34 this._lastSearchConfig = searchConfig; this._inner
allada 2016/05/05 19:17:59 Done.
191 this._innerPerformSearch(searchConfig, shouldJump, jumpBackwards);
192 },
193
194 /**
195 * @override
196 */
197 jumpToNextSearchResult: 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 */
209 jumpToPreviousSearchResult: function()
210 {
211 if (!this._currentSearchTreeElements.length)
212 return;
213
214 var newIndex = mod(this._currentSearchFocusIndex - 1, this._currentSearc hTreeElements.length);
215 this._jumpToMatch(newIndex, true);
216 },
217
218 /**
219 * @override
220 * @return {boolean}
221 */
222 supportsCaseSensitiveSearch: function()
223 {
224 return true;
225 },
226
227 /**
228 * @override
229 * @return {boolean}
230 */
231 supportsRegexSearch: function()
232 {
233 return true;
234 },
235
39 __proto__: WebInspector.Widget.prototype 236 __proto__: WebInspector.Widget.prototype
40 } 237 }
41 238
42 /** 239 /**
43 * @constructor 240 * @constructor
44 * @extends {TreeElement} 241 * @extends {TreeElement}
45 * @param {!Node} node 242 * @param {!Node} node
46 * @param {boolean} closeTag 243 * @param {boolean} closeTag
244 * @param {!WebInspector.XMLView} xmlView
47 */ 245 */
48 WebInspector.XMLView.Node = function(node, closeTag) 246 WebInspector.XMLView.Node = function(node, closeTag, xmlView)
49 { 247 {
50 TreeElement.call(this, "", !closeTag && !!node.childElementCount); 248 TreeElement.call(this, "", !closeTag && !!node.childElementCount);
51 this._node = node; 249 this._node = node;
52 this._closeTag = closeTag; 250 this._closeTag = closeTag;
53 this.selectable = false; 251 this.selectable = false;
252 /** @type {!Array.<!Object>} */
253 this._highlightChanges = [];
254 this._xmlView = xmlView;
54 this._updateTitle(); 255 this._updateTitle();
55 } 256 }
56 257
57 /** 258 /**
58 * @param {!TreeOutline|!TreeElement} root 259 * @param {!TreeOutline|!TreeElement} root
59 * @param {!Node} xmlNode 260 * @param {!Node} xmlNode
261 * @param {!WebInspector.XMLView} xmlView
60 */ 262 */
61 WebInspector.XMLView.Node.populate = function(root, xmlNode) 263 WebInspector.XMLView.Node.populate = function(root, xmlNode, xmlView)
62 { 264 {
63 var node = xmlNode.firstChild; 265 var node = xmlNode.firstChild;
64 while (node) { 266 while (node) {
65 var currentNode = node; 267 var currentNode = node;
66 node = node.nextSibling; 268 node = node.nextSibling;
67 var nodeType = currentNode.nodeType; 269 var nodeType = currentNode.nodeType;
68 // ignore empty TEXT 270 // ignore empty TEXT
69 if (nodeType === 3 && currentNode.nodeValue.match(/\s+/)) 271 if (nodeType === 3 && currentNode.nodeValue.match(/\s+/))
70 continue; 272 continue;
71 // ignore ATTRIBUTE, ENTITY_REFERENCE, ENTITY, DOCUMENT, DOCUMENT_TYPE, DOCUMENT_FRAGMENT, NOTATION 273 // ignore ATTRIBUTE, ENTITY_REFERENCE, ENTITY, DOCUMENT, DOCUMENT_TYPE, DOCUMENT_FRAGMENT, NOTATION
72 if ((nodeType !== 1) && (nodeType !== 3) && (nodeType !== 4) && (nodeTyp e !== 7) && (nodeType !== 8)) 274 if ((nodeType !== 1) && (nodeType !== 3) && (nodeType !== 4) && (nodeTyp e !== 7) && (nodeType !== 8))
73 continue; 275 continue;
74 root.appendChild(new WebInspector.XMLView.Node(currentNode, false)); 276 root.appendChild(new WebInspector.XMLView.Node(currentNode, false, xmlVi ew));
75 } 277 }
76 } 278 }
77 279
78 WebInspector.XMLView.Node.prototype = { 280 WebInspector.XMLView.Node.prototype = {
281 /**
282 * @param {?RegExp} regex
283 * @param {string=} additionalCssClassName
284 * @return {boolean}
285 */
286 setSearchRegex: function(regex, additionalCssClassName) {
287 this.revertHighlightChanges();
288 if (!regex)
289 return false;
290 if (this._closeTag && this.parent && !this.parent.expanded)
291 return false;
292 regex.lastIndex = 0;
293 var cssClasses = WebInspector.highlightedSearchResultClassName;
294 if (additionalCssClassName)
295 cssClasses += " " + additionalCssClassName;
296 var content = this.listItemElement.textContent.replace(/\xA0/g, " ");
297 var match = regex.exec(content);
298 var ranges = [];
299 while (match) {
300 ranges.push(new WebInspector.SourceRange(match.index, match[0].lengt h));
301 match = regex.exec(content);
302 }
303 if (ranges.length)
304 WebInspector.highlightRangesWithStyleClass(this.listItemElement, ran ges, cssClasses, this._highlightChanges);
305 return !!this._highlightChanges.length;
306 },
307
308 revertHighlightChanges: function()
309 {
310 WebInspector.revertDomChanges(this._highlightChanges);
311 this._highlightChanges = [];
312 },
313
79 _updateTitle: function() 314 _updateTitle: function()
80 { 315 {
81 var node = this._node; 316 var node = this._node;
82 switch (node.nodeType) { 317 switch (node.nodeType) {
83 case 1: // ELEMENT 318 case 1: // ELEMENT
84 var tag = node.tagName; 319 var tag = node.tagName;
85 if (this._closeTag) { 320 if (this._closeTag) {
86 this._setTitle(["</" + tag + ">", "shadow-xml-view-tag"]); 321 this._setTitle(["</" + tag + ">", "shadow-xml-view-tag"]);
87 return; 322 return;
88 } 323 }
(...skipping 46 matching lines...) Expand 10 before | Expand all | Expand 10 after
135 370
136 /** 371 /**
137 * @param {!Array.<string>} items 372 * @param {!Array.<string>} items
138 */ 373 */
139 _setTitle: function(items) 374 _setTitle: function(items)
140 { 375 {
141 var titleFragment = createDocumentFragment(); 376 var titleFragment = createDocumentFragment();
142 for (var i = 0; i < items.length; i += 2) 377 for (var i = 0; i < items.length; i += 2)
143 titleFragment.createChild("span", items[i + 1]).textContent = items[ i]; 378 titleFragment.createChild("span", items[i + 1]).textContent = items[ i];
144 this.title = titleFragment; 379 this.title = titleFragment;
380 this._xmlView._rerunSearch();
lushnikov 2016/05/05 00:10:34 this._xmlView._innerPerformSearch(false, false);
allada 2016/05/05 19:17:59 Done.
145 }, 381 },
146 382
147 onattach: function() 383 onattach: function()
148 { 384 {
149 this.listItemElement.classList.toggle("shadow-xml-view-close-tag", this. _closeTag); 385 this.listItemElement.classList.toggle("shadow-xml-view-close-tag", this. _closeTag);
150 }, 386 },
151 387
152 onexpand: function() 388 onexpand: function()
153 { 389 {
154 this._updateTitle(); 390 this._updateTitle();
155 }, 391 },
156 392
157 oncollapse: function() 393 oncollapse: function()
158 { 394 {
159 this._updateTitle(); 395 this._updateTitle();
160 }, 396 },
161 397
162 onpopulate: function() 398 onpopulate: function()
163 { 399 {
164 WebInspector.XMLView.Node.populate(this, this._node); 400 WebInspector.XMLView.Node.populate(this, this._node, this._xmlView);
165 this.appendChild(new WebInspector.XMLView.Node(this._node, true)); 401 this.appendChild(new WebInspector.XMLView.Node(this._node, true, this._x mlView));
166 }, 402 },
167 403
168 __proto__: TreeElement.prototype 404 __proto__: TreeElement.prototype
169 } 405 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698