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

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: rebased 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;
60 this._maybeHideBound = this._maybeHide.bind(this); 61 this._captureEnter = captureEnter;
61 this._hideBound = this.hide.bind(this);
62 this._container = createElementWithClass('div', 'suggest-box-container');
63 this._rowHeight = 17; 62 this._rowHeight = 17;
63 this._userInteracted = false;
64 this._userEnteredText = '';
65 /** @type {?string} */
66 this._onlyCompletion = null;
67
64 /** @type {!UI.ListControl<!UI.SuggestBox.Suggestion>} */ 68 /** @type {!UI.ListControl<!UI.SuggestBox.Suggestion>} */
65 this._list = new UI.ListControl(this, UI.ListMode.EqualHeightItems); 69 this._list = new UI.ListControl(this, UI.ListMode.EqualHeightItems);
66 this._element = this._list.element; 70 this._element = this._list.element;
67 this._element.classList.add('suggest-box'); 71 this._element.classList.add('suggest-box');
68 this._container.appendChild(this._element); 72 this._element.addEventListener('mousedown', event => event.preventDefault(), true);
69 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 73
75 /** @type {?UI.SuggestBox.Overlay} */ 74 // TODO(dgozman): take document in constructor.
76 this._overlay = null; 75 this._glassPane =
77 /** @type {?AnchorBox} */ 76 new UI.GlassPane(document, false /* dimmed */, false /* blockPointerEven ts */, this.hide.bind(this));
78 this._lastAnchorBox = null; 77 this._glassPane.setAnchorBehavior(UI.GlassPane.AnchorBehavior.PreferBottom);
79 this._lastItemCount = 0; 78 var shadowRoot = UI.createShadowRootWithCoreStyles(this._glassPane.contentEl ement, 'ui/suggestBox.css');
80 this._hideTimeoutId = 0; 79 shadowRoot.appendChild(this._element);
81 /** @type {?Element} */
82 this._bodyElement = null;
83 /** @type {?string} */
84 this._onlyCompletion = null;
85 } 80 }
86 81
87 /** 82 /**
88 * @return {boolean} 83 * @return {boolean}
89 */ 84 */
90 visible() { 85 visible() {
91 return !!this._container.parentElement; 86 return this._glassPane.visible();
92 } 87 }
93 88
94 /** 89 /**
95 * @param {!AnchorBox} anchorBox 90 * @param {!AnchorBox} anchorBox
96 */ 91 */
97 setPosition(anchorBox) { 92 setPosition(anchorBox) {
98 this._updateBoxPosition(anchorBox, this._list.length()); 93 this._glassPane.setContentAnchorBox(anchorBox);
99 }
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 } 94 }
135 95
136 /** 96 /**
137 * @param {!UI.SuggestBox.Suggestions} items 97 * @param {!UI.SuggestBox.Suggestions} items
138 */ 98 */
139 _updateWidth(items) { 99 _updateMaxSize(items) {
140 if (this._hasVerticalScroll) { 100 var maxWidth = this._maxWidth(items);
141 this._element.style.width = '100vw'; 101 var length = this._maxItemsHeight ? Math.min(this._maxItemsHeight, items.len gth) : items.length;
142 return; 102 var maxHeight = length * this._rowHeight;
143 } 103 this._glassPane.setMaxContentSize(new UI.Size(maxWidth, maxHeight));
104 }
105
106 /**
107 * @param {!UI.SuggestBox.Suggestions} items
108 * @return {number}
109 */
110 _maxWidth(items) {
111 var kMaxWidth = 300;
144 if (!items.length) 112 if (!items.length)
145 return; 113 return kMaxWidth;
146 // If there are no scrollbars, set the width to the width of the largest row .
147 var maxItem; 114 var maxItem;
148 var maxLength = -Infinity; 115 var maxLength = -Infinity;
149 for (var i = 0; i < items.length; i++) { 116 for (var i = 0; i < items.length; i++) {
150 var length = items[i].title.length + (items[i].subtitle || '').length; 117 var length = items[i].title.length + (items[i].subtitle || '').length;
151 if (length > maxLength) { 118 if (length > maxLength) {
152 maxLength = length; 119 maxLength = length;
153 maxItem = items[i]; 120 maxItem = items[i];
154 } 121 }
155 } 122 }
156 this._element.style.width = 123 var element = this.createElementForItem(/** @type {!UI.SuggestBox.Suggestion } */ (maxItem));
157 UI.measurePreferredSize( 124 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 } 125 }
162 126
163 /**
164 * @param {!Event} event
165 */
166 _onBoxMouseDown(event) {
167 if (this._hideTimeoutId) {
168 window.clearTimeout(this._hideTimeoutId);
169 this._hideTimeoutId = 0;
170 }
171 event.preventDefault();
172 }
173
174 _maybeHide() {
175 if (!this._hideTimeoutId)
176 this._hideTimeoutId = window.setTimeout(this._hideBound, 0);
177 }
178
179 /**
180 * // FIXME: make SuggestBox work for multiple documents.
181 * @suppressGlobalPropertiesCheck
182 */
183 _show() { 127 _show() {
184 if (this.visible()) 128 if (this.visible())
185 return; 129 return;
186 this._bodyElement = document.body; 130 this._glassPane.show();
187 this._bodyElement.addEventListener('mousedown', this._maybeHideBound, true);
188 this._element.ownerDocument.defaultView.addEventListener('resize', this._hid eBound, false);
189 this._overlay = new UI.SuggestBox.Overlay();
190 this._overlay.setContentElement(this._container);
191 this._rowHeight = 131 this._rowHeight =
192 UI.measurePreferredSize(this.createElementForItem({title: '1', subtitle: '12'}), this._element).height; 132 UI.measurePreferredSize(this.createElementForItem({title: '1', subtitle: '12'}), this._element).height;
193 } 133 }
194 134
195 hide() { 135 hide() {
196 if (!this.visible()) 136 if (!this.visible())
197 return; 137 return;
198
199 this._userInteracted = false; 138 this._userInteracted = false;
200 this._bodyElement.removeEventListener('mousedown', this._maybeHideBound, tru e); 139 this._glassPane.hide();
201 this._element.ownerDocument.defaultView.removeEventListener('resize', this._ hideBound, false);
202 this._bodyElement = null;
203 this._container.remove();
204 this._overlay.dispose();
205 this._overlay = null;
206 this._lastAnchorBox = null;
207 } 140 }
208 141
209 /** 142 /**
210 * @param {boolean=} isIntermediateSuggestion 143 * @param {boolean=} isIntermediateSuggestion
211 * @return {boolean} 144 * @return {boolean}
212 */ 145 */
213 _applySuggestion(isIntermediateSuggestion) { 146 _applySuggestion(isIntermediateSuggestion) {
214 if (this._onlyCompletion) { 147 if (this._onlyCompletion) {
215 this._suggestBoxDelegate.applySuggestion(this._onlyCompletion, isIntermedi ateSuggestion); 148 this._suggestBoxDelegate.applySuggestion(this._onlyCompletion, isIntermedi ateSuggestion);
216 return true; 149 return true;
(...skipping 125 matching lines...) Expand 10 before | Expand all | Expand 10 after
342 * @param {boolean} selectHighestPriority 275 * @param {boolean} selectHighestPriority
343 * @param {boolean} canShowForSingleItem 276 * @param {boolean} canShowForSingleItem
344 * @param {string} userEnteredText 277 * @param {string} userEnteredText
345 */ 278 */
346 updateSuggestions(anchorBox, completions, selectHighestPriority, canShowForSin gleItem, userEnteredText) { 279 updateSuggestions(anchorBox, completions, selectHighestPriority, canShowForSin gleItem, userEnteredText) {
347 this._onlyCompletion = null; 280 this._onlyCompletion = null;
348 if (this._canShowBox(completions, canShowForSingleItem, userEnteredText)) { 281 if (this._canShowBox(completions, canShowForSingleItem, userEnteredText)) {
349 this._userEnteredText = userEnteredText; 282 this._userEnteredText = userEnteredText;
350 283
351 this._show(); 284 this._show();
352 this._updateBoxPosition(anchorBox, completions.length); 285 this._updateMaxSize(completions);
353 this._updateWidth(completions); 286 this._glassPane.setContentAnchorBox(anchorBox);
354 this._list.invalidateItemHeight(); 287 this._list.invalidateItemHeight();
355 this._list.replaceAllItems(completions); 288 this._list.replaceAllItems(completions);
356 289
357 if (selectHighestPriority) { 290 if (selectHighestPriority) {
358 var highestPriorityItem = completions[0]; 291 var highestPriorityItem = completions[0];
359 var highestPriority = completions[0].priority || 0; 292 var highestPriority = completions[0].priority || 0;
360 for (var i = 0; i < completions.length; i++) { 293 for (var i = 0; i < completions.length; i++) {
361 var priority = completions[i].priority || 0; 294 var priority = completions[i].priority || 0;
362 if (highestPriority < priority) { 295 if (highestPriority < priority) {
363 highestPriority = priority; 296 highestPriority = priority;
(...skipping 60 matching lines...) Expand 10 before | Expand all | Expand 10 after
424 357
425 /** 358 /**
426 * @typedef {!{title: string, subtitle: (string|undefined), iconType: (string|un defined), priority: (number|undefined), isSecondary: (boolean|undefined)}} 359 * @typedef {!{title: string, subtitle: (string|undefined), iconType: (string|un defined), priority: (number|undefined), isSecondary: (boolean|undefined)}}
427 */ 360 */
428 UI.SuggestBox.Suggestion; 361 UI.SuggestBox.Suggestion;
429 362
430 /** 363 /**
431 * @typedef {!Array<!UI.SuggestBox.Suggestion>} 364 * @typedef {!Array<!UI.SuggestBox.Suggestion>}
432 */ 365 */
433 UI.SuggestBox.Suggestions; 366 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