Spinner.js 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441
  1. /*
  2. * Ext JS Library 3.3.0
  3. * Copyright(c) 2006-2010 Ext JS, Inc.
  4. * licensing@extjs.com
  5. * http://www.extjs.com/license
  6. */
  7. /**
  8. * @class Ext.ux.Spinner
  9. * @extends Ext.util.Observable
  10. * Creates a Spinner control utilized by Ext.ux.form.SpinnerField
  11. */
  12. Ext.ux.Spinner = Ext.extend(Ext.util.Observable, {
  13. incrementValue: 1,
  14. alternateIncrementValue: 5,
  15. triggerClass: 'x-form-spinner-trigger',
  16. splitterClass: 'x-form-spinner-splitter',
  17. alternateKey: Ext.EventObject.shiftKey,
  18. defaultValue: 0,
  19. accelerate: false,
  20. constructor: function(config){
  21. Ext.ux.Spinner.superclass.constructor.call(this, config);
  22. Ext.apply(this, config);
  23. this.mimicing = false;
  24. },
  25. init: function(field){
  26. this.field = field;
  27. field.afterMethod('onRender', this.doRender, this);
  28. field.afterMethod('onEnable', this.doEnable, this);
  29. field.afterMethod('onDisable', this.doDisable, this);
  30. field.afterMethod('afterRender', this.doAfterRender, this);
  31. field.afterMethod('onResize', this.doResize, this);
  32. field.afterMethod('onFocus', this.doFocus, this);
  33. field.beforeMethod('onDestroy', this.doDestroy, this);
  34. },
  35. doRender: function(ct, position){
  36. var el = this.el = this.field.getEl();
  37. var f = this.field;
  38. if (!f.wrap) {
  39. f.wrap = this.wrap = el.wrap({
  40. cls: "x-form-field-wrap"
  41. });
  42. }
  43. else {
  44. this.wrap = f.wrap.addClass('x-form-field-wrap');
  45. }
  46. this.trigger = this.wrap.createChild({
  47. tag: "img",
  48. src: Ext.BLANK_IMAGE_URL,
  49. cls: "x-form-trigger " + this.triggerClass
  50. });
  51. if (!f.width) {
  52. this.wrap.setWidth(el.getWidth() + this.trigger.getWidth());
  53. }
  54. this.splitter = this.wrap.createChild({
  55. tag: 'div',
  56. cls: this.splitterClass,
  57. style: 'width:13px; height:2px;'
  58. });
  59. this.splitter.setRight((Ext.isIE) ? 1 : 2).setTop(10).show();
  60. this.proxy = this.trigger.createProxy('', this.splitter, true);
  61. this.proxy.addClass("x-form-spinner-proxy");
  62. this.proxy.setStyle('left', '0px');
  63. this.proxy.setSize(14, 1);
  64. this.proxy.hide();
  65. this.dd = new Ext.dd.DDProxy(this.splitter.dom.id, "SpinnerDrag", {
  66. dragElId: this.proxy.id
  67. });
  68. this.initTrigger();
  69. this.initSpinner();
  70. },
  71. doAfterRender: function(){
  72. var y;
  73. if (Ext.isIE && this.el.getY() != (y = this.trigger.getY())) {
  74. this.el.position();
  75. this.el.setY(y);
  76. }
  77. },
  78. doEnable: function(){
  79. if (this.wrap) {
  80. this.wrap.removeClass(this.field.disabledClass);
  81. }
  82. },
  83. doDisable: function(){
  84. if (this.wrap) {
  85. this.wrap.addClass(this.field.disabledClass);
  86. this.el.removeClass(this.field.disabledClass);
  87. }
  88. },
  89. doResize: function(w, h){
  90. if (typeof w == 'number') {
  91. this.el.setWidth(w - this.trigger.getWidth());
  92. }
  93. this.wrap.setWidth(this.el.getWidth() + this.trigger.getWidth());
  94. },
  95. doFocus: function(){
  96. if (!this.mimicing) {
  97. this.wrap.addClass('x-trigger-wrap-focus');
  98. this.mimicing = true;
  99. Ext.get(Ext.isIE ? document.body : document).on("mousedown", this.mimicBlur, this, {
  100. delay: 10
  101. });
  102. this.el.on('keydown', this.checkTab, this);
  103. }
  104. },
  105. // private
  106. checkTab: function(e){
  107. if (e.getKey() == e.TAB) {
  108. this.triggerBlur();
  109. }
  110. },
  111. // private
  112. mimicBlur: function(e){
  113. if (!this.wrap.contains(e.target) && this.field.validateBlur(e)) {
  114. this.triggerBlur();
  115. }
  116. },
  117. // private
  118. triggerBlur: function(){
  119. this.mimicing = false;
  120. Ext.get(Ext.isIE ? document.body : document).un("mousedown", this.mimicBlur, this);
  121. this.el.un("keydown", this.checkTab, this);
  122. this.field.beforeBlur();
  123. this.wrap.removeClass('x-trigger-wrap-focus');
  124. this.field.onBlur.call(this.field);
  125. },
  126. initTrigger: function(){
  127. this.trigger.addClassOnOver('x-form-trigger-over');
  128. this.trigger.addClassOnClick('x-form-trigger-click');
  129. },
  130. initSpinner: function(){
  131. this.field.addEvents({
  132. 'spin': true,
  133. 'spinup': true,
  134. 'spindown': true
  135. });
  136. this.keyNav = new Ext.KeyNav(this.el, {
  137. "up": function(e){
  138. e.preventDefault();
  139. this.onSpinUp();
  140. },
  141. "down": function(e){
  142. e.preventDefault();
  143. this.onSpinDown();
  144. },
  145. "pageUp": function(e){
  146. e.preventDefault();
  147. this.onSpinUpAlternate();
  148. },
  149. "pageDown": function(e){
  150. e.preventDefault();
  151. this.onSpinDownAlternate();
  152. },
  153. scope: this
  154. });
  155. this.repeater = new Ext.util.ClickRepeater(this.trigger, {
  156. accelerate: this.accelerate
  157. });
  158. this.field.mon(this.repeater, "click", this.onTriggerClick, this, {
  159. preventDefault: true
  160. });
  161. this.field.mon(this.trigger, {
  162. mouseover: this.onMouseOver,
  163. mouseout: this.onMouseOut,
  164. mousemove: this.onMouseMove,
  165. mousedown: this.onMouseDown,
  166. mouseup: this.onMouseUp,
  167. scope: this,
  168. preventDefault: true
  169. });
  170. this.field.mon(this.wrap, "mousewheel", this.handleMouseWheel, this);
  171. this.dd.setXConstraint(0, 0, 10)
  172. this.dd.setYConstraint(1500, 1500, 10);
  173. this.dd.endDrag = this.endDrag.createDelegate(this);
  174. this.dd.startDrag = this.startDrag.createDelegate(this);
  175. this.dd.onDrag = this.onDrag.createDelegate(this);
  176. },
  177. onMouseOver: function(){
  178. if (this.disabled) {
  179. return;
  180. }
  181. var middle = this.getMiddle();
  182. this.tmpHoverClass = (Ext.EventObject.getPageY() < middle) ? 'x-form-spinner-overup' : 'x-form-spinner-overdown';
  183. this.trigger.addClass(this.tmpHoverClass);
  184. },
  185. //private
  186. onMouseOut: function(){
  187. this.trigger.removeClass(this.tmpHoverClass);
  188. },
  189. //private
  190. onMouseMove: function(){
  191. if (this.disabled) {
  192. return;
  193. }
  194. var middle = this.getMiddle();
  195. if (((Ext.EventObject.getPageY() > middle) && this.tmpHoverClass == "x-form-spinner-overup") ||
  196. ((Ext.EventObject.getPageY() < middle) && this.tmpHoverClass == "x-form-spinner-overdown")) {
  197. }
  198. },
  199. //private
  200. onMouseDown: function(){
  201. if (this.disabled) {
  202. return;
  203. }
  204. var middle = this.getMiddle();
  205. this.tmpClickClass = (Ext.EventObject.getPageY() < middle) ? 'x-form-spinner-clickup' : 'x-form-spinner-clickdown';
  206. this.trigger.addClass(this.tmpClickClass);
  207. },
  208. //private
  209. onMouseUp: function(){
  210. this.trigger.removeClass(this.tmpClickClass);
  211. },
  212. //private
  213. onTriggerClick: function(){
  214. if (this.disabled || this.el.dom.readOnly) {
  215. return;
  216. }
  217. var middle = this.getMiddle();
  218. var ud = (Ext.EventObject.getPageY() < middle) ? 'Up' : 'Down';
  219. this['onSpin' + ud]();
  220. },
  221. //private
  222. getMiddle: function(){
  223. var t = this.trigger.getTop();
  224. var h = this.trigger.getHeight();
  225. var middle = t + (h / 2);
  226. return middle;
  227. },
  228. //private
  229. //checks if control is allowed to spin
  230. isSpinnable: function(){
  231. if (this.disabled || this.el.dom.readOnly) {
  232. Ext.EventObject.preventDefault(); //prevent scrolling when disabled/readonly
  233. return false;
  234. }
  235. return true;
  236. },
  237. handleMouseWheel: function(e){
  238. //disable scrolling when not focused
  239. if (this.wrap.hasClass('x-trigger-wrap-focus') == false) {
  240. return;
  241. }
  242. var delta = e.getWheelDelta();
  243. if (delta > 0) {
  244. this.onSpinUp();
  245. e.stopEvent();
  246. }
  247. else
  248. if (delta < 0) {
  249. this.onSpinDown();
  250. e.stopEvent();
  251. }
  252. },
  253. //private
  254. startDrag: function(){
  255. this.proxy.show();
  256. this._previousY = Ext.fly(this.dd.getDragEl()).getTop();
  257. },
  258. //private
  259. endDrag: function(){
  260. this.proxy.hide();
  261. },
  262. //private
  263. onDrag: function(){
  264. if (this.disabled) {
  265. return;
  266. }
  267. var y = Ext.fly(this.dd.getDragEl()).getTop();
  268. var ud = '';
  269. if (this._previousY > y) {
  270. ud = 'Up';
  271. } //up
  272. if (this._previousY < y) {
  273. ud = 'Down';
  274. } //down
  275. if (ud != '') {
  276. this['onSpin' + ud]();
  277. }
  278. this._previousY = y;
  279. },
  280. //private
  281. onSpinUp: function(){
  282. if (this.isSpinnable() == false) {
  283. return;
  284. }
  285. if (Ext.EventObject.shiftKey == true) {
  286. this.onSpinUpAlternate();
  287. return;
  288. }
  289. else {
  290. this.spin(false, false);
  291. }
  292. this.field.fireEvent("spin", this);
  293. this.field.fireEvent("spinup", this);
  294. },
  295. //private
  296. onSpinDown: function(){
  297. if (this.isSpinnable() == false) {
  298. return;
  299. }
  300. if (Ext.EventObject.shiftKey == true) {
  301. this.onSpinDownAlternate();
  302. return;
  303. }
  304. else {
  305. this.spin(true, false);
  306. }
  307. this.field.fireEvent("spin", this);
  308. this.field.fireEvent("spindown", this);
  309. },
  310. //private
  311. onSpinUpAlternate: function(){
  312. if (this.isSpinnable() == false) {
  313. return;
  314. }
  315. this.spin(false, true);
  316. this.field.fireEvent("spin", this);
  317. this.field.fireEvent("spinup", this);
  318. },
  319. //private
  320. onSpinDownAlternate: function(){
  321. if (this.isSpinnable() == false) {
  322. return;
  323. }
  324. this.spin(true, true);
  325. this.field.fireEvent("spin", this);
  326. this.field.fireEvent("spindown", this);
  327. },
  328. spin: function(down, alternate){
  329. var v = parseFloat(this.field.getValue());
  330. var incr = (alternate == true) ? this.alternateIncrementValue : this.incrementValue;
  331. (down == true) ? v -= incr : v += incr;
  332. v = (isNaN(v)) ? this.defaultValue : v;
  333. v = this.fixBoundries(v);
  334. this.field.setRawValue(v);
  335. },
  336. fixBoundries: function(value){
  337. var v = value;
  338. if (this.field.minValue != undefined && v < this.field.minValue) {
  339. v = this.field.minValue;
  340. }
  341. if (this.field.maxValue != undefined && v > this.field.maxValue) {
  342. v = this.field.maxValue;
  343. }
  344. return this.fixPrecision(v);
  345. },
  346. // private
  347. fixPrecision: function(value){
  348. var nan = isNaN(value);
  349. if (!this.field.allowDecimals || this.field.decimalPrecision == -1 || nan || !value) {
  350. return nan ? '' : value;
  351. }
  352. return parseFloat(parseFloat(value).toFixed(this.field.decimalPrecision));
  353. },
  354. doDestroy: function(){
  355. if (this.trigger) {
  356. this.trigger.remove();
  357. }
  358. if (this.wrap) {
  359. this.wrap.remove();
  360. delete this.field.wrap;
  361. }
  362. if (this.splitter) {
  363. this.splitter.remove();
  364. }
  365. if (this.dd) {
  366. this.dd.unreg();
  367. this.dd = null;
  368. }
  369. if (this.proxy) {
  370. this.proxy.remove();
  371. }
  372. if (this.repeater) {
  373. this.repeater.purgeListeners();
  374. }
  375. if (this.mimicing){
  376. Ext.get(Ext.isIE ? document.body : document).un("mousedown", this.mimicBlur, this);
  377. }
  378. }
  379. });
  380. //backwards compat
  381. Ext.form.Spinner = Ext.ux.Spinner;