Prechádzať zdrojové kódy

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

Mattia Larentis 10 rokov pred
rodič
commit
61b2289187

Rozdielové dáta súboru neboli zobrazené, pretože súbor je príliš veľký
+ 0 - 0
dist/css/bootstrap2/bootstrap-switch.min.css


Rozdielové dáta súboru neboli zobrazené, pretože súbor je príliš veľký
+ 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);

Rozdielové dáta súboru neboli zobrazené, pretože súbor je príliš veľký
+ 0 - 0
dist/js/bootstrap-switch.min.js


Rozdielové dáta súboru neboli zobrazené, pretože súbor je príliš veľký
+ 2 - 2
docs/css/bootstrap.min.css


Rozdielové dáta súboru neboli zobrazené, pretože súbor je príliš veľký
+ 2 - 2
docs/js/bootstrap.min.js


Rozdielové dáta súboru neboli zobrazené, pretože súbor je príliš veľký
+ 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);

Niektoré súbory nie sú zobrazené, pretože je v týchto rozdielových dátach zmenené mnoho súborov