major updates to slice reservation page and plugins
[myslice.git] / third-party / bootstrap-slider-1 / bootstrap-slider.js
1 /* =========================================================
2  * bootstrap-slider.js v3.0.0
3  * =========================================================
4  *
5  * Licensed under the Apache License, Version 2.0 (the "License");
6  * you may not use this file except in compliance with the License.
7  * You may obtain a copy of the License at
8  *
9  * http://www.apache.org/licenses/LICENSE-2.0
10  *
11  * Unless required by applicable law or agreed to in writing, software
12  * distributed under the License is distributed on an "AS IS" BASIS,
13  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14  * See the License for the specific language governing permissions and
15  * limitations under the License.
16  * ========================================================= */
17
18 (function( $ ) {
19
20         var ErrorMsgs = {
21                 formatInvalidInputErrorMsg : function(input) {
22                         return "Invalid input value '" + input + "' passed in";
23                 },
24                 callingContextNotSliderInstance : "Calling context element does not have instance of Slider bound to it. Check your code to make sure the JQuery object returned from the call to the slider() initializer is calling the method"
25         };
26
27         var Slider = function(element, options) {
28                 var el = this.element = $(element).hide();
29                 var origWidth =  $(element)[0].style.width;
30
31                 var updateSlider = false;
32                 var parent = this.element.parent();
33
34
35                 if (parent.hasClass('slider') === true) {
36                         updateSlider = true;
37                         this.picker = parent;
38                 } else {
39                         this.picker = $('<div class="slider">'+
40                                                                 '<div class="slider-track">'+
41                                                                         '<div class="slider-selection"></div>'+
42                                                                         '<div class="slider-handle min-slider-handle"></div>'+
43                                                                         '<div class="slider-handle max-slider-handle"></div>'+
44                                                                 '</div>'+
45                                                                 '<div id="tooltip" class="tooltip"><div class="tooltip-arrow"></div><div class="tooltip-inner"></div></div>'+
46                                                                 '<div id="tooltip_min" class="tooltip"><div class="tooltip-arrow"></div><div class="tooltip-inner"></div></div>'+
47                                                                 '<div id="tooltip_max" class="tooltip"><div class="tooltip-arrow"></div><div class="tooltip-inner"></div></div>'+
48                                                         '</div>')
49                                                                 .insertBefore(this.element)
50                                                                 .append(this.element);
51                 }
52
53                 this.id = this.element.data('slider-id')||options.id;
54                 if (this.id) {
55                         this.picker[0].id = this.id;
56                 }
57
58                 if (('ontouchstart' in window) || window.DocumentTouch && document instanceof window.DocumentTouch) {
59                         this.touchCapable = true;
60                 }
61
62                 var tooltip = this.element.data('slider-tooltip')||options.tooltip;
63
64                 this.tooltip = this.picker.find('#tooltip');
65                 this.tooltipInner = this.tooltip.find('div.tooltip-inner');
66
67                 this.tooltip_min = this.picker.find('#tooltip_min');
68                 this.tooltipInner_min = this.tooltip_min.find('div.tooltip-inner');
69
70                 this.tooltip_max = this.picker.find('#tooltip_max');
71                 this.tooltipInner_max= this.tooltip_max.find('div.tooltip-inner');
72
73                 if (updateSlider === true) {
74                         // Reset classes
75                         this.picker.removeClass('slider-horizontal');
76                         this.picker.removeClass('slider-vertical');
77                         this.tooltip.removeClass('hide');
78                         this.tooltip_min.removeClass('hide');
79                         this.tooltip_max.removeClass('hide');
80
81                 }
82
83                 this.orientation = this.element.data('slider-orientation')||options.orientation;
84                 switch(this.orientation) {
85                         case 'vertical':
86                                 this.picker.addClass('slider-vertical');
87                                 this.stylePos = 'top';
88                                 this.mousePos = 'pageY';
89                                 this.sizePos = 'offsetHeight';
90                                 this.tooltip.addClass('right')[0].style.left = '100%';
91                                 this.tooltip_min.addClass('right')[0].style.left = '100%';
92                                 this.tooltip_max.addClass('right')[0].style.left = '100%';
93                                 break;
94                         default:
95                                 this.picker
96                                         .addClass('slider-horizontal')
97                                         .css('width', origWidth);
98                                 this.orientation = 'horizontal';
99                                 this.stylePos = 'left';
100                                 this.mousePos = 'pageX';
101                                 this.sizePos = 'offsetWidth';
102                                 this.tooltip.addClass('top')[0].style.top = -this.tooltip.outerHeight() - 14 + 'px';
103                                 this.tooltip_min.addClass('top')[0].style.top = -this.tooltip_min.outerHeight() - 14 + 'px';
104                                 this.tooltip_max.addClass('top')[0].style.top = -this.tooltip_max.outerHeight() - 14 + 'px';
105                                 break;
106                 }
107
108                 var self = this;
109                 $.each(['min',
110                                 'max',
111                                 'step',
112                                 'precision',
113                                 'value',
114                                 'reversed',
115                                 'handle'
116                         ], function(i, attr) {
117                                 if (typeof el.data('slider-' + attr) !== 'undefined') {
118                                         self[attr] = el.data('slider-' + attr);
119                                 } else if (typeof options[attr] !== 'undefined') {
120                                         self[attr] = options[attr];
121                                 } else if (typeof el.prop(attr) !== 'undefined') {
122                                         self[attr] = el.prop(attr);
123                                 } else {
124                                         self[attr] = 0; // to prevent empty string issues in calculations in IE
125                                 }
126                 });
127
128                 if (this.value instanceof Array) {
129                         if (updateSlider && !this.range) {
130                                 this.value = this.value[0];
131                         } else {
132                                 this.range = true;
133                         }
134                 } else if (this.range) {
135                         // User wants a range, but value is not an array
136                         this.value = [this.value, this.max];
137                 }
138
139                 this.selection = this.element.data('slider-selection')||options.selection;
140                 this.selectionEl = this.picker.find('.slider-selection');
141                 if (this.selection === 'none') {
142                         this.selectionEl.addClass('hide');
143                 }
144
145                 this.selectionElStyle = this.selectionEl[0].style;
146
147                 this.handle1 = this.picker.find('.slider-handle:first');
148                 this.handle1Stype = this.handle1[0].style;
149
150                 this.handle2 = this.picker.find('.slider-handle:last');
151                 this.handle2Stype = this.handle2[0].style;
152
153                 if (updateSlider === true) {
154                         // Reset classes
155                         this.handle1.removeClass('round triangle');
156                         this.handle2.removeClass('round triangle hide');
157                 }
158
159                 var availableHandleModifiers = ['round', 'triangle', 'custom'];
160                 if (availableHandleModifiers.indexOf(this.handle) !== -1){
161                         this.handle1.addClass(this.handle);
162                         this.handle2.addClass(this.handle);
163                 }
164
165                 this.offset = this.picker.offset();
166                 this.size = this.picker[0][this.sizePos];
167                 this.formater = options.formater;
168                 
169                 this.tooltip_separator = options.tooltip_separator;
170                 this.tooltip_split = options.tooltip_split;
171
172                 this.setValue(this.value);
173
174                 this.handle1.on({
175                         keydown: $.proxy(this.keydown, this, 0)
176                 });
177                 this.handle2.on({
178                         keydown: $.proxy(this.keydown, this, 1)
179                 });
180
181                 if (this.touchCapable) {
182                         // Touch: Bind touch events:
183                         this.picker.on({
184                                 touchstart: $.proxy(this.mousedown, this)
185                         });
186                 }
187                 // Bind mouse events:
188                 this.picker.on({
189                         mousedown: $.proxy(this.mousedown, this)
190                 });
191
192                 if(tooltip === 'hide') {
193                         this.tooltip.addClass('hide');
194                         this.tooltip_min.addClass('hide');
195                         this.tooltip_max.addClass('hide');
196                 } else if(tooltip === 'always') {
197                         this.showTooltip();
198                         this.alwaysShowTooltip = true;
199                 } else {
200                         this.picker.on({
201                                 mouseenter: $.proxy(this.showTooltip, this),
202                                 mouseleave: $.proxy(this.hideTooltip, this)
203                         });
204                         this.handle1.on({
205                                 focus: $.proxy(this.showTooltip, this),
206                                 blur: $.proxy(this.hideTooltip, this)
207                         });
208                         this.handle2.on({
209                                 focus: $.proxy(this.showTooltip, this),
210                                 blur: $.proxy(this.hideTooltip, this)
211                         });
212                 }
213
214                 this.enabled = options.enabled &&
215                                                 (this.element.data('slider-enabled') === undefined || this.element.data('slider-enabled') === true);
216                 if(this.enabled) {
217                         this.enable();
218                 } else {
219                         this.disable();
220                 }
221                 this.natural_arrow_keys = this.element.data('slider-natural_arrow_keys') || options.natural_arrow_keys;
222         };
223
224         Slider.prototype = {
225                 constructor: Slider,
226
227                 over: false,
228                 inDrag: false,
229
230                 showTooltip: function(){
231             if (this.tooltip_split === false ){
232                 this.tooltip.addClass('in');
233             } else {
234                 this.tooltip_min.addClass('in');
235                 this.tooltip_max.addClass('in');
236             }
237
238                         this.over = true;
239                 },
240
241                 hideTooltip: function(){
242                         if (this.inDrag === false && this.alwaysShowTooltip !== true) {
243                                 this.tooltip.removeClass('in');
244                                 this.tooltip_min.removeClass('in');
245                                 this.tooltip_max.removeClass('in');
246                         }
247                         this.over = false;
248                 },
249
250                 layout: function(){
251                         var positionPercentages;
252
253                         if(this.reversed) {
254                                 positionPercentages = [ 100 - this.percentage[0], this.percentage[1] ];
255                         } else {
256                                 positionPercentages = [ this.percentage[0], this.percentage[1] ];
257                         }
258
259                         this.handle1Stype[this.stylePos] = positionPercentages[0]+'%';
260                         this.handle2Stype[this.stylePos] = positionPercentages[1]+'%';
261
262                         if (this.orientation === 'vertical') {
263                                 this.selectionElStyle.top = Math.min(positionPercentages[0], positionPercentages[1]) +'%';
264                                 this.selectionElStyle.height = Math.abs(positionPercentages[0] - positionPercentages[1]) +'%';
265                         } else {
266                                 this.selectionElStyle.left = Math.min(positionPercentages[0], positionPercentages[1]) +'%';
267                                 this.selectionElStyle.width = Math.abs(positionPercentages[0] - positionPercentages[1]) +'%';
268
269                 var offset_min = this.tooltip_min[0].getBoundingClientRect();
270                 var offset_max = this.tooltip_max[0].getBoundingClientRect();
271
272                 if (offset_min.right > offset_max.left) {
273                     this.tooltip_max.removeClass('top');
274                     this.tooltip_max.addClass('bottom')[0].style.top = 18 + 'px';
275                 } else {
276                     this.tooltip_max.removeClass('bottom');
277                     this.tooltip_max.addClass('top')[0].style.top = -30 + 'px';
278                 }
279                         }
280
281                         if (this.range) {
282                                 this.tooltipInner.text(
283                                         this.formater(this.value[0]) + this.tooltip_separator + this.formater(this.value[1])
284                                 );
285                                 this.tooltip[0].style[this.stylePos] = (positionPercentages[1] + positionPercentages[0])/2 + '%';
286                                 if (this.orientation === 'vertical') {
287                                         this.tooltip.css('margin-top', -this.tooltip.outerHeight() / 2 + 'px');
288                                 } else {
289                                         this.tooltip.css('margin-left', -this.tooltip.outerWidth() / 2 + 'px');
290                                 }
291                                 
292                                 if (this.orientation === 'vertical') {
293                                         this.tooltip.css('margin-top', -this.tooltip.outerHeight() / 2 + 'px');
294                                 } else {
295                                         this.tooltip.css('margin-left', -this.tooltip.outerWidth() / 2 + 'px');
296                                 }
297                                 this.tooltipInner_min.text(
298                                         this.formater(this.value[0])
299                                 );
300                                 this.tooltipInner_max.text(
301                                         this.formater(this.value[1])
302                                 );
303
304                                 this.tooltip_min[0].style[this.stylePos] = positionPercentages[0] + '%';
305                                 if (this.orientation === 'vertical') {
306                                         this.tooltip_min.css('margin-top', -this.tooltip_min.outerHeight() / 2 + 'px');
307                                 } else {
308                                         this.tooltip_min.css('margin-left', -this.tooltip_min.outerWidth() / 2 + 'px');
309                                 }
310                                 this.tooltip_max[0].style[this.stylePos] = positionPercentages[1] + '%';
311                                 if (this.orientation === 'vertical') {
312                                         this.tooltip_max.css('margin-top', -this.tooltip_max.outerHeight() / 2 + 'px');
313                                 } else {
314                                         this.tooltip_max.css('margin-left', -this.tooltip_max.outerWidth() / 2 + 'px');
315                                 }
316                         } else {
317                                 this.tooltipInner.text(
318                                         this.formater(this.value[0])
319                                 );
320                                 this.tooltip[0].style[this.stylePos] = positionPercentages[0] + '%';
321                                 if (this.orientation === 'vertical') {
322                                         this.tooltip.css('margin-top', -this.tooltip.outerHeight() / 2 + 'px');
323                                 } else {
324                                         this.tooltip.css('margin-left', -this.tooltip.outerWidth() / 2 + 'px');
325                                 }
326                         }
327                 },
328
329                 mousedown: function(ev) {
330                         if(!this.isEnabled()) {
331                                 return false;
332                         }
333                         // Touch: Get the original event:
334                         if (this.touchCapable && ev.type === 'touchstart') {
335                                 ev = ev.originalEvent;
336                         }
337
338                         this.triggerFocusOnHandle();
339
340                         this.offset = this.picker.offset();
341                         this.size = this.picker[0][this.sizePos];
342
343                         var percentage = this.getPercentage(ev);
344
345                         if (this.range) {
346                                 var diff1 = Math.abs(this.percentage[0] - percentage);
347                                 var diff2 = Math.abs(this.percentage[1] - percentage);
348                                 this.dragged = (diff1 < diff2) ? 0 : 1;
349                         } else {
350                                 this.dragged = 0;
351                         }
352
353                         this.percentage[this.dragged] = this.reversed ? 100 - percentage : percentage;
354                         this.layout();
355
356                         if (this.touchCapable) {
357                                 // Touch: Bind touch events:
358                                 $(document).on({
359                                         touchmove: $.proxy(this.mousemove, this),
360                                         touchend: $.proxy(this.mouseup, this)
361                                 });
362                         }
363                         // Bind mouse events:
364                         $(document).on({
365                                 mousemove: $.proxy(this.mousemove, this),
366                                 mouseup: $.proxy(this.mouseup, this)
367                         });
368
369                         this.inDrag = true;
370                         var val = this.calculateValue();
371                         this.element.trigger({
372                                         type: 'slideStart',
373                                         value: val
374                                 })
375                                 .data('value', val)
376                                 .prop('value', val);
377                         this.setValue(val);
378                         return true;
379                 },
380
381                 triggerFocusOnHandle: function(handleIdx) {
382                         if(handleIdx === 0) {
383                                 this.handle1.focus();
384                         }
385                         if(handleIdx === 1) {
386                                 this.handle2.focus();
387                         }
388                 },
389
390                 keydown: function(handleIdx, ev) {
391                         if(!this.isEnabled()) {
392                                 return false;
393                         }
394
395                         var dir;
396                         switch (ev.which) {
397                                 case 37: // left
398                                 case 40: // down
399                                         dir = -1;
400                                         break;
401                                 case 39: // right
402                                 case 38: // up
403                                         dir = 1;
404                                         break;
405                         }
406                         if (!dir) {
407                                 return;
408                         }
409
410                         // use natural arrow keys instead of from min to max
411                         if (this.natural_arrow_keys) {
412                                 if ((this.orientation === 'vertical' && !this.reversed) || (this.orientation === 'horizontal' && this.reversed)) {
413                                         dir = dir * -1;
414                                 }
415                         }
416
417                         var oneStepValuePercentageChange = dir * this.percentage[2];
418                         var percentage = this.percentage[handleIdx] + oneStepValuePercentageChange;
419
420                         if (percentage > 100) {
421                                 percentage = 100;
422                         } else if (percentage < 0) {
423                                 percentage = 0;
424                         }
425
426                         this.dragged = handleIdx;
427                         this.adjustPercentageForRangeSliders(percentage);
428                         this.percentage[this.dragged] = percentage;
429                         this.layout();
430
431                         var val = this.calculateValue();
432                         
433                         this.element.trigger({
434                                         type: 'slideStart',
435                                         value: val
436                                 })
437                                 .data('value', val)
438                                 .prop('value', val);
439
440                         this.setValue(val, true);
441
442                         this.element
443                                 .trigger({
444                                         type: 'slideStop',
445                                         value: val
446                                 })
447                                 .data('value', val)
448                                 .prop('value', val);
449                         return false;
450                 },
451
452                 mousemove: function(ev) {
453                         if(!this.isEnabled()) {
454                                 return false;
455                         }
456                         // Touch: Get the original event:
457                         if (this.touchCapable && ev.type === 'touchmove') {
458                                 ev = ev.originalEvent;
459                         }
460
461                         var percentage = this.getPercentage(ev);
462                         this.adjustPercentageForRangeSliders(percentage);
463                         this.percentage[this.dragged] = this.reversed ? 100 - percentage : percentage;
464                         this.layout();
465
466                         var val = this.calculateValue();
467                         this.setValue(val, true);
468
469                         return false;
470                 },
471                 adjustPercentageForRangeSliders: function(percentage) {
472                         if (this.range) {
473                                 if (this.dragged === 0 && this.percentage[1] < percentage) {
474                                         this.percentage[0] = this.percentage[1];
475                                         this.dragged = 1;
476                                 } else if (this.dragged === 1 && this.percentage[0] > percentage) {
477                                         this.percentage[1] = this.percentage[0];
478                                         this.dragged = 0;
479                                 }
480                         }
481                 },
482
483                 mouseup: function() {
484                         if(!this.isEnabled()) {
485                                 return false;
486                         }
487                         if (this.touchCapable) {
488                                 // Touch: Unbind touch event handlers:
489                                 $(document).off({
490                                         touchmove: this.mousemove,
491                                         touchend: this.mouseup
492                                 });
493                         }
494                         // Unbind mouse event handlers:
495                         $(document).off({
496                                 mousemove: this.mousemove,
497                                 mouseup: this.mouseup
498                         });
499
500                         this.inDrag = false;
501                         if (this.over === false) {
502                                 this.hideTooltip();
503                         }
504                         var val = this.calculateValue();
505                         this.layout();
506                         this.element
507                                 .data('value', val)
508                                 .prop('value', val)
509                                 .trigger({
510                                         type: 'slideStop',
511                                         value: val
512                                 });
513                         return false;
514                 },
515
516                 calculateValue: function() {
517                         var val;
518                         if (this.range) {
519                                 val = [this.min,this.max];
520                 if (this.percentage[0] !== 0){
521                     val[0] = (Math.max(this.min, this.min + Math.round((this.diff * this.percentage[0]/100)/this.step)*this.step));
522                     val[0] = this.applyPrecision(val[0]);
523                 }
524                 if (this.percentage[1] !== 100){
525                     val[1] = (Math.min(this.max, this.min + Math.round((this.diff * this.percentage[1]/100)/this.step)*this.step));
526                     val[1] = this.applyPrecision(val[1]);
527                 }
528                                 this.value = val;
529                         } else {
530                                 val = (this.min + Math.round((this.diff * this.percentage[0]/100)/this.step)*this.step);
531                                 if (val < this.min) {
532                                         val = this.min;
533                                 }
534                                 else if (val > this.max) {
535                                         val = this.max;
536                                 }
537                                 val = parseFloat(val);
538                                 val = this.applyPrecision(val);
539                                 this.value = [val, this.value[1]];
540                         }
541                         return val;
542                 },
543                 applyPrecision: function(val) {
544                         var precision = this.precision || this.getNumDigitsAfterDecimalPlace(this.step);
545                         return this.applyToFixedAndParseFloat(val, precision);
546                 },
547                 /*
548                         Credits to Mike Samuel for the following method!
549                         Source: http://stackoverflow.com/questions/10454518/javascript-how-to-retrieve-the-number-of-decimals-of-a-string-number
550                 */
551                 getNumDigitsAfterDecimalPlace: function(num) {
552                         var match = (''+num).match(/(?:\.(\d+))?(?:[eE]([+-]?\d+))?$/);
553                         if (!match) { return 0; }
554                         return Math.max(0, (match[1] ? match[1].length : 0) - (match[2] ? +match[2] : 0));
555                 },
556
557                 applyToFixedAndParseFloat: function(num, toFixedInput) {
558                         var truncatedNum = num.toFixed(toFixedInput);
559                         return parseFloat(truncatedNum);
560                 },
561
562                 getPercentage: function(ev) {
563                         if (this.touchCapable && (ev.type === 'touchstart' || ev.type === 'touchmove')) {
564                                 ev = ev.touches[0];
565                         }
566                         var percentage = (ev[this.mousePos] - this.offset[this.stylePos])*100/this.size;
567                         percentage = Math.round(percentage/this.percentage[2])*this.percentage[2];
568                         return Math.max(0, Math.min(100, percentage));
569                 },
570
571                 getValue: function() {
572                         if (this.range) {
573                                 return this.value;
574                         }
575                         return this.value[0];
576                 },
577
578                 setValue: function(val, triggerSlideEvent) {
579                         if (!val) {
580                                 val = 0;
581                         }
582                         this.value = this.validateInputValue(val);
583
584                         if (this.range) {
585                                 this.value[0] = this.applyPrecision(this.value[0]);
586                                 this.value[1] = this.applyPrecision(this.value[1]); 
587
588                                 this.value[0] = Math.max(this.min, Math.min(this.max, this.value[0]));
589                                 this.value[1] = Math.max(this.min, Math.min(this.max, this.value[1]));
590                         } else {
591                                 this.value = this.applyPrecision(this.value);
592                                 this.value = [ Math.max(this.min, Math.min(this.max, this.value))];
593                                 this.handle2.addClass('hide');
594                                 if (this.selection === 'after') {
595                                         this.value[1] = this.max;
596                                 } else {
597                                         this.value[1] = this.min;
598                                 }
599                         }
600
601                         this.diff = this.max - this.min;
602                         if (this.diff > 0) {
603                                 this.percentage = [
604                                         (this.value[0] - this.min) * 100 / this.diff,
605                                         (this.value[1] - this.min) * 100 / this.diff,
606                                         this.step * 100 / this.diff
607                                 ];
608                         } else {
609                                 this.percentage = [0, 0, 100];
610                         }
611
612                         this.layout();
613
614
615                         if(triggerSlideEvent === true) {
616                                 var slideEventValue = this.range ? this.value : this.value[0];
617                                 this.element
618                                         .trigger({
619                                                 'type': 'slide',
620                                                 'value': slideEventValue
621                                         })
622                                         .data('value', slideEventValue)
623                                         .prop('value', slideEventValue);
624                         }
625                 },
626
627                 validateInputValue : function(val) {
628                         if(typeof val === 'number') {
629                                 return val;
630                         } else if(val instanceof Array) {
631                                 $.each(val, function(i, input) { if (typeof input !== 'number') { throw new Error( ErrorMsgs.formatInvalidInputErrorMsg(input) ); }});
632                                 return val;
633                         } else {
634                                 throw new Error( ErrorMsgs.formatInvalidInputErrorMsg(val) );
635                         }
636                 },
637
638                 destroy: function(){
639                         this.handle1.off();
640                         this.handle2.off();
641                         this.element.off().show().insertBefore(this.picker);
642                         this.picker.off().remove();
643                         $(this.element).removeData('slider');
644                 },
645
646                 disable: function() {
647                         this.enabled = false;
648                         this.handle1.removeAttr("tabindex");
649                         this.handle2.removeAttr("tabindex");
650                         this.picker.addClass('slider-disabled');
651                         this.element.trigger('slideDisabled');
652                 },
653
654                 enable: function() {
655                         this.enabled = true;
656                         this.handle1.attr("tabindex", 0);
657                         this.handle2.attr("tabindex", 0);
658                         this.picker.removeClass('slider-disabled');
659                         this.element.trigger('slideEnabled');
660                 },
661
662                 toggle: function() {
663                         if(this.enabled) {
664                                 this.disable();
665                         } else {
666                                 this.enable();
667                         }
668                 },
669
670                 isEnabled: function() {
671                         return this.enabled;
672                 },
673
674                 setAttribute: function(attribute, value) {
675                         this[attribute] = value;
676                 },
677
678                 getAttribute: function(attribute) {
679                         return this[attribute];
680                 }
681
682         };
683
684         var publicMethods = {
685                 getValue : Slider.prototype.getValue,
686                 setValue : Slider.prototype.setValue,
687                 setAttribute : Slider.prototype.setAttribute,
688                 getAttribute : Slider.prototype.getAttribute,
689                 destroy : Slider.prototype.destroy,
690                 disable : Slider.prototype.disable,
691                 enable : Slider.prototype.enable,
692                 toggle : Slider.prototype.toggle,
693                 isEnabled: Slider.prototype.isEnabled
694         };
695
696         $.fn.slider = function (option) {
697                 if (typeof option === 'string' && option !== 'refresh') {
698                         var args = Array.prototype.slice.call(arguments, 1);
699                         return invokePublicMethod.call(this, option, args);
700                 } else {
701                         return createNewSliderInstance.call(this, option);
702                 }
703         };
704
705         function invokePublicMethod(methodName, args) {
706                 if(publicMethods[methodName]) {
707                         var sliderObject = retrieveSliderObjectFromElement(this);
708                         var result = publicMethods[methodName].apply(sliderObject, args);
709
710                         if (typeof result === "undefined") {
711                                 return $(this);
712                         } else {
713                                 return result;
714                         }
715                 } else {
716                         throw new Error("method '" + methodName + "()' does not exist for slider.");
717                 }
718         }
719
720         function retrieveSliderObjectFromElement(element) {
721                 var sliderObject = $(element).data('slider');
722                 if(sliderObject && sliderObject instanceof Slider) {
723                         return sliderObject;
724                 } else {
725                         throw new Error(ErrorMsgs.callingContextNotSliderInstance);
726                 }
727         }
728
729         function createNewSliderInstance(opts) {
730                 var $this = $(this);
731                 $this.each(function() {
732                         var $this = $(this),
733                                 slider = $this.data('slider'),
734                                 options = typeof opts === 'object' && opts;
735
736                         // If slider already exists, use its attributes
737                         // as options so slider refreshes properly
738                         if (slider && !options) {
739                                 options = {};
740
741                                 $.each($.fn.slider.defaults, function(key) {
742                                         options[key] = slider[key];
743                                 });
744                         }
745
746                         $this.data('slider', (new Slider(this, $.extend({}, $.fn.slider.defaults, options))));
747                 });
748                 return $this;
749         }
750
751         $.fn.slider.defaults = {
752                 min: 0,
753                 max: 10,
754                 step: 1,
755                 precision: 0,
756                 orientation: 'horizontal',
757                 value: 5,
758                 range: false,
759                 selection: 'before',
760                 tooltip: 'show',
761                 tooltip_separator: ':',
762                 tooltip_split: false,
763                 natural_arrow_keys: false,
764                 handle: 'round',
765                 reversed : false,
766                 enabled: true,
767                 formater: function(value) {
768                         return value;
769                 }
770         };
771
772         $.fn.slider.Constructor = Slider;
773
774 })( window.jQuery );
775
776 /* vim: set noexpandtab tabstop=4 shiftwidth=4 autoindent: */