1 /**
  2  * Defines the search components
  3  * @extends Workbench.component.Component
  4  * @author Alejandro
  5  * @modified by Andrew -various updates to support filter search
  6  * @modified by Amit Kumar -added support for
  7  * Hide and Display based on events
  8  * @modfied by Amit kumar -clear the search term when the
  9  * component goes from one step to another
 10  */
 11 
 12 Ext.ux.SearchField = Ext.extend(Ext.form.TwinTriggerField, {
 13     initComponent : function(){
 14         Ext.ux.SearchField.superclass.initComponent.call(this);
 15         this.addEvents(
 16             'search'
 17         );
 18         this.on('specialkey', function(f, e){
 19             if(e.getKey() == e.ENTER){
 20                 this.onTrigger1Click();
 21             }
 22         }, this);
 23     },
 24     hideTrigger2: false,
 25     hasFilter: false,
 26     trigger1Class: 'x-form-search-trigger',
 27     trigger2Class: 'x-form-clear-trigger',
 28     handleStoreDataChange : function(store){
 29         var count = store.getCount();
 30         var filtered = store.isFiltered();
 31         if (count == 0 && !filtered) {
 32             this.hasFilter = false;
 33             this.triggers[0].replaceClass('x-form-filter-trigger','x-form-search-trigger');
 34             this.triggers[1].replaceClass('x-form-filter-clear-trigger','x-form-clear-trigger');
 35             Ext.QuickTips.register({
 36                 target: this.triggers[0],
 37                 title: 'Search',
 38                 text: 'Perform Search'
 39             });
 40             Ext.QuickTips.register({
 41                 target: this.triggers[1],
 42                 title: 'Search',
 43                 text: 'Clear All'
 44             });
 45         } else if (count != 0 && !filtered) {
 46             this.hasFilter = false;
 47             this.triggers[0].replaceClass('x-form-search-trigger','x-form-filter-trigger');
 48             this.triggers[1].replaceClass('x-form-filter-clear-trigger','x-form-clear-trigger');
 49             Ext.QuickTips.register({
 50                 target: this.triggers[0],
 51                 title: 'Search',
 52                 text: 'Filter Search'
 53             });
 54             Ext.QuickTips.register({
 55                 target: this.triggers[1],
 56                 title: 'Search',
 57                 text: 'Clear All'
 58             });
 59         } else if (filtered) {
 60             this.hasFilter = true;
 61             this.triggers[1].replaceClass('x-form-clear-trigger','x-form-filter-clear-trigger');
 62             Ext.QuickTips.register({
 63                 target: this.triggers[1],
 64                 title: 'Search',
 65                 text: 'Clear Filter'
 66             });
 67         }
 68     },
 69     onTrigger1Click : function(){
 70         var value = this.getRawValue();
 71         this.fireEvent('search', this, value);
 72     },
 73     onTrigger2Click : function(){
 74         if (this.hasFilter) {
 75             Workbench.component.manager.notify(new Monk.event.workbench.ClearSearch({
 76                 label: 'clear search sent'
 77             }), {clearAll: false});
 78         } else {
 79             Workbench.component.manager.notify(new Monk.event.workbench.ClearSearch({
 80                 label: 'clear all search sent'
 81             }), {clearAll: true});
 82         }
 83     }
 84 });
 85 
 86 /* Search Component */
 87 Monk.framework.component.SearchComponent = function (args) {
 88     this.alreadyRendered = false;
 89     this.numCollections = 0;
 90     this.numTotalWorks = 0;
 91     this.authorRecord = Ext.data.Record.create(
 92         {name:'name'},{birthYear:'birthYear'},
 93         {deathYear:'deathYear'},{numWorks:'numWorks'},{title: 'title'}
 94     );
 95     
 96     this.authorStore = new Ext.data.Store({
 97             url: Monk.data.PROXY_URL + "get/CorpusManager.getAuthorList",
 98             reader : new Ext.data.XmlReader({record : 'author', name : 'name'},
 99                 new Ext.data.Record.create([{name : 'name', mapping : 'name'},
100                         {name:'birthYear',mapping: '@birthYear'},
101                         {name:'deathYear',mapping: '@deathYear'},
102                         {name:'id',mapping: '@id'},
103                         {name:'numWorks',mapping: '@numWorks'},
104                         {name:'gender',mapping: '@gender'}
105                  ])
106              ),
107              autoLoad: false
108 
109     });
110      this.genderStore = new Ext.data.SimpleStore({
111          fields: ['id','label'],
112          data : [['*','All'],['M','Male'],
113          ["F","Female"],
114          ["U","Unknown"]
115          ]
116     });
117 
118 
119     this.genreStore = new Ext.data.SimpleStore({
120          fields: ['id','label'],
121          data : [['*','All'],
122          ["fiction","Fiction"],
123          ['play','Play All'],
124          ['play-history','--History'],
125          ['play-comedy','--Comedy'],
126          ['play-tragedy','--Tragedy'],
127          ["prose","Prose"],
128          ["poetry","Poetry"]
129          
130          ]
131     });
132     
133 
134     this.searchForm = null;
135 
136     var thisComponent = this;
137 
138     this.panel = new Ext.Panel({
139         split: false,
140         collapsible: false,
141         hideMode: 'visibility',
142         width: 190,
143         layout: 'fit',
144         items: [
145             new Ext.ux.SearchField({
146                 id: 'searchField',
147                 width: 180
148             }),
149             {
150             	id: "advancedSearchId",
151                 bodyStyle: "background: transparent; height: 20px; text-align: center;",
152                 html: '<a href="#" id="advancedSearchLink">Advanced Search</a>'
153             }
154         ],
155 
156         listeners: {
157             'afterlayout': {
158                 fn: function (){
159                     // remove this listener after it's fired the first time
160                     thisComponent.hide();
161                     thisComponent.initialize();
162                 },
163                 single: true
164             }
165         }
166 
167     });
168     
169     Monk.framework.component.SearchComponent.superclass.constructor.call(this, args);
170 }
171 
172 Workbench.extend(Monk.framework.component.SearchComponent, Monk.component.Component, {
173 
174     label : 'Search',
175     id: 'searchComponent',
176    
177     // this call sends notification that is caught by the data-manager which does
178     // an exhaustive search in all the features.
179     sendSimpleSearchNofication: function(featureValue){
180     	   Workbench.component.manager.notify(new Monk.event.workbench.SimpleSearchQuery({
181             label: 'new simple search request: '+featureValue
182             }), {featureValue: featureValue});
183     },
184 
185     // this call does full search metadata search
186     sendSearchNotification: function(form){
187          var paramValues = form.getValues();
188          if(paramValues.authorStartBirthYear=="") paramValues.authorStartBirthYear="-1";
189          if(paramValues.authorEndBirthYear=="") paramValues.authorEndBirthYear="-1";
190          if(paramValues.authorStartDeathYear=="") paramValues.authorStartDeathYear="-1";
191          if(paramValues.authorEndDeathYear=="") paramValues.authorEndDeathYear="-1";
192          if(paramValues.circulationDateStart=="") paramValues.circulationDateStart="-1";
193          if(paramValues.circulationDateEnd=="") paramValues.circulationDateEnd="-1";
194          
195          // need to manually get values for combo fields, since auto returns label instead of value
196          // and setting hiddenName messed up combo display (who knows why?)
197          var corpusCriterion = Ext.getCmp("corpusCriterion").getValue();
198          var authorName = Ext.getCmp("authorName").getRawValue();
199          var authorGender = Ext.getCmp("authorGender").getValue();
200          var genre = Ext.getCmp("genre").getValue();
201          paramValues.corpusCriterion = corpusCriterion;
202          paramValues.authorName = authorName;
203          paramValues.authorGender = authorGender;
204          paramValues.genre = genre;
205          // this is a new search -go back to the server
206          Monk.component.dataManager.getResultStore().removeAll();
207                    
208          this.notify(new Monk.event.workbench.AdvancedSearchQuery({
209             label: 'new search request'
210          }), [paramValues]);
211         
212          this.advancedSearchDialog.hide()
213          
214          //Ext.getCmp('searchField').searchPerformed();
215      },
216 chooseCollection: function(){
217     var collectionVal=Ext.getCmp("corpusCriterion").getValue();
218     Ext.getCmp("authorName").clearValue();
219     this.authorStore.on('beforeload',function(store,options){
220         store.removeAll();
221         if (!collectionVal) {
222             store.baseParams={corpusId:collectionVal}
223         }
224 //        store.add(new this.authorRecord({
225 //            name:'All',birthYear:-1,deathYear:-1,numWorks:-1,gender:' '
226 //        }));
227     }, this);
228     this.authorStore.load({
229         params:{corpusId:collectionVal},
230         add: false
231     });
232     this.authorStore.on('loadexception', function(){
233         Workbench.console.info("Error happened trying to load data");
234     });
235 },
236 
237     initialize: function(){
238         var triggers = Ext.getCmp('searchField').triggers;
239         Ext.QuickTips.register({
240             target: triggers[0],
241             title: 'Search',
242             text: 'Perform Search'
243         });
244         Ext.QuickTips.register({
245             target: triggers[1],
246             title: 'Search',
247             text: 'Clear All'
248         });
249         
250         Monk.component.dataManager.getResultStore().on('datachanged', function(store){
251             Ext.getCmp('searchField').handleStoreDataChange(store);
252         });
253         Monk.component.dataManager.getResultStore().on('clear', function(store){
254             Ext.getCmp('searchField').handleStoreDataChange(store);
255         });
256         
257         var thisComponent = this;
258 
259         Ext.getCmp('searchField').on('search', function(field, query) {
260             if (field.isValid()) this.sendSimpleSearchNofication(query);
261         },this);
262 
263         Ext.get('advancedSearchLink').on('click', function (e){
264             e.preventDefault();
265             if(!thisComponent.alreadyRendered)
266             thisComponent.initializeAdvancedSearchDialog();
267 	        thisComponent.advancedSearchDialog.show('advancedSearchLink');
268         });
269 
270         this.initialized = true;
271     },
272     
273    handle: function(monkEvent, data){
274     if (monkEvent.instanceOf(Monk.event.view.ShowSearchOption)) {
275      	  this.show();
276     }else if(monkEvent.instanceOf(Monk.event.view.HideSearchOption)){
277           this.hide();
278     }else if(monkEvent.instanceOf(Monk.event.flowmanager.StepSelected)){
279     	 Ext.getCmp('searchField').setRawValue("");
280     	 Monk.event.workbench.ClearSearch
281                         this.notify(new Monk.event.workbench.ClearSearch({
282                 label: 'clear filter search sent'
283             }), {clearAll: false});
284     }else if (monkEvent.instanceOf(Monk.event.view.ShowAdvancedSearchLink)) {
285           this.showAdvancedSearchLink();
286     }else if(monkEvent.instanceOf(Monk.event.view.HideAdvancedSearchLink)){
287           this.hideAdvancedSearchLink();
288     }
289    },
290 
291    hideAdvancedSearchLink : function() {
292             if(Ext.getCmp("advancedSearchId")!=null){
293                 Ext.getCmp("advancedSearchId").hide();
294             }
295    },
296    
297    showAdvancedSearchLink : function() {
298             if(Ext.getCmp("advancedSearchId")!=null){
299                 Ext.getCmp("advancedSearchId").show();
300             }
301    },
302    
303    
304    
305     show : function() {
306         this.panel.show();
307         Ext.getCmp('searchPanelSplit').show();
308         var hideSearchPanel = true;
309         if(hideSearchPanel){
310         	Ext.getCmp("advancedSearchId").hide();
311 
312         }
313         
314     },
315 
316     hide : function() {
317         this.panel.hide();
318         Ext.getCmp('searchPanelSplit').hide();
319     },
320 
321  initializeAdvancedSearchDialog : function() {
322    this.alreadyRendered=true;
323    this.collectionDS = Monk.data.collection.getMetaDataHierarchy();
324    var collectionStore = new Ext.data.SimpleStore({
325      fields: ['id','collectionId','text','numWorks','title']
326     });
327 
328    var CollectionRecord=Ext.data.Record.create({id:'id'},{collectionId:'collectionId'},
329     {text:'text'},{numWorks:'numWorks'},{title: 'title'});
330 
331    collectionStore.add(new CollectionRecord({
332         id: ""
333         ,collectionId: "All"
334         ,text: "All Collections"
335         ,numWorks: ""
336         ,title:    "All Collections"
337     }));
338 
339 
340     for(var i=0; i< this.collectionDS.length;i++){
341     collectionStore.add(new CollectionRecord({
342         id: this.collectionDS[i].id
343         ,collectionId: this.collectionDS[i].collectionId
344         ,text: this.collectionDS[i].text
345         ,numWorks: this.collectionDS[i].children.length
346         ,title:    this.collectionDS[i].text+ " ("+this.collectionDS[i].children.length+") works"
347     }));
348     this.numTotalWorks = this.numTotalWorks+this.collectionDS[i].children.length;
349     this.numCollections =this.numCollections+1;
350     }
351      var collectionCombo = {
352             id: 'corpusCriterion'
353             ,name: 'corpusCriterion'
354             ,xtype: 'combo'
355             ,triggerAction: 'all'
356             ,fieldLabel :'Collection'
357             ,forceSelection : true
358             ,editable: false
359             ,store : collectionStore
360             ,valueField : 'id'
361             ,displayField : 'title'
362             ,mode : 'local'
363             ,allowBlank : true
364             ,maxHeight: 130
365             ,width: 210
366             ,listeners :{
367               select : {fn:  this.chooseCollection, scope: this}
368              }
369         };
370 
371       var authorCombo = {
372             id:'authorName'
373             ,name:'authorName'
374             ,triggerAction: 'all'
375             ,xtype: 'combo'
376             ,fieldLabel :'Author'
377             ,forceSelection : true
378             ,store : this.authorStore
379             ,valueField : 'id'
380             ,displayField : 'name'
381             ,mode : 'local'
382             ,allowBlank : true
383             ,maxHeight: 100
384             ,width: 210
385 
386         };
387 
388       var authorGenderCombo = {
389             id: 'authorGender'
390             ,name: 'authorGender'
391             ,triggerAction: 'all'
392             ,xtype: 'combo'
393             ,fieldLabel :'Author Gender'
394             ,forceSelection : true
395             ,editable: false
396             ,store : this.genderStore
397             ,valueField : 'id'
398             ,displayField : 'label'
399             ,mode : 'local'
400             ,allowBlank : true
401             ,maxHeight: 100
402             ,width: 80
403         };
404 
405 
406     var authorStartBirthDate = {
407             fieldLabel: 'Birth Year from',
408             name: 'authorStartBirthYear',
409             id: 'authorStartBirthYear',
410             maxLength: 4,
411             validator: function(value) {
412                 if (value.match(/\D/) != null) return 'You can only enter year in YYYY format.';
413                 else return true;
414             },
415             autoCreate: {tag: 'input', type: 'text', size: 4, maxlength: 4, style: 'width: auto'}
416        };
417 
418     var authorEndBirthDate = {
419             fieldLabel: 'Birth Year to',
420             name: 'authorEndBirthYear',
421             id: 'authorEndBirthYear',
422             maxLength: 4,
423             validator: function(value) {
424                 if (value.match(/\D/) != null) return 'You can only enter year in YYYY format.';
425                 else return true;
426             },
427             autoCreate: {tag: 'input', type: 'text', size: 4, maxlength: 4, style: 'width: auto'}
428      };
429 
430 
431     var authorStartDeathDate = {
432             fieldLabel: 'Death Year from',
433             name: 'authorStartDeathYear',
434             id: 'authorStartDeathYear',
435             maxLength: 4,
436             validator: function(value) {
437                 if (value.match(/\D/) != null) return 'You can only enter year in YYYY format.';
438                 else return true;
439             },
440             autoCreate: {tag: 'input', type: 'text', size: 4, maxlength: 4, style: 'width: auto'}
441     };
442 
443     var authorEndDeathDate = {
444             fieldLabel: 'Death Year to',
445             name: 'authorEndDeathYear',
446             id: 'authorEndDeathYear',
447             maxLength: 4,
448             validator: function(value) {
449                 if (value.match(/\D/) != null) return 'You can only enter year in YYYY format.';
450                 else return true;
451             },
452             autoCreate: {tag: 'input', type: 'text', size: 4, maxlength: 4, style: 'width: auto'}
453     };
454 
455 
456     var workGenre={
457             id: 'genre'
458             ,name: 'genre'
459             ,xtype: 'combo'
460             ,forceSelection :false
461             ,triggerAction: 'all'
462             ,fieldLabel: 'Genre'
463             ,name: 'genre'
464             ,valueField : 'id'
465             ,displayField : 'label'
466             ,store : this.genreStore
467             ,mode : 'local'
468             ,width: 100
469     };
470 
471     var workCirculationDateStart = {
472             fieldLabel: 'Circulation Date Start',
473             name: 'circulationDateStart',
474             id: 'circulationDateStart',
475             maxLength: 4,
476             validator: function(value) {
477                 if (value.match(/\D/) != null) return 'You can only enter year in YYYY format.';
478                 else return true;
479             },
480             autoCreate: {tag: 'input', type: 'text', size: 4, maxlength: 4, style: 'width: auto'}
481     };
482 
483 
484     var workCirculationDateEnd = {
485             fieldLabel: 'Circulation Date End',
486             name: 'circulationDateEnd',
487             id: 'circulationDateEnd',
488             maxLength: 4,
489             validator: function(value) {
490                 if (value.match(/\D/) != null) return 'You can only enter year in YYYY format.';
491                 else return true;
492             },
493             autoCreate: {tag: 'input', type: 'text', size: 4, maxlength: 4, style: 'width: auto'}
494     };
495 
496      var workTitle = {
497             fieldLabel: 'Title with pattern',
498             name: 'titlePattern',
499             id: 'titlePattern',
500             width: 210
501      };
502 
503      this.authorStore.add(new this.authorRecord({
504             name:'All',birthYear:-1,deathYear:-1,numWorks:-1,gender:' '
505         }));
506 
507       Workbench.console.info(this.collectionDS[0].id);
508 
509 
510         this.advancedSearchDialog = new Ext.Window({
511             title: 'Advanced Search',
512             height: 380,
513             width: 380,
514             modal: false,
515             shadow: true,
516             plain: true,
517             border: false,
518             collapsible: false,
519             bodyStyle: 'padding-top: 10px',
520             items: {
521                 id: 'advanced-search-form',
522                 xtype: 'form',
523                 labelAlign: 'right',
524                 labelWidth: 135,
525                 autoHeight: true,
526                 border: false,
527                 defaultType: 'textfield',
528                 items: [
529                     collectionCombo,
530                     authorCombo,
531                     authorGenderCombo,
532                     authorStartBirthDate,
533                     authorEndBirthDate,
534                     authorStartDeathDate,
535                     authorEndDeathDate,
536                     workTitle,
537                     workGenre,
538                     workCirculationDateStart,
539                     workCirculationDateEnd
540                 ]
541             },
542               buttons: [{
543                     id: 'gobutton',
544                     xtype: 'button',
545                     fieldLabel: 'Click to Search.',
546                     text: 'Search',
547                     tooltip: 'click here to search',
548                     listeners :{
549                         click :{fn : function(){
550                             var form = Ext.getCmp('advanced-search-form').getForm();
551                             if (form.isValid()) {
552                                 this.sendSearchNotification(form);
553                             } else {
554                                 Monk.component.messenger.show({
555                                     title: 'Advanced Search',
556                                     msg: 'The form is not valid.  Please correct the highlighted field(s) and try again.',
557                                     width: 240,
558                                     modal: true
559                                });
560                             }
561                         }, scope: this}
562                     }
563                 },{
564                     text: 'Cancel',
565                     handler: function(){
566                         this.advancedSearchDialog.hide();
567                     },
568                     scope: this
569                 }
570             ]
571         });
572 
573     }
574 });
575