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

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

Issue 2658383002: [DevTools] Make UI.GlassPane position contentElement for different overlay controls. (Closed)
Patch Set: GlassPane Created 3 years, 10 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
OLDNEW
1 /* 1 /*
2 * Copyright (C) 2013 Google Inc. All rights reserved. 2 * Copyright (C) 2013 Google Inc. All rights reserved.
3 * 3 *
4 * Redistribution and use in source and binary forms, with or without 4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions are 5 * modification, are permitted provided that the following conditions are
6 * met: 6 * met:
7 * 7 *
8 * * Redistributions of source code must retain the above copyright 8 * * 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 * * Redistributions in binary form must reproduce the above 10 * * Redistributions in binary form must reproduce the above
(...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after
46 }; 46 };
47 47
48 /** 48 /**
49 * @implements {UI.ListDelegate} 49 * @implements {UI.ListDelegate}
50 */ 50 */
51 UI.SuggestBox = class { 51 UI.SuggestBox = class {
52 /** 52 /**
53 * @param {!UI.SuggestBoxDelegate} suggestBoxDelegate 53 * @param {!UI.SuggestBoxDelegate} suggestBoxDelegate
54 * @param {number=} maxItemsHeight 54 * @param {number=} maxItemsHeight
55 * @param {boolean=} captureEnter 55 * @param {boolean=} captureEnter
56 * @suppressGlobalPropertiesCheck
56 */ 57 */
57 constructor(suggestBoxDelegate, maxItemsHeight, captureEnter) { 58 constructor(suggestBoxDelegate, maxItemsHeight, captureEnter) {
58 this._suggestBoxDelegate = suggestBoxDelegate; 59 this._suggestBoxDelegate = suggestBoxDelegate;
59 this._maxItemsHeight = maxItemsHeight; 60 this._maxItemsHeight = maxItemsHeight;
61 this._captureEnter = captureEnter;
60 this._maybeHideBound = this._maybeHide.bind(this); 62 this._maybeHideBound = this._maybeHide.bind(this);
61 this._hideBound = this.hide.bind(this); 63 this._hideBound = this.hide.bind(this);
62 this._container = createElementWithClass('div', 'suggest-box-container');
63 this._rowHeight = 17; 64 this._rowHeight = 17;
65 this._userInteracted = false;
66 this._userEnteredText = '';
67 this._hideTimeoutId = 0;
68 /** @type {?string} */
69 this._onlyCompletion = null;
70
71 var container = createElement('div');
72 var shadowRoot = UI.createShadowRootWithCoreStyles(container, 'ui/suggestBox .css');
73
64 /** @type {!UI.ListControl<!UI.SuggestBox.Suggestion>} */ 74 /** @type {!UI.ListControl<!UI.SuggestBox.Suggestion>} */
65 this._list = new UI.ListControl(this, UI.ListMode.EqualHeightItems); 75 this._list = new UI.ListControl(this, UI.ListMode.EqualHeightItems);
66 this._element = this._list.element; 76 this._element = this._list.element;
67 this._element.classList.add('suggest-box'); 77 this._element.classList.add('suggest-box');
68 this._container.appendChild(this._element); 78 shadowRoot.appendChild(this._element);
69 this._element.addEventListener('mousedown', this._onBoxMouseDown.bind(this), true); 79 this._element.addEventListener('mousedown', this._onBoxMouseDown.bind(this), true);
70 this._userInteracted = false;
71 this._captureEnter = captureEnter;
72 this._hasVerticalScroll = false;
73 this._userEnteredText = '';
74 80
75 /** @type {?UI.SuggestBox.Overlay} */ 81 // TODO(dgozman): take document in constructor.
76 this._overlay = null; 82 this._glassPane = new UI.GlassPane(document, false /* dimmed */, false /* bl ockPointerEvents */);
77 /** @type {?AnchorBox} */ 83 this._glassPane.setAnchorBehavior(UI.GlassPane.AnchorBehavior.PreferTop);
pfeldman 2017/02/01 00:07:19 PreferBottom
dgozman 2017/02/01 16:19:44 Done.
78 this._lastAnchorBox = null; 84 this._glassPane.setContentElement(container);
79 this._lastItemCount = 0;
80 this._hideTimeoutId = 0;
81 /** @type {?Element} */
82 this._bodyElement = null;
83 /** @type {?string} */
84 this._onlyCompletion = null;
85 } 85 }
86 86
87 /** 87 /**
88 * @return {boolean} 88 * @return {boolean}
89 */ 89 */
90 visible() { 90 visible() {
91 return !!this._container.parentElement; 91 return this._glassPane.visible();
92 } 92 }
93 93
94 /** 94 /**
95 * @param {!AnchorBox} anchorBox 95 * @param {!AnchorBox} anchorBox
96 */ 96 */
97 setPosition(anchorBox) { 97 setPosition(anchorBox) {
98 this._updateBoxPosition(anchorBox, this._list.length()); 98 this._glassPane.setAnchorBox(anchorBox);
99 } 99 this._glassPane.positionContent();
100
101 /**
102 * @param {!AnchorBox} anchorBox
103 * @param {number} length
104 */
105 _updateBoxPosition(anchorBox, length) {
106 console.assert(this._overlay);
107 if (this._lastAnchorBox && this._lastAnchorBox.equals(anchorBox) && this._la stItemCount === length)
108 return;
109 this._lastItemCount = length;
110 this._lastAnchorBox = anchorBox;
111
112 // Position relative to main DevTools element.
113 var container = UI.Dialog.modalHostView().element;
114 anchorBox = anchorBox.relativeToElement(container);
115 var totalHeight = container.offsetHeight;
116 var aboveHeight = anchorBox.y;
117 var underHeight = totalHeight - anchorBox.y - anchorBox.height;
118
119 this._overlay.setLeftOffset(anchorBox.x);
120
121 var under = underHeight >= aboveHeight;
122 if (under)
123 this._overlay.setVerticalOffset(anchorBox.y + anchorBox.height, true);
124 else
125 this._overlay.setVerticalOffset(totalHeight - anchorBox.y, false);
126
127 var spacer = 6;
128 var maxHeight = Math.min(
129 Math.max(underHeight, aboveHeight) - spacer,
130 this._maxItemsHeight ? this._maxItemsHeight * this._rowHeight : Infinity );
131 var height = this._rowHeight * length;
132 this._hasVerticalScroll = height > maxHeight;
133 this._element.style.height = Math.min(maxHeight, height) + 'px';
134 } 100 }
135 101
136 /** 102 /**
137 * @param {!UI.SuggestBox.Suggestions} items 103 * @param {!UI.SuggestBox.Suggestions} items
138 */ 104 */
139 _updateWidth(items) { 105 _updateMaxSize(items) {
140 if (this._hasVerticalScroll) { 106 var maxWidth = this._maxWidth(items);
141 this._element.style.width = '100vw'; 107 var length = this._maxItemsHeight ? Math.min(this._maxItemsHeight, items.len gth) : items.length;
142 return; 108 var maxHeight = length * this._rowHeight;
143 } 109 this._glassPane.setMaxContentSize(new UI.Size(maxWidth, maxHeight));
110 }
111
112 /**
113 * @param {!UI.SuggestBox.Suggestions} items
114 * @return {number}
115 */
116 _maxWidth(items) {
117 var kMaxWidth = 300;
144 if (!items.length) 118 if (!items.length)
145 return; 119 return kMaxWidth;
146 // If there are no scrollbars, set the width to the width of the largest row .
147 var maxItem; 120 var maxItem;
148 var maxLength = -Infinity; 121 var maxLength = -Infinity;
149 for (var i = 0; i < items.length; i++) { 122 for (var i = 0; i < items.length; i++) {
150 var length = items[i].title.length + (items[i].subtitle || '').length; 123 var length = items[i].title.length + (items[i].subtitle || '').length;
151 if (length > maxLength) { 124 if (length > maxLength) {
152 maxLength = length; 125 maxLength = length;
153 maxItem = items[i]; 126 maxItem = items[i];
154 } 127 }
155 } 128 }
156 this._element.style.width = 129 var element = this.createElementForItem(/** @type {!UI.SuggestBox.Suggestion } */ (maxItem));
157 UI.measurePreferredSize( 130 return Math.min(kMaxWidth, UI.measurePreferredSize(element, this._element).w idth);
158 this.createElementForItem(/** @type {!UI.SuggestBox.Suggestion} */ (maxItem)), this._element)
159 .width +
160 'px';
161 } 131 }
162 132
163 /** 133 /**
164 * @param {!Event} event 134 * @param {!Event} event
165 */ 135 */
166 _onBoxMouseDown(event) { 136 _onBoxMouseDown(event) {
167 if (this._hideTimeoutId) { 137 if (this._hideTimeoutId) {
168 window.clearTimeout(this._hideTimeoutId); 138 window.clearTimeout(this._hideTimeoutId);
169 this._hideTimeoutId = 0; 139 this._hideTimeoutId = 0;
170 } 140 }
171 event.preventDefault(); 141 event.preventDefault();
172 } 142 }
173 143
174 _maybeHide() { 144 _maybeHide() {
175 if (!this._hideTimeoutId) 145 if (!this._hideTimeoutId)
176 this._hideTimeoutId = window.setTimeout(this._hideBound, 0); 146 this._hideTimeoutId = window.setTimeout(this._hideBound, 0);
177 } 147 }
178 148
179 /**
180 * // FIXME: make SuggestBox work for multiple documents.
181 * @suppressGlobalPropertiesCheck
182 */
183 _show() { 149 _show() {
184 if (this.visible()) 150 if (this.visible())
185 return; 151 return;
186 this._bodyElement = document.body; 152 this._glassPane.show();
187 this._bodyElement.addEventListener('mousedown', this._maybeHideBound, true); 153 this._glassPane.element.ownerDocument.body.addEventListener('mousedown', thi s._maybeHideBound, true);
pfeldman 2017/02/01 00:07:18 You don't need it anymore.
dgozman 2017/02/01 16:19:44 Done.
188 this._element.ownerDocument.defaultView.addEventListener('resize', this._hid eBound, false); 154 this._glassPane.element.window().addEventListener('resize', this._hideBound, false);
pfeldman 2017/02/01 00:07:19 You don't need it anymore
dgozman 2017/02/01 16:19:44 Done.
189 this._overlay = new UI.SuggestBox.Overlay();
190 this._overlay.setContentElement(this._container);
191 this._rowHeight = 155 this._rowHeight =
192 UI.measurePreferredSize(this.createElementForItem({title: '1', subtitle: '12'}), this._element).height; 156 UI.measurePreferredSize(this.createElementForItem({title: '1', subtitle: '12'}), this._element).height;
193 } 157 }
194 158
195 hide() { 159 hide() {
196 if (!this.visible()) 160 if (!this.visible())
197 return; 161 return;
198
199 this._userInteracted = false; 162 this._userInteracted = false;
200 this._bodyElement.removeEventListener('mousedown', this._maybeHideBound, tru e); 163 this._glassPane.element.ownerDocument.body.removeEventListener('mousedown', this._maybeHideBound, true);
pfeldman 2017/02/01 00:07:18 You should not need it anymore.
dgozman 2017/02/01 16:19:44 Done.
201 this._element.ownerDocument.defaultView.removeEventListener('resize', this._ hideBound, false); 164 this._glassPane.element.window().removeEventListener('resize', this._hideBou nd, false);
202 this._bodyElement = null; 165 this._glassPane.hide();
203 this._container.remove();
204 this._overlay.dispose();
205 this._overlay = null;
206 this._lastAnchorBox = null;
207 } 166 }
208 167
209 /** 168 /**
210 * @param {boolean=} isIntermediateSuggestion 169 * @param {boolean=} isIntermediateSuggestion
211 * @return {boolean} 170 * @return {boolean}
212 */ 171 */
213 _applySuggestion(isIntermediateSuggestion) { 172 _applySuggestion(isIntermediateSuggestion) {
214 if (this._onlyCompletion) { 173 if (this._onlyCompletion) {
215 this._suggestBoxDelegate.applySuggestion(this._onlyCompletion, isIntermedi ateSuggestion); 174 this._suggestBoxDelegate.applySuggestion(this._onlyCompletion, isIntermedi ateSuggestion);
216 return true; 175 return true;
(...skipping 125 matching lines...) Expand 10 before | Expand all | Expand 10 after
342 * @param {boolean} selectHighestPriority 301 * @param {boolean} selectHighestPriority
343 * @param {boolean} canShowForSingleItem 302 * @param {boolean} canShowForSingleItem
344 * @param {string} userEnteredText 303 * @param {string} userEnteredText
345 */ 304 */
346 updateSuggestions(anchorBox, completions, selectHighestPriority, canShowForSin gleItem, userEnteredText) { 305 updateSuggestions(anchorBox, completions, selectHighestPriority, canShowForSin gleItem, userEnteredText) {
347 this._onlyCompletion = null; 306 this._onlyCompletion = null;
348 if (this._canShowBox(completions, canShowForSingleItem, userEnteredText)) { 307 if (this._canShowBox(completions, canShowForSingleItem, userEnteredText)) {
349 this._userEnteredText = userEnteredText; 308 this._userEnteredText = userEnteredText;
350 309
351 this._show(); 310 this._show();
352 this._updateBoxPosition(anchorBox, completions.length); 311 this._updateMaxSize(completions);
353 this._updateWidth(completions); 312 this._glassPane.setAnchorBox(anchorBox);
313 this._glassPane.positionContent();
354 this._list.invalidateItemHeight(); 314 this._list.invalidateItemHeight();
355 this._list.replaceAllItems(completions); 315 this._list.replaceAllItems(completions);
356 316
357 if (selectHighestPriority) { 317 if (selectHighestPriority) {
358 var highestPriorityItem = completions[0]; 318 var highestPriorityItem = completions[0];
359 var highestPriority = completions[0].priority || 0; 319 var highestPriority = completions[0].priority || 0;
360 for (var i = 0; i < completions.length; i++) { 320 for (var i = 0; i < completions.length; i++) {
361 var priority = completions[i].priority || 0; 321 var priority = completions[i].priority || 0;
362 if (highestPriority < priority) { 322 if (highestPriority < priority) {
363 highestPriority = priority; 323 highestPriority = priority;
(...skipping 60 matching lines...) Expand 10 before | Expand all | Expand 10 after
424 384
425 /** 385 /**
426 * @typedef {!{title: string, subtitle: (string|undefined), iconType: (string|un defined), priority: (number|undefined), isSecondary: (boolean|undefined)}} 386 * @typedef {!{title: string, subtitle: (string|undefined), iconType: (string|un defined), priority: (number|undefined), isSecondary: (boolean|undefined)}}
427 */ 387 */
428 UI.SuggestBox.Suggestion; 388 UI.SuggestBox.Suggestion;
429 389
430 /** 390 /**
431 * @typedef {!Array<!UI.SuggestBox.Suggestion>} 391 * @typedef {!Array<!UI.SuggestBox.Suggestion>}
432 */ 392 */
433 UI.SuggestBox.Suggestions; 393 UI.SuggestBox.Suggestions;
434
435 UI.SuggestBox.Overlay = class {
436 /**
437 * // FIXME: make SuggestBox work for multiple documents.
438 * @suppressGlobalPropertiesCheck
439 */
440 constructor() {
441 this.element = createElementWithClass('div', 'suggest-box-overlay');
442 var root = UI.createShadowRootWithCoreStyles(this.element, 'ui/suggestBox.cs s');
443 this._leftSpacerElement = root.createChild('div', 'suggest-box-left-spacer') ;
444 this._horizontalElement = root.createChild('div', 'suggest-box-horizontal');
445 this._topSpacerElement = this._horizontalElement.createChild('div', 'suggest -box-top-spacer');
446 this._bottomSpacerElement = this._horizontalElement.createChild('div', 'sugg est-box-bottom-spacer');
447 this._resize();
448 document.body.appendChild(this.element);
449 }
450
451 /**
452 * @param {number} offset
453 */
454 setLeftOffset(offset) {
455 this._leftSpacerElement.style.flexBasis = offset + 'px';
456 }
457
458 /**
459 * @param {number} offset
460 * @param {boolean} isTopOffset
461 */
462 setVerticalOffset(offset, isTopOffset) {
463 this.element.classList.toggle('under-anchor', isTopOffset);
464
465 if (isTopOffset) {
466 this._bottomSpacerElement.style.flexBasis = 'auto';
467 this._topSpacerElement.style.flexBasis = offset + 'px';
468 } else {
469 this._bottomSpacerElement.style.flexBasis = offset + 'px';
470 this._topSpacerElement.style.flexBasis = 'auto';
471 }
472 }
473
474 /**
475 * @param {!Element} element
476 */
477 setContentElement(element) {
478 this._horizontalElement.insertBefore(element, this._bottomSpacerElement);
479 }
480
481 _resize() {
482 var container = UI.Dialog.modalHostView().element;
483 var containerBox = container.boxInWindow(container.ownerDocument.defaultView );
484
485 this.element.style.left = containerBox.x + 'px';
486 this.element.style.top = containerBox.y + 'px';
487 this.element.style.height = containerBox.height + 'px';
488 this.element.style.width = containerBox.width + 'px';
489 }
490
491 dispose() {
492 this.element.remove();
493 }
494 };
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698