Emanuele Marchi 10 роки тому
батько
коміт
12d4bc7aa5

+ 7 - 2
bower.json

@@ -3,8 +3,8 @@
   "description": "Turn checkboxes and radio buttons in toggle switches.",
   "version": "3.0.2",
   "main": [
-    "dist/js/bootstrap-switch.js",
-    "dist/css/bootstrap3/bootstrap-switch.css"
+    "./dist/js/bootstrap-switch.js",
+    "./dist/css/bootstrap3/bootstrap-switch.css"
   ],
   "ignore": [
     "docs",
@@ -19,6 +19,11 @@
     "package.json"
   ],
   "dependencies": {
+    "bootstrap": ">=2.3.2",
     "jquery": ">=1.9.0"
+  },
+  "devDependencies": {
+    "jquery": "~2.1.1",
+    "bootstrap": "~3.2.0"
   }
 }

+ 59 - 37
gulpfile.coffee

@@ -1,14 +1,20 @@
 gulp = require 'gulp'
-$ = require('gulp-load-plugins')()
+$ = require('gulp-load-plugins') lazy: false
+extend = require('util')._extend
+karma = require('karma').server
+karmaConfig = require './karma.json'
 pkg = require './package.json'
 name = pkg.name
 
-SOURCE_PATH = './src'
-DIST_PATH = './dist'
-DOCS_PATH = "./docs"
-SERVER_HOST = 'localhost'
-SERVER_PORT = 3000
-BANNER = """
+paths =
+  src: './src'
+  dist: './dist'
+  test: './test'
+  docs: "./"
+server =
+  host: 'localhost'
+  port: 3000
+banner = """
   /* ========================================================================
    * <%= pkg.name %> - v<%= pkg.version %>
    * <%= pkg.homepage %>
@@ -35,74 +41,89 @@ BANNER = """
 
 gulp.task 'coffee', ->
   gulp
-  .src "#{SOURCE_PATH}/coffee/#{name}.coffee"
-  .pipe $.changed "#{DIST_PATH}/js"
+  .src "#{paths.src}/coffee/#{name}.coffee"
+  .pipe $.changed "#{paths.dist}/js"
   .pipe $.coffeelint './coffeelint.json'
   .pipe $.coffeelint.reporter()
     .on 'error', $.util.log
   .pipe $.coffee()
     .on 'error', $.util.log
-  .pipe $.header BANNER, pkg: pkg
-  .pipe gulp.dest "#{DIST_PATH}/js"
+  .pipe $.header banner, pkg: pkg
+  .pipe gulp.dest "#{paths.dist}/js"
+  .pipe gulp.dest paths.test
   .pipe $.uglify()
-  .pipe $.header BANNER, pkg: pkg
+  .pipe $.header banner, pkg: pkg
   .pipe $.rename suffix: '.min'
-  .pipe gulp.dest "#{DIST_PATH}/js"
+  .pipe gulp.dest "#{paths.dist}/js"
 
 gulp.task 'less-bootstrap2', ->
   gulp
-  .src "#{SOURCE_PATH}/less/bootstrap2/build.less"
-  .pipe $.changed "#{DIST_PATH}/css/bootstrap2"
+  .src "#{paths.src}/less/bootstrap2/build.less"
+  .pipe $.changed "#{paths.dist}/css/bootstrap2"
   .pipe $.less()
     .on 'error', $.util.log
-  .pipe $.header BANNER, pkg: pkg
+  .pipe $.header banner, pkg: pkg
   .pipe $.rename basename: name
-  .pipe gulp.dest "#{DIST_PATH}/css/bootstrap2"
+  .pipe gulp.dest "#{paths.dist}/css/bootstrap2"
   .pipe $.less compress: true, cleancss: true
-  .pipe $.header BANNER, pkg: pkg
+  .pipe $.header banner, pkg: pkg
   .pipe $.rename suffix: '.min'
-  .pipe gulp.dest "#{DIST_PATH}/css/bootstrap2"
+  .pipe gulp.dest "#{paths.dist}/css/bootstrap2"
 
 gulp.task 'less-bootstrap3', ->
   gulp
-  .src "#{SOURCE_PATH}/less/bootstrap3/build.less"
-  .pipe $.changed "#{DIST_PATH}/css/bootstrap3"
+  .src "#{paths.src}/less/bootstrap3/build.less"
+  .pipe $.changed "#{paths.dist}/css/bootstrap3"
   .pipe $.less()
-  .pipe $.header BANNER, pkg: pkg
+  .pipe $.header banner, pkg: pkg
   .pipe $.rename basename: name
-  .pipe gulp.dest "#{DIST_PATH}/css/bootstrap3"
+  .pipe gulp.dest "#{paths.dist}/css/bootstrap3"
   .pipe $.less compress: true, cleancss: true
-  .pipe $.header BANNER, pkg: pkg
+  .pipe $.header banner, pkg: pkg
   .pipe $.rename suffix: '.min'
-  .pipe gulp.dest "#{DIST_PATH}/css/bootstrap3"
+  .pipe gulp.dest "#{paths.dist}/css/bootstrap3"
 
 gulp.task 'docs', ->
   gulp
-  .src "#{SOURCE_PATH}/docs/*.jade"
-  .pipe $.changed './'
+  .src "#{paths.src}/docs/*.jade"
+  .pipe $.changed paths.docs
   .pipe $.jade pretty: true
-  .pipe gulp.dest './'
+  .pipe gulp.dest paths.docs
+
+gulp.task 'test-coffee', ['coffee'], ->
+  gulp
+  .src "#{paths.src}/coffee/#{name}.tests.coffee"
+  .pipe $.changed paths.test
+  .pipe $.coffeelint './coffeelint.json'
+  .pipe $.coffeelint.reporter()
+    .on 'error', $.util.log
+  .pipe $.coffee()
+    .on 'error', $.util.log
+  .pipe gulp.dest paths.test
+
+gulp.task 'test-go', ['test-coffee'], (done) ->
+  karma.start extend(karmaConfig, singleRun: true), done
 
 gulp.task 'connect', ['docs'], ->
   $.connect.server
     root: [__dirname]
-    host: SERVER_HOST
-    port: SERVER_PORT
+    host: server.host
+    port: server.port
     livereload: true
 
 gulp.task 'open', ['connect'], ->
   gulp
   .src './index.html'
-  .pipe $.open '', url: "http://#{SERVER_HOST}:#{SERVER_PORT}"
+  .pipe $.open '', url: "http://#{server.host}:#{server.port}"
 
 gulp.task 'watch', ['connect'], ->
-  gulp.watch "#{SOURCE_PATH}/coffee/#{name}.coffee", ['coffee']
-  gulp.watch "#{SOURCE_PATH}/less/bootstrap2/*.less", ['less-bootstrap2']
-  gulp.watch "#{SOURCE_PATH}/less/bootstrap3/*.less", ['less-bootstrap3']
-  gulp.watch "#{SOURCE_PATH}/docs/*.jade", ['docs']
+  gulp.watch "#{paths.src}/coffee/#{name}.coffee", ['coffee']
+  gulp.watch "#{paths.src}/less/bootstrap2/*.less", ['less-bootstrap2']
+  gulp.watch "#{paths.src}/less/bootstrap3/*.less", ['less-bootstrap3']
+  gulp.watch "#{paths.src}/docs/*.jade", ['docs']
   gulp.watch [
-    "#{DIST_PATH}/js/**/*.js"
-    "#{DIST_PATH}/css/**/*.css"
+    "#{paths.dist}/js/**/*.js"
+    "#{paths.dist}/css/**/*.css"
     './*.html'
   ]
   .on 'change', (event) ->
