Chromium Code Reviews| OLD | NEW |
|---|---|
| 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 Loading... | |
| 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 } |
| OLD | NEW |