Changeset 249443 in webkit
- Timestamp:
- Sep 3, 2019 2:52:16 PM (5 years ago)
- Location:
- trunk/Tools
- Files:
-
- 9 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/Tools/ChangeLog
r249432 r249443 1 2019-09-03 Jonathan Bedard <jbedard@apple.com> 2 3 results.webkit.org: Move legend into sidebar 4 https://bugs.webkit.org/show_bug.cgi?id=201258 5 6 Rubber-stamped by Aakash Jain. 7 8 * resultsdbpy/resultsdbpy/view/static/js/timeline.js: 9 (Legend): Make the legend vertical instead of horizontal, add ToolTip to dots in the legend. 10 * resultsdbpy/resultsdbpy/view/static/js/tooltip.css: Add left and right tooltip arrows. 11 * resultsdbpy/resultsdbpy/view/static/js/tooltip.js: 12 (isPointInElement): Make bound check include borders. 13 (_ToolTip.toString): Add left/right cases. 14 (_ToolTip.prototype.setByElement): Set the tooltip location given an element. 15 * resultsdbpy/resultsdbpy/view/templates/search.html: Put the legend into the sidebar. 16 * resultsdbpy/resultsdbpy/view/templates/suite_results.html: Ditto. 17 1 18 2019-09-03 Jonathan Bedard <jbedard@apple.com> 2 19 -
trunk/Tools/resultsdbpy/resultsdbpy/view/static/css/timeline.css
r247830 r249443 24 24 */ 25 25 26 .dot.time out {26 .dot.timedout { 27 27 background-color: var(--orangeLight); 28 28 } 29 29 30 .dot.crash {30 .dot.crashed { 31 31 background-color: var(--purpleLight); 32 32 } -
trunk/Tools/resultsdbpy/resultsdbpy/view/static/css/tooltip.css
r249285 r249443 44 44 } 45 45 46 .tooltip.arrow-left { 47 border-color: transparent transparent transparent #cccd; 48 } 49 .tooltip.arrow-right { 50 border-color: transparent #cccd transparent transparent; 51 } 52 46 53 .tooltip-content { 47 z-index: 50;54 z-index: var(--middleZIndex); 48 55 position: absolute; 49 56 -webkit-backdrop-filter: blur(10px) brightness(88%); … … 55 62 list-style: none; 56 63 max-width: 600px; 64 min-width: 30px; 65 min-height: 30px; 57 66 } -
trunk/Tools/resultsdbpy/resultsdbpy/view/static/js/drawer.js
r249432 r249443 75 75 if (element.style.display) 76 76 element.style.display = null; 77 else 77 else { 78 for (let node of element.children) { 79 if (node.classList.contains("list")) 80 setEnableRecursive(node, true); 81 } 78 82 element.style.display = 'block'; 83 } 79 84 } 80 85 } -
trunk/Tools/resultsdbpy/resultsdbpy/view/static/js/timeline.js
r249358 r249443 245 245 }, 246 246 onScaleLeave: (event, canvas) => { 247 if (!ToolTip.isIn({x: event.x, y: event.y})) 247 const scrollDelta = document.documentElement.scrollTop || document.body.scrollTop; 248 if (!ToolTip.isIn({x: event.x, y: event.y - scrollDelta})) 248 249 ToolTip.unset(); 249 250 }, … … 643 644 644 645 function onDotLeave(event, canvas) { 645 if (!ToolTip.isIn({x: event.pageX, y: event.pageY})) 646 const scrollDelta = document.documentElement.scrollTop || document.body.scrollTop; 647 if (!ToolTip.isIn({x: event.pageX, y: event.pageY - scrollDelta})) 646 648 ToolTip.unset(); 647 649 } … … 802 804 function Legend(callback=null, plural=false) { 803 805 let updateLabelEvents = new EventStream(); 804 let result = `<br> 805 <div class="lengend timeline"> 806 <div class="item"> 807 <div class="dot success"><div class="text">${TestResultsSymbolMap.success}</div></div> 808 ${LegendLabel( 809 updateLabelEvents, 810 plural ? 'No unexpected results' : 'Result expected', 811 plural ? 'All tests passed' : 'Test passed', 812 )} 813 </div> 814 <div class="item"> 815 <div class="dot failed"><div class="text">${TestResultsSymbolMap.failed}</div></div> 816 ${LegendLabel( 817 updateLabelEvents, 818 plural ? 'Some tests unexpectedly failed' : 'Unexpectedly failed', 819 plural ? 'Some tests failed' : 'Test failed', 820 )} 821 </div> 822 <div class="item"> 823 <div class="dot timeout"><div class="text">${TestResultsSymbolMap.timedout}</div></div> 824 ${LegendLabel( 825 updateLabelEvents, 826 plural ? 'Some tests unexpectedly timed out' : 'Unexpectedly timed out', 827 plural ? 'Some tests timed out' : 'Test timed out', 828 )} 829 </div> 830 <div class="item"> 831 <div class="dot crash"><div class="text">${TestResultsSymbolMap.crashed}</div></div> 832 ${LegendLabel( 833 updateLabelEvents, 834 plural ? 'Some tests unexpectedly crashed' : 'Unexpectedly crashed', 835 plural ? 'Some tests crashed' : 'Test crashed', 836 )} 837 </div> 838 <br> 806 const legendDetails = { 807 success: { 808 expected: plural ? 'No unexpected results' : 'Result expected', 809 unexpected: plural ? 'All tests passed' : 'Test passed', 810 }, 811 failed: { 812 expected: plural ? 'Some tests unexpectedly failed' : 'Unexpectedly failed', 813 unexpected: plural ? 'Some tests failed' : 'Test failed', 814 }, 815 timedout: { 816 expected: plural ? 'Some tests unexpectedly timed out' : 'Unexpectedly timed out', 817 unexpected: plural ? 'Some tests timed out' : 'Test timed out', 818 }, 819 crashed: { 820 expected: plural ? 'Some tests unexpectedly crashed' : 'Unexpectedly crashed', 821 unexpected: plural ? 'Some tests crashed' : 'Test crashed', 822 }, 823 }; 824 let result = `<div class="lengend horizontal"> 825 ${Object.keys(legendDetails).map((key) => { 826 const dot = REF.createRef({ 827 onElementMount: (element) => { 828 element.addEventListener('mouseleave', (event) => { 829 if (!ToolTip.isIn({x: event.x, y: event.y})) 830 ToolTip.unset(); 831 }); 832 element.onmouseover = (event) => { 833 if (!element.classList.contains('disabled')) 834 return; 835 ToolTip.setByElement( 836 `<div class="content"> 837 ${willFilterExpected ? legendDetails[key].expected : legendDetails[key].unexpected} 838 </div>`, 839 element, 840 {orientation: ToolTip.HORIZONTAL}, 841 ); 842 }; 843 } 844 }); 845 return `<div class="item"> 846 <div class="dot ${key}" ref="${dot}"><div class="text">${TestResultsSymbolMap[key]}</div></div> 847 ${LegendLabel(updateLabelEvents, legendDetails[key].expected, legendDetails[key].unexpected)} 848 </div>` 849 }).join('')} 839 850 </div>`; 840 851 … … 853 864 }); 854 865 855 result += `<div class="input" style="width:400px">856 <label >Filter expected results</label>866 result += `<div class="input"> 867 <label style="font-size: var(--tinySize); color: var(--boldInverseColor)">Filter expected results</label> 857 868 <label class="switch"> 858 869 <input type="checkbox"${willFilterExpected ? ' checked': ''} ref="${swtch}"> … … 862 873 } 863 874 864 return ` <div class="content">${result}</div><br>`;875 return `${result}`; 865 876 } 866 877 -
trunk/Tools/resultsdbpy/resultsdbpy/view/static/js/tooltip.js
r249111 r249443 29 29 return false; 30 30 const bounds = element.getBoundingClientRect(); 31 return point.x >= bounds.left && point.x <= bounds.right && point.y >= bounds.top && point.y <= bounds.bottom;31 return point.x >= bounds.left - 1 && point.x <= bounds.right + 1 && point.y >= bounds.top - 1 && point.y <= bounds.bottom + 1; 32 32 } 33 33 … … 37 37 this.arrow = null; 38 38 this.onArrowClick = null; 39 40 this.VERTICAL = 0; 41 this.HORIZONTAL = 1; 39 42 } 40 43 toString() { … … 44 47 onElementMount: (element) => { 45 48 element.addEventListener('mouseleave', (event) => { 49 if (element.style.display === 'none') 50 return; 46 51 if (!isPointInElement(self.arrow.element, event)) 47 52 this.unset() … … 52 57 DOM.inject(element, stateDiff.content); 53 58 element.style.display = null; 54 } 55 if (!state.content && !element.style.display) { 59 } else { 56 60 element.style.display = 'none'; 57 61 DOM.inject(element, ''); 58 62 } 63 59 64 if (stateDiff.points) { 60 65 element.style.left = '0px'; … … 68 73 const viewportHeight = Math.max(document.documentElement.clientHeight, window.innerHeight || 0); 69 74 70 // Make an effort to place the tooltip in the center of the viewport.71 75 let direction = 'down'; 72 let tipY = upperPoint.y - 8 - bounds.height;73 76 let point = upperPoint; 74 if (tipY < scrollDelta || tipY + bounds.height + (lowerPoint.y - upperPoint.y) / 2 < scrollDelta + viewportHeight / 2) { 75 direction = 'up'; 76 tipY = lowerPoint.y + 16; 77 point = lowerPoint; 77 78 if (upperPoint.y == lowerPoint.y) { 79 // Horizontal tooltip 80 const leftPoint = stateDiff.points.length > 1 && stateDiff.points[0].x > stateDiff.points[1].x ? stateDiff.points[1] : stateDiff.points[0]; 81 const rightPoint = stateDiff.points.length > 1 && stateDiff.points[1].x > stateDiff.points[0].x ? stateDiff.points[1] : stateDiff.points[0]; 82 83 direction = 'left'; 84 let tipX = leftPoint.x - 12 - bounds.width; 85 point = rightPoint; 86 if (tipX < 0 || tipX + bounds.width + (rightPoint.x - leftPoint.x) / 2 < viewportWitdh / 2) { 87 direction = 'right'; 88 tipX = rightPoint.x + 16; 89 point = rightPoint; 90 } 91 element.style.left = `${tipX}px`; 92 93 let tipY = point.y - bounds.height / 2; 94 if (tipY + bounds.height > scrollDelta + viewportHeight) 95 tipY = scrollDelta + viewportHeight - bounds.height; 96 if (tipY < 0) 97 tipY = 0; 98 element.style.top = `${tipY}px`; 99 } else { 100 // Make an effort to place the tooltip in the center of the viewport. 101 let tipY = upperPoint.y - 8 - bounds.height; 102 point = upperPoint; 103 if (tipY < scrollDelta || tipY + bounds.height + (lowerPoint.y - upperPoint.y) / 2 < scrollDelta + viewportHeight / 2) { 104 direction = 'up'; 105 tipY = lowerPoint.y + 16; 106 point = lowerPoint; 107 } 108 element.style.top = `${tipY}px`; 109 110 let tipX = point.x - bounds.width / 2; 111 if (tipX + bounds.width > viewportWitdh) 112 tipX = viewportWitdh - bounds.width; 113 if (tipX < 0) 114 tipX = 0; 115 element.style.left = `${tipX}px`; 78 116 } 79 element.style.top = `${tipY}px`;80 81 let tipX = point.x - bounds.width / 2;82 if (tipX + bounds.width > viewportWitdh)83 tipX = viewportWitdh - bounds.width;84 if (tipX < 0)85 tipX = 0;86 element.style.left = `${tipX}px`;87 117 88 118 self.arrow.setState({direction: direction, location: point}); … … 94 124 onElementMount: (element) => { 95 125 element.addEventListener('mouseleave', (event) => { 96 if (!isPointInElement(self.ref.element, event)) 126 if (element.style.display === 'none') 127 return; 128 if (!isPointInElement(self.ref.element, event) && !isPointInElement(element, event)) 97 129 this.unset() 98 130 }); 99 131 }, 100 onStateUpdate: (element, stateDiff , state) => {101 if (!state .direction || !state.location) {132 onStateUpdate: (element, stateDiff) => { 133 if (!stateDiff.direction || !stateDiff.location) { 102 134 element.style.display = 'none'; 103 135 element.onclick = null; … … 114 146 } 115 147 116 element.classList = [`tooltip arrow-${state.direction}`]; 117 element.style.left = `${state.location.x - 15}px`; 118 if (state.direction == 'down') 119 element.style.top = `${state.location.y - 8}px`; 120 else 121 element.style.top = `${state.location.y - 13}px`; 148 element.classList = [`tooltip arrow-${stateDiff.direction}`]; 149 150 if (stateDiff.direction == 'down') { 151 element.style.left = `${stateDiff.location.x - 15}px`; 152 element.style.top = `${stateDiff.location.y - 8}px`; 153 } else if (stateDiff.direction == 'left') { 154 element.style.left = `${stateDiff.location.x - 30}px`; 155 element.style.top = `${stateDiff.location.y - 15}px`; 156 } else if (stateDiff.direction == 'right') { 157 element.style.left = `${stateDiff.location.x - 13}px`; 158 element.style.top = `${stateDiff.location.y - 15}px`; 159 } else { 160 element.style.left = `${stateDiff.location.x - 15}px`; 161 element.style.top = `${stateDiff.location.y - 13}px`; 162 } 122 163 element.style.display = null; 123 164 }, … … 140 181 this.ref.setState({content: content, points: points}); 141 182 } 183 setByElement(content, element, options) { 184 const bound = element.getBoundingClientRect(); 185 const orientation = options.orientation ? options.orientation : this.VERTICAL; 186 const onArrowClick = options.onArrowClick ? options.onArrowClick : null; 187 188 // Manage the scroll delta 189 let scrollDelta = 0; 190 if (window.getComputedStyle(element.offsetParent).getPropertyValue('position') == 'fixed') 191 scrollDelta = document.documentElement.scrollTop || document.body.scrollTop; 192 193 if (options.orientation) { 194 this.set(content, [ 195 {x: bound.right, y: (bound.top + bound.bottom) / 2 + scrollDelta}, 196 {x: bound.left, y: (bound.top + bound.bottom) / 2 + scrollDelta}, 197 ], onArrowClick); 198 } else { 199 this.set(content, [ 200 {x: (bound.right + bound.left) / 2, y: bound.top + scrollDelta}, 201 {x: (bound.right + bound.left) / 2, y: bound.bottom + scrollDelta}, 202 ], onArrowClick); 203 } 204 } 142 205 unset() { 143 206 if (this.ref) -
trunk/Tools/resultsdbpy/resultsdbpy/view/static/library/css/webkit.css
r249213 r249443 91 91 --sectionPaddingSize: 12px 24px; 92 92 --formLabelPadding: 14px; 93 --middleZIndex: 50; 93 94 --topZIndex: 100; 94 95 --boldInverseColor: var(--black); … … 923 924 -webkit-backdrop-filter: blur(5px) brightness(88%); 924 925 backdrop-filter: blur(5px) brightness(88%); 925 z-index: var(--topZIndex);926 z-index: 50; 926 927 right: 0; 927 928 } -
trunk/Tools/resultsdbpy/resultsdbpy/view/templates/search.html
r249358 r249443 129 129 130 130 if (diff.children) 131 DOM.inject(element, Legend(() => { 132 self.ref.state.children.forEach((child) => { 133 child.timeline.update(); 134 }); 135 }, false) + diff.children.map(renderChild).join('')); 131 DOM.inject(element, diff.children.map(renderChild).join('')); 136 132 if (diff.prepending) { 137 133 diff.prepending.forEach(child => { … … 228 224 `${ToolTip} 229 225 ${Drawer([ 226 Legend(() => { 227 view.children.forEach((child) => { 228 child.timeline.update(); 229 }); 230 }, false), 230 231 LimitSlider(() => {view.reload()}), 231 232 BranchSelector(() => { -
trunk/Tools/resultsdbpy/resultsdbpy/view/templates/suite_results.html
r249358 r249443 40 40 41 41 const DEFAULT_LIMIT = 100; 42 const SUITES = JSON.parse('{{ suites|safe }}'); 42 const SUITES = JSON.parse('{{ suites|safe }}'); 43 43 44 44 class MainView { … … 144 144 render(suites) { 145 145 let children = this.children; 146 return Legend(() => { 147 for (let suite in children) { 148 children[suite].update(); 149 } 150 }, true) + suites.map(suite => { 146 return suites.map(suite => { 151 147 return `<div class="section"> 152 148 <div class="header"> … … 172 168 DOM.inject(document.getElementById('app'), `${ToolTip} 173 169 ${Drawer([ 170 Legend(() => { 171 for (let suite in view.children) { 172 view.children[suite].update(); 173 } 174 }, true), 174 175 LimitSlider(() => {view.reload()}), 175 176 BranchSelector(() => {
Note: See TracChangeset
for help on using the changeset viewer.