Browse Source

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

Mattia Larentis 10 năm trước cách đây
mục cha
commit
61b2289187

Những thai đổi đã bị hủy bỏ vì nó quá lớn
+ 0 - 0
dist/css/bootstrap2/bootstrap-switch.min.css


Những thai đổi đã bị hủy bỏ vì nó quá lớn
+ 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);

Những thai đổi đã bị hủy bỏ vì nó quá lớn
+ 0 - 0
dist/js/bootstrap-switch.min.js


Những thai đổi đã bị hủy bỏ vì nó quá lớn
+ 2 - 2
docs/css/bootstrap.min.css


Những thai đổi đã bị hủy bỏ vì nó quá lớn
+ 2 - 2
docs/js/bootstrap.min.js


Những thai đổi đã bị hủy bỏ vì nó quá lớn
+ 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);

Một số tệp đã không được hiển thị bởi vì quá nhiều tập tin thay đổi trong này khác