Project

General

Profile

1
import {Component, Input, ViewChild, Output, EventEmitter} from '@angular/core';
2
import {Observable}       from 'rxjs/Observable';
3
import {Location} from '@angular/common';
4
import { Filter, Value} from './searchHelperClasses.class';
5
import {SearchResult}     from '../../utils/entities/searchResult';
6
import {SearchFields} from '../../utils/properties/searchFields';
7
import {SearchUtilsClass} from './searchUtils.class';
8
import {DOI} from '../../utils/string-utils.class';
9
import {ModalLoading} from '../../utils/modal/loading.component';
10

    
11
@Component({
12
    selector: 'search-page',
13
    template: `
14

    
15
    <div class="uk-margin-top">
16
      <div class="page-header">
17
          <h1>{{pageTitle}}</h1>
18
      </div>
19
      <div>
20
        <div *ngIf="showRefine" class="uk-grid">
21
          <div  class="uk-width-1-1  uk-margin uk-panel uk-panel-box uk-panel-box-default">
22
              <search-form [(keyword)]="searchUtils.keyword" (keywordChange)="keywordChanged($event)"></search-form>
23
              <div *ngIf="isFiltered()" class = " uk-text-center ">
24
                <span *ngIf = "searchUtils.keyword.length > 0">Keywords:
25
                  <span>{{searchUtils.keyword}}<a (click) = "clearKeywords() "> <span class=" clickable" aria-hidden="true"><i class="uk-icon-remove"></i></span></a></span>
26
                </span>
27
                <span *ngFor="let filter of filters " >
28
                  <span *ngIf = "filter.countSelectedValues > 0"> {{filter.title}}:
29
                    <span *ngFor="let value of filter.values.slice(0,filter.countSelectedValues); let i = index;  let end = last; " >
30
                       {{value.name}} <a (click) = "removeFilter(value, filter) "> <span class=" e clickable" aria-hidden="true"><i class="uk-icon-remove"></i></span></a>
31
                       <span *ngIf="!end">,</span>
32
                    </span>
33
                  </span>
34
                </span>
35
                <a  (click)="clearFilters()"  class = "btn uk-text-right"> Clear Filters</a>
36
              </div>
37
          </div>
38
          <div  class="uk-grid uk-width-1-1 uk-margin">
39
            <div class=" search-filters uk-width-large-1-4  uk-width-medium-1-4  uk-width-small-1-1">
40
               <search-filter  *ngFor="let filter of filters " [filter]="filter"  [showResultCount]=showResultCount (change)="filterChanged($event)"></search-filter>
41
            </div>
42

    
43
            <div class="uk-width-large-3-4  uk-width-medium-3-4  uk-width-small-1-1" >
44
              <search-download [totalResults]="searchUtils.totalResults" (downloadClick)="downloadClicked($event)"></search-download>
45
              <search-paging [type]="type" [(searchUtils)] = "searchUtils"  [(results)] = "results"  [(baseUrl)] = "baseURLWithParameters"></search-paging>
46
              <search-result [results]="results" [totalResults]="searchUtils.totalResults" [status]=searchUtils.status [page]="searchUtils.page"></search-result>
47
            </div>
48
          </div>
49
        </div>
50

    
51

    
52
        <div *ngIf="!showRefine" >
53

    
54
            <search-form [(keyword)]="searchUtils.keyword" (keywordChange)="keywordChanged($event)"></search-form>
55
            <search-paging [type]="type" [(searchUtils)] = "searchUtils"  [(results)] = "results"   [(baseUrl)] = "baseURLWithParameters"></search-paging>
56
             <search-result [results]="results" [totalResults]="searchUtils.totalResults" [status]=searchUtils.status [page]="searchUtils.page"></search-result>
57

    
58
        </div>
59
      </div>
60
    </div>
61

    
62
    <modal-loading [message]= "'Loading results...'"></modal-loading>
63

    
64
    `
65
})
66
export class SearchPageComponent {
67
  @Input() pageTitle = "";
68
  @Input() results = [];
69
  @Input() filters = [];
70
  @Input() type:string = "";
71
  @Input() searchUtils:SearchUtilsClass = new SearchUtilsClass();
72
  @Output() queryChange  = new EventEmitter();
73
  @Output() downloadClick = new EventEmitter();
74
  @Input() baseUrl:string = '';
75
  @Input() showResultCount:boolean = true;
76
  @Input() showRefine:boolean = true;
77
  @Input() refineFields = [];
78
  @ViewChild (ModalLoading) loading : ModalLoading ;
79
  public fieldIdsMap;//:  { [key:string]:{ name:string, operator:string, type:string, indexField:string, equalityOperator:string  }};
80
  private searchFieldsHelper:SearchFields = new SearchFields();
81
  private queryParameters: Map<string, string>  = new Map<string,string>();
82
  private baseURLWithParameters:string = '';
83
  private sub: any;
84

    
85
  constructor (private location: Location ) {
86

    
87
   }
88

    
89
  ngOnInit() {
90
        this.updateBaseUrlWithParameters(this.filters);
91
  }
92
  ngAfterViewChecked(){
93

    
94
  }
95

    
96
  public getQueryParametersFromUrl(params){
97
    //TODO when final search is done-allFqs/fq
98

    
99
    var parameters = "";
100
    var allFqs = "";
101

    
102
    for(var i=0; i< this.refineFields.length ; i++){
103
         var filterId =  this.refineFields[i];
104

    
105
          if(params[filterId] != undefined) {
106
            if(this.queryParameters == undefined){
107
              this.queryParameters = new Map<string,string>();
108
            }
109
             this.queryParameters[filterId]=decodeURIComponent(params[filterId]);
110
             let values = decodeURIComponent(this.queryParameters[filterId]).split(",");
111
             var countvalues = 0;
112
             var fq = "";
113
             for(let value of values) {
114
               countvalues++;
115
               var paramId = this.fieldIdsMap[filterId].param;
116
              parameters+='&' + paramId+ '='+ value;//+"&" + this.fieldIdsMap[paramId].operator + "="+((countvalues == 1)?"and":"or");
117
              fq+=(fq.length > 0 ? " " + "or" + " ":"" ) + filterId +" exact " + this.quote(value) ;
118
             }
119
             if(countvalues > 0){
120
               fq="&fq="+fq;
121
             }
122
             allFqs += fq;
123
          }
124

    
125

    
126
   }
127
   var keyword = params['keyword'];
128
   console.info("Type:" + this.type + "filters: "+allFqs);
129
   var doiQuery = "";
130
   var keywordQuery = "";
131
   if((keyword && keyword.length > 0)){
132
     if((this.type == 'publications' ||this.type == 'datasets')){
133
       var DOIs:string[] = DOI.getDOIsFromString(keyword);
134
       var doisParams = "";
135

    
136
       for(var i =0 ;i < DOIs.length; i++){
137
         doisParams+=(doisParams.length > 0?" or ":"")+'((pidclassid exact doi) and (pid exact "'+ DOIs[i]+'"))';
138
       }
139
       if(doisParams.length > 0){
140
         doiQuery += "q=("+doisParams+")"
141
       }
142
     }else{
143
        keywordQuery += "q=("+this.quote(keyword) +")"
144

    
145
     }
146
   }
147
   return (doiQuery.length > 0 ? doiQuery:keywordQuery) + allFqs;
148
 }
149
 public getIndexQueryParametersFromUrl(params){
150
   var parameters = "";
151
   var allFqs = "";
152

    
153
   for(var i=0; i< this.refineFields.length ; i++){
154
        var filterId =  this.refineFields[i];
155
        var fq = "";
156
         if(params[filterId] != undefined) {
157
           if(this.queryParameters == undefined){
158
             this.queryParameters = new Map<string,string>();
159
           }
160
            this.queryParameters[filterId]=decodeURIComponent(params[filterId]);
161
            let values = decodeURIComponent(this.queryParameters[filterId]).split(",");
162
            var countvalues = 0
163
            for(let value of values) {
164
              countvalues++;
165
              parameters+= ((countvalues == 1)?" and (":" or ")+ filterId+ '='+ value;
166
              fq+=(fq.length > 0 ? " " + "or" + " ":"" ) + filterId + " exact " + this.quote(value);
167
            }
168
            parameters+= " ) ";
169
            if(countvalues > 0){
170
              fq="&fq="+fq;
171
            }
172
            allFqs += fq;
173
        }
174

    
175
  }
176
  var keyword = params['keyword'];
177
  var doiQuery = "";
178
  var keywordQuery = "";
179
  if((keyword && keyword.length > 0)){
180
    if((this.type == 'publications' ||this.type == 'datasets')){
181
      var DOIs:string[] = DOI.getDOIsFromString(keyword);
182
      var doisParams = "";
183

    
184
      for(var i =0 ;i < DOIs.length; i++){
185
        doisParams+=(doisParams.length > 0?" or ":"")+'((pidclassid exact doi) and (pid exact "'+ DOIs[i]+'"))';
186
      }
187
      if(doisParams.length > 0){
188
        doiQuery += "and ("+doisParams+")"
189
      }
190
    }else{
191
       keywordQuery += "and ("+this.quote(keyword) +")"
192

    
193
    }
194
  }
195
  return (doiQuery.length > 0 ? doiQuery:keywordQuery) + allFqs;
196

    
197
}
198
 /*
199
 * Mark as check the new filters that are selected, when you get them from search
200
 */
201
  public checkSelectedFilters(filters:Filter[]){
202
    this.filters = filters;
203
       for(var i=0; i< filters.length ; i++){
204
            var filter:Filter = filters[i];
205
            filter.countSelectedValues = 0;
206
              if(this.queryParameters[filter.filterId] != undefined) {
207
                let values = decodeURIComponent(this.queryParameters[filter.filterId]).split(",");
208
                    for(let filterValue of filter.values) {
209
                      if(values.indexOf(filterValue.id) > -1) {
210
                            filterValue.selected = true;
211
                            filter.countSelectedValues++;
212
                         }else{
213
                           filterValue.selected = false;
214

    
215
                         }
216
                    }
217
            }else{
218
              for(let filterValue of filter.values) {
219
                 filterValue.selected = false;
220
              }
221
            }
222
        }
223

    
224
        return filters;
225
  }
226
  /*
227
  * Update the url with proper parameters. This is used as base url in Paging Component
228
  */
229
  public updateBaseUrlWithParameters(filters:Filter[]){
230
    this.baseURLWithParameters = this.baseUrl + this.createUrlParameters(filters,false);
231
  }
232
  /*
233
  *
234
  */
235
  private createUrlParameters(filters:Filter[], includePage:boolean){
236
    var allLimits="";//location.search.slice(1);
237
    for (let filter of filters){
238
      var filterLimits="";
239
      if(filter.countSelectedValues > 0){
240
        for (let value of filter.values){
241
          if(value.selected == true){
242
            filterLimits+=((filterLimits.length == 0)?'':',') + encodeURIComponent(value.id);
243
           }
244
        }
245
        this.queryParameters[filter.filterId]=filterLimits;
246
        allLimits+=((filterLimits.length == 0 )?'':"&" +filter.filterId + '='+ filterLimits) ;
247
      }
248
    }
249
    if(this.searchUtils.keyword.length > 0 ){
250
       allLimits+='&keyword=' + this.searchUtils.keyword;
251
    }
252
    if(this.searchUtils.page != 1 && includePage){
253
       allLimits+=((allLimits.length == 0)?'':'&') + 'page=' + this.searchUtils.page;
254
    }
255
    return allLimits;
256
  }
257
  /*
258
  *
259
  */
260
  private createSearchQueryParameters(filters:Filter[]){
261
    var allFqs = "";
262
    for (let filter of filters){
263
      if(filter.countSelectedValues > 0){
264
        var fq = "";
265
        var count_selected=0;
266
        for (let value of filter.values){
267
          if(value.selected == true){
268
              count_selected++;
269
              fq+=(fq.length > 0 ? " " + filter.filterOperator + " ":"" ) + filter.filterId +  " exact " + this.quote(value.id);
270
           }
271
        }
272
        fq="&fq="+fq;
273
        allFqs += fq;
274
      }
275
    }
276
    var doiQuery = "";
277
    var keywordQuery = "";
278
    console.info("keyyyyword::::"+ this.searchUtils.keyword )
279
    if((this.searchUtils.keyword && this.searchUtils.keyword.length > 0)){
280
      if((this.type == 'publications' ||this.type == 'datasets')){
281
        var DOIs:string[] = DOI.getDOIsFromString(this.searchUtils.keyword);
282
        var doisParams = "";
283

    
284
        for(var i =0 ;i < DOIs.length; i++){
285
          doisParams+=(doisParams.length > 0?" or ":"")+'((pidclassid exact doi) and (pid exact "'+ DOIs[i]+'"))';
286
        }
287
        if(doisParams.length > 0){
288
          doiQuery += "q=("+doisParams+")"
289
        }else{
290
          keywordQuery += "q=("+this.quote(this.searchUtils.keyword) +")"
291
        }
292
      }else{
293
         keywordQuery += "q=("+this.quote(this.searchUtils.keyword) +")"
294
      }
295
    }
296
    console.info("keyyyyword:::: doi:"+ doiQuery+ " keyword:"+keywordQuery )
297

    
298
    return (doiQuery.length > 0 ? doiQuery:keywordQuery) + allFqs;
299

    
300
  }
301
  private createIndexQueryParameters(filters:Filter[]){
302
    var allFqs = "";
303
    for (let filter of filters){
304
      if(filter.countSelectedValues > 0){
305
        var count_selected=0;
306
        var fq = "";
307
        for (let value of filter.values){
308
          if(value.selected == true){
309
              count_selected++;
310
               fq+=(fq.length > 0 ? " " + filter.filterOperator + " ":"" ) + filter.filterId + " exact " + this.quote(value.id);
311
           }
312
        }
313
        if(count_selected > 0){
314
          fq="&fq="+fq;
315
          allFqs += fq;
316
        }
317
      }
318
    }
319
    var doiQuery = "";
320
    var keywordQuery = "";
321
    if((this.searchUtils.keyword && this.searchUtils.keyword.length > 0)){
322
      if((this.type == 'publications' ||this.type == 'datasets')){
323
        var DOIs:string[] = DOI.getDOIsFromString(this.searchUtils.keyword);
324
        var doisParams = "";
325
        for(var i =0 ;i < DOIs.length; i++){
326
          doisParams+=(doisParams.length > 0?" or ":"")+'((pidclassid exact doi) and (pid exact "'+ DOIs[i]+'"))';
327
        }
328
        if(doisParams.length > 0){
329
          doiQuery += " and ("+doisParams+")"
330
        }
331
      }else{
332
         keywordQuery += " and ("+this.quote(this.searchUtils.keyword) +")"
333

    
334
      }
335
    }
336
    return (doiQuery.length > 0 ? doiQuery:keywordQuery) + allFqs;
337

    
338
  }
339
  private isFiltered(){
340
    var filtered=false;
341
    for (let filter of this.filters){
342
       if(filter.countSelectedValues > 0){
343
           filtered = true;
344
           break;
345
       }
346
     }
347
    if(this.searchUtils.keyword.length > 0 ){
348
      filtered = true;
349
    }
350
    return filtered;
351
  }
352
  private clearKeywords(){
353
    if(this.searchUtils.keyword.length > 0 ){
354
      this.searchUtils.keyword ='';
355
    }
356
    this.goTo(1);
357
  }
358
  private clearFilters(){
359
    for (var i =0 ; i <  this.filters.length; i++){
360
         for (var j=0; j <  this.filters[i].countSelectedValues; j++){
361
          if(this.filters[i].values[j].selected){
362
            this.filters[i].values[j].selected = false;
363
           }
364
        this.filters[i].countSelectedValues = 0;
365
      }
366
    }
367
    this.clearKeywords();
368

    
369
  }
370
  private removeFilter(value:Value,filter:Filter){
371
    filter.countSelectedValues--;
372
    if(value.selected == true){
373
      value.selected = false;
374
     }
375
    this.goTo(1);
376

    
377
  }
378
  goTo(page:number = 1){
379
    this.searchUtils.page = page;
380
    // console.info("searchUtils.page goto = "+this.searchUtils.page);
381
    this.queryParameters = new Map<string,string>();
382
    var urlParameters = this.createUrlParameters(this.filters,true);
383
    console.info("urlParams : "+urlParameters);
384
    this.updateBaseUrlWithParameters(this.filters);
385
    var queryParameters = this.createSearchQueryParameters(this.filters);
386
    console.info("queryParams : "+queryParameters);
387
    var indexQuery = this.createIndexQueryParameters(this.filters);
388

    
389
    this.location.go(location.pathname,urlParameters);
390
    // console.info("SearchPAGE::page "+this.searchUtils.page);
391

    
392
    this.queryChange.emit({
393
        value: queryParameters,
394
        index:indexQuery
395

    
396
    });
397

    
398
  }
399
  filterChanged($event){
400
       this.goTo(1);
401
  }
402
  keywordChanged($event) {
403
       this.searchUtils.keyword = $event.value;
404
       this.goTo(1);
405
  }
406

    
407
	downloadClicked($event) {
408
		if($event.value == true) {
409
		    var queryParameters = this.createSearchQueryParameters(this.filters);
410

    
411
		    this.downloadClick.emit({
412
		        value: queryParameters
413
		    });
414
		}
415
	}
416

    
417
  /*
418
  * Get A sub-array of this.refineFields array, which contains the ids of the selected filters
419
  */
420
  public getSelectedFilters():string[] {
421
    var selected:string[] = [];
422
    for(var i=0; i <  this.filters.length; i++){
423
      var filter:Filter = this.filters[i];
424
      if(filter.countSelectedValues > 0){
425
          selected.push(filter.filterId);
426
      }
427
    }
428
    return selected;
429
  }
430
  /*
431
  * Get A sub-array of this.refineFields array, which contains the ids of the selected parameters
432
  */
433
  private getSelectedParameters():string[] {
434
    var selected:string[] = [];
435
    var params:string[] = Object.keys(this.queryParameters);
436
    for(var i=0; i <  params.length; i++){
437
       if(this.refineFields.indexOf(params[i]) > -1){
438
          selected.push(params[i]);
439
      }
440
    }
441
    return selected;
442
  }
443
  /*
444
  * Get A sub-array of this.refineFields array, which hides hidden fields (e.g Funding level 0,1,2,..), and contains those that depend on another fields (e.g  Funding level 0 if Funder is selected )
445
  */
446
  public getFields():string[] {
447
    var selected_filters:string[] = this.getSelectedFilters();
448
    if(selected_filters.length == 0){
449
      selected_filters = this.getSelectedParameters();
450
    }
451
    var fields:string[] = [];
452
    for(var i =0 ; i < this.refineFields.length;i++){
453
      var dependentTo = this.searchFieldsHelper.DEPENDENT_FIELDS[this.refineFields[i]];
454

    
455
      //if filter is not marked as hidden OR it is hidden but it is dependent to a field that it IS selected
456
      if(this.searchFieldsHelper.HIDDEN_FIELDS.indexOf(this.refineFields[i]) == -1 || (selected_filters.indexOf(dependentTo) != -1) ){
457
          fields.push(this.refineFields[i]);
458
       }
459
    }
460
    return fields;
461
  }
462
  /*
463
  * Get a query  string of all fields, that want to get from search (e.g. &fields=funderid&fields=projectstartyear&...))
464
  */
465
  public getRefineFieldsQuery():string{
466

    
467
    var fields:string[] = this.getFields();
468
    var fieldsStr = ""
469
    for(var i =0 ; i < fields.length  ;i++){
470
        fieldsStr+="&fields="+fields[i];
471
    }
472
    return "&refine=true"+fieldsStr;
473
  }
474
  private quote(params: string):string {
475
      return encodeURIComponent('"'+params+'"');
476
  }
477
  // for loading
478
  public openLoading(){
479
    this.loading.open();
480
  }
481
  public closeLoading(){
482
      this.loading.close();
483
  }
484

    
485
}
(9-9/12)