SpinWheelSlot.js 9.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327
  1. define("dojox/mobile/SpinWheelSlot", [
  2. "dojo/_base/declare",
  3. "dojo/_base/window",
  4. "dojo/dom-class",
  5. "dojo/dom-construct",
  6. "dijit/_Contained",
  7. "dijit/_WidgetBase",
  8. "./_ScrollableMixin"
  9. ], function(declare, win, domClass, domConstruct, Contained, WidgetBase, ScrollableMixin){
  10. /*=====
  11. var Contained = dijit._Contained;
  12. var WidgetBase = dijit._WidgetBase;
  13. var ScrollableMixin = dojox.mobile._ScrollableMixin;
  14. =====*/
  15. // module:
  16. // dojox/mobile/SpinWheelSlot
  17. // summary:
  18. // A slot of a SpinWheel.
  19. return declare("dojox.mobile.SpinWheelSlot", [WidgetBase, Contained, ScrollableMixin], {
  20. // summary:
  21. // A slot of a SpinWheel.
  22. // description:
  23. // SpinWheelSlot is a slot that is placed in the SpinWheel widget.
  24. // items: Array
  25. // An array of array of key-label paris.
  26. // (e.g. [[0,"Jan"],[1,"Feb"],...] ) If key values for each label
  27. // are not necessary, labels can be used instead.
  28. items: [],
  29. // labels: Array
  30. // An array of labels to be displayed on the slot.
  31. // (e.g. ["Jan","Feb",...] ) This is a simplified version of the
  32. // items property.
  33. labels: [],
  34. // labelFrom: Number
  35. // The start value of display values of the slot. This parameter is
  36. // especially useful when slot has serial values.
  37. labelFrom: 0,
  38. // labelTo: Number
  39. // The end value of display values of the slot.
  40. labelTo: 0,
  41. // value: String
  42. // The initial value of the slot.
  43. value: "",
  44. /* internal properties */
  45. maxSpeed: 500,
  46. minItems: 15,
  47. centerPos: 0,
  48. scrollBar: false,
  49. constraint: false,
  50. allowNestedScrolls: false,
  51. androidWorkaroud: false, // disable workaround in SpinWheel
  52. buildRendering: function(){
  53. this.inherited(arguments);
  54. domClass.add(this.domNode, "mblSpinWheelSlot");
  55. var i, j, idx;
  56. if(this.labelFrom !== this.labelTo){
  57. this.labels = [];
  58. for(i = this.labelFrom, idx = 0; i <= this.labelTo; i++, idx++){
  59. this.labels[idx] = String(i);
  60. }
  61. }
  62. if(this.labels.length > 0){
  63. this.items = [];
  64. for(i = 0; i < this.labels.length; i++){
  65. this.items.push([i, this.labels[i]]);
  66. }
  67. }
  68. this.containerNode = domConstruct.create("DIV", {className:"mblSpinWheelSlotContainer"});
  69. this.containerNode.style.height
  70. = (win.global.innerHeight||win.doc.documentElement.clientHeight) * 2 + "px"; // must bigger than the screen
  71. this.panelNodes = [];
  72. for(var k = 0; k < 3; k++){
  73. this.panelNodes[k] = domConstruct.create("DIV", {className:"mblSpinWheelSlotPanel"});
  74. var len = this.items.length;
  75. var n = Math.ceil(this.minItems / len);
  76. for(j = 0; j < n; j++){
  77. for(i = 0; i < len; i++){
  78. domConstruct.create("DIV", {
  79. className: "mblSpinWheelSlotLabel",
  80. name: this.items[i][0],
  81. innerHTML: this._cv ? this._cv(this.items[i][1]) : this.items[i][1]
  82. }, this.panelNodes[k]);
  83. }
  84. }
  85. this.containerNode.appendChild(this.panelNodes[k]);
  86. }
  87. this.domNode.appendChild(this.containerNode);
  88. this.touchNode = domConstruct.create("DIV", {className:"mblSpinWheelSlotTouch"}, this.domNode);
  89. this.setSelectable(this.domNode, false);
  90. },
  91. startup: function(){
  92. this.inherited(arguments);
  93. this.centerPos = this.getParent().centerPos;
  94. var items = this.panelNodes[1].childNodes;
  95. this._itemHeight = items[0].offsetHeight;
  96. this.adjust();
  97. },
  98. adjust: function(){
  99. // summary:
  100. // Adjusts the position of slot panels.
  101. var items = this.panelNodes[1].childNodes;
  102. var adjustY;
  103. for(var i = 0, len = items.length; i < len; i++){
  104. var item = items[i];
  105. if(item.offsetTop <= this.centerPos && this.centerPos < item.offsetTop + item.offsetHeight){
  106. adjustY = this.centerPos - (item.offsetTop + Math.round(item.offsetHeight/2));
  107. break;
  108. }
  109. }
  110. var h = this.panelNodes[0].offsetHeight;
  111. this.panelNodes[0].style.top = -h + adjustY + "px";
  112. this.panelNodes[1].style.top = adjustY + "px";
  113. this.panelNodes[2].style.top = h + adjustY + "px";
  114. },
  115. setInitialValue: function(){
  116. // summary:
  117. // Sets the initial value using this.value or the first item.
  118. if(this.items.length > 0){
  119. var val = (this.value !== "") ? this.value : this.items[0][1];
  120. this.setValue(val);
  121. }
  122. },
  123. getCenterPanel: function(){
  124. // summary:
  125. // Gets a panel that contains the currently selected item.
  126. var pos = this.getPos();
  127. for(var i = 0, len = this.panelNodes.length; i < len; i++){
  128. var top = pos.y + this.panelNodes[i].offsetTop;
  129. if(top <= this.centerPos && this.centerPos < top + this.panelNodes[i].offsetHeight){
  130. return this.panelNodes[i];
  131. }
  132. }
  133. return null;
  134. },
  135. setColor: function(/*String*/value){
  136. // summary:
  137. // Sets the color of the specified item as blue.
  138. for(var i = 0, len = this.panelNodes.length; i < len; i++){
  139. var items = this.panelNodes[i].childNodes;
  140. for(var j = 0; j < items.length; j++){
  141. if(items[j].innerHTML === String(value)){
  142. domClass.add(items[j], "mblSpinWheelSlotLabelBlue");
  143. }else{
  144. domClass.remove(items[j], "mblSpinWheelSlotLabelBlue");
  145. }
  146. }
  147. }
  148. },
  149. disableValues: function(/*Array*/values){
  150. // summary:
  151. // Makes the specified items grayed out.
  152. for(var i = 0, len = this.panelNodes.length; i < len; i++){
  153. var items = this.panelNodes[i].childNodes;
  154. for(var j = 0; j < items.length; j++){
  155. domClass.remove(items[j], "mblSpinWheelSlotLabelGray");
  156. for(var k = 0; k < values.length; k++){
  157. if(items[j].innerHTML === String(values[k])){
  158. domClass.add(items[j], "mblSpinWheelSlotLabelGray");
  159. break;
  160. }
  161. }
  162. }
  163. }
  164. },
  165. getCenterItem: function(){
  166. // summary:
  167. // Gets the currently selected item.
  168. var pos = this.getPos();
  169. var centerPanel = this.getCenterPanel();
  170. if(centerPanel){
  171. var top = pos.y + centerPanel.offsetTop;
  172. var items = centerPanel.childNodes;
  173. for(var i = 0, len = items.length; i < len; i++){
  174. if(top + items[i].offsetTop <= this.centerPos && this.centerPos < top + items[i].offsetTop + items[i].offsetHeight){
  175. return items[i];
  176. }
  177. }
  178. }
  179. return null;
  180. },
  181. getValue: function(){
  182. // summary:
  183. // Gets the currently selected value.
  184. var item = this.getCenterItem();
  185. return (item && item.innerHTML);
  186. },
  187. getKey: function(){
  188. // summary:
  189. // Gets the key for the currently selected value.
  190. return this.getCenterItem().getAttribute("name");
  191. },
  192. setValue: function(newValue){
  193. // summary:
  194. // Sets the newValue to this slot.
  195. var idx0, idx1;
  196. var curValue = this.getValue();
  197. if(!curValue){
  198. this._penddingValue = newValue;
  199. return;
  200. }
  201. this._penddingValue = undefined;
  202. var n = this.items.length;
  203. for(var i = 0; i < n; i++){
  204. if(this.items[i][1] === String(curValue)){
  205. idx0 = i;
  206. }
  207. if(this.items[i][1] === String(newValue)){
  208. idx1 = i;
  209. }
  210. if(idx0 !== undefined && idx1 !== undefined){
  211. break;
  212. }
  213. }
  214. var d = idx1 - (idx0 || 0);
  215. var m;
  216. if(d > 0){
  217. m = (d < n - d) ? -d : n - d;
  218. }else{
  219. m = (-d < n + d) ? -d : -(n + d);
  220. }
  221. var to = this.getPos();
  222. to.y += m * this._itemHeight;
  223. this.slideTo(to, 1);
  224. },
  225. getSpeed: function(){
  226. // summary:
  227. // Overrides dojox.mobile.scrollable.getSpeed().
  228. var y = 0, n = this._time.length;
  229. var delta = (new Date()).getTime() - this.startTime - this._time[n - 1];
  230. if(n >= 2 && delta < 200){
  231. var dy = this._posY[n - 1] - this._posY[(n - 6) >= 0 ? n - 6 : 0];
  232. var dt = this._time[n - 1] - this._time[(n - 6) >= 0 ? n - 6 : 0];
  233. y = this.calcSpeed(dy, dt);
  234. }
  235. return {x:0, y:y};
  236. },
  237. calcSpeed: function(/*Number*/d, /*Number*/t){
  238. // summary:
  239. // Overrides dojox.mobile.scrollable.calcSpeed().
  240. var speed = this.inherited(arguments);
  241. if(!speed){ return 0; }
  242. var v = Math.abs(speed);
  243. var ret = speed;
  244. if(v > this.maxSpeed){
  245. ret = this.maxSpeed*(speed/v);
  246. }
  247. return ret;
  248. },
  249. adjustDestination: function(to, pos){
  250. // summary:
  251. // Overrides dojox.mobile.scrollable.adjustDestination().
  252. var h = this._itemHeight;
  253. var j = to.y + Math.round(h/2);
  254. var a = Math.abs(j);
  255. var r = j >= 0 ? j % h : j % h + h;
  256. to.y = j - r;
  257. },
  258. resize: function(e){
  259. if(this._penddingValue){
  260. this.setValue(this._penddingValue);
  261. }
  262. },
  263. slideTo: function(/*Object*/to, /*Number*/duration, /*String*/easing){
  264. // summary:
  265. // Overrides dojox.mobile.scrollable.slideTo().
  266. var pos = this.getPos();
  267. var top = pos.y + this.panelNodes[1].offsetTop;
  268. var bottom = top + this.panelNodes[1].offsetHeight;
  269. var vh = this.domNode.parentNode.offsetHeight;
  270. var t;
  271. if(pos.y < to.y){ // going down
  272. if(bottom > vh){
  273. // move up the bottom panel
  274. t = this.panelNodes[2];
  275. t.style.top = this.panelNodes[0].offsetTop - this.panelNodes[0].offsetHeight + "px";
  276. this.panelNodes[2] = this.panelNodes[1];
  277. this.panelNodes[1] = this.panelNodes[0];
  278. this.panelNodes[0] = t;
  279. }
  280. }else if(pos.y > to.y){ // going up
  281. if(top < 0){
  282. // move down the top panel
  283. t = this.panelNodes[0];
  284. t.style.top = this.panelNodes[2].offsetTop + this.panelNodes[2].offsetHeight + "px";
  285. this.panelNodes[0] = this.panelNodes[1];
  286. this.panelNodes[1] = this.panelNodes[2];
  287. this.panelNodes[2] = t;
  288. }
  289. }
  290. if(!this._initialized){
  291. duration = 0; // to reduce flickers at start-up especially on android
  292. this._initialized = true;
  293. }else if(Math.abs(this._speed.y) < 40){
  294. duration = 0.2;
  295. }
  296. this.inherited(arguments, [to, duration, easing]); // 2nd arg is to avoid excessive optimization by closure compiler
  297. }
  298. });
  299. });