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