1 /*
  2  * JBoss, Home of Professional Open Source
  3  * Copyright ${year}, Red Hat, Inc. and individual contributors
  4  * by the @authors tag. See the copyright.txt in the distribution for a
  5  * full listing of individual contributors.
  6  *
  7  * This is free software; you can redistribute it and/or modify it
  8  * under the terms of the GNU Lesser General Public License as
  9  * published by the Free Software Foundation; either version 2.1 of
 10  * the License, or (at your option) any later version.
 11  *
 12  * This software is distributed in the hope that it will be useful,
 13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
 14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
 15  * Lesser General Public License for more details.
 16  *
 17  * You should have received a copy of the GNU Lesser General Public
 18  * License along with this software; if not, write to the Free
 19  * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
 20  * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
 21  */
 22 (function($, rf) {
 23     rf.ui = rf.ui || {};
 24 
 25     rf.ui.InputNumberSlider = rf.BaseComponent.extendClass({
 26 
 27             name: "InputNumberSlider",
 28 
 29             delay: 200,
 30             maxValue: 100,
 31             minValue: 0,
 32             step: 1,
 33             tabIndex: 0,
 34 
 35             decreaseSelectedClass: "rf-insl-dec-sel",
 36             handleSelectedClass: "rf-insl-hnd-sel",
 37             increaseSelectedClass: "rf-insl-inc-sel",
 38 
 39             init: function (id, options, selectedClasses) {
 40                 $superInputNumberSlider.constructor.call(this, id);
 41                 $.extend(this, options);
 42                 this.range = this.maxValue - this.minValue;
 43                 this.id = id;
 44                 this.element = $(this.attachToDom());
 45                 this.input = this.element.children(".rf-insl-inp-cntr").children(".rf-insl-inp");
 46                 this.track = this.element.children(".rf-insl-trc-cntr").children(".rf-insl-trc");
 47                 this.handleContainer = this.track.children("span");
 48                 this.handle = this.handleContainer.children(".rf-insl-hnd, .rf-insl-hnd-dis");
 49                 this.tooltip = this.element.children(".rf-insl-tt");
 50 
 51                 var value = Number(this.input.val());
 52                 if (isNaN(value)) {
 53                     value = this.minValue;
 54                 }
 55                 this.handleContainer.css("display", "block");
 56                 this.track.css("padding-right", this.handle.width() + "px");
 57                 this.__setValue(value, null, true);
 58 
 59                 if (!this.disabled) {
 60                     this.decreaseButton = this.element.children(".rf-insl-dec");
 61                     this.increaseButton = this.element.children(".rf-insl-inc");
 62 
 63                     this.track[0].tabIndex = this.tabIndex;
 64 
 65                     for (var i in selectedClasses) {
 66                         this[i] += " " + selectedClasses[i];
 67                     }
 68                     var proxy = $.proxy(this.__inputHandler, this);
 69                     this.input.change(proxy);
 70                     this.input.submit(proxy);
 71                     this.element.mousewheel($.proxy(this.__mousewheelHandler, this));
 72                     this.track.keydown($.proxy(this.__keydownHandler, this));
 73                     this.decreaseButton.mousedown($.proxy(this.__decreaseHandler, this));
 74                     this.increaseButton.mousedown($.proxy(this.__increaseHandler, this));
 75                     this.track.mousedown($.proxy(this.__mousedownHandler, this));
 76                 }
 77             },
 78 
 79             decrease: function (event) {
 80                 var value = this.value - this.step;
 81                 value = this.roundFloat(value);
 82                 this.setValue(value, event);
 83             },
 84 
 85             increase: function (event) {
 86                 var value = this.value + this.step;
 87                 value = this.roundFloat(value);
 88                 this.setValue(value, event);
 89             },
 90 
 91             getValue: function () {
 92                 return this.value;
 93             },
 94 
 95             setValue: function (value, event) {
 96                 if (!this.disabled) {
 97                     this.__setValue(value, event);
 98                 }
 99             },
100 
101             roundFloat: function(x){
102                 var str = this.step.toString();
103                 var power = 0;
104                 if (!/\./.test(str)) {
105                     if (this.step >= 1) {
106                         return x;
107                     }
108                     if (/e/.test(str)) {
109                         power = str.split("-")[1];
110                     }
111                 } else {
112                     power = str.length - str.indexOf(".") - 1;
113                 }
114                 var ret = x.toFixed(power);
115                 return parseFloat(ret);
116             },
117 
118             __setValue: function (value, event, skipOnchange) {
119                 if (!isNaN(value)) {
120                     var changed = false;
121                     if (this.input.val() == "") {
122                         // value already changed from "" to 0, compare to real value to track changes
123                         changed = true;
124                     }
125 
126                     if (value > this.maxValue) {
127                         value = this.maxValue;
128                         this.input.val(value);
129                         changed = true;
130                     } else if (value < this.minValue) {
131                         value = this.minValue;
132                         this.input.val(value);
133                         changed = true;
134                     }
135                     if (value != this.value || changed) {
136                         this.input.val(value);
137                         var left = 100 * (value - this.minValue) / this.range;
138                         if(this.handleType=='bar') {
139                             this.handleContainer.css("width", left + "%");
140                         } else {
141                             this.handleContainer.css("padding-left", left + "%");
142                         }
143                         this.tooltip.text(value);
144                         this.tooltip.setPosition(this.handle, {from: 'LT', offset: [0, 5]}); //TODO Seems offset doesn't work now.
145                         this.value = value;
146                         if (this.onchange && !skipOnchange) {
147                             this.onchange.call(this.element[0], event);
148                         }
149                     }
150                 }
151             },
152 
153             __inputHandler: function (event) {
154                 var value = Number(this.input.val());
155                 if (isNaN(value)) {
156                     this.input.val(this.value);
157                 } else {
158                     this.__setValue(value, event);
159                 }
160             },
161 
162             __mousewheelHandler: function (event, delta, deltaX, deltaY) {
163                 delta = deltaX || deltaY;
164                 if (delta > 0) {
165                     this.increase(event);
166                 } else if (delta < 0) {
167                     this.decrease(event);
168                 }
169                 return false;
170             },
171 
172             __keydownHandler: function (event) {
173                 if (event.keyCode == 37) { //LEFT
174                     var value = Number(this.input.val()) - this.step;
175                     value = this.roundFloat(value);
176                     this.__setValue(value, event);
177                     event.preventDefault();
178                 } else if (event.keyCode == 39) { //RIGHT
179                     var value = Number(this.input.val()) + this.step;
180                     value = this.roundFloat(value);
181                     this.__setValue(value, event);
182                     event.preventDefault();
183                 }
184             },
185 
186             __decreaseHandler: function (event) {
187                 var component = this;
188                 component.decrease(event);
189                 this.intervalId = window.setInterval(function() {
190                     component.decrease(event);
191                 }, this.delay);
192                 $(document).one("mouseup", true, $.proxy(this.__clearInterval, this));
193                 this.decreaseButton.addClass(this.decreaseSelectedClass);
194                 event.preventDefault();
195             },
196 
197             __increaseHandler: function (event) {
198                 var component = this;
199                 component.increase(event);
200                 this.intervalId = window.setInterval(function() {
201                     component.increase(event);
202                 }, this.delay);
203                 $(document).one("mouseup", $.proxy(this.__clearInterval, this));
204                 this.increaseButton.addClass(this.increaseSelectedClass);
205                 event.preventDefault();
206             },
207 
208             __clearInterval: function (event) {
209                 window.clearInterval(this.intervalId);
210                 if (event.data) { // decreaseButton
211                     this.decreaseButton.removeClass(this.decreaseSelectedClass);
212                 } else {
213                     this.increaseButton.removeClass(this.increaseSelectedClass);
214                 }
215             },
216 
217             __mousedownHandler: function (event) {
218                 this.__mousemoveHandler(event);
219                 this.track.focus();
220                 var jQueryDocument = $(document);
221                 jQueryDocument.mousemove($.proxy(this.__mousemoveHandler, this));
222                 jQueryDocument.one("mouseup", $.proxy(this.__mouseupHandler, this));
223                 this.handle.addClass(this.handleSelectedClass);
224                 this.tooltip.show();
225             },
226 
227             __mousemoveHandler: function (event) {
228                 var value = this.range * (event.pageX - this.track.offset().left - this.handle.width() / 2) / (this.track.width()
229                     - this.handle.width()) + this.minValue;
230                 value = Math.round(value / this.step) * this.step;
231                 value = this.roundFloat(value);
232                 this.__setValue(value, event);
233                 event.preventDefault();
234             },
235 
236             __mouseupHandler: function () {
237                 this.handle.removeClass(this.handleSelectedClass);
238                 this.tooltip.hide();
239                 $(document).unbind("mousemove", this.__mousemoveHandler);
240             },
241 
242             destroy: function (event) {
243                 $(document).unbind("mousemove", this.__mousemoveHandler);
244                 $superInputNumberSlider.destroy.call(this);
245             }
246         });
247     $superInputNumberSlider = rf.ui.InputNumberSlider.$super;
248 }(RichFaces.jQuery, window.RichFaces));
249