Source: src/js/views/filters/ToggleFilterView.js

/*global define */
define(['jquery', 'underscore', 'backbone',
        'models/filters/ToggleFilter',
        'views/filters/FilterView',
        'text!templates/filters/toggleFilter.html',
        'text!templates/filters/booleanFilter.html'],
  function($, _, Backbone, ToggleFilter, FilterView, Template, BooleanTemplate) {
  'use strict';

  /**
  * @class ToggleFilterView
  * @classdesc Render a view of a single ToggleFilter model
  * @classcategory Views/Filters
  * @extends FilterView
  */
  var ToggleFilterView = FilterView.extend(
    /** @lends ToggleFilterView.prototype */{

    /**
    *  A ToggleFilter model to be rendered in this view
    * @type {ToggleFilter} */
    model: null,

    /**
     * @inheritdoc
     */
    modelClass: ToggleFilter,

    className: "filter toggle",

    template: _.template(Template),
    booleanTemplate: _.template(BooleanTemplate),

    /**
     * @inheritdoc
     */
    events: function () {
      try {
        var events = FilterView.prototype.events.call(this);
        events["click input[type='checkbox']"] = "updateModel";
        
        return events
      }
      catch (error) {
        console.log('There was an error creating the events object for a ToggleFilterView' +
          ' Error details: ' + error);
      }
    },

    /**
    * @inheritdoc
    */
      render: function (templateVars = {}) {

      try {
        templateVars = _.extend(this.model.toJSON(), templateVars);
        templateVars.id = this.model.cid;

        if (!this.model.get("falseLabel")) {
          //If the value is the same as the trueValue, the checkbox should be checked
          templateVars.checked = (this.model.get("values")[0] == this.model.get("trueValue"))? true : false;

          //Use the BooleanFilter template for toggles with only a true value
          this.$el.addClass("boolean");
          this.template = this.booleanTemplate
        }
        
        // Renders the template and inserts the FilterEditorView if the mode is uiBuilder
        FilterView.prototype.render.call(this, templateVars);

        this.listenTo(this.model, "change:values", this.updateToggle);
      }
      catch (error) {
        console.log( 'There was an error rendering a ToggleFilterView.' +
          ' Error details: ' + error );
      }
      
    },

    /**
    * Actions to perform after the render() function has completed and this view's
    * element is added to the webpage.
    */
    postRender: function(){
      this.setToggleWidth();
    },

    updateToggle: function(){

      //If the model is set to true
      if( this.model.get("values").length && this.model.get("values")[0] == this.model.get("trueValue") ){
        this.$("input").prop("checked", true);
      }
      else if( this.model.get("values").length && this.model.get("values")[0] == this.model.get("falseValue") ){
        this.$("input").prop("checked", false);
      }
      else if( !this.model.get("values").length ){
        this.$("input").prop("checked", false);
      }

      this.setToggleWidth();

    },

    /**
    * Gets the width of the toggle labels and sets the various CSS attributes
    * necessary for the switch to fully display each label
    */
    setToggleWidth: function(){

      //If there is no toggle element, exit now
      if( !this.$(".can-toggle-switch").length ){
        return;
      }

      //Get the padding and widths of the switch elements
      var switchPadding    = 24,
          onSwitchWidth = this.$(".true-label").width(),
          offSwitchWidth  = this.$(".false-label").width(),
          totalSwitchWidth = onSwitchWidth + offSwitchWidth + (switchPadding * 2) + 2,
          isChecked = this.$("input[type='checkbox']").prop("checked");

      //Set the width on the whole view
      this.$el.width(totalSwitchWidth + "px");

      //Get the toggle switch element
      var toggleSwitch = this.$(".can-toggle-switch");

      //Add an identifier to the toggle switch element
      toggleSwitch.attr("id", "toggle-" + this.model.cid);

      //Change the width of the toggle switch
      toggleSwitch.css("flex", "0 0 " + totalSwitchWidth + "px");

      //Create CSS for the :before and :after pseudo elements, which is best done
      // by adding a style tag directly to the DOM
      if( isChecked ){
        var newCSS = "#" + "toggle-" + this.model.cid + ":before{ " +
                       "transform: translate3d(" + (onSwitchWidth + switchPadding) + "px, 0, 0);" +
                       "width: " + (offSwitchWidth + switchPadding) + "px ;" +
                     "}" +
                     "#" + "toggle-" + this.model.cid + ":after{ " +
                      "width: " + (onSwitchWidth + switchPadding) + "px;" +
                      "transform: translate3d(0px, 0, 0);" +
                    "}";
      }
      else{
        var newCSS = "#" + "toggle-" + this.model.cid + ":before{ " +
                       "width: " + (offSwitchWidth + switchPadding) + "px ;" +
                       "left: 0px ;" +
                     "}" +
                     "#" + "toggle-" + this.model.cid + ":after{ " +
                      "width: " + (onSwitchWidth + switchPadding) + "px;" +
                      "transform: translate3d(" + (offSwitchWidth + switchPadding) + "px, 0, 0);" +
                    "}";
      }

      //Get or create a style tag
      var styleTag = toggleSwitch.children("style");
      if( !styleTag.length ){
        styleTag = $(document.createElement("style"));
        toggleSwitch.append(styleTag);
      }

      //Add the CSS to the style tag
      styleTag.html(newCSS);
    },

    /**
    * Updates the value set on the ToggleFilter Model associated with this view.
    * The filter value is grabbed from the checkbox element in this view.
    *
    */
      updateModel: function () {

      //Check if the checkbox is checked
      var isChecked = this.$("input").prop("checked");

      //If the toggle is checked, then set the true toggle value on the model
      if( isChecked ){
        if( this.model.get("values")[0] !== this.model.get("trueValue") ){
          this.model.set("values", [ this.model.get("trueValue") ]);
        }
      }
      //If the toggle is not checked and there is no false value specified,
      // then remove the value from the model completely
      else if(!this.model.get("falseValue")){
        if( this.model.get("values").length > 0 ){
          this.model.set("values", []);
        }
      }
      //If the toggle is not checked and there is a false value specified,
      // then set the false toggle value on the model
      else{
        if( this.model.get("values")[0] !== this.model.get("falseValue") ){
          this.model.set("values", [ this.model.get("falseValue") ]);
        }
      }

    }

  });
  return ToggleFilterView;
});