OLD | NEW |
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 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 // require: event_tracker.js | 5 // require: event_tracker.js |
6 | 6 |
7 cr.define('cr.ui', function() { | 7 cr.define('cr.ui', function() { |
8 | 8 |
9 /** | 9 /** |
10 * The arrow location specifies how the arrow and bubble are positioned in | 10 * The arrow location specifies how the arrow and bubble are positioned in |
(...skipping 296 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
307 | 307 |
308 /** | 308 /** |
309 * A bubble that remains open until the user explicitly dismisses it or clicks | 309 * A bubble that remains open until the user explicitly dismisses it or clicks |
310 * outside the bubble after it has been shown for at least the specified | 310 * outside the bubble after it has been shown for at least the specified |
311 * amount of time (making it less likely that the user will unintentionally | 311 * amount of time (making it less likely that the user will unintentionally |
312 * dismiss the bubble). The bubble repositions itself on layout changes. | 312 * dismiss the bubble). The bubble repositions itself on layout changes. |
313 */ | 313 */ |
314 var Bubble = cr.ui.define('div'); | 314 var Bubble = cr.ui.define('div'); |
315 | 315 |
316 Bubble.prototype = { | 316 Bubble.prototype = { |
317 // Set up the prototype chain | 317 // Set up the prototype chain. |
318 __proto__: BubbleBase.prototype, | 318 __proto__: BubbleBase.prototype, |
319 | 319 |
320 /** | 320 /** |
321 * Initialization function for the cr.ui framework. | 321 * Initialization function for the cr.ui framework. |
322 */ | 322 */ |
323 decorate: function() { | 323 decorate: function() { |
324 BubbleBase.prototype.decorate.call(this); | 324 BubbleBase.prototype.decorate.call(this); |
325 | 325 |
326 var close = document.createElement('div'); | 326 var close = document.createElement('div'); |
327 close.className = 'bubble-close'; | 327 close.className = 'bubble-close'; |
(...skipping 62 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
390 // Dismiss the bubble when the user clicks outside it after the | 390 // Dismiss the bubble when the user clicks outside it after the |
391 // specified delay has passed. | 391 // specified delay has passed. |
392 } else if (!this.contains(event.target) && | 392 } else if (!this.contains(event.target) && |
393 Date.now() - this.showTime_ >= this.deactivateToDismissDelay_) { | 393 Date.now() - this.showTime_ >= this.deactivateToDismissDelay_) { |
394 this.hide(); | 394 this.hide(); |
395 } | 395 } |
396 } | 396 } |
397 }, | 397 }, |
398 }; | 398 }; |
399 | 399 |
| 400 /** |
| 401 * A bubble that closes automatically when the user clicks or moves the focus |
| 402 * outside the bubble and its target element, scrolls the underlying document |
| 403 * or resizes the window. |
| 404 */ |
| 405 var AutoCloseBubble = cr.ui.define('div'); |
| 406 |
| 407 AutoCloseBubble.prototype = { |
| 408 // Set up the prototype chain. |
| 409 __proto__: BubbleBase.prototype, |
| 410 |
| 411 /** |
| 412 * Initialization function for the cr.ui framework. |
| 413 */ |
| 414 decorate: function() { |
| 415 BubbleBase.prototype.decorate.call(this); |
| 416 this.classList.add('auto-close-bubble'); |
| 417 }, |
| 418 |
| 419 /** |
| 420 * Set the DOM sibling node, i.e. the node as whose sibling the bubble |
| 421 * should join the DOM to ensure that focusable elements inside the bubble |
| 422 * follow the target element in the document's tab order. Only available |
| 423 * when the bubble is not being shown. |
| 424 * @param {HTMLElement} node The new DOM sibling node. |
| 425 */ |
| 426 set domSibling(node) { |
| 427 if (!this.hidden) |
| 428 return; |
| 429 |
| 430 this.domSibling_ = node; |
| 431 }, |
| 432 |
| 433 /** |
| 434 * Show the bubble. |
| 435 */ |
| 436 show: function() { |
| 437 if (!this.hidden) |
| 438 return; |
| 439 |
| 440 BubbleBase.prototype.show.call(this); |
| 441 this.domSibling_.showingBubble = true; |
| 442 |
| 443 var doc = this.ownerDocument; |
| 444 this.eventTracker_.add(doc, 'mousewheel', this, true); |
| 445 this.eventTracker_.add(doc, 'scroll', this, true); |
| 446 this.eventTracker_.add(doc, 'elementFocused', this, true); |
| 447 this.eventTracker_.add(window, 'resize', this); |
| 448 }, |
| 449 |
| 450 /** |
| 451 * Hide the bubble. |
| 452 */ |
| 453 hide: function() { |
| 454 BubbleBase.prototype.hide.call(this); |
| 455 this.domSibling_.showingBubble = false; |
| 456 }, |
| 457 |
| 458 /** |
| 459 * Handle events, closing the bubble when the user clicks or moves the focus |
| 460 * outside the bubble and its target element, scrolls the underlying |
| 461 * document or resizes the window. |
| 462 * @param {Event} event The event. |
| 463 */ |
| 464 handleEvent: function(event) { |
| 465 BubbleBase.prototype.handleEvent.call(this, event); |
| 466 |
| 467 switch (event.type) { |
| 468 // Close the bubble when the user clicks outside it, except if it is a |
| 469 // left-click on the bubble's target element (allowing the target to |
| 470 // handle the event and close the bubble itself). |
| 471 case 'mousedown': |
| 472 if (event.button == 0 && this.anchorNode_.contains(event.target)) |
| 473 break; |
| 474 // Close the bubble when the underlying document is scrolled. |
| 475 case 'mousewheel': |
| 476 case 'scroll': |
| 477 if (this.contains(event.target)) |
| 478 break; |
| 479 // Close the bubble when the window is resized. |
| 480 case 'resize': |
| 481 this.hide(); |
| 482 break; |
| 483 // Close the bubble when the focus moves to an element that is not the |
| 484 // bubble target and is not inside the bubble. |
| 485 case 'elementFocused': |
| 486 if (!this.anchorNode_.contains(event.target) && |
| 487 !this.contains(event.target)) { |
| 488 this.hide(); |
| 489 } |
| 490 break; |
| 491 } |
| 492 }, |
| 493 |
| 494 /** |
| 495 * Attach the bubble to the document's DOM, making it a sibling of the |
| 496 * |domSibling_| so that focusable elements inside the bubble follow the |
| 497 * target element in the document's tab order. |
| 498 * @private |
| 499 */ |
| 500 attachToDOM_: function() { |
| 501 var parent = this.domSibling_.parentNode; |
| 502 parent.insertBefore(this, this.domSibling_.nextSibling); |
| 503 }, |
| 504 }; |
| 505 |
| 506 |
400 return { | 507 return { |
401 ArrowLocation: ArrowLocation, | 508 ArrowLocation: ArrowLocation, |
402 BubbleAlignment: BubbleAlignment, | 509 BubbleAlignment: BubbleAlignment, |
403 BubbleBase: BubbleBase, | 510 BubbleBase: BubbleBase, |
404 Bubble: Bubble | 511 Bubble: Bubble, |
| 512 AutoCloseBubble: AutoCloseBubble |
405 }; | 513 }; |
406 }); | 514 }); |
OLD | NEW |