Explorar el Código

fixed: allow users to prevent switches changing status returning false from the onSwitchChange function

Mattia Larentis hace 10 años
padre
commit
61b2289187

La diferencia del archivo ha sido suprimido porque es demasiado grande
+ 0 - 0
dist/css/bootstrap2/bootstrap-switch.min.css


La diferencia del archivo ha sido suprimido porque es demasiado grande
+ 0 - 0
dist/css/bootstrap3/bootstrap-switch.min.css


+ 36 - 3
dist/js/bootstrap-switch.js

@@ -32,6 +32,7 @@
         }
         this.$element = $(element);
         this.options = $.extend({}, $.fn.bootstrapSwitch.defaults, {
+          prevOption: {},
           state: this.$element.is(":checked"),
           size: this.$element.data("size"),
           animate: this.$element.data("animate"),
@@ -99,8 +100,14 @@
           };
         })(this));
         this.$element.on("switchChange.bootstrapSwitch", (function(_this) {
-          return function() {
-            return _this.options.onSwitchChange.apply(element, arguments);
+          return function(e) {
+            if (false === _this.options.onSwitchChange.apply(element, arguments)) {
+              if (_this.$element.is(":radio")) {
+                return $("[name='" + (_this.$element.attr('name')) + "']").trigger("previousState.bootstrapSwitch", true);
+              } else {
+                return _this.$element.trigger("previousState.bootstrapSwitch", true);
+              }
+            }
           };
         })(this));
         this.$container = this.$element.wrap(this.$container).parent();
@@ -120,6 +127,10 @@
 
       BootstrapSwitch.prototype._constructor = BootstrapSwitch;
 
+      BootstrapSwitch.prototype.setPrevOptions = function() {
+        return this.options.prevOption = $.extend(true, {}, this.options);
+      };
+
       BootstrapSwitch.prototype.state = function(value, skip) {
         if (typeof value === "undefined") {
           return this.options.state;
@@ -130,6 +141,11 @@
         if (this.options.state && !this.options.radioAllOff && this.$element.is(":radio")) {
           return this.$element;
         }
+        if (this.$element.is(":radio")) {
+          $("[name='" + (this.$element.attr('name')) + "']").trigger("setPreviousOptions.bootstrapSwitch");
+        } else {
+          this.$element.trigger("setPreviousOptions.bootstrapSwitch");
+        }
         if (this.options.indeterminate) {
           this.indeterminate(false);
         }
@@ -466,6 +482,7 @@
         var init, initInterval;
         init = (function(_this) {
           return function() {
+            _this.setPrevOptions();
             _this._width();
             return _this._containerPosition(null, function() {
               if (_this.options.animate) {
@@ -489,6 +506,20 @@
 
       BootstrapSwitch.prototype._elementHandlers = function() {
         return this.$element.on({
+          "setPreviousOptions.bootstrapSwitch": (function(_this) {
+            return function(e) {
+              return _this.setPrevOptions();
+            };
+          })(this),
+          "previousState.bootstrapSwitch": (function(_this) {
+            return function(e) {
+              _this.options = _this.options.prevOption;
+              if (_this.options.indeterminate) {
+                _this.$wrapper.addClass(_this.options.baseClass + "-indeterminate");
+              }
+              return _this.$element.prop("checked", _this.options.state).trigger("change.bootstrapSwitch", true);
+            };
+          })(this),
           "change.bootstrapSwitch": (function(_this) {
             return function(e, skip) {
               var state;
@@ -687,7 +718,8 @@
       return ret;
     };
     $.fn.bootstrapSwitch.Constructor = BootstrapSwitch;
-    return $.fn.bootstrapSwitch.defaults = {
+    $.fn.bootstrapSwitch.defaults = {
+      prevOption: {},
       state: true,
       size: null,
       animate: true,
@@ -708,6 +740,7 @@
       onInit: function() {},
       onSwitchChange: function() {}
     };
+    return $.fn.bootstrapSwitch.defaults.prevOption = $.extend(true, {}, $.fn.bootstrapSwitch.defaults);
   })(window.jQuery, window);
 
 }).call(this);

La diferencia del archivo ha sido suprimido porque es demasiado grande
+ 0 - 0
dist/js/bootstrap-switch.min.js


La diferencia del archivo ha sido suprimido porque es demasiado grande
+ 2 - 2
docs/css/bootstrap.min.css


La diferencia del archivo ha sido suprimido porque es demasiado grande
+ 2 - 2
docs/js/bootstrap.min.js


La diferencia del archivo ha sido suprimido porque es demasiado grande
+ 0 - 1
docs/js/jquery.min.js


+ 2 - 2
karma.json

@@ -1,8 +1,8 @@
 {
   "frameworks": ["jasmine"],
   "files": [
-    "bower_components/jquery/dist/jquery.js",
-    "bower_components/bootstrap/dist/js/bootstrap.js",
+    "components/jquery/dist/jquery.js",
+    "components/bootstrap/dist/js/bootstrap.js",
     "test/bootstrap-switch.js",
     "test/bootstrap-switch.tests.js"
   ],

+ 1 - 1
options.html

@@ -219,7 +219,7 @@
               <td>onSwitchChange</td>
               <td></td>
               <td>Function</td>
-              <td>Callback function to execute on switch state change</td>
+              <td>Callback function to execute on switch state change. If false is returned, the status will be reverted, otherwise nothing changes</td>
               <td>Function</td>
               <td>
                 <pre><code class="javascript">function(event, state) {}</code></pre>

+ 29 - 2
src/coffee/bootstrap-switch.coffee

@@ -5,6 +5,7 @@ do ($ = window.jQuery, window) ->
     constructor: (element, options = {}) ->
       @$element = $ element
       @options = $.extend {}, $.fn.bootstrapSwitch.defaults,
+        prevOption: {}
         state: @$element.is ":checked"
         size: @$element.data "size"
         animate: @$element.data "animate"
@@ -49,7 +50,13 @@ do ($ = window.jQuery, window) ->
 
       # set up events
       @$element.on "init.bootstrapSwitch", => @options.onInit.apply element, arguments
-      @$element.on "switchChange.bootstrapSwitch", => @options.onSwitchChange.apply element, arguments
+      @$element.on "switchChange.bootstrapSwitch", (e) =>
+        if false == @options.onSwitchChange.apply element, arguments
+          if @$element.is ":radio"
+            $("[name='#{@$element.attr('name')}']")
+            .trigger "previousState.bootstrapSwitch", true
+          else
+            @$element.trigger "previousState.bootstrapSwitch", true
 
       # reassign elements after dom modification
       @$container = @$element.wrap(@$container).parent()
@@ -78,15 +85,23 @@ do ($ = window.jQuery, window) ->
 
     _constructor: BootstrapSwitch
 
+    setPrevOptions: ->
+      @options.prevOption = $.extend(true, {}, @options)
+
     state: (value, skip) ->
       return @options.state  if typeof value is "undefined"
       return @$element  if @options.disabled or @options.readonly
       return @$element  if @options.state and not @options.radioAllOff and @$element.is ":radio"
 
+      if @$element.is ":radio"
+        $("[name='#{@$element.attr('name')}']")
+        .trigger "setPreviousOptions.bootstrapSwitch"
+      else
+        @$element.trigger "setPreviousOptions.bootstrapSwitch"
+
       # remove indeterminate
       @indeterminate false  if @options.indeterminate
       value = not not value
-
       @$element.prop("checked", value).trigger "change.bootstrapSwitch", skip
       @$element
 
@@ -344,6 +359,7 @@ do ($ = window.jQuery, window) ->
 
     _init: ->
       init = =>
+        @setPrevOptions()
         @_width()
         @_containerPosition null, =>
           @$wrapper.addClass "#{@options.baseClass}-animate"  if @options.animate
@@ -358,6 +374,15 @@ do ($ = window.jQuery, window) ->
 
     _elementHandlers: ->
       @$element.on
+        "setPreviousOptions.bootstrapSwitch": (e) =>
+          @setPrevOptions()
+
+        "previousState.bootstrapSwitch": (e) =>
+          @options = @options.prevOption
+
+          @$wrapper.addClass "#{@options.baseClass}-indeterminate"  if @options.indeterminate
+          @$element.prop("checked", @options.state).trigger "change.bootstrapSwitch", true
+
         "change.bootstrapSwitch": (e, skip) =>
           e.preventDefault()
           e.stopImmediatePropagation()
@@ -507,6 +532,7 @@ do ($ = window.jQuery, window) ->
 
   $.fn.bootstrapSwitch.Constructor = BootstrapSwitch
   $.fn.bootstrapSwitch.defaults =
+    prevOption: {}
     state: true
     size: null
     animate: true
@@ -526,3 +552,4 @@ do ($ = window.jQuery, window) ->
     wrapperClass: "wrapper"
     onInit: ->
     onSwitchChange: ->
+  $.fn.bootstrapSwitch.defaults.prevOption = $.extend(true, {}, $.fn.bootstrapSwitch.defaults)

+ 73 - 5
src/coffee/bootstrap-switch.tests.coffee

@@ -1,4 +1,4 @@
-describe "Bootstrap Switch", ->
+describe "Bootstrap Switch:", ->
 
   beforeEach ->
     $.support.transition = false
@@ -7,21 +7,89 @@ describe "Bootstrap Switch", ->
   afterEach ->
     $(".#{$.fn.bootstrapSwitch.defaults.baseClass}").bootstrapSwitch "destroy"
 
-  createElement = ->
+  createCheckbox = ->
     $("<input>",
       type: "checkbox"
       class: "switch"
     ).appendTo "body"
 
+  createRadio = ->
+    $("<input>",
+      type: "radio"
+      name: "name"
+      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()
+    $switch = createCheckbox().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
+    $switch = createCheckbox().prop("checked", false).bootstrapSwitch()
+    $switch2 = createCheckbox().bootstrapSwitch state: false
     expect(getOptions($switch).state).toBe false
     expect(getOptions($switch2).state).toBe false
+
+  describe "The Checkbox Bootstrap Switch", ->
+    it "should conserve its state if onSwitchChange returns false", ->
+      $switch = createCheckbox().bootstrapSwitch
+        onSwitchChange:(e, s) ->
+          expect(s).toEqual true
+          false
+      $indeterminateSwitch = createCheckbox().data("indeterminate", true).bootstrapSwitch
+        onSwitchChange:(e, s) ->
+          expect(s).toEqual true
+          false
+
+      $switch.click()
+      $indeterminateSwitch.click()
+
+      expect($switch.bootstrapSwitch('state')).toEqual false
+      expect($indeterminateSwitch.bootstrapSwitch('state')).toEqual false
+
+    it "should change its state if onSwitchChange not returns false", ->
+      $switch = createCheckbox().bootstrapSwitch
+        onSwitchChange:(e, s) -> expect(s).toEqual true
+
+      $switch.click()
+
+      expect($switch.bootstrapSwitch('state')).toEqual true
+
+  describe "The Radio Bootstrap Switch", ->
+    it "should conserve its state if onSwitchChange returns false", ->
+      $radio1 = createRadio().prop("checked", true)
+      $radio2 = createRadio().prop("checked", false)
+      $radio3 = createRadio().prop("checked", false)
+
+      $('[name="name"]').bootstrapSwitch
+        onSwitchChange:(e, s) ->
+          expect(s).toEqual true
+          false
+
+      $radio2.click()
+
+      expect($radio1.bootstrapSwitch('state')).toEqual true
+      expect($radio2.bootstrapSwitch('state')).toEqual false
+      expect($radio3.bootstrapSwitch('state')).toEqual false
+
+    it "should change its state if onSwitchChange not returns false", ->
+      $radio1 = createRadio().prop("checked", true)
+      $radio2 = createRadio().prop("checked", false)
+      $radio3 = createRadio().prop("checked", false)
+
+      $('[name="name"]').bootstrapSwitch
+        onSwitchChange:(e, s) -> expect(s).toEqual true
+
+      $radio2.click()
+
+      expect($radio1.bootstrapSwitch('state')).toEqual false
+      expect($radio2.bootstrapSwitch('state')).toEqual true
+      expect($radio3.bootstrapSwitch('state')).toEqual false
+
+
+
+
+

+ 1 - 1
src/docs/jade/options.jade

@@ -146,7 +146,7 @@ block content
           td onSwitchChange
           td
           td Function
-          td Callback function to execute on switch state change
+          td Callback function to execute on switch state change. If false is returned, the status will be reverted, otherwise nothing changes
           td Function
           td: pre: code.javascript function(event, state) {}
 

+ 36 - 3
test/bootstrap-switch.js

@@ -32,6 +32,7 @@
         }
         this.$element = $(element);
         this.options = $.extend({}, $.fn.bootstrapSwitch.defaults, {
+          prevOption: {},
           state: this.$element.is(":checked"),
           size: this.$element.data("size"),
           animate: this.$element.data("animate"),
@@ -99,8 +100,14 @@
           };
         })(this));
         this.$element.on("switchChange.bootstrapSwitch", (function(_this) {
-          return function() {
-            return _this.options.onSwitchChange.apply(element, arguments);
+          return function(e) {
+            if (false === _this.options.onSwitchChange.apply(element, arguments)) {
+              if (_this.$element.is(":radio")) {
+                return $("[name='" + (_this.$element.attr('name')) + "']").trigger("previousState.bootstrapSwitch", true);
+              } else {
+                return _this.$element.trigger("previousState.bootstrapSwitch", true);
+              }
+            }
           };
         })(this));
         this.$container = this.$element.wrap(this.$container).parent();
@@ -120,6 +127,10 @@
 
       BootstrapSwitch.prototype._constructor = BootstrapSwitch;
 
+      BootstrapSwitch.prototype.setPrevOptions = function() {
+        return this.options.prevOption = $.extend(true, {}, this.options);
+      };
+
       BootstrapSwitch.prototype.state = function(value, skip) {
         if (typeof value === "undefined") {
           return this.options.state;
@@ -130,6 +141,11 @@
         if (this.options.state && !this.options.radioAllOff && this.$element.is(":radio")) {
           return this.$element;
         }
+        if (this.$element.is(":radio")) {
+          $("[name='" + (this.$element.attr('name')) + "']").trigger("setPreviousOptions.bootstrapSwitch");
+        } else {
+          this.$element.trigger("setPreviousOptions.bootstrapSwitch");
+        }
         if (this.options.indeterminate) {
           this.indeterminate(false);
         }
@@ -466,6 +482,7 @@
         var init, initInterval;
         init = (function(_this) {
           return function() {
+            _this.setPrevOptions();
             _this._width();
             return _this._containerPosition(null, function() {
               if (_this.options.animate) {
@@ -489,6 +506,20 @@
 
       BootstrapSwitch.prototype._elementHandlers = function() {
         return this.$element.on({
+          "setPreviousOptions.bootstrapSwitch": (function(_this) {
+            return function(e) {
+              return _this.setPrevOptions();
+            };
+          })(this),
+          "previousState.bootstrapSwitch": (function(_this) {
+            return function(e) {
+              _this.options = _this.options.prevOption;
+              if (_this.options.indeterminate) {
+                _this.$wrapper.addClass(_this.options.baseClass + "-indeterminate");
+              }
+              return _this.$element.prop("checked", _this.options.state).trigger("change.bootstrapSwitch", true);
+            };
+          })(this),
           "change.bootstrapSwitch": (function(_this) {
             return function(e, skip) {
               var state;
@@ -687,7 +718,8 @@
       return ret;
     };
     $.fn.bootstrapSwitch.Constructor = BootstrapSwitch;
-    return $.fn.bootstrapSwitch.defaults = {
+    $.fn.bootstrapSwitch.defaults = {
+      prevOption: {},
       state: true,
       size: null,
       animate: true,
@@ -708,6 +740,7 @@
       onInit: function() {},
       onSwitchChange: function() {}
     };
+    return $.fn.bootstrapSwitch.defaults.prevOption = $.extend(true, {}, $.fn.bootstrapSwitch.defaults);
   })(window.jQuery, window);
 
 }).call(this);

+ 78 - 7
test/bootstrap-switch.tests.js

@@ -1,6 +1,6 @@
 (function() {
-  describe("Bootstrap Switch", function() {
-    var createElement, getOptions;
+  describe("Bootstrap Switch:", function() {
+    var createCheckbox, createRadio, getOptions;
     beforeEach(function() {
       $.support.transition = false;
       return $.fx.off = true;
@@ -8,29 +8,100 @@
     afterEach(function() {
       return $("." + $.fn.bootstrapSwitch.defaults.baseClass).bootstrapSwitch("destroy");
     });
-    createElement = function() {
+    createCheckbox = function() {
       return $("<input>", {
         type: "checkbox",
         "class": "switch"
       }).appendTo("body");
     };
+    createRadio = function() {
+      return $("<input>", {
+        type: "radio",
+        name: "name",
+        "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();
+      $switch = createCheckbox().prop("checked", true).bootstrapSwitch();
       return expect(getOptions($switch)).toEqual($.fn.bootstrapSwitch.defaults);
     });
-    return it("should override default options with initialization ones", function() {
+    it("should override default options with initialization ones", function() {
       var $switch, $switch2;
-      $switch = createElement().prop("checked", false).bootstrapSwitch();
-      $switch2 = createElement().bootstrapSwitch({
+      $switch = createCheckbox().prop("checked", false).bootstrapSwitch();
+      $switch2 = createCheckbox().bootstrapSwitch({
         state: false
       });
       expect(getOptions($switch).state).toBe(false);
       return expect(getOptions($switch2).state).toBe(false);
     });
+    describe("The Checkbox Bootstrap Switch", function() {
+      it("should conserve its state if onSwitchChange returns false", function() {
+        var $indeterminateSwitch, $switch;
+        $switch = createCheckbox().bootstrapSwitch({
+          onSwitchChange: function(e, s) {
+            expect(s).toEqual(true);
+            return false;
+          }
+        });
+        $indeterminateSwitch = createCheckbox().data("indeterminate", true).bootstrapSwitch({
+          onSwitchChange: function(e, s) {
+            expect(s).toEqual(true);
+            return false;
+          }
+        });
+        $switch.click();
+        $indeterminateSwitch.click();
+        expect($switch.bootstrapSwitch('state')).toEqual(false);
+        return expect($indeterminateSwitch.bootstrapSwitch('state')).toEqual(false);
+      });
+      return it("should change its state if onSwitchChange not returns false", function() {
+        var $switch;
+        $switch = createCheckbox().bootstrapSwitch({
+          onSwitchChange: function(e, s) {
+            return expect(s).toEqual(true);
+          }
+        });
+        $switch.click();
+        return expect($switch.bootstrapSwitch('state')).toEqual(true);
+      });
+    });
+    return describe("The Radio Bootstrap Switch", function() {
+      it("should conserve its state if onSwitchChange returns false", function() {
+        var $radio1, $radio2, $radio3;
+        $radio1 = createRadio().prop("checked", true);
+        $radio2 = createRadio().prop("checked", false);
+        $radio3 = createRadio().prop("checked", false);
+        $('[name="name"]').bootstrapSwitch({
+          onSwitchChange: function(e, s) {
+            expect(s).toEqual(true);
+            return false;
+          }
+        });
+        $radio2.click();
+        expect($radio1.bootstrapSwitch('state')).toEqual(true);
+        expect($radio2.bootstrapSwitch('state')).toEqual(false);
+        return expect($radio3.bootstrapSwitch('state')).toEqual(false);
+      });
+      return it("should change its state if onSwitchChange not returns false", function() {
+        var $radio1, $radio2, $radio3;
+        $radio1 = createRadio().prop("checked", true);
+        $radio2 = createRadio().prop("checked", false);
+        $radio3 = createRadio().prop("checked", false);
+        $('[name="name"]').bootstrapSwitch({
+          onSwitchChange: function(e, s) {
+            return expect(s).toEqual(true);
+          }
+        });
+        $radio2.click();
+        expect($radio1.bootstrapSwitch('state')).toEqual(false);
+        expect($radio2.bootstrapSwitch('state')).toEqual(true);
+        return expect($radio3.bootstrapSwitch('state')).toEqual(false);
+      });
+    });
   });
 
 }).call(this);

Algunos archivos no se mostraron porque demasiados archivos cambiaron en este cambio