OLD | NEW |
| (Empty) |
1 /* | |
2 * Copyright (C) 2011 Google Inc. All rights reserved. | |
3 * | |
4 * Redistribution and use in source and binary forms, with or without | |
5 * modification, are permitted provided that the following conditions | |
6 * are met: | |
7 * 1. Redistributions of source code must retain the above copyright | |
8 * notice, this list of conditions and the following disclaimer. | |
9 * 2. Redistributions in binary form must reproduce the above copyright | |
10 * notice, this list of conditions and the following disclaimer in the | |
11 * documentation and/or other materials provided with the distribution. | |
12 * | |
13 * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' | |
14 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, | |
15 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR | |
16 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS | |
17 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR | |
18 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF | |
19 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS | |
20 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN | |
21 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) | |
22 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF | |
23 * THE POSSIBILITY OF SUCH DAMAGE. | |
24 */ | |
25 | |
26 var ui = ui || {}; | |
27 ui.results = ui.results || {}; | |
28 | |
29 (function(){ | |
30 | |
31 var kResultsPrefetchDelayMS = 500; | |
32 | |
33 ui.results.ResultsGrid = base.extends('div', { | |
34 init: function() | |
35 { | |
36 this.className = 'results-grid'; | |
37 }, | |
38 addResults: function(resultsURLs) | |
39 { | |
40 var resultsURLsByTypeAndKind = {}; | |
41 resultsURLs.forEach(function(url) { | |
42 var resultType = results.resultType(url); | |
43 if (!resultsURLsByTypeAndKind[resultType]) | |
44 resultsURLsByTypeAndKind[resultType] = {}; | |
45 resultsURLsByTypeAndKind[resultType][results.resultKind(url)] = url; | |
46 }); | |
47 | |
48 Object.keys(resultsURLsByTypeAndKind, function(resultType, resultsURLsBy
Kind) { | |
49 if (results.kUnknownKind in resultsURLsByKind) { | |
50 // This is something like "crash" that isn't a comparison. | |
51 var result = document.createElement('ct-test-output'); | |
52 result.url = resultsURLsByKind[results.kUnknownKind]; | |
53 result.type = results.kTextType; | |
54 this.appendChild(result); | |
55 return; | |
56 } | |
57 | |
58 var comparison = document.createElement('ct-results-comparison'); | |
59 comparison.type = resultType; | |
60 | |
61 if (results.kActualKind in resultsURLsByKind) | |
62 comparison.actualUrl = resultsURLsByKind[results.kActualKind]; | |
63 if (results.kExpectedKind in resultsURLsByKind) | |
64 comparison.expectedUrl = resultsURLsByKind[results.kExpectedKind
]; | |
65 if (results.kDiffKind in resultsURLsByKind) | |
66 comparison.diffUrl = resultsURLsByKind[results.kDiffKind]; | |
67 | |
68 this.appendChild(comparison); | |
69 }.bind(this)); | |
70 | |
71 if (!this.children.length) | |
72 this.textContent = 'No results to display.' | |
73 } | |
74 }); | |
75 | |
76 ui.results.ResultsDetails = base.extends('div', { | |
77 init: function(delegate, failureInfo) | |
78 { | |
79 this.className = 'results-detail'; | |
80 this._delegate = delegate; | |
81 this._failureInfo = failureInfo; | |
82 this._haveShownOnce = false; | |
83 }, | |
84 show: function() { | |
85 if (this._haveShownOnce) | |
86 return; | |
87 this._haveShownOnce = true; | |
88 this._delegate.fetchResultsURLs(this._failureInfo).then(function(results
URLs) { | |
89 var resultsGrid = new ui.results.ResultsGrid(); | |
90 resultsGrid.addResults(resultsURLs); | |
91 | |
92 this.innerHTML = '' | |
93 this.appendChild( | |
94 new ui.actions.List([ | |
95 new ui.actions.Previous(), | |
96 new ui.actions.Next() | |
97 ])) | |
98 this.appendChild(resultsGrid); | |
99 }.bind(this)); | |
100 }, | |
101 }); | |
102 | |
103 ui.results.FlakinessData = base.extends('iframe', { | |
104 init: function() | |
105 { | |
106 this.className = 'flakiness-iframe'; | |
107 this.src = ui.urlForEmbeddedFlakinessDashboard(); | |
108 this.addEventListener('load', function() { | |
109 window.addEventListener('message', this._handleMessage.bind(this)); | |
110 }); | |
111 }, | |
112 _handleMessage: function(event) { | |
113 if (!this.contentWindow) | |
114 return; | |
115 | |
116 if (event.data.command != 'heightChanged') { | |
117 return; | |
118 } | |
119 | |
120 this.style.height = event.data.height + 'px'; | |
121 } | |
122 }); | |
123 | |
124 ui.results.TestSelector = base.extends('div', { | |
125 init: function(delegate, resultsByTest) | |
126 { | |
127 this.className = 'test-selector'; | |
128 this._delegate = delegate; | |
129 | |
130 var topPanel = document.createElement('div'); | |
131 topPanel.className = 'top-panel'; | |
132 this.appendChild(topPanel); | |
133 | |
134 this._appendResizeHandle(); | |
135 | |
136 var bottomPanel = document.createElement('div'); | |
137 bottomPanel.className = 'bottom-panel'; | |
138 this.appendChild(bottomPanel); | |
139 | |
140 this._flakinessData = new ui.results.FlakinessData(); | |
141 this.appendChild(this._flakinessData); | |
142 | |
143 var testNames = Object.keys(resultsByTest); | |
144 testNames.sort().forEach(function(testName) { | |
145 var nonLinkTitle = document.createElement('a'); | |
146 nonLinkTitle.classList.add('non-link-title'); | |
147 nonLinkTitle.textContent = testName; | |
148 | |
149 var linkTitle = document.createElement('a'); | |
150 linkTitle.classList.add('link-title'); | |
151 linkTitle.setAttribute('href', ui.urlForFlakinessDashboard([testName
])); | |
152 ui.setTargetForLink(linkTitle); | |
153 linkTitle.textContent = testName; | |
154 | |
155 var header = document.createElement('h3'); | |
156 header.appendChild(nonLinkTitle); | |
157 header.appendChild(linkTitle); | |
158 header.addEventListener('click', this._showResults.bind(this, header
, false)); | |
159 topPanel.appendChild(header); | |
160 }, this); | |
161 | |
162 // If we have a small amount of content, don't show the resize handler. | |
163 // Otherwise, set the minHeight so that the percentage height of the | |
164 // topPanel is not too small. | |
165 if (testNames.length <= 4) | |
166 this.removeChild(this.querySelector('.resize-handle')); | |
167 else | |
168 topPanel.style.minHeight = '100px'; | |
169 }, | |
170 _appendResizeHandle: function() | |
171 { | |
172 var resizeHandle = document.createElement('div'); | |
173 resizeHandle.className = 'resize-handle'; | |
174 this.appendChild(resizeHandle); | |
175 | |
176 resizeHandle.addEventListener('mousedown', function(event) { | |
177 this._is_resizing = true; | |
178 event.preventDefault(); | |
179 }.bind(this)); | |
180 | |
181 var cancelResize = function(event) { this._is_resizing = false; }.bind(t
his); | |
182 this.addEventListener('mouseup', cancelResize); | |
183 document.body.addEventListener('mouseleave', cancelResize); | |
184 | |
185 this.addEventListener('mousemove', function(event) { | |
186 if (!this._is_resizing) | |
187 return; | |
188 var mouseY = event.clientY + document.body.scrollTop - this.offsetTo
p; | |
189 var percentage = 100 * mouseY / this.offsetHeight; | |
190 document.querySelector('.top-panel').style.maxHeight = percentage +
'%'; | |
191 }.bind(this)) | |
192 }, | |
193 _showResults: function(header, scrollInfoView) | |
194 { | |
195 if (!header) | |
196 return false; | |
197 | |
198 var activeHeader = this.querySelector('.active') | |
199 if (activeHeader) | |
200 activeHeader.classList.remove('active'); | |
201 header.classList.add('active'); | |
202 | |
203 var testName = this.currentTestName(); | |
204 this._flakinessData.src = ui.urlForEmbeddedFlakinessDashboard([testName]
); | |
205 | |
206 var bottomPanel = this.querySelector('.bottom-panel') | |
207 bottomPanel.innerHTML = ''; | |
208 bottomPanel.appendChild(this._delegate.contentForTest(testName)); | |
209 | |
210 var topPanel = this.querySelector('.top-panel'); | |
211 if (scrollInfoView) { | |
212 topPanel.scrollTop = header.offsetTop; | |
213 if (header.offsetTop - topPanel.scrollTop < header.offsetHeight) | |
214 topPanel.scrollTop = topPanel.scrollTop - header.offsetHeight; | |
215 } | |
216 | |
217 var resultsDetails = this.querySelectorAll('.results-detail'); | |
218 if (resultsDetails.length) | |
219 resultsDetails[0].show(); | |
220 setTimeout(function() { | |
221 Array.prototype.forEach.call(resultsDetails, function(resultsDetail)
{ | |
222 resultsDetail.show(); | |
223 }); | |
224 }, kResultsPrefetchDelayMS); | |
225 | |
226 return true; | |
227 }, | |
228 nextResult: function() | |
229 { | |
230 if (this.querySelector('.builder-selector').nextResult()) | |
231 return true; | |
232 return this.nextTest(); | |
233 }, | |
234 previousResult: function() | |
235 { | |
236 if (this.querySelector('.builder-selector').previousResult()) | |
237 return true; | |
238 return this.previousTest(); | |
239 }, | |
240 nextTest: function() | |
241 { | |
242 return this._showResults(this.querySelector('.active').nextSibling, true
); | |
243 }, | |
244 previousTest: function() | |
245 { | |
246 var succeeded = this._showResults(this.querySelector('.active').previous
Sibling, true); | |
247 if (succeeded) | |
248 this.querySelector('.builder-selector').lastResult(); | |
249 return succeeded; | |
250 }, | |
251 firstResult: function() | |
252 { | |
253 this._showResults(this.querySelector('h3'), true); | |
254 }, | |
255 currentTestName: function() | |
256 { | |
257 return this.querySelector('.active .non-link-title').textContent; | |
258 } | |
259 }); | |
260 | |
261 ui.results.BuilderSelector = base.extends('div', { | |
262 init: function(delegate, testName, resultsByBuilder) | |
263 { | |
264 this.className = 'builder-selector'; | |
265 this._delegate = delegate; | |
266 | |
267 var tabStrip = this.appendChild(document.createElement('ul')); | |
268 | |
269 Object.keys(resultsByBuilder).sort().forEach(function(builderName) { | |
270 var builderHash = base.underscoredBuilderName(builderName); | |
271 | |
272 var link = document.createElement('a'); | |
273 link.href = "#" + builderHash; | |
274 link.textContent = ui.displayNameForBuilder(builderName); | |
275 tabStrip.appendChild(document.createElement('li')).appendChild(link)
; | |
276 | |
277 var content = this._delegate.contentForTestAndBuilder(testName, buil
derName); | |
278 content.id = builderHash; | |
279 this.appendChild(content); | |
280 }, this); | |
281 | |
282 $(this).tabs(); | |
283 }, | |
284 nextResult: function() | |
285 { | |
286 var nextIndex = $(this).tabs('option', 'selected') + 1; | |
287 if (nextIndex >= $(this).tabs('length')) | |
288 return false | |
289 $(this).tabs('option', 'selected', nextIndex); | |
290 return true; | |
291 }, | |
292 previousResult: function() | |
293 { | |
294 var previousIndex = $(this).tabs('option', 'selected') - 1; | |
295 if (previousIndex < 0) | |
296 return false; | |
297 $(this).tabs('option', 'selected', previousIndex); | |
298 return true; | |
299 }, | |
300 firstResult: function() | |
301 { | |
302 $(this).tabs('option', 'selected', 0); | |
303 }, | |
304 lastResult: function() | |
305 { | |
306 $(this).tabs('option', 'selected', $(this).tabs('length') - 1); | |
307 } | |
308 }); | |
309 | |
310 ui.results.View = base.extends('div', { | |
311 init: function(delegate) | |
312 { | |
313 this.className = 'results-view'; | |
314 this._delegate = delegate; | |
315 }, | |
316 contentForTest: function(testName) | |
317 { | |
318 var builderSelector = new ui.results.BuilderSelector(this, testName, thi
s._resultsByTest[testName]); | |
319 $(builderSelector).bind('tabsselect', function(event, ui) { | |
320 // We will probably have pre-fetched the tab already, but we need to
make sure. | |
321 ui.panel.show(); | |
322 }); | |
323 return builderSelector; | |
324 }, | |
325 contentForTestAndBuilder: function(testName, builderName) | |
326 { | |
327 var failureInfo = results.failureInfoForTestAndBuilder(this._resultsByTe
st, testName, builderName); | |
328 return new ui.results.ResultsDetails(this, failureInfo); | |
329 }, | |
330 setResultsByTest: function(resultsByTest) | |
331 { | |
332 this.innerHTML = ''; | |
333 this._resultsByTest = resultsByTest; | |
334 this._testSelector = new ui.results.TestSelector(this, resultsByTest); | |
335 this.appendChild(this._testSelector); | |
336 }, | |
337 fetchResultsURLs: function(failureInfo) | |
338 { | |
339 return this._delegate.fetchResultsURLs(failureInfo); | |
340 }, | |
341 nextResult: function() | |
342 { | |
343 return this._testSelector.nextResult(); | |
344 }, | |
345 previousResult: function() | |
346 { | |
347 return this._testSelector.previousResult(); | |
348 }, | |
349 nextTest: function() | |
350 { | |
351 return this._testSelector.nextTest(); | |
352 }, | |
353 previousTest: function() | |
354 { | |
355 return this._testSelector.previousTest(); | |
356 }, | |
357 firstResult: function() | |
358 { | |
359 this._testSelector.firstResult() | |
360 }, | |
361 currentTestName: function() | |
362 { | |
363 return this._testSelector.currentTestName() | |
364 } | |
365 }); | |
366 | |
367 })(); | |
OLD | NEW |