[ Index ]

PHP Cross Reference of MediaWiki-1.24.0

title

Body

[close]

/resources/lib/jquery.ui/ -> jquery.ui.spinner.js (source)

   1  /*!
   2   * jQuery UI Spinner 1.9.2
   3   * http://jqueryui.com
   4   *
   5   * Copyright 2012 jQuery Foundation and other contributors
   6   * Released under the MIT license.
   7   * http://jquery.org/license
   8   *
   9   * http://api.jqueryui.com/spinner/
  10   *
  11   * Depends:
  12   *  jquery.ui.core.js
  13   *  jquery.ui.widget.js
  14   *  jquery.ui.button.js
  15   */
  16  (function( $ ) {
  17  
  18  function modifier( fn ) {
  19      return function() {
  20          var previous = this.element.val();
  21          fn.apply( this, arguments );
  22          this._refresh();
  23          if ( previous !== this.element.val() ) {
  24              this._trigger( "change" );
  25          }
  26      };
  27  }
  28  
  29  $.widget( "ui.spinner", {
  30      version: "1.9.2",
  31      defaultElement: "<input>",
  32      widgetEventPrefix: "spin",
  33      options: {
  34          culture: null,
  35          icons: {
  36              down: "ui-icon-triangle-1-s",
  37              up: "ui-icon-triangle-1-n"
  38          },
  39          incremental: true,
  40          max: null,
  41          min: null,
  42          numberFormat: null,
  43          page: 10,
  44          step: 1,
  45  
  46          change: null,
  47          spin: null,
  48          start: null,
  49          stop: null
  50      },
  51  
  52      _create: function() {
  53          // handle string values that need to be parsed
  54          this._setOption( "max", this.options.max );
  55          this._setOption( "min", this.options.min );
  56          this._setOption( "step", this.options.step );
  57  
  58          // format the value, but don't constrain
  59          this._value( this.element.val(), true );
  60  
  61          this._draw();
  62          this._on( this._events );
  63          this._refresh();
  64  
  65          // turning off autocomplete prevents the browser from remembering the
  66          // value when navigating through history, so we re-enable autocomplete
  67          // if the page is unloaded before the widget is destroyed. #7790
  68          this._on( this.window, {
  69              beforeunload: function() {
  70                  this.element.removeAttr( "autocomplete" );
  71              }
  72          });
  73      },
  74  
  75      _getCreateOptions: function() {
  76          var options = {},
  77              element = this.element;
  78  
  79          $.each( [ "min", "max", "step" ], function( i, option ) {
  80              var value = element.attr( option );
  81              if ( value !== undefined && value.length ) {
  82                  options[ option ] = value;
  83              }
  84          });
  85  
  86          return options;
  87      },
  88  
  89      _events: {
  90          keydown: function( event ) {
  91              if ( this._start( event ) && this._keydown( event ) ) {
  92                  event.preventDefault();
  93              }
  94          },
  95          keyup: "_stop",
  96          focus: function() {
  97              this.previous = this.element.val();
  98          },
  99          blur: function( event ) {
 100              if ( this.cancelBlur ) {
 101                  delete this.cancelBlur;
 102                  return;
 103              }
 104  
 105              this._refresh();
 106              if ( this.previous !== this.element.val() ) {
 107                  this._trigger( "change", event );
 108              }
 109          },
 110          mousewheel: function( event, delta ) {
 111              if ( !delta ) {
 112                  return;
 113              }
 114              if ( !this.spinning && !this._start( event ) ) {
 115                  return false;
 116              }
 117  
 118              this._spin( (delta > 0 ? 1 : -1) * this.options.step, event );
 119              clearTimeout( this.mousewheelTimer );
 120              this.mousewheelTimer = this._delay(function() {
 121                  if ( this.spinning ) {
 122                      this._stop( event );
 123                  }
 124              }, 100 );
 125              event.preventDefault();
 126          },
 127          "mousedown .ui-spinner-button": function( event ) {
 128              var previous;
 129  
 130              // We never want the buttons to have focus; whenever the user is
 131              // interacting with the spinner, the focus should be on the input.
 132              // If the input is focused then this.previous is properly set from
 133              // when the input first received focus. If the input is not focused
 134              // then we need to set this.previous based on the value before spinning.
 135              previous = this.element[0] === this.document[0].activeElement ?
 136                  this.previous : this.element.val();
 137  			function checkFocus() {
 138                  var isActive = this.element[0] === this.document[0].activeElement;
 139                  if ( !isActive ) {
 140                      this.element.focus();
 141                      this.previous = previous;
 142                      // support: IE
 143                      // IE sets focus asynchronously, so we need to check if focus
 144                      // moved off of the input because the user clicked on the button.
 145                      this._delay(function() {
 146                          this.previous = previous;
 147                      });
 148                  }
 149              }
 150  
 151              // ensure focus is on (or stays on) the text field
 152              event.preventDefault();
 153              checkFocus.call( this );
 154  
 155              // support: IE
 156              // IE doesn't prevent moving focus even with event.preventDefault()
 157              // so we set a flag to know when we should ignore the blur event
 158              // and check (again) if focus moved off of the input.
 159              this.cancelBlur = true;
 160              this._delay(function() {
 161                  delete this.cancelBlur;
 162                  checkFocus.call( this );
 163              });
 164  
 165              if ( this._start( event ) === false ) {
 166                  return;
 167              }
 168  
 169              this._repeat( null, $( event.currentTarget ).hasClass( "ui-spinner-up" ) ? 1 : -1, event );
 170          },
 171          "mouseup .ui-spinner-button": "_stop",
 172          "mouseenter .ui-spinner-button": function( event ) {
 173              // button will add ui-state-active if mouse was down while mouseleave and kept down
 174              if ( !$( event.currentTarget ).hasClass( "ui-state-active" ) ) {
 175                  return;
 176              }
 177  
 178              if ( this._start( event ) === false ) {
 179                  return false;
 180              }
 181              this._repeat( null, $( event.currentTarget ).hasClass( "ui-spinner-up" ) ? 1 : -1, event );
 182          },
 183          // TODO: do we really want to consider this a stop?
 184          // shouldn't we just stop the repeater and wait until mouseup before
 185          // we trigger the stop event?
 186          "mouseleave .ui-spinner-button": "_stop"
 187      },
 188  
 189      _draw: function() {
 190          var uiSpinner = this.uiSpinner = this.element
 191              .addClass( "ui-spinner-input" )
 192              .attr( "autocomplete", "off" )
 193              .wrap( this._uiSpinnerHtml() )
 194              .parent()
 195                  // add buttons
 196                  .append( this._buttonHtml() );
 197  
 198          this.element.attr( "role", "spinbutton" );
 199  
 200          // button bindings
 201          this.buttons = uiSpinner.find( ".ui-spinner-button" )
 202              .attr( "tabIndex", -1 )
 203              .button()
 204              .removeClass( "ui-corner-all" );
 205  
 206          // IE 6 doesn't understand height: 50% for the buttons
 207          // unless the wrapper has an explicit height
 208          if ( this.buttons.height() > Math.ceil( uiSpinner.height() * 0.5 ) &&
 209                  uiSpinner.height() > 0 ) {
 210              uiSpinner.height( uiSpinner.height() );
 211          }
 212  
 213          // disable spinner if element was already disabled
 214          if ( this.options.disabled ) {
 215              this.disable();
 216          }
 217      },
 218  
 219      _keydown: function( event ) {
 220          var options = this.options,
 221              keyCode = $.ui.keyCode;
 222  
 223          switch ( event.keyCode ) {
 224          case keyCode.UP:
 225              this._repeat( null, 1, event );
 226              return true;
 227          case keyCode.DOWN:
 228              this._repeat( null, -1, event );
 229              return true;
 230          case keyCode.PAGE_UP:
 231              this._repeat( null, options.page, event );
 232              return true;
 233          case keyCode.PAGE_DOWN:
 234              this._repeat( null, -options.page, event );
 235              return true;
 236          }
 237  
 238          return false;
 239      },
 240  
 241      _uiSpinnerHtml: function() {
 242          return "<span class='ui-spinner ui-widget ui-widget-content ui-corner-all'></span>";
 243      },
 244  
 245      _buttonHtml: function() {
 246          return "" +
 247              "<a class='ui-spinner-button ui-spinner-up ui-corner-tr'>" +
 248                  "<span class='ui-icon " + this.options.icons.up + "'>&#9650;</span>" +
 249              "</a>" +
 250              "<a class='ui-spinner-button ui-spinner-down ui-corner-br'>" +
 251                  "<span class='ui-icon " + this.options.icons.down + "'>&#9660;</span>" +
 252              "</a>";
 253      },
 254  
 255      _start: function( event ) {
 256          if ( !this.spinning && this._trigger( "start", event ) === false ) {
 257              return false;
 258          }
 259  
 260          if ( !this.counter ) {
 261              this.counter = 1;
 262          }
 263          this.spinning = true;
 264          return true;
 265      },
 266  
 267      _repeat: function( i, steps, event ) {
 268          i = i || 500;
 269  
 270          clearTimeout( this.timer );
 271          this.timer = this._delay(function() {
 272              this._repeat( 40, steps, event );
 273          }, i );
 274  
 275          this._spin( steps * this.options.step, event );
 276      },
 277  
 278      _spin: function( step, event ) {
 279          var value = this.value() || 0;
 280  
 281          if ( !this.counter ) {
 282              this.counter = 1;
 283          }
 284  
 285          value = this._adjustValue( value + step * this._increment( this.counter ) );
 286  
 287          if ( !this.spinning || this._trigger( "spin", event, { value: value } ) !== false) {
 288              this._value( value );
 289              this.counter++;
 290          }
 291      },
 292  
 293      _increment: function( i ) {
 294          var incremental = this.options.incremental;
 295  
 296          if ( incremental ) {
 297              return $.isFunction( incremental ) ?
 298                  incremental( i ) :
 299                  Math.floor( i*i*i/50000 - i*i/500 + 17*i/200 + 1 );
 300          }
 301  
 302          return 1;
 303      },
 304  
 305      _precision: function() {
 306          var precision = this._precisionOf( this.options.step );
 307          if ( this.options.min !== null ) {
 308              precision = Math.max( precision, this._precisionOf( this.options.min ) );
 309          }
 310          return precision;
 311      },
 312  
 313      _precisionOf: function( num ) {
 314          var str = num.toString(),
 315              decimal = str.indexOf( "." );
 316          return decimal === -1 ? 0 : str.length - decimal - 1;
 317      },
 318  
 319      _adjustValue: function( value ) {
 320          var base, aboveMin,
 321              options = this.options;
 322  
 323          // make sure we're at a valid step
 324          // - find out where we are relative to the base (min or 0)
 325          base = options.min !== null ? options.min : 0;
 326          aboveMin = value - base;
 327          // - round to the nearest step
 328          aboveMin = Math.round(aboveMin / options.step) * options.step;
 329          // - rounding is based on 0, so adjust back to our base
 330          value = base + aboveMin;
 331  
 332          // fix precision from bad JS floating point math
 333          value = parseFloat( value.toFixed( this._precision() ) );
 334  
 335          // clamp the value
 336          if ( options.max !== null && value > options.max) {
 337              return options.max;
 338          }
 339          if ( options.min !== null && value < options.min ) {
 340              return options.min;
 341          }
 342  
 343          return value;
 344      },
 345  
 346      _stop: function( event ) {
 347          if ( !this.spinning ) {
 348              return;
 349          }
 350  
 351          clearTimeout( this.timer );
 352          clearTimeout( this.mousewheelTimer );
 353          this.counter = 0;
 354          this.spinning = false;
 355          this._trigger( "stop", event );
 356      },
 357  
 358      _setOption: function( key, value ) {
 359          if ( key === "culture" || key === "numberFormat" ) {
 360              var prevValue = this._parse( this.element.val() );
 361              this.options[ key ] = value;
 362              this.element.val( this._format( prevValue ) );
 363              return;
 364          }
 365  
 366          if ( key === "max" || key === "min" || key === "step" ) {
 367              if ( typeof value === "string" ) {
 368                  value = this._parse( value );
 369              }
 370          }
 371  
 372          this._super( key, value );
 373  
 374          if ( key === "disabled" ) {
 375              if ( value ) {
 376                  this.element.prop( "disabled", true );
 377                  this.buttons.button( "disable" );
 378              } else {
 379                  this.element.prop( "disabled", false );
 380                  this.buttons.button( "enable" );
 381              }
 382          }
 383      },
 384  
 385      _setOptions: modifier(function( options ) {
 386          this._super( options );
 387          this._value( this.element.val() );
 388      }),
 389  
 390      _parse: function( val ) {
 391          if ( typeof val === "string" && val !== "" ) {
 392              val = window.Globalize && this.options.numberFormat ?
 393                  Globalize.parseFloat( val, 10, this.options.culture ) : +val;
 394          }
 395          return val === "" || isNaN( val ) ? null : val;
 396      },
 397  
 398      _format: function( value ) {
 399          if ( value === "" ) {
 400              return "";
 401          }
 402          return window.Globalize && this.options.numberFormat ?
 403              Globalize.format( value, this.options.numberFormat, this.options.culture ) :
 404              value;
 405      },
 406  
 407      _refresh: function() {
 408          this.element.attr({
 409              "aria-valuemin": this.options.min,
 410              "aria-valuemax": this.options.max,
 411              // TODO: what should we do with values that can't be parsed?
 412              "aria-valuenow": this._parse( this.element.val() )
 413          });
 414      },
 415  
 416      // update the value without triggering change
 417      _value: function( value, allowAny ) {
 418          var parsed;
 419          if ( value !== "" ) {
 420              parsed = this._parse( value );
 421              if ( parsed !== null ) {
 422                  if ( !allowAny ) {
 423                      parsed = this._adjustValue( parsed );
 424                  }
 425                  value = this._format( parsed );
 426              }
 427          }
 428          this.element.val( value );
 429          this._refresh();
 430      },
 431  
 432      _destroy: function() {
 433          this.element
 434              .removeClass( "ui-spinner-input" )
 435              .prop( "disabled", false )
 436              .removeAttr( "autocomplete" )
 437              .removeAttr( "role" )
 438              .removeAttr( "aria-valuemin" )
 439              .removeAttr( "aria-valuemax" )
 440              .removeAttr( "aria-valuenow" );
 441          this.uiSpinner.replaceWith( this.element );
 442      },
 443  
 444      stepUp: modifier(function( steps ) {
 445          this._stepUp( steps );
 446      }),
 447      _stepUp: function( steps ) {
 448          this._spin( (steps || 1) * this.options.step );
 449      },
 450  
 451      stepDown: modifier(function( steps ) {
 452          this._stepDown( steps );
 453      }),
 454      _stepDown: function( steps ) {
 455          this._spin( (steps || 1) * -this.options.step );
 456      },
 457  
 458      pageUp: modifier(function( pages ) {
 459          this._stepUp( (pages || 1) * this.options.page );
 460      }),
 461  
 462      pageDown: modifier(function( pages ) {
 463          this._stepDown( (pages || 1) * this.options.page );
 464      }),
 465  
 466      value: function( newVal ) {
 467          if ( !arguments.length ) {
 468              return this._parse( this.element.val() );
 469          }
 470          modifier( this._value ).call( this, newVal );
 471      },
 472  
 473      widget: function() {
 474          return this.uiSpinner;
 475      }
 476  });
 477  
 478  }( jQuery ) );


Generated: Fri Nov 28 14:03:12 2014 Cross-referenced by PHPXref 0.7.1