PageRenderTime 63ms CodeModel.GetById 36ms RepoModel.GetById 0ms app.codeStats 0ms

/js/model/appmodel.js

https://bitbucket.org/worldsayshi/master_thesis-gui
JavaScript | 231 lines | 170 code | 15 blank | 46 comment | 20 complexity | 8e4f54253a85cb18ebbc7ef3aba8531f MD5 | raw file
  1. // Groups of properties in the leftmost property list
  2. var Groups = Backbone.Collection.extend({
  3. initialize: function (solrInterface) {
  4. var self = this;
  5. solrInterface.on('change:fieldgroups',function (model,groups) {
  6. groups = removeNullElementsInGroups(groups);
  7. self.reset(groups);
  8. });
  9. }
  10. });
  11. // List of document results from a query
  12. var Results = Backbone.Collection.extend({
  13. initialize: function (solrInterface) {
  14. var self = this;
  15. solrInterface.on('change:docs',function (model,articles) {
  16. self.reset(articles);
  17. });
  18. }
  19. });
  20. // List of filters; maintaining only id's
  21. // The rest is kept in the attribute model
  22. var Filters = Backbone.Collection.extend({
  23. // Move a filter to a new pos
  24. move: function (id,pos) {
  25. this.remove(id);
  26. this.add({id:id},pos);
  27. },
  28. appendId: function (id) {
  29. this.add({id:id});
  30. },
  31. removeId: function(id) {
  32. this.remove({id:id});
  33. }
  34. });
  35. // The overall model
  36. // Most (but not all) of the event propagation goes through here
  37. var ApplicationModel = Backbone.Model.extend({
  38. // defaultHighlightedAttributes should be
  39. // moved into a configuration module
  40. defaultHighlightedAttributes:["name"],
  41. initialize: function (solrInterface,urlData) {
  42. this.set('attributes',new Attributes({},solrInterface));
  43. this.set('results',new Results(solrInterface));
  44. this.set('groupings',new Groups(solrInterface));
  45. this.set('filters',new Filters());
  46. this.set('query',new Query());
  47. this.set('solrInterface',solrInterface);
  48. this.set('global-tools',GlobalTools(this));
  49. // The 'fetch-needed' event will trigger the processed
  50. // query to be submitted to the solr interface
  51. this.on('fetch-needed',
  52. _.bind(this._postQuery,this));
  53. this.get('query').set('phrase',urlData.search);
  54. // When attribute focus is changed, we need to
  55. // de-focus the old attribute item
  56. this.listenTo(this.get('attributes'),'focus-change',
  57. _.bind(function(newInFocus_Id) {
  58. // Put other attributes out of focus
  59. var old_focused_id = this.get('attribute_in_focus');
  60. if(old_focused_id && (old_focused_id != newInFocus_Id)){
  61. var old_focused = this.get('attributes').get(old_focused_id);
  62. if(old_focused){old_focused.set('in_focus',false);}
  63. }
  64. this.set('attribute_in_focus',newInFocus_Id);
  65. },this));
  66. // If an attribute wants to become a filter, it has to be added in
  67. // a few places
  68. this.listenTo(this.get('attributes'),'attribute-wants-to-be-filter',
  69. _.bind(function(id) {
  70. this.get('query').addFacetField(id);
  71. this.get('filters').appendId(id);
  72. this.trigger('fetch-needed',this);
  73. },this));
  74. // If we delete a filter, we need to remove it from filters and query,
  75. // And we need to make and submit a new query
  76. this.listenTo(this.get('attributes'),'attribute-dont-want-to-be-filter',
  77. _.bind(function(id) {
  78. if(!id){return;}
  79. if(!this.get('filters').get(id)){return;}
  80. this.get('attributes').get(id).dropValues();
  81. this.get('filters').removeId(id);
  82. this.get('query').removeFacetField(id);
  83. // Triggers the filterprocessor
  84. this.get('filters').trigger('selection-change',this.get('filters'));
  85. this.trigger('fetch-needed',this);
  86. },this));
  87. // query Solr for the initial state
  88. // (without trying to process filters)
  89. this.trigger('fetch-needed',this);
  90. // The filters should be processed by a filter processor whenever
  91. // a selection-change happens
  92. var filterProcessor = new FilterProcessor({model:this});
  93. this.listenTo(this.get('filters'),'selection-change',
  94. _.bind(filterProcessor.processFilters,filterProcessor));
  95. },
  96. // tell the solr interface to send the query to Solr
  97. _postQuery: function () {
  98. this.get('solrInterface').placeQuery(this.get('query'));
  99. },
  100. // Toggle selection of a value of an attribute and let
  101. // listeners know it happened
  102. selectValue: function (parentAttrName,valueName) {
  103. this.get('attributes').get(parentAttrName).selectValue(valueName);
  104. this.get('filters').trigger('selection-change',this.get('filters'));
  105. },
  106. // Get field names that are to be used as columns for the
  107. // result list
  108. getHighlightedAttributes: function () {
  109. if(this.get('query').get('sortingFields')){
  110. return this.defaultHighlightedAttributes
  111. .concat(this.get('query').get('sortingFields'));
  112. } else {
  113. return this.defaultHighlightedAttributes;
  114. }
  115. },
  116. // Make the query ask for sorted results
  117. // and trigger a new fetch to Solr
  118. cycleGlobalSorting: function () {
  119. this.get('query').cycleSorting();
  120. this.triggerReload();
  121. },
  122. toggleFuzziness: function () {
  123. this.get('query').toggleFuzziness();
  124. this.triggerReload();
  125. },
  126. // Select a range of values on a enumerable facet
  127. // without triggering a reload
  128. selectRangeSilently: function (attribute,range) {
  129. attribute.selectRangeSilently(range);
  130. },
  131. // Trigger filters to be processed and a Solr fetch to happen
  132. triggerReload: function () {
  133. this.get('filters').trigger('selection-change',this.get('filters'));
  134. }
  135. });
  136. // Query object, maintaining processed information
  137. // on what is to be requested from Solr
  138. var Query = Backbone.Model.extend({
  139. initialize: function () {
  140. this.set('sorting',false);
  141. this.set('fuzziness',false);
  142. this.set('fuzzy-params',[10000,0.1]);
  143. this.set('facet_fields',{});
  144. },
  145. // sorting is based on selected filters
  146. cycleSorting: function () {
  147. if(!this.get('sorting')){
  148. this.set('sorting','asc');
  149. } else if (this.get('sorting')=='asc'){
  150. this.set('sorting','desc');
  151. } else if (this.get('sorting')=='desc'){
  152. this.set('sorting',false);
  153. }
  154. },
  155. toggleFuzziness: function () {
  156. this.set('fuzziness',!this.get('fuzziness'));
  157. },
  158. // Convert this query object into a
  159. // Solr query object
  160. prepare: function () {
  161. assert(this instanceof Query);
  162. var self = this;
  163. var prepared_query = {
  164. q:self._getStatement()
  165. };
  166. if(this.get('facet_fields')){
  167. var facetFields = _.keys(self.get('facet_fields'));
  168. // the propertyNames field is needed for sorting in the
  169. // grouping component
  170. facetFields.push("propertyNames");
  171. prepared_query = _.extend(prepared_query,{
  172. 'facet' : true,
  173. 'facet.mincount' : 1,
  174. 'facet.limit' : 40,
  175. 'facet.field' : facetFields
  176. });
  177. }
  178. if(this.get('sorting') && this.get('sortingFields') && (this.get('sortingFields').length>0)){
  179. prepared_query = _.extend(prepared_query,{
  180. sort:self._getSortingExpression()
  181. });
  182. }
  183. return prepared_query;
  184. },
  185. //
  186. _getStatement: function () {
  187. if(this.get('filterStatement')){
  188. return '('+this.get('phrase')+') AND '+this.get('filterStatement');
  189. }
  190. return this.get('phrase');
  191. },
  192. // Defining the part of the query that determine sorting order
  193. // of the result. Should only be used when score sorting is not
  194. // desired
  195. _getSortingExpression: function() {
  196. var self = this;
  197. return _.map(this.get('sortingFields'),function (fieldName) {
  198. return fieldName+' '+self.get('sorting');
  199. }).join(', ');
  200. },
  201. // Maintaining a redundant store on what
  202. // property fields are used as filters
  203. addFacetField: function (name) {
  204. if(!this.get('facet_fields')[name]){
  205. this.get('facet_fields')[name] = true;
  206. this.trigger('change',this);
  207. }
  208. },
  209. removeFacetField: function(name) {
  210. if(this.get('facet_fields')[name]){
  211. var facet_fields = this.get('facet_fields');
  212. delete facet_fields[name];
  213. this.set('facet_fields',facet_fields);
  214. }
  215. }
  216. });