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

Side by Side Diff: ui/webui/resources/cr_elements/cr_action_menu/cr_action_menu.js

Issue 2966163004: [cr-action-menu] Use clientWidth for rtl flipping. (Closed)
Patch Set: fix test on mac Created 3 years, 5 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
« no previous file with comments | « chrome/test/data/webui/cr_elements/cr_action_menu_test.js ('k') | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright 2016 The Chromium Authors. All rights reserved. 1 // Copyright 2016 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 /** 5 /**
6 * @typedef {{ 6 * @typedef {{
7 * top: number, 7 * top: number,
8 * left: number, 8 * left: number,
9 * width: (number|undefined), 9 * width: (number|undefined),
10 * height: (number|undefined), 10 * height: (number|undefined),
(...skipping 71 matching lines...) Expand 10 before | Expand all | Expand 10 after
82 */ 82 */
83 function getDefaultShowConfig() { 83 function getDefaultShowConfig() {
84 var doc = document.scrollingElement; 84 var doc = document.scrollingElement;
85 return { 85 return {
86 top: 0, 86 top: 0,
87 left: 0, 87 left: 0,
88 height: 0, 88 height: 0,
89 width: 0, 89 width: 0,
90 anchorAlignmentX: AnchorAlignment.AFTER_START, 90 anchorAlignmentX: AnchorAlignment.AFTER_START,
91 anchorAlignmentY: AnchorAlignment.AFTER_START, 91 anchorAlignmentY: AnchorAlignment.AFTER_START,
92 minX: doc.scrollLeft, 92 minX: 0,
93 minY: doc.scrollTop, 93 minY: 0,
94 maxX: doc.scrollLeft + window.innerWidth, 94 maxX: 0,
95 maxY: doc.scrollTop + window.innerHeight, 95 maxY: 0,
96 }; 96 };
97 } 97 }
98 98
99 Polymer({ 99 Polymer({
100 is: 'cr-action-menu', 100 is: 'cr-action-menu',
101 extends: 'dialog', 101 extends: 'dialog',
102 102
103 /** 103 /**
104 * The element which the action menu will be anchored to. Also the element 104 * The element which the action menu will be anchored to. Also the element
105 * where focus will be returned after the menu is closed. Only populated if 105 * where focus will be returned after the menu is closed. Only populated if
(...skipping 140 matching lines...) Expand 10 before | Expand all | Expand 10 after
246 * Shows the menu anchored to the given element. 246 * Shows the menu anchored to the given element.
247 * @param {!Element} anchorElement 247 * @param {!Element} anchorElement
248 * @param {ShowConfig=} opt_config 248 * @param {ShowConfig=} opt_config
249 */ 249 */
250 showAt: function(anchorElement, opt_config) { 250 showAt: function(anchorElement, opt_config) {
251 this.anchorElement_ = anchorElement; 251 this.anchorElement_ = anchorElement;
252 // Scroll the anchor element into view so that the bounding rect will be 252 // Scroll the anchor element into view so that the bounding rect will be
253 // accurate for where the menu should be shown. 253 // accurate for where the menu should be shown.
254 this.anchorElement_.scrollIntoViewIfNeeded(); 254 this.anchorElement_.scrollIntoViewIfNeeded();
255 255
256 // Save the scroll position that ensures the anchor element is onscreen.
257 var doc = document.scrollingElement;
258 var scrollLeft = doc.scrollLeft;
259 var scrollTop = doc.scrollTop;
260
261 // Reset position so that layout isn't affected by the previous position,
262 // and so that the dialog is positioned at the top-start corner of the
263 // document.
264 this.resetStyle_();
265
266 // Show the dialog which will focus the top-start of the body. This makes
267 // the client rect calculation relative to the top-start of the body.
268 this.showModal();
269
270 var rect = this.anchorElement_.getBoundingClientRect(); 256 var rect = this.anchorElement_.getBoundingClientRect();
271 this.positionDialog_(/** @type {ShowConfig} */ (Object.assign( 257 this.showAtPosition(/** @type {ShowConfig} */ (Object.assign(
272 { 258 {
273 top: rect.top, 259 top: rect.top,
274 left: rect.left, 260 left: rect.left,
275 height: rect.height, 261 height: rect.height,
276 width: rect.width, 262 width: rect.width,
277 // Default to anchoring towards the left. 263 // Default to anchoring towards the left.
278 anchorAlignmentX: AnchorAlignment.BEFORE_END, 264 anchorAlignmentX: AnchorAlignment.BEFORE_END,
279 minX: scrollLeft,
280 minY: scrollTop,
281 maxX: scrollLeft + window.innerWidth,
282 maxY: scrollTop + window.innerHeight,
283 }, 265 },
284 opt_config))); 266 opt_config)));
285
286 // Restore the scroll position.
287 doc.scrollTop = scrollTop;
288 doc.scrollLeft = scrollLeft;
289
290 this.addCloseListeners_();
291 }, 267 },
292 268
293 /** 269 /**
294 * Shows the menu anchored to the given box. The anchor alignment is 270 * Shows the menu anchored to the given box. The anchor alignment is
295 * specified as an X and Y alignment which represents a point in the anchor 271 * specified as an X and Y alignment which represents a point in the anchor
296 * where the menu will align to, which can have the menu either before or 272 * where the menu will align to, which can have the menu either before or
297 * after the given point in each axis. Center alignment places the center of 273 * after the given point in each axis. Center alignment places the center of
298 * the menu in line with the center of the anchor. 274 * the menu in line with the center of the anchor. Coordinates are relative to
275 * the top-left of the viewport.
299 * 276 *
300 * y-start 277 * y-start
301 * _____________ 278 * _____________
302 * | | 279 * | |
303 * | | 280 * | |
304 * | CENTER | 281 * | CENTER |
305 * x-start | x | x-end 282 * x-start | x | x-end
306 * | | 283 * | |
307 * |anchor box | 284 * |anchor box |
308 * |___________| 285 * |___________|
309 * 286 *
310 * y-end 287 * y-end
311 * 288 *
312 * For example, aligning the menu to the inside of the top-right edge of 289 * For example, aligning the menu to the inside of the top-right edge of
313 * the anchor, extending towards the bottom-left would use a alignment of 290 * the anchor, extending towards the bottom-left would use a alignment of
314 * (BEFORE_END, AFTER_START), whereas centering the menu below the bottom 291 * (BEFORE_END, AFTER_START), whereas centering the menu below the bottom
315 * edge of the anchor would use (CENTER, AFTER_END). 292 * edge of the anchor would use (CENTER, AFTER_END).
316 * 293 *
317 * @param {!ShowConfig} config 294 * @param {!ShowConfig} config
318 */ 295 */
319 showAtPosition: function(config) { 296 showAtPosition: function(config) {
297 // Save the scroll position of the viewport.
298 var doc = document.scrollingElement;
299 var scrollLeft = doc.scrollLeft;
300 var scrollTop = doc.scrollTop;
301
302 // Reset position so that layout isn't affected by the previous position,
303 // and so that the dialog is positioned at the top-start corner of the
304 // document.
320 this.resetStyle_(); 305 this.resetStyle_();
321 this.showModal(); 306 this.showModal();
322 this.positionDialog_(config); 307
308 config.top += scrollTop;
309 config.left += scrollLeft;
310
311 this.positionDialog_(/** @type {ShowConfig} */ (Object.assign(
312 {
313 minX: scrollLeft,
314 minY: scrollTop,
315 maxX: scrollLeft + doc.clientWidth,
316 maxY: scrollTop + doc.clientHeight,
317 },
318 config)));
319
320 // Restore the scroll position.
321 doc.scrollTop = scrollTop;
322 doc.scrollLeft = scrollLeft;
323 this.addCloseListeners_(); 323 this.addCloseListeners_();
324 }, 324 },
325 325
326 /** @private */ 326 /** @private */
327 resetStyle_: function() { 327 resetStyle_: function() {
328 this.style.left = ''; 328 this.style.left = '';
329 this.style.right = ''; 329 this.style.right = '';
330 this.style.top = '0'; 330 this.style.top = '0';
331 }, 331 },
332 332
333 /** 333 /**
334 * Position the dialog using the coordinates in config. Coordinates are
335 * relative to the top-left of the viewport when scrolled to (0, 0).
334 * @param {!ShowConfig} config 336 * @param {!ShowConfig} config
335 * @private 337 * @private
336 */ 338 */
337 positionDialog_: function(config) { 339 positionDialog_: function(config) {
338 var c = Object.assign(getDefaultShowConfig(), config); 340 var c = Object.assign(getDefaultShowConfig(), config);
339 341
340 var top = c.top; 342 var top = c.top;
341 var left = c.left; 343 var left = c.left;
342 var bottom = top + c.height; 344 var bottom = top + c.height;
343 var right = left + c.width; 345 var right = left + c.width;
344 346
345 // Flip the X anchor in RTL. 347 // Flip the X anchor in RTL.
346 var rtl = getComputedStyle(this).direction == 'rtl'; 348 var rtl = getComputedStyle(this).direction == 'rtl';
347 if (rtl) 349 if (rtl)
348 c.anchorAlignmentX *= -1; 350 c.anchorAlignmentX *= -1;
349 351
350 var menuLeft = getStartPointWithAnchor( 352 var menuLeft = getStartPointWithAnchor(
351 left, right, this.offsetWidth, c.anchorAlignmentX, c.minX, c.maxX); 353 left, right, this.offsetWidth, c.anchorAlignmentX, c.minX, c.maxX);
352 354
353 if (rtl) { 355 if (rtl) {
354 var menuRight = document.body.scrollWidth - menuLeft - this.offsetWidth; 356 var menuRight =
357 document.scrollingElement.clientWidth - menuLeft - this.offsetWidth;
355 this.style.right = menuRight + 'px'; 358 this.style.right = menuRight + 'px';
356 } else { 359 } else {
357 this.style.left = menuLeft + 'px'; 360 this.style.left = menuLeft + 'px';
358 } 361 }
359 362
360 var menuTop = getStartPointWithAnchor( 363 var menuTop = getStartPointWithAnchor(
361 top, bottom, this.offsetHeight, c.anchorAlignmentY, c.minY, c.maxY); 364 top, bottom, this.offsetHeight, c.anchorAlignmentY, c.minY, c.maxY);
362 this.style.top = menuTop + 'px'; 365 this.style.top = menuTop + 'px';
363 }, 366 },
364 367
365 /** 368 /**
366 * @private 369 * @private
367 */ 370 */
368 addCloseListeners_: function() { 371 addCloseListeners_: function() {
369 this.boundClose_ = this.boundClose_ || function() { 372 this.boundClose_ = this.boundClose_ || function() {
370 if (this.open) 373 if (this.open)
371 this.close(); 374 this.close();
372 }.bind(this); 375 }.bind(this);
373 window.addEventListener('resize', this.boundClose_); 376 window.addEventListener('resize', this.boundClose_);
374 window.addEventListener('popstate', this.boundClose_); 377 window.addEventListener('popstate', this.boundClose_);
375 }, 378 },
376 }); 379 });
377 })(); 380 })();
OLDNEW
« no previous file with comments | « chrome/test/data/webui/cr_elements/cr_action_menu_test.js ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698