@@ -112,4 +133,5 @@ gulp.task 'watch', ['connect'], ->
 gulp.task 'server', ['connect', 'open', 'watch']
 gulp.task 'less', ['less-bootstrap2', 'less-bootstrap3']
 gulp.task 'dist', ['coffee', 'less']
+gulp.task 'test', ['coffee', 'test-coffee', 'test-go']
 gulp.task 'default', ['dist', 'docs', 'server']

+ 19 - 0
karma.json

@@ -0,0 +1,19 @@
+{
+  "frameworks": ["jasmine"],
+  "files": [
+    "bower_components/jquery/dist/jquery.js",
+    "bower_components/bootstrap/dist/js/bootstrap.js",
+    "test/bootstrap-switch.js",
+    "test/bootstrap-switch.tests.js"
+  ],
+  "reporters": ["progress"],
+  "port": 9876,
+  "colors": true,
+  "autoWatch": true,
+  "browsers": ["Firefox"],
+  "singleRun": false,
+  "plugins": [
+    "karma-jasmine",
+    "karma-firefox-launcher"
+  ]
+}

+ 8 - 1
package.json

@@ -51,6 +51,13 @@
     "run-sequence": "~0.3.6",
     "gulp-connect": "~2.0.6",
     "coffee-script": "~1.7.1",
