search/Search.js

var FieldDBObject = require("./../FieldDBObject").FieldDBObject;
var DataList = require("./../data_list/DataList").DataList;

/**
 * @class Search progressively searches a corpus and updates a search/data list
 *  view as a user types keywords in the search box. Both intersection and
 *  union search is possible. It highlights search keywords in the list view.
 *
 * @property {String} searchQuery
 * @property {DataList} A list of data which fulfill the search query
 *
 * @name  Search
 * @extends FieldDBObject
 * @constructs
 */
var Search = function Search(options) {
  if (!this._fieldDBtype) {
    this._fieldDBtype = "Search";
  }
  this.debug("Constructing Search length: ", options);
  FieldDBObject.apply(this, arguments);
};

Search.prototype = Object.create(FieldDBObject.prototype, /** @lends Search.prototype */ {
  constructor: {
    value: Search
  },

  defaults: {
    value: {
      searchQuery: ""
    }
  },

  INTERNAL_MODELS: {
    value: {
      datalist: DataList
    }
  },

  searchKeywords: {
    get: function() {
      this.warn("searchKeywords is deprecated, use searchQuery instead.");
      return this.searchQuery;
    },
    set: function(value) {
      this.warn("searchKeywords is deprecated, use searchQuery instead.");
      this.searchQuery = value;
    }
  },

  /**
   *  Search id is a url encoded version of the current search which means the id will change over time.
   */
  id: {
    configurable: true,
    get: function() {
      return encodeURI(this.searchQuery);
    },
    set: function(value) {
      var decoded = decodeURI(value);
      if (this.searchQuery !== value && this.searchQuery !== decoded) {
        if (value === decoded) {
          this.searchQuery = value;
        } else if (value !== decoded) {
          this.searchQuery = decoded;
        }
      }
    }
  },

  searchQuery: {
    get: function() {
      return this._searchQuery || this.defaults.searchQuery;
    },
    set: function(value) {
      if (value === this._searchQuery) {
        return;
      }
      if (!value) {
        delete this._searchQuery;
        return;
      }
      this._searchQuery = value.trim();
      this._id = encodeURI(this._searchQuery);
    }
  },

  search: {
    configurable: true,
    writable: true,
    value: function(value) {
      if (value !== this.searchQuery) {
        this.searchQuery = value;
      }
      this.prepareDataListForSearchQuery(value);
      this.warn("Search has not been set up for this app." + value);
    }
  },

  prepareDataListForSearchQuery: {
    value: function(searchQuery) {
      if (searchQuery && this.datalist && this.datalist.id === encodeURI(searchQuery)) {
        this.warn("Search data list was already set up for " + searchQuery);
        return;
      }
      var title = "";
      if (this.corpus && this.corpus.dbname) {
        title = this.corpus.title || this.corpus.dbname;
        title = " in " + title;
      }
      this.datalist = {
        id: this.id,
        title: searchQuery,
        description: "This is the result of searching for : " + searchQuery + title + " on " + new Date()
      };
    }
  },

  datalist: {
    get: function() {
      this.debug("Getting datalist " + this.searchQuery, this._datalist);
      // if (!this._datalist || !(this._datalist instanceof DataList) || typeof this._datalist.reindexFromApi !== "function") {
      //   this.initializeDatalist();
      // }
      return this._datalist;
    },
    set: function(value) {
      if (value && value.id && this._datalist && this._datalist.id && value.id !== this._datalist.id && this._datalist.length) {
        // add to previous searches
        if (!this.previousSearchDataLists) {
          this.previousSearchDataLists = {};
          this.previousSearchDataListsCount = 0;
        }
        this.previousSearchDataLists[this._datalist.id] = this._datalist;
        this.previousSearchDataListsCount++;
      }

      this.debug("Setting datalist on search ", this._datalist, value);
      this.ensureSetViaAppropriateType("datalist", value);

      // Setting encodeURI search query as the id.
      this._datalist.id = this.id;
    }
  },

  clearPreviousSearchDataLists: {
    value: function() {
      this.warn("Releasing memory for" + this.previousSearchDataListsCount + " previousSearchDataLists ");
      delete this.previousSearchDataLists;
      delete this.previousSearchDataListsCount;
    }
  }

});
exports.Search = Search;