Source: src/js/views/queryBuilder/QueryBuilderView.js

define(["jquery",
    "underscore",
    "backbone",
    "collections/Filters",
    "collections/queryFields/QueryFields",
    "views/queryBuilder/QueryRuleView",
    "text!templates/queryBuilder/queryBuilder.html"
  ],
  function($, _, Backbone, Filters, QueryFields, QueryRule, Template) {

    /**
     * @class QueryBuilder
     * @classdesc A view that provides a UI for users to construct a complex
     * search through the DataONE Solr index
     * @classcategory Views/QueryBuilder
     * @screenshot views/QueryBuilderView.png
     * @extends Backbone.View
     * @constructor
     * @since 2.14.0
     */
    return Backbone.View.extend(
      /** @lends QueryBuilderView.prototype */
      {

        /**
        * The type of View this is
        * @type {string}
        */
        type: "QueryBuilderView",

        /**
         * The HTML class names for this view element
         * @type {string}
         */
        className: "query-builder",

        /**
         * A jquery selector for the element in the template that will contain
         * the query rules
         * @type {string}
         */
        rulesContainerSelector: ".rules-container",

        /**
         * A jquery selector for the element in the template that a user should click to
         * add a new rule
         * @type {string}
         */
        addRuleButtonSelector: ".add-rule",

        /**
         * An array of hex color codes used to help distinguish between different rules
         * @type {string[]}
         */
        ruleColorPalette: ["#44AA99", "#137733", "#c9a538", "#CC6677", "#882355", "#AA4499","#332288"],

        /**
         * Search index fields to exclude in the metadata field selector of each query rule
         * @type {string[]}
         */
        excludeFields: [],

        /**
        * A Filters collection that stores definition filters for a collection (or portal)
        * @type {Filters}
        */
        collection: undefined,

        /**
         * The primary HTML template for this view
         * @type {Underscore.template}
         */
        template: _.template(Template),

        /**
         * events - A function that specifies a set of DOM events that will be
         * bound to methods on your View through Backbone.delegateEvents.
         * See: https://backbonejs.org/#View-events
         *
         * @return {Object}  The events hash
         */
        events: function(){
          try {
            var events = {};
            var addRuleAction = "click " + this.addRuleButtonSelector;
            events[addRuleAction] = "addQueryRule"
            return events
          } catch (e) {
            console.error("Failed to specify events for  the Query Builder View, error message: " + e);
          }
        },

        /**
         * The list of QueryRuleViews that are contained within this queryBuilder
         * @type {QueryRuleView[]}
         */
        rules: [],

        /**
         * Creates a new QueryBuilderView
         * @param {Object} options - A literal object with options to pass to the view
         */
        initialize: function(options) {

          try {

            // Get all the options and apply them to this view
            if (typeof options == "object") {
              var optionKeys = Object.keys(options);
              _.each(optionKeys, function(key, i) {
                this[key] = options[key];
              }, this);
            }

            // If no filters collection is provided in the options, then set a
            // new Filters collection
            if(!this.collection || typeof this.collection === 'undefined'){
              // TODO: Which properties to set?
              this.collection = new Filters()
            }

          } catch (e) {
            console.error("Failed to initialize the query builder view, error message:", e);
          }
        },

        /**
         * render - Render the view
         *
         * @return {QueryBuilder}  Returns the view
         */
        render: function() {

          try {

            // Ensure the query fields are cached for the Query Field Select
            // View and the Query Rule View
            if ( typeof MetacatUI.queryFields === "undefined" || MetacatUI.queryFields.length === 0) {
              MetacatUI.queryFields = new QueryFields();
              this.listenToOnce(MetacatUI.queryFields, "sync", this.render)
              MetacatUI.queryFields.fetch();
              return
            }

            // Insert the template into the view
            this.$el.html(this.template());

            // Add a row for each rule that exists already in the model
            if(this.collection && this.collection.models && this.collection.models.length){
              this.collection.models.forEach(function(model){
                this.addQueryRule(model)
              }, this);
            }
            // Render a new query rule at the end
            this.addQueryRule();

            return this;

          } catch (e) {
            console.error("Failed to render a Query Builder view, error message: ", e);
          }
        },

        /**
         * Appends a new row (query rule view) to the end of the query builder
         *
         * @param {Filter} filterModel The filter model for which to create a rule for
         */
        addQueryRule: function(filterModel){

          try {

            var view = this;

            // Ensure that the object passed to this function is a filter.
            // When the "add rule" button is clicked, the Event object is passed
            // to this function instead.
            if(!filterModel || (filterModel && !/filter/i.test(filterModel.type))){
              filterModel = this.collection.add({
                nodeName: "filter",
                operator: "OR"
              });
            }

            // Don't show invisible rules
            if(filterModel.get("isInvisible")){
              return
            }

            // If no filter model is provided, assume that this is a new rule
            // insert QueryRuleView
            var rule = new QueryRule({
              model: filterModel,
              ruleColorPalette: this.ruleColorPalette,
              excludeFields: this.excludeFields
            });

            // Insert and render the rule
            this.$(this.rulesContainerSelector).append(rule.el);
            rule.render();
            // Add the rule to the list of rule sub-views
            this.rules.push(rule);


          } catch (e) {
            console.error("Error adding a query rule, error message:", e);
          }
        },

        /**
         * Removes a query rule from the list of rules
         *
         * @param  {QueryRule} rule The query rule to remove
         */
        removeQueryRule: function(rule){
          try {
            // TODO
            // Remove rule from the view
            // Remove rule collection
          } catch (e) {
            console.error("Error removing a query rule, error message:", e);
          }
        },


      });
  });