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

Side by Side Diff: Source/devtools/front_end/ui/View.js

Issue 1113813002: [DevTools] Rename View to Widget. (Closed) Base URL: svn://svn.chromium.org/blink/trunk
Patch Set: rebased Created 5 years, 7 months 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 | Annotate | Revision Log
« no previous file with comments | « Source/devtools/front_end/ui/UIUtils.js ('k') | Source/devtools/front_end/ui/Widget.js » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
1 /*
2 * Copyright (C) 2008 Apple Inc. All Rights Reserved.
3 * Copyright (C) 2011 Google Inc. All Rights Reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 *
14 * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
15 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
17 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
18 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
19 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
20 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
21 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
22 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
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.
25 */
26
27 /**
28 * @constructor
29 * @extends {WebInspector.Object}
30 * @param {boolean=} isWebComponent
31 */
32 WebInspector.View = function(isWebComponent)
33 {
34 this.contentElement = createElementWithClass("div", "view");
35 if (isWebComponent) {
36 WebInspector.installComponentRootStyles(this.contentElement);
37 this.element = createElementWithClass("div", "vbox flex-auto");
38 this._shadowRoot = this.element.createShadowRoot();
39 this._shadowRoot.appendChild(this.contentElement);
40 } else {
41 this.element = this.contentElement;
42 }
43 this._isWebComponent = isWebComponent;
44 this.element.__view = this;
45 this._visible = true;
46 this._isRoot = false;
47 this._isShowing = false;
48 this._children = [];
49 this._hideOnDetach = false;
50 this._notificationDepth = 0;
51 }
52
53 /**
54 * @param {string} cssFile
55 * @return {!Element}
56 */
57 WebInspector.View.createStyleElement = function(cssFile)
58 {
59 var content = Runtime.cachedResources[cssFile] || "";
60 if (!content)
61 console.error(cssFile + " not preloaded. Check module.json");
62 var styleElement = createElement("style");
63 styleElement.type = "text/css";
64 styleElement.textContent = content;
65 return styleElement;
66 }
67
68 WebInspector.View.prototype = {
69 markAsRoot: function()
70 {
71 WebInspector.installComponentRootStyles(this.element);
72 WebInspector.View.__assert(!this.element.parentElement, "Attempt to mark as root attached node");
73 this._isRoot = true;
74 },
75
76 /**
77 * @return {?WebInspector.View}
78 */
79 parentView: function()
80 {
81 return this._parentView;
82 },
83
84 /**
85 * @return {!Array.<!WebInspector.View>}
86 */
87 children: function()
88 {
89 return this._children;
90 },
91
92 /**
93 * @param {!WebInspector.View} view
94 * @protected
95 */
96 childWasDetached: function(view)
97 {
98 },
99
100 /**
101 * @return {boolean}
102 */
103 isShowing: function()
104 {
105 return this._isShowing;
106 },
107
108 /**
109 * @return {boolean}
110 */
111 _shouldHideOnDetach: function()
112 {
113 if (this._hideOnDetach)
114 return true;
115 for (var child of this._children) {
116 if (child._shouldHideOnDetach())
117 return true;
118 }
119 return false;
120 },
121
122 setHideOnDetach: function()
123 {
124 this._hideOnDetach = true;
125 },
126
127 /**
128 * @return {boolean}
129 */
130 _inNotification: function()
131 {
132 return !!this._notificationDepth || (this._parentView && this._parentVie w._inNotification());
133 },
134
135 _parentIsShowing: function()
136 {
137 if (this._isRoot)
138 return true;
139 return this._parentView && this._parentView.isShowing();
140 },
141
142 /**
143 * @param {function(this:WebInspector.View)} method
144 */
145 _callOnVisibleChildren: function(method)
146 {
147 var copy = this._children.slice();
148 for (var i = 0; i < copy.length; ++i) {
149 if (copy[i]._parentView === this && copy[i]._visible)
150 method.call(copy[i]);
151 }
152 },
153
154 _processWillShow: function()
155 {
156 this._callOnVisibleChildren(this._processWillShow);
157 this._isShowing = true;
158 },
159
160 _processWasShown: function()
161 {
162 if (this._inNotification())
163 return;
164 this.restoreScrollPositions();
165 this._notify(this.wasShown);
166 this._callOnVisibleChildren(this._processWasShown);
167 },
168
169 _processWillHide: function()
170 {
171 if (this._inNotification())
172 return;
173 this.storeScrollPositions();
174
175 this._callOnVisibleChildren(this._processWillHide);
176 this._notify(this.willHide);
177 this._isShowing = false;
178 },
179
180 _processWasHidden: function()
181 {
182 this._callOnVisibleChildren(this._processWasHidden);
183 },
184
185 _processOnResize: function()
186 {
187 if (this._inNotification())
188 return;
189 if (!this.isShowing())
190 return;
191 this._notify(this.onResize);
192 this._callOnVisibleChildren(this._processOnResize);
193 },
194
195 /**
196 * @param {function(this:WebInspector.View)} notification
197 */
198 _notify: function(notification)
199 {
200 ++this._notificationDepth;
201 try {
202 notification.call(this);
203 } finally {
204 --this._notificationDepth;
205 }
206 },
207
208 wasShown: function()
209 {
210 },
211
212 willHide: function()
213 {
214 },
215
216 onResize: function()
217 {
218 },
219
220 onLayout: function()
221 {
222 },
223
224 /**
225 * @param {?Element} parentElement
226 * @param {?Element=} insertBefore
227 */
228 show: function(parentElement, insertBefore)
229 {
230 WebInspector.View.__assert(parentElement, "Attempt to attach view with n o parent element");
231
232 // Update view hierarchy
233 if (this.element.parentElement !== parentElement) {
234 if (this.element.parentElement)
235 this.detach();
236
237 var currentParent = parentElement;
238 while (currentParent && !currentParent.__view)
239 currentParent = currentParent.parentElementOrShadowHost();
240
241 if (currentParent) {
242 this._parentView = currentParent.__view;
243 this._parentView._children.push(this);
244 this._isRoot = false;
245 } else
246 WebInspector.View.__assert(this._isRoot, "Attempt to attach view to orphan node");
247 } else if (this._visible) {
248 return;
249 }
250
251 this._visible = true;
252
253 if (this._parentIsShowing())
254 this._processWillShow();
255
256 this.element.classList.add("visible");
257
258 // Reparent
259 if (this.element.parentElement !== parentElement) {
260 WebInspector.View._incrementViewCounter(parentElement, this.element) ;
261 if (insertBefore)
262 WebInspector.View._originalInsertBefore.call(parentElement, this .element, insertBefore);
263 else
264 WebInspector.View._originalAppendChild.call(parentElement, this. element);
265 }
266
267 if (this._parentIsShowing())
268 this._processWasShown();
269
270 if (this._parentView && this._hasNonZeroConstraints())
271 this._parentView.invalidateConstraints();
272 else
273 this._processOnResize();
274 },
275
276 /**
277 * @param {boolean=} overrideHideOnDetach
278 */
279 detach: function(overrideHideOnDetach)
280 {
281 var parentElement = this.element.parentElement;
282 if (!parentElement)
283 return;
284
285 if (this._parentIsShowing())
286 this._processWillHide();
287
288 if (!overrideHideOnDetach && this._shouldHideOnDetach()) {
289 this.element.classList.remove("visible");
290 this._visible = false;
291 if (this._parentIsShowing())
292 this._processWasHidden();
293 if (this._parentView && this._hasNonZeroConstraints())
294 this._parentView.invalidateConstraints();
295 return;
296 }
297
298 // Force legal removal
299 WebInspector.View._decrementViewCounter(parentElement, this.element);
300 WebInspector.View._originalRemoveChild.call(parentElement, this.element) ;
301
302 this._visible = false;
303 if (this._parentIsShowing())
304 this._processWasHidden();
305
306 // Update view hierarchy
307 if (this._parentView) {
308 var childIndex = this._parentView._children.indexOf(this);
309 WebInspector.View.__assert(childIndex >= 0, "Attempt to remove non-c hild view");
310 this._parentView._children.splice(childIndex, 1);
311 this._parentView.childWasDetached(this);
312 var parent = this._parentView;
313 this._parentView = null;
314 if (this._hasNonZeroConstraints())
315 parent.invalidateConstraints();
316 } else
317 WebInspector.View.__assert(this._isRoot, "Removing non-root view fro m DOM");
318 },
319
320 detachChildViews: function()
321 {
322 var children = this._children.slice();
323 for (var i = 0; i < children.length; ++i)
324 children[i].detach();
325 },
326
327 /**
328 * @return {!Array.<!Element>}
329 */
330 elementsToRestoreScrollPositionsFor: function()
331 {
332 return [this.element];
333 },
334
335 storeScrollPositions: function()
336 {
337 var elements = this.elementsToRestoreScrollPositionsFor();
338 for (var i = 0; i < elements.length; ++i) {
339 var container = elements[i];
340 container._scrollTop = container.scrollTop;
341 container._scrollLeft = container.scrollLeft;
342 }
343 },
344
345 restoreScrollPositions: function()
346 {
347 var elements = this.elementsToRestoreScrollPositionsFor();
348 for (var i = 0; i < elements.length; ++i) {
349 var container = elements[i];
350 if (container._scrollTop)
351 container.scrollTop = container._scrollTop;
352 if (container._scrollLeft)
353 container.scrollLeft = container._scrollLeft;
354 }
355 },
356
357 doResize: function()
358 {
359 if (!this.isShowing())
360 return;
361 // No matter what notification we are in, dispatching onResize is not ne eded.
362 if (!this._inNotification())
363 this._callOnVisibleChildren(this._processOnResize);
364 },
365
366 doLayout: function()
367 {
368 if (!this.isShowing())
369 return;
370 this._notify(this.onLayout);
371 this.doResize();
372 },
373
374 /**
375 * @param {string} cssFile
376 */
377 registerRequiredCSS: function(cssFile)
378 {
379 (this._isWebComponent ? this._shadowRoot : this.element).appendChild(Web Inspector.View.createStyleElement(cssFile));
380 },
381
382 printViewHierarchy: function()
383 {
384 var lines = [];
385 this._collectViewHierarchy("", lines);
386 console.log(lines.join("\n"));
387 },
388
389 _collectViewHierarchy: function(prefix, lines)
390 {
391 lines.push(prefix + "[" + this.element.className + "]" + (this._children .length ? " {" : ""));
392
393 for (var i = 0; i < this._children.length; ++i)
394 this._children[i]._collectViewHierarchy(prefix + " ", lines);
395
396 if (this._children.length)
397 lines.push(prefix + "}");
398 },
399
400 /**
401 * @return {!Element}
402 */
403 defaultFocusedElement: function()
404 {
405 return this._defaultFocusedElement || this.element;
406 },
407
408 /**
409 * @param {!Element} element
410 */
411 setDefaultFocusedElement: function(element)
412 {
413 this._defaultFocusedElement = element;
414 },
415
416 focus: function()
417 {
418 var element = this.defaultFocusedElement();
419 if (!element || element.isAncestor(this.element.ownerDocument.activeElem ent))
420 return;
421
422 WebInspector.setCurrentFocusElement(element);
423 },
424
425 /**
426 * @return {boolean}
427 */
428 hasFocus: function()
429 {
430 var activeElement = this.element.ownerDocument.activeElement;
431 return activeElement && activeElement.isSelfOrDescendant(this.element);
432 },
433
434 /**
435 * @return {!Size}
436 */
437 measurePreferredSize: function()
438 {
439 var document = this.element.ownerDocument;
440 WebInspector.View._originalAppendChild.call(document.body, this.element) ;
441 this.element.positionAt(0, 0);
442 var result = new Size(this.element.offsetWidth, this.element.offsetHeigh t);
443 this.element.positionAt(undefined, undefined);
444 WebInspector.View._originalRemoveChild.call(document.body, this.element) ;
445 return result;
446 },
447
448 /**
449 * @return {!Constraints}
450 */
451 calculateConstraints: function()
452 {
453 return new Constraints();
454 },
455
456 /**
457 * @return {!Constraints}
458 */
459 constraints: function()
460 {
461 if (typeof this._constraints !== "undefined")
462 return this._constraints;
463 if (typeof this._cachedConstraints === "undefined")
464 this._cachedConstraints = this.calculateConstraints();
465 return this._cachedConstraints;
466 },
467
468 /**
469 * @param {number} width
470 * @param {number} height
471 * @param {number} preferredWidth
472 * @param {number} preferredHeight
473 */
474 setMinimumAndPreferredSizes: function(width, height, preferredWidth, preferr edHeight)
475 {
476 this._constraints = new Constraints(new Size(width, height), new Size(pr eferredWidth, preferredHeight));
477 this.invalidateConstraints();
478 },
479
480 /**
481 * @param {number} width
482 * @param {number} height
483 */
484 setMinimumSize: function(width, height)
485 {
486 this._constraints = new Constraints(new Size(width, height));
487 this.invalidateConstraints();
488 },
489
490 /**
491 * @return {boolean}
492 */
493 _hasNonZeroConstraints: function()
494 {
495 var constraints = this.constraints();
496 return !!(constraints.minimum.width || constraints.minimum.height || con straints.preferred.width || constraints.preferred.height);
497 },
498
499 invalidateConstraints: function()
500 {
501 var cached = this._cachedConstraints;
502 delete this._cachedConstraints;
503 var actual = this.constraints();
504 if (!actual.isEqual(cached) && this._parentView)
505 this._parentView.invalidateConstraints();
506 else
507 this.doLayout();
508 },
509
510 __proto__: WebInspector.Object.prototype
511 }
512
513 WebInspector.View._originalAppendChild = Element.prototype.appendChild;
514 WebInspector.View._originalInsertBefore = Element.prototype.insertBefore;
515 WebInspector.View._originalRemoveChild = Element.prototype.removeChild;
516 WebInspector.View._originalRemoveChildren = Element.prototype.removeChildren;
517
518 WebInspector.View._incrementViewCounter = function(parentElement, childElement)
519 {
520 var count = (childElement.__viewCounter || 0) + (childElement.__view ? 1 : 0 );
521 if (!count)
522 return;
523
524 while (parentElement) {
525 parentElement.__viewCounter = (parentElement.__viewCounter || 0) + count ;
526 parentElement = parentElement.parentElementOrShadowHost();
527 }
528 }
529
530 WebInspector.View._decrementViewCounter = function(parentElement, childElement)
531 {
532 var count = (childElement.__viewCounter || 0) + (childElement.__view ? 1 : 0 );
533 if (!count)
534 return;
535
536 while (parentElement) {
537 parentElement.__viewCounter -= count;
538 parentElement = parentElement.parentElementOrShadowHost();
539 }
540 }
541
542 WebInspector.View.__assert = function(condition, message)
543 {
544 if (!condition) {
545 console.trace();
546 throw new Error(message);
547 }
548 }
549
550 /**
551 * @constructor
552 * @extends {WebInspector.View}
553 * @param {boolean=} isWebComponent
554 */
555 WebInspector.VBox = function(isWebComponent)
556 {
557 WebInspector.View.call(this, isWebComponent);
558 this.contentElement.classList.add("vbox");
559 };
560
561 WebInspector.VBox.prototype = {
562 /**
563 * @override
564 * @return {!Constraints}
565 */
566 calculateConstraints: function()
567 {
568 var constraints = new Constraints();
569
570 /**
571 * @this {!WebInspector.View}
572 * @suppressReceiverCheck
573 */
574 function updateForChild()
575 {
576 var child = this.constraints();
577 constraints = constraints.widthToMax(child);
578 constraints = constraints.addHeight(child);
579 }
580
581 this._callOnVisibleChildren(updateForChild);
582 return constraints;
583 },
584
585 __proto__: WebInspector.View.prototype
586 };
587
588 /**
589 * @constructor
590 * @extends {WebInspector.View}
591 * @param {boolean=} isWebComponent
592 */
593 WebInspector.HBox = function(isWebComponent)
594 {
595 WebInspector.View.call(this, isWebComponent);
596 this.contentElement.classList.add("hbox");
597 };
598
599 WebInspector.HBox.prototype = {
600 /**
601 * @override
602 * @return {!Constraints}
603 */
604 calculateConstraints: function()
605 {
606 var constraints = new Constraints();
607
608 /**
609 * @this {!WebInspector.View}
610 * @suppressReceiverCheck
611 */
612 function updateForChild()
613 {
614 var child = this.constraints();
615 constraints = constraints.addWidth(child);
616 constraints = constraints.heightToMax(child);
617 }
618
619 this._callOnVisibleChildren(updateForChild);
620 return constraints;
621 },
622
623 __proto__: WebInspector.View.prototype
624 };
625
626 /**
627 * @constructor
628 * @extends {WebInspector.VBox}
629 * @param {function()} resizeCallback
630 */
631 WebInspector.VBoxWithResizeCallback = function(resizeCallback)
632 {
633 WebInspector.VBox.call(this);
634 this._resizeCallback = resizeCallback;
635 }
636
637 WebInspector.VBoxWithResizeCallback.prototype = {
638 onResize: function()
639 {
640 this._resizeCallback();
641 },
642
643 __proto__: WebInspector.VBox.prototype
644 }
645
646 /**
647 * @override
648 * @param {?Node} child
649 * @return {?Node}
650 * @suppress {duplicate}
651 */
652 Element.prototype.appendChild = function(child)
653 {
654 WebInspector.View.__assert(!child.__view || child.parentElement === this, "A ttempt to add view via regular DOM operation.");
655 return WebInspector.View._originalAppendChild.call(this, child);
656 }
657
658 /**
659 * @override
660 * @param {?Node} child
661 * @param {?Node} anchor
662 * @return {!Node}
663 * @suppress {duplicate}
664 */
665 Element.prototype.insertBefore = function(child, anchor)
666 {
667 WebInspector.View.__assert(!child.__view || child.parentElement === this, "A ttempt to add view via regular DOM operation.");
668 return WebInspector.View._originalInsertBefore.call(this, child, anchor);
669 }
670
671 /**
672 * @override
673 * @param {?Node} child
674 * @return {!Node}
675 * @suppress {duplicate}
676 */
677 Element.prototype.removeChild = function(child)
678 {
679 WebInspector.View.__assert(!child.__viewCounter && !child.__view, "Attempt t o remove element containing view via regular DOM operation");
680 return WebInspector.View._originalRemoveChild.call(this, child);
681 }
682
683 Element.prototype.removeChildren = function()
684 {
685 WebInspector.View.__assert(!this.__viewCounter, "Attempt to remove element c ontaining view via regular DOM operation");
686 WebInspector.View._originalRemoveChildren.call(this);
687 }
OLDNEW
« no previous file with comments | « Source/devtools/front_end/ui/UIUtils.js ('k') | Source/devtools/front_end/ui/Widget.js » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698