jquery.iphone.toggle.js 9.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284
  1. (function() {
  2. var iOSCheckbox;
  3. var __slice = Array.prototype.slice;
  4. iOSCheckbox = (function() {
  5. function iOSCheckbox(elem, options) {
  6. var key, opts, value;
  7. this.elem = $(elem);
  8. opts = $.extend({}, iOSCheckbox.defaults, options);
  9. for (key in opts) {
  10. value = opts[key];
  11. this[key] = value;
  12. }
  13. this.elem.data(this.dataName, this);
  14. this.wrapCheckboxWithDivs();
  15. this.attachEvents();
  16. this.disableTextSelection();
  17. if (this.resizeHandle) {
  18. this.optionallyResize('handle');
  19. }
  20. if (this.resizeContainer) {
  21. this.optionallyResize('container');
  22. }
  23. this.initialPosition();
  24. }
  25. iOSCheckbox.prototype.isDisabled = function() {
  26. return this.elem.is(':disabled');
  27. };
  28. iOSCheckbox.prototype.wrapCheckboxWithDivs = function() {
  29. this.elem.wrap("<div class='" + this.containerClass + "' />");
  30. this.container = this.elem.parent();
  31. this.offLabel = $("<label class='" + this.labelOffClass + "'>\n <span>" + this.uncheckedLabel + "</span>\n</label>").appendTo(this.container);
  32. this.offSpan = this.offLabel.children('span');
  33. this.onLabel = $("<label class='" + this.labelOnClass + "'>\n <span>" + this.checkedLabel + "</span>\n</label>").appendTo(this.container);
  34. this.onSpan = this.onLabel.children('span');
  35. return this.handle = $("<div class='" + this.handleClass + "'>\n <div class='" + this.handleRightClass + "'>\n <div class='" + this.handleCenterClass + "' />\n </div>\n</div>").appendTo(this.container);
  36. };
  37. iOSCheckbox.prototype.disableTextSelection = function() {
  38. if ($.browser.msie) {
  39. return $([this.handle, this.offLabel, this.onLabel, this.container]).attr("unselectable", "on");
  40. }
  41. };
  42. iOSCheckbox.prototype._getDimension = function(elem, dimension) {
  43. if ($.fn.actual != null) {
  44. return elem.actual(dimension);
  45. } else {
  46. return elem[dimension]();
  47. }
  48. };
  49. iOSCheckbox.prototype.optionallyResize = function(mode) {
  50. var newWidth, offLabelWidth, onLabelWidth;
  51. onLabelWidth = this._getDimension(this.onLabel, "width");
  52. offLabelWidth = this._getDimension(this.offLabel, "width");
  53. if (mode === "container") {
  54. newWidth = onLabelWidth > offLabelWidth ? onLabelWidth : offLabelWidth;
  55. newWidth += this._getDimension(this.handle, "width") + this.handleMargin;
  56. return this.container.css({
  57. width: newWidth
  58. });
  59. } else {
  60. newWidth = onLabelWidth > offLabelWidth ? onLabelWidth : offLabelWidth;
  61. return this.handle.css({
  62. width: newWidth
  63. });
  64. }
  65. };
  66. iOSCheckbox.prototype.onMouseDown = function(event) {
  67. var x;
  68. event.preventDefault();
  69. if (this.isDisabled()) {
  70. return;
  71. }
  72. x = event.pageX || event.originalEvent.changedTouches[0].pageX;
  73. iOSCheckbox.currentlyClicking = this.handle;
  74. iOSCheckbox.dragStartPosition = x;
  75. return iOSCheckbox.handleLeftOffset = parseInt(this.handle.css('left'), 10) || 0;
  76. };
  77. iOSCheckbox.prototype.onDragMove = function(event, x) {
  78. var newWidth, p;
  79. if (iOSCheckbox.currentlyClicking !== this.handle) {
  80. return;
  81. }
  82. p = (x + iOSCheckbox.handleLeftOffset - iOSCheckbox.dragStartPosition) / this.rightSide;
  83. if (p < 0) {
  84. p = 0;
  85. }
  86. if (p > 1) {
  87. p = 1;
  88. }
  89. newWidth = p * this.rightSide;
  90. this.handle.css({
  91. left: newWidth
  92. });
  93. this.onLabel.css({
  94. width: newWidth + this.handleRadius
  95. });
  96. this.offSpan.css({
  97. marginRight: -newWidth
  98. });
  99. return this.onSpan.css({
  100. marginLeft: -(1 - p) * this.rightSide
  101. });
  102. };
  103. iOSCheckbox.prototype.onDragEnd = function(event, x) {
  104. var p;
  105. if (iOSCheckbox.currentlyClicking !== this.handle) {
  106. return;
  107. }
  108. if (this.isDisabled()) {
  109. return;
  110. }
  111. if (iOSCheckbox.dragging) {
  112. p = (x - iOSCheckbox.dragStartPosition) / this.rightSide;
  113. this.elem.prop('checked', p >= 0.5);
  114. } else {
  115. this.elem.prop('checked', !this.elem.prop('checked'));
  116. }
  117. iOSCheckbox.currentlyClicking = null;
  118. iOSCheckbox.dragging = null;
  119. return this.didChange();
  120. };
  121. iOSCheckbox.prototype.refresh = function() {
  122. return this.didChange();
  123. };
  124. iOSCheckbox.prototype.didChange = function() {
  125. var new_left;
  126. if (typeof this.onChange === "function") {
  127. this.onChange(this.elem, this.elem.prop('checked'));
  128. }
  129. if (this.isDisabled()) {
  130. this.container.addClass(this.disabledClass);
  131. return false;
  132. } else {
  133. this.container.removeClass(this.disabledClass);
  134. }
  135. new_left = this.elem.prop('checked') ? this.rightSide : 0;
  136. this.handle.animate({
  137. left: new_left
  138. }, this.duration);
  139. this.onLabel.animate({
  140. width: new_left + this.handleRadius
  141. }, this.duration);
  142. this.offSpan.animate({
  143. marginRight: -new_left
  144. }, this.duration);
  145. return this.onSpan.animate({
  146. marginLeft: new_left - this.rightSide
  147. }, this.duration);
  148. };
  149. iOSCheckbox.prototype.attachEvents = function() {
  150. var localMouseMove, localMouseUp, self;
  151. self = this;
  152. localMouseMove = function(event) {
  153. return self.onGlobalMove.apply(self, arguments);
  154. };
  155. localMouseUp = function(event) {
  156. self.onGlobalUp.apply(self, arguments);
  157. $(document).unbind('mousemove touchmove', localMouseMove);
  158. return $(document).unbind('mouseup touchend', localMouseUp);
  159. };
  160. this.elem.change(function() {
  161. return self.refresh();
  162. });
  163. return this.container.bind('mousedown touchstart', function(event) {
  164. self.onMouseDown.apply(self, arguments);
  165. $(document).bind('mousemove touchmove', localMouseMove);
  166. return $(document).bind('mouseup touchend', localMouseUp);
  167. });
  168. };
  169. iOSCheckbox.prototype.initialPosition = function() {
  170. var containerWidth, offset;
  171. containerWidth = this._getDimension(this.container, "width");
  172. this.offLabel.css({
  173. width: containerWidth - this.containerRadius
  174. });
  175. offset = this.containerRadius + 1;
  176. if ($.browser.msie && $.browser.version < 7) {
  177. offset -= 3;
  178. }
  179. this.rightSide = containerWidth - this._getDimension(this.handle, "width") - offset;
  180. if (this.elem.is(':checked')) {
  181. this.handle.css({
  182. left: this.rightSide
  183. });
  184. this.onLabel.css({
  185. width: this.rightSide + this.handleRadius
  186. });
  187. this.offSpan.css({
  188. marginRight: -this.rightSide
  189. });
  190. } else {
  191. this.onLabel.css({
  192. width: 0
  193. });
  194. this.onSpan.css({
  195. marginLeft: -this.rightSide
  196. });
  197. }
  198. if (this.isDisabled()) {
  199. return this.container.addClass(this.disabledClass);
  200. }
  201. };
  202. iOSCheckbox.prototype.onGlobalMove = function(event) {
  203. var x;
  204. if (!(!this.isDisabled() && iOSCheckbox.currentlyClicking)) {
  205. return;
  206. }
  207. event.preventDefault();
  208. x = event.pageX || event.originalEvent.changedTouches[0].pageX;
  209. if (!iOSCheckbox.dragging && (Math.abs(iOSCheckbox.dragStartPosition - x) > this.dragThreshold)) {
  210. iOSCheckbox.dragging = true;
  211. }
  212. return this.onDragMove(event, x);
  213. };
  214. iOSCheckbox.prototype.onGlobalUp = function(event) {
  215. var x;
  216. if (!iOSCheckbox.currentlyClicking) {
  217. return;
  218. }
  219. event.preventDefault();
  220. x = event.pageX || event.originalEvent.changedTouches[0].pageX;
  221. this.onDragEnd(event, x);
  222. return false;
  223. };
  224. iOSCheckbox.defaults = {
  225. duration: 200,
  226. checkedLabel: 'ON',
  227. uncheckedLabel: 'OFF',
  228. resizeHandle: true,
  229. resizeContainer: true,
  230. disabledClass: 'iPhoneCheckDisabled',
  231. containerClass: 'iPhoneCheckContainer',
  232. labelOnClass: 'iPhoneCheckLabelOn',
  233. labelOffClass: 'iPhoneCheckLabelOff',
  234. handleClass: 'iPhoneCheckHandle',
  235. handleCenterClass: 'iPhoneCheckHandleCenter',
  236. handleRightClass: 'iPhoneCheckHandleRight',
  237. dragThreshold: 5,
  238. handleMargin: 15,
  239. handleRadius: 4,
  240. containerRadius: 5,
  241. dataName: "iphoneStyle",
  242. onChange: function() {}
  243. };
  244. return iOSCheckbox;
  245. })();
  246. $.iphoneStyle = this.iOSCheckbox = iOSCheckbox;
  247. $.fn.iphoneStyle = function() {
  248. var args, checkbox, dataName, existingControl, method, params, _i, _len, _ref, _ref2, _ref3, _ref4;
  249. args = 1 <= arguments.length ? __slice.call(arguments, 0) : [];
  250. dataName = (_ref = (_ref2 = args[0]) != null ? _ref2.dataName : void 0) != null ? _ref : iOSCheckbox.defaults.dataName;
  251. _ref3 = this.filter(':checkbox');
  252. for (_i = 0, _len = _ref3.length; _i < _len; _i++) {
  253. checkbox = _ref3[_i];
  254. existingControl = $(checkbox).data(dataName);
  255. if (existingControl != null) {
  256. method = args[0], params = 2 <= args.length ? __slice.call(args, 1) : [];
  257. if ((_ref4 = existingControl[method]) != null) {
  258. _ref4.apply(existingControl, params);
  259. }
  260. } else {
  261. new iOSCheckbox(checkbox, args[0]);
  262. }
  263. }
  264. return this;
  265. };
  266. $.fn.iOSCheckbox = function(options) {
  267. var opts;
  268. if (options == null) {
  269. options = {};
  270. }
  271. opts = $.extend({}, options, {
  272. resizeHandle: false,
  273. disabledClass: 'iOSCheckDisabled',
  274. containerClass: 'iOSCheckContainer',
  275. labelOnClass: 'iOSCheckLabelOn',
  276. labelOffClass: 'iOSCheckLabelOff',
  277. handleClass: 'iOSCheckHandle',
  278. handleCenterClass: 'iOSCheckHandleCenter',
  279. handleRightClass: 'iOSCheckHandleRight',
  280. dataName: 'iOSCheckbox'
  281. });
  282. return this.iphoneStyle(opts);
  283. };
  284. }).call(this);