-    "gulp-changed": "~0.4.1"
+    "gulp-changed": "~0.4.1",
+    "karma": "~0.12.22",
+    "karma-firefox-launcher": "~0.1.3",
+    "karma-jasmine": "~0.1.5"
+  },
+  "scripts": {
+    "build": "gulp dist",
+    "test": "gulp test"
   }
 }

+ 27 - 0
src/coffee/bootstrap-switch.tests.coffee

@@ -0,0 +1,27 @@
+describe "Bootstrap Switch", ->
+
+  beforeEach ->
+    $.support.transition = false
+    $.fx.off = true
+
+  afterEach ->
+    $(".#{$.fn.bootstrapSwitch.defaults.baseClass}").bootstrapSwitch "destroy"
+
+  createElement = ->
+    $("<input>",
+      type: "checkbox"
+      class: "switch"
+    ).appendTo "body"
+
+  getOptions = ($element) ->
+    $element.data("bootstrap-switch").options
+
+  it "should set the default options as element options, except state", ->
+    $switch = createElement().prop("checked", true).bootstrapSwitch()
+    expect(getOptions($switch)).toEqual $.fn.bootstrapSwitch.defaults
+
+  it "should override default options with initialization ones", ->
+    $switch = createElement().prop("checked", false).bootstrapSwitch()
+    $switch2 = createElement().bootstrapSwitch state: false
+    expect(getOptions($switch).state).toBe false
+    expect(getOptions($switch2).state).toBe false

+ 0 - 1
src/test/bootstrap-switch.coffee

@@ -1 +0,0 @@
-describe "Bootstrap Switch", ->

+ 532 - 0
test/bootstrap-switch.js

