Source: src/js/models/filters/ToggleFilter.js

define(["jquery", "underscore", "backbone", "models/filters/Filter"], function (
  $,
  _,
  Backbone,
  Filter,
) {
  /**
   * @class ToggleFilter
   * @classdesc A search filter whose search term is only one of two opposing choices
   * @classcategory Models/Filters
   * @constructs ToggleFilter
   * @extends Filter
   */
  var ToggleFilter = Filter.extend(
    /** @lends ToggleFilter.prototype */ {
      type: "ToggleFilter",

      /**
       * The Backbone Model attributes set on this ToggleFilter
       * @type {object}
       * @extends Filter#defaultts
       * @property {string}         trueLabel - A human-readable label for the first search term
       * @property {string}         falseLabel - A human-readable label for the second search term
       * @property {string|boolean} trueValue - The exact search value to use for search term one
       * @property {string|boolean} falseValue - The exact search value to use for search term two
       * @property {string}         nodeName - The XML node name to use when serializing this model into XML
       */
      defaults: function () {
        return _.extend(Filter.prototype.defaults(), {
          trueLabel: "On",
          trueValue: null,
          falseLabel: "Off",
          falseValue: null,
          nodeName: "toggleFilter",
        });
      },

      /*
       * Parses the ToggleFilter XML node into JSON
       *
       * @param {Element} xml - The XML Element that contains all the ToggleFilter elements
       * @return {JSON} - The JSON object literal to be set on the model
       */
      parse: function (xml) {
        var modelJSON = Filter.prototype.parse.call(this, xml);

        //Parse the trueLabel and falseLabels
        modelJSON.trueLabel = this.parseTextNode(xml, "trueLabel");
        modelJSON.trueValue = this.parseTextNode(xml, "trueValue");
        modelJSON.falseLabel = this.parseTextNode(xml, "falseLabel");
        modelJSON.falseValue = this.parseTextNode(xml, "falseValue");

        //Delete any attributes from the JSON that don't exist in the XML
        if (!modelJSON.trueLabel) {
          delete modelJSON.trueLabel;
        }
        if (!modelJSON.falseLabel) {
          delete modelJSON.falseLabel;
        }
        if (!modelJSON.trueValue && modelJSON.trueValue !== false) {
          delete modelJSON.trueValue;
        }
        if (!modelJSON.falseValue && modelJSON.falseValue !== false) {
          delete modelJSON.falseValue;
        }

        return modelJSON;
      },

      /**
       * Updates the XML DOM with the new values from the model
       *  @inheritdoc
       *  @return {XMLElement} An updated toggleFilter XML element from a portal document
       */
      updateDOM: function (options) {
        try {
          var objectDOM = Filter.prototype.updateDOM.call(this, options);

          if (
            typeof options == "undefined" ||
            (typeof options == "object" && this.get("isUIFilterType"))
          ) {
            var toggleData = {
              trueValue: this.get("trueValue"),
              trueLabel: this.get("trueLabel"),
              falseValue: this.get("falseValue"),
              falseLabel: this.get("falseLabel"),
            };

            // Make and append new subnodes
            _.map(
              toggleData,
              function (value, nodeName) {
                // Remove the node if it exists in the DOM already
                $(objectDOM).find(nodeName).remove();

                // Don't serialize falsey or default values
                if (
                  (value || value === false) &&
                  value != this.defaults()[nodeName]
                ) {
                  var nodeSerialized =
                    objectDOM.ownerDocument.createElement(nodeName);
                  $(nodeSerialized).text(value);
                  $(objectDOM).append(nodeSerialized);
                }
              },
              this,
            );

            //Move the filterOptions node to the end of the filter node
            /*  var filterOptionsNode = $(objectDOM).find("filterOptions");
          filterOptionsNode.detach();
          $(objectDOM).append(filterOptionsNode);*/
          }
          //For collection definitions, serialize the filter differently
          else {
            //Remove the filterOptions
            $(objectDOM).find("filterOptions").remove();

            //Change the root element into a <filter> element
            var newFilterEl = objectDOM.ownerDocument.createElement("filter");
            $(newFilterEl).html($(objectDOM).children());

            //Return this node
            return newFilterEl;
          }

          return objectDOM;
        } catch (e) {
          //If there's an error, return the original DOM or an empty string
          console.log(
            "error updating the toggle filter object DOM, returning un-updated object DOM instead. Error message: " +
              e,
          );
          return this.get("objectDOM") || "";
        }
      },

      /**
       * Checks if the values set on this model are valid and expected
       * @return {object} - Returns a literal object with the invalid attributes and their
       * corresponding error message
       */
      validate: function () {
        try {
          // Validate most of the ToggleFilter attributes using the parent validate
          // function
          var errors = Filter.prototype.validate.call(this);

          // If everything is valid so far, then we have to create a new object to store
          // errors
          if (typeof errors != "object") {
            errors = {};
          }

          // Delete error messages for the attributes that are going to be validated
          // specially for the ToggleFilter
          ["trueLabel", "trueValue", "falseLabel", "falseValue"].forEach(
            function (attr) {
              delete errors[attr];
            },
          );

          // At least one trueValue required
          var trueValue = this.get("trueValue");
          if (!trueValue) {
            errors.trueValue =
              "The filter requires a term to search for when the toggle is on";
          }

          // Return the errors, if there are any
          if (Object.keys(errors).length) return errors;
          else {
            return;
          }
        } catch (error) {
          console.log(
            "There was an error validating a ToggleFilter" +
              ". Error details: " +
              error,
          );
        }
      },
    },
  );

  return ToggleFilter;
});