@@ -436,7 +436,6 @@ goog.ui.SliderBase.prototype.enterDocument = function() {
436
436
this . keyHandler_ = new goog . events . KeyHandler ( this . getElement ( ) ) ;
437
437
this . enableEventHandlers_ ( true ) ;
438
438
439
- this . getElement ( ) . tabIndex = 0 ;
440
439
this . updateUi_ ( ) ;
441
440
} ;
442
441
@@ -587,45 +586,49 @@ goog.ui.SliderBase.prototype.handleThumbDragStartEnd_ = function(e) {
587
586
*/
588
587
goog . ui . SliderBase . prototype . handleKeyDown_ = function ( e ) {
589
588
var handled = true ;
589
+ var thumb ;
590
+ if ( e . target == this . valueThumb || e . target == this . extentThumb ) {
591
+ thumb = goog . asserts . assertElement ( e . target ) ;
592
+ }
593
+ var delta ;
590
594
switch ( e . keyCode ) {
591
595
case goog . events . KeyCodes . HOME :
592
- this . animatedSetValue ( this . getMinimum ( ) ) ;
596
+ this . animateThumbToStart_ ( thumb ) ;
593
597
break ;
594
598
case goog . events . KeyCodes . END :
595
- this . animatedSetValue ( this . getMaximum ( ) ) ;
599
+ this . animateThumbToEnd_ ( thumb ) ;
596
600
break ;
597
601
case goog . events . KeyCodes . PAGE_UP :
598
- this . moveThumbs ( this . getBlockIncrement ( ) ) ;
602
+ delta = this . getBlockIncrement ( ) ;
599
603
break ;
600
604
case goog . events . KeyCodes . PAGE_DOWN :
601
- this . moveThumbs ( - this . getBlockIncrement ( ) ) ;
605
+ delta = - this . getBlockIncrement ( ) ;
602
606
break ;
603
607
case goog . events . KeyCodes . LEFT :
604
608
var sign = this . flipForRtl_ && this . isRightToLeft ( ) ? 1 : - 1 ;
605
- this . moveThumbs (
606
- e . shiftKey ? sign * this . getBlockIncrement ( ) :
607
- sign * this . getUnitIncrement ( ) ) ;
609
+ delta = e . shiftKey ? sign * this . getBlockIncrement ( ) :
610
+ sign * this . getUnitIncrement ( ) ;
608
611
break ;
609
612
case goog . events . KeyCodes . DOWN :
610
- this . moveThumbs (
611
- e . shiftKey ? - this . getBlockIncrement ( ) : - this . getUnitIncrement ( ) ) ;
613
+ delta = e . shiftKey ? - this . getBlockIncrement ( ) : - this . getUnitIncrement ( ) ;
612
614
break ;
613
615
case goog . events . KeyCodes . RIGHT :
614
616
var sign = this . flipForRtl_ && this . isRightToLeft ( ) ? - 1 : 1 ;
615
- this . moveThumbs (
616
- e . shiftKey ? sign * this . getBlockIncrement ( ) :
617
- sign * this . getUnitIncrement ( ) ) ;
617
+ delta = e . shiftKey ? sign * this . getBlockIncrement ( ) :
618
+ sign * this . getUnitIncrement ( ) ;
618
619
break ;
619
620
case goog . events . KeyCodes . UP :
620
- this . moveThumbs (
621
- e . shiftKey ? this . getBlockIncrement ( ) : this . getUnitIncrement ( ) ) ;
621
+ delta = e . shiftKey ? this . getBlockIncrement ( ) : this . getUnitIncrement ( ) ;
622
622
break ;
623
623
624
624
default :
625
625
handled = false ;
626
626
}
627
627
628
628
if ( handled ) {
629
+ if ( delta ) {
630
+ thumb ? this . moveThumb_ ( delta , thumb ) : this . moveThumbs ( delta ) ;
631
+ }
629
632
e . preventDefault ( ) ;
630
633
}
631
634
} ;
@@ -851,6 +854,54 @@ goog.ui.SliderBase.prototype.getThumbPosition_ = function(thumb) {
851
854
} ;
852
855
853
856
857
+ /**
858
+ * Animates the given thumb (or the handle if thumb is not specified) towards
859
+ * the minimum value position.
860
+ * @param {!Element= } opt_thumb
861
+ * @private
862
+ */
863
+ goog . ui . SliderBase . prototype . animateThumbToStart_ = function ( opt_thumb ) {
864
+ if ( opt_thumb ) {
865
+ if ( opt_thumb == this . valueThumb ) {
866
+ if ( this . getValue ( ) != this . getMinimum ( ) ) {
867
+ this . animatedSetValue ( this . getMinimum ( ) , this . valueThumb ) ;
868
+ }
869
+ } else if ( opt_thumb == this . extentThumb ) {
870
+ var newExtentValue = this . getValue ( ) + this . minExtent_ ;
871
+ if ( this . getValue ( ) + this . getExtent ( ) != newExtentValue ) {
872
+ this . animatedSetValue ( newExtentValue , this . extentThumb ) ;
873
+ }
874
+ }
875
+ } else {
876
+ this . animatedSetValue ( this . getMinimum ( ) ) ;
877
+ }
878
+ } ;
879
+
880
+
881
+ /**
882
+ * Animates the given thumb (or the handle if thumb is not specified) towards
883
+ * the maximum value position.
884
+ * @param {!Element= } opt_thumb
885
+ * @private
886
+ */
887
+ goog . ui . SliderBase . prototype . animateThumbToEnd_ = function ( opt_thumb ) {
888
+ if ( opt_thumb ) {
889
+ if ( opt_thumb == this . extentThumb ) {
890
+ if ( this . getValue ( ) + this . getExtent ( ) != this . getMaximum ( ) ) {
891
+ this . animatedSetValue ( this . getMaximum ( ) , this . extentThumb ) ;
892
+ }
893
+ } else if ( opt_thumb == this . valueThumb ) {
894
+ var newValue = this . getValue ( ) + this . getExtent ( ) - this . minExtent_ ;
895
+ if ( this . getValue ( ) != newValue ) {
896
+ this . animatedSetValue ( newValue , this . valueThumb ) ;
897
+ }
898
+ }
899
+ } else {
900
+ this . animatedSetValue ( this . getMaximum ( ) ) ;
901
+ }
902
+ } ;
903
+
904
+
854
905
/**
855
906
* Returns whether a thumb is currently being dragged with the mouse (or via
856
907
* touch). Note that changing the value with keyboard, mouswheel, or via
@@ -890,6 +941,44 @@ goog.ui.SliderBase.prototype.moveThumbs = function(delta) {
890
941
} ;
891
942
892
943
944
+ /**
945
+ * Moves the given thumb by the the specified delta as follows:
946
+ * - The thumb is moved as long as it stays within its [min,max].
947
+ * - Once it reaches or exceeds min (or max), it stays at min (or max).
948
+ * In case the thumb has reached min (or max), no change event will fire.
949
+ * If the specified delta is smaller than the step size, it will be rounded
950
+ * to the step size.
951
+ * @param {number } delta The delta by which to move the selected range.
952
+ * @param {!Element } thumb The thumb to move if given.
953
+ * @private
954
+ */
955
+ goog . ui . SliderBase . prototype . moveThumb_ = function ( delta , thumb ) {
956
+ // Assume that a small delta is supposed to be at least a step.
957
+ if ( Math . abs ( delta ) < this . getStep ( ) ) {
958
+ delta = goog . math . sign ( delta ) * this . getStep ( ) ;
959
+ }
960
+ var currentMinPos = this . getValue ( ) ;
961
+ var currentMaxPos = this . getValue ( ) + this . getExtent ( ) ;
962
+ if ( thumb == this . valueThumb ) {
963
+ var newMinPos = this . getThumbPosition_ ( this . valueThumb ) + delta ;
964
+ newMinPos = goog . math . clamp (
965
+ newMinPos , this . getMinimum ( ) , this . getMaximum ( ) - this . minExtent_ ) ;
966
+ // Change the extent value to keep the present extentThumb position while
967
+ // move the valueThumb to newMinPos.
968
+ var newExtent = currentMaxPos - newMinPos ;
969
+ this . setValueAndExtent ( newMinPos , newExtent >= 0 ? newExtent : 0 ) ;
970
+ } else if ( thumb == this . extentThumb ) {
971
+ var newMaxPos = this . getThumbPosition_ ( this . extentThumb ) + delta ;
972
+ newMaxPos = goog . math . clamp (
973
+ newMaxPos , this . getMinimum ( ) + this . minExtent_ , this . getMaximum ( ) ) ;
974
+ // Change the extent value to keep the present valueThumb position while
975
+ // move the extentThumb to newMaxPos.
976
+ var newExtent = newMaxPos - currentMinPos ;
977
+ this . setValueAndExtent ( currentMinPos , newExtent >= 0 ? newExtent : 0 ) ;
978
+ }
979
+ } ;
980
+
981
+
893
982
/**
894
983
* Sets the position of the given thumb. The set is ignored and no CHANGE event
895
984
* fires if it violates the constraint minimum <= value (valueThumb position) <=
@@ -1119,8 +1208,9 @@ goog.ui.SliderBase.prototype.getThumbCoordinateForValue = function(val) {
1119
1208
/**
1120
1209
* Sets the value and starts animating the handle towards that position.
1121
1210
* @param {number } v Value to set and animate to.
1211
+ * @param {!HTMLDivElement= } opt_thumb The thumb to move if given.
1122
1212
*/
1123
- goog . ui . SliderBase . prototype . animatedSetValue = function ( v ) {
1213
+ goog . ui . SliderBase . prototype . animatedSetValue = function ( v , opt_thumb ) {
1124
1214
// the value might be out of bounds
1125
1215
v = goog . math . clamp ( v , this . getMinimum ( ) , this . getMaximum ( ) ) ;
1126
1216
@@ -1131,7 +1221,7 @@ goog.ui.SliderBase.prototype.animatedSetValue = function(v) {
1131
1221
var animations = new goog . fx . AnimationParallelQueue ( ) ;
1132
1222
var end ;
1133
1223
1134
- var thumb = this . getClosestThumb_ ( v ) ;
1224
+ var thumb = opt_thumb || this . getClosestThumb_ ( v ) ;
1135
1225
var previousValue = this . getValue ( ) ;
1136
1226
var previousExtent = this . getExtent ( ) ;
1137
1227
var previousThumbValue = this . getThumbPosition_ ( thumb ) ;
@@ -1519,10 +1609,17 @@ goog.ui.SliderBase.prototype.setVisible = function(visible) {
1519
1609
* @protected
1520
1610
*/
1521
1611
goog . ui . SliderBase . prototype . setAriaRoles = function ( ) {
1522
- var el = this . getElement ( ) ;
1523
- goog . asserts . assert (
1524
- el , 'The DOM element for the slider base cannot be null.' ) ;
1525
- goog . a11y . aria . setRole ( el , goog . a11y . aria . Role . SLIDER ) ;
1612
+ if ( ! this . valueThumb ) {
1613
+ return ;
1614
+ }
1615
+
1616
+ var valueThumb = goog . asserts . assertElement ( this . valueThumb ) ;
1617
+ goog . a11y . aria . setRole ( valueThumb , goog . a11y . aria . Role . SLIDER ) ;
1618
+ valueThumb . tabIndex = 0 ;
1619
+ var extentThumb = goog . asserts . assertElement ( this . extentThumb ) ;
1620
+ goog . a11y . aria . setRole ( extentThumb , goog . a11y . aria . Role . SLIDER ) ;
1621
+ extentThumb . tabIndex = 0 ;
1622
+
1526
1623
this . updateAriaStates ( ) ;
1527
1624
} ;
1528
1625
@@ -1532,18 +1629,48 @@ goog.ui.SliderBase.prototype.setAriaRoles = function() {
1532
1629
* @protected
1533
1630
*/
1534
1631
goog . ui . SliderBase . prototype . updateAriaStates = function ( ) {
1535
- var element = this . getElement ( ) ;
1536
- if ( element ) {
1537
- goog . a11y . aria . setState (
1538
- element , goog . a11y . aria . State . VALUEMIN , this . getMinimum ( ) ) ;
1539
- goog . a11y . aria . setState (
1540
- element , goog . a11y . aria . State . VALUEMAX , this . getMaximum ( ) ) ;
1541
- goog . a11y . aria . setState (
1542
- element , goog . a11y . aria . State . VALUENOW , this . getValue ( ) ) ;
1543
- // Passing an empty value to setState will restore the default.
1544
- goog . a11y . aria . setState (
1545
- element , goog . a11y . aria . State . VALUETEXT , this . getTextValue ( ) || '' ) ;
1632
+ if ( ! this . valueThumb ) {
1633
+ return ;
1546
1634
}
1635
+
1636
+ var valueThumb = goog . asserts . assertElement ( this . valueThumb ) ;
1637
+ var extentThumb = goog . asserts . assertElement ( this . extentThumb ) ;
1638
+
1639
+ goog . a11y . aria . setState (
1640
+ extentThumb , goog . a11y . aria . State . VALUEMIN ,
1641
+ this . getValue ( ) + this . minExtent_ ) ;
1642
+ goog . a11y . aria . setState (
1643
+ valueThumb , goog . a11y . aria . State . VALUEMIN , this . getMinimum ( ) ) ;
1644
+
1645
+ goog . a11y . aria . setState (
1646
+ extentThumb , goog . a11y . aria . State . VALUENOW ,
1647
+ this . getValue ( ) + this . getExtent ( ) ) ;
1648
+ goog . a11y . aria . setState (
1649
+ valueThumb , goog . a11y . aria . State . VALUENOW , this . getValue ( ) ) ;
1650
+
1651
+ goog . a11y . aria . setState (
1652
+ valueThumb , goog . a11y . aria . State . VALUEMAX ,
1653
+ this . getValue ( ) + this . getExtent ( ) - this . minExtent_ ) ;
1654
+ goog . a11y . aria . setState (
1655
+ extentThumb , goog . a11y . aria . State . VALUEMAX , this . getMaximum ( ) ) ;
1656
+
1657
+ this . updateAriaValueText_ ( ) ;
1658
+ } ;
1659
+
1660
+
1661
+ /**
1662
+ * Updates the 'aria-valuetext' property for the slider thumbs.
1663
+ * @private
1664
+ */
1665
+ goog . ui . SliderBase . prototype . updateAriaValueText_ = function ( ) {
1666
+ // Passing an empty value to setState will restore the default.
1667
+ goog . a11y . aria . setState (
1668
+ goog . asserts . assertElement ( this . extentThumb ) ,
1669
+ goog . a11y . aria . State . VALUETEXT ,
1670
+ this . getTextValue ( this . getValue ( ) + this . getExtent ( ) ) || '' ) ;
1671
+ goog . a11y . aria . setState (
1672
+ goog . asserts . assertElement ( this . valueThumb ) ,
1673
+ goog . a11y . aria . State . VALUETEXT , this . getTextValue ( this . getValue ( ) ) || '' ) ;
1547
1674
} ;
1548
1675
1549
1676
@@ -1605,6 +1732,20 @@ goog.ui.SliderBase.prototype.setEnabled = function(enable) {
1605
1732
return ;
1606
1733
}
1607
1734
1735
+ if ( enable ) {
1736
+ this . valueThumb . tabIndex = 0 ;
1737
+ goog . a11y . aria . removeState ( this . valueThumb , goog . a11y . aria . State . DISABLED ) ;
1738
+ this . extentThumb . tabIndex = 0 ;
1739
+ goog . a11y . aria . removeState ( this . extentThumb , goog . a11y . aria . State . DISABLED ) ;
1740
+ } else {
1741
+ this . valueThumb . tabIndex = - 1 ;
1742
+ goog . a11y . aria . setState (
1743
+ this . valueThumb , goog . a11y . aria . State . DISABLED , 'true' ) ;
1744
+ this . extentThumb . tabIndex = - 1 ;
1745
+ goog . a11y . aria . setState (
1746
+ this . extentThumb , goog . a11y . aria . State . DISABLED , 'true' ) ;
1747
+ }
1748
+
1608
1749
var eventType = enable ? goog . ui . Component . EventType . ENABLE :
1609
1750
goog . ui . Component . EventType . DISABLE ;
1610
1751
if ( this . dispatchEvent ( eventType ) ) {
@@ -1644,14 +1785,25 @@ goog.ui.SliderBase.prototype.getOffsetStart_ = function(element) {
1644
1785
1645
1786
1646
1787
/**
1788
+ * @param {number= } opt_value
1647
1789
* @return {?string } The text value for the slider's current value, or null if
1648
1790
* unavailable.
1649
1791
*/
1650
- goog . ui . SliderBase . prototype . getTextValue = function ( ) {
1651
- return this . labelFn_ ( this . getValue ( ) ) ;
1792
+ goog . ui . SliderBase . prototype . getTextValue = function ( opt_value ) {
1793
+ var value = opt_value || this . getValue ( ) ;
1794
+ return this . labelFn_ ( value ) ;
1652
1795
} ;
1653
1796
1654
1797
1798
+ /**
1799
+ * Sets the function to map slider values to text description.
1800
+ * @param {!function(number): string } labelFn
1801
+ */
1802
+ goog . ui . SliderBase . prototype . setLabelFn = function ( labelFn ) {
1803
+ this . labelFn_ = labelFn ;
1804
+ this . updateAriaValueText_ ( ) ;
1805
+ } ;
1806
+
1655
1807
1656
1808
/**
1657
1809
* The factory for creating additional animations to be played when animating to
0 commit comments