[ Index ] |
PHP Cross Reference of WordPress |
[Summary view] [Print] [Text view]
1 /*! 2 * jQuery UI Spinner 1.13.1 3 * http://jqueryui.com 4 * 5 * Copyright jQuery Foundation and other contributors 6 * Released under the MIT license. 7 * http://jquery.org/license 8 */ 9 10 //>>label: Spinner 11 //>>group: Widgets 12 //>>description: Displays buttons to easily input numbers via the keyboard or mouse. 13 //>>docs: http://api.jqueryui.com/spinner/ 14 //>>demos: http://jqueryui.com/spinner/ 15 //>>css.structure: ../../themes/base/core.css 16 //>>css.structure: ../../themes/base/spinner.css 17 //>>css.theme: ../../themes/base/theme.css 18 19 ( function( factory ) { 20 "use strict"; 21 22 if ( typeof define === "function" && define.amd ) { 23 24 // AMD. Register as an anonymous module. 25 define( [ 26 "jquery", 27 "./button", 28 "./core" 29 ], factory ); 30 } else { 31 32 // Browser globals 33 factory( jQuery ); 34 } 35 } )( function( $ ) { 36 "use strict"; 37 38 function spinnerModifier( fn ) { 39 return function() { 40 var previous = this.element.val(); 41 fn.apply( this, arguments ); 42 this._refresh(); 43 if ( previous !== this.element.val() ) { 44 this._trigger( "change" ); 45 } 46 }; 47 } 48 49 $.widget( "ui.spinner", { 50 version: "1.13.1", 51 defaultElement: "<input>", 52 widgetEventPrefix: "spin", 53 options: { 54 classes: { 55 "ui-spinner": "ui-corner-all", 56 "ui-spinner-down": "ui-corner-br", 57 "ui-spinner-up": "ui-corner-tr" 58 }, 59 culture: null, 60 icons: { 61 down: "ui-icon-triangle-1-s", 62 up: "ui-icon-triangle-1-n" 63 }, 64 incremental: true, 65 max: null, 66 min: null, 67 numberFormat: null, 68 page: 10, 69 step: 1, 70 71 change: null, 72 spin: null, 73 start: null, 74 stop: null 75 }, 76 77 _create: function() { 78 79 // handle string values that need to be parsed 80 this._setOption( "max", this.options.max ); 81 this._setOption( "min", this.options.min ); 82 this._setOption( "step", this.options.step ); 83 84 // Only format if there is a value, prevents the field from being marked 85 // as invalid in Firefox, see #9573. 86 if ( this.value() !== "" ) { 87 88 // Format the value, but don't constrain. 89 this._value( this.element.val(), true ); 90 } 91 92 this._draw(); 93 this._on( this._events ); 94 this._refresh(); 95 96 // Turning off autocomplete prevents the browser from remembering the 97 // value when navigating through history, so we re-enable autocomplete 98 // if the page is unloaded before the widget is destroyed. #7790 99 this._on( this.window, { 100 beforeunload: function() { 101 this.element.removeAttr( "autocomplete" ); 102 } 103 } ); 104 }, 105 106 _getCreateOptions: function() { 107 var options = this._super(); 108 var element = this.element; 109 110 $.each( [ "min", "max", "step" ], function( i, option ) { 111 var value = element.attr( option ); 112 if ( value != null && value.length ) { 113 options[ option ] = value; 114 } 115 } ); 116 117 return options; 118 }, 119 120 _events: { 121 keydown: function( event ) { 122 if ( this._start( event ) && this._keydown( event ) ) { 123 event.preventDefault(); 124 } 125 }, 126 keyup: "_stop", 127 focus: function() { 128 this.previous = this.element.val(); 129 }, 130 blur: function( event ) { 131 if ( this.cancelBlur ) { 132 delete this.cancelBlur; 133 return; 134 } 135 136 this._stop(); 137 this._refresh(); 138 if ( this.previous !== this.element.val() ) { 139 this._trigger( "change", event ); 140 } 141 }, 142 mousewheel: function( event, delta ) { 143 var activeElement = $.ui.safeActiveElement( this.document[ 0 ] ); 144 var isActive = this.element[ 0 ] === activeElement; 145 146 if ( !isActive || !delta ) { 147 return; 148 } 149 150 if ( !this.spinning && !this._start( event ) ) { 151 return false; 152 } 153 154 this._spin( ( delta > 0 ? 1 : -1 ) * this.options.step, event ); 155 clearTimeout( this.mousewheelTimer ); 156 this.mousewheelTimer = this._delay( function() { 157 if ( this.spinning ) { 158 this._stop( event ); 159 } 160 }, 100 ); 161 event.preventDefault(); 162 }, 163 "mousedown .ui-spinner-button": function( event ) { 164 var previous; 165 166 // We never want the buttons to have focus; whenever the user is 167 // interacting with the spinner, the focus should be on the input. 168 // If the input is focused then this.previous is properly set from 169 // when the input first received focus. If the input is not focused 170 // then we need to set this.previous based on the value before spinning. 171 previous = this.element[ 0 ] === $.ui.safeActiveElement( this.document[ 0 ] ) ? 172 this.previous : this.element.val(); 173 function checkFocus() { 174 var isActive = this.element[ 0 ] === $.ui.safeActiveElement( this.document[ 0 ] ); 175 if ( !isActive ) { 176 this.element.trigger( "focus" ); 177 this.previous = previous; 178 179 // support: IE 180 // IE sets focus asynchronously, so we need to check if focus 181 // moved off of the input because the user clicked on the button. 182 this._delay( function() { 183 this.previous = previous; 184 } ); 185 } 186 } 187 188 // Ensure focus is on (or stays on) the text field 189 event.preventDefault(); 190 checkFocus.call( this ); 191 192 // Support: IE 193 // IE doesn't prevent moving focus even with event.preventDefault() 194 // so we set a flag to know when we should ignore the blur event 195 // and check (again) if focus moved off of the input. 196 this.cancelBlur = true; 197 this._delay( function() { 198 delete this.cancelBlur; 199 checkFocus.call( this ); 200 } ); 201 202 if ( this._start( event ) === false ) { 203 return; 204 } 205 206 this._repeat( null, $( event.currentTarget ) 207 .hasClass( "ui-spinner-up" ) ? 1 : -1, event ); 208 }, 209 "mouseup .ui-spinner-button": "_stop", 210 "mouseenter .ui-spinner-button": function( event ) { 211 212 // button will add ui-state-active if mouse was down while mouseleave and kept down 213 if ( !$( event.currentTarget ).hasClass( "ui-state-active" ) ) { 214 return; 215 } 216 217 if ( this._start( event ) === false ) { 218 return false; 219 } 220 this._repeat( null, $( event.currentTarget ) 221 .hasClass( "ui-spinner-up" ) ? 1 : -1, event ); 222 }, 223 224 // TODO: do we really want to consider this a stop? 225 // shouldn't we just stop the repeater and wait until mouseup before 226 // we trigger the stop event? 227 "mouseleave .ui-spinner-button": "_stop" 228 }, 229 230 // Support mobile enhanced option and make backcompat more sane 231 _enhance: function() { 232 this.uiSpinner = this.element 233 .attr( "autocomplete", "off" ) 234 .wrap( "<span>" ) 235 .parent() 236 237 // Add buttons 238 .append( 239 "<a></a><a></a>" 240 ); 241 }, 242 243 _draw: function() { 244 this._enhance(); 245 246 this._addClass( this.uiSpinner, "ui-spinner", "ui-widget ui-widget-content" ); 247 this._addClass( "ui-spinner-input" ); 248 249 this.element.attr( "role", "spinbutton" ); 250 251 // Button bindings 252 this.buttons = this.uiSpinner.children( "a" ) 253 .attr( "tabIndex", -1 ) 254 .attr( "aria-hidden", true ) 255 .button( { 256 classes: { 257 "ui-button": "" 258 } 259 } ); 260 261 // TODO: Right now button does not support classes this is already updated in button PR 262 this._removeClass( this.buttons, "ui-corner-all" ); 263 264 this._addClass( this.buttons.first(), "ui-spinner-button ui-spinner-up" ); 265 this._addClass( this.buttons.last(), "ui-spinner-button ui-spinner-down" ); 266 this.buttons.first().button( { 267 "icon": this.options.icons.up, 268 "showLabel": false 269 } ); 270 this.buttons.last().button( { 271 "icon": this.options.icons.down, 272 "showLabel": false 273 } ); 274 275 // IE 6 doesn't understand height: 50% for the buttons 276 // unless the wrapper has an explicit height 277 if ( this.buttons.height() > Math.ceil( this.uiSpinner.height() * 0.5 ) && 278 this.uiSpinner.height() > 0 ) { 279 this.uiSpinner.height( this.uiSpinner.height() ); 280 } 281 }, 282 283 _keydown: function( event ) { 284 var options = this.options, 285 keyCode = $.ui.keyCode; 286 287 switch ( event.keyCode ) { 288 case keyCode.UP: 289 this._repeat( null, 1, event ); 290 return true; 291 case keyCode.DOWN: 292 this._repeat( null, -1, event ); 293 return true; 294 case keyCode.PAGE_UP: 295 this._repeat( null, options.page, event ); 296 return true; 297 case keyCode.PAGE_DOWN: 298 this._repeat( null, -options.page, event ); 299 return true; 300 } 301 302 return false; 303 }, 304 305 _start: function( event ) { 306 if ( !this.spinning && this._trigger( "start", event ) === false ) { 307 return false; 308 } 309 310 if ( !this.counter ) { 311 this.counter = 1; 312 } 313 this.spinning = true; 314 return true; 315 }, 316 317 _repeat: function( i, steps, event ) { 318 i = i || 500; 319 320 clearTimeout( this.timer ); 321 this.timer = this._delay( function() { 322 this._repeat( 40, steps, event ); 323 }, i ); 324 325 this._spin( steps * this.options.step, event ); 326 }, 327 328 _spin: function( step, event ) { 329 var value = this.value() || 0; 330 331 if ( !this.counter ) { 332 this.counter = 1; 333 } 334 335 value = this._adjustValue( value + step * this._increment( this.counter ) ); 336 337 if ( !this.spinning || this._trigger( "spin", event, { value: value } ) !== false ) { 338 this._value( value ); 339 this.counter++; 340 } 341 }, 342 343 _increment: function( i ) { 344 var incremental = this.options.incremental; 345 346 if ( incremental ) { 347 return typeof incremental === "function" ? 348 incremental( i ) : 349 Math.floor( i * i * i / 50000 - i * i / 500 + 17 * i / 200 + 1 ); 350 } 351 352 return 1; 353 }, 354 355 _precision: function() { 356 var precision = this._precisionOf( this.options.step ); 357 if ( this.options.min !== null ) { 358 precision = Math.max( precision, this._precisionOf( this.options.min ) ); 359 } 360 return precision; 361 }, 362 363 _precisionOf: function( num ) { 364 var str = num.toString(), 365 decimal = str.indexOf( "." ); 366 return decimal === -1 ? 0 : str.length - decimal - 1; 367 }, 368 369 _adjustValue: function( value ) { 370 var base, aboveMin, 371 options = this.options; 372 373 // Make sure we're at a valid step 374 // - find out where we are relative to the base (min or 0) 375 base = options.min !== null ? options.min : 0; 376 aboveMin = value - base; 377 378 // - round to the nearest step 379 aboveMin = Math.round( aboveMin / options.step ) * options.step; 380 381 // - rounding is based on 0, so adjust back to our base 382 value = base + aboveMin; 383 384 // Fix precision from bad JS floating point math 385 value = parseFloat( value.toFixed( this._precision() ) ); 386 387 // Clamp the value 388 if ( options.max !== null && value > options.max ) { 389 return options.max; 390 } 391 if ( options.min !== null && value < options.min ) { 392 return options.min; 393 } 394 395 return value; 396 }, 397 398 _stop: function( event ) { 399 if ( !this.spinning ) { 400 return; 401 } 402 403 clearTimeout( this.timer ); 404 clearTimeout( this.mousewheelTimer ); 405 this.counter = 0; 406 this.spinning = false; 407 this._trigger( "stop", event ); 408 }, 409 410 _setOption: function( key, value ) { 411 var prevValue, first, last; 412 413 if ( key === "culture" || key === "numberFormat" ) { 414 prevValue = this._parse( this.element.val() ); 415 this.options[ key ] = value; 416 this.element.val( this._format( prevValue ) ); 417 return; 418 } 419 420 if ( key === "max" || key === "min" || key === "step" ) { 421 if ( typeof value === "string" ) { 422 value = this._parse( value ); 423 } 424 } 425 if ( key === "icons" ) { 426 first = this.buttons.first().find( ".ui-icon" ); 427 this._removeClass( first, null, this.options.icons.up ); 428 this._addClass( first, null, value.up ); 429 last = this.buttons.last().find( ".ui-icon" ); 430 this._removeClass( last, null, this.options.icons.down ); 431 this._addClass( last, null, value.down ); 432 } 433 434 this._super( key, value ); 435 }, 436 437 _setOptionDisabled: function( value ) { 438 this._super( value ); 439 440 this._toggleClass( this.uiSpinner, null, "ui-state-disabled", !!value ); 441 this.element.prop( "disabled", !!value ); 442 this.buttons.button( value ? "disable" : "enable" ); 443 }, 444 445 _setOptions: spinnerModifier( function( options ) { 446 this._super( options ); 447 } ), 448 449 _parse: function( val ) { 450 if ( typeof val === "string" && val !== "" ) { 451 val = window.Globalize && this.options.numberFormat ? 452 Globalize.parseFloat( val, 10, this.options.culture ) : +val; 453 } 454 return val === "" || isNaN( val ) ? null : val; 455 }, 456 457 _format: function( value ) { 458 if ( value === "" ) { 459 return ""; 460 } 461 return window.Globalize && this.options.numberFormat ? 462 Globalize.format( value, this.options.numberFormat, this.options.culture ) : 463 value; 464 }, 465 466 _refresh: function() { 467 this.element.attr( { 468 "aria-valuemin": this.options.min, 469 "aria-valuemax": this.options.max, 470 471 // TODO: what should we do with values that can't be parsed? 472 "aria-valuenow": this._parse( this.element.val() ) 473 } ); 474 }, 475 476 isValid: function() { 477 var value = this.value(); 478 479 // Null is invalid 480 if ( value === null ) { 481 return false; 482 } 483 484 // If value gets adjusted, it's invalid 485 return value === this._adjustValue( value ); 486 }, 487 488 // Update the value without triggering change 489 _value: function( value, allowAny ) { 490 var parsed; 491 if ( value !== "" ) { 492 parsed = this._parse( value ); 493 if ( parsed !== null ) { 494 if ( !allowAny ) { 495 parsed = this._adjustValue( parsed ); 496 } 497 value = this._format( parsed ); 498 } 499 } 500 this.element.val( value ); 501 this._refresh(); 502 }, 503 504 _destroy: function() { 505 this.element 506 .prop( "disabled", false ) 507 .removeAttr( "autocomplete role aria-valuemin aria-valuemax aria-valuenow" ); 508 509 this.uiSpinner.replaceWith( this.element ); 510 }, 511 512 stepUp: spinnerModifier( function( steps ) { 513 this._stepUp( steps ); 514 } ), 515 _stepUp: function( steps ) { 516 if ( this._start() ) { 517 this._spin( ( steps || 1 ) * this.options.step ); 518 this._stop(); 519 } 520 }, 521 522 stepDown: spinnerModifier( function( steps ) { 523 this._stepDown( steps ); 524 } ), 525 _stepDown: function( steps ) { 526 if ( this._start() ) { 527 this._spin( ( steps || 1 ) * -this.options.step ); 528 this._stop(); 529 } 530 }, 531 532 pageUp: spinnerModifier( function( pages ) { 533 this._stepUp( ( pages || 1 ) * this.options.page ); 534 } ), 535 536 pageDown: spinnerModifier( function( pages ) { 537 this._stepDown( ( pages || 1 ) * this.options.page ); 538 } ), 539 540 value: function( newVal ) { 541 if ( !arguments.length ) { 542 return this._parse( this.element.val() ); 543 } 544 spinnerModifier( this._value ).call( this, newVal ); 545 }, 546 547 widget: function() { 548 return this.uiSpinner; 549 } 550 } ); 551 552 // DEPRECATED 553 // TODO: switch return back to widget declaration at top of file when this is removed 554 if ( $.uiBackCompat !== false ) { 555 556 // Backcompat for spinner html extension points 557 $.widget( "ui.spinner", $.ui.spinner, { 558 _enhance: function() { 559 this.uiSpinner = this.element 560 .attr( "autocomplete", "off" ) 561 .wrap( this._uiSpinnerHtml() ) 562 .parent() 563 564 // Add buttons 565 .append( this._buttonHtml() ); 566 }, 567 _uiSpinnerHtml: function() { 568 return "<span>"; 569 }, 570 571 _buttonHtml: function() { 572 return "<a></a><a></a>"; 573 } 574 } ); 575 } 576 577 return $.ui.spinner; 578 579 } );
title
Description
Body
title
Description
Body
title
Description
Body
title
Body
Generated: Thu Nov 21 01:00:03 2024 | Cross-referenced by PHPXref 0.7.1 |