@@ -0,0 +1,532 @@
+/* ========================================================================
+ * bootstrap-switch - v3.0.2
+ * http://www.bootstrap-switch.org
+ * ========================================================================
+ * Copyright 2012-2013 Mattia Larentis
+ *
+ * ========================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ========================================================================
+ */
+
+(function() {
+  var __slice = [].slice;
+
+  (function($, window) {
+    "use strict";
+    var BootstrapSwitch;
+    BootstrapSwitch = (function() {
+      function BootstrapSwitch(element, options) {
+        if (options == null) {
+          options = {};
+        }
+        this.$element = $(element);
+        this.options = $.extend({}, $.fn.bootstrapSwitch.defaults, {
+          state: this.$element.is(":checked"),
+          size: this.$element.data("size"),
+          animate: this.$element.data("animate"),
+          disabled: this.$element.is(":disabled"),
+          readonly: this.$element.is("[readonly]"),
+          indeterminate: this.$element.data("indeterminate"),
+          onColor: this.$element.data("on-color"),
+          offColor: this.$element.data("off-color"),
+          onText: this.$element.data("on-text"),
+          offText: this.$element.data("off-text"),
+          labelText: this.$element.data("label-text"),
+          baseClass: this.$element.data("base-class"),
+          wrapperClass: this.$element.data("wrapper-class"),
+          radioAllOff: this.$element.data("radio-all-off")
+        }, options);
+        this.$wrapper = $("<div>", {
+          "class": (function(_this) {
+            return function() {
+              var classes;
+              classes = ["" + _this.options.baseClass].concat(_this._getClasses(_this.options.wrapperClass));
+              classes.push(_this.options.state ? "" + _this.options.baseClass + "-on" : "" + _this.options.baseClass + "-off");
+              if (_this.options.size != null) {
+                classes.push("" + _this.options.baseClass + "-" + _this.options.size);
+              }
+              if (_this.options.animate) {
+                classes.push("" + _this.options.baseClass + "-animate");
+              }
+              if (_this.options.disabled) {
+                classes.push("" + _this.options.baseClass + "-disabled");
+              }
+              if (_this.options.readonly) {
+                classes.push("" + _this.options.baseClass + "-readonly");
+              }
+              if (_this.options.indeterminate) {
+                classes.push("" + _this.options.baseClass + "-indeterminate");
+              }
+              if (_this.$element.attr("id")) {
+                classes.push("" + _this.options.baseClass + "-id-" + (_this.$element.attr("id")));
+              }
+              return classes.join(" ");
+            };
+          })(this)()
+        });
+        this.$container = $("<div>", {
+          "class": "" + this.options.baseClass + "-container"
+        });
+        this.$on = $("<span>", {
+          html: this.options.onText,
+          "class": "" + this.options.baseClass + "-handle-on " + this.options.baseClass + "-" + this.options.onColor
+        });
+        this.$off = $("<span>", {
+          html: this.options.offText,
+          "class": "" + this.options.baseClass + "-handle-off " + this.options.baseClass + "-" + this.options.offColor
+        });
+        this.$label = $("<label>", {
+          html: this.options.labelText,
+          "class": "" + this.options.baseClass + "-label"
+        });
+        if (this.options.indeterminate) {
+          this.$element.prop("indeterminate", true);
+        }
+        this.$element.on("init.bootstrapSwitch", (function(_this) {
+          return function() {
+            return _this.options.onInit.apply(element, arguments);
+          };
+        })(this));
+        this.$element.on("switchChange.bootstrapSwitch", (function(_this) {
+          return function() {
+            return _this.options.onSwitchChange.apply(element, arguments);
+          };
+        })(this));
+        this.$container = this.$element.wrap(this.$container).parent();
+        this.$wrapper = this.$container.wrap(this.$wrapper).parent();
+        this.$element.before(this.$on).before(this.$label).before(this.$off).trigger("init.bootstrapSwitch");
+        this._elementHandlers();
+        this._handleHandlers();
+        this._labelHandlers();
+        this._formHandler();
+      }
+
+      BootstrapSwitch.prototype._constructor = BootstrapSwitch;
+
+      BootstrapSwitch.prototype.state = function(value, skip) {
+        if (typeof value === "undefined") {
+          return this.options.state;
+        }
+        if (this.options.disabled || this.options.readonly || this.options.indeterminate) {
+          return this.$element;
+        }
+        if (this.options.state && !this.options.radioAllOff && this.$element.is(':radio')) {
+          return this.$element;
+        }
+        value = !!value;
+        this.$element.prop("checked", value).trigger("change.bootstrapSwitch", skip);
+        return this.$element;
+      };
+
+      BootstrapSwitch.prototype.toggleState = function(skip) {
+        if (this.options.disabled || this.options.readonly || this.options.indeterminate) {
+          return this.$element;
+        }
+        return this.$element.prop("checked", !this.options.state).trigger("change.bootstrapSwitch", skip);
+      };
+
+      BootstrapSwitch.prototype.size = function(value) {
+        if (typeof value === "undefined") {
+          return this.options.size;
+        }
+        if (this.options.size != null) {
+          this.$wrapper.removeClass("" + this.options.baseClass + "-" + this.options.size);
+        }
+        if (value) {
+          this.$wrapper.addClass("" + this.options.baseClass + "-" + value);
+        }
+        this.options.size = value;
+        return this.$element;
+      };
+
+      BootstrapSwitch.prototype.animate = function(value) {
+        if (typeof value === "undefined") {
+          return this.options.animate;
+        }
+        value = !!value;
+        this.$wrapper[value ? "addClass" : "removeClass"]("" + this.options.baseClass + "-animate");
+        this.options.animate = value;
+        return this.$element;
+      };
+
+      BootstrapSwitch.prototype.disabled = function(value) {
+        if (typeof value === "undefined") {
+          return this.options.disabled;
+        }
+        value = !!value;
+        this.$wrapper[value ? "addClass" : "removeClass"]("" + this.options.baseClass + "-disabled");
+        this.$element.prop("disabled", value);
+        this.options.disabled = value;
+        return this.$element;
+      };
+
+      BootstrapSwitch.prototype.toggleDisabled = function() {
+        this.$element.prop("disabled", !this.options.disabled);
+        this.$wrapper.toggleClass("" + this.options.baseClass + "-disabled");
+        this.options.disabled = !this.options.disabled;
+        return this.$element;
+      };
+
+      BootstrapSwitch.prototype.readonly = function(value) {
+        if (typeof value === "undefined") {
+          return this.options.readonly;
+        }
+        value = !!value;
+        this.$wrapper[value ? "addClass" : "removeClass"]("" + this.options.baseClass + "-readonly");
+        this.$element.prop("readonly", value);
+        this.options.readonly = value;
+        return this.$element;
+      };
+
+      BootstrapSwitch.prototype.toggleReadonly = function() {
+        this.$element.prop("readonly", !this.options.readonly);
+        this.$wrapper.toggleClass("" + this.options.baseClass + "-readonly");
+        this.options.readonly = !this.options.readonly;
+        return this.$element;
+      };
+
+      BootstrapSwitch.prototype.indeterminate = function(value) {
+        if (typeof value === "undefined") {
+          return this.options.indeterminate;
+        }
+        value = !!value;
+        this.$wrapper[value ? "addClass" : "removeClass"]("" + this.options.baseClass + "-indeterminate");
+        this.$element.prop("indeterminate", value);
+        this.options.indeterminate = value;
+        return this.$element;
+      };
+
+      BootstrapSwitch.prototype.toggleIndeterminate = function() {
+        this.$element.prop("indeterminate", !this.options.indeterminate);
+        this.$wrapper.toggleClass("" + this.options.baseClass + "-indeterminate");
+        this.options.indeterminate = !this.options.indeterminate;
+        return this.$element;
+      };
+
+      BootstrapSwitch.prototype.onColor = function(value) {
+        var color;
+        color = this.options.onColor;
+        if (typeof value === "undefined") {
+          return color;
+        }
+        if (color != null) {
+          this.$on.removeClass("" + this.options.baseClass + "-" + color);
+        }
+        this.$on.addClass("" + this.options.baseClass + "-" + value);
+        this.options.onColor = value;
+        return this.$element;
+      };
+
+      BootstrapSwitch.prototype.offColor = function(value) {
+        var color;
+        color = this.options.offColor;
+        if (typeof value === "undefined") {
+          return color;
+        }
+        if (color != null) {
+          this.$off.removeClass("" + this.options.baseClass + "-" + color);
+        }
+        this.$off.addClass("" + this.options.baseClass + "-" + value);
+        this.options.offColor = value;
+        return this.$element;
+      };
+
+      BootstrapSwitch.prototype.onText = function(value) {
+        if (typeof value === "undefined") {
+          return this.options.onText;
+        }
+        this.$on.html(value);
+        this.options.onText = value;
+        return this.$element;
+      };
+
+      BootstrapSwitch.prototype.offText = function(value) {
+        if (typeof value === "undefined") {
+          return this.options.offText;
+        }
+        this.$off.html(value);
+        this.options.offText = value;
+        return this.$element;
+      };
+
+      BootstrapSwitch.prototype.labelText = function(value) {
+        if (typeof value === "undefined") {
+          return this.options.labelText;
+        }
+        this.$label.html(value);
+        this.options.labelText = value;
+        return this.$element;
+      };
+
+      BootstrapSwitch.prototype.baseClass = function(value) {
+        return this.options.baseClass;
+      };
+
+      BootstrapSwitch.prototype.wrapperClass = function(value) {
+        if (typeof value === "undefined") {
+          return this.options.wrapperClass;
+        }
+        if (!value) {
+          value = $.fn.bootstrapSwitch.defaults.wrapperClass;
+        }
+        this.$wrapper.removeClass(this._getClasses(this.options.wrapperClass).join(" "));
+        this.$wrapper.addClass(this._getClasses(value).join(" "));
+        this.options.wrapperClass = value;
+        return this.$element;
+      };
+
+      BootstrapSwitch.prototype.radioAllOff = function(value) {
+        if (typeof value === "undefined") {
+          return this.options.radioAllOff;
+        }
+        this.options.radioAllOff = value;
+        return this.$element;
+      };
+
+      BootstrapSwitch.prototype.onInit = function(value) {
+        if (typeof value === "undefined") {
+          return this.options.onInit;
+        }
+        if (!value) {
+          value = $.fn.bootstrapSwitch.defaults.onInit;
+        }
+        this.options.onInit = value;
+        return this.$element;
+      };
+
+      BootstrapSwitch.prototype.onSwitchChange = function(value) {
+        if (typeof value === "undefined") {
+          return this.options.onSwitchChange;
+        }
+        if (!value) {
+          value = $.fn.bootstrapSwitch.defaults.onSwitchChange;
+        }
+        this.options.onSwitchChange = value;
+        return this.$element;
+      };
+
+      BootstrapSwitch.prototype.destroy = function() {
+        var $form;
+        $form = this.$element.closest("form");
+        if ($form.length) {
+          $form.off("reset.bootstrapSwitch").removeData("bootstrap-switch");
+        }
+        this.$container.children().not(this.$element).remove();
+        this.$element.unwrap().unwrap().off(".bootstrapSwitch").removeData("bootstrap-switch");
+        return this.$element;
+      };
+
+      BootstrapSwitch.prototype._elementHandlers = function() {
+        return this.$element.on({
+          "change.bootstrapSwitch": (function(_this) {
+            return function(e, skip) {
+              var checked;
+              e.preventDefault();
+              e.stopImmediatePropagation();
+              checked = _this.$element.is(":checked");
+              if (checked === _this.options.state) {
+                return;
+              }
+              _this.options.state = checked;
+              _this.$wrapper.removeClass(checked ? "" + _this.options.baseClass + "-off" : "" + _this.options.baseClass + "-on").addClass(checked ? "" + _this.options.baseClass + "-on" : "" + _this.options.baseClass + "-off");
+              if (!skip) {
+                if (_this.$element.is(":radio")) {
+                  $("[name='" + (_this.$element.attr('name')) + "']").not(_this.$element).prop("checked", false).trigger("change.bootstrapSwitch", true);
+                }
+                return _this.$element.trigger("switchChange.bootstrapSwitch", [checked]);
+              }
+            };
+          })(this),
+          "focus.bootstrapSwitch": (function(_this) {
+            return function(e) {
+              e.preventDefault();
+              return _this.$wrapper.addClass("" + _this.options.baseClass + "-focused");
+            };
+          })(this),
+          "blur.bootstrapSwitch": (function(_this) {
+            return function(e) {
+              e.preventDefault();
+              return _this.$wrapper.removeClass("" + _this.options.baseClass + "-focused");
+            };
+          })(this),
+          "keydown.bootstrapSwitch": (function(_this) {
+            return function(e) {
+              if (!e.which || _this.options.disabled || _this.options.readonly || _this.options.indeterminate) {
+                return;
+              }
+              switch (e.which) {
+                case 37:
+                  e.preventDefault();
+                  e.stopImmediatePropagation();
+                  return _this.state(false);
+                case 39:
+                  e.preventDefault();
+                  e.stopImmediatePropagation();
+                  return _this.state(true);
+              }
+            };
+          })(this)
+        });
+      };
+
+      BootstrapSwitch.prototype._handleHandlers = function() {
+        this.$on.on("click.bootstrapSwitch", (function(_this) {
+          return function(e) {
+            _this.state(false);
+            return _this.$element.trigger("focus.bootstrapSwitch");
+          };
+        })(this));
+        return this.$off.on("click.bootstrapSwitch", (function(_this) {
+          return function(e) {
+            _this.state(true);
+            return _this.$element.trigger("focus.bootstrapSwitch");
+          };
+        })(this));
+      };
+
+      BootstrapSwitch.prototype._labelHandlers = function() {
+        return this.$label.on({
+          "mousemove.bootstrapSwitch touchmove.bootstrapSwitch": (function(_this) {
+            return function(e) {
+              var left, pageX, percent, right;
+              if (!_this.isLabelDragging) {
+                return;
+              }
+              e.preventDefault();
+              _this.isLabelDragged = true;
+              pageX = e.pageX || e.originalEvent.touches[0].pageX;
+              percent = ((pageX - _this.$wrapper.offset().left) / _this.$wrapper.width()) * 100;
+              left = 25;
+              right = 75;
+              if (_this.options.animate) {
+                _this.$wrapper.removeClass("" + _this.options.baseClass + "-animate");
+              }
+              if (percent < left) {
+                percent = left;
+              } else if (percent > right) {
+                percent = right;
+              }
+              _this.$container.css("margin-left", "" + (percent - right) + "%");
+              return _this.$element.trigger("focus.bootstrapSwitch");
+            };
+          })(this),
+          "mousedown.bootstrapSwitch touchstart.bootstrapSwitch": (function(_this) {
+            return function(e) {
+              if (_this.isLabelDragging || _this.options.disabled || _this.options.readonly || _this.options.indeterminate) {
+                return;
+              }
+              e.preventDefault();
+              _this.isLabelDragging = true;
+              return _this.$element.trigger("focus.bootstrapSwitch");
+            };
+          })(this),
+          "mouseup.bootstrapSwitch touchend.bootstrapSwitch": (function(_this) {
+            return function(e) {
+              if (!_this.isLabelDragging) {
+                return;
+              }
+              e.preventDefault();
+              if (_this.isLabelDragged) {
+                _this.isLabelDragged = false;
+                _this.state(parseInt(_this.$container.css("margin-left"), 10) > -(_this.$container.width() / 6));
+                if (_this.options.animate) {
+                  _this.$wrapper.addClass("" + _this.options.baseClass + "-animate");
+                }
+                _this.$container.css("margin-left", "");
+              } else {
+                _this.state(!_this.options.state);
+              }
+              return _this.isLabelDragging = false;
+            };
+          })(this),
+          "mouseleave.bootstrapSwitch": (function(_this) {
+            return function(e) {
+              return _this.$label.trigger("mouseup.bootstrapSwitch");
+            };
+          })(this)
+        });
+      };
+
+      BootstrapSwitch.prototype._formHandler = function() {
+        var $form;
+        $form = this.$element.closest("form");
+        if ($form.data("bootstrap-switch")) {
+          return;
+        }
+        return $form.on("reset.bootstrapSwitch", function() {
+          return window.setTimeout(function() {
+            return $form.find("input").filter(function() {
+              return $(this).data("bootstrap-switch");
+            }).each(function() {
+              return $(this).bootstrapSwitch("state", this.checked);
+            });
+          }, 1);
+        }).data("bootstrap-switch", true);
+      };
+
+      BootstrapSwitch.prototype._getClasses = function(classes) {
+        var c, cls, _i, _len;
+        if (!$.isArray(classes)) {
+          return ["" + this.options.baseClass + "-" + classes];
+        }
+        cls = [];
+        for (_i = 0, _len = classes.length; _i < _len; _i++) {
+          c = classes[_i];
+          cls.push("" + this.options.baseClass + "-" + c);
+        }
+        return cls;
+      };
+
+      return BootstrapSwitch;
+
+    })();
+    $.fn.bootstrapSwitch = function() {
+      var args, option, ret;
+      option = arguments[0], args = 2 <= arguments.length ? __slice.call(arguments, 1) : [];
+      ret = this;
+      this.each(function() {
+        var $this, data;
+        $this = $(this);
+        data = $this.data("bootstrap-switch");
+        if (!data) {
+          $this.data("bootstrap-switch", data = new BootstrapSwitch(this, option));
+        }
+        if (typeof option === "string") {
+          return ret = data[option].apply(data, args);
+        }
+      });
+      return ret;
+    };
+    $.fn.bootstrapSwitch.Constructor = BootstrapSwitch;
+    return $.fn.bootstrapSwitch.defaults = {
+      state: true,
+      size: null,
+      animate: true,
+      disabled: false,
+      readonly: false,
+      indeterminate: false,
+      onColor: "primary",
+      offColor: "default",
+      onText: "ON",
+      offText: "OFF",
+      labelText: "&nbsp;",
+      baseClass: "bootstrap-switch",
+      wrapperClass: "wrapper",
+      radioAllOff: false,
+      onInit: function() {},
+      onSwitchChange: function() {}
+    };
+  })(window.jQuery, window);
+
+}).call(this);

