bootstrap-switch.js 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458
  1. /* ========================================================================
  2. * bootstrap-switch - v2.0.1
  3. * http://www.bootstrap-switch.org
  4. * ========================================================================
  5. * Copyright 2012-2013 Mattia Larentis
  6. *
  7. * ========================================================================
  8. * Licensed under the Apache License, Version 2.0 (the "License");
  9. * you may not use this file except in compliance with the License.
  10. * You may obtain a copy of the License at
  11. *
  12. * http://www.apache.org/licenses/LICENSE-2.0
  13. *
  14. * Unless required by applicable law or agreed to in writing, software
  15. * distributed under the License is distributed on an "AS IS" BASIS,
  16. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  17. * See the License for the specific language governing permissions and
  18. * limitations under the License.
  19. * ========================================================================
  20. */
  21. (function() {
  22. var __slice = [].slice;
  23. (function($, window) {
  24. "use strict";
  25. var BootstrapSwitch;
  26. BootstrapSwitch = (function() {
  27. function BootstrapSwitch(element, option) {
  28. var _this = this;
  29. this.$element = $(element);
  30. this.$switchLeft = $("<span>", {
  31. "class": function() {
  32. var cls, color;
  33. cls = "switch-left";
  34. color = _this.$element.data("on-color");
  35. if (color != null) {
  36. cls += " switch-" + color;
  37. }
  38. return cls;
  39. },
  40. html: function() {
  41. var html, text;
  42. html = "ON";
  43. text = _this.$element.data("on-text");
  44. if (text != null) {
  45. html = text;
  46. }
  47. return html;
  48. }
  49. });
  50. this.$switchRight = $("<span>", {
  51. "class": function() {
  52. var cls, color;
  53. cls = "switch-right";
  54. color = _this.$element.data("off-color");
  55. if (color != null) {
  56. cls += " switch-" + color;
  57. }
  58. return cls;
  59. },
  60. html: function() {
  61. var html, text;
  62. html = "OFF";
  63. text = _this.$element.data("off-text");
  64. if (text != null) {
  65. html = text;
  66. }
  67. return html;
  68. }
  69. });
  70. this.$label = $("<label>", {
  71. "for": this.$element.attr("id"),
  72. html: function() {
  73. var html, text;
  74. html = "&nbsp;";
  75. text = _this.$element.data("label-text");
  76. if (text != null) {
  77. html = text;
  78. }
  79. return html;
  80. }
  81. });
  82. this.$wrapper = $("<div>", {
  83. "class": function() {
  84. var classes, cls, _i, _len, _ref;
  85. classes = ["has-switch"];
  86. if (_this.$element.attr("class")) {
  87. _ref = ["mini", "small", "large"];
  88. for (_i = 0, _len = _ref.length; _i < _len; _i++) {
  89. cls = _ref[_i];
  90. if (_this.$element.hasClass("switch-" + cls)) {
  91. classes.push("switch-" + cls);
  92. }
  93. }
  94. }
  95. classes.push(_this.$element.is(":checked") ? "switch-on" : "switch-off");
  96. if (_this.$element.data("animate") !== false) {
  97. classes.push("switch-animate");
  98. }
  99. if (_this.$element.is(":disabled") || _this.$element.is("[readonly]")) {
  100. classes.push("disabled");
  101. }
  102. return classes.join(" ");
  103. },
  104. tabindex: 0
  105. });
  106. this.$div = this.$element.wrap($("<div>")).parent();
  107. this.$wrapper = this.$div.wrap(this.$wrapper).parent();
  108. this.$element.before(this.$switchLeft).before(this.$label).before(this.$switchRight);
  109. this._elementHandlers();
  110. this._wrapperHandlers();
  111. this._switchesHandlers();
  112. this._labelHandlers();
  113. this._form();
  114. }
  115. BootstrapSwitch.prototype._constructor = BootstrapSwitch;
  116. BootstrapSwitch.prototype.state = function(value, skip) {
  117. if (typeof value === "undefined") {
  118. return this.$element.is(":checked");
  119. }
  120. this.$element.prop("checked", !!value).trigger("change", skip);
  121. return this.$element;
  122. };
  123. BootstrapSwitch.prototype.toggleState = function(skip) {
  124. this.$element.prop("checked", !this.$element.is(":checked")).trigger("change", skip);
  125. return this.$element;
  126. };
  127. /*
  128. TODO: refactor
  129. toggleRadioState: (uncheck, skip) ->
  130. $element = @$element.not ":checked"
  131. if uncheck
  132. $element.trigger "change", skip
  133. else
  134. $element.prop("checked", not @$element.is ":checked").trigger "change", skip
  135. @$element
  136. */
  137. BootstrapSwitch.prototype.disabled = function(value) {
  138. if (typeof value === "undefined") {
  139. return this.$element.is(":disabled");
  140. }
  141. value = !!value;
  142. this.$wrapper[value ? "addClass" : "removeClass"]("disabled");
  143. this.$element.prop("disabled", value);
  144. return this.$element;
  145. };
  146. BootstrapSwitch.prototype.toggleDisabled = function() {
  147. this.$element.prop("disabled", !this.$element.is(":disabled"));
  148. this.$wrapper.toggleClass("disabled");
  149. return this.$element;
  150. };
  151. BootstrapSwitch.prototype.readOnly = function(value) {
  152. if (typeof value === "undefined") {
  153. return this.$element.is("[readonly]");
  154. }
  155. if (readonly) {
  156. this.$wrapper.addClass("disabled");
  157. this.$element.prop("readonly", true);
  158. } else {
  159. this.$wrapper.removeClass("disabled");
  160. this.$element.prop("readonly", false);
  161. }
  162. return this.$element;
  163. };
  164. BootstrapSwitch.prototype.toggleReadOnly = function() {
  165. this.$element.prop("readonly", !this.$element.is("[readonly]")).parents(".has-switch").toggleClass("disabled");
  166. return this.$element;
  167. };
  168. BootstrapSwitch.prototype.labelText = function(value) {
  169. this.$element.siblings("label").html(value || "&nbsp");
  170. return this.$element;
  171. };
  172. BootstrapSwitch.prototype.onText = function(value) {
  173. if (typeof value === "undefined") {
  174. return this.$switchLeft.html();
  175. }
  176. this.$switchLeft.html(value);
  177. return this.$element;
  178. };
  179. BootstrapSwitch.prototype.offText = function(value) {
  180. if (typeof value === "undefined") {
  181. return this.$switchRight.html();
  182. }
  183. this.$switchRight.html(value);
  184. return this.$element;
  185. };
  186. BootstrapSwitch.prototype.onColor = function(value) {
  187. var color;
  188. color = this.$element.data("on-color");
  189. if (typeof value === "undefined") {
  190. return color;
  191. }
  192. if (color != null) {
  193. this.$switchLeft.removeClass("switch-" + color);
  194. }
  195. this.$switchLeft.addClass("switch-" + value);
  196. this.$element.data("on-color", value);
  197. return this.$element;
  198. };
  199. BootstrapSwitch.prototype.offColor = function(value) {
  200. var color;
  201. color = this.$element.data("off-color");
  202. if (typeof value === "undefined") {
  203. return color;
  204. }
  205. if (color != null) {
  206. this.$switchRight.removeClass("switch-" + color);
  207. }
  208. this.$switchRight.addClass("switch-" + value);
  209. this.$element.data("off-color", value);
  210. return this.$element;
  211. };
  212. BootstrapSwitch.prototype.animate = function(value) {
  213. if (typeof value === "undefined") {
  214. return this.$element.data("animate");
  215. }
  216. value = !!value;
  217. this.$wrapper[value ? "addClass" : "removeClass"]("switch-animate");
  218. this.$element.data("animate", value);
  219. return this.$element;
  220. };
  221. BootstrapSwitch.prototype.size = function(value) {
  222. var cls, _i, _len, _ref;
  223. if (typeof value === "undefined") {
  224. return this.$wrapper.hasClass("switch-" + value);
  225. }
  226. _ref = ["mini", "small", "large"];
  227. for (_i = 0, _len = _ref.length; _i < _len; _i++) {
  228. cls = _ref[_i];
  229. this.$wrapper[cls !== value ? "removeClass" : "addClass"]("switch-" + cls);
  230. }
  231. return this.$element;
  232. };
  233. BootstrapSwitch.prototype.destroy = function() {
  234. var $form;
  235. $form = this.$element.closest("form");
  236. this.$div.children().not(this.$element).remove();
  237. this.$element.unwrap().unwrap().off("change");
  238. if ($form.length) {
  239. $form.off("reset").removeData("bootstrap-switch");
  240. }
  241. return this.$element;
  242. };
  243. BootstrapSwitch.prototype._elementHandlers = function() {
  244. var _this = this;
  245. return this.$element.on("change", function(e, skip) {
  246. var isChecked, state;
  247. e.preventDefault();
  248. isChecked = _this.$element.is(":checked");
  249. state = _this.$wrapper.hasClass("switch-off");
  250. _this.$div.css("margin-left", "");
  251. if (state !== isChecked) {
  252. return;
  253. }
  254. if (isChecked) {
  255. _this.$wrapper.removeClass("switch-off").addClass("switch-on");
  256. } else {
  257. _this.$wrapper.removeClass("switch-on").addClass("switch-off");
  258. }
  259. if (_this.$element.data("animate") !== false) {
  260. _this.$wrapper.addClass("switch-animate");
  261. }
  262. if (typeof skip === "boolean" && skip) {
  263. return;
  264. }
  265. return _this.$element.trigger("switch-change", {
  266. el: _this.$element,
  267. value: isChecked
  268. });
  269. });
  270. };
  271. BootstrapSwitch.prototype._wrapperHandlers = function() {
  272. var _this = this;
  273. return this.$wrapper.on("keydown", function(e) {
  274. if (!e.which || _this.$element.is(":disabled") || _this.$element.is("[readonly]")) {
  275. return;
  276. }
  277. switch (e.which) {
  278. case 32:
  279. e.preventDefault();
  280. return _this.toggleState();
  281. case 37:
  282. e.preventDefault();
  283. if (_this.$element.is(":checked")) {
  284. return _this.toggleState();
  285. }
  286. break;
  287. case 39:
  288. e.preventDefault();
  289. if (!_this.$element.is(":checked")) {
  290. return _this.toggleState();
  291. }
  292. }
  293. });
  294. };
  295. BootstrapSwitch.prototype._switchesHandlers = function() {
  296. var _this = this;
  297. this.$switchLeft.on("click", function() {
  298. return _this.toggleState();
  299. });
  300. return this.$switchRight.on("click", function() {
  301. return _this.toggleState();
  302. });
  303. };
  304. BootstrapSwitch.prototype._labelHandlers = function() {
  305. /*
  306. @$label.on "click", =>
  307. e.preventDefault()
  308. e.stopImmediatePropagation()
  309. @toggleState()
  310. */
  311. var _this = this;
  312. return this.$label.on("click", function(e) {
  313. e.preventDefault();
  314. e.stopImmediatePropagation();
  315. _this.$wrapper.removeClass("switch-animate");
  316. if (_this.moving) {
  317. return;
  318. }
  319. _this.$label.on("mousemove", function(e) {
  320. var left, percent, relativeX, right;
  321. relativeX = (e.pageX || e.originalEvent.targetTouches[0].pageX) - _this.$wrapper.offset().left;
  322. percent = (relativeX / _this.$wrapper.width()) * 100;
  323. left = 25;
  324. right = 75;
  325. _this.moving = true;
  326. if (percent < left) {
  327. percent = left;
  328. } else if (percent > right) {
  329. percent = right;
  330. }
  331. return _this.$div.css("margin-left", "" + (percent - right) + "%");
  332. });
  333. _this.$label.on("mouseup mouseleave", function(e) {
  334. e.preventDefault();
  335. e.stopImmediatePropagation();
  336. _this.$element.prop("checked", parseInt(_this.$div.css("margin-left"), 10) > -25).trigger("change");
  337. return _this.$label.off("mousemove");
  338. });
  339. return _this.$label.trigger("mousemove");
  340. });
  341. /*
  342. @$label.on
  343. "click touchstart": (e) =>
  344. @moving = false
  345. e.preventDefault()
  346. e.stopImmediatePropagation()
  347. @$wrapper.removeClass "switch-animate"
  348. if @moving
  349. @$element.prop "checked", (parseInt(@$div.css("margin-left"), 10) > -25)
  350. else
  351. @$element.prop "checked", not @$element.is(":checked")
  352. @$element.trigger "change"
  353. # @$label.off "click" if @$element.is(":disabled") or @$element.is("[readonly]") or @$element.hasClass "radio-no-uncheck"
  354. "mousemove touchmove": (e) =>
  355. relativeX = (e.pageX or e.originalEvent.targetTouches[0].pageX) - @$wrapper.offset().left
  356. percent = (relativeX / @$wrapper.width()) * 100
  357. left = 25
  358. right = 75
  359. @moving = true
  360. if percent < left
  361. percent = left
  362. else if percent > right
  363. percent = right
  364. @$div.css "margin-left", "#{percent - right}%"
  365. "click touchend": (e) =>
  366. e.stopImmediatePropagation()
  367. e.preventDefault()
  368. @$label.off "mouseleave"
  369. mouseleave: (e) =>
  370. e.preventDefault()
  371. e.stopImmediatePropagation()
  372. @$label.off("mouseleave mousemove").trigger "mouseup"
  373. @$element.prop("checked", (parseInt(@$div.css("margin-left"), 10) > -25)).trigger "change"
  374. mouseup: (e) =>
  375. e.stopImmediatePropagation()
  376. e.preventDefault()
  377. @$label.trigger "mouseleave"
  378. */
  379. };
  380. BootstrapSwitch.prototype._form = function() {
  381. var $form;
  382. $form = this.$element.closest("form");
  383. if ($form.data("bootstrap-switch")) {
  384. return;
  385. }
  386. return $form.data("bootstrap-switch", true).on("reset", function() {
  387. return window.setTimeout(function() {
  388. return $form.find(".has-switch").each(function() {
  389. var $input;
  390. $input = $(this).find("input");
  391. return $input.prop("checked", $input.is(":checked")).trigger("change");
  392. });
  393. }, 1);
  394. });
  395. };
  396. return BootstrapSwitch;
  397. })();
  398. return $.fn.extend({
  399. bootstrapSwitch: function() {
  400. var args, option, ret;
  401. option = arguments[0], args = 2 <= arguments.length ? __slice.call(arguments, 1) : [];
  402. ret = this;
  403. this.each(function() {
  404. var $this, data;
  405. $this = $(this);
  406. data = $this.data("bootstrap-switch");
  407. if (!data) {
  408. $this.data("bootstrap-switch", (data = new BootstrapSwitch(this, option)));
  409. }
  410. if (typeof option === "string") {
  411. return ret = data[option].apply(data, args);
  412. }
  413. });
  414. return ret;
  415. }
  416. });
  417. })(window.jQuery, window);
  418. }).call(this);