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