Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(136)

Side by Side Diff: third_party/WebKit/Source/devtools/front_end/ui/UIUtils.js

Issue 2466123002: DevTools: reformat front-end code to match chromium style. (Closed)
Patch Set: all done Created 4 years, 1 month ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
1 /* 1 /*
2 * Copyright (C) 2011 Google Inc. All rights reserved. 2 * Copyright (C) 2011 Google Inc. All rights reserved.
3 * Copyright (C) 2006, 2007, 2008 Apple Inc. All rights reserved. 3 * Copyright (C) 2006, 2007, 2008 Apple Inc. All rights reserved.
4 * Copyright (C) 2007 Matt Lilek (pewtermoose@gmail.com). 4 * Copyright (C) 2007 Matt Lilek (pewtermoose@gmail.com).
5 * Copyright (C) 2009 Joseph Pecoraro 5 * Copyright (C) 2009 Joseph Pecoraro
6 * 6 *
7 * Redistribution and use in source and binary forms, with or without 7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions 8 * modification, are permitted provided that the following conditions
9 * are met: 9 * are met:
10 * 10 *
(...skipping 10 matching lines...) Expand all
21 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 21 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
22 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 22 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
23 * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY 23 * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
24 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 24 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
25 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 25 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
26 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 26 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
27 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 27 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
28 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 28 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
29 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30 */ 30 */
31 31 WebInspector.highlightedSearchResultClassName = 'highlighted-search-result';
32 WebInspector.highlightedSearchResultClassName = "highlighted-search-result"; 32 WebInspector.highlightedCurrentSearchResultClassName = 'current-search-result';
33 WebInspector.highlightedCurrentSearchResultClassName = "current-search-result";
34 33
35 /** 34 /**
36 * @param {!Element} element 35 * @param {!Element} element
37 * @param {?function(!MouseEvent): boolean} elementDragStart 36 * @param {?function(!MouseEvent): boolean} elementDragStart
38 * @param {function(!MouseEvent)} elementDrag 37 * @param {function(!MouseEvent)} elementDrag
39 * @param {?function(!MouseEvent)} elementDragEnd 38 * @param {?function(!MouseEvent)} elementDragEnd
40 * @param {string} cursor 39 * @param {string} cursor
41 * @param {?string=} hoverCursor 40 * @param {?string=} hoverCursor
42 * @param {number=} startDelay 41 * @param {number=} startDelay
43 */ 42 */
44 WebInspector.installDragHandle = function(element, elementDragStart, elementDrag , elementDragEnd, cursor, hoverCursor, startDelay) 43 WebInspector.installDragHandle = function(
45 { 44 element, elementDragStart, elementDrag, elementDragEnd, cursor, hoverCursor, startDelay) {
46 /** 45 /**
47 * @param {!Event} event 46 * @param {!Event} event
48 */ 47 */
49 function onMouseDown(event) 48 function onMouseDown(event) {
50 { 49 var dragHandler = new WebInspector.DragHandler();
51 var dragHandler = new WebInspector.DragHandler(); 50 var dragStart = dragHandler.elementDragStart.bind(
52 var dragStart = dragHandler.elementDragStart.bind(dragHandler, element, elementDragStart, elementDrag, elementDragEnd, cursor, event); 51 dragHandler, element, elementDragStart, elementDrag, elementDragEnd, cur sor, event);
53 if (startDelay) 52 if (startDelay)
54 startTimer = setTimeout(dragStart, startDelay); 53 startTimer = setTimeout(dragStart, startDelay);
55 else 54 else
56 dragStart(); 55 dragStart();
57 } 56 }
58 57
59 function onMouseUp() 58 function onMouseUp() {
60 { 59 if (startTimer)
61 if (startTimer) 60 clearTimeout(startTimer);
62 clearTimeout(startTimer); 61 startTimer = null;
63 startTimer = null; 62 }
64 }
65 63
66 var startTimer; 64 var startTimer;
67 element.addEventListener("mousedown", onMouseDown, false); 65 element.addEventListener('mousedown', onMouseDown, false);
68 if (startDelay) 66 if (startDelay)
69 element.addEventListener("mouseup", onMouseUp, false); 67 element.addEventListener('mouseup', onMouseUp, false);
70 if (hoverCursor !== null) 68 if (hoverCursor !== null)
71 element.style.cursor = hoverCursor || cursor; 69 element.style.cursor = hoverCursor || cursor;
72 }; 70 };
73 71
74 /** 72 /**
75 * @param {!Element} targetElement 73 * @param {!Element} targetElement
76 * @param {?function(!MouseEvent):boolean} elementDragStart 74 * @param {?function(!MouseEvent):boolean} elementDragStart
77 * @param {function(!MouseEvent)} elementDrag 75 * @param {function(!MouseEvent)} elementDrag
78 * @param {?function(!MouseEvent)} elementDragEnd 76 * @param {?function(!MouseEvent)} elementDragEnd
79 * @param {string} cursor 77 * @param {string} cursor
80 * @param {!Event} event 78 * @param {!Event} event
81 */ 79 */
82 WebInspector.elementDragStart = function(targetElement, elementDragStart, elemen tDrag, elementDragEnd, cursor, event) 80 WebInspector.elementDragStart = function(targetElement, elementDragStart, elemen tDrag, elementDragEnd, cursor, event) {
83 { 81 var dragHandler = new WebInspector.DragHandler();
84 var dragHandler = new WebInspector.DragHandler(); 82 dragHandler.elementDragStart(targetElement, elementDragStart, elementDrag, ele mentDragEnd, cursor, event);
85 dragHandler.elementDragStart(targetElement, elementDragStart, elementDrag, e lementDragEnd, cursor, event);
86 }; 83 };
87 84
88 /** 85 /**
89 * @constructor 86 * @unrestricted
90 */ 87 */
91 WebInspector.DragHandler = function() 88 WebInspector.DragHandler = class {
92 { 89 constructor() {
93 this._elementDragMove = this._elementDragMove.bind(this); 90 this._elementDragMove = this._elementDragMove.bind(this);
94 this._elementDragEnd = this._elementDragEnd.bind(this); 91 this._elementDragEnd = this._elementDragEnd.bind(this);
95 this._mouseOutWhileDragging = this._mouseOutWhileDragging.bind(this); 92 this._mouseOutWhileDragging = this._mouseOutWhileDragging.bind(this);
96 }; 93 }
97 94
98 WebInspector.DragHandler._glassPaneUsageCount = 0; 95 _createGlassPane() {
96 this._glassPaneInUse = true;
97 if (!WebInspector.DragHandler._glassPaneUsageCount++)
98 WebInspector.DragHandler._glassPane = new WebInspector.GlassPane(WebInspec tor.DragHandler._documentForMouseOut);
99 }
99 100
100 WebInspector.DragHandler.prototype = { 101 _disposeGlassPane() {
101 _createGlassPane: function() 102 if (!this._glassPaneInUse)
102 { 103 return;
103 this._glassPaneInUse = true; 104 this._glassPaneInUse = false;
104 if (!WebInspector.DragHandler._glassPaneUsageCount++) 105 if (--WebInspector.DragHandler._glassPaneUsageCount)
105 WebInspector.DragHandler._glassPane = new WebInspector.GlassPane(Web Inspector.DragHandler._documentForMouseOut); 106 return;
106 }, 107 WebInspector.DragHandler._glassPane.dispose();
108 delete WebInspector.DragHandler._glassPane;
109 delete WebInspector.DragHandler._documentForMouseOut;
110 }
107 111
108 _disposeGlassPane: function() 112 /**
109 { 113 * @param {!Element} targetElement
110 if (!this._glassPaneInUse) 114 * @param {?function(!MouseEvent):boolean} elementDragStart
111 return; 115 * @param {function(!MouseEvent)} elementDrag
112 this._glassPaneInUse = false; 116 * @param {?function(!MouseEvent)} elementDragEnd
113 if (--WebInspector.DragHandler._glassPaneUsageCount) 117 * @param {string} cursor
114 return; 118 * @param {!Event} event
115 WebInspector.DragHandler._glassPane.dispose(); 119 */
116 delete WebInspector.DragHandler._glassPane; 120 elementDragStart(targetElement, elementDragStart, elementDrag, elementDragEnd, cursor, event) {
117 delete WebInspector.DragHandler._documentForMouseOut;
118 }
119 };
120
121 /**
122 * @param {!Element} targetElement
123 * @param {?function(!MouseEvent):boolean} elementDragStart
124 * @param {function(!MouseEvent)} elementDrag
125 * @param {?function(!MouseEvent)} elementDragEnd
126 * @param {string} cursor
127 * @param {!Event} event
128 */
129 WebInspector.DragHandler.prototype.elementDragStart = function(targetElement, el ementDragStart, elementDrag, elementDragEnd, cursor, event)
130 {
131 // Only drag upon left button. Right will likely cause a context menu. So wi ll ctrl-click on mac. 121 // Only drag upon left button. Right will likely cause a context menu. So wi ll ctrl-click on mac.
132 if (event.button || (WebInspector.isMac() && event.ctrlKey)) 122 if (event.button || (WebInspector.isMac() && event.ctrlKey))
133 return; 123 return;
134 124
135 if (this._elementDraggingEventListener) 125 if (this._elementDraggingEventListener)
136 return; 126 return;
137 127
138 if (elementDragStart && !elementDragStart(/** @type {!MouseEvent} */ (event) )) 128 if (elementDragStart && !elementDragStart(/** @type {!MouseEvent} */ (event) ))
139 return; 129 return;
140 130
141 var targetDocument = event.target.ownerDocument; 131 var targetDocument = event.target.ownerDocument;
142 this._elementDraggingEventListener = elementDrag; 132 this._elementDraggingEventListener = elementDrag;
143 this._elementEndDraggingEventListener = elementDragEnd; 133 this._elementEndDraggingEventListener = elementDragEnd;
144 console.assert((WebInspector.DragHandler._documentForMouseOut || targetDocum ent) === targetDocument, 134 console.assert(
145 "Dragging on multiple documents."); 135 (WebInspector.DragHandler._documentForMouseOut || targetDocument) === ta rgetDocument,
136 'Dragging on multiple documents.');
146 WebInspector.DragHandler._documentForMouseOut = targetDocument; 137 WebInspector.DragHandler._documentForMouseOut = targetDocument;
147 this._dragEventsTargetDocument = targetDocument; 138 this._dragEventsTargetDocument = targetDocument;
148 this._dragEventsTargetDocumentTop = targetDocument.defaultView.top.document; 139 this._dragEventsTargetDocumentTop = targetDocument.defaultView.top.document;
149 140
150 targetDocument.addEventListener("mousemove", this._elementDragMove, true); 141 targetDocument.addEventListener('mousemove', this._elementDragMove, true);
151 targetDocument.addEventListener("mouseup", this._elementDragEnd, true); 142 targetDocument.addEventListener('mouseup', this._elementDragEnd, true);
152 targetDocument.addEventListener("mouseout", this._mouseOutWhileDragging, tru e); 143 targetDocument.addEventListener('mouseout', this._mouseOutWhileDragging, tru e);
153 if (targetDocument !== this._dragEventsTargetDocumentTop) 144 if (targetDocument !== this._dragEventsTargetDocumentTop)
154 this._dragEventsTargetDocumentTop.addEventListener("mouseup", this._elem entDragEnd, true); 145 this._dragEventsTargetDocumentTop.addEventListener('mouseup', this._elemen tDragEnd, true);
155 146
156 if (typeof cursor === "string") { 147 if (typeof cursor === 'string') {
157 this._restoreCursorAfterDrag = restoreCursor.bind(this, targetElement.st yle.cursor); 148 this._restoreCursorAfterDrag = restoreCursor.bind(this, targetElement.styl e.cursor);
158 targetElement.style.cursor = cursor; 149 targetElement.style.cursor = cursor;
159 targetDocument.body.style.cursor = cursor; 150 targetDocument.body.style.cursor = cursor;
160 } 151 }
161 /** 152 /**
162 * @param {string} oldCursor 153 * @param {string} oldCursor
163 * @this {WebInspector.DragHandler} 154 * @this {WebInspector.DragHandler}
164 */ 155 */
165 function restoreCursor(oldCursor) 156 function restoreCursor(oldCursor) {
166 { 157 targetDocument.body.style.removeProperty('cursor');
167 targetDocument.body.style.removeProperty("cursor"); 158 targetElement.style.cursor = oldCursor;
168 targetElement.style.cursor = oldCursor; 159 this._restoreCursorAfterDrag = null;
169 this._restoreCursorAfterDrag = null;
170 } 160 }
171 event.preventDefault(); 161 event.preventDefault();
172 }; 162 }
173 163
174 WebInspector.DragHandler.prototype._mouseOutWhileDragging = function() 164 _mouseOutWhileDragging() {
175 {
176 this._unregisterMouseOutWhileDragging(); 165 this._unregisterMouseOutWhileDragging();
177 this._createGlassPane(); 166 this._createGlassPane();
178 }; 167 }
179 168
180 WebInspector.DragHandler.prototype._unregisterMouseOutWhileDragging = function() 169 _unregisterMouseOutWhileDragging() {
181 {
182 if (!WebInspector.DragHandler._documentForMouseOut) 170 if (!WebInspector.DragHandler._documentForMouseOut)
183 return; 171 return;
184 WebInspector.DragHandler._documentForMouseOut.removeEventListener("mouseout" , this._mouseOutWhileDragging, true); 172 WebInspector.DragHandler._documentForMouseOut.removeEventListener('mouseout' , this._mouseOutWhileDragging, true);
185 }; 173 }
186 174
187 WebInspector.DragHandler.prototype._unregisterDragEvents = function() 175 _unregisterDragEvents() {
188 {
189 if (!this._dragEventsTargetDocument) 176 if (!this._dragEventsTargetDocument)
190 return; 177 return;
191 this._dragEventsTargetDocument.removeEventListener("mousemove", this._elemen tDragMove, true); 178 this._dragEventsTargetDocument.removeEventListener('mousemove', this._elemen tDragMove, true);
192 this._dragEventsTargetDocument.removeEventListener("mouseup", this._elementD ragEnd, true); 179 this._dragEventsTargetDocument.removeEventListener('mouseup', this._elementD ragEnd, true);
193 if (this._dragEventsTargetDocument !== this._dragEventsTargetDocumentTop) 180 if (this._dragEventsTargetDocument !== this._dragEventsTargetDocumentTop)
194 this._dragEventsTargetDocumentTop.removeEventListener("mouseup", this._e lementDragEnd, true); 181 this._dragEventsTargetDocumentTop.removeEventListener('mouseup', this._ele mentDragEnd, true);
195 delete this._dragEventsTargetDocument; 182 delete this._dragEventsTargetDocument;
196 delete this._dragEventsTargetDocumentTop; 183 delete this._dragEventsTargetDocumentTop;
197 }; 184 }
198 185
199 /** 186 /**
200 * @param {!Event} event 187 * @param {!Event} event
201 */ 188 */
202 WebInspector.DragHandler.prototype._elementDragMove = function(event) 189 _elementDragMove(event) {
203 {
204 if (event.buttons !== 1) { 190 if (event.buttons !== 1) {
205 this._elementDragEnd(event); 191 this._elementDragEnd(event);
206 return; 192 return;
207 } 193 }
208 if (this._elementDraggingEventListener(/** @type {!MouseEvent} */ (event))) 194 if (this._elementDraggingEventListener(/** @type {!MouseEvent} */ (event)))
209 this._cancelDragEvents(event); 195 this._cancelDragEvents(event);
210 }; 196 }
211 197
212 /** 198 /**
213 * @param {!Event} event 199 * @param {!Event} event
214 */ 200 */
215 WebInspector.DragHandler.prototype._cancelDragEvents = function(event) 201 _cancelDragEvents(event) {
216 {
217 this._unregisterDragEvents(); 202 this._unregisterDragEvents();
218 this._unregisterMouseOutWhileDragging(); 203 this._unregisterMouseOutWhileDragging();
219 204
220 if (this._restoreCursorAfterDrag) 205 if (this._restoreCursorAfterDrag)
221 this._restoreCursorAfterDrag(); 206 this._restoreCursorAfterDrag();
222 207
223 this._disposeGlassPane(); 208 this._disposeGlassPane();
224 209
225 delete this._elementDraggingEventListener; 210 delete this._elementDraggingEventListener;
226 delete this._elementEndDraggingEventListener; 211 delete this._elementEndDraggingEventListener;
227 }; 212 }
228 213
229 /** 214 /**
230 * @param {!Event} event 215 * @param {!Event} event
231 */ 216 */
232 WebInspector.DragHandler.prototype._elementDragEnd = function(event) 217 _elementDragEnd(event) {
233 {
234 var elementDragEnd = this._elementEndDraggingEventListener; 218 var elementDragEnd = this._elementEndDraggingEventListener;
235 this._cancelDragEvents(/** @type {!MouseEvent} */ (event)); 219 this._cancelDragEvents(/** @type {!MouseEvent} */ (event));
236 event.preventDefault(); 220 event.preventDefault();
237 if (elementDragEnd) 221 if (elementDragEnd)
238 elementDragEnd(/** @type {!MouseEvent} */ (event)); 222 elementDragEnd(/** @type {!MouseEvent} */ (event));
223 }
239 }; 224 };
240 225
226 WebInspector.DragHandler._glassPaneUsageCount = 0;
227
241 /** 228 /**
242 * @param {!Element} element 229 * @param {!Element} element
243 * @param {function(number, number, !MouseEvent): boolean} elementDragStart 230 * @param {function(number, number, !MouseEvent): boolean} elementDragStart
244 * @param {function(number, number)} elementDrag 231 * @param {function(number, number)} elementDrag
245 * @param {function(number, number)} elementDragEnd 232 * @param {function(number, number)} elementDragEnd
246 * @param {string} cursor 233 * @param {string} cursor
247 * @param {?string=} hoverCursor 234 * @param {?string=} hoverCursor
248 * @param {number=} startDelay 235 * @param {number=} startDelay
249 * @param {number=} friction 236 * @param {number=} friction
250 */ 237 */
251 WebInspector.installInertialDragHandle = function(element, elementDragStart, ele mentDrag, elementDragEnd, cursor, hoverCursor, startDelay, friction) 238 WebInspector.installInertialDragHandle = function(
252 { 239 element, elementDragStart, elementDrag, elementDragEnd, cursor, hoverCursor, startDelay, friction) {
253 WebInspector.installDragHandle(element, drag.bind(null, elementDragStart), d rag.bind(null, elementDrag), dragEnd, cursor, hoverCursor, startDelay); 240 WebInspector.installDragHandle(
254 if (typeof friction !== "number") 241 element, drag.bind(null, elementDragStart), drag.bind(null, elementDrag), dragEnd, cursor, hoverCursor,
255 friction = 50; 242 startDelay);
256 var lastX; 243 if (typeof friction !== 'number')
257 var lastY; 244 friction = 50;
258 var lastTime; 245 var lastX;
259 var velocityX; 246 var lastY;
260 var velocityY; 247 var lastTime;
261 var holding = false; 248 var velocityX;
249 var velocityY;
250 var holding = false;
262 251
263 /** 252 /**
264 * @param {function(number, number, !MouseEvent): boolean} callback 253 * @param {function(number, number, !MouseEvent): boolean} callback
265 * @param {!MouseEvent} event 254 * @param {!MouseEvent} event
266 * @return {boolean} 255 * @return {boolean}
267 */ 256 */
268 function drag(callback, event) 257 function drag(callback, event) {
269 { 258 lastTime = window.performance.now();
270 lastTime = window.performance.now(); 259 lastX = event.pageX;
271 lastX = event.pageX; 260 lastY = event.pageY;
272 lastY = event.pageY; 261 holding = true;
273 holding = true; 262 return callback(lastX, lastY, event);
274 return callback(lastX, lastY, event); 263 }
264
265 /**
266 * @param {!MouseEvent} event
267 */
268 function dragEnd(event) {
269 var now = window.performance.now();
270 var duration = now - lastTime || 1;
271 const maxVelocity = 4; // 4px per millisecond.
272 velocityX = Number.constrain((event.pageX - lastX) / duration, -maxVelocity, maxVelocity);
273 velocityY = Number.constrain((event.pageY - lastY) / duration, -maxVelocity, maxVelocity);
274 lastX = event.pageX;
275 lastY = event.pageY;
276 lastTime = now;
277 holding = false;
278 animationStep();
279 }
280
281 function animationStep() {
282 var v2 = velocityX * velocityX + velocityY * velocityY;
283 if (v2 < 0.001 || holding) {
284 elementDragEnd(lastX, lastY);
285 return;
275 } 286 }
276 287 element.window().requestAnimationFrame(animationStep);
277 /** 288 var now = window.performance.now();
278 * @param {!MouseEvent} event 289 var duration = now - lastTime;
279 */ 290 if (!duration)
280 function dragEnd(event) 291 return;
281 { 292 lastTime = now;
282 var now = window.performance.now(); 293 lastX += velocityX * duration;
283 var duration = now - lastTime || 1; 294 lastY += velocityY * duration;
284 const maxVelocity = 4; // 4px per millisecond. 295 var k = Math.pow(1 / (1 + friction), duration / 1000);
285 velocityX = Number.constrain((event.pageX - lastX) / duration, -maxVeloc ity, maxVelocity); 296 velocityX *= k;
286 velocityY = Number.constrain((event.pageY - lastY) / duration, -maxVeloc ity, maxVelocity); 297 velocityY *= k;
287 lastX = event.pageX; 298 elementDrag(lastX, lastY);
288 lastY = event.pageY; 299 }
289 lastTime = now;
290 holding = false;
291 animationStep();
292 }
293
294 function animationStep()
295 {
296 var v2 = velocityX * velocityX + velocityY * velocityY;
297 if (v2 < 0.001 || holding) {
298 elementDragEnd(lastX, lastY);
299 return;
300 }
301 element.window().requestAnimationFrame(animationStep);
302 var now = window.performance.now();
303 var duration = now - lastTime;
304 if (!duration)
305 return;
306 lastTime = now;
307 lastX += velocityX * duration;
308 lastY += velocityY * duration;
309 var k = Math.pow(1 / (1 + friction), duration / 1000);
310 velocityX *= k;
311 velocityY *= k;
312 elementDrag(lastX, lastY);
313 }
314 }; 300 };
315 301
316 /** 302 /**
317 * @constructor 303 * @unrestricted
318 * @param {!Document} document
319 * @param {boolean=} dimmed
320 */ 304 */
321 WebInspector.GlassPane = function(document, dimmed) 305 WebInspector.GlassPane = class {
322 { 306 /**
323 this.element = createElement("div"); 307 * @param {!Document} document
324 var background = dimmed ? "rgba(255, 255, 255, 0.5)" : "transparent"; 308 * @param {boolean=} dimmed
325 this._zIndex = WebInspector._glassPane ? WebInspector._glassPane._zIndex + 1 000 : 3000; // Deliberately starts with 3000 to hide other z-indexed elements be low. 309 */
326 this.element.style.cssText = "position:absolute;top:0;bottom:0;left:0;right: 0;background-color:" + background + ";z-index:" + this._zIndex + ";overflow:hidd en;"; 310 constructor(document, dimmed) {
311 this.element = createElement('div');
312 var background = dimmed ? 'rgba(255, 255, 255, 0.5)' : 'transparent';
313 this._zIndex = WebInspector._glassPane ?
314 WebInspector._glassPane._zIndex + 1000 :
315 3000; // Deliberately starts with 3000 to hide other z-indexed elements below.
316 this.element.style.cssText = 'position:absolute;top:0;bottom:0;left:0;right: 0;background-color:' + background +
317 ';z-index:' + this._zIndex + ';overflow:hidden;';
327 document.body.appendChild(this.element); 318 document.body.appendChild(this.element);
328 WebInspector._glassPane = this; 319 WebInspector._glassPane = this;
329 // TODO(dgozman): disallow focus outside of glass pane? 320 // TODO(dgozman): disallow focus outside of glass pane?
330 }; 321 }
331 322
332 WebInspector.GlassPane.prototype = { 323 dispose() {
333 dispose: function() 324 delete WebInspector._glassPane;
334 { 325 this.element.remove();
335 delete WebInspector._glassPane; 326 }
336 this.element.remove();
337 }
338 }; 327 };
339 328
340 /** @type {!WebInspector.GlassPane|undefined} */ 329 /** @type {!WebInspector.GlassPane|undefined} */
341 WebInspector._glassPane; 330 WebInspector._glassPane;
342 331
343 /** 332 /**
344 * @param {?Node=} node 333 * @param {?Node=} node
345 * @return {boolean} 334 * @return {boolean}
346 */ 335 */
347 WebInspector.isBeingEdited = function(node) 336 WebInspector.isBeingEdited = function(node) {
348 { 337 if (!node || node.nodeType !== Node.ELEMENT_NODE)
349 if (!node || node.nodeType !== Node.ELEMENT_NODE) 338 return false;
350 return false; 339 var element = /** {!Element} */ (node);
351 var element = /** {!Element} */ (node); 340 if (element.classList.contains('text-prompt') || element.nodeName === 'INPUT' || element.nodeName === 'TEXTAREA')
352 if (element.classList.contains("text-prompt") || element.nodeName === "INPUT " || element.nodeName === "TEXTAREA") 341 return true;
353 return true;
354 342
355 if (!WebInspector.__editingCount) 343 if (!WebInspector.__editingCount)
356 return false; 344 return false;
357 345
358 while (element) { 346 while (element) {
359 if (element.__editing) 347 if (element.__editing)
360 return true; 348 return true;
361 element = element.parentElementOrShadowHost(); 349 element = element.parentElementOrShadowHost();
362 } 350 }
363 return false; 351 return false;
364 }; 352 };
365 353
366 /** 354 /**
367 * @return {boolean} 355 * @return {boolean}
368 * @suppressGlobalPropertiesCheck 356 * @suppressGlobalPropertiesCheck
369 */ 357 */
370 WebInspector.isEditing = function() 358 WebInspector.isEditing = function() {
371 { 359 if (WebInspector.__editingCount)
372 if (WebInspector.__editingCount) 360 return true;
373 return true;
374 361
375 var focused = document.deepActiveElement(); 362 var focused = document.deepActiveElement();
376 if (!focused) 363 if (!focused)
377 return false; 364 return false;
378 return focused.classList.contains("text-prompt") || focused.nodeName === "IN PUT" || focused.nodeName === "TEXTAREA"; 365 return focused.classList.contains('text-prompt') || focused.nodeName === 'INPU T' || focused.nodeName === 'TEXTAREA';
379 }; 366 };
380 367
381 /** 368 /**
382 * @param {!Element} element 369 * @param {!Element} element
383 * @param {boolean} value 370 * @param {boolean} value
384 * @return {boolean} 371 * @return {boolean}
385 */ 372 */
386 WebInspector.markBeingEdited = function(element, value) 373 WebInspector.markBeingEdited = function(element, value) {
387 { 374 if (value) {
388 if (value) { 375 if (element.__editing)
389 if (element.__editing) 376 return false;
390 return false; 377 element.classList.add('being-edited');
391 element.classList.add("being-edited"); 378 element.__editing = true;
392 element.__editing = true; 379 WebInspector.__editingCount = (WebInspector.__editingCount || 0) + 1;
393 WebInspector.__editingCount = (WebInspector.__editingCount || 0) + 1; 380 } else {
394 } else { 381 if (!element.__editing)
395 if (!element.__editing) 382 return false;
396 return false; 383 element.classList.remove('being-edited');
397 element.classList.remove("being-edited"); 384 delete element.__editing;
398 delete element.__editing; 385 --WebInspector.__editingCount;
399 --WebInspector.__editingCount; 386 }
400 } 387 return true;
401 return true;
402 }; 388 };
403 389
404 WebInspector.CSSNumberRegex = /^(-?(?:\d+(?:\.\d+)?|\.\d+))$/; 390 WebInspector.CSSNumberRegex = /^(-?(?:\d+(?:\.\d+)?|\.\d+))$/;
405 391
406 WebInspector.StyleValueDelimiters = " \xA0\t\n\"':;,/()"; 392 WebInspector.StyleValueDelimiters = ' \xA0\t\n"\':;,/()';
407
408 393
409 /** 394 /**
410 * @param {!Event} event 395 * @param {!Event} event
411 * @return {?string} 396 * @return {?string}
412 */ 397 */
413 WebInspector._valueModificationDirection = function(event) 398 WebInspector._valueModificationDirection = function(event) {
414 { 399 var direction = null;
415 var direction = null; 400 if (event.type === 'mousewheel') {
416 if (event.type === "mousewheel") { 401 // When shift is pressed while spinning mousewheel, delta comes as wheelDelt aX.
417 // When shift is pressed while spinning mousewheel, delta comes as wheel DeltaX. 402 if (event.wheelDeltaY > 0 || event.wheelDeltaX > 0)
418 if (event.wheelDeltaY > 0 || event.wheelDeltaX > 0) 403 direction = 'Up';
419 direction = "Up"; 404 else if (event.wheelDeltaY < 0 || event.wheelDeltaX < 0)
420 else if (event.wheelDeltaY < 0 || event.wheelDeltaX < 0) 405 direction = 'Down';
421 direction = "Down"; 406 } else {
422 } else { 407 if (event.key === 'ArrowUp' || event.key === 'PageUp')
423 if (event.key === "ArrowUp" || event.key === "PageUp") 408 direction = 'Up';
424 direction = "Up"; 409 else if (event.key === 'ArrowDown' || event.key === 'PageDown')
425 else if (event.key === "ArrowDown" || event.key === "PageDown") 410 direction = 'Down';
426 direction = "Down"; 411 }
427 } 412 return direction;
428 return direction;
429 }; 413 };
430 414
431 /** 415 /**
432 * @param {string} hexString 416 * @param {string} hexString
433 * @param {!Event} event 417 * @param {!Event} event
434 * @return {?string} 418 * @return {?string}
435 */ 419 */
436 WebInspector._modifiedHexValue = function(hexString, event) 420 WebInspector._modifiedHexValue = function(hexString, event) {
437 { 421 var direction = WebInspector._valueModificationDirection(event);
438 var direction = WebInspector._valueModificationDirection(event); 422 if (!direction)
439 if (!direction) 423 return null;
440 return null;
441 424
442 var mouseEvent = /** @type {!MouseEvent} */(event); 425 var mouseEvent = /** @type {!MouseEvent} */ (event);
443 var number = parseInt(hexString, 16); 426 var number = parseInt(hexString, 16);
444 if (isNaN(number) || !isFinite(number)) 427 if (isNaN(number) || !isFinite(number))
445 return null; 428 return null;
446 429
447 var hexStrLen = hexString.length; 430 var hexStrLen = hexString.length;
448 var channelLen = hexStrLen / 3; 431 var channelLen = hexStrLen / 3;
449 432
450 // Colors are either rgb or rrggbb. 433 // Colors are either rgb or rrggbb.
451 if (channelLen !== 1 && channelLen !== 2) 434 if (channelLen !== 1 && channelLen !== 2)
452 return null; 435 return null;
453 436
454 // Precision modifier keys work with both mousewheel and up/down keys. 437 // Precision modifier keys work with both mousewheel and up/down keys.
455 // When ctrl is pressed, increase R by 1. 438 // When ctrl is pressed, increase R by 1.
456 // When shift is pressed, increase G by 1. 439 // When shift is pressed, increase G by 1.
457 // When alt is pressed, increase B by 1. 440 // When alt is pressed, increase B by 1.
458 // If no shortcut keys are pressed then increase hex value by 1. 441 // If no shortcut keys are pressed then increase hex value by 1.
459 // Keys can be pressed together to increase RGB channels. e.g trying differe nt shades. 442 // Keys can be pressed together to increase RGB channels. e.g trying different shades.
460 var delta = 0; 443 var delta = 0;
461 if (WebInspector.KeyboardShortcut.eventHasCtrlOrMeta(mouseEvent)) 444 if (WebInspector.KeyboardShortcut.eventHasCtrlOrMeta(mouseEvent))
462 delta += Math.pow(16, channelLen * 2); 445 delta += Math.pow(16, channelLen * 2);
463 if (mouseEvent.shiftKey) 446 if (mouseEvent.shiftKey)
464 delta += Math.pow(16, channelLen); 447 delta += Math.pow(16, channelLen);
465 if (mouseEvent.altKey) 448 if (mouseEvent.altKey)
466 delta += 1; 449 delta += 1;
467 if (delta === 0) 450 if (delta === 0)
468 delta = 1; 451 delta = 1;
469 if (direction === "Down") 452 if (direction === 'Down')
470 delta *= -1; 453 delta *= -1;
471 454
472 // Increase hex value by 1 and clamp from 0 ... maxValue. 455 // Increase hex value by 1 and clamp from 0 ... maxValue.
473 var maxValue = Math.pow(16, hexStrLen) - 1; 456 var maxValue = Math.pow(16, hexStrLen) - 1;
474 var result = Number.constrain(number + delta, 0, maxValue); 457 var result = Number.constrain(number + delta, 0, maxValue);
475 458
476 // Ensure the result length is the same as the original hex value. 459 // Ensure the result length is the same as the original hex value.
477 var resultString = result.toString(16).toUpperCase(); 460 var resultString = result.toString(16).toUpperCase();
478 for (var i = 0, lengthDelta = hexStrLen - resultString.length; i < lengthDel ta; ++i) 461 for (var i = 0, lengthDelta = hexStrLen - resultString.length; i < lengthDelta ; ++i)
479 resultString = "0" + resultString; 462 resultString = '0' + resultString;
480 return resultString; 463 return resultString;
481 }; 464 };
482 465
483 /** 466 /**
484 * @param {number} number 467 * @param {number} number
485 * @param {!Event} event 468 * @param {!Event} event
486 * @return {?number} 469 * @return {?number}
487 */ 470 */
488 WebInspector._modifiedFloatNumber = function(number, event) 471 WebInspector._modifiedFloatNumber = function(number, event) {
489 { 472 var direction = WebInspector._valueModificationDirection(event);
490 var direction = WebInspector._valueModificationDirection(event); 473 if (!direction)
491 if (!direction) 474 return null;
492 return null;
493 475
494 var mouseEvent = /** @type {!MouseEvent} */(event); 476 var mouseEvent = /** @type {!MouseEvent} */ (event);
495 477
496 // Precision modifier keys work with both mousewheel and up/down keys. 478 // Precision modifier keys work with both mousewheel and up/down keys.
497 // When ctrl is pressed, increase by 100. 479 // When ctrl is pressed, increase by 100.
498 // When shift is pressed, increase by 10. 480 // When shift is pressed, increase by 10.
499 // When alt is pressed, increase by 0.1. 481 // When alt is pressed, increase by 0.1.
500 // Otherwise increase by 1. 482 // Otherwise increase by 1.
501 var delta = 1; 483 var delta = 1;
502 if (WebInspector.KeyboardShortcut.eventHasCtrlOrMeta(mouseEvent)) 484 if (WebInspector.KeyboardShortcut.eventHasCtrlOrMeta(mouseEvent))
503 delta = 100; 485 delta = 100;
504 else if (mouseEvent.shiftKey) 486 else if (mouseEvent.shiftKey)
505 delta = 10; 487 delta = 10;
506 else if (mouseEvent.altKey) 488 else if (mouseEvent.altKey)
507 delta = 0.1; 489 delta = 0.1;
508 490
509 if (direction === "Down") 491 if (direction === 'Down')
510 delta *= -1; 492 delta *= -1;
511 493
512 // Make the new number and constrain it to a precision of 6, this matches nu mbers the engine returns. 494 // Make the new number and constrain it to a precision of 6, this matches numb ers the engine returns.
513 // Use the Number constructor to forget the fixed precision, so 1.100000 wil l print as 1.1. 495 // Use the Number constructor to forget the fixed precision, so 1.100000 will print as 1.1.
514 var result = Number((number + delta).toFixed(6)); 496 var result = Number((number + delta).toFixed(6));
515 if (!String(result).match(WebInspector.CSSNumberRegex)) 497 if (!String(result).match(WebInspector.CSSNumberRegex))
516 return null; 498 return null;
517 499
518 return result; 500 return result;
519 }; 501 };
520 502
521 /** 503 /**
522 * @param {string} wordString 504 * @param {string} wordString
523 * @param {!Event} event 505 * @param {!Event} event
524 * @param {function(string, number, string):string=} customNumberHandler 506 * @param {function(string, number, string):string=} customNumberHandler
525 * @return {?string} 507 * @return {?string}
526 */ 508 */
527 WebInspector.createReplacementString = function(wordString, event, customNumberH andler) 509 WebInspector.createReplacementString = function(wordString, event, customNumberH andler) {
528 { 510 var prefix;
529 var prefix; 511 var suffix;
530 var suffix; 512 var number;
531 var number; 513 var replacementString = null;
532 var replacementString = null; 514 var matches = /(.*#)([\da-fA-F]+)(.*)/.exec(wordString);
533 var matches = /(.*#)([\da-fA-F]+)(.*)/.exec(wordString); 515 if (matches && matches.length) {
516 prefix = matches[1];
517 suffix = matches[3];
518 number = WebInspector._modifiedHexValue(matches[2], event);
519 if (number !== null)
520 replacementString = prefix + number + suffix;
521 } else {
522 matches = /(.*?)(-?(?:\d+(?:\.\d+)?|\.\d+))(.*)/.exec(wordString);
534 if (matches && matches.length) { 523 if (matches && matches.length) {
535 prefix = matches[1]; 524 prefix = matches[1];
536 suffix = matches[3]; 525 suffix = matches[3];
537 number = WebInspector._modifiedHexValue(matches[2], event); 526 number = WebInspector._modifiedFloatNumber(parseFloat(matches[2]), event);
538 if (number !== null) 527 if (number !== null)
539 replacementString = prefix + number + suffix; 528 replacementString =
540 } else { 529 customNumberHandler ? customNumberHandler(prefix, number, suffix) : prefix + number + suffix;
541 matches = /(.*?)(-?(?:\d+(?:\.\d+)?|\.\d+))(.*)/.exec(wordString);
542 if (matches && matches.length) {
543 prefix = matches[1];
544 suffix = matches[3];
545 number = WebInspector._modifiedFloatNumber(parseFloat(matches[2]), e vent);
546 if (number !== null)
547 replacementString = customNumberHandler ? customNumberHandler(pr efix, number, suffix) : prefix + number + suffix;
548 }
549 } 530 }
550 return replacementString; 531 }
532 return replacementString;
551 }; 533 };
552 534
553 /** 535 /**
554 * @param {!Event} event 536 * @param {!Event} event
555 * @param {!Element} element 537 * @param {!Element} element
556 * @param {function(string,string)=} finishHandler 538 * @param {function(string,string)=} finishHandler
557 * @param {function(string)=} suggestionHandler 539 * @param {function(string)=} suggestionHandler
558 * @param {function(string, number, string):string=} customNumberHandler 540 * @param {function(string, number, string):string=} customNumberHandler
559 * @return {boolean} 541 * @return {boolean}
560 */ 542 */
561 WebInspector.handleElementValueModifications = function(event, element, finishHa ndler, suggestionHandler, customNumberHandler) 543 WebInspector.handleElementValueModifications = function(
562 { 544 event, element, finishHandler, suggestionHandler, customNumberHandler) {
563 /** 545 /**
564 * @return {?Range} 546 * @return {?Range}
565 * @suppressGlobalPropertiesCheck 547 * @suppressGlobalPropertiesCheck
566 */ 548 */
567 function createRange() 549 function createRange() {
568 { 550 return document.createRange();
569 return document.createRange(); 551 }
570 }
571 552
572 var arrowKeyOrMouseWheelEvent = (event.key === "ArrowUp" || event.key === "A rrowDown" || event.type === "mousewheel"); 553 var arrowKeyOrMouseWheelEvent = (event.key === 'ArrowUp' || event.key === 'Arr owDown' || event.type === 'mousewheel');
573 var pageKeyPressed = (event.key === "PageUp" || event.key === "PageDown"); 554 var pageKeyPressed = (event.key === 'PageUp' || event.key === 'PageDown');
574 if (!arrowKeyOrMouseWheelEvent && !pageKeyPressed) 555 if (!arrowKeyOrMouseWheelEvent && !pageKeyPressed)
575 return false; 556 return false;
576 557
577 var selection = element.getComponentSelection(); 558 var selection = element.getComponentSelection();
578 if (!selection.rangeCount) 559 if (!selection.rangeCount)
579 return false; 560 return false;
580 561
581 var selectionRange = selection.getRangeAt(0); 562 var selectionRange = selection.getRangeAt(0);
582 if (!selectionRange.commonAncestorContainer.isSelfOrDescendant(element)) 563 if (!selectionRange.commonAncestorContainer.isSelfOrDescendant(element))
583 return false; 564 return false;
584 565
585 var originalValue = element.textContent; 566 var originalValue = element.textContent;
586 var wordRange = selectionRange.startContainer.rangeOfWord(selectionRange.sta rtOffset, WebInspector.StyleValueDelimiters, element); 567 var wordRange =
587 var wordString = wordRange.toString(); 568 selectionRange.startContainer.rangeOfWord(selectionRange.startOffset, WebI nspector.StyleValueDelimiters, element);
569 var wordString = wordRange.toString();
588 570
589 if (suggestionHandler && suggestionHandler(wordString)) 571 if (suggestionHandler && suggestionHandler(wordString))
590 return false; 572 return false;
591 573
592 var replacementString = WebInspector.createReplacementString(wordString, eve nt, customNumberHandler); 574 var replacementString = WebInspector.createReplacementString(wordString, event , customNumberHandler);
593 575
594 if (replacementString) { 576 if (replacementString) {
595 var replacementTextNode = createTextNode(replacementString); 577 var replacementTextNode = createTextNode(replacementString);
596 578
597 wordRange.deleteContents(); 579 wordRange.deleteContents();
598 wordRange.insertNode(replacementTextNode); 580 wordRange.insertNode(replacementTextNode);
599 581
600 var finalSelectionRange = createRange(); 582 var finalSelectionRange = createRange();
601 finalSelectionRange.setStart(replacementTextNode, 0); 583 finalSelectionRange.setStart(replacementTextNode, 0);
602 finalSelectionRange.setEnd(replacementTextNode, replacementString.length ); 584 finalSelectionRange.setEnd(replacementTextNode, replacementString.length);
603 585
604 selection.removeAllRanges(); 586 selection.removeAllRanges();
605 selection.addRange(finalSelectionRange); 587 selection.addRange(finalSelectionRange);
606 588
607 event.handled = true; 589 event.handled = true;
608 event.preventDefault(); 590 event.preventDefault();
609 591
610 if (finishHandler) 592 if (finishHandler)
611 finishHandler(originalValue, replacementString); 593 finishHandler(originalValue, replacementString);
612 594
613 return true; 595 return true;
614 } 596 }
615 return false; 597 return false;
616 }; 598 };
617 599
618 /** 600 /**
619 * @param {number} ms 601 * @param {number} ms
620 * @param {number=} precision 602 * @param {number=} precision
621 * @return {string} 603 * @return {string}
622 */ 604 */
623 Number.preciseMillisToString = function(ms, precision) 605 Number.preciseMillisToString = function(ms, precision) {
624 { 606 precision = precision || 0;
625 precision = precision || 0; 607 var format = '%.' + precision + 'f\u2009ms';
626 var format = "%." + precision + "f\u2009ms"; 608 return WebInspector.UIString(format, ms);
627 return WebInspector.UIString(format, ms);
628 }; 609 };
629 610
630 /** @type {!WebInspector.UIStringFormat} */ 611 /** @type {!WebInspector.UIStringFormat} */
631 WebInspector._microsFormat = new WebInspector.UIStringFormat("%.0f\u2009\u03bcs" ); 612 WebInspector._microsFormat = new WebInspector.UIStringFormat('%.0f\u2009\u03bcs' );
632 613
633 /** @type {!WebInspector.UIStringFormat} */ 614 /** @type {!WebInspector.UIStringFormat} */
634 WebInspector._subMillisFormat = new WebInspector.UIStringFormat("%.2f\u2009ms"); 615 WebInspector._subMillisFormat = new WebInspector.UIStringFormat('%.2f\u2009ms');
635 616
636 /** @type {!WebInspector.UIStringFormat} */ 617 /** @type {!WebInspector.UIStringFormat} */
637 WebInspector._millisFormat = new WebInspector.UIStringFormat("%.0f\u2009ms"); 618 WebInspector._millisFormat = new WebInspector.UIStringFormat('%.0f\u2009ms');
638 619
639 /** @type {!WebInspector.UIStringFormat} */ 620 /** @type {!WebInspector.UIStringFormat} */
640 WebInspector._secondsFormat = new WebInspector.UIStringFormat("%.2f\u2009s"); 621 WebInspector._secondsFormat = new WebInspector.UIStringFormat('%.2f\u2009s');
641 622
642 /** @type {!WebInspector.UIStringFormat} */ 623 /** @type {!WebInspector.UIStringFormat} */
643 WebInspector._minutesFormat = new WebInspector.UIStringFormat("%.1f\u2009min"); 624 WebInspector._minutesFormat = new WebInspector.UIStringFormat('%.1f\u2009min');
644 625
645 /** @type {!WebInspector.UIStringFormat} */ 626 /** @type {!WebInspector.UIStringFormat} */
646 WebInspector._hoursFormat = new WebInspector.UIStringFormat("%.1f\u2009hrs"); 627 WebInspector._hoursFormat = new WebInspector.UIStringFormat('%.1f\u2009hrs');
647 628
648 /** @type {!WebInspector.UIStringFormat} */ 629 /** @type {!WebInspector.UIStringFormat} */
649 WebInspector._daysFormat = new WebInspector.UIStringFormat("%.1f\u2009days"); 630 WebInspector._daysFormat = new WebInspector.UIStringFormat('%.1f\u2009days');
650 631
651 /** 632 /**
652 * @param {number} ms 633 * @param {number} ms
653 * @param {boolean=} higherResolution 634 * @param {boolean=} higherResolution
654 * @return {string} 635 * @return {string}
655 */ 636 */
656 Number.millisToString = function(ms, higherResolution) 637 Number.millisToString = function(ms, higherResolution) {
657 { 638 if (!isFinite(ms))
658 if (!isFinite(ms)) 639 return '-';
659 return "-";
660 640
661 if (ms === 0) 641 if (ms === 0)
662 return "0"; 642 return '0';
663 643
664 if (higherResolution && ms < 0.1) 644 if (higherResolution && ms < 0.1)
665 return WebInspector._microsFormat.format(ms * 1000); 645 return WebInspector._microsFormat.format(ms * 1000);
666 if (higherResolution && ms < 1000) 646 if (higherResolution && ms < 1000)
667 return WebInspector._subMillisFormat.format(ms); 647 return WebInspector._subMillisFormat.format(ms);
668 if (ms < 1000) 648 if (ms < 1000)
669 return WebInspector._millisFormat.format(ms); 649 return WebInspector._millisFormat.format(ms);
670 650
671 var seconds = ms / 1000; 651 var seconds = ms / 1000;
672 if (seconds < 60) 652 if (seconds < 60)
673 return WebInspector._secondsFormat.format(seconds); 653 return WebInspector._secondsFormat.format(seconds);
674 654
675 var minutes = seconds / 60; 655 var minutes = seconds / 60;
676 if (minutes < 60) 656 if (minutes < 60)
677 return WebInspector._minutesFormat.format(minutes); 657 return WebInspector._minutesFormat.format(minutes);
678 658
679 var hours = minutes / 60; 659 var hours = minutes / 60;
680 if (hours < 24) 660 if (hours < 24)
681 return WebInspector._hoursFormat.format(hours); 661 return WebInspector._hoursFormat.format(hours);
682 662
683 var days = hours / 24; 663 var days = hours / 24;
684 return WebInspector._daysFormat.format(days); 664 return WebInspector._daysFormat.format(days);
685 }; 665 };
686 666
687 /** 667 /**
688 * @param {number} seconds 668 * @param {number} seconds
689 * @param {boolean=} higherResolution 669 * @param {boolean=} higherResolution
690 * @return {string} 670 * @return {string}
691 */ 671 */
692 Number.secondsToString = function(seconds, higherResolution) 672 Number.secondsToString = function(seconds, higherResolution) {
693 { 673 if (!isFinite(seconds))
694 if (!isFinite(seconds)) 674 return '-';
695 return "-"; 675 return Number.millisToString(seconds * 1000, higherResolution);
696 return Number.millisToString(seconds * 1000, higherResolution);
697 }; 676 };
698 677
699 /** 678 /**
700 * @param {number} bytes 679 * @param {number} bytes
701 * @return {string} 680 * @return {string}
702 */ 681 */
703 Number.bytesToString = function(bytes) 682 Number.bytesToString = function(bytes) {
704 { 683 if (bytes < 1024)
705 if (bytes < 1024) 684 return WebInspector.UIString('%.0f\u2009B', bytes);
706 return WebInspector.UIString("%.0f\u2009B", bytes);
707 685
708 var kilobytes = bytes / 1024; 686 var kilobytes = bytes / 1024;
709 if (kilobytes < 100) 687 if (kilobytes < 100)
710 return WebInspector.UIString("%.1f\u2009KB", kilobytes); 688 return WebInspector.UIString('%.1f\u2009KB', kilobytes);
711 if (kilobytes < 1024) 689 if (kilobytes < 1024)
712 return WebInspector.UIString("%.0f\u2009KB", kilobytes); 690 return WebInspector.UIString('%.0f\u2009KB', kilobytes);
713 691
714 var megabytes = kilobytes / 1024; 692 var megabytes = kilobytes / 1024;
715 if (megabytes < 100) 693 if (megabytes < 100)
716 return WebInspector.UIString("%.1f\u2009MB", megabytes); 694 return WebInspector.UIString('%.1f\u2009MB', megabytes);
717 else 695 else
718 return WebInspector.UIString("%.0f\u2009MB", megabytes); 696 return WebInspector.UIString('%.0f\u2009MB', megabytes);
719 }; 697 };
720 698
721 /** 699 /**
722 * @param {number} num 700 * @param {number} num
723 * @return {string} 701 * @return {string}
724 */ 702 */
725 Number.withThousandsSeparator = function(num) 703 Number.withThousandsSeparator = function(num) {
726 { 704 var str = num + '';
727 var str = num + ""; 705 var re = /(\d+)(\d{3})/;
728 var re = /(\d+)(\d{3})/; 706 while (str.match(re))
729 while (str.match(re)) 707 str = str.replace(re, '$1\u2009$2'); // \u2009 is a thin space.
730 str = str.replace(re, "$1\u2009$2"); // \u2009 is a thin space. 708 return str;
731 return str;
732 }; 709 };
733 710
734 /** 711 /**
735 * @param {string} format 712 * @param {string} format
736 * @param {?ArrayLike} substitutions 713 * @param {?ArrayLike} substitutions
737 * @return {!Element} 714 * @return {!Element}
738 */ 715 */
739 WebInspector.formatLocalized = function(format, substitutions) 716 WebInspector.formatLocalized = function(format, substitutions) {
740 { 717 var formatters = {s: substitution => substitution};
741 var formatters = { 718 /**
742 s: substitution => substitution 719 * @param {!Element} a
743 }; 720 * @param {string|!Element} b
744 /** 721 * @return {!Element}
745 * @param {!Element} a 722 */
746 * @param {string|!Element} b 723 function append(a, b) {
747 * @return {!Element} 724 a.appendChild(typeof b === 'string' ? createTextNode(b) : b);
748 */ 725 return a;
749 function append(a, b) 726 }
750 { 727 return String.format(WebInspector.UIString(format), substitutions, formatters, createElement('span'), append)
751 a.appendChild(typeof b === "string" ? createTextNode(b) : b); 728 .formattedResult;
752 return a;
753 }
754 return String.format(WebInspector.UIString(format), substitutions, formatter s, createElement("span"), append).formattedResult;
755 }; 729 };
756 730
757 /** 731 /**
758 * @return {string} 732 * @return {string}
759 */ 733 */
760 WebInspector.openLinkExternallyLabel = function() 734 WebInspector.openLinkExternallyLabel = function() {
761 { 735 return WebInspector.UIString.capitalize('Open ^link in ^new ^tab');
762 return WebInspector.UIString.capitalize("Open ^link in ^new ^tab");
763 }; 736 };
764 737
765 /** 738 /**
766 * @return {string} 739 * @return {string}
767 */ 740 */
768 WebInspector.copyLinkAddressLabel = function() 741 WebInspector.copyLinkAddressLabel = function() {
769 { 742 return WebInspector.UIString.capitalize('Copy ^link ^address');
770 return WebInspector.UIString.capitalize("Copy ^link ^address");
771 }; 743 };
772 744
773 /** 745 /**
774 * @return {string} 746 * @return {string}
775 */ 747 */
776 WebInspector.anotherProfilerActiveLabel = function() 748 WebInspector.anotherProfilerActiveLabel = function() {
777 { 749 return WebInspector.UIString('Another profiler is already active');
778 return WebInspector.UIString("Another profiler is already active");
779 }; 750 };
780 751
781 /** 752 /**
782 * @param {string|undefined} description 753 * @param {string|undefined} description
783 * @return {string} 754 * @return {string}
784 */ 755 */
785 WebInspector.asyncStackTraceLabel = function(description) 756 WebInspector.asyncStackTraceLabel = function(description) {
786 { 757 if (description)
787 if (description) 758 return description + ' ' + WebInspector.UIString('(async)');
788 return description + " " + WebInspector.UIString("(async)"); 759 return WebInspector.UIString('Async Call');
789 return WebInspector.UIString("Async Call");
790 }; 760 };
791 761
792 /** 762 /**
793 * @param {!Element} element 763 * @param {!Element} element
794 */ 764 */
795 WebInspector.installComponentRootStyles = function(element) 765 WebInspector.installComponentRootStyles = function(element) {
796 { 766 WebInspector.appendStyle(element, 'ui/inspectorCommon.css');
797 WebInspector.appendStyle(element, "ui/inspectorCommon.css"); 767 WebInspector.themeSupport.injectHighlightStyleSheets(element);
798 WebInspector.themeSupport.injectHighlightStyleSheets(element); 768 element.classList.add('platform-' + WebInspector.platform());
799 element.classList.add("platform-" + WebInspector.platform());
800 }; 769 };
801 770
802 /** 771 /**
803 * @param {!Element} element 772 * @param {!Element} element
804 * @param {string=} cssFile 773 * @param {string=} cssFile
805 * @return {!DocumentFragment} 774 * @return {!DocumentFragment}
806 */ 775 */
807 WebInspector.createShadowRootWithCoreStyles = function(element, cssFile) 776 WebInspector.createShadowRootWithCoreStyles = function(element, cssFile) {
808 { 777 var shadowRoot = element.createShadowRoot();
809 var shadowRoot = element.createShadowRoot(); 778 WebInspector.appendStyle(shadowRoot, 'ui/inspectorCommon.css');
810 WebInspector.appendStyle(shadowRoot, "ui/inspectorCommon.css"); 779 WebInspector.themeSupport.injectHighlightStyleSheets(shadowRoot);
811 WebInspector.themeSupport.injectHighlightStyleSheets(shadowRoot); 780 if (cssFile)
812 if (cssFile) 781 WebInspector.appendStyle(shadowRoot, cssFile);
813 WebInspector.appendStyle(shadowRoot, cssFile); 782 shadowRoot.addEventListener('focus', WebInspector._focusChanged.bind(WebInspec tor), true);
814 shadowRoot.addEventListener("focus", WebInspector._focusChanged.bind(WebInsp ector), true); 783 return shadowRoot;
815 return shadowRoot;
816 }; 784 };
817 785
818 /** 786 /**
819 * @param {!Document} document 787 * @param {!Document} document
820 * @param {!Event} event 788 * @param {!Event} event
821 */ 789 */
822 WebInspector._windowFocused = function(document, event) 790 WebInspector._windowFocused = function(document, event) {
823 { 791 if (event.target.document.nodeType === Node.DOCUMENT_NODE)
824 if (event.target.document.nodeType === Node.DOCUMENT_NODE) 792 document.body.classList.remove('inactive');
825 document.body.classList.remove("inactive");
826 }; 793 };
827 794
828 /** 795 /**
829 * @param {!Document} document 796 * @param {!Document} document
830 * @param {!Event} event 797 * @param {!Event} event
831 */ 798 */
832 WebInspector._windowBlurred = function(document, event) 799 WebInspector._windowBlurred = function(document, event) {
833 { 800 if (event.target.document.nodeType === Node.DOCUMENT_NODE)
834 if (event.target.document.nodeType === Node.DOCUMENT_NODE) 801 document.body.classList.add('inactive');
835 document.body.classList.add("inactive");
836 }; 802 };
837 803
838 /** 804 /**
839 * @param {!Event} event 805 * @param {!Event} event
840 */ 806 */
841 WebInspector._focusChanged = function(event) 807 WebInspector._focusChanged = function(event) {
842 { 808 var document = event.target && event.target.ownerDocument;
843 var document = event.target && event.target.ownerDocument; 809 var element = document ? document.deepActiveElement() : null;
844 var element = document ? document.deepActiveElement() : null; 810 WebInspector.Widget.focusWidgetForNode(element);
845 WebInspector.Widget.focusWidgetForNode(element);
846 }; 811 };
847 812
848 /** 813 /**
849 * @param {!Element} element 814 * @unrestricted
850 * @constructor
851 */ 815 */
852 WebInspector.ElementFocusRestorer = function(element) 816 WebInspector.ElementFocusRestorer = class {
853 { 817 /**
818 * @param {!Element} element
819 */
820 constructor(element) {
854 this._element = element; 821 this._element = element;
855 this._previous = element.ownerDocument.deepActiveElement(); 822 this._previous = element.ownerDocument.deepActiveElement();
856 element.focus(); 823 element.focus();
857 }; 824 }
858 825
859 WebInspector.ElementFocusRestorer.prototype = { 826 restore() {
860 restore: function() 827 if (!this._element)
861 { 828 return;
862 if (!this._element) 829 if (this._element.hasFocus() && this._previous)
863 return; 830 this._previous.focus();
864 if (this._element.hasFocus() && this._previous) 831 this._previous = null;
865 this._previous.focus(); 832 this._element = null;
866 this._previous = null; 833 }
867 this._element = null;
868 }
869 }; 834 };
870 835
871 /** 836 /**
872 * @param {!Element} element 837 * @param {!Element} element
873 * @param {number} offset 838 * @param {number} offset
874 * @param {number} length 839 * @param {number} length
875 * @param {!Array.<!Object>=} domChanges 840 * @param {!Array.<!Object>=} domChanges
876 * @return {?Element} 841 * @return {?Element}
877 */ 842 */
878 WebInspector.highlightSearchResult = function(element, offset, length, domChange s) 843 WebInspector.highlightSearchResult = function(element, offset, length, domChange s) {
879 { 844 var result = WebInspector.highlightSearchResults(element, [new WebInspector.So urceRange(offset, length)], domChanges);
880 var result = WebInspector.highlightSearchResults(element, [new WebInspector. SourceRange(offset, length)], domChanges); 845 return result.length ? result[0] : null;
881 return result.length ? result[0] : null;
882 }; 846 };
883 847
884 /** 848 /**
885 * @param {!Element} element 849 * @param {!Element} element
886 * @param {!Array.<!WebInspector.SourceRange>} resultRanges 850 * @param {!Array.<!WebInspector.SourceRange>} resultRanges
887 * @param {!Array.<!Object>=} changes 851 * @param {!Array.<!Object>=} changes
888 * @return {!Array.<!Element>} 852 * @return {!Array.<!Element>}
889 */ 853 */
890 WebInspector.highlightSearchResults = function(element, resultRanges, changes) 854 WebInspector.highlightSearchResults = function(element, resultRanges, changes) {
891 { 855 return WebInspector.highlightRangesWithStyleClass(
892 return WebInspector.highlightRangesWithStyleClass(element, resultRanges, Web Inspector.highlightedSearchResultClassName, changes); 856 element, resultRanges, WebInspector.highlightedSearchResultClassName, chan ges);
893 }; 857 };
894 858
895 /** 859 /**
896 * @param {!Element} element 860 * @param {!Element} element
897 * @param {string} className 861 * @param {string} className
898 */ 862 */
899 WebInspector.runCSSAnimationOnce = function(element, className) 863 WebInspector.runCSSAnimationOnce = function(element, className) {
900 { 864 function animationEndCallback() {
901 function animationEndCallback() 865 element.classList.remove(className);
902 { 866 element.removeEventListener('webkitAnimationEnd', animationEndCallback, fals e);
903 element.classList.remove(className); 867 }
904 element.removeEventListener("webkitAnimationEnd", animationEndCallback, false);
905 }
906 868
907 if (element.classList.contains(className)) 869 if (element.classList.contains(className))
908 element.classList.remove(className); 870 element.classList.remove(className);
909 871
910 element.addEventListener("webkitAnimationEnd", animationEndCallback, false); 872 element.addEventListener('webkitAnimationEnd', animationEndCallback, false);
911 element.classList.add(className); 873 element.classList.add(className);
912 }; 874 };
913 875
914 /** 876 /**
915 * @param {!Element} element 877 * @param {!Element} element
916 * @param {!Array.<!WebInspector.SourceRange>} resultRanges 878 * @param {!Array.<!WebInspector.SourceRange>} resultRanges
917 * @param {string} styleClass 879 * @param {string} styleClass
918 * @param {!Array.<!Object>=} changes 880 * @param {!Array.<!Object>=} changes
919 * @return {!Array.<!Element>} 881 * @return {!Array.<!Element>}
920 */ 882 */
921 WebInspector.highlightRangesWithStyleClass = function(element, resultRanges, sty leClass, changes) 883 WebInspector.highlightRangesWithStyleClass = function(element, resultRanges, sty leClass, changes) {
922 { 884 changes = changes || [];
923 changes = changes || []; 885 var highlightNodes = [];
924 var highlightNodes = []; 886 var textNodes = element.childTextNodes();
925 var textNodes = element.childTextNodes(); 887 var lineText = textNodes
926 var lineText = textNodes.map(function(node) { return node.textContent; }).jo in(""); 888 .map(function(node) {
927 var ownerDocument = element.ownerDocument; 889 return node.textContent;
890 })
891 .join('');
892 var ownerDocument = element.ownerDocument;
928 893
929 if (textNodes.length === 0) 894 if (textNodes.length === 0)
930 return highlightNodes; 895 return highlightNodes;
931 896
932 var nodeRanges = []; 897 var nodeRanges = [];
933 var rangeEndOffset = 0; 898 var rangeEndOffset = 0;
934 for (var i = 0; i < textNodes.length; ++i) { 899 for (var i = 0; i < textNodes.length; ++i) {
935 var range = {}; 900 var range = {};
936 range.offset = rangeEndOffset; 901 range.offset = rangeEndOffset;
937 range.length = textNodes[i].textContent.length; 902 range.length = textNodes[i].textContent.length;
938 rangeEndOffset = range.offset + range.length; 903 rangeEndOffset = range.offset + range.length;
939 nodeRanges.push(range); 904 nodeRanges.push(range);
905 }
906
907 var startIndex = 0;
908 for (var i = 0; i < resultRanges.length; ++i) {
909 var startOffset = resultRanges[i].offset;
910 var endOffset = startOffset + resultRanges[i].length;
911
912 while (startIndex < textNodes.length &&
913 nodeRanges[startIndex].offset + nodeRanges[startIndex].length <= star tOffset)
914 startIndex++;
915 var endIndex = startIndex;
916 while (endIndex < textNodes.length && nodeRanges[endIndex].offset + nodeRang es[endIndex].length < endOffset)
917 endIndex++;
918 if (endIndex === textNodes.length)
919 break;
920
921 var highlightNode = ownerDocument.createElement('span');
922 highlightNode.className = styleClass;
923 highlightNode.textContent = lineText.substring(startOffset, endOffset);
924
925 var lastTextNode = textNodes[endIndex];
926 var lastText = lastTextNode.textContent;
927 lastTextNode.textContent = lastText.substring(endOffset - nodeRanges[endInde x].offset);
928 changes.push({node: lastTextNode, type: 'changed', oldText: lastText, newTex t: lastTextNode.textContent});
929
930 if (startIndex === endIndex) {
931 lastTextNode.parentElement.insertBefore(highlightNode, lastTextNode);
932 changes.push({node: highlightNode, type: 'added', nextSibling: lastTextNod e, parent: lastTextNode.parentElement});
933 highlightNodes.push(highlightNode);
934
935 var prefixNode = ownerDocument.createTextNode(lastText.substring(0, startO ffset - nodeRanges[startIndex].offset));
936 lastTextNode.parentElement.insertBefore(prefixNode, highlightNode);
937 changes.push({node: prefixNode, type: 'added', nextSibling: highlightNode, parent: lastTextNode.parentElement});
938 } else {
939 var firstTextNode = textNodes[startIndex];
940 var firstText = firstTextNode.textContent;
941 var anchorElement = firstTextNode.nextSibling;
942
943 firstTextNode.parentElement.insertBefore(highlightNode, anchorElement);
944 changes.push(
945 {node: highlightNode, type: 'added', nextSibling: anchorElement, paren t: firstTextNode.parentElement});
946 highlightNodes.push(highlightNode);
947
948 firstTextNode.textContent = firstText.substring(0, startOffset - nodeRange s[startIndex].offset);
949 changes.push({node: firstTextNode, type: 'changed', oldText: firstText, ne wText: firstTextNode.textContent});
950
951 for (var j = startIndex + 1; j < endIndex; j++) {
952 var textNode = textNodes[j];
953 var text = textNode.textContent;
954 textNode.textContent = '';
955 changes.push({node: textNode, type: 'changed', oldText: text, newText: t extNode.textContent});
956 }
940 } 957 }
941 958 startIndex = endIndex;
942 var startIndex = 0; 959 nodeRanges[startIndex].offset = endOffset;
943 for (var i = 0; i < resultRanges.length; ++i) { 960 nodeRanges[startIndex].length = lastTextNode.textContent.length;
944 var startOffset = resultRanges[i].offset; 961 }
945 var endOffset = startOffset + resultRanges[i].length; 962 return highlightNodes;
946
947 while (startIndex < textNodes.length && nodeRanges[startIndex].offset + nodeRanges[startIndex].length <= startOffset)
948 startIndex++;
949 var endIndex = startIndex;
950 while (endIndex < textNodes.length && nodeRanges[endIndex].offset + node Ranges[endIndex].length < endOffset)
951 endIndex++;
952 if (endIndex === textNodes.length)
953 break;
954
955 var highlightNode = ownerDocument.createElement("span");
956 highlightNode.className = styleClass;
957 highlightNode.textContent = lineText.substring(startOffset, endOffset);
958
959 var lastTextNode = textNodes[endIndex];
960 var lastText = lastTextNode.textContent;
961 lastTextNode.textContent = lastText.substring(endOffset - nodeRanges[end Index].offset);
962 changes.push({ node: lastTextNode, type: "changed", oldText: lastText, n ewText: lastTextNode.textContent });
963
964 if (startIndex === endIndex) {
965 lastTextNode.parentElement.insertBefore(highlightNode, lastTextNode) ;
966 changes.push({ node: highlightNode, type: "added", nextSibling: last TextNode, parent: lastTextNode.parentElement });
967 highlightNodes.push(highlightNode);
968
969 var prefixNode = ownerDocument.createTextNode(lastText.substring(0, startOffset - nodeRanges[startIndex].offset));
970 lastTextNode.parentElement.insertBefore(prefixNode, highlightNode);
971 changes.push({ node: prefixNode, type: "added", nextSibling: highlig htNode, parent: lastTextNode.parentElement });
972 } else {
973 var firstTextNode = textNodes[startIndex];
974 var firstText = firstTextNode.textContent;
975 var anchorElement = firstTextNode.nextSibling;
976
977 firstTextNode.parentElement.insertBefore(highlightNode, anchorElemen t);
978 changes.push({ node: highlightNode, type: "added", nextSibling: anch orElement, parent: firstTextNode.parentElement });
979 highlightNodes.push(highlightNode);
980
981 firstTextNode.textContent = firstText.substring(0, startOffset - nod eRanges[startIndex].offset);
982 changes.push({ node: firstTextNode, type: "changed", oldText: firstT ext, newText: firstTextNode.textContent });
983
984 for (var j = startIndex + 1; j < endIndex; j++) {
985 var textNode = textNodes[j];
986 var text = textNode.textContent;
987 textNode.textContent = "";
988 changes.push({ node: textNode, type: "changed", oldText: text, n ewText: textNode.textContent });
989 }
990 }
991 startIndex = endIndex;
992 nodeRanges[startIndex].offset = endOffset;
993 nodeRanges[startIndex].length = lastTextNode.textContent.length;
994
995 }
996 return highlightNodes;
997 }; 963 };
998 964
999 WebInspector.applyDomChanges = function(domChanges) 965 WebInspector.applyDomChanges = function(domChanges) {
1000 { 966 for (var i = 0, size = domChanges.length; i < size; ++i) {
1001 for (var i = 0, size = domChanges.length; i < size; ++i) { 967 var entry = domChanges[i];
1002 var entry = domChanges[i]; 968 switch (entry.type) {
1003 switch (entry.type) { 969 case 'added':
1004 case "added": 970 entry.parent.insertBefore(entry.node, entry.nextSibling);
1005 entry.parent.insertBefore(entry.node, entry.nextSibling); 971 break;
1006 break; 972 case 'changed':
1007 case "changed": 973 entry.node.textContent = entry.newText;
1008 entry.node.textContent = entry.newText; 974 break;
1009 break;
1010 }
1011 } 975 }
976 }
1012 }; 977 };
1013 978
1014 WebInspector.revertDomChanges = function(domChanges) 979 WebInspector.revertDomChanges = function(domChanges) {
1015 { 980 for (var i = domChanges.length - 1; i >= 0; --i) {
1016 for (var i = domChanges.length - 1; i >= 0; --i) { 981 var entry = domChanges[i];
1017 var entry = domChanges[i]; 982 switch (entry.type) {
1018 switch (entry.type) { 983 case 'added':
1019 case "added": 984 entry.node.remove();
1020 entry.node.remove(); 985 break;
1021 break; 986 case 'changed':
1022 case "changed": 987 entry.node.textContent = entry.oldText;
1023 entry.node.textContent = entry.oldText; 988 break;
1024 break;
1025 }
1026 } 989 }
990 }
1027 }; 991 };
1028 992
1029 /** 993 /**
1030 * @param {!Element} element 994 * @param {!Element} element
1031 * @param {?Element=} containerElement 995 * @param {?Element=} containerElement
1032 * @return {!Size} 996 * @return {!Size}
1033 */ 997 */
1034 WebInspector.measurePreferredSize = function(element, containerElement) 998 WebInspector.measurePreferredSize = function(element, containerElement) {
1035 { 999 var oldParent = element.parentElement;
1036 var oldParent = element.parentElement; 1000 var oldNextSibling = element.nextSibling;
1037 var oldNextSibling = element.nextSibling; 1001 containerElement = containerElement || element.ownerDocument.body;
1038 containerElement = containerElement || element.ownerDocument.body; 1002 containerElement.appendChild(element);
1039 containerElement.appendChild(element); 1003 element.positionAt(0, 0);
1040 element.positionAt(0, 0); 1004 var result = new Size(element.offsetWidth, element.offsetHeight);
1041 var result = new Size(element.offsetWidth, element.offsetHeight);
1042 1005
1043 element.positionAt(undefined, undefined); 1006 element.positionAt(undefined, undefined);
1044 if (oldParent) 1007 if (oldParent)
1045 oldParent.insertBefore(element, oldNextSibling); 1008 oldParent.insertBefore(element, oldNextSibling);
1046 else 1009 else
1047 element.remove(); 1010 element.remove();
1048 return result; 1011 return result;
1049 }; 1012 };
1050 1013
1051 /** 1014 /**
1052 * @constructor 1015 * @unrestricted
1053 * @param {boolean} autoInvoke
1054 */ 1016 */
1055 WebInspector.InvokeOnceHandlers = function(autoInvoke) 1017 WebInspector.InvokeOnceHandlers = class {
1056 { 1018 /**
1019 * @param {boolean} autoInvoke
1020 */
1021 constructor(autoInvoke) {
1057 this._handlers = null; 1022 this._handlers = null;
1058 this._autoInvoke = autoInvoke; 1023 this._autoInvoke = autoInvoke;
1059 }; 1024 }
1060 1025
1061 WebInspector.InvokeOnceHandlers.prototype = { 1026 /**
1062 /** 1027 * @param {!Object} object
1063 * @param {!Object} object 1028 * @param {function()} method
1064 * @param {function()} method 1029 */
1065 */ 1030 add(object, method) {
1066 add: function(object, method) 1031 if (!this._handlers) {
1067 { 1032 this._handlers = new Map();
1068 if (!this._handlers) { 1033 if (this._autoInvoke)
1069 this._handlers = new Map(); 1034 this.scheduleInvoke();
1070 if (this._autoInvoke) 1035 }
1071 this.scheduleInvoke(); 1036 var methods = this._handlers.get(object);
1072 } 1037 if (!methods) {
1073 var methods = this._handlers.get(object); 1038 methods = new Set();
1074 if (!methods) { 1039 this._handlers.set(object, methods);
1075 methods = new Set(); 1040 }
1076 this._handlers.set(object, methods); 1041 methods.add(method);
1077 } 1042 }
1078 methods.add(method);
1079 },
1080 1043
1081 /** 1044 /**
1082 * @suppressGlobalPropertiesCheck 1045 * @suppressGlobalPropertiesCheck
1083 */ 1046 */
1084 scheduleInvoke: function() 1047 scheduleInvoke() {
1085 { 1048 if (this._handlers)
1086 if (this._handlers) 1049 requestAnimationFrame(this._invoke.bind(this));
1087 requestAnimationFrame(this._invoke.bind(this)); 1050 }
1088 },
1089 1051
1090 _invoke: function() 1052 _invoke() {
1091 { 1053 var handlers = this._handlers;
1092 var handlers = this._handlers; 1054 this._handlers = null;
1093 this._handlers = null; 1055 var keys = handlers.keysArray();
1094 var keys = handlers.keysArray(); 1056 for (var i = 0; i < keys.length; ++i) {
1095 for (var i = 0; i < keys.length; ++i) { 1057 var object = keys[i];
1096 var object = keys[i]; 1058 var methods = handlers.get(object).valuesArray();
1097 var methods = handlers.get(object).valuesArray(); 1059 for (var j = 0; j < methods.length; ++j)
1098 for (var j = 0; j < methods.length; ++j) 1060 methods[j].call(object);
1099 methods[j].call(object);
1100 }
1101 } 1061 }
1062 }
1102 }; 1063 };
1103 1064
1104 WebInspector._coalescingLevel = 0; 1065 WebInspector._coalescingLevel = 0;
1105 WebInspector._postUpdateHandlers = null; 1066 WebInspector._postUpdateHandlers = null;
1106 1067
1107 WebInspector.startBatchUpdate = function() 1068 WebInspector.startBatchUpdate = function() {
1108 { 1069 if (!WebInspector._coalescingLevel++)
1109 if (!WebInspector._coalescingLevel++) 1070 WebInspector._postUpdateHandlers = new WebInspector.InvokeOnceHandlers(false );
1110 WebInspector._postUpdateHandlers = new WebInspector.InvokeOnceHandlers(f alse);
1111 }; 1071 };
1112 1072
1113 WebInspector.endBatchUpdate = function() 1073 WebInspector.endBatchUpdate = function() {
1114 { 1074 if (--WebInspector._coalescingLevel)
1115 if (--WebInspector._coalescingLevel) 1075 return;
1116 return; 1076 WebInspector._postUpdateHandlers.scheduleInvoke();
1117 WebInspector._postUpdateHandlers.scheduleInvoke(); 1077 WebInspector._postUpdateHandlers = null;
1118 WebInspector._postUpdateHandlers = null;
1119 }; 1078 };
1120 1079
1121 /** 1080 /**
1122 * @param {!Object} object 1081 * @param {!Object} object
1123 * @param {function()} method 1082 * @param {function()} method
1124 */ 1083 */
1125 WebInspector.invokeOnceAfterBatchUpdate = function(object, method) 1084 WebInspector.invokeOnceAfterBatchUpdate = function(object, method) {
1126 { 1085 if (!WebInspector._postUpdateHandlers)
1127 if (!WebInspector._postUpdateHandlers) 1086 WebInspector._postUpdateHandlers = new WebInspector.InvokeOnceHandlers(true) ;
1128 WebInspector._postUpdateHandlers = new WebInspector.InvokeOnceHandlers(t rue); 1087 WebInspector._postUpdateHandlers.add(object, method);
1129 WebInspector._postUpdateHandlers.add(object, method);
1130 }; 1088 };
1131 1089
1132 /** 1090 /**
1133 * @param {!Window} window 1091 * @param {!Window} window
1134 * @param {!Function} func 1092 * @param {!Function} func
1135 * @param {!Array.<{from:number, to:number}>} params 1093 * @param {!Array.<{from:number, to:number}>} params
1136 * @param {number} frames 1094 * @param {number} frames
1137 * @param {function()=} animationComplete 1095 * @param {function()=} animationComplete
1138 * @return {function()} 1096 * @return {function()}
1139 */ 1097 */
1140 WebInspector.animateFunction = function(window, func, params, frames, animationC omplete) 1098 WebInspector.animateFunction = function(window, func, params, frames, animationC omplete) {
1141 { 1099 var values = new Array(params.length);
1142 var values = new Array(params.length); 1100 var deltas = new Array(params.length);
1143 var deltas = new Array(params.length); 1101 for (var i = 0; i < params.length; ++i) {
1102 values[i] = params[i].from;
1103 deltas[i] = (params[i].to - params[i].from) / frames;
1104 }
1105
1106 var raf = window.requestAnimationFrame(animationStep);
1107
1108 var framesLeft = frames;
1109
1110 function animationStep() {
1111 if (--framesLeft < 0) {
1112 if (animationComplete)
1113 animationComplete();
1114 return;
1115 }
1144 for (var i = 0; i < params.length; ++i) { 1116 for (var i = 0; i < params.length; ++i) {
1145 values[i] = params[i].from; 1117 if (params[i].to > params[i].from)
1146 deltas[i] = (params[i].to - params[i].from) / frames; 1118 values[i] = Number.constrain(values[i] + deltas[i], params[i].from, para ms[i].to);
1119 else
1120 values[i] = Number.constrain(values[i] + deltas[i], params[i].to, params [i].from);
1147 } 1121 }
1122 func.apply(null, values);
1123 raf = window.requestAnimationFrame(animationStep);
1124 }
1148 1125
1149 var raf = window.requestAnimationFrame(animationStep); 1126 function cancelAnimation() {
1127 window.cancelAnimationFrame(raf);
1128 }
1150 1129
1151 var framesLeft = frames; 1130 return cancelAnimation;
1152
1153 function animationStep()
1154 {
1155 if (--framesLeft < 0) {
1156 if (animationComplete)
1157 animationComplete();
1158 return;
1159 }
1160 for (var i = 0; i < params.length; ++i) {
1161 if (params[i].to > params[i].from)
1162 values[i] = Number.constrain(values[i] + deltas[i], params[i].fr om, params[i].to);
1163 else
1164 values[i] = Number.constrain(values[i] + deltas[i], params[i].to , params[i].from);
1165 }
1166 func.apply(null, values);
1167 raf = window.requestAnimationFrame(animationStep);
1168 }
1169
1170 function cancelAnimation()
1171 {
1172 window.cancelAnimationFrame(raf);
1173 }
1174
1175 return cancelAnimation;
1176 }; 1131 };
1177 1132
1178 /** 1133 /**
1179 * @constructor 1134 * @unrestricted
1180 * @extends {WebInspector.Object}
1181 * @param {!Element} element
1182 * @param {function(!Event)} callback
1183 */ 1135 */
1184 WebInspector.LongClickController = function(element, callback) 1136 WebInspector.LongClickController = class extends WebInspector.Object {
1185 { 1137 /**
1138 * @param {!Element} element
1139 * @param {function(!Event)} callback
1140 */
1141 constructor(element, callback) {
1142 super();
1186 this._element = element; 1143 this._element = element;
1187 this._callback = callback; 1144 this._callback = callback;
1188 this._enable(); 1145 this._enable();
1189 }; 1146 }
1190 1147
1191 WebInspector.LongClickController.prototype = { 1148 reset() {
1192 reset: function() 1149 if (this._longClickInterval) {
1193 { 1150 clearInterval(this._longClickInterval);
1194 if (this._longClickInterval) { 1151 delete this._longClickInterval;
1195 clearInterval(this._longClickInterval); 1152 }
1196 delete this._longClickInterval; 1153 }
1197 }
1198 },
1199 1154
1200 _enable: function() 1155 _enable() {
1201 { 1156 if (this._longClickData)
1202 if (this._longClickData) 1157 return;
1203 return; 1158 var boundMouseDown = mouseDown.bind(this);
1204 var boundMouseDown = mouseDown.bind(this); 1159 var boundMouseUp = mouseUp.bind(this);
1205 var boundMouseUp = mouseUp.bind(this); 1160 var boundReset = this.reset.bind(this);
1206 var boundReset = this.reset.bind(this);
1207 1161
1208 this._element.addEventListener("mousedown", boundMouseDown, false); 1162 this._element.addEventListener('mousedown', boundMouseDown, false);
1209 this._element.addEventListener("mouseout", boundReset, false); 1163 this._element.addEventListener('mouseout', boundReset, false);
1210 this._element.addEventListener("mouseup", boundMouseUp, false); 1164 this._element.addEventListener('mouseup', boundMouseUp, false);
1211 this._element.addEventListener("click", boundReset, true); 1165 this._element.addEventListener('click', boundReset, true);
1212 1166
1213 this._longClickData = { mouseUp: boundMouseUp, mouseDown: boundMouseDown , reset: boundReset }; 1167 this._longClickData = {mouseUp: boundMouseUp, mouseDown: boundMouseDown, res et: boundReset};
1214 1168
1215 /** 1169 /**
1216 * @param {!Event} e 1170 * @param {!Event} e
1217 * @this {WebInspector.LongClickController} 1171 * @this {WebInspector.LongClickController}
1218 */ 1172 */
1219 function mouseDown(e) 1173 function mouseDown(e) {
1220 { 1174 if (e.which !== 1)
1221 if (e.which !== 1) 1175 return;
1222 return; 1176 var callback = this._callback;
1223 var callback = this._callback; 1177 this._longClickInterval = setTimeout(callback.bind(null, e), 200);
1224 this._longClickInterval = setTimeout(callback.bind(null, e), 200); 1178 }
1225 }
1226 1179
1227 /** 1180 /**
1228 * @param {!Event} e 1181 * @param {!Event} e
1229 * @this {WebInspector.LongClickController} 1182 * @this {WebInspector.LongClickController}
1230 */ 1183 */
1231 function mouseUp(e) 1184 function mouseUp(e) {
1232 { 1185 if (e.which !== 1)
1233 if (e.which !== 1) 1186 return;
1234 return; 1187 this.reset();
1235 this.reset(); 1188 }
1236 } 1189 }
1237 },
1238 1190
1239 dispose: function() 1191 dispose() {
1240 { 1192 if (!this._longClickData)
1241 if (!this._longClickData) 1193 return;
1242 return; 1194 this._element.removeEventListener('mousedown', this._longClickData.mouseDown , false);
1243 this._element.removeEventListener("mousedown", this._longClickData.mouse Down, false); 1195 this._element.removeEventListener('mouseout', this._longClickData.reset, fal se);
1244 this._element.removeEventListener("mouseout", this._longClickData.reset, false); 1196 this._element.removeEventListener('mouseup', this._longClickData.mouseUp, fa lse);
1245 this._element.removeEventListener("mouseup", this._longClickData.mouseUp , false); 1197 this._element.addEventListener('click', this._longClickData.reset, true);
1246 this._element.addEventListener("click", this._longClickData.reset, true) ; 1198 delete this._longClickData;
1247 delete this._longClickData; 1199 }
1248 },
1249
1250 __proto__: WebInspector.Object.prototype
1251 }; 1200 };
1252 1201
1253 /** 1202 /**
1254 * @param {!Document} document 1203 * @param {!Document} document
1255 * @param {!WebInspector.Setting} themeSetting 1204 * @param {!WebInspector.Setting} themeSetting
1256 */ 1205 */
1257 WebInspector.initializeUIUtils = function(document, themeSetting) 1206 WebInspector.initializeUIUtils = function(document, themeSetting) {
1258 { 1207 document.defaultView.addEventListener('focus', WebInspector._windowFocused.bin d(WebInspector, document), false);
1259 document.defaultView.addEventListener("focus", WebInspector._windowFocused.b ind(WebInspector, document), false); 1208 document.defaultView.addEventListener('blur', WebInspector._windowBlurred.bind (WebInspector, document), false);
1260 document.defaultView.addEventListener("blur", WebInspector._windowBlurred.bi nd(WebInspector, document), false); 1209 document.addEventListener('focus', WebInspector._focusChanged.bind(WebInspecto r), true);
1261 document.addEventListener("focus", WebInspector._focusChanged.bind(WebInspec tor), true);
1262 1210
1263 if (!WebInspector.themeSupport) 1211 if (!WebInspector.themeSupport)
1264 WebInspector.themeSupport = new WebInspector.ThemeSupport(themeSetting); 1212 WebInspector.themeSupport = new WebInspector.ThemeSupport(themeSetting);
1265 WebInspector.themeSupport.applyTheme(document); 1213 WebInspector.themeSupport.applyTheme(document);
1266 1214
1267 var body = /** @type {!Element} */ (document.body); 1215 var body = /** @type {!Element} */ (document.body);
1268 WebInspector.appendStyle(body, "ui/inspectorStyle.css"); 1216 WebInspector.appendStyle(body, 'ui/inspectorStyle.css');
1269 WebInspector.appendStyle(body, "ui/popover.css"); 1217 WebInspector.appendStyle(body, 'ui/popover.css');
1270 }; 1218 };
1271 1219
1272 /** 1220 /**
1273 * @param {string} name 1221 * @param {string} name
1274 * @return {string} 1222 * @return {string}
1275 */ 1223 */
1276 WebInspector.beautifyFunctionName = function(name) 1224 WebInspector.beautifyFunctionName = function(name) {
1277 { 1225 return name || WebInspector.UIString('(anonymous)');
1278 return name || WebInspector.UIString("(anonymous)");
1279 }; 1226 };
1280 1227
1281 /** 1228 /**
1282 * @param {string} localName 1229 * @param {string} localName
1283 * @param {string} typeExtension 1230 * @param {string} typeExtension
1284 * @param {!Object} prototype 1231 * @param {!Object} prototype
1285 * @return {function()} 1232 * @return {function()}
1286 * @suppressGlobalPropertiesCheck 1233 * @suppressGlobalPropertiesCheck
1287 * @template T 1234 * @template T
1288 */ 1235 */
1289 function registerCustomElement(localName, typeExtension, prototype) 1236 function registerCustomElement(localName, typeExtension, prototype) {
1290 { 1237 return document.registerElement(typeExtension, {prototype: Object.create(proto type), extends: localName});
1291 return document.registerElement(typeExtension, {
1292 prototype: Object.create(prototype),
1293 extends: localName
1294 });
1295 } 1238 }
1296 1239
1297 /** 1240 /**
1298 * @param {string} text 1241 * @param {string} text
1299 * @param {function(!Event)=} clickHandler 1242 * @param {function(!Event)=} clickHandler
1300 * @param {string=} className 1243 * @param {string=} className
1301 * @param {string=} title 1244 * @param {string=} title
1302 * @return {!Element} 1245 * @return {!Element}
1303 */ 1246 */
1304 function createTextButton(text, clickHandler, className, title) 1247 function createTextButton(text, clickHandler, className, title) {
1305 { 1248 var element = createElementWithClass('button', className || '', 'text-button') ;
1306 var element = createElementWithClass("button", className || "", "text-button "); 1249 element.textContent = text;
1307 element.textContent = text; 1250 if (clickHandler)
1308 if (clickHandler) 1251 element.addEventListener('click', clickHandler, false);
1309 element.addEventListener("click", clickHandler, false); 1252 if (title)
1310 if (title) 1253 element.title = title;
1311 element.title = title; 1254 return element;
1312 return element;
1313 } 1255 }
1314 1256
1315 /** 1257 /**
1316 * @param {string} name 1258 * @param {string} name
1317 * @param {string} title 1259 * @param {string} title
1318 * @param {boolean=} checked 1260 * @param {boolean=} checked
1319 * @return {!Element} 1261 * @return {!Element}
1320 */ 1262 */
1321 function createRadioLabel(name, title, checked) 1263 function createRadioLabel(name, title, checked) {
1322 { 1264 var element = createElement('label', 'dt-radio');
1323 var element = createElement("label", "dt-radio"); 1265 element.radioElement.name = name;
1324 element.radioElement.name = name; 1266 element.radioElement.checked = !!checked;
1325 element.radioElement.checked = !!checked; 1267 element.createTextChild(title);
1326 element.createTextChild(title); 1268 return element;
1327 return element;
1328 } 1269 }
1329 1270
1330 /** 1271 /**
1331 * @param {string} title 1272 * @param {string} title
1332 * @param {string} iconClass 1273 * @param {string} iconClass
1333 * @return {!Element} 1274 * @return {!Element}
1334 */ 1275 */
1335 function createLabel(title, iconClass) 1276 function createLabel(title, iconClass) {
1336 { 1277 var element = createElement('label', 'dt-icon-label');
1337 var element = createElement("label", "dt-icon-label"); 1278 element.createChild('span').textContent = title;
1338 element.createChild("span").textContent = title; 1279 element.type = iconClass;
1339 element.type = iconClass; 1280 return element;
1340 return element;
1341 } 1281 }
1342 1282
1343 /** 1283 /**
1344 * @param {string=} title 1284 * @param {string=} title
1345 * @param {boolean=} checked 1285 * @param {boolean=} checked
1346 * @param {string=} subtitle 1286 * @param {string=} subtitle
1347 * @return {!Element} 1287 * @return {!Element}
1348 */ 1288 */
1349 function createCheckboxLabel(title, checked, subtitle) 1289 function createCheckboxLabel(title, checked, subtitle) {
1350 { 1290 var element = createElement('label', 'dt-checkbox');
1351 var element = createElement("label", "dt-checkbox"); 1291 element.checkboxElement.checked = !!checked;
1352 element.checkboxElement.checked = !!checked; 1292 if (title !== undefined) {
1353 if (title !== undefined) { 1293 element.textElement = element.createChild('div', 'dt-checkbox-text');
1354 element.textElement = element.createChild("div", "dt-checkbox-text"); 1294 element.textElement.textContent = title;
1355 element.textElement.textContent = title; 1295 if (subtitle !== undefined) {
1356 if (subtitle !== undefined) { 1296 element.subtitleElement = element.textElement.createChild('div', 'dt-check box-subtitle');
1357 element.subtitleElement = element.textElement.createChild("div", "dt -checkbox-subtitle"); 1297 element.subtitleElement.textContent = subtitle;
1358 element.subtitleElement.textContent = subtitle;
1359 }
1360 } 1298 }
1361 return element; 1299 }
1300 return element;
1362 } 1301 }
1363 1302
1364 /** 1303 /**
1365 * @return {!Element} 1304 * @return {!Element}
1366 * @param {number} min 1305 * @param {number} min
1367 * @param {number} max 1306 * @param {number} max
1368 * @param {number} tabIndex 1307 * @param {number} tabIndex
1369 */ 1308 */
1370 function createSliderLabel(min, max, tabIndex) 1309 function createSliderLabel(min, max, tabIndex) {
1371 { 1310 var element = createElement('label', 'dt-slider');
1372 var element = createElement("label", "dt-slider"); 1311 element.sliderElement.min = min;
1373 element.sliderElement.min = min; 1312 element.sliderElement.max = max;
1374 element.sliderElement.max = max; 1313 element.sliderElement.step = 1;
1375 element.sliderElement.step = 1; 1314 element.sliderElement.tabIndex = tabIndex;
1376 element.sliderElement.tabIndex = tabIndex; 1315 return element;
1377 return element;
1378 } 1316 }
1379 1317
1380 /** 1318 /**
1381 * @param {!Node} node 1319 * @param {!Node} node
1382 * @param {string} cssFile 1320 * @param {string} cssFile
1383 * @suppressGlobalPropertiesCheck 1321 * @suppressGlobalPropertiesCheck
1384 */ 1322 */
1385 WebInspector.appendStyle = function(node, cssFile) 1323 WebInspector.appendStyle =
1386 { 1324 function(node, cssFile) {
1387 var content = Runtime.cachedResources[cssFile] || ""; 1325 var content = Runtime.cachedResources[cssFile] || '';
1388 if (!content) 1326 if (!content)
1389 console.error(cssFile + " not preloaded. Check module.json"); 1327 console.error(cssFile + ' not preloaded. Check module.json');
1390 var styleElement = createElement("style"); 1328 var styleElement = createElement('style');
1391 styleElement.type = "text/css"; 1329 styleElement.type = 'text/css';
1392 styleElement.textContent = content; 1330 styleElement.textContent = content;
1331 node.appendChild(styleElement);
1332
1333 var themeStyleSheet = WebInspector.themeSupport.themeStyleSheet(cssFile, conte nt);
1334 if (themeStyleSheet) {
1335 styleElement = createElement('style');
1336 styleElement.type = 'text/css';
1337 styleElement.textContent = themeStyleSheet + '\n' + Runtime.resolveSourceURL (cssFile + '.theme');
1393 node.appendChild(styleElement); 1338 node.appendChild(styleElement);
1394 1339 }
1395 var themeStyleSheet = WebInspector.themeSupport.themeStyleSheet(cssFile, con tent);
1396 if (themeStyleSheet) {
1397 styleElement = createElement("style");
1398 styleElement.type = "text/css";
1399 styleElement.textContent = themeStyleSheet + "\n" + Runtime.resolveSourc eURL(cssFile + ".theme");
1400 node.appendChild(styleElement);
1401 }
1402 } 1340 }
1403 1341
1404 ;(function() { 1342 ;
1405 registerCustomElement("button", "text-button", { 1343 (function() {
1406 /** 1344 registerCustomElement('button', 'text-button', {
1407 * @this {Element} 1345 /**
1408 */ 1346 * @this {Element}
1409 createdCallback: function() 1347 */
1410 { 1348 createdCallback: function() {
1411 this.type = "button"; 1349 this.type = 'button';
1412 var root = WebInspector.createShadowRootWithCoreStyles(this, "ui/tex tButton.css"); 1350 var root = WebInspector.createShadowRootWithCoreStyles(this, 'ui/textButto n.css');
1413 root.createChild("content"); 1351 root.createChild('content');
1414 }, 1352 },
1415 1353
1416 __proto__: HTMLButtonElement.prototype 1354 __proto__: HTMLButtonElement.prototype
1417 }); 1355 });
1418 1356
1419 registerCustomElement("label", "dt-radio", { 1357 registerCustomElement('label', 'dt-radio', {
1420 /** 1358 /**
1421 * @this {Element} 1359 * @this {Element}
1422 */ 1360 */
1423 createdCallback: function() 1361 createdCallback: function() {
1424 { 1362 this.radioElement = this.createChild('input', 'dt-radio-button');
1425 this.radioElement = this.createChild("input", "dt-radio-button"); 1363 this.radioElement.type = 'radio';
1426 this.radioElement.type = "radio"; 1364 var root = WebInspector.createShadowRootWithCoreStyles(this, 'ui/radioButt on.css');
1427 var root = WebInspector.createShadowRootWithCoreStyles(this, "ui/rad ioButton.css"); 1365 root.createChild('content').select = '.dt-radio-button';
1428 root.createChild("content").select = ".dt-radio-button"; 1366 root.createChild('content');
1429 root.createChild("content"); 1367 this.addEventListener('click', radioClickHandler, false);
1430 this.addEventListener("click", radioClickHandler, false); 1368 },
1431 }, 1369
1432 1370 __proto__: HTMLLabelElement.prototype
1433 __proto__: HTMLLabelElement.prototype 1371 });
1434 }); 1372
1435 1373 /**
1436 /** 1374 * @param {!Event} event
1437 * @param {!Event} event 1375 * @suppressReceiverCheck
1438 * @suppressReceiverCheck 1376 * @this {Element}
1439 * @this {Element} 1377 */
1440 */ 1378 function radioClickHandler(event) {
1441 function radioClickHandler(event) 1379 if (this.radioElement.checked || this.radioElement.disabled)
1442 { 1380 return;
1443 if (this.radioElement.checked || this.radioElement.disabled) 1381 this.radioElement.checked = true;
1444 return; 1382 this.radioElement.dispatchEvent(new Event('change'));
1445 this.radioElement.checked = true; 1383 }
1446 this.radioElement.dispatchEvent(new Event("change")); 1384
1447 } 1385 registerCustomElement('label', 'dt-checkbox', {
1448 1386 /**
1449 registerCustomElement("label", "dt-checkbox", { 1387 * @this {Element}
1450 /** 1388 */
1451 * @this {Element} 1389 createdCallback: function() {
1452 */ 1390 this._root = WebInspector.createShadowRootWithCoreStyles(this, 'ui/checkbo xTextLabel.css');
1453 createdCallback: function() 1391 var checkboxElement = createElementWithClass('input', 'dt-checkbox-button' );
1454 { 1392 checkboxElement.type = 'checkbox';
1455 this._root = WebInspector.createShadowRootWithCoreStyles(this, "ui/c heckboxTextLabel.css"); 1393 this._root.appendChild(checkboxElement);
1456 var checkboxElement = createElementWithClass("input", "dt-checkbox-b utton"); 1394 this.checkboxElement = checkboxElement;
1457 checkboxElement.type = "checkbox"; 1395
1458 this._root.appendChild(checkboxElement); 1396 this.addEventListener('click', toggleCheckbox.bind(this));
1459 this.checkboxElement = checkboxElement; 1397
1460 1398 /**
1461 this.addEventListener("click", toggleCheckbox.bind(this)); 1399 * @param {!Event} event
1462 1400 * @this {Node}
1463 /** 1401 */
1464 * @param {!Event} event 1402 function toggleCheckbox(event) {
1465 * @this {Node} 1403 if (event.target !== checkboxElement && event.target !== this) {
1466 */ 1404 event.consume();
1467 function toggleCheckbox(event) 1405 checkboxElement.click();
1468 { 1406 }
1469 if (event.target !== checkboxElement && event.target !== this) { 1407 }
1470 event.consume(); 1408
1471 checkboxElement.click(); 1409 this._root.createChild('content');
1472 } 1410 },
1473 } 1411
1474 1412 /**
1475 this._root.createChild("content"); 1413 * @param {string} color
1476 }, 1414 * @this {Element}
1477 1415 */
1478 /** 1416 set backgroundColor(color) {
1479 * @param {string} color 1417 this.checkboxElement.classList.add('dt-checkbox-themed');
1480 * @this {Element} 1418 this.checkboxElement.style.backgroundColor = color;
1481 */ 1419 },
1482 set backgroundColor(color) 1420
1483 { 1421 /**
1484 this.checkboxElement.classList.add("dt-checkbox-themed"); 1422 * @param {string} color
1485 this.checkboxElement.style.backgroundColor = color; 1423 * @this {Element}
1486 }, 1424 */
1487 1425 set checkColor(color) {
1488 /** 1426 this.checkboxElement.classList.add('dt-checkbox-themed');
1489 * @param {string} color 1427 var stylesheet = createElement('style');
1490 * @this {Element} 1428 stylesheet.textContent = 'input.dt-checkbox-themed:checked:after { backgro und-color: ' + color + '}';
1491 */ 1429 this._root.appendChild(stylesheet);
1492 set checkColor(color) 1430 },
1493 { 1431
1494 this.checkboxElement.classList.add("dt-checkbox-themed"); 1432 /**
1495 var stylesheet = createElement("style"); 1433 * @param {string} color
1496 stylesheet.textContent = "input.dt-checkbox-themed:checked:after { b ackground-color: " + color + "}"; 1434 * @this {Element}
1497 this._root.appendChild(stylesheet); 1435 */
1498 }, 1436 set borderColor(color) {
1499 1437 this.checkboxElement.classList.add('dt-checkbox-themed');
1500 /** 1438 this.checkboxElement.style.borderColor = color;
1501 * @param {string} color 1439 },
1502 * @this {Element} 1440
1503 */ 1441 /**
1504 set borderColor(color) 1442 * @param {boolean} focus
1505 { 1443 * @this {Element}
1506 this.checkboxElement.classList.add("dt-checkbox-themed"); 1444 */
1507 this.checkboxElement.style.borderColor = color; 1445 set visualizeFocus(focus) {
1508 }, 1446 this.checkboxElement.classList.toggle('dt-checkbox-visualize-focus', focus );
1509 1447 },
1510 /** 1448
1511 * @param {boolean} focus 1449 __proto__: HTMLLabelElement.prototype
1512 * @this {Element} 1450 });
1513 */ 1451
1514 set visualizeFocus(focus) 1452 registerCustomElement('label', 'dt-icon-label', {
1515 { 1453 /**
1516 this.checkboxElement.classList.toggle("dt-checkbox-visualize-focus", focus); 1454 * @this {Element}
1517 }, 1455 */
1518 1456 createdCallback: function() {
1519 __proto__: HTMLLabelElement.prototype 1457 var root = WebInspector.createShadowRootWithCoreStyles(this, 'ui/smallIcon .css');
1520 }); 1458 this._iconElement = root.createChild('div');
1521 1459 root.createChild('content');
1522 registerCustomElement("label", "dt-icon-label", { 1460 },
1523 /** 1461
1524 * @this {Element} 1462 /**
1525 */ 1463 * @param {string} type
1526 createdCallback: function() 1464 * @this {Element}
1527 { 1465 */
1528 var root = WebInspector.createShadowRootWithCoreStyles(this, "ui/sma llIcon.css"); 1466 set type(type) {
1529 this._iconElement = root.createChild("div"); 1467 this._iconElement.className = type;
1530 root.createChild("content"); 1468 },
1531 }, 1469
1532 1470 __proto__: HTMLLabelElement.prototype
1533 /** 1471 });
1534 * @param {string} type 1472
1535 * @this {Element} 1473 registerCustomElement('label', 'dt-slider', {
1536 */ 1474 /**
1537 set type(type) 1475 * @this {Element}
1538 { 1476 */
1539 this._iconElement.className = type; 1477 createdCallback: function() {
1540 }, 1478 var root = WebInspector.createShadowRootWithCoreStyles(this, 'ui/slider.cs s');
1541 1479 this.sliderElement = createElementWithClass('input', 'dt-range-input');
1542 __proto__: HTMLLabelElement.prototype 1480 this.sliderElement.type = 'range';
1543 }); 1481 root.appendChild(this.sliderElement);
1544 1482 },
1545 registerCustomElement("label", "dt-slider", { 1483
1546 /** 1484 /**
1547 * @this {Element} 1485 * @param {number} amount
1548 */ 1486 * @this {Element}
1549 createdCallback: function() 1487 */
1550 { 1488 set value(amount) {
1551 var root = WebInspector.createShadowRootWithCoreStyles(this, "ui/sli der.css"); 1489 this.sliderElement.value = amount;
1552 this.sliderElement = createElementWithClass("input", "dt-range-input "); 1490 },
1553 this.sliderElement.type = "range"; 1491
1554 root.appendChild(this.sliderElement); 1492 /**
1555 }, 1493 * @this {Element}
1556 1494 */
1557 /** 1495 get value() {
1558 * @param {number} amount 1496 return this.sliderElement.value;
1559 * @this {Element} 1497 },
1560 */ 1498
1561 set value(amount) 1499 __proto__: HTMLLabelElement.prototype
1562 { 1500 });
1563 this.sliderElement.value = amount; 1501
1564 }, 1502 registerCustomElement('label', 'dt-small-bubble', {
1565 1503 /**
1566 /** 1504 * @this {Element}
1567 * @this {Element} 1505 */
1568 */ 1506 createdCallback: function() {
1569 get value() 1507 var root = WebInspector.createShadowRootWithCoreStyles(this, 'ui/smallBubb le.css');
1570 { 1508 this._textElement = root.createChild('div');
1571 return this.sliderElement.value; 1509 this._textElement.className = 'info';
1572 }, 1510 this._textElement.createChild('content');
1573 1511 },
1574 __proto__: HTMLLabelElement.prototype 1512
1575 }); 1513 /**
1576 1514 * @param {string} type
1577 registerCustomElement("label", "dt-small-bubble", { 1515 * @this {Element}
1578 /** 1516 */
1579 * @this {Element} 1517 set type(type) {
1580 */ 1518 this._textElement.className = type;
1581 createdCallback: function() 1519 },
1582 { 1520
1583 var root = WebInspector.createShadowRootWithCoreStyles(this, "ui/sma llBubble.css"); 1521 __proto__: HTMLLabelElement.prototype
1584 this._textElement = root.createChild("div"); 1522 });
1585 this._textElement.className = "info"; 1523
1586 this._textElement.createChild("content"); 1524 registerCustomElement('div', 'dt-close-button', {
1587 }, 1525 /**
1588 1526 * @this {Element}
1589 /** 1527 */
1590 * @param {string} type 1528 createdCallback: function() {
1591 * @this {Element} 1529 var root = WebInspector.createShadowRootWithCoreStyles(this, 'ui/closeButt on.css');
1592 */ 1530 this._buttonElement = root.createChild('div', 'close-button');
1593 set type(type) 1531 },
1594 { 1532
1595 this._textElement.className = type; 1533 /**
1596 }, 1534 * @param {boolean} gray
1597 1535 * @this {Element}
1598 __proto__: HTMLLabelElement.prototype 1536 */
1599 }); 1537 set gray(gray) {
1600 1538 this._buttonElement.className = gray ? 'close-button-gray' : 'close-button ';
1601 registerCustomElement("div", "dt-close-button", { 1539 },
1602 /** 1540
1603 * @this {Element} 1541 __proto__: HTMLDivElement.prototype
1604 */ 1542 });
1605 createdCallback: function()
1606 {
1607 var root = WebInspector.createShadowRootWithCoreStyles(this, "ui/clo seButton.css");
1608 this._buttonElement = root.createChild("div", "close-button");
1609 },
1610
1611 /**
1612 * @param {boolean} gray
1613 * @this {Element}
1614 */
1615 set gray(gray)
1616 {
1617 this._buttonElement.className = gray ? "close-button-gray" : "close- button";
1618 },
1619
1620 __proto__: HTMLDivElement.prototype
1621 });
1622 })(); 1543 })();
1623 1544
1624 /** 1545 /**
1625 * @param {!Element} input 1546 * @param {!Element} input
1626 * @param {function(string)} apply 1547 * @param {function(string)} apply
1627 * @param {function(string):boolean} validate 1548 * @param {function(string):boolean} validate
1628 * @param {boolean} numeric 1549 * @param {boolean} numeric
1629 * @return {function(string)} 1550 * @return {function(string)}
1630 */ 1551 */
1631 WebInspector.bindInput = function(input, apply, validate, numeric) 1552 WebInspector.bindInput = function(input, apply, validate, numeric) {
1632 { 1553 input.addEventListener('change', onChange, false);
1633 input.addEventListener("change", onChange, false); 1554 input.addEventListener('input', onInput, false);
1634 input.addEventListener("input", onInput, false); 1555 input.addEventListener('keydown', onKeyDown, false);
1635 input.addEventListener("keydown", onKeyDown, false); 1556 input.addEventListener('focus', input.select.bind(input), false);
1636 input.addEventListener("focus", input.select.bind(input), false); 1557
1637 1558 function onInput() {
1638 function onInput() 1559 input.classList.toggle('error-input', !validate(input.value));
1639 { 1560 }
1640 input.classList.toggle("error-input", !validate(input.value)); 1561
1562 function onChange() {
1563 var valid = validate(input.value);
1564 input.classList.toggle('error-input', !valid);
1565 if (valid)
1566 apply(input.value);
1567 }
1568
1569 /**
1570 * @param {!Event} event
1571 */
1572 function onKeyDown(event) {
1573 if (isEnterKey(event)) {
1574 if (validate(input.value))
1575 apply(input.value);
1576 return;
1641 } 1577 }
1642 1578
1643 function onChange() 1579 if (!numeric)
1644 { 1580 return;
1645 var valid = validate(input.value); 1581
1646 input.classList.toggle("error-input", !valid); 1582 var increment = event.key === 'ArrowUp' ? 1 : event.key === 'ArrowDown' ? -1 : 0;
1647 if (valid) 1583 if (!increment)
1648 apply(input.value); 1584 return;
1649 } 1585 if (event.shiftKey)
1650 1586 increment *= 10;
1651 /** 1587
1652 * @param {!Event} event 1588 var value = input.value;
1653 */ 1589 if (!validate(value) || !value)
1654 function onKeyDown(event) 1590 return;
1655 { 1591
1656 if (isEnterKey(event)) { 1592 value = (value ? Number(value) : 0) + increment;
1657 if (validate(input.value)) 1593 var stringValue = value ? String(value) : '';
1658 apply(input.value); 1594 if (!validate(stringValue) || !value)
1659 return; 1595 return;
1660 } 1596
1661 1597 input.value = stringValue;
1662 if (!numeric) 1598 apply(input.value);
1663 return; 1599 event.preventDefault();
1664 1600 }
1665 var increment = event.key === "ArrowUp" ? 1 : event.key === "ArrowDown" ? -1 : 0; 1601
1666 if (!increment) 1602 /**
1667 return; 1603 * @param {string} value
1668 if (event.shiftKey) 1604 */
1669 increment *= 10; 1605 function setValue(value) {
1670 1606 if (value === input.value)
1671 var value = input.value; 1607 return;
1672 if (!validate(value) || !value) 1608 var valid = validate(value);
1673 return; 1609 input.classList.toggle('error-input', !valid);
1674 1610 input.value = value;
1675 value = (value ? Number(value) : 0) + increment; 1611 }
1676 var stringValue = value ? String(value) : ""; 1612
1677 if (!validate(stringValue) || !value) 1613 return setValue;
1678 return;
1679
1680 input.value = stringValue;
1681 apply(input.value);
1682 event.preventDefault();
1683 }
1684
1685 /**
1686 * @param {string} value
1687 */
1688 function setValue(value)
1689 {
1690 if (value === input.value)
1691 return;
1692 var valid = validate(value);
1693 input.classList.toggle("error-input", !valid);
1694 input.value = value;
1695 }
1696
1697 return setValue;
1698 }; 1614 };
1699 1615
1700 /** 1616 /**
1701 * @constructor 1617 * @unrestricted
1702 * @param {!WebInspector.Setting} setting
1703 */ 1618 */
1704 WebInspector.ThemeSupport = function(setting) 1619 WebInspector.ThemeSupport = class {
1705 { 1620 /**
1706 this._themeName = setting.get() || "default"; 1621 * @param {!WebInspector.Setting} setting
1622 */
1623 constructor(setting) {
1624 this._themeName = setting.get() || 'default';
1707 this._themableProperties = new Set([ 1625 this._themableProperties = new Set([
1708 "color", "box-shadow", "text-shadow", "outline-color", 1626 'color', 'box-shadow', 'text-shadow', 'outline-color', 'background-image', 'background-color',
1709 "background-image", "background-color", 1627 'border-left-color', 'border-right-color', 'border-top-color', 'border-bot tom-color', '-webkit-border-image'
1710 "border-left-color", "border-right-color", "border-top-color", "border-b ottom-color", 1628 ]);
1711 "-webkit-border-image"]);
1712 /** @type {!Map<string, string>} */ 1629 /** @type {!Map<string, string>} */
1713 this._cachedThemePatches = new Map(); 1630 this._cachedThemePatches = new Map();
1714 this._setting = setting; 1631 this._setting = setting;
1632 }
1633
1634 /**
1635 * @return {boolean}
1636 */
1637 hasTheme() {
1638 return this._themeName !== 'default';
1639 }
1640
1641 /**
1642 * @return {string}
1643 */
1644 themeName() {
1645 return this._themeName;
1646 }
1647
1648 /**
1649 * @param {!Element} element
1650 */
1651 injectHighlightStyleSheets(element) {
1652 this._injectingStyleSheet = true;
1653 WebInspector.appendStyle(element, 'ui/inspectorSyntaxHighlight.css');
1654 if (this._themeName === 'dark')
1655 WebInspector.appendStyle(element, 'ui/inspectorSyntaxHighlightDark.css');
1656 this._injectingStyleSheet = false;
1657 }
1658
1659 /**
1660 * @param {!Document} document
1661 */
1662 applyTheme(document) {
1663 if (!this.hasTheme())
1664 return;
1665
1666 if (this._themeName === 'dark')
1667 document.body.classList.add('-theme-with-dark-background');
1668
1669 var styleSheets = document.styleSheets;
1670 var result = [];
1671 for (var i = 0; i < styleSheets.length; ++i)
1672 result.push(this._patchForTheme(styleSheets[i].href, styleSheets[i]));
1673 result.push('/*# sourceURL=inspector.css.theme */');
1674
1675 var styleElement = createElement('style');
1676 styleElement.type = 'text/css';
1677 styleElement.textContent = result.join('\n');
1678 document.head.appendChild(styleElement);
1679 }
1680
1681 /**
1682 * @param {string} id
1683 * @param {string} text
1684 * @return {string}
1685 * @suppressGlobalPropertiesCheck
1686 */
1687 themeStyleSheet(id, text) {
1688 if (!this.hasTheme() || this._injectingStyleSheet)
1689 return '';
1690
1691 var patch = this._cachedThemePatches.get(id);
1692 if (!patch) {
1693 var styleElement = createElement('style');
1694 styleElement.type = 'text/css';
1695 styleElement.textContent = text;
1696 document.body.appendChild(styleElement);
1697 patch = this._patchForTheme(id, styleElement.sheet);
1698 document.body.removeChild(styleElement);
1699 }
1700 return patch;
1701 }
1702
1703 /**
1704 * @param {string} id
1705 * @param {!StyleSheet} styleSheet
1706 * @return {string}
1707 */
1708 _patchForTheme(id, styleSheet) {
1709 var cached = this._cachedThemePatches.get(id);
1710 if (cached)
1711 return cached;
1712
1713 try {
1714 var rules = styleSheet.cssRules;
1715 var result = [];
1716 for (var j = 0; j < rules.length; ++j) {
1717 if (rules[j] instanceof CSSImportRule) {
1718 result.push(this._patchForTheme(rules[j].styleSheet.href, rules[j].sty leSheet));
1719 continue;
1720 }
1721 var output = [];
1722 var style = rules[j].style;
1723 var selectorText = rules[j].selectorText;
1724 for (var i = 0; style && i < style.length; ++i)
1725 this._patchProperty(selectorText, style, style[i], output);
1726 if (output.length)
1727 result.push(rules[j].selectorText + '{' + output.join('') + '}');
1728 }
1729
1730 var fullText = result.join('\n');
1731 this._cachedThemePatches.set(id, fullText);
1732 return fullText;
1733 } catch (e) {
1734 this._setting.set('default');
1735 return '';
1736 }
1737 }
1738
1739 /**
1740 * @param {string} selectorText
1741 * @param {!CSSStyleDeclaration} style
1742 * @param {string} name
1743 * @param {!Array<string>} output
1744 *
1745 * Theming API is primarily targeted at making dark theme look good.
1746 * - If rule has ".-theme-preserve" in selector, it won't be affected.
1747 * - If rule has ".selection" or "selected" or "-theme-selection-color" in sel ector, its hue is rotated 180deg in dark themes.
1748 * - One can create specializations for dark themes via body.-theme-with-dark- background selector in host context.
1749 */
1750 _patchProperty(selectorText, style, name, output) {
1751 if (!this._themableProperties.has(name))
1752 return;
1753
1754 var value = style.getPropertyValue(name);
1755 if (!value || value === 'none' || value === 'inherit' || value === 'initial' || value === 'transparent')
1756 return;
1757 if (name === 'background-image' && value.indexOf('gradient') === -1)
1758 return;
1759
1760 var isSelection = selectorText.indexOf('.-theme-selection-color') !== -1;
1761 if (selectorText.indexOf('-theme-') !== -1 && !isSelection)
1762 return;
1763
1764 if (name === '-webkit-border-image') {
1765 output.push('-webkit-filter: invert(100%)');
1766 return;
1767 }
1768
1769 isSelection = isSelection || selectorText.indexOf('selected') !== -1 || sele ctorText.indexOf('.selection') !== -1;
1770 var colorUsage = WebInspector.ThemeSupport.ColorUsage.Unknown;
1771 if (isSelection)
1772 colorUsage |= WebInspector.ThemeSupport.ColorUsage.Selection;
1773 if (name.indexOf('background') === 0 || name.indexOf('border') === 0)
1774 colorUsage |= WebInspector.ThemeSupport.ColorUsage.Background;
1775 if (name.indexOf('background') === -1)
1776 colorUsage |= WebInspector.ThemeSupport.ColorUsage.Foreground;
1777
1778 output.push(name);
1779 output.push(':');
1780 var items = value.replace(WebInspector.Color.Regex, '\0$1\0').split('\0');
1781 for (var i = 0; i < items.length; ++i)
1782 output.push(this.patchColor(items[i], colorUsage));
1783 if (style.getPropertyPriority(name))
1784 output.push(' !important');
1785 output.push(';');
1786 }
1787
1788 /**
1789 * @param {string} text
1790 * @param {!WebInspector.ThemeSupport.ColorUsage} colorUsage
1791 * @return {string}
1792 */
1793 patchColor(text, colorUsage) {
1794 var color = WebInspector.Color.parse(text);
1795 if (!color)
1796 return text;
1797
1798 var hsla = color.hsla();
1799 this._patchHSLA(hsla, colorUsage);
1800 var rgba = [];
1801 WebInspector.Color.hsl2rgb(hsla, rgba);
1802 var outColor = new WebInspector.Color(rgba, color.format());
1803 var outText = outColor.asString(null);
1804 if (!outText)
1805 outText = outColor.asString(outColor.hasAlpha() ? WebInspector.Color.Forma t.RGBA : WebInspector.Color.Format.RGB);
1806 return outText || text;
1807 }
1808
1809 /**
1810 * @param {!Array<number>} hsla
1811 * @param {!WebInspector.ThemeSupport.ColorUsage} colorUsage
1812 */
1813 _patchHSLA(hsla, colorUsage) {
1814 var hue = hsla[0];
1815 var sat = hsla[1];
1816 var lit = hsla[2];
1817 var alpha = hsla[3];
1818
1819 switch (this._themeName) {
1820 case 'dark':
1821 if (colorUsage & WebInspector.ThemeSupport.ColorUsage.Selection)
1822 hue = (hue + 0.5) % 1;
1823 var minCap = colorUsage & WebInspector.ThemeSupport.ColorUsage.Backgroun d ? 0.14 : 0;
1824 var maxCap = colorUsage & WebInspector.ThemeSupport.ColorUsage.Foregroun d ? 0.9 : 1;
1825 lit = 1 - lit;
1826 if (lit < minCap * 2)
1827 lit = minCap + lit / 2;
1828 else if (lit > 2 * maxCap - 1)
1829 lit = maxCap - 1 / 2 + lit / 2;
1830
1831 break;
1832 }
1833 hsla[0] = Number.constrain(hue, 0, 1);
1834 hsla[1] = Number.constrain(sat, 0, 1);
1835 hsla[2] = Number.constrain(lit, 0, 1);
1836 hsla[3] = Number.constrain(alpha, 0, 1);
1837 }
1715 }; 1838 };
1716 1839
1717 /** 1840 /**
1718 * @enum {number} 1841 * @enum {number}
1719 */ 1842 */
1720 WebInspector.ThemeSupport.ColorUsage = { 1843 WebInspector.ThemeSupport.ColorUsage = {
1721 Unknown: 0, 1844 Unknown: 0,
1722 Foreground: 1 << 0, 1845 Foreground: 1 << 0,
1723 Background: 1 << 1, 1846 Background: 1 << 1,
1724 Selection: 1 << 2, 1847 Selection: 1 << 2,
1725 }; 1848 };
1726 1849
1727 WebInspector.ThemeSupport.prototype = {
1728 /**
1729 * @return {boolean}
1730 */
1731 hasTheme: function()
1732 {
1733 return this._themeName !== "default";
1734 },
1735
1736 /**
1737 * @return {string}
1738 */
1739 themeName: function()
1740 {
1741 return this._themeName;
1742 },
1743
1744 /**
1745 * @param {!Element} element
1746 */
1747 injectHighlightStyleSheets: function(element)
1748 {
1749 this._injectingStyleSheet = true;
1750 WebInspector.appendStyle(element, "ui/inspectorSyntaxHighlight.css");
1751 if (this._themeName === "dark")
1752 WebInspector.appendStyle(element, "ui/inspectorSyntaxHighlightDark.c ss");
1753 this._injectingStyleSheet = false;
1754 },
1755
1756 /**
1757 * @param {!Document} document
1758 */
1759 applyTheme: function(document)
1760 {
1761 if (!this.hasTheme())
1762 return;
1763
1764 if (this._themeName === "dark")
1765 document.body.classList.add("-theme-with-dark-background");
1766
1767 var styleSheets = document.styleSheets;
1768 var result = [];
1769 for (var i = 0; i < styleSheets.length; ++i)
1770 result.push(this._patchForTheme(styleSheets[i].href, styleSheets[i]) );
1771 result.push("/*# sourceURL=inspector.css.theme */");
1772
1773 var styleElement = createElement("style");
1774 styleElement.type = "text/css";
1775 styleElement.textContent = result.join("\n");
1776 document.head.appendChild(styleElement);
1777 },
1778
1779 /**
1780 * @param {string} id
1781 * @param {string} text
1782 * @return {string}
1783 * @suppressGlobalPropertiesCheck
1784 */
1785 themeStyleSheet: function(id, text)
1786 {
1787 if (!this.hasTheme() || this._injectingStyleSheet)
1788 return "";
1789
1790 var patch = this._cachedThemePatches.get(id);
1791 if (!patch) {
1792 var styleElement = createElement("style");
1793 styleElement.type = "text/css";
1794 styleElement.textContent = text;
1795 document.body.appendChild(styleElement);
1796 patch = this._patchForTheme(id, styleElement.sheet);
1797 document.body.removeChild(styleElement);
1798 }
1799 return patch;
1800 },
1801
1802 /**
1803 * @param {string} id
1804 * @param {!StyleSheet} styleSheet
1805 * @return {string}
1806 */
1807 _patchForTheme: function(id, styleSheet)
1808 {
1809 var cached = this._cachedThemePatches.get(id);
1810 if (cached)
1811 return cached;
1812
1813 try {
1814 var rules = styleSheet.cssRules;
1815 var result = [];
1816 for (var j = 0; j < rules.length; ++j) {
1817 if (rules[j] instanceof CSSImportRule) {
1818 result.push(this._patchForTheme(rules[j].styleSheet.href, ru les[j].styleSheet));
1819 continue;
1820 }
1821 var output = [];
1822 var style = rules[j].style;
1823 var selectorText = rules[j].selectorText;
1824 for (var i = 0; style && i < style.length; ++i)
1825 this._patchProperty(selectorText, style, style[i], output);
1826 if (output.length)
1827 result.push(rules[j].selectorText + "{" + output.join("") + "}");
1828 }
1829
1830 var fullText = result.join("\n");
1831 this._cachedThemePatches.set(id, fullText);
1832 return fullText;
1833 } catch (e) {
1834 this._setting.set("default");
1835 return "";
1836 }
1837 },
1838
1839 /**
1840 * @param {string} selectorText
1841 * @param {!CSSStyleDeclaration} style
1842 * @param {string} name
1843 * @param {!Array<string>} output
1844 *
1845 * Theming API is primarily targeted at making dark theme look good.
1846 * - If rule has ".-theme-preserve" in selector, it won't be affected.
1847 * - If rule has ".selection" or "selected" or "-theme-selection-color" in s elector, its hue is rotated 180deg in dark themes.
1848 * - One can create specializations for dark themes via body.-theme-with-dar k-background selector in host context.
1849 */
1850 _patchProperty: function(selectorText, style, name, output)
1851 {
1852 if (!this._themableProperties.has(name))
1853 return;
1854
1855 var value = style.getPropertyValue(name);
1856 if (!value || value === "none" || value === "inherit" || value === "init ial" || value === "transparent")
1857 return;
1858 if (name === "background-image" && value.indexOf("gradient") === -1)
1859 return;
1860
1861 var isSelection = selectorText.indexOf(".-theme-selection-color") !== -1 ;
1862 if (selectorText.indexOf("-theme-") !== -1 && !isSelection)
1863 return;
1864
1865 if (name === "-webkit-border-image") {
1866 output.push("-webkit-filter: invert(100%)");
1867 return;
1868 }
1869
1870 isSelection = isSelection || selectorText.indexOf("selected") !== -1 || selectorText.indexOf(".selection") !== -1;
1871 var colorUsage = WebInspector.ThemeSupport.ColorUsage.Unknown;
1872 if (isSelection)
1873 colorUsage |= WebInspector.ThemeSupport.ColorUsage.Selection;
1874 if (name.indexOf("background") === 0 || name.indexOf("border") === 0)
1875 colorUsage |= WebInspector.ThemeSupport.ColorUsage.Background;
1876 if (name.indexOf("background") === -1)
1877 colorUsage |= WebInspector.ThemeSupport.ColorUsage.Foreground;
1878
1879 output.push(name);
1880 output.push(":");
1881 var items = value.replace(WebInspector.Color.Regex, "\0$1\0").split("\0" );
1882 for (var i = 0; i < items.length; ++i)
1883 output.push(this.patchColor(items[i], colorUsage));
1884 if (style.getPropertyPriority(name))
1885 output.push(" !important");
1886 output.push(";");
1887 },
1888
1889 /**
1890 * @param {string} text
1891 * @param {!WebInspector.ThemeSupport.ColorUsage} colorUsage
1892 * @return {string}
1893 */
1894 patchColor: function(text, colorUsage)
1895 {
1896 var color = WebInspector.Color.parse(text);
1897 if (!color)
1898 return text;
1899
1900 var hsla = color.hsla();
1901 this._patchHSLA(hsla, colorUsage);
1902 var rgba = [];
1903 WebInspector.Color.hsl2rgb(hsla, rgba);
1904 var outColor = new WebInspector.Color(rgba, color.format());
1905 var outText = outColor.asString(null);
1906 if (!outText)
1907 outText = outColor.asString(outColor.hasAlpha() ? WebInspector.Color .Format.RGBA : WebInspector.Color.Format.RGB);
1908 return outText || text;
1909 },
1910
1911 /**
1912 * @param {!Array<number>} hsla
1913 * @param {!WebInspector.ThemeSupport.ColorUsage} colorUsage
1914 */
1915 _patchHSLA: function(hsla, colorUsage)
1916 {
1917 var hue = hsla[0];
1918 var sat = hsla[1];
1919 var lit = hsla[2];
1920 var alpha = hsla[3];
1921
1922 switch (this._themeName) {
1923 case "dark":
1924 if (colorUsage & WebInspector.ThemeSupport.ColorUsage.Selection)
1925 hue = (hue + 0.5) % 1;
1926 var minCap = colorUsage & WebInspector.ThemeSupport.ColorUsage.Backg round ? 0.14 : 0;
1927 var maxCap = colorUsage & WebInspector.ThemeSupport.ColorUsage.Foreg round ? 0.9 : 1;
1928 lit = 1 - lit;
1929 if (lit < minCap * 2)
1930 lit = minCap + lit / 2;
1931 else if (lit > 2 * maxCap - 1)
1932 lit = maxCap - 1 / 2 + lit / 2;
1933
1934 break;
1935 }
1936 hsla[0] = Number.constrain(hue, 0, 1);
1937 hsla[1] = Number.constrain(sat, 0, 1);
1938 hsla[2] = Number.constrain(lit, 0, 1);
1939 hsla[3] = Number.constrain(alpha, 0, 1);
1940 }
1941 };
1942
1943 /** 1850 /**
1944 * @param {string} url 1851 * @param {string} url
1945 * @param {string=} linkText 1852 * @param {string=} linkText
1946 * @param {string=} classes 1853 * @param {string=} classes
1947 * @param {boolean=} isExternal 1854 * @param {boolean=} isExternal
1948 * @param {string=} tooltipText 1855 * @param {string=} tooltipText
1949 * @return {!Element} 1856 * @return {!Element}
1950 */ 1857 */
1951 WebInspector.linkifyURLAsNode = function(url, linkText, classes, isExternal, too ltipText) 1858 WebInspector.linkifyURLAsNode = function(url, linkText, classes, isExternal, too ltipText) {
1952 { 1859 if (!linkText)
1953 if (!linkText) 1860 linkText = url;
1954 linkText = url;
1955 1861
1956 var a = createElementWithClass("a", classes); 1862 var a = createElementWithClass('a', classes);
1957 var href = url; 1863 var href = url;
1958 if (url.trim().toLowerCase().startsWith("javascript:")) 1864 if (url.trim().toLowerCase().startsWith('javascript:'))
1959 href = null; 1865 href = null;
1960 if (isExternal && WebInspector.ParsedURL.isRelativeURL(url)) 1866 if (isExternal && WebInspector.ParsedURL.isRelativeURL(url))
1961 href = null; 1867 href = null;
1962 if (href !== null) { 1868 if (href !== null) {
1963 a.href = href; 1869 a.href = href;
1964 a.classList.add(isExternal ? "webkit-html-external-link" : "webkit-html- resource-link"); 1870 a.classList.add(isExternal ? 'webkit-html-external-link' : 'webkit-html-reso urce-link');
1965 } 1871 }
1966 if (!tooltipText && linkText !== url) 1872 if (!tooltipText && linkText !== url)
1967 a.title = url; 1873 a.title = url;
1968 else if (tooltipText) 1874 else if (tooltipText)
1969 a.title = tooltipText; 1875 a.title = tooltipText;
1970 a.textContent = linkText.trimMiddle(150); 1876 a.textContent = linkText.trimMiddle(150);
1971 if (isExternal) 1877 if (isExternal)
1972 a.setAttribute("target", "_blank"); 1878 a.setAttribute('target', '_blank');
1973 1879
1974 return a; 1880 return a;
1975 }; 1881 };
1976 1882
1977 /** 1883 /**
1978 * @param {string} article 1884 * @param {string} article
1979 * @param {string} title 1885 * @param {string} title
1980 * @return {!Element} 1886 * @return {!Element}
1981 */ 1887 */
1982 WebInspector.linkifyDocumentationURLAsNode = function(article, title) 1888 WebInspector.linkifyDocumentationURLAsNode = function(article, title) {
1983 { 1889 return WebInspector.linkifyURLAsNode(
1984 return WebInspector.linkifyURLAsNode("https://developers.google.com/web/tool s/chrome-devtools/" + article, title, undefined, true); 1890 'https://developers.google.com/web/tools/chrome-devtools/' + article, titl e, undefined, true);
1985 }; 1891 };
1986 1892
1987 /** 1893 /**
1988 * @param {string} url 1894 * @param {string} url
1989 * @return {!Promise<?Image>} 1895 * @return {!Promise<?Image>}
1990 */ 1896 */
1991 WebInspector.loadImage = function(url) 1897 WebInspector.loadImage = function(url) {
1992 { 1898 return new Promise(fulfill => {
1993 return new Promise(fulfill => { 1899 var image = new Image();
1994 var image = new Image(); 1900 image.addEventListener('load', () => fulfill(image));
1995 image.addEventListener("load", () => fulfill(image)); 1901 image.addEventListener('error', () => fulfill(null));
1996 image.addEventListener("error", () => fulfill(null)); 1902 image.src = url;
1997 image.src = url; 1903 });
1998 });
1999 }; 1904 };
2000 1905
2001 /** @type {!WebInspector.ThemeSupport} */ 1906 /** @type {!WebInspector.ThemeSupport} */
2002 WebInspector.themeSupport; 1907 WebInspector.themeSupport;
OLDNEW
« no previous file with comments | « third_party/WebKit/Source/devtools/front_end/ui/Tooltip.js ('k') | third_party/WebKit/Source/devtools/front_end/ui/View.js » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698