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