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