[ Index ]

PHP Cross Reference of Unnamed Project

title

Body

[close]

/lib/yuilib/3.17.2/dial/ -> dial-debug.js (source)

   1  /*
   2  YUI 3.17.2 (build 9c3c78e)
   3  Copyright 2014 Yahoo! Inc. All rights reserved.
   4  Licensed under the BSD License.
   5  http://yuilibrary.com/license/
   6  */
   7  
   8  YUI.add('dial', function (Y, NAME) {
   9  
  10  /**
  11   * Create a circular dial value range input visualized as a draggable handle on a
  12   * background element.
  13   *
  14   * @module dial
  15   */
  16      var supportsVML = false;
  17          //testVMLNode;
  18  
  19      if (Y.UA.ie && Y.UA.ie < 9){
  20          supportsVML = true;
  21      }
  22  
  23      var Lang = Y.Lang,
  24          Widget = Y.Widget,
  25          Node = Y.Node;
  26  
  27      /**
  28       * Create a dial to represent an input control capable of representing a
  29       * series of intermediate states based on the position of the Dial's handle.
  30       * These states are typically aligned to a value algorithm whereby the angle of the handle's
  31       * position corresponds to a given value.
  32       *
  33       * @class Dial
  34       * @extends Widget
  35       * @param config {Object} Configuration object
  36       * @constructor
  37       */
  38      function Dial(config) {
  39          Dial.superclass.constructor.apply(this, arguments);
  40      }
  41  
  42      // Y.Dial static properties
  43  
  44      /**
  45       * The identity of the widget.
  46       *
  47       * @property NAME
  48       * @type String
  49       * @default 'dial'
  50       * @readOnly
  51       * @protected
  52       * @static
  53       */
  54      Dial.NAME = "dial";
  55  
  56      /**
  57       * Static property used to define the default attribute configuration of
  58       * the Widget.
  59       *
  60       * @property ATTRS
  61       * @type {Object}
  62       * @protected
  63       * @static
  64       */
  65      Dial.ATTRS = {
  66  
  67          /**
  68           * minimum value allowed
  69           *
  70           * @attribute min
  71           * @type {Number}
  72           * @default -220
  73           */
  74          min : {
  75              value:-220
  76          },
  77  
  78          /**
  79           * maximum value allowed
  80           *
  81           * @attribute max
  82           * @type {Number}
  83           * @default 220
  84           */
  85          max : {
  86              value:220
  87          },
  88  
  89          /**
  90           * diameter of the circular background object.
  91           * Other objects scale accordingly.
  92           * Set this only before rendering.
  93           *
  94           * @attribute diameter
  95           * @type {Number} the number of px in diameter
  96           * @default 100
  97           * @writeOnce
  98           */
  99          diameter : {
 100              value:100
 101          },
 102  
 103          /**
 104           * diameter of the handle object which users drag to change the value.
 105           * Dial sets the pixel dimension of the handle equal to handleDiameter * diameter.
 106           * Set this only before rendering.
 107           *
 108           * @attribute handleDiameter
 109           * @type {Number}
 110           * @default 0.2
 111           * @writeOnce
 112           */
 113          handleDiameter : {
 114              value:0.2
 115          },
 116  
 117          /**
 118           * diameter of the marker object which follows the angle of the handle during value changes.
 119           * Dial sets the pixel dimension of the marker equal to markerDiameter * diameter.
 120           * Set this only before rendering.
 121           *
 122           * @attribute markerDiameter
 123           * @type {Number}
 124           * @default 0.1
 125           * @writeOnce
 126           */
 127          markerDiameter : {
 128              value:0.1
 129          },
 130  
 131          /**
 132           * diameter of the center button object.
 133           * Dial sets the pixel dimension of the centerButton equal to centerButtonDiameter * diameter.
 134           * Set this only before rendering.
 135           *
 136           * @attribute centerButtonDiameter
 137           * @type {Number}
 138           * @default 0.1
 139           * @writeOnce
 140           */
 141          centerButtonDiameter : {
 142              value:0.5
 143          },
 144  
 145          /**
 146           * initial value of the Dial
 147           *
 148           * @attribute value
 149           * @type {Number}
 150           * @default 0
 151           */
 152          value : {
 153              value:0,
 154              validator: function(val) {
 155                  return this._validateValue(val);
 156              }
 157          },
 158  
 159          /**
 160           * amount to increment/decrement the dial value
 161           * when the arrow up/down/left/right keys are pressed
 162           *
 163           * @attribute minorStep
 164           * @type {Number}
 165           * @default 1
 166           */
 167          minorStep : {
 168              value:1
 169          },
 170  
 171          /**
 172           * amount to increment/decrement the dial value
 173           * when the page up/down keys are pressed
 174           *
 175           * @attribute majorStep
 176           * @type {Number}
 177           * @default 10
 178           */
 179          majorStep : {
 180              value:10
 181          },
 182  
 183          /**
 184           * number of value increments in one 360 degree revolution
 185           * of the handle around the dial
 186           *
 187           * @attribute stepsPerRevolution
 188           * @type {Number}
 189           * @default 100
 190           */
 191          stepsPerRevolution : {
 192              value:100
 193          },
 194  
 195          /**
 196           * number of decimal places of accuracy in the value
 197           *
 198           * @attribute decimalPlaces
 199           * @type {Number}
 200           * @default 0
 201           */
 202          decimalPlaces : {
 203              value:0
 204          },
 205  
 206          /**
 207           * visible strings for the dial UI. This attribute is
 208           * defined by the base Widget class but has an empty value. The
 209           * Dial is simply providing a default value for the attribute.
 210           * Gets localized strings in the current language
 211           *
 212           * @attribute strings
 213           * @type {Object} the values are HTML strings
 214           * @default {label: 'My label', resetStr: 'Reset', tooltipHandle: 'Drag to set value'}
 215           */
 216          strings: {
 217              valueFn: function () {
 218                  return Y.Intl.get('dial');
 219              }
 220          },
 221  
 222          /**
 223           * distance from the center of the dial to the
 224           * center of the marker and handle, when at rest.
 225           * The value is a percent of the radius of the dial.
 226           *
 227           * @attribute handleDistance
 228           * @type {number}
 229           * @default 0.75
 230           */
 231          handleDistance:{
 232              value:0.75
 233          }
 234  
 235      };
 236  
 237      /**
 238       * returns a properly formed yui class name
 239       *
 240       * @method
 241       * @param {String} string to be appended at the end of class name
 242       * @return
 243       * @private
 244       */
 245      function makeClassName(str) {
 246          return Y.ClassNameManager.getClassName(Dial.NAME, str);
 247      }
 248  
 249       /** array of static constants used to identify the classname applied to the Dial DOM objects
 250       *
 251       * @property CSS_CLASSES
 252       * @type {Array}
 253       * @private
 254       * @static
 255       */
 256      Dial.CSS_CLASSES = {
 257          label : makeClassName("label"),
 258          labelString : makeClassName("label-string"),
 259          valueString : makeClassName("value-string"),
 260          northMark : makeClassName("north-mark"),
 261          ring : makeClassName('ring'),
 262          ringVml : makeClassName('ring-vml'),
 263          marker : makeClassName("marker"),
 264          markerVml : makeClassName("marker-vml"),
 265          markerMaxMin : makeClassName("marker-max-min"),
 266          centerButton : makeClassName("center-button"),
 267          centerButtonVml : makeClassName('center-button-vml'),
 268          resetString : makeClassName("reset-string"),
 269          handle : makeClassName("handle"),
 270          handleVml : makeClassName("handle-vml"),
 271          hidden : makeClassName("hidden"),
 272          dragging : Y.ClassNameManager.getClassName("dd-dragging")
 273      };
 274  
 275      /* Static constants used to define the markup templates used to create Dial DOM elements */
 276  
 277  
 278      /**
 279       * template that will contain the Dial's label.
 280       *
 281       * @property LABEL_TEMPLATE
 282       * @type {String}
 283       * @default &lt;div class="[...-label]">&lt;span id="" class="[...-label-string]">{label}&lt;/span>&lt;span class="[...-value-string]">&lt;/span>&lt;/div>
 284       * @protected
 285       */
 286  
 287      Dial.LABEL_TEMPLATE = '<div class="' + Dial.CSS_CLASSES.label + '"><span id="" class="' + Dial.CSS_CLASSES.labelString + '">{label}</span><span class="' + Dial.CSS_CLASSES.valueString + '"></span></div>';
 288  
 289      if(supportsVML === false){
 290          /**
 291           * template that will contain the Dial's background ring.
 292           *
 293           * @property RING_TEMPLATE
 294           * @type {String}
 295           * @default &lt;div class="[...-ring]">&lt;div class="[...-northMark]">&lt;/div>&lt;/div>
 296           * @protected
 297           */
 298          Dial.RING_TEMPLATE = '<div class="' + Dial.CSS_CLASSES.ring + '"><div class="' + Dial.CSS_CLASSES.northMark + '"></div></div>';
 299  
 300          /**
 301           * template that will contain the Dial's current angle marker.
 302           *
 303           * @property MARKER_TEMPLATE
 304           * @type {String}
 305           * @default &lt;div class="[...-marker] [...-marker-hidden]">&lt;div class="[...-markerUser]">&lt;/div>&lt;/div>
 306           * @protected
 307           */
 308          Dial.MARKER_TEMPLATE = '<div class="' + Dial.CSS_CLASSES.marker + ' ' + Dial.CSS_CLASSES.hidden + '"></div>';
 309  
 310          /**
 311           * template that will contain the Dial's center button.
 312           *
 313           * @property CENTER_BUTTON_TEMPLATE
 314           * @type {String}
 315           * @default &lt;div class="[...-centerButton]">&lt;div class="[...-resetString]">' + Y.Lang.sub('{resetStr}', Dial.ATTRS.strings.value) + '&lt;/div>&lt;/div>
 316           * @protected
 317           */
 318          Dial.CENTER_BUTTON_TEMPLATE = '<div class="' + Dial.CSS_CLASSES.centerButton + '"><div class="' + Dial.CSS_CLASSES.resetString + ' ' + Dial.CSS_CLASSES.hidden + '">{resetStr}</div></div>';
 319  
 320          /**
 321           * template that will contain the Dial's handle.
 322           *
 323           * @property HANDLE_TEMPLATE
 324           * @type {String}
 325           * @default &lt;div class="[...-handle]">&lt;div class="[...-handleUser]" aria-labelledby="" aria-valuetext="" aria-valuemax="" aria-valuemin="" aria-valuenow="" role="slider"  tabindex="0">&lt;/div>&lt;/div>';// title="{tooltipHandle}"
 326           * @protected
 327           */
 328          Dial.HANDLE_TEMPLATE = '<div class="' + Dial.CSS_CLASSES.handle + '" aria-labelledby="" aria-valuetext="" aria-valuemax="" aria-valuemin="" aria-valuenow="" role="slider"  tabindex="0" title="{tooltipHandle}">';
 329  
 330      }else{ // VML case
 331          Dial.RING_TEMPLATE = '<div class="' + Dial.CSS_CLASSES.ring +  ' ' + Dial.CSS_CLASSES.ringVml + '">'+
 332                                  '<div class="' + Dial.CSS_CLASSES.northMark + '"></div>'+
 333                                      '<v:oval strokecolor="#ceccc0" strokeweight="1px"><v:fill type=gradient color="#8B8A7F" color2="#EDEDEB" angle="45"/></v:oval>'+
 334                                  '</div>'+
 335                                  '';
 336          Dial.MARKER_TEMPLATE = '<div class="' + Dial.CSS_CLASSES.markerVml + ' ' + Dial.CSS_CLASSES.hidden + '">'+
 337                                          '<v:oval stroked="false">'+
 338                                              '<v:fill opacity="20%" color="#000"/>'+
 339                                          '</v:oval>'+
 340                                  '</div>'+
 341                                  '';
 342          Dial.CENTER_BUTTON_TEMPLATE = '<div class="' + Dial.CSS_CLASSES.centerButton + ' ' + Dial.CSS_CLASSES.centerButtonVml + '">'+
 343                                              '<v:oval strokecolor="#ceccc0" strokeweight="1px">'+
 344                                                  '<v:fill type=gradient color="#C7C5B9" color2="#fefcf6" colors="35% #d9d7cb, 65% #fefcf6" angle="45"/>'+
 345                                                  '<v:shadow on="True" color="#000" opacity="10%" offset="2px, 2px"/>'+
 346                                              '</v:oval>'+
 347                                              '<div class="' + Dial.CSS_CLASSES.resetString + ' ' + Dial.CSS_CLASSES.hidden + '">{resetStr}</div>'+
 348                                      '</div>'+
 349                                      '';
 350          Dial.HANDLE_TEMPLATE = '<div class="' + Dial.CSS_CLASSES.handleVml + '" aria-labelledby="" aria-valuetext="" aria-valuemax="" aria-valuemin="" aria-valuenow="" role="slider"  tabindex="0" title="{tooltipHandle}">'+
 351                                          '<v:oval stroked="false">'+
 352                                              '<v:fill opacity="20%" color="#6C3A3A"/>'+
 353                                          '</v:oval>'+
 354                                  '</div>'+
 355                                  '';
 356      }
 357  
 358      /* Dial extends the base Widget class */
 359      Y.extend(Dial, Widget, {
 360  
 361          /**
 362           * creates the DOM structure for the Dial.
 363           *
 364           * @method renderUI
 365           * @protected
 366           */
 367          renderUI : function() {
 368              this._renderLabel();
 369              this._renderRing();
 370              this._renderMarker();
 371              this._renderCenterButton();
 372              this._renderHandle();
 373  
 374              // object handles
 375              this.contentBox = this.get("contentBox");
 376  
 377              // constants
 378              this._originalValue = this.get('value');
 379              this._minValue = this.get('min'); // saves doing a .get many times, but we need to remember to update this if/when we allow changing min or max after instantiation
 380              this._maxValue = this.get('max');
 381              this._stepsPerRevolution = this.get('stepsPerRevolution');
 382              this._minTimesWrapped = (Math.floor(this._minValue / this._stepsPerRevolution - 1));
 383              this._maxTimesWrapped = (Math.floor(this._maxValue / this._stepsPerRevolution + 1));
 384  
 385              // variables
 386              this._timesWrapped = 0;
 387              this._angle = this._getAngleFromValue(this.get('value'));
 388              this._prevAng = this._angle;
 389  
 390              // init
 391              this._setTimesWrappedFromValue(this._originalValue);
 392              this._handleNode.set('aria-valuemin', this._minValue);
 393              this._handleNode.set('aria-valuemax', this._maxValue);
 394          },
 395  
 396          /**
 397           * Sets -webkit-border-radius to 50% of width/height of the ring, handle, marker, and center-button.
 398           * This is needed for iOS 3.x.
 399           * The objects render square if the radius is > 50% of the width/height
 400           * @method _setBorderRadius
 401           * @private
 402           */
 403          _setBorderRadius : function(){
 404              this._ringNode.setStyles({'WebkitBorderRadius':this._ringNodeRadius + 'px',
 405                                          'MozBorderRadius':this._ringNodeRadius + 'px',
 406                                          'borderRadius':this._ringNodeRadius + 'px'
 407                                       });
 408              this._handleNode.setStyles({'WebkitBorderRadius':this._handleNodeRadius + 'px',
 409                                          'MozBorderRadius':this._handleNodeRadius + 'px',
 410                                          'borderRadius':this._handleNodeRadius + 'px'
 411                                       });
 412              this._markerNode.setStyles({'WebkitBorderRadius':this._markerNodeRadius + 'px',
 413                                          'MozBorderRadius':this._markerNodeRadius + 'px',
 414                                          'borderRadius':this._markerNodeRadius + 'px'
 415                                       });
 416              this._centerButtonNode.setStyles({'WebkitBorderRadius':this._centerButtonNodeRadius + 'px',
 417                                          'MozBorderRadius':this._centerButtonNodeRadius + 'px',
 418                                          'borderRadius':this._centerButtonNodeRadius + 'px'
 419                                       });
 420          },
 421  
 422          /**
 423           * Handles the mouseenter on the centerButton
 424           *
 425           * @method _handleCenterButtonEnter
 426           * @protected
 427           */
 428          _handleCenterButtonEnter : function(){
 429              this._resetString.removeClass(Dial.CSS_CLASSES.hidden);
 430          },
 431  
 432          /**
 433           * Handles the mouseleave on the centerButton
 434           *
 435           * @method _handleCenterButtonLeave
 436           * @protected
 437           */
 438          _handleCenterButtonLeave : function(){
 439              this._resetString.addClass(Dial.CSS_CLASSES.hidden);
 440          },
 441  
 442          /**
 443           * Creates the Y.DD.Drag instance used for the handle movement and
 444           * binds Dial interaction to the configured value model.
 445           *
 446           * @method bindUI
 447           * @protected
 448           */
 449          bindUI : function() {
 450  
 451              this.after("valueChange", this._afterValueChange);
 452  
 453              var boundingBox = this.get("boundingBox"),
 454                  // Looking for a key event which will fire continously across browsers while the key is held down.
 455                  keyEvent = (!Y.UA.opera) ? "down:" : "press:",
 456                  // 38, 40 = arrow up/down, 33, 34 = page up/down,  35 , 36 = end/home
 457                  keyEventSpec = keyEvent + "38,40,33,34,35,36",
 458                  // 37 , 39 = arrow left/right
 459                  keyLeftRightSpec = keyEvent + "37,39",
 460                  // 37 , 39 = arrow left/right + meta (command/apple key) for mac
 461                  keyLeftRightSpecMeta = keyEvent + "37+meta,39+meta",
 462                  Drag = Y.DD.Drag;
 463  
 464              Y.on("key", Y.bind(this._onDirectionKey, this), boundingBox, keyEventSpec);
 465              Y.on("key", Y.bind(this._onLeftRightKey, this), boundingBox, keyLeftRightSpec);
 466              boundingBox.on("key", this._onLeftRightKeyMeta, keyLeftRightSpecMeta, this);
 467  
 468              Y.on('mouseenter', Y.bind(this._handleCenterButtonEnter, this), this._centerButtonNode);
 469              Y.on('mouseleave', Y.bind(this._handleCenterButtonLeave, this), this._centerButtonNode);
 470              // Needed to replace mousedown/up with gesturemovestart/end to make behavior on touch devices work the same.
 471              Y.on('gesturemovestart', Y.bind(this._resetDial, this), this._centerButtonNode);  //[#2530441]
 472              Y.on('gesturemoveend', Y.bind(this._handleCenterButtonMouseup, this), this._centerButtonNode);
 473  
 474  
 475              Y.on(Drag.START_EVENT, Y.bind(this._handleHandleMousedown, this), this._handleNode);
 476              Y.on(Drag.START_EVENT, Y.bind(this._handleMousedown, this), this._ringNode); // [#2530766]
 477  
 478              //TODO: Can this be merged this into the drag:end event listener to avoid another registration?
 479              Y.on('gesturemoveend', Y.bind(this._handleRingMouseup, this), this._ringNode);
 480  
 481              this._dd1 = new Drag({ //// [#2530206] changed global this._dd1 from just var dd1 = new Y.DD.drag so
 482                  node: this._handleNode,
 483                  on : {
 484                      'drag:drag' : Y.bind(this._handleDrag, this),
 485                      'drag:start' : Y.bind(this._handleDragStart, this),
 486                      'drag:end' : Y.bind(this._handleDragEnd, this) //,
 487                  }
 488              });
 489              Y.bind(this._dd1.addHandle(this._ringNode), this); // [#2530206] added the ring as a handle to the dd1 (the dd of the handleNode)
 490          },
 491  
 492          /**
 493           * Sets _timesWrapped based on Dial value
 494           * to net integer revolutions the user dragged the handle around the Dial
 495           *
 496           * @method _setTimesWrappedFromValue
 497           * @param val {Number} current value of the Dial
 498           * @private
 499           */
 500          _setTimesWrappedFromValue : function(val){
 501              if(val % this._stepsPerRevolution === 0){
 502                  this._timesWrapped = (val / this._stepsPerRevolution);
 503              }else{
 504                  this._timesWrapped = Math.floor(val / this._stepsPerRevolution);
 505              }
 506          },
 507  
 508          /**
 509           * gets the angle of the line from the center of the Dial to the center of the handle
 510           *
 511           * @method _getAngleFromHandleCenter
 512           * @param handleCenterX {number}
 513           * @param handleCenterY {number}
 514           * @return ang {number} the angle
 515           * @protected
 516           */
 517          _getAngleFromHandleCenter : function(handleCenterX, handleCenterY){
 518              var ang = Math.atan( (this._dialCenterY - handleCenterY)  /  (this._dialCenterX - handleCenterX)  ) * (180 / Math.PI);
 519              ang = ((this._dialCenterX - handleCenterX) < 0) ? ang + 90 : ang + 90 + 180; // Compensate for neg angles from Math.atan
 520              return ang;
 521          },
 522  
 523          /**
 524           * calculates the XY of the center of the dial relative to the ring node.
 525           * This is needed for calculating the angle of the handle
 526           *
 527           * @method _calculateDialCenter
 528           * @protected
 529           */
 530          _calculateDialCenter : function(){ // #2531111 value, and marker don't track handle when dial position changes on page (resize when inline)
 531              this._dialCenterX = this._ringNode.get('offsetWidth') / 2;
 532              this._dialCenterY = this._ringNode.get('offsetHeight') / 2;
 533          },
 534  
 535          /**
 536           * Handles the mouseup on the ring
 537           *
 538           * @method _handleRingMouseup
 539           * @protected
 540           */
 541          _handleRingMouseup : function(){
 542              this._handleNode.focus();  // need to re-focus on the handle so keyboard is accessible [#2530206]
 543          },
 544  
 545          /**
 546           * Handles the mouseup on the centerButton
 547           *
 548           * @method _handleCenterButtonMouseup
 549           * @protected
 550           */
 551          _handleCenterButtonMouseup : function(){
 552              this._handleNode.focus();  // need to re-focus on the handle so keyboard is accessible [#2530206]
 553          },
 554  
 555          /**
 556           * Handles the mousedown on the handle
 557           *
 558           * @method _handleHandleMousedown
 559           * @protected
 560           */
 561          _handleHandleMousedown : function(){
 562              this._handleNode.focus();  // need to re-focus on the handle so keyboard is accessible [#2530206]
 563              // this is better done here instead of on _handleDragEnd
 564              // because we should make the keyboard accessible after a click of the handle
 565          },
 566  
 567          /**
 568           * handles the user dragging the handle around the Dial, gets the angle,
 569           * checks for wrapping around top center.
 570           * Sets the new value of the Dial
 571           *
 572           * @method _handleDrag
 573           * @param e {DOMEvent} the drag event object
 574           * @protected
 575           */
 576          _handleDrag : function(e){
 577              var handleCenterX,
 578              handleCenterY,
 579              ang,
 580              newValue;
 581  
 582              // The event was emitted from drag:drag of handle.
 583              // The center of the handle is top left position of the handle node + radius of handle.
 584              // This is different than a mousedown on the ring.
 585              handleCenterX = (parseInt(this._handleNode.getStyle('left'),10) + this._handleNodeRadius);
 586              handleCenterY = (parseInt(this._handleNode.getStyle('top'),10) + this._handleNodeRadius);
 587              ang = this._getAngleFromHandleCenter(handleCenterX, handleCenterY);
 588  
 589              // check for need to set timesWrapped
 590              if((this._prevAng > 270) && (ang < 90)){ // If wrapping, clockwise
 591                  if(this._timesWrapped < this._maxTimesWrapped){
 592                      this._timesWrapped = (this._timesWrapped + 1);
 593                  }
 594              }else if((this._prevAng < 90) && (ang > 270)){ // if un-wrapping, counter-clockwise
 595                  if(this._timesWrapped > this._minTimesWrapped){
 596                     this._timesWrapped = (this._timesWrapped - 1);
 597                  }
 598              }
 599              newValue = this._getValueFromAngle(ang); // This function needs the current _timesWrapped value. That's why it comes after the _timesWrapped code above
 600  
 601              // If you've gone past max more than one full revolution, we decrement the _timesWrapped value
 602              // This gives the effect of a ratchet mechanism.
 603              // It feels like you are never more than one revolution past max
 604              // The effect is the same for min, only in reverse.
 605              // We can't reset the _timesWrapped to the max or min here.
 606              // If we did, the next (continuous) drag would reset the value incorrectly.
 607              if(newValue > (this._maxValue + this._stepsPerRevolution) ){
 608                  this._timesWrapped --;
 609              }else if(newValue < (this._minValue - this._stepsPerRevolution) ){
 610                  this._timesWrapped ++;
 611              }
 612              this._prevAng = ang; // need to keep the previous angle in order to check for wrapping on the next drag, click, or keypress
 613  
 614              this._handleValuesBeyondMinMax(e, newValue);
 615          },
 616  
 617          /**
 618           * handles a mousedown or gesturemovestart event on the ring node
 619           *
 620           * @method _handleMousedown
 621           * @param e {DOMEvent} the event object
 622           * @private
 623           */
 624          _handleMousedown : function(e){ // #2530306
 625  
 626              if (this._ringNode.compareTo(e.target)) {
 627                  var minAng = this._getAngleFromValue(this._minValue),
 628                  maxAng = this._getAngleFromValue(this._maxValue),
 629                  newValue, oppositeMidRangeAngle,
 630                  handleCenterX, handleCenterY,
 631                  ang;
 632  
 633  
 634  
 635                  // The event was emitted from mousedown on the ring node,
 636                  // so the center of the handle should be the XY of mousedown.
 637                  if(Y.UA.ios){  // ios adds the scrollLeft and top onto clientX and Y in a native click
 638                      handleCenterX = (e.clientX - this._ringNode.getX());
 639                      handleCenterY = (e.clientY - this._ringNode.getY());
 640                  }else{
 641                      handleCenterX = (e.clientX + Y.one('document').get('scrollLeft') - this._ringNode.getX());
 642                      handleCenterY = (e.clientY + Y.one('document').get('scrollTop') - this._ringNode.getY());
 643                  }
 644                  ang = this._getAngleFromHandleCenter(handleCenterX, handleCenterY);
 645  
 646                  /* ///////////////////////////////////////////////////////////////////////////////////////////////////////
 647                  * The next sections of logic
 648                  * set this._timesWrapped in the different cases of value range
 649                  * and value range position,
 650                  * then the Dial value is set at the end of this method
 651                  */ ///////////////////////////////////////////////////////////////////////////////////////////////////////
 652  
 653  
 654                  ////////////////////////////////////////////////////////////////////////////////////////////////////////////
 655                  if(this._maxValue - this._minValue > this._stepsPerRevolution){
 656  
 657                  // Case: range min-to-max is greater than stepsPerRevolution (one revolution)
 658  
 659                      // This checks the shortest way around the dial between the prevAng and this ang.
 660                      if(Math.abs(this._prevAng - ang) > 180){ // this crossed a wrapping
 661  
 662                          // Only change the _timesWrapped if it's between minTimesWrapped and maxTimesWrapped
 663                          if((this._timesWrapped > this._minTimesWrapped) &&
 664                             (this._timesWrapped < this._maxTimesWrapped)
 665                          ){
 666                              // this checks which direction, clock wise or CCW and incr or decr _timesWrapped
 667                              this._timesWrapped = ((this._prevAng - ang) > 0) ? (this._timesWrapped + 1) : (this._timesWrapped - 1);
 668                          }
 669                      // special case of getting un-stuck from a min value case
 670                      // where timesWrapped is minTimesWrapped but new ang won't trigger a cross wrap boundry
 671                      // because prevAng is set to 0 or > 0
 672                      }else if(
 673                              (this._timesWrapped === this._minTimesWrapped) &&
 674                              (ang - this._prevAng < 180)
 675                      ){
 676                          this._timesWrapped ++;
 677                      } //it didn't cross a wrapping boundary
 678  
 679                  } /////////////////////////////////////////////////////////////////////////////////////////////////////////
 680                  else if(this._maxValue - this._minValue === this._stepsPerRevolution){
 681                  // Case: range min-to-max === stepsPerRevolution     (one revolution)
 682                  // This means min and max will be at same angle
 683                  // This does not mean they are at "north"
 684  
 685                      if(ang < minAng){ // if mousedown angle is < minAng (and maxAng, because they're the same)
 686                                        // The only way it can be, is if min and max are not at north
 687                          this._timesWrapped = 1;
 688                      }else{
 689                          this._timesWrapped = 0;
 690                      }
 691  
 692                  } //////////////////////////////////////////////////////////////////////////////////////////////////////////
 693                  else if(minAng > maxAng){
 694                  // Case: range includes the wrap point (north)
 695                  // Because of "else if"...
 696                  // range is < stepsPerRevolution
 697  
 698                      if(
 699                         (this._prevAng >= minAng) && // if prev angle was greater than angle of min and...
 700                         (ang <= (minAng + maxAng) / 2) // the angle of this click is less than
 701                                                        // the angle opposite the mid-range angle, then...
 702                      ){
 703                          this._timesWrapped ++;
 704                      }else if(
 705                          (this._prevAng <= maxAng) &&
 706                          // if prev angle is < max angle and...
 707  
 708                          (ang > (minAng + maxAng) / 2)
 709                          // the angle of this click is greater than,
 710                          // the angle opposite the mid-range angle and...
 711  
 712                      ){
 713                          this._timesWrapped --;
 714                      }
 715  
 716                  } ////////////////////////////////////////////////////////////////////////////////////////////////////
 717                  else{
 718                  // "else" Case: min-to-max range doesn't include the wrap point
 719                  // Because of "else if"...
 720                  // range is still < stepsPerRevolution
 721  
 722                      if ((ang < minAng) || (ang > maxAng)){ // angle is out of range
 723                          oppositeMidRangeAngle = (((minAng + maxAng) / 2) + 180) % 360;
 724                          // This is the bisection of the min-to-max range + 180.  (opposite the bisection)
 725  
 726                          if(oppositeMidRangeAngle > 180){
 727                              newValue = ((maxAng < ang) && (ang < oppositeMidRangeAngle)) ? this.get('max') : this.get('min');
 728                          }else{ //oppositeMidRangeAngle <= 180
 729                              newValue = ((minAng > ang) && (ang > oppositeMidRangeAngle)) ? this.get('min') : this.get('max');
 730                          }
 731                          this._prevAng = this._getAngleFromValue(newValue);
 732                          this.set('value', newValue);
 733                          this._setTimesWrappedFromValue(newValue);
 734                          return;
 735                      }
 736                  }
 737  
 738                  // Now that _timesWrapped is set, set newValue .......................................................................
 739                  newValue = this._getValueFromAngle(ang); // This function needs the correct, current _timesWrapped value.
 740  
 741  
 742                  /* updating _prevAng (previous angle)
 743                   * When past min or max, _prevAng is set to the angle of min or max
 744                   * Don't do this in a drag method, or it will affect wrapping,
 745                   * causing the marker to stick at min, when min is 0 degrees (north)
 746                   * #2532878
 747                   */
 748                  if (newValue > this._maxValue) {
 749                      this._prevAng = this._getAngleFromValue(this._maxValue);  // #2530766 need for mousedown on the ring; causes prob for drag
 750                  } else if (newValue < this._minValue) {
 751                      this._prevAng = this._getAngleFromValue(this._minValue);
 752                  } else {
 753                      this._prevAng = ang;
 754                  }
 755  
 756                  this._handleValuesBeyondMinMax(e, newValue);
 757              }
 758          },
 759  
 760          /**
 761           * handles the case where the value is less than min or greater than max
 762           * This is used both when handle is dragged and when the ring is clicked
 763           *
 764           * @method _handleValuesBeyondMinMax
 765           * @param e {DOMEvent} the event object
 766           * @param newValue {number} current value of the dial
 767           * @protected
 768           */
 769          _handleValuesBeyondMinMax : function(e, newValue){ // #2530306
 770              // If _getValueFromAngle() is passed 0, it increments the _timesWrapped value.
 771              // handle hitting max and min and going beyond, stops at max or min
 772              if((newValue >= this._minValue) && (newValue <= this._maxValue)) {
 773                  this.set('value', newValue);
 774                  // [#2530206] transfer the mousedown event from the _ringNode to the _handleNode drag, so we can mousedown, then continue dragging
 775                  if(e.currentTarget === this._ringNode){
 776                      // Delegate to DD's natural behavior
 777                      this._dd1._handleMouseDownEvent(e);
 778                  }
 779              } else if (newValue > this._maxValue) {
 780                  this.set('value', this._maxValue);
 781              } else if (newValue < this._minValue) {
 782                  this.set('value', this._minValue);
 783              }
 784          },
 785  
 786          /**
 787           * handles the user starting to drag the handle around the Dial
 788           *
 789           * @method _handleDragStart
 790           * @param e {DOMEvent} the drag event object
 791           * @protected
 792           */
 793          _handleDragStart : function(e){
 794              this._markerNode.removeClass(Dial.CSS_CLASSES.hidden);
 795          },
 796  
 797          /*
 798           * When handle is handleDragEnd, this animates the return to the fixed dial
 799           */
 800  
 801          /**
 802           * handles the end of a user dragging the handle, animates the handle returning to
 803           * resting position.
 804           *
 805           * @method _handleDragEnd
 806           * @protected
 807           */
 808          _handleDragEnd : function(){
 809              var node = this._handleNode;
 810                  node.transition({
 811                      duration: 0.08, // seconds
 812                      easing: 'ease-in',
 813                      left: this._setNodeToFixedRadius(this._handleNode, true)[0] + 'px',
 814                      top: this._setNodeToFixedRadius(this._handleNode, true)[1] + 'px'
 815                  }, Y.bind(function(){
 816                          var value = this.get('value');
 817                          //[#2530206] only hide marker if not at max or min
 818                          // more persistant user visibility of when the dial is at max or min
 819                          if((value > this._minValue) && (value < this._maxValue)){
 820                              this._markerNode.addClass(Dial.CSS_CLASSES.hidden);
 821                          }else{
 822                              this._setTimesWrappedFromValue(value);  //#2530766 secondary bug when drag past max + cross wrapping boundry
 823                              this._prevAng = this._getAngleFromValue(value); //#2530766 secondary bug when drag past max + cross wrapping boundry
 824                          }
 825                      }, this)
 826                  );
 827          },
 828  
 829          /**
 830           * returns the XY of the fixed position, handleDistance, from the center of the Dial (resting position).
 831           * The XY also represents the angle related to the current value.
 832           * If typeArray is true, [X,Y] is returned.
 833           * If typeArray is false, the XY of the obj node passed in is set.
 834           *
 835           * @method _setNodeToFixedRadius
 836           * @param obj {Node}
 837           * @param typeArray {Boolean} true returns an array [X,Y]
 838           * @protected
 839           * @return {Array} an array of [XY] is optionally returned
 840           */
 841           _setNodeToFixedRadius : function(obj, typeArray){
 842              var thisAngle = (this._angle - 90),
 843              rad = (Math.PI / 180),
 844              newY = Math.round(Math.sin(thisAngle * rad) * this._handleDistance),
 845              newX = Math.round(Math.cos(thisAngle * rad) * this._handleDistance),
 846              dia = obj.get('offsetWidth'); //Ticket #2529852
 847  
 848              newY = newY - (dia * 0.5);
 849              newX = newX - (dia * 0.5);
 850              if(typeArray){ // just need the style for css transform left and top to animate the handle drag:end
 851                  return [(this._ringNodeRadius + newX), (this._ringNodeRadius + newY)];
 852              }else{
 853                  obj.setStyle('left', (this._ringNodeRadius + newX) + 'px');
 854                  obj.setStyle('top', (this._ringNodeRadius + newY) + 'px');
 855              }
 856           },
 857  
 858          /**
 859           * Synchronizes the DOM state with the attribute settings.
 860           *
 861           * @method syncUI
 862           */
 863          syncUI : function() {
 864              // Make the marker and the resetString display so their placement and borderRadius can be calculated, then hide them again.
 865              // We would have used visibility:hidden in the css of this class,
 866              // but IE8 VML never returns to visible after applying visibility:hidden then removing it.
 867              this._setSizes();
 868              this._calculateDialCenter(); // #2531111 initialize center of dial
 869              this._setBorderRadius();
 870              this._uiSetValue(this.get("value"));
 871              this._markerNode.addClass(Dial.CSS_CLASSES.hidden);
 872              this._resetString.addClass(Dial.CSS_CLASSES.hidden);
 873          },
 874  
 875          /**
 876           * sets the sizes of ring, center-button, marker, handle, and VML ovals in pixels.
 877           * Needed only because some IE versions
 878           * ignore CSS percent sizes/offsets.
 879           * so these must be set in pixels.
 880           * Normally these are set in % of the ring.
 881           *
 882           * @method _setSizes
 883           * @protected
 884           */
 885          _setSizes : function(){
 886              var dia = this.get('diameter'),
 887              offset, offsetResetX, offsetResetY,
 888              setSize = function(node, dia, percent){
 889                  var suffix = 'px';
 890                  node.getElementsByTagName('oval').setStyle('width', (dia * percent) + suffix);
 891                  node.getElementsByTagName('oval').setStyle('height', (dia * percent) + suffix);
 892                  node.setStyle('width', (dia * percent) + suffix);
 893                  node.setStyle('height', (dia * percent) + suffix);
 894              };
 895              setSize(this._ringNode, dia, 1.0);
 896              setSize(this._handleNode, dia, this.get('handleDiameter'));
 897              setSize(this._markerNode, dia, this.get('markerDiameter'));
 898              setSize(this._centerButtonNode, dia, this.get('centerButtonDiameter'));
 899  
 900              // Set these (used for trig) this way instead of relative to dia,
 901              // in case they have borders, have images etc.
 902              this._ringNodeRadius = this._ringNode.get('offsetWidth') * 0.5;
 903              this._handleNodeRadius = this._handleNode.get('offsetWidth') * 0.5;
 904              this._markerNodeRadius = this._markerNode.get('offsetWidth') * 0.5;
 905              this._centerButtonNodeRadius = this._centerButtonNode.get('offsetWidth') * 0.5;
 906              this._handleDistance = this._ringNodeRadius * this.get('handleDistance');
 907              // place the centerButton
 908              offset = (this._ringNodeRadius - this._centerButtonNodeRadius);
 909              this._centerButtonNode.setStyle('left', offset + 'px');
 910              this._centerButtonNode.setStyle('top', offset + 'px');
 911              /*
 912              Place the resetString
 913              This seems like it should be able to be done with CSS,
 914              But since there is also a VML oval in IE that is absolute positioned,
 915              The resetString ends up behind the VML oval.
 916              */
 917              offsetResetX = (this._centerButtonNodeRadius - (this._resetString.get('offsetWidth') * 0.5));
 918              offsetResetY = (this._centerButtonNodeRadius - (this._resetString.get('offsetHeight') * 0.5));
 919              this._resetString.setStyles({'left':offsetResetX + 'px', 'top':offsetResetY + 'px'});
 920          },
 921  
 922  
 923          /**
 924           * renders the DOM object for the Dial's label
 925           *
 926           * @method _renderLabel
 927           * @protected
 928           */
 929          _renderLabel : function() {
 930              var contentBox = this.get("contentBox"),
 931                  label = contentBox.one("." + Dial.CSS_CLASSES.label);
 932              if (!label) {
 933                  label = Node.create(Y.Lang.sub(Dial.LABEL_TEMPLATE, this.get('strings')));
 934                  contentBox.append(label);
 935              }
 936              this._labelNode = label;
 937              this._valueStringNode = this._labelNode.one("." + Dial.CSS_CLASSES.valueString);
 938          },
 939  
 940          /**
 941           * renders the DOM object for the Dial's background ring
 942           *
 943           * @method _renderRing
 944           * @protected
 945           */
 946          _renderRing : function() {
 947              var contentBox = this.get("contentBox"),
 948                  ring = contentBox.one("." + Dial.CSS_CLASSES.ring);
 949              if (!ring) {
 950                  ring = contentBox.appendChild(Dial.RING_TEMPLATE);
 951                  ring.setStyles({width:this.get('diameter') + 'px', height:this.get('diameter') + 'px'});
 952              }
 953              this._ringNode = ring;
 954          },
 955  
 956          /**
 957           * renders the DOM object for the Dial's background marker which
 958           * tracks the angle of the user dragging the handle
 959           *
 960           * @method _renderMarker
 961           * @protected
 962           */
 963          _renderMarker : function() {
 964              var contentBox = this.get("contentBox"),
 965              marker = contentBox.one("." + Dial.CSS_CLASSES.marker);
 966              if (!marker) {
 967                  marker = contentBox.one('.' + Dial.CSS_CLASSES.ring).appendChild(Dial.MARKER_TEMPLATE);
 968              }
 969              this._markerNode = marker;
 970          },
 971  
 972          /**
 973           * renders the DOM object for the Dial's center
 974           *
 975           * @method _renderCenterButton
 976           * @protected
 977           */
 978          _renderCenterButton : function() {
 979              var contentBox = this.get("contentBox"),
 980                  centerButton = contentBox.one("." + Dial.CSS_CLASSES.centerButton);
 981              if (!centerButton) {
 982                  centerButton = Node.create(Y.Lang.sub(Dial.CENTER_BUTTON_TEMPLATE, this.get('strings')));
 983                  contentBox.one('.' + Dial.CSS_CLASSES.ring).append(centerButton);
 984              }
 985              this._centerButtonNode = centerButton;
 986              this._resetString = this._centerButtonNode.one('.' + Dial.CSS_CLASSES.resetString);
 987          },
 988  
 989          /**
 990           * renders the DOM object for the Dial's user draggable handle
 991           *
 992           * @method _renderHandle
 993           * @protected
 994           */
 995          _renderHandle : function() {
 996              var labelId = Dial.CSS_CLASSES.label + Y.guid(), //get this unique id once then use for handle and label for ARIA
 997                  contentBox = this.get("contentBox"),
 998                  handle = contentBox.one("." + Dial.CSS_CLASSES.handle);
 999              if (!handle) {
1000                  handle = Node.create(Y.Lang.sub(Dial.HANDLE_TEMPLATE, this.get('strings')));
1001                  handle.setAttribute('aria-labelledby', labelId);  // get unique id for specifying a label & handle for ARIA
1002                  this._labelNode.one('.' + Dial.CSS_CLASSES.labelString).setAttribute('id', labelId);  // When handle gets focus, screen reader will include label text when reading the value.
1003                  contentBox.one('.' + Dial.CSS_CLASSES.ring).append(handle);
1004              }
1005              this._handleNode = handle;
1006          },
1007  
1008          /**
1009           * sets the visible UI label HTML string
1010           *
1011           * @method _setLabelString
1012           * @param str {String}
1013           * @protected
1014           * @deprecated Use DialObjName.set('strings',{'label':'My new label'});   before DialObjName.render();
1015  
1016           */
1017          _setLabelString : function(str) {
1018              this.get("contentBox").one("." + Dial.CSS_CLASSES.labelString).setHTML(str);
1019          },
1020  
1021          /**
1022           * sets the visible UI label HTML string
1023           *
1024           * @method _setResetString
1025           * @param str {String}
1026           * @protected
1027           * @deprecated Use DialObjName.set('strings',{'resetStr':'My new reset string'});   before DialObjName.render();
1028           */
1029          _setResetString : function(str) {
1030               this.get("contentBox").one("." + Dial.CSS_CLASSES.resetString).setHTML(str);
1031              // this._setXYResetString(); // This used to recenter the string in the button. Done with CSS now. Method has been removed.
1032              // this._resetString.setHTML(''); //We no longer show/hide the reset string with setHTML but by addClass and removeClass .yui3-dial-reset-string-hidden
1033          },
1034  
1035          /**
1036           * sets the tooltip HTML string in the Dial's handle
1037           *
1038           * @method _setTooltipString
1039           * @param str {String}
1040           * @protected
1041           * @deprecated Use DialObjName.set('strings',{'tooltipHandle':'My new tooltip'});   before DialObjName.render();
1042           */
1043          _setTooltipString : function(str) {
1044              this._handleNode.set('title', str);
1045          },
1046  
1047          /**
1048           * sets the Dial's value in response to key events.
1049           * Left and right keys are in a separate method
1050           * in case an implementation wants to increment values
1051           * but needs left and right arrow keys for other purposes.
1052           *
1053           * @method _onDirectionKey
1054           * @param e {Event} the key event
1055           * @protected
1056           */
1057          _onDirectionKey : function(e) {
1058              e.preventDefault();
1059              switch (e.charCode) {
1060                  case 38: // up
1061                      this._incrMinor();
1062                      break;
1063                  case 40: // down
1064                      this._decrMinor();
1065                      break;
1066                  case 36: // home
1067                      this._setToMin();
1068                      break;
1069                  case 35: // end
1070                      this._setToMax();
1071                      break;
1072                  case 33: // page up
1073                      this._incrMajor();
1074                      break;
1075                  case 34: // page down
1076                      this._decrMajor();
1077                      break;
1078              }
1079          },
1080  
1081          /**
1082           * sets the Dial's value in response to left or right key events
1083           *
1084           * @method _onLeftRightKey
1085           * @param e {Event} the key event
1086           * @protected
1087           */
1088          _onLeftRightKey : function(e) {
1089              e.preventDefault();
1090              switch (e.charCode) {
1091                  case 37: // left
1092                      this._decrMinor();
1093                      break;
1094                  case 39: // right
1095                      this._incrMinor();
1096                      break;
1097              }
1098          },
1099  
1100          /**
1101           * sets the Dial's value in response to left or right key events when a meta (mac command/apple) key is also pressed
1102           *
1103           * @method _onLeftRightKeyMeta
1104           * @param e {Event} the key event
1105           * @protected
1106           */
1107          _onLeftRightKeyMeta : function(e) {
1108              e.preventDefault();
1109              switch (e.charCode) {
1110                  case 37: // left + meta
1111                      this._setToMin();
1112                      break;
1113                  case 39: // right + meta
1114                      this._setToMax();
1115                      break;
1116              }
1117          },
1118  
1119          /**
1120           * increments Dial value by a minor increment
1121           *
1122           * @method _incrMinor
1123           * @protected
1124           */
1125          _incrMinor : function(){
1126                  var newVal = (this.get('value') + this.get("minorStep"));
1127                  newVal = Math.min(newVal, this.get("max"));
1128                  // [#2530045] .toFixed returns a string.
1129                  // Dial's value needs a number. -0 makes it a number, but removes trailing zeros.
1130                  // Added toFixed(...) again in _uiSetValue where content of yui3-dial-value-string is set.
1131                  // Removing the toFixed here, loses the feature of "snap-to" when for example, stepsPerRevolution is 10 and decimalPlaces is 0.
1132                  this.set('value', newVal.toFixed(this.get('decimalPlaces')) - 0);
1133          },
1134  
1135          /**
1136           * decrements Dial value by a minor increment
1137           *
1138           * @method _decrMinor
1139           * @protected
1140           */
1141          _decrMinor : function(){
1142                  var newVal = (this.get('value') - this.get("minorStep"));
1143                  newVal = Math.max(newVal, this.get("min"));
1144                  this.set('value', newVal.toFixed(this.get('decimalPlaces')) - 0);
1145          },
1146  
1147          /**
1148           * increments Dial value by a major increment
1149           *
1150           * @method _incrMajor
1151           * @protected
1152           */
1153          _incrMajor : function(){
1154                  var newVal = (this.get('value') + this.get("majorStep"));
1155                  newVal = Math.min(newVal, this.get("max"));
1156                  this.set('value', newVal.toFixed(this.get('decimalPlaces')) - 0);
1157          },
1158  
1159          /**
1160           * decrements Dial value by a major increment
1161           *
1162           * @method _decrMajor
1163           * @protected
1164           */
1165          _decrMajor : function(){
1166                  var newVal = (this.get('value') - this.get("majorStep"));
1167                  newVal = Math.max(newVal, this.get("min"));
1168                  this.set('value', newVal.toFixed(this.get('decimalPlaces')) - 0);
1169          },
1170  
1171          /**
1172           * sets Dial value to dial's max attr
1173           *
1174           * @method _setToMax
1175           * @protected
1176           */
1177          _setToMax : function(){
1178                  this.set('value', this.get("max"));
1179          },
1180  
1181          /**
1182           * sets Dial value to dial's min attr
1183           *
1184           * @method _setToMin
1185           * @protected
1186           */
1187          _setToMin : function(){
1188                  this.set('value', this.get("min"));
1189          },
1190  
1191          /**
1192           * resets Dial value to the orignal initial value.
1193           *
1194           * @method _resetDial
1195           * @protected
1196           */
1197          _resetDial : function(e){
1198              if(e){
1199                  e.stopPropagation(); //[#2530206] need to add so mousedown doesn't propagate to ring and move the handle
1200              }
1201              this.set('value', this._originalValue);
1202              this._resetString.addClass(Dial.CSS_CLASSES.hidden); //[#2530441]
1203              this._handleNode.focus();
1204          },
1205  
1206          /**
1207           * returns the handle angle associated with the current value of the Dial.
1208           * Returns a number between 0 and 360.
1209           *
1210           * @method _getAngleFromValue
1211           * @param newVal {Number} the current value of the Dial
1212           * @return {Number} the angle associated with the current Dial value
1213           * @protected
1214           */
1215          _getAngleFromValue : function(newVal){
1216              var nonWrappedPartOfValue = newVal % this._stepsPerRevolution,
1217              angleFromValue = nonWrappedPartOfValue / this._stepsPerRevolution * 360;
1218              return (angleFromValue < 0) ? (angleFromValue + 360) : angleFromValue;
1219          },
1220  
1221          /**
1222           * returns the value of the Dial calculated from the current handle angle
1223           *
1224           * @method _getValueFromAngle
1225           * @param angle {Number} the current angle of the Dial's handle
1226           * @return {Number} the current Dial value corresponding to the handle position
1227           * @protected
1228           */
1229          _getValueFromAngle : function(angle){
1230              if(angle < 0){
1231                  angle = (360 + angle);
1232              }else if(angle === 0){
1233                  angle = 360;
1234              }
1235              var value = (angle / 360) * this._stepsPerRevolution;
1236              value = (value + (this._timesWrapped * this._stepsPerRevolution));
1237              //return Math.round(value * 100) / 100;
1238              return value.toFixed(this.get('decimalPlaces')) - 0;
1239          },
1240  
1241          /**
1242           * calls the method to update the UI whenever the Dial value changes
1243           *
1244           * @method _afterValueChange
1245           * @param e {Event}
1246           * @protected
1247           */
1248          _afterValueChange : function(e) {
1249              this._uiSetValue(e.newVal);
1250          },
1251  
1252          /**
1253           * Changes a value to have the correct decimal places per the attribute decimalPlaces
1254           *
1255           * @method _valueToDecimalPlaces
1256           * @param val {Number} a raw value to set to the Dial
1257           * @return {Number} the input val changed to have the correct decimal places
1258           * @protected
1259           */
1260          _valueToDecimalPlaces : function(val) { // [#2530206] cleaned up and better user feedback of when it's max or min.
1261  
1262          },
1263  
1264          /**
1265           * Updates the UI display value of the Dial to reflect
1266           * the value passed in.
1267           * Makes all other needed UI display changes
1268           *
1269           * @method _uiSetValue
1270           * @param val {Number} value of the Dial
1271           * @protected
1272           */
1273          _uiSetValue : function(val) { // [#2530206] cleaned up and better user feedback of when it's max or min.
1274              this._angle = this._getAngleFromValue(val);
1275              if(this._handleNode.hasClass(Dial.CSS_CLASSES.dragging) === false){
1276                  this._setTimesWrappedFromValue(val);
1277                  this._setNodeToFixedRadius(this._handleNode, false);
1278                  this._prevAng = this._getAngleFromValue(this.get('value'));
1279              }
1280              this._valueStringNode.setHTML(val.toFixed(this.get('decimalPlaces'))); // [#2530045]
1281              this._handleNode.set('aria-valuenow', val);
1282              this._handleNode.set('aria-valuetext', val);
1283              this._setNodeToFixedRadius(this._markerNode, false);
1284              if((val === this._maxValue) || (val === this._minValue)){
1285                  this._markerNode.addClass(Dial.CSS_CLASSES.markerMaxMin);
1286                  if(supportsVML === true){
1287                      this._markerNode.getElementsByTagName('fill').set('color', '#AB3232');
1288                  }
1289                  this._markerNode.removeClass(Dial.CSS_CLASSES.hidden);
1290              }else{ // not max or min
1291                  if(supportsVML === true){
1292                      this._markerNode.getElementsByTagName('fill').set('color', '#000');
1293                  }
1294                  this._markerNode.removeClass(Dial.CSS_CLASSES.markerMaxMin);
1295                  if(this._handleNode.hasClass(Dial.CSS_CLASSES.dragging) === false){ // if not max || min, and not dragging handle, hide the marker
1296                      this._markerNode.addClass(Dial.CSS_CLASSES.hidden);
1297                  }
1298              }
1299          },
1300  
1301          /**
1302           * value attribute default validator. Verifies that
1303           * the value being set lies between the min/max value
1304           *
1305           * @method _validateValue
1306           * @param val {Number} value of the Dial
1307           * @protected
1308           */
1309          _validateValue: function(val) {
1310              var min = this.get("min"),
1311                  max = this.get("max");
1312              return (Lang.isNumber(val) && val >= min && val <= max);
1313          }
1314      });
1315      Y.Dial = Dial;
1316  
1317  
1318  }, '3.17.2', {
1319      "requires": [
1320          "widget",
1321          "dd-drag",
1322          "event-mouseenter",
1323          "event-move",
1324          "event-key",
1325          "transition",
1326          "intl"
1327      ],
1328      "lang": [
1329          "en",
1330          "es",
1331          "hu"
1332      ],
1333      "skinnable": true
1334  });


Generated: Thu Aug 11 10:00:09 2016 Cross-referenced by PHPXref 0.7.1