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

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

Issue 2466123002: DevTools: reformat front-end code to match chromium style. (Closed)
Patch Set: all done Created 4 years, 1 month ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
1 /* 1 /*
2 * Copyright (C) 2008 Apple Inc. All Rights Reserved. 2 * Copyright (C) 2008 Apple Inc. All Rights Reserved.
3 * Copyright (C) 2011 Google Inc. All Rights Reserved. 3 * Copyright (C) 2011 Google Inc. All Rights Reserved.
4 * 4 *
5 * Redistribution and use in source and binary forms, with or without 5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions 6 * modification, are permitted provided that the following conditions
7 * are met: 7 * are met:
8 * 1. Redistributions of source code must retain the above copyright 8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer. 9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright 10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the 11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution. 12 * documentation and/or other materials provided with the distribution.
13 * 13 *
14 * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY 14 * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
15 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 15 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
17 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR 17 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
18 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 18 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
19 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 19 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
20 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 20 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
21 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY 21 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
22 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 22 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 23 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
24 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 24 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25 */ 25 */
26
27 /** 26 /**
28 * @constructor 27 * @unrestricted
29 * @extends {WebInspector.Object}
30 * @param {boolean=} isWebComponent
31 */ 28 */
32 WebInspector.Widget = function(isWebComponent) 29 WebInspector.Widget = class extends WebInspector.Object {
33 { 30 /**
34 this.contentElement = createElementWithClass("div", "widget"); 31 * @param {boolean=} isWebComponent
32 */
33 constructor(isWebComponent) {
34 super();
35 this.contentElement = createElementWithClass('div', 'widget');
35 if (isWebComponent) { 36 if (isWebComponent) {
36 this.element = createElementWithClass("div", "vbox flex-auto"); 37 this.element = createElementWithClass('div', 'vbox flex-auto');
37 this._shadowRoot = WebInspector.createShadowRootWithCoreStyles(this.elem ent); 38 this._shadowRoot = WebInspector.createShadowRootWithCoreStyles(this.elemen t);
38 this._shadowRoot.appendChild(this.contentElement); 39 this._shadowRoot.appendChild(this.contentElement);
39 } else { 40 } else {
40 this.element = this.contentElement; 41 this.element = this.contentElement;
41 } 42 }
42 this._isWebComponent = isWebComponent; 43 this._isWebComponent = isWebComponent;
43 this.element.__widget = this; 44 this.element.__widget = this;
44 this._visible = false; 45 this._visible = false;
45 this._isRoot = false; 46 this._isRoot = false;
46 this._isShowing = false; 47 this._isShowing = false;
47 this._children = []; 48 this._children = [];
48 this._hideOnDetach = false; 49 this._hideOnDetach = false;
49 this._notificationDepth = 0; 50 this._notificationDepth = 0;
50 this._invalidationsSuspended = 0; 51 this._invalidationsSuspended = 0;
51 this._defaultFocusedChild = null; 52 this._defaultFocusedChild = null;
53 }
54
55 static _incrementWidgetCounter(parentElement, childElement) {
56 var count = (childElement.__widgetCounter || 0) + (childElement.__widget ? 1 : 0);
57 if (!count)
58 return;
59
60 while (parentElement) {
61 parentElement.__widgetCounter = (parentElement.__widgetCounter || 0) + cou nt;
62 parentElement = parentElement.parentElementOrShadowHost();
63 }
64 }
65
66 static _decrementWidgetCounter(parentElement, childElement) {
67 var count = (childElement.__widgetCounter || 0) + (childElement.__widget ? 1 : 0);
68 if (!count)
69 return;
70
71 while (parentElement) {
72 parentElement.__widgetCounter -= count;
73 parentElement = parentElement.parentElementOrShadowHost();
74 }
75 }
76
77 static __assert(condition, message) {
78 if (!condition) {
79 console.trace();
80 throw new Error(message);
81 }
82 }
83
84 /**
85 * @param {?Node} node
86 */
87 static focusWidgetForNode(node) {
88 while (node) {
89 if (node.__widget)
90 break;
91 node = node.parentNodeOrShadowHost();
92 }
93 if (!node)
94 return;
95
96 var widget = node.__widget;
97 while (widget._parentWidget) {
98 widget._parentWidget._defaultFocusedChild = widget;
99 widget = widget._parentWidget;
100 }
101 }
102
103 markAsRoot() {
104 WebInspector.Widget.__assert(!this.element.parentElement, 'Attempt to mark a s root attached node');
105 this._isRoot = true;
106 }
107
108 /**
109 * @return {?WebInspector.Widget}
110 */
111 parentWidget() {
112 return this._parentWidget;
113 }
114
115 /**
116 * @return {!Array.<!WebInspector.Widget>}
117 */
118 children() {
119 return this._children;
120 }
121
122 /**
123 * @param {!WebInspector.Widget} widget
124 * @protected
125 */
126 childWasDetached(widget) {
127 }
128
129 /**
130 * @return {boolean}
131 */
132 isShowing() {
133 return this._isShowing;
134 }
135
136 /**
137 * @return {boolean}
138 */
139 shouldHideOnDetach() {
140 if (!this.element.parentElement)
141 return false;
142 if (this._hideOnDetach)
143 return true;
144 for (var child of this._children) {
145 if (child.shouldHideOnDetach())
146 return true;
147 }
148 return false;
149 }
150
151 setHideOnDetach() {
152 this._hideOnDetach = true;
153 }
154
155 /**
156 * @return {boolean}
157 */
158 _inNotification() {
159 return !!this._notificationDepth || (this._parentWidget && this._parentWidge t._inNotification());
160 }
161
162 _parentIsShowing() {
163 if (this._isRoot)
164 return true;
165 return !!this._parentWidget && this._parentWidget.isShowing();
166 }
167
168 /**
169 * @param {function(this:WebInspector.Widget)} method
170 */
171 _callOnVisibleChildren(method) {
172 var copy = this._children.slice();
173 for (var i = 0; i < copy.length; ++i) {
174 if (copy[i]._parentWidget === this && copy[i]._visible)
175 method.call(copy[i]);
176 }
177 }
178
179 _processWillShow() {
180 this._callOnVisibleChildren(this._processWillShow);
181 this._isShowing = true;
182 }
183
184 _processWasShown() {
185 if (this._inNotification())
186 return;
187 this.restoreScrollPositions();
188 this._notify(this.wasShown);
189 this._callOnVisibleChildren(this._processWasShown);
190 }
191
192 _processWasDetachedFromHierarchy() {
193 this._notify(this.wasDetachedFromHierarchy);
194 var copy = this._children.slice();
195 for (var widget of copy)
196 widget._processWasDetachedFromHierarchy();
197 }
198
199 _processWillHide() {
200 if (this._inNotification())
201 return;
202 this.storeScrollPositions();
203
204 this._callOnVisibleChildren(this._processWillHide);
205 this._notify(this.willHide);
206 this._isShowing = false;
207 }
208
209 _processWasHidden() {
210 this._callOnVisibleChildren(this._processWasHidden);
211 }
212
213 _processOnResize() {
214 if (this._inNotification())
215 return;
216 if (!this.isShowing())
217 return;
218 this._notify(this.onResize);
219 this._callOnVisibleChildren(this._processOnResize);
220 }
221
222 /**
223 * @param {function(this:WebInspector.Widget)} notification
224 */
225 _notify(notification) {
226 ++this._notificationDepth;
227 try {
228 notification.call(this);
229 } finally {
230 --this._notificationDepth;
231 }
232 }
233
234 wasShown() {
235 }
236
237 willHide() {
238 }
239
240 wasDetachedFromHierarchy() {
241 }
242
243 onResize() {
244 }
245
246 onLayout() {
247 }
248
249 /**
250 * @param {!Element} parentElement
251 * @param {?Element=} insertBefore
252 */
253 show(parentElement, insertBefore) {
254 WebInspector.Widget.__assert(parentElement, 'Attempt to attach widget with n o parent element');
255
256 if (!this._isRoot) {
257 // Update widget hierarchy.
258 var currentParent = parentElement;
259 while (currentParent && !currentParent.__widget)
260 currentParent = currentParent.parentElementOrShadowHost();
261 WebInspector.Widget.__assert(currentParent, 'Attempt to attach widget to o rphan node');
262 this.attach(currentParent.__widget);
263 }
264
265 this.showWidget(parentElement, insertBefore);
266 }
267
268 /**
269 * @param {!WebInspector.Widget} parentWidget
270 */
271 attach(parentWidget) {
272 if (parentWidget === this._parentWidget)
273 return;
274 if (this._parentWidget)
275 this.detach();
276 this._parentWidget = parentWidget;
277 this._parentWidget._children.push(this);
278 this._isRoot = false;
279 }
280
281 /**
282 * @param {!Element} parentElement
283 * @param {?Element=} insertBefore
284 */
285 showWidget(parentElement, insertBefore) {
286 var currentParent = parentElement;
287 while (currentParent && !currentParent.__widget)
288 currentParent = currentParent.parentElementOrShadowHost();
289
290 if (this._isRoot)
291 WebInspector.Widget.__assert(!currentParent, 'Attempt to show root widget under another widget');
292 else
293 WebInspector.Widget.__assert(
294 currentParent && currentParent.__widget === this._parentWidget,
295 'Attempt to show under node belonging to alien widget');
296
297 var wasVisible = this._visible;
298 if (wasVisible && this.element.parentElement === parentElement)
299 return;
300
301 this._visible = true;
302
303 if (!wasVisible && this._parentIsShowing())
304 this._processWillShow();
305
306 this.element.classList.remove('hidden');
307
308 // Reparent
309 if (this.element.parentElement !== parentElement) {
310 WebInspector.Widget._incrementWidgetCounter(parentElement, this.element);
311 if (insertBefore)
312 WebInspector.Widget._originalInsertBefore.call(parentElement, this.eleme nt, insertBefore);
313 else
314 WebInspector.Widget._originalAppendChild.call(parentElement, this.elemen t);
315 }
316
317 if (!wasVisible && this._parentIsShowing())
318 this._processWasShown();
319
320 if (this._parentWidget && this._hasNonZeroConstraints())
321 this._parentWidget.invalidateConstraints();
322 else
323 this._processOnResize();
324 }
325
326 hideWidget() {
327 if (!this._parentWidget)
328 return;
329 this._hideWidget();
330 }
331
332 /**
333 * @param {boolean=} overrideHideOnDetach
334 */
335 _hideWidget(overrideHideOnDetach) {
336 if (!this._visible)
337 return;
338 this._visible = false;
339 var parentElement = this.element.parentElement;
340
341 if (this._parentIsShowing())
342 this._processWillHide();
343
344 if (!overrideHideOnDetach && this.shouldHideOnDetach()) {
345 this.element.classList.add('hidden');
346 } else {
347 // Force legal removal
348 WebInspector.Widget._decrementWidgetCounter(parentElement, this.element);
349 WebInspector.Widget._originalRemoveChild.call(parentElement, this.element) ;
350 }
351
352 if (this._parentIsShowing())
353 this._processWasHidden();
354 if (this._parentWidget && this._hasNonZeroConstraints())
355 this._parentWidget.invalidateConstraints();
356 }
357
358 detach() {
359 if (!this._parentWidget && !this._isRoot)
360 return;
361
362 if (this._visible)
363 this._hideWidget(true);
364
365 // Update widget hierarchy.
366 if (this._parentWidget) {
367 var childIndex = this._parentWidget._children.indexOf(this);
368 WebInspector.Widget.__assert(childIndex >= 0, 'Attempt to remove non-child widget');
369 this._parentWidget._children.splice(childIndex, 1);
370 if (this._parentWidget._defaultFocusedChild === this)
371 this._parentWidget._defaultFocusedChild = null;
372 this._parentWidget.childWasDetached(this);
373 var parent = this._parentWidget;
374 this._parentWidget = null;
375 this._processWasDetachedFromHierarchy();
376 } else {
377 WebInspector.Widget.__assert(this._isRoot, 'Removing non-root widget from DOM');
378 }
379 }
380
381 detachChildWidgets() {
382 var children = this._children.slice();
383 for (var i = 0; i < children.length; ++i)
384 children[i].detach();
385 }
386
387 /**
388 * @return {!Array.<!Element>}
389 */
390 elementsToRestoreScrollPositionsFor() {
391 return [this.element];
392 }
393
394 storeScrollPositions() {
395 var elements = this.elementsToRestoreScrollPositionsFor();
396 for (var i = 0; i < elements.length; ++i) {
397 var container = elements[i];
398 container._scrollTop = container.scrollTop;
399 container._scrollLeft = container.scrollLeft;
400 }
401 }
402
403 restoreScrollPositions() {
404 var elements = this.elementsToRestoreScrollPositionsFor();
405 for (var i = 0; i < elements.length; ++i) {
406 var container = elements[i];
407 if (container._scrollTop)
408 container.scrollTop = container._scrollTop;
409 if (container._scrollLeft)
410 container.scrollLeft = container._scrollLeft;
411 }
412 }
413
414 doResize() {
415 if (!this.isShowing())
416 return;
417 // No matter what notification we are in, dispatching onResize is not needed .
418 if (!this._inNotification())
419 this._callOnVisibleChildren(this._processOnResize);
420 }
421
422 doLayout() {
423 if (!this.isShowing())
424 return;
425 this._notify(this.onLayout);
426 this.doResize();
427 }
428
429 /**
430 * @param {string} cssFile
431 */
432 registerRequiredCSS(cssFile) {
433 WebInspector.appendStyle(this._isWebComponent ? this._shadowRoot : this.elem ent, cssFile);
434 }
435
436 printWidgetHierarchy() {
437 var lines = [];
438 this._collectWidgetHierarchy('', lines);
439 console.log(lines.join('\n'));
440 }
441
442 _collectWidgetHierarchy(prefix, lines) {
443 lines.push(prefix + '[' + this.element.className + ']' + (this._children.len gth ? ' {' : ''));
444
445 for (var i = 0; i < this._children.length; ++i)
446 this._children[i]._collectWidgetHierarchy(prefix + ' ', lines);
447
448 if (this._children.length)
449 lines.push(prefix + '}');
450 }
451
452 /**
453 * @param {?Element} element
454 */
455 setDefaultFocusedElement(element) {
456 this._defaultFocusedElement = element;
457 }
458
459 /**
460 * @param {!WebInspector.Widget} child
461 */
462 setDefaultFocusedChild(child) {
463 WebInspector.Widget.__assert(child._parentWidget === this, 'Attempt to set n on-child widget as default focused.');
464 this._defaultFocusedChild = child;
465 }
466
467 focus() {
468 if (!this.isShowing())
469 return;
470
471 var element = this._defaultFocusedElement;
472 if (element) {
473 if (!element.hasFocus())
474 element.focus();
475 return;
476 }
477
478 if (this._defaultFocusedChild && this._defaultFocusedChild._visible) {
479 this._defaultFocusedChild.focus();
480 } else {
481 for (var child of this._children) {
482 if (child._visible) {
483 child.focus();
484 break;
485 }
486 }
487 }
488 }
489
490 /**
491 * @return {boolean}
492 */
493 hasFocus() {
494 return this.element.hasFocus();
495 }
496
497 /**
498 * @return {!Size}
499 */
500 measurePreferredSize() {
501 var document = this.element.ownerDocument;
502 var oldParent = this.element.parentElement;
503 var oldNextSibling = this.element.nextSibling;
504
505 WebInspector.Widget._originalAppendChild.call(document.body, this.element);
506 this.element.positionAt(0, 0);
507 var result = new Size(this.element.offsetWidth, this.element.offsetHeight);
508
509 this.element.positionAt(undefined, undefined);
510 if (oldParent)
511 WebInspector.Widget._originalInsertBefore.call(oldParent, this.element, ol dNextSibling);
512 else
513 WebInspector.Widget._originalRemoveChild.call(document.body, this.element) ;
514 return result;
515 }
516
517 /**
518 * @return {!Constraints}
519 */
520 calculateConstraints() {
521 return new Constraints();
522 }
523
524 /**
525 * @return {!Constraints}
526 */
527 constraints() {
528 if (typeof this._constraints !== 'undefined')
529 return this._constraints;
530 if (typeof this._cachedConstraints === 'undefined')
531 this._cachedConstraints = this.calculateConstraints();
532 return this._cachedConstraints;
533 }
534
535 /**
536 * @param {number} width
537 * @param {number} height
538 * @param {number} preferredWidth
539 * @param {number} preferredHeight
540 */
541 setMinimumAndPreferredSizes(width, height, preferredWidth, preferredHeight) {
542 this._constraints = new Constraints(new Size(width, height), new Size(prefer redWidth, preferredHeight));
543 this.invalidateConstraints();
544 }
545
546 /**
547 * @param {number} width
548 * @param {number} height
549 */
550 setMinimumSize(width, height) {
551 this._constraints = new Constraints(new Size(width, height));
552 this.invalidateConstraints();
553 }
554
555 /**
556 * @return {boolean}
557 */
558 _hasNonZeroConstraints() {
559 var constraints = this.constraints();
560 return !!(
561 constraints.minimum.width || constraints.minimum.height || constraints.p referred.width ||
562 constraints.preferred.height);
563 }
564
565 suspendInvalidations() {
566 ++this._invalidationsSuspended;
567 }
568
569 resumeInvalidations() {
570 --this._invalidationsSuspended;
571 if (!this._invalidationsSuspended && this._invalidationsRequested)
572 this.invalidateConstraints();
573 }
574
575 invalidateConstraints() {
576 if (this._invalidationsSuspended) {
577 this._invalidationsRequested = true;
578 return;
579 }
580 this._invalidationsRequested = false;
581 var cached = this._cachedConstraints;
582 delete this._cachedConstraints;
583 var actual = this.constraints();
584 if (!actual.isEqual(cached) && this._parentWidget)
585 this._parentWidget.invalidateConstraints();
586 else
587 this.doLayout();
588 }
589
590 invalidateSize() {
591 if (this._parentWidget)
592 this._parentWidget.doLayout();
593 }
52 }; 594 };
53 595
54 WebInspector.Widget.prototype = {
55 markAsRoot: function()
56 {
57 WebInspector.Widget.__assert(!this.element.parentElement, "Attempt to ma rk as root attached node");
58 this._isRoot = true;
59 },
60
61 /**
62 * @return {?WebInspector.Widget}
63 */
64 parentWidget: function()
65 {
66 return this._parentWidget;
67 },
68
69 /**
70 * @return {!Array.<!WebInspector.Widget>}
71 */
72 children: function()
73 {
74 return this._children;
75 },
76
77 /**
78 * @param {!WebInspector.Widget} widget
79 * @protected
80 */
81 childWasDetached: function(widget)
82 {
83 },
84
85 /**
86 * @return {boolean}
87 */
88 isShowing: function()
89 {
90 return this._isShowing;
91 },
92
93 /**
94 * @return {boolean}
95 */
96 shouldHideOnDetach: function()
97 {
98 if (!this.element.parentElement)
99 return false;
100 if (this._hideOnDetach)
101 return true;
102 for (var child of this._children) {
103 if (child.shouldHideOnDetach())
104 return true;
105 }
106 return false;
107 },
108
109 setHideOnDetach: function()
110 {
111 this._hideOnDetach = true;
112 },
113
114 /**
115 * @return {boolean}
116 */
117 _inNotification: function()
118 {
119 return !!this._notificationDepth || (this._parentWidget && this._parentW idget._inNotification());
120 },
121
122 _parentIsShowing: function()
123 {
124 if (this._isRoot)
125 return true;
126 return !!this._parentWidget && this._parentWidget.isShowing();
127 },
128
129 /**
130 * @param {function(this:WebInspector.Widget)} method
131 */
132 _callOnVisibleChildren: function(method)
133 {
134 var copy = this._children.slice();
135 for (var i = 0; i < copy.length; ++i) {
136 if (copy[i]._parentWidget === this && copy[i]._visible)
137 method.call(copy[i]);
138 }
139 },
140
141 _processWillShow: function()
142 {
143 this._callOnVisibleChildren(this._processWillShow);
144 this._isShowing = true;
145 },
146
147 _processWasShown: function()
148 {
149 if (this._inNotification())
150 return;
151 this.restoreScrollPositions();
152 this._notify(this.wasShown);
153 this._callOnVisibleChildren(this._processWasShown);
154 },
155
156 _processWasDetachedFromHierarchy: function()
157 {
158 this._notify(this.wasDetachedFromHierarchy);
159 var copy = this._children.slice();
160 for (var widget of copy)
161 widget._processWasDetachedFromHierarchy();
162 },
163
164 _processWillHide: function()
165 {
166 if (this._inNotification())
167 return;
168 this.storeScrollPositions();
169
170 this._callOnVisibleChildren(this._processWillHide);
171 this._notify(this.willHide);
172 this._isShowing = false;
173 },
174
175 _processWasHidden: function()
176 {
177 this._callOnVisibleChildren(this._processWasHidden);
178 },
179
180 _processOnResize: function()
181 {
182 if (this._inNotification())
183 return;
184 if (!this.isShowing())
185 return;
186 this._notify(this.onResize);
187 this._callOnVisibleChildren(this._processOnResize);
188 },
189
190 /**
191 * @param {function(this:WebInspector.Widget)} notification
192 */
193 _notify: function(notification)
194 {
195 ++this._notificationDepth;
196 try {
197 notification.call(this);
198 } finally {
199 --this._notificationDepth;
200 }
201 },
202
203 wasShown: function()
204 {
205 },
206
207 willHide: function()
208 {
209 },
210
211 wasDetachedFromHierarchy: function()
212 {
213 },
214
215 onResize: function()
216 {
217 },
218
219 onLayout: function()
220 {
221 },
222
223 /**
224 * @param {!Element} parentElement
225 * @param {?Element=} insertBefore
226 */
227 show: function(parentElement, insertBefore)
228 {
229 WebInspector.Widget.__assert(parentElement, "Attempt to attach widget wi th no parent element");
230
231 if (!this._isRoot) {
232 // Update widget hierarchy.
233 var currentParent = parentElement;
234 while (currentParent && !currentParent.__widget)
235 currentParent = currentParent.parentElementOrShadowHost();
236 WebInspector.Widget.__assert(currentParent, "Attempt to attach widge t to orphan node");
237 this.attach(currentParent.__widget);
238 }
239
240 this.showWidget(parentElement, insertBefore);
241 },
242
243 /**
244 * @param {!WebInspector.Widget} parentWidget
245 */
246 attach: function(parentWidget)
247 {
248 if (parentWidget === this._parentWidget)
249 return;
250 if (this._parentWidget)
251 this.detach();
252 this._parentWidget = parentWidget;
253 this._parentWidget._children.push(this);
254 this._isRoot = false;
255 },
256
257 /**
258 * @param {!Element} parentElement
259 * @param {?Element=} insertBefore
260 */
261 showWidget: function(parentElement, insertBefore)
262 {
263 var currentParent = parentElement;
264 while (currentParent && !currentParent.__widget)
265 currentParent = currentParent.parentElementOrShadowHost();
266
267 if (this._isRoot)
268 WebInspector.Widget.__assert(!currentParent, "Attempt to show root w idget under another widget");
269 else
270 WebInspector.Widget.__assert(currentParent && currentParent.__widget === this._parentWidget, "Attempt to show under node belonging to alien widget") ;
271
272 var wasVisible = this._visible;
273 if (wasVisible && this.element.parentElement === parentElement)
274 return;
275
276 this._visible = true;
277
278 if (!wasVisible && this._parentIsShowing())
279 this._processWillShow();
280
281 this.element.classList.remove("hidden");
282
283 // Reparent
284 if (this.element.parentElement !== parentElement) {
285 WebInspector.Widget._incrementWidgetCounter(parentElement, this.elem ent);
286 if (insertBefore)
287 WebInspector.Widget._originalInsertBefore.call(parentElement, th is.element, insertBefore);
288 else
289 WebInspector.Widget._originalAppendChild.call(parentElement, thi s.element);
290 }
291
292 if (!wasVisible && this._parentIsShowing())
293 this._processWasShown();
294
295 if (this._parentWidget && this._hasNonZeroConstraints())
296 this._parentWidget.invalidateConstraints();
297 else
298 this._processOnResize();
299 },
300
301 hideWidget: function()
302 {
303 if (!this._parentWidget)
304 return;
305 this._hideWidget();
306 },
307
308 /**
309 * @param {boolean=} overrideHideOnDetach
310 */
311 _hideWidget: function(overrideHideOnDetach)
312 {
313 if (!this._visible)
314 return;
315 this._visible = false;
316 var parentElement = this.element.parentElement;
317
318 if (this._parentIsShowing())
319 this._processWillHide();
320
321 if (!overrideHideOnDetach && this.shouldHideOnDetach()) {
322 this.element.classList.add("hidden");
323 } else {
324 // Force legal removal
325 WebInspector.Widget._decrementWidgetCounter(parentElement, this.elem ent);
326 WebInspector.Widget._originalRemoveChild.call(parentElement, this.el ement);
327 }
328
329 if (this._parentIsShowing())
330 this._processWasHidden();
331 if (this._parentWidget && this._hasNonZeroConstraints())
332 this._parentWidget.invalidateConstraints();
333 },
334
335 detach: function()
336 {
337 if (!this._parentWidget && !this._isRoot)
338 return;
339
340 if (this._visible)
341 this._hideWidget(true);
342
343 // Update widget hierarchy.
344 if (this._parentWidget) {
345 var childIndex = this._parentWidget._children.indexOf(this);
346 WebInspector.Widget.__assert(childIndex >= 0, "Attempt to remove non -child widget");
347 this._parentWidget._children.splice(childIndex, 1);
348 if (this._parentWidget._defaultFocusedChild === this)
349 this._parentWidget._defaultFocusedChild = null;
350 this._parentWidget.childWasDetached(this);
351 var parent = this._parentWidget;
352 this._parentWidget = null;
353 this._processWasDetachedFromHierarchy();
354 } else {
355 WebInspector.Widget.__assert(this._isRoot, "Removing non-root widget from DOM");
356 }
357 },
358
359 detachChildWidgets: function()
360 {
361 var children = this._children.slice();
362 for (var i = 0; i < children.length; ++i)
363 children[i].detach();
364 },
365
366 /**
367 * @return {!Array.<!Element>}
368 */
369 elementsToRestoreScrollPositionsFor: function()
370 {
371 return [this.element];
372 },
373
374 storeScrollPositions: function()
375 {
376 var elements = this.elementsToRestoreScrollPositionsFor();
377 for (var i = 0; i < elements.length; ++i) {
378 var container = elements[i];
379 container._scrollTop = container.scrollTop;
380 container._scrollLeft = container.scrollLeft;
381 }
382 },
383
384 restoreScrollPositions: function()
385 {
386 var elements = this.elementsToRestoreScrollPositionsFor();
387 for (var i = 0; i < elements.length; ++i) {
388 var container = elements[i];
389 if (container._scrollTop)
390 container.scrollTop = container._scrollTop;
391 if (container._scrollLeft)
392 container.scrollLeft = container._scrollLeft;
393 }
394 },
395
396 doResize: function()
397 {
398 if (!this.isShowing())
399 return;
400 // No matter what notification we are in, dispatching onResize is not ne eded.
401 if (!this._inNotification())
402 this._callOnVisibleChildren(this._processOnResize);
403 },
404
405 doLayout: function()
406 {
407 if (!this.isShowing())
408 return;
409 this._notify(this.onLayout);
410 this.doResize();
411 },
412
413 /**
414 * @param {string} cssFile
415 */
416 registerRequiredCSS: function(cssFile)
417 {
418 WebInspector.appendStyle(this._isWebComponent ? this._shadowRoot : this. element, cssFile);
419 },
420
421 printWidgetHierarchy: function()
422 {
423 var lines = [];
424 this._collectWidgetHierarchy("", lines);
425 console.log(lines.join("\n"));
426 },
427
428 _collectWidgetHierarchy: function(prefix, lines)
429 {
430 lines.push(prefix + "[" + this.element.className + "]" + (this._children .length ? " {" : ""));
431
432 for (var i = 0; i < this._children.length; ++i)
433 this._children[i]._collectWidgetHierarchy(prefix + " ", lines);
434
435 if (this._children.length)
436 lines.push(prefix + "}");
437 },
438
439 /**
440 * @param {?Element} element
441 */
442 setDefaultFocusedElement: function(element)
443 {
444 this._defaultFocusedElement = element;
445 },
446
447 /**
448 * @param {!WebInspector.Widget} child
449 */
450 setDefaultFocusedChild: function(child)
451 {
452 WebInspector.Widget.__assert(child._parentWidget === this, "Attempt to s et non-child widget as default focused.");
453 this._defaultFocusedChild = child;
454 },
455
456 focus: function()
457 {
458 if (!this.isShowing())
459 return;
460
461 var element = this._defaultFocusedElement;
462 if (element) {
463 if (!element.hasFocus())
464 element.focus();
465 return;
466 }
467
468 if (this._defaultFocusedChild && this._defaultFocusedChild._visible) {
469 this._defaultFocusedChild.focus();
470 } else {
471 for (var child of this._children) {
472 if (child._visible) {
473 child.focus();
474 break;
475 }
476 }
477 }
478
479 },
480
481 /**
482 * @return {boolean}
483 */
484 hasFocus: function()
485 {
486 return this.element.hasFocus();
487 },
488
489 /**
490 * @return {!Size}
491 */
492 measurePreferredSize: function()
493 {
494 var document = this.element.ownerDocument;
495 var oldParent = this.element.parentElement;
496 var oldNextSibling = this.element.nextSibling;
497
498 WebInspector.Widget._originalAppendChild.call(document.body, this.elemen t);
499 this.element.positionAt(0, 0);
500 var result = new Size(this.element.offsetWidth, this.element.offsetHeigh t);
501
502 this.element.positionAt(undefined, undefined);
503 if (oldParent)
504 WebInspector.Widget._originalInsertBefore.call(oldParent, this.eleme nt, oldNextSibling);
505 else
506 WebInspector.Widget._originalRemoveChild.call(document.body, this.el ement);
507 return result;
508 },
509
510 /**
511 * @return {!Constraints}
512 */
513 calculateConstraints: function()
514 {
515 return new Constraints();
516 },
517
518 /**
519 * @return {!Constraints}
520 */
521 constraints: function()
522 {
523 if (typeof this._constraints !== "undefined")
524 return this._constraints;
525 if (typeof this._cachedConstraints === "undefined")
526 this._cachedConstraints = this.calculateConstraints();
527 return this._cachedConstraints;
528 },
529
530 /**
531 * @param {number} width
532 * @param {number} height
533 * @param {number} preferredWidth
534 * @param {number} preferredHeight
535 */
536 setMinimumAndPreferredSizes: function(width, height, preferredWidth, preferr edHeight)
537 {
538 this._constraints = new Constraints(new Size(width, height), new Size(pr eferredWidth, preferredHeight));
539 this.invalidateConstraints();
540 },
541
542 /**
543 * @param {number} width
544 * @param {number} height
545 */
546 setMinimumSize: function(width, height)
547 {
548 this._constraints = new Constraints(new Size(width, height));
549 this.invalidateConstraints();
550 },
551
552 /**
553 * @return {boolean}
554 */
555 _hasNonZeroConstraints: function()
556 {
557 var constraints = this.constraints();
558 return !!(constraints.minimum.width || constraints.minimum.height || con straints.preferred.width || constraints.preferred.height);
559 },
560
561 suspendInvalidations()
562 {
563 ++this._invalidationsSuspended;
564 },
565
566 resumeInvalidations()
567 {
568 --this._invalidationsSuspended;
569 if (!this._invalidationsSuspended && this._invalidationsRequested)
570 this.invalidateConstraints();
571 },
572
573 invalidateConstraints: function()
574 {
575 if (this._invalidationsSuspended) {
576 this._invalidationsRequested = true;
577 return;
578 }
579 this._invalidationsRequested = false;
580 var cached = this._cachedConstraints;
581 delete this._cachedConstraints;
582 var actual = this.constraints();
583 if (!actual.isEqual(cached) && this._parentWidget)
584 this._parentWidget.invalidateConstraints();
585 else
586 this.doLayout();
587 },
588
589 invalidateSize: function()
590 {
591 if (this._parentWidget)
592 this._parentWidget.doLayout();
593 },
594
595 __proto__: WebInspector.Object.prototype
596 };
597
598 WebInspector.Widget._originalAppendChild = Element.prototype.appendChild; 596 WebInspector.Widget._originalAppendChild = Element.prototype.appendChild;
599 WebInspector.Widget._originalInsertBefore = Element.prototype.insertBefore; 597 WebInspector.Widget._originalInsertBefore = Element.prototype.insertBefore;
600 WebInspector.Widget._originalRemoveChild = Element.prototype.removeChild; 598 WebInspector.Widget._originalRemoveChild = Element.prototype.removeChild;
601 WebInspector.Widget._originalRemoveChildren = Element.prototype.removeChildren; 599 WebInspector.Widget._originalRemoveChildren = Element.prototype.removeChildren;
602 600
603 WebInspector.Widget._incrementWidgetCounter = function(parentElement, childEleme nt)
604 {
605 var count = (childElement.__widgetCounter || 0) + (childElement.__widget ? 1 : 0);
606 if (!count)
607 return;
608 601
609 while (parentElement) { 602 /**
610 parentElement.__widgetCounter = (parentElement.__widgetCounter || 0) + c ount; 603 * @unrestricted
611 parentElement = parentElement.parentElementOrShadowHost(); 604 */
605 WebInspector.VBox = class extends WebInspector.Widget {
606 /**
607 * @param {boolean=} isWebComponent
608 */
609 constructor(isWebComponent) {
610 super(isWebComponent);
611 this.contentElement.classList.add('vbox');
612 }
613
614 /**
615 * @override
616 * @return {!Constraints}
617 */
618 calculateConstraints() {
619 var constraints = new Constraints();
620
621 /**
622 * @this {!WebInspector.Widget}
623 * @suppressReceiverCheck
624 */
625 function updateForChild() {
626 var child = this.constraints();
627 constraints = constraints.widthToMax(child);
628 constraints = constraints.addHeight(child);
612 } 629 }
613 };
614 630
615 WebInspector.Widget._decrementWidgetCounter = function(parentElement, childEleme nt) 631 this._callOnVisibleChildren(updateForChild);
616 { 632 return constraints;
617 var count = (childElement.__widgetCounter || 0) + (childElement.__widget ? 1 : 0); 633 }
618 if (!count)
619 return;
620
621 while (parentElement) {
622 parentElement.__widgetCounter -= count;
623 parentElement = parentElement.parentElementOrShadowHost();
624 }
625 };
626
627 WebInspector.Widget.__assert = function(condition, message)
628 {
629 if (!condition) {
630 console.trace();
631 throw new Error(message);
632 }
633 }; 634 };
634 635
635 /** 636 /**
636 * @param {?Node} node 637 * @unrestricted
637 */ 638 */
638 WebInspector.Widget.focusWidgetForNode = function(node) 639 WebInspector.HBox = class extends WebInspector.Widget {
639 { 640 /**
640 while (node) { 641 * @param {boolean=} isWebComponent
641 if (node.__widget) 642 */
642 break; 643 constructor(isWebComponent) {
643 node = node.parentNodeOrShadowHost(); 644 super(isWebComponent);
645 this.contentElement.classList.add('hbox');
646 }
647
648 /**
649 * @override
650 * @return {!Constraints}
651 */
652 calculateConstraints() {
653 var constraints = new Constraints();
654
655 /**
656 * @this {!WebInspector.Widget}
657 * @suppressReceiverCheck
658 */
659 function updateForChild() {
660 var child = this.constraints();
661 constraints = constraints.addWidth(child);
662 constraints = constraints.heightToMax(child);
644 } 663 }
645 if (!node)
646 return;
647 664
648 var widget = node.__widget; 665 this._callOnVisibleChildren(updateForChild);
649 while (widget._parentWidget) { 666 return constraints;
650 widget._parentWidget._defaultFocusedChild = widget; 667 }
651 widget = widget._parentWidget;
652 }
653 }; 668 };
654 669
655 /** 670 /**
656 * @constructor 671 * @unrestricted
657 * @extends {WebInspector.Widget}
658 * @param {boolean=} isWebComponent
659 */ 672 */
660 WebInspector.VBox = function(isWebComponent) 673 WebInspector.VBoxWithResizeCallback = class extends WebInspector.VBox {
661 { 674 /**
662 WebInspector.Widget.call(this, isWebComponent); 675 * @param {function()} resizeCallback
663 this.contentElement.classList.add("vbox"); 676 */
664 }; 677 constructor(resizeCallback) {
678 super();
679 this._resizeCallback = resizeCallback;
680 }
665 681
666 WebInspector.VBox.prototype = { 682 /**
667 /** 683 * @override
668 * @override 684 */
669 * @return {!Constraints} 685 onResize() {
670 */ 686 this._resizeCallback();
671 calculateConstraints: function() 687 }
672 {
673 var constraints = new Constraints();
674
675 /**
676 * @this {!WebInspector.Widget}
677 * @suppressReceiverCheck
678 */
679 function updateForChild()
680 {
681 var child = this.constraints();
682 constraints = constraints.widthToMax(child);
683 constraints = constraints.addHeight(child);
684 }
685
686 this._callOnVisibleChildren(updateForChild);
687 return constraints;
688 },
689
690 __proto__: WebInspector.Widget.prototype
691 }; 688 };
692 689
693 /** 690 /**
694 * @constructor 691 * @unrestricted
695 * @extends {WebInspector.Widget}
696 * @param {boolean=} isWebComponent
697 */ 692 */
698 WebInspector.HBox = function(isWebComponent) 693 WebInspector.WidgetFocusRestorer = class {
699 { 694 /**
700 WebInspector.Widget.call(this, isWebComponent); 695 * @param {!WebInspector.Widget} widget
701 this.contentElement.classList.add("hbox"); 696 */
702 }; 697 constructor(widget) {
698 this._widget = widget;
699 this._previous = widget.element.ownerDocument.deepActiveElement();
700 widget.focus();
701 }
703 702
704 WebInspector.HBox.prototype = { 703 restore() {
705 /** 704 if (!this._widget)
706 * @override 705 return;
707 * @return {!Constraints} 706 if (this._widget.hasFocus() && this._previous)
708 */ 707 this._previous.focus();
709 calculateConstraints: function() 708 this._previous = null;
710 { 709 this._widget = null;
711 var constraints = new Constraints(); 710 }
712
713 /**
714 * @this {!WebInspector.Widget}
715 * @suppressReceiverCheck
716 */
717 function updateForChild()
718 {
719 var child = this.constraints();
720 constraints = constraints.addWidth(child);
721 constraints = constraints.heightToMax(child);
722 }
723
724 this._callOnVisibleChildren(updateForChild);
725 return constraints;
726 },
727
728 __proto__: WebInspector.Widget.prototype
729 }; 711 };
730 712
731 /** 713 /**
732 * @constructor
733 * @extends {WebInspector.VBox}
734 * @param {function()} resizeCallback
735 */
736 WebInspector.VBoxWithResizeCallback = function(resizeCallback)
737 {
738 WebInspector.VBox.call(this);
739 this._resizeCallback = resizeCallback;
740 };
741
742 WebInspector.VBoxWithResizeCallback.prototype = {
743 onResize: function()
744 {
745 this._resizeCallback();
746 },
747
748 __proto__: WebInspector.VBox.prototype
749 };
750
751 /**
752 * @param {!WebInspector.Widget} widget
753 * @constructor
754 */
755 WebInspector.WidgetFocusRestorer = function(widget)
756 {
757 this._widget = widget;
758 this._previous = widget.element.ownerDocument.deepActiveElement();
759 widget.focus();
760 };
761
762 WebInspector.WidgetFocusRestorer.prototype = {
763 restore: function()
764 {
765 if (!this._widget)
766 return;
767 if (this._widget.hasFocus() && this._previous)
768 this._previous.focus();
769 this._previous = null;
770 this._widget = null;
771 }
772 };
773
774 /**
775 * @override 714 * @override
776 * @param {?Node} child 715 * @param {?Node} child
777 * @return {?Node} 716 * @return {?Node}
778 * @suppress {duplicate} 717 * @suppress {duplicate}
779 */ 718 */
780 Element.prototype.appendChild = function(child) 719 Element.prototype.appendChild = function(child) {
781 { 720 WebInspector.Widget.__assert(
782 WebInspector.Widget.__assert(!child.__widget || child.parentElement === this , "Attempt to add widget via regular DOM operation."); 721 !child.__widget || child.parentElement === this, 'Attempt to add widget vi a regular DOM operation.');
783 return WebInspector.Widget._originalAppendChild.call(this, child); 722 return WebInspector.Widget._originalAppendChild.call(this, child);
784 }; 723 };
785 724
786 /** 725 /**
787 * @override 726 * @override
788 * @param {?Node} child 727 * @param {?Node} child
789 * @param {?Node} anchor 728 * @param {?Node} anchor
790 * @return {!Node} 729 * @return {!Node}
791 * @suppress {duplicate} 730 * @suppress {duplicate}
792 */ 731 */
793 Element.prototype.insertBefore = function(child, anchor) 732 Element.prototype.insertBefore = function(child, anchor) {
794 { 733 WebInspector.Widget.__assert(
795 WebInspector.Widget.__assert(!child.__widget || child.parentElement === this , "Attempt to add widget via regular DOM operation."); 734 !child.__widget || child.parentElement === this, 'Attempt to add widget vi a regular DOM operation.');
796 return WebInspector.Widget._originalInsertBefore.call(this, child, anchor); 735 return WebInspector.Widget._originalInsertBefore.call(this, child, anchor);
797 }; 736 };
798 737
799 /** 738 /**
800 * @override 739 * @override
801 * @param {?Node} child 740 * @param {?Node} child
802 * @return {!Node} 741 * @return {!Node}
803 * @suppress {duplicate} 742 * @suppress {duplicate}
804 */ 743 */
805 Element.prototype.removeChild = function(child) 744 Element.prototype.removeChild = function(child) {
806 { 745 WebInspector.Widget.__assert(
807 WebInspector.Widget.__assert(!child.__widgetCounter && !child.__widget, "Att empt to remove element containing widget via regular DOM operation"); 746 !child.__widgetCounter && !child.__widget,
808 return WebInspector.Widget._originalRemoveChild.call(this, child); 747 'Attempt to remove element containing widget via regular DOM operation');
748 return WebInspector.Widget._originalRemoveChild.call(this, child);
809 }; 749 };
810 750
811 Element.prototype.removeChildren = function() 751 Element.prototype.removeChildren = function() {
812 { 752 WebInspector.Widget.__assert(
813 WebInspector.Widget.__assert(!this.__widgetCounter, "Attempt to remove eleme nt containing widget via regular DOM operation"); 753 !this.__widgetCounter, 'Attempt to remove element containing widget via re gular DOM operation');
814 WebInspector.Widget._originalRemoveChildren.call(this); 754 WebInspector.Widget._originalRemoveChildren.call(this);
815 }; 755 };
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698