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