Upstream version 7.36.149.0
[platform/framework/web/crosswalk.git] / src / third_party / WebKit / Source / devtools / front_end / search / FileBasedSearchResultsPane.js
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
3 // found in the LICENSE file.
4
5 /**
6  * @constructor
7  * @extends {WebInspector.SearchResultsPane}
8  * @param {!WebInspector.ProjectSearchConfig} searchConfig
9  */
10 WebInspector.FileBasedSearchResultsPane = function(searchConfig)
11 {
12     WebInspector.SearchResultsPane.call(this, searchConfig);
13
14     this._searchResults = [];
15
16     this.element.id = "search-results-pane-file-based";
17
18     this._treeOutlineElement = document.createElement("ol");
19     this._treeOutlineElement.className = "search-results-outline-disclosure";
20     this.element.appendChild(this._treeOutlineElement);
21     this._treeOutline = new TreeOutline(this._treeOutlineElement);
22
23     this._matchesExpandedCount = 0;
24 }
25
26 WebInspector.FileBasedSearchResultsPane.matchesExpandedByDefaultCount = 20;
27 WebInspector.FileBasedSearchResultsPane.fileMatchesShownAtOnce = 20;
28
29 WebInspector.FileBasedSearchResultsPane.prototype = {
30     /**
31      * @param {!WebInspector.FileBasedSearchResult} searchResult
32      */
33     addSearchResult: function(searchResult)
34     {
35         this._searchResults.push(searchResult);
36         var uiSourceCode = searchResult.uiSourceCode;
37         if (!uiSourceCode)
38             return;
39         this._addFileTreeElement(searchResult);
40     },
41
42     /**
43      * @param {!WebInspector.FileBasedSearchResult} searchResult
44      */
45     _addFileTreeElement: function(searchResult)
46     {
47         var fileTreeElement = new WebInspector.FileBasedSearchResultsPane.FileTreeElement(this._searchConfig, searchResult);
48         this._treeOutline.appendChild(fileTreeElement);
49         // Expand until at least a certain number of matches is expanded.
50         if (this._matchesExpandedCount < WebInspector.FileBasedSearchResultsPane.matchesExpandedByDefaultCount)
51             fileTreeElement.expand();
52         this._matchesExpandedCount += searchResult.searchMatches.length;
53     },
54
55     __proto__: WebInspector.SearchResultsPane.prototype
56 }
57
58 /**
59  * @constructor
60  * @extends {TreeElement}
61  * @param {!WebInspector.ProjectSearchConfig} searchConfig
62  * @param {!WebInspector.FileBasedSearchResult} searchResult
63  */
64 WebInspector.FileBasedSearchResultsPane.FileTreeElement = function(searchConfig, searchResult)
65 {
66     TreeElement.call(this, "", null, true);
67     this._searchConfig = searchConfig;
68     this._searchResult = searchResult;
69
70     this.toggleOnClick = true;
71     this.selectable = false;
72 }
73
74 WebInspector.FileBasedSearchResultsPane.FileTreeElement.prototype = {
75     onexpand: function()
76     {
77         if (this._initialized)
78             return;
79
80         this._updateMatchesUI();
81         this._initialized = true;
82     },
83
84     _updateMatchesUI: function()
85     {
86         this.removeChildren();
87         var toIndex = Math.min(this._searchResult.searchMatches.length, WebInspector.FileBasedSearchResultsPane.fileMatchesShownAtOnce);
88         if (toIndex < this._searchResult.searchMatches.length) {
89             this._appendSearchMatches(0, toIndex - 1);
90             this._appendShowMoreMatchesElement(toIndex - 1);
91         } else {
92             this._appendSearchMatches(0, toIndex);
93         }
94     },
95
96     onattach: function()
97     {
98         this._updateSearchMatches();
99     },
100
101     _updateSearchMatches: function()
102     {
103         this.listItemElement.classList.add("search-result");
104
105         var fileNameSpan = document.createElement("span");
106         fileNameSpan.className = "search-result-file-name";
107         fileNameSpan.textContent = this._searchResult.uiSourceCode.fullDisplayName();
108         this.listItemElement.appendChild(fileNameSpan);
109
110         var matchesCountSpan = document.createElement("span");
111         matchesCountSpan.className = "search-result-matches-count";
112
113         var searchMatchesCount = this._searchResult.searchMatches.length;
114         if (searchMatchesCount === 1)
115             matchesCountSpan.textContent = WebInspector.UIString("(%d match)", searchMatchesCount);
116         else
117             matchesCountSpan.textContent = WebInspector.UIString("(%d matches)", searchMatchesCount);
118
119         this.listItemElement.appendChild(matchesCountSpan);
120         if (this.expanded)
121             this._updateMatchesUI();
122     },
123
124     /**
125      * @param {number} fromIndex
126      * @param {number} toIndex
127      */
128     _appendSearchMatches: function(fromIndex, toIndex)
129     {
130         var searchResult = this._searchResult;
131         var uiSourceCode = searchResult.uiSourceCode;
132         var searchMatches = searchResult.searchMatches;
133
134         var queries = this._searchConfig.queries();
135         var regexes = [];
136         for (var i = 0; i < queries.length; ++i)
137             regexes.push(createSearchRegex(queries[i], !this._searchConfig.ignoreCase(), this._searchConfig.isRegex()));
138
139         for (var i = fromIndex; i < toIndex; ++i) {
140             var lineNumber = searchMatches[i].lineNumber;
141             var lineContent = searchMatches[i].lineContent;
142             var matchRanges = [];
143             for (var j = 0; j < regexes.length; ++j)
144                 matchRanges = matchRanges.concat(this._regexMatchRanges(lineContent, regexes[j]));
145
146             var anchor = this._createAnchor(uiSourceCode, lineNumber, matchRanges[0].offset);
147
148             var numberString = numberToStringWithSpacesPadding(lineNumber + 1, 4);
149             var lineNumberSpan = document.createElement("span");
150             lineNumberSpan.classList.add("search-match-line-number");
151             lineNumberSpan.textContent = numberString;
152             anchor.appendChild(lineNumberSpan);
153
154             var contentSpan = this._createContentSpan(lineContent, matchRanges);
155             anchor.appendChild(contentSpan);
156
157             var searchMatchElement = new TreeElement("");
158             searchMatchElement.selectable = false;
159             this.appendChild(searchMatchElement);
160             searchMatchElement.listItemElement.className = "search-match source-code";
161             searchMatchElement.listItemElement.appendChild(anchor);
162         }
163     },
164
165     /**
166      * @param {number} startMatchIndex
167      */
168     _appendShowMoreMatchesElement: function(startMatchIndex)
169     {
170         var matchesLeftCount = this._searchResult.searchMatches.length - startMatchIndex;
171         var showMoreMatchesText = WebInspector.UIString("Show all matches (%d more).", matchesLeftCount);
172         this._showMoreMatchesTreeElement = new TreeElement(showMoreMatchesText);
173         this.appendChild(this._showMoreMatchesTreeElement);
174         this._showMoreMatchesTreeElement.listItemElement.classList.add("show-more-matches");
175         this._showMoreMatchesTreeElement.onselect = this._showMoreMatchesElementSelected.bind(this, startMatchIndex);
176     },
177
178     /**
179      * @param {!WebInspector.UISourceCode} uiSourceCode
180      * @param {number} lineNumber
181      * @param {number} columnNumber
182      * @return {!Element}
183      */
184     _createAnchor: function(uiSourceCode, lineNumber, columnNumber)
185     {
186         return WebInspector.Linkifier.linkifyUsingRevealer(uiSourceCode.uiLocation(lineNumber, columnNumber), "", uiSourceCode.url, lineNumber);
187     },
188
189     /**
190      * @param {string} lineContent
191      * @param {!Array.<!WebInspector.SourceRange>} matchRanges
192      */
193     _createContentSpan: function(lineContent, matchRanges)
194     {
195         var contentSpan = document.createElement("span");
196         contentSpan.className = "search-match-content";
197         contentSpan.textContent = lineContent;
198         WebInspector.highlightRangesWithStyleClass(contentSpan, matchRanges, "highlighted-match");
199         return contentSpan;
200     },
201
202     /**
203      * @param {string} lineContent
204      * @param {!RegExp} regex
205      * @return {!Array.<!WebInspector.SourceRange>}
206      */
207     _regexMatchRanges: function(lineContent, regex)
208     {
209         regex.lastIndex = 0;
210         var match;
211         var offset = 0;
212         var matchRanges = [];
213         while ((regex.lastIndex < lineContent.length) && (match = regex.exec(lineContent)))
214             matchRanges.push(new WebInspector.SourceRange(match.index, match[0].length));
215
216         return matchRanges;
217     },
218
219     /**
220      * @param {number} startMatchIndex
221      * @return {boolean}
222      */
223     _showMoreMatchesElementSelected: function(startMatchIndex)
224     {
225         this.removeChild(this._showMoreMatchesTreeElement);
226         this._appendSearchMatches(startMatchIndex, this._searchResult.searchMatches.length);
227         return false;
228     },
229
230     __proto__: TreeElement.prototype
231 }