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); } }, }); });