/[projects]/misc/horsensspejder-web/jquery/jquery-ui-1.10.3/ui/jquery.ui.spinner.js
ViewVC logotype

Contents of /misc/horsensspejder-web/jquery/jquery-ui-1.10.3/ui/jquery.ui.spinner.js

Parent Directory Parent Directory | Revision Log Revision Log


Revision 2125 - (show annotations) (download) (as text)
Wed Mar 12 19:30:05 2014 UTC (10 years, 3 months ago) by torben
File MIME type: application/javascript
File size: 12377 byte(s)
initial import
1 /*!
2 * jQuery UI Spinner 1.10.3
3 * http://jqueryui.com
4 *
5 * Copyright 2013 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.10.3",
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._stop();
106 this._refresh();
107 if ( this.previous !== this.element.val() ) {
108 this._trigger( "change", event );
109 }
110 },
111 mousewheel: function( event, delta ) {
112 if ( !delta ) {
113 return;
114 }
115 if ( !this.spinning && !this._start( event ) ) {
116 return false;
117 }
118
119 this._spin( (delta > 0 ? 1 : -1) * this.options.step, event );
120 clearTimeout( this.mousewheelTimer );
121 this.mousewheelTimer = this._delay(function() {
122 if ( this.spinning ) {
123 this._stop( event );
124 }
125 }, 100 );
126 event.preventDefault();
127 },
128 "mousedown .ui-spinner-button": function( event ) {
129 var previous;
130
131 // We never want the buttons to have focus; whenever the user is
132 // interacting with the spinner, the focus should be on the input.
133 // If the input is focused then this.previous is properly set from
134 // when the input first received focus. If the input is not focused
135 // then we need to set this.previous based on the value before spinning.
136 previous = this.element[0] === this.document[0].activeElement ?
137 this.previous : this.element.val();
138 function checkFocus() {
139 var isActive = this.element[0] === this.document[0].activeElement;
140 if ( !isActive ) {
141 this.element.focus();
142 this.previous = previous;
143 // support: IE
144 // IE sets focus asynchronously, so we need to check if focus
145 // moved off of the input because the user clicked on the button.
146 this._delay(function() {
147 this.previous = previous;
148 });
149 }
150 }
151
152 // ensure focus is on (or stays on) the text field
153 event.preventDefault();
154 checkFocus.call( this );
155
156 // support: IE
157 // IE doesn't prevent moving focus even with event.preventDefault()
158 // so we set a flag to know when we should ignore the blur event
159 // and check (again) if focus moved off of the input.
160 this.cancelBlur = true;
161 this._delay(function() {
162 delete this.cancelBlur;
163 checkFocus.call( this );
164 });
165
166 if ( this._start( event ) === false ) {
167 return;
168 }
169
170 this._repeat( null, $( event.currentTarget ).hasClass( "ui-spinner-up" ) ? 1 : -1, event );
171 },
172 "mouseup .ui-spinner-button": "_stop",
173 "mouseenter .ui-spinner-button": function( event ) {
174 // button will add ui-state-active if mouse was down while mouseleave and kept down
175 if ( !$( event.currentTarget ).hasClass( "ui-state-active" ) ) {
176 return;
177 }
178
179 if ( this._start( event ) === false ) {
180 return false;
181 }
182 this._repeat( null, $( event.currentTarget ).hasClass( "ui-spinner-up" ) ? 1 : -1, event );
183 },
184 // TODO: do we really want to consider this a stop?
185 // shouldn't we just stop the repeater and wait until mouseup before
186 // we trigger the stop event?
187 "mouseleave .ui-spinner-button": "_stop"
188 },
189
190 _draw: function() {
191 var uiSpinner = this.uiSpinner = this.element
192 .addClass( "ui-spinner-input" )
193 .attr( "autocomplete", "off" )
194 .wrap( this._uiSpinnerHtml() )
195 .parent()
196 // add buttons
197 .append( this._buttonHtml() );
198
199 this.element.attr( "role", "spinbutton" );
200
201 // button bindings
202 this.buttons = uiSpinner.find( ".ui-spinner-button" )
203 .attr( "tabIndex", -1 )
204 .button()
205 .removeClass( "ui-corner-all" );
206
207 // IE 6 doesn't understand height: 50% for the buttons
208 // unless the wrapper has an explicit height
209 if ( this.buttons.height() > Math.ceil( uiSpinner.height() * 0.5 ) &&
210 uiSpinner.height() > 0 ) {
211 uiSpinner.height( uiSpinner.height() );
212 }
213
214 // disable spinner if element was already disabled
215 if ( this.options.disabled ) {
216 this.disable();
217 }
218 },
219
220 _keydown: function( event ) {
221 var options = this.options,
222 keyCode = $.ui.keyCode;
223
224 switch ( event.keyCode ) {
225 case keyCode.UP:
226 this._repeat( null, 1, event );
227 return true;
228 case keyCode.DOWN:
229 this._repeat( null, -1, event );
230 return true;
231 case keyCode.PAGE_UP:
232 this._repeat( null, options.page, event );
233 return true;
234 case keyCode.PAGE_DOWN:
235 this._repeat( null, -options.page, event );
236 return true;
237 }
238
239 return false;
240 },
241
242 _uiSpinnerHtml: function() {
243 return "<span class='ui-spinner ui-widget ui-widget-content ui-corner-all'></span>";
244 },
245
246 _buttonHtml: function() {
247 return "" +
248 "<a class='ui-spinner-button ui-spinner-up ui-corner-tr'>" +
249 "<span class='ui-icon " + this.options.icons.up + "'>&#9650;</span>" +
250 "</a>" +
251 "<a class='ui-spinner-button ui-spinner-down ui-corner-br'>" +
252 "<span class='ui-icon " + this.options.icons.down + "'>&#9660;</span>" +
253 "</a>";
254 },
255
256 _start: function( event ) {
257 if ( !this.spinning && this._trigger( "start", event ) === false ) {
258 return false;
259 }
260
261 if ( !this.counter ) {
262 this.counter = 1;
263 }
264 this.spinning = true;
265 return true;
266 },
267
268 _repeat: function( i, steps, event ) {
269 i = i || 500;
270
271 clearTimeout( this.timer );
272 this.timer = this._delay(function() {
273 this._repeat( 40, steps, event );
274 }, i );
275
276 this._spin( steps * this.options.step, event );
277 },
278
279 _spin: function( step, event ) {
280 var value = this.value() || 0;
281
282 if ( !this.counter ) {
283 this.counter = 1;
284 }
285
286 value = this._adjustValue( value + step * this._increment( this.counter ) );
287
288 if ( !this.spinning || this._trigger( "spin", event, { value: value } ) !== false) {
289 this._value( value );
290 this.counter++;
291 }
292 },
293
294 _increment: function( i ) {
295 var incremental = this.options.incremental;
296
297 if ( incremental ) {
298 return $.isFunction( incremental ) ?
299 incremental( i ) :
300 Math.floor( i*i*i/50000 - i*i/500 + 17*i/200 + 1 );
301 }
302
303 return 1;
304 },
305
306 _precision: function() {
307 var precision = this._precisionOf( this.options.step );
308 if ( this.options.min !== null ) {
309 precision = Math.max( precision, this._precisionOf( this.options.min ) );
310 }
311 return precision;
312 },
313
314 _precisionOf: function( num ) {
315 var str = num.toString(),
316 decimal = str.indexOf( "." );
317 return decimal === -1 ? 0 : str.length - decimal - 1;
318 },
319
320 _adjustValue: function( value ) {
321 var base, aboveMin,
322 options = this.options;
323
324 // make sure we're at a valid step
325 // - find out where we are relative to the base (min or 0)
326 base = options.min !== null ? options.min : 0;
327 aboveMin = value - base;
328 // - round to the nearest step
329 aboveMin = Math.round(aboveMin / options.step) * options.step;
330 // - rounding is based on 0, so adjust back to our base
331 value = base + aboveMin;
332
333 // fix precision from bad JS floating point math
334 value = parseFloat( value.toFixed( this._precision() ) );
335
336 // clamp the value
337 if ( options.max !== null && value > options.max) {
338 return options.max;
339 }
340 if ( options.min !== null && value < options.min ) {
341 return options.min;
342 }
343
344 return value;
345 },
346
347 _stop: function( event ) {
348 if ( !this.spinning ) {
349 return;
350 }
351
352 clearTimeout( this.timer );
353 clearTimeout( this.mousewheelTimer );
354 this.counter = 0;
355 this.spinning = false;
356 this._trigger( "stop", event );
357 },
358
359 _setOption: function( key, value ) {
360 if ( key === "culture" || key === "numberFormat" ) {
361 var prevValue = this._parse( this.element.val() );
362 this.options[ key ] = value;
363 this.element.val( this._format( prevValue ) );
364 return;
365 }
366
367 if ( key === "max" || key === "min" || key === "step" ) {
368 if ( typeof value === "string" ) {
369 value = this._parse( value );
370 }
371 }
372 if ( key === "icons" ) {
373 this.buttons.first().find( ".ui-icon" )
374 .removeClass( this.options.icons.up )
375 .addClass( value.up );
376 this.buttons.last().find( ".ui-icon" )
377 .removeClass( this.options.icons.down )
378 .addClass( value.down );
379 }
380
381 this._super( key, value );
382
383 if ( key === "disabled" ) {
384 if ( value ) {
385 this.element.prop( "disabled", true );
386 this.buttons.button( "disable" );
387 } else {
388 this.element.prop( "disabled", false );
389 this.buttons.button( "enable" );
390 }
391 }
392 },
393
394 _setOptions: modifier(function( options ) {
395 this._super( options );
396 this._value( this.element.val() );
397 }),
398
399 _parse: function( val ) {
400 if ( typeof val === "string" && val !== "" ) {
401 val = window.Globalize && this.options.numberFormat ?
402 Globalize.parseFloat( val, 10, this.options.culture ) : +val;
403 }
404 return val === "" || isNaN( val ) ? null : val;
405 },
406
407 _format: function( value ) {
408 if ( value === "" ) {
409 return "";
410 }
411 return window.Globalize && this.options.numberFormat ?
412 Globalize.format( value, this.options.numberFormat, this.options.culture ) :
413 value;
414 },
415
416 _refresh: function() {
417 this.element.attr({
418 "aria-valuemin": this.options.min,
419 "aria-valuemax": this.options.max,
420 // TODO: what should we do with values that can't be parsed?
421 "aria-valuenow": this._parse( this.element.val() )
422 });
423 },
424
425 // update the value without triggering change
426 _value: function( value, allowAny ) {
427 var parsed;
428 if ( value !== "" ) {
429 parsed = this._parse( value );
430 if ( parsed !== null ) {
431 if ( !allowAny ) {
432 parsed = this._adjustValue( parsed );
433 }
434 value = this._format( parsed );
435 }
436 }
437 this.element.val( value );
438 this._refresh();
439 },
440
441 _destroy: function() {
442 this.element
443 .removeClass( "ui-spinner-input" )
444 .prop( "disabled", false )
445 .removeAttr( "autocomplete" )
446 .removeAttr( "role" )
447 .removeAttr( "aria-valuemin" )
448 .removeAttr( "aria-valuemax" )
449 .removeAttr( "aria-valuenow" );
450 this.uiSpinner.replaceWith( this.element );
451 },
452
453 stepUp: modifier(function( steps ) {
454 this._stepUp( steps );
455 }),
456 _stepUp: function( steps ) {
457 if ( this._start() ) {
458 this._spin( (steps || 1) * this.options.step );
459 this._stop();
460 }
461 },
462
463 stepDown: modifier(function( steps ) {
464 this._stepDown( steps );
465 }),
466 _stepDown: function( steps ) {
467 if ( this._start() ) {
468 this._spin( (steps || 1) * -this.options.step );
469 this._stop();
470 }
471 },
472
473 pageUp: modifier(function( pages ) {
474 this._stepUp( (pages || 1) * this.options.page );
475 }),
476
477 pageDown: modifier(function( pages ) {
478 this._stepDown( (pages || 1) * this.options.page );
479 }),
480
481 value: function( newVal ) {
482 if ( !arguments.length ) {
483 return this._parse( this.element.val() );
484 }
485 modifier( this._value ).call( this, newVal );
486 },
487
488 widget: function() {
489 return this.uiSpinner;
490 }
491 });
492
493 }( jQuery ) );

  ViewVC Help
Powered by ViewVC 1.1.20