Przeglądaj źródła

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

Mattia Larentis 10 lat temu
rodzic
commit
61b2289187

Plik diff jest za duży
+ 0 - 0
dist/css/bootstrap2/bootstrap-switch.min.css


Plik diff jest za duży
+ 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);

Plik diff jest za duży
+ 0 - 0
dist/js/bootstrap-switch.min.js


Plik diff jest za duży
+ 2 - 2
docs/css/bootstrap.min.css


Plik diff jest za duży
+ 2 - 2
docs/js/bootstrap.min.js


Plik diff jest za duży
+ 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);

Niektóre pliki nie zostały wyświetlone z powodu dużej ilości zmienionych plików