+ 36 - 0
test/bootstrap-switch.tests.js

@@ -0,0 +1,36 @@
+(function() {
+  describe("Bootstrap Switch", function() {
+    var createElement, getOptions;
+    beforeEach(function() {
+      $.support.transition = false;
+      return $.fx.off = true;
+    });
+    afterEach(function() {
+      return $("." + $.fn.bootstrapSwitch.defaults.baseClass).bootstrapSwitch("destroy");
+    });
+    createElement = function() {
+      return $("<input>", {
+        type: "checkbox",
+        "class": "switch"
+      }).appendTo("body");
+    };
+    getOptions = function($element) {
+      return $element.data("bootstrap-switch").options;
+    };
+    it("should set the default options as element options, except state", function() {
+      var $switch;
+      $switch = createElement().prop("checked", true).bootstrapSwitch();
+      return expect(getOptions($switch)).toEqual($.fn.bootstrapSwitch.defaults);
+    });
+    return it("should override default options with initialization ones", function() {
+      var $switch, $switch2;
+      $switch = createElement().prop("checked", false).bootstrapSwitch();
+      $switch2 = createElement().bootstrapSwitch({
+        state: false
+      });
+      expect(getOptions($switch).state).toBe(false);
+      return expect(getOptions($switch2).state).toBe(false);
+    });
+  });
+
+}).call(this);