Switch.js 6.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222
  1. define("dojox/mobile/Switch", [
  2. "dojo/_base/array",
  3. "dojo/_base/connect",
  4. "dojo/_base/declare",
  5. "dojo/_base/event",
  6. "dojo/_base/window",
  7. "dojo/dom-class",
  8. "dijit/_Contained",
  9. "dijit/_WidgetBase",
  10. "./sniff"
  11. ], function(array, connect, declare, event, win, domClass, Contained, WidgetBase, has){
  12. /*=====
  13. Contained = dijit._Contained;
  14. WidgetBase = dijit._WidgetBase;
  15. =====*/
  16. // module:
  17. // dojox/mobile/Switch
  18. // summary:
  19. // A toggle switch with a sliding knob.
  20. return declare("dojox.mobile.Switch", [WidgetBase, Contained],{
  21. // summary:
  22. // A toggle switch with a sliding knob.
  23. // description:
  24. // Switch is a toggle switch with a sliding knob. You can either
  25. // tap or slide the knob to toggle the switch. The onStateChanged
  26. // handler is called when the switch is manipulated.
  27. // value: String
  28. // The initial state of the switch. "on" or "off". The default
  29. // value is "on".
  30. value: "on",
  31. // name: String
  32. // A name for a hidden input field, which holds the current value.
  33. name: "",
  34. // leftLabel: String
  35. // The left-side label of the switch.
  36. leftLabel: "ON",
  37. // rightLabel: String
  38. // The right-side label of the switch.
  39. rightLabel: "OFF",
  40. /* internal properties */
  41. _width: 53,
  42. buildRendering: function(){
  43. this.domNode = win.doc.createElement("DIV");
  44. var c = (this.srcNodeRef && this.srcNodeRef.className) || this.className || this["class"];
  45. this._swClass = (c || "").replace(/ .*/,"");
  46. this.domNode.className = "mblSwitch";
  47. var nameAttr = this.name ? " name=\"" + this.name + "\"" : "";
  48. this.domNode.innerHTML =
  49. '<div class="mblSwitchInner">'
  50. + '<div class="mblSwitchBg mblSwitchBgLeft">'
  51. + '<div class="mblSwitchText mblSwitchTextLeft"></div>'
  52. + '</div>'
  53. + '<div class="mblSwitchBg mblSwitchBgRight">'
  54. + '<div class="mblSwitchText mblSwitchTextRight"></div>'
  55. + '</div>'
  56. + '<div class="mblSwitchKnob"></div>'
  57. + '<input type="hidden"'+nameAttr+'></div>'
  58. + '</div>';
  59. var n = this.inner = this.domNode.firstChild;
  60. this.left = n.childNodes[0];
  61. this.right = n.childNodes[1];
  62. this.knob = n.childNodes[2];
  63. this.input = n.childNodes[3];
  64. },
  65. postCreate: function(){
  66. this.connect(this.domNode, "onclick", "onClick");
  67. this.connect(this.domNode, has("touch") ? "touchstart" : "onmousedown", "onTouchStart");
  68. this._initialValue = this.value; // for reset()
  69. },
  70. _changeState: function(/*String*/state, /*Boolean*/anim){
  71. var on = (state === "on");
  72. this.left.style.display = "";
  73. this.right.style.display = "";
  74. this.inner.style.left = "";
  75. if(anim){
  76. domClass.add(this.domNode, "mblSwitchAnimation");
  77. }
  78. domClass.remove(this.domNode, on ? "mblSwitchOff" : "mblSwitchOn");
  79. domClass.add(this.domNode, on ? "mblSwitchOn" : "mblSwitchOff");
  80. var _this = this;
  81. setTimeout(function(){
  82. _this.left.style.display = on ? "" : "none";
  83. _this.right.style.display = !on ? "" : "none";
  84. domClass.remove(_this.domNode, "mblSwitchAnimation");
  85. }, anim ? 300 : 0);
  86. },
  87. startup: function(){
  88. if(this._swClass.indexOf("Round") != -1){
  89. var r = Math.round(this.domNode.offsetHeight / 2);
  90. this.createRoundMask(this._swClass, r, this.domNode.offsetWidth);
  91. }
  92. },
  93. createRoundMask: function(className, r, w){
  94. if(!has("webkit") || !className){ return; }
  95. if(!this._createdMasks){ this._createdMasks = []; }
  96. if(this._createdMasks[className]){ return; }
  97. this._createdMasks[className] = 1;
  98. var ctx = win.doc.getCSSCanvasContext("2d", className+"Mask", w, 100);
  99. ctx.fillStyle = "#000000";
  100. ctx.beginPath();
  101. ctx.moveTo(r, 0);
  102. ctx.arcTo(0, 0, 0, 2*r, r);
  103. ctx.arcTo(0, 2*r, r, 2*r, r);
  104. ctx.lineTo(w - r, 2*r);
  105. ctx.arcTo(w, 2*r, w, r, r);
  106. ctx.arcTo(w, 0, w - r, 0, r);
  107. ctx.closePath();
  108. ctx.fill();
  109. },
  110. onClick: function(e){
  111. if(this._moved){ return; }
  112. this.value = this.input.value = (this.value == "on") ? "off" : "on";
  113. this._changeState(this.value, true);
  114. this.onStateChanged(this.value);
  115. },
  116. onTouchStart: function(e){
  117. // summary:
  118. // Internal function to handle touchStart events.
  119. this._moved = false;
  120. this.innerStartX = this.inner.offsetLeft;
  121. if(!this._conn){
  122. this._conn = [];
  123. this._conn.push(connect.connect(this.inner, has("touch") ? "touchmove" : "onmousemove", this, "onTouchMove"));
  124. this._conn.push(connect.connect(this.inner, has("touch") ? "touchend" : "onmouseup", this, "onTouchEnd"));
  125. }
  126. this.touchStartX = e.touches ? e.touches[0].pageX : e.clientX;
  127. this.left.style.display = "";
  128. this.right.style.display = "";
  129. event.stop(e);
  130. },
  131. onTouchMove: function(e){
  132. // summary:
  133. // Internal function to handle touchMove events.
  134. e.preventDefault();
  135. var dx;
  136. if(e.targetTouches){
  137. if(e.targetTouches.length != 1){ return false; }
  138. dx = e.targetTouches[0].clientX - this.touchStartX;
  139. }else{
  140. dx = e.clientX - this.touchStartX;
  141. }
  142. var pos = this.innerStartX + dx;
  143. var d = 10;
  144. if(pos <= -(this._width-d)){ pos = -this._width; }
  145. if(pos >= -d){ pos = 0; }
  146. this.inner.style.left = pos + "px";
  147. if(Math.abs(dx) > d){
  148. this._moved = true;
  149. }
  150. },
  151. onTouchEnd: function(e){
  152. // summary:
  153. // Internal function to handle touchEnd events.
  154. array.forEach(this._conn, connect.disconnect);
  155. this._conn = null;
  156. if(this.innerStartX == this.inner.offsetLeft){
  157. if(has("touch")){
  158. var ev = win.doc.createEvent("MouseEvents");
  159. ev.initEvent("click", true, true);
  160. this.inner.dispatchEvent(ev);
  161. }
  162. return;
  163. }
  164. var newState = (this.inner.offsetLeft < -(this._width/2)) ? "off" : "on";
  165. this._changeState(newState, true);
  166. if(newState != this.value){
  167. this.value = this.input.value = newState;
  168. this.onStateChanged(newState);
  169. }
  170. },
  171. onStateChanged: function(/*String*/newState){
  172. // summary:
  173. // Stub function to connect to from your application.
  174. // description:
  175. // Called when the state has been changed.
  176. },
  177. _setValueAttr: function(/*String*/value){
  178. this._changeState(value, false);
  179. if(this.value != value){
  180. this.onStateChanged(value);
  181. }
  182. this.value = this.input.value = value;
  183. },
  184. _setLeftLabelAttr: function(/*String*/label){
  185. this.leftLabel = label;
  186. this.left.firstChild.innerHTML = this._cv ? this._cv(label) : label;
  187. },
  188. _setRightLabelAttr: function(/*String*/label){
  189. this.rightLabel = label;
  190. this.right.firstChild.innerHTML = this._cv ? this._cv(label) : label;
  191. },
  192. reset: function(){
  193. // summary:
  194. // Reset the widget's value to what it was at initialization time
  195. this.set("value", this._initialValue);
  196. }
  197. });
  198. });