OLD | NEW |
---|---|
1 // Copyright 2017 The Chromium Authors. All rights reserved. | 1 // Copyright 2017 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 (function() { | |
6 | |
5 /** | 7 /** |
6 * @fileoverview | 8 * @fileoverview |
7 * night-light-slider is used to set the custom automatic schedule of the | 9 * night-light-slider is used to set the custom automatic schedule of the |
8 * Night Light feature, so that users can set their desired start and end | 10 * Night Light feature, so that users can set their desired start and end |
9 * times. | 11 * times. |
10 */ | 12 */ |
11 | 13 |
12 /** @const */ var HOURS_PER_DAY = 24; | 14 /** @const */ var HOURS_PER_DAY = 24; |
13 /** @const */ var MIN_KNOBS_DISTANCE_MINUTES = 30; | 15 /** @const */ var MIN_KNOBS_DISTANCE_MINUTES = 30; |
14 /** @const */ var OFFSET_MINUTES_6PM = 18 * 60; | 16 /** @const */ var OFFSET_MINUTES_6PM = 18 * 60; |
15 /** @const */ var TOTAL_MINUTES_PER_DAY = 24 * 60; | 17 /** @const */ var TOTAL_MINUTES_PER_DAY = 24 * 60; |
16 | 18 |
17 Polymer({ | 19 Polymer({ |
18 is: 'night-light-slider', | 20 is: 'night-light-slider', |
19 | 21 |
20 behaviors: [ | 22 behaviors: [ |
21 I18nBehavior, | |
22 PrefsBehavior, | 23 PrefsBehavior, |
23 Polymer.IronA11yKeysBehavior, | 24 Polymer.IronA11yKeysBehavior, |
25 Polymer.PaperInkyFocusBehavior, | |
24 ], | 26 ], |
25 | 27 |
26 properties: { | 28 properties: { |
27 /** | 29 /** |
28 * The object currently being dragged. Either the start or end knobs. | |
29 * @type {?Object} | |
30 * @private | |
31 */ | |
32 dragObject_: { | |
33 type: Object, | |
34 value: null, | |
35 }, | |
36 | |
37 /** | |
38 * The start knob time as a string to be shown on the start label bubble. | 30 * The start knob time as a string to be shown on the start label bubble. |
39 * @private | 31 * @private |
40 */ | 32 */ |
41 startTime_: { | 33 startTime_: String, |
42 type: String, | |
43 }, | |
44 | 34 |
45 /** | 35 /** |
46 * The end knob time as a string to be shown on the end label bubble. | 36 * The end knob time as a string to be shown on the end label bubble. |
47 * @private | 37 * @private |
48 */ | 38 */ |
49 endTime_: { | 39 endTime_: String, |
50 type: String, | |
51 }, | |
52 }, | 40 }, |
53 | 41 |
54 observers: [ | 42 observers: [ |
55 'customTimesChanged_(prefs.ash.night_light.custom_start_time.*, ' + | 43 'customTimesChanged_(prefs.ash.night_light.custom_start_time.*, ' + |
56 'prefs.ash.night_light.custom_end_time.*)', | 44 'prefs.ash.night_light.custom_end_time.*)', |
57 ], | 45 ], |
58 | 46 |
59 keyBindings: { | 47 keyBindings: { |
60 'left': 'onLeftKey_', | 48 'left': 'onLeftKey_', |
61 'right': 'onRightKey_', | 49 'right': 'onRightKey_', |
62 }, | 50 }, |
63 | 51 |
52 /** | |
53 * The object currently being dragged. Either the start or end knobs. | |
54 * @type {?Object} | |
55 * @private | |
56 */ | |
57 dragObject_: null, | |
58 | |
59 /** @override */ | |
64 ready: function() { | 60 ready: function() { |
65 // Build the legend markers. | 61 // Build the legend markers. |
66 var markersContainer = this.$.markersContainer; | 62 var markersContainer = this.$.markersContainer; |
67 var width = markersContainer.offsetWidth; | 63 var width = markersContainer.offsetWidth; |
68 for (var i = 0; i <= HOURS_PER_DAY; ++i) { | 64 for (var i = 0; i <= HOURS_PER_DAY; ++i) { |
69 var marker = document.createElement('div'); | 65 var marker = document.createElement('div'); |
70 marker.className = 'markers'; | 66 marker.className = 'markers'; |
71 markersContainer.appendChild(marker); | 67 markersContainer.appendChild(marker); |
72 marker.style.left = (i * 100 / HOURS_PER_DAY) + '%'; | 68 marker.style.left = (i * 100 / HOURS_PER_DAY) + '%'; |
73 } | 69 } |
70 | |
74 this.async(function() { | 71 this.async(function() { |
75 // Read the initial prefs values and refresh the slider. | 72 // Read the initial prefs values and refresh the slider. |
76 this.customTimesChanged_(); | 73 this.customTimesChanged_(); |
77 }); | 74 }); |
78 }, | 75 }, |
79 | 76 |
80 /** | 77 /** |
81 * Expands or un-expands the knob being dragged along with its corresponding | 78 * Expands or un-expands the knob being dragged along with its corresponding |
82 * label bubble. | 79 * label bubble. |
83 * @param {boolean} expand True to expand, and false to un-expand. | 80 * @param {boolean} expand True to expand, and false to un-expand. |
(...skipping 20 matching lines...) Expand all Loading... | |
104 if (activeElement == this.$.startKnob || activeElement == this.$.endKnob) | 101 if (activeElement == this.$.startKnob || activeElement == this.$.endKnob) |
105 activeElement.blur(); | 102 activeElement.blur(); |
106 }, | 103 }, |
107 | 104 |
108 /** | 105 /** |
109 * Start dragging the target knob. | 106 * Start dragging the target knob. |
110 * @private | 107 * @private |
111 */ | 108 */ |
112 startDrag_: function(event) { | 109 startDrag_: function(event) { |
113 event.preventDefault(); | 110 event.preventDefault(); |
114 this.dragObject_ = event.target; | 111 |
112 // Only handle start or end knobs. Use the "knob-inner" divs just to display | |
113 // the knobs. | |
114 if (event.target == this.$.startKnob || | |
115 event.target == this.$.startKnob.firstElementChild) { | |
116 this.dragObject_ = this.$.startKnob; | |
117 } else if (event.target == this.$.endKnob || | |
118 event.target == this.$.endKnob.firstElementChild) { | |
119 this.dragObject_ = this.$.endKnob; | |
120 } else { | |
121 return; | |
122 } | |
123 | |
115 this.setExpanded_(true); | 124 this.setExpanded_(true); |
116 | 125 |
117 // Focus is only given to the knobs by means of keyboard tab navigations. | 126 // Focus is only given to the knobs by means of keyboard tab navigations. |
118 // When we start dragging, we don't want to see any focus halos around any | 127 // When we start dragging, we don't want to see any focus halos around any |
119 // knob. | 128 // knob. |
120 this.blurAnyFocusedKnob_(); | 129 this.blurAnyFocusedKnob_(); |
121 | 130 |
122 // However, our night-light-slider element must get the focus. | 131 // However, our night-light-slider element must get the focus. |
123 this.focus(); | 132 this.focus(); |
124 }, | 133 }, |
(...skipping 317 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
442 * @private | 451 * @private |
443 */ | 452 */ |
444 onRightKey_: function(e) { | 453 onRightKey_: function(e) { |
445 e.preventDefault(); | 454 e.preventDefault(); |
446 var knobPref = this.getFocusedKnobPrefPathIfAny_(); | 455 var knobPref = this.getFocusedKnobPrefPathIfAny_(); |
447 if (!knobPref) | 456 if (!knobPref) |
448 return; | 457 return; |
449 | 458 |
450 this.incrementPref_(knobPref, 1); | 459 this.incrementPref_(knobPref, 1); |
451 }, | 460 }, |
452 }); | 461 |
462 /** | |
463 * Whether either of the two knobs is focused. | |
464 * | |
465 * @return {boolean} true if either of the two knobs is focused. | |
dpapad
2017/06/20 21:11:56
Can we make this comment less verbose?
/**
* @re
afakhry
2017/06/20 21:38:07
Done.
| |
466 * @private | |
467 */ | |
468 isEitherKnobFocused_: function() { | |
469 var activeElement = this.shadowRoot.activeElement; | |
470 return activeElement == this.$.startKnob || activeElement == this.$.endKnob; | |
471 }, | |
472 | |
473 /** | |
474 * Overrides _createRipple() from PaperInkyFocusBehavior to create the ripple | |
475 * only on a knob if it's focused, or on a dummy hidden element so that it | |
476 * doesn't show. | |
477 * @private | |
478 */ | |
479 _createRipple: function() { | |
480 if (this.isEitherKnobFocused_()) { | |
481 this._rippleContainer = this.shadowRoot.activeElement; | |
482 } else { | |
483 // We can't just skip the ripple creation and return early with null here. | |
484 // The code inherited from PaperInkyFocusBehavior expects that this | |
485 // function returns a ripple element. So to avoid crashes, we'll setup the | |
486 // ripple to be created under a hidden element. | |
487 this._rippleContainer = this.$.dummyRippleContainer; | |
488 } | |
489 | |
490 return Polymer.PaperInkyFocusBehaviorImpl._createRipple.call(this); | |
491 }, | |
492 | |
493 /** | |
494 * Handles focus events on the start and end knobs. | |
495 * @private | |
496 */ | |
497 onFocus_: function() { | |
498 this.ensureRipple(); | |
499 | |
500 if (this.hasRipple()) { | |
501 this._ripple.style.display = ''; | |
502 this._ripple.holdDown = true; | |
503 } | |
504 }, | |
505 | |
506 /** | |
507 * Handles blur events on the start and end knobs. | |
508 * @private | |
509 */ | |
510 onBlur_: function() { | |
511 if (this.hasRipple()) { | |
512 this._ripple.remove(); | |
513 this._ripple = null; | |
514 } | |
515 }, | |
516 | |
517 /** @private */ | |
518 _focusedChanged: function(receivedFocusFromKeyboard) { | |
519 // Overrides the _focusedChanged() from the PaperInkyFocusBehavior so that | |
520 // it does nothing. This function is called only once for the entire | |
521 // night-light-slider element even when focus is moved between the two | |
522 // knobs. This doesn't allow us to decide on which knob the ripple will be | |
523 // created. Hence we handle focus and blur explicitly above. | |
524 } | |
525 }); | |
526 | |
527 })(); | |
OLD | NEW |