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, StringUtils} 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:<span>{{searchUtils.keyword}}<a (click) = "clearKeywords() "><span class=" clickable" aria-hidden="true">[<i class="uk-icon-remove"></i>]</span></a></span>
25
                </span>
26
                <span *ngFor="let filter of filters " >
27
                  <span *ngIf = "filter.countSelectedValues > 0"> {{filter.title}}:
28
                    <span *ngFor="let value of getSelectedValues(filter); let i = index;  let end = last; " >{{value.name}}<a (click) = "removeFilter(value, filter) "><span class=" e clickable" aria-hidden="true">[<i class="uk-icon-remove"></i>]</span></a>
29
                     <span *ngIf="!end">, </span>
30
                    </span>
31
                  </span>
32
                </span>
33
                <a  (click)="clearFilters()"  class = "btn uk-text-right"> Clear Filters[<i class="uk-icon-remove"></i>]</a>
34
              </div>
35
              <a *ngIf = "advancedSearchLink && advancedSearchLink.length > 0" routerLinkActive="router-link-active" class="uk-float-right" [routerLink]=advancedSearchLink >More search options <i class="uk-icon-angle-double-right"></i></a>
36
          </div>
37
          <div  class="uk-grid uk-width-1-1 uk-margin">
38
            <div class=" search-filters uk-width-large-1-4  uk-width-medium-1-4  uk-width-small-1-1">
39
               <search-filter  *ngFor="let filter of filters " [filter]="filter"  [showResultCount]=showResultCount (change)="filterChanged($event)"></search-filter>
40
            </div>
41

    
42
            <div class="uk-width-large-3-4  uk-width-medium-3-4  uk-width-small-1-1" >
43
              <search-paging [type]="type" [(searchUtils)] = "searchUtils"  [(results)] = "results"  [(baseUrl)] = "baseUrl" [(parameterNames)] = "parameterNames" [(parameterValues)] = "parameterValues" ></search-paging>
44
              <search-download [type]="csvPath" [csvParams]="csvParams" [totalResults]="searchUtils.totalResults" (downloadClick)="downloadClicked($event)"></search-download>
45
              <search-result    [results]="results"
46
                                [status]=searchUtils.status
47
                                [type]="entityType" [urlParam]="urlParam">
48
              </search-result>
49
            </div>
50
          </div>
51
        </div>
52

    
53

    
54
        <div *ngIf="!showRefine" >
55
            <search-form [(keyword)]="searchUtils.keyword" (keywordChange)="keywordChanged($event)"></search-form>
56
            <search-paging [type]="type" [(searchUtils)] = "searchUtils"  [(results)] = "results"   [(baseUrl)] = "baseUrl"  [(parameterNames)] = "parameterNames" [(parameterValues)] = "parameterValues"></search-paging>
57
            <search-download [type]="csvPath" [csvParams]="csvParams" [totalResults]="searchUtils.totalResults" (downloadClick)="downloadClicked($event)"></search-download>
58
            <search-result  [results]="results"
59
                            [status]=searchUtils.status
60
                            [type]="entityType" [urlParam]="urlParam">
61
            </search-result>
62
        </div>
63
      </div>
64
    </div>
65

    
66
    <modal-loading [message]= "'Loading results...'"></modal-loading>
67

    
68
    `
69
})
70
export class SearchPageComponent {
71
  @Input() pageTitle = "";
72
  @Input() results = [];
73
  @Input() filters = [];
74
  @Input() type:string = "";
75
  @Input() entityType: string = "";
76
  @Input() searchUtils:SearchUtilsClass = new SearchUtilsClass();
77
  @Output() queryChange  = new EventEmitter();
78
  @Output() downloadClick = new EventEmitter();
79
  @Input() baseUrl:string = '';
80
  @Input() showResultCount:boolean = true;
81
  @Input() showRefine:boolean = true;
82
  @Input() refineFields = [];
83
  @Input() csvParams: string;
84
  @Input() csvPath: string;
85
  @Input() advancedSearchLink: string = "";
86
  @ViewChild (ModalLoading) loading : ModalLoading ;
87
  public fieldIdsMap;//:  { [key:string]:{ name:string, operator:string, type:string, indexField:string, equalityOperator:string  }};
88
  private searchFieldsHelper:SearchFields = new SearchFields();
89
  private queryParameters: Map<string, string>  = new Map<string,string>();
90
  private baseURLWithParameters:string = '';
91
  private sub: any;
92
  public countFilters= 0;
93
  public urlParam: string;
94
  public parameterNames:string[] =[];
95
  public parameterValues:string[] =[];
96
  constructor (private location: Location ) {
97

    
98
   }
99

    
100
  ngOnInit() {
101
        this.updateBaseUrlWithParameters(this.filters);
102
        this.defineUrlParam();
103
        //console.info(this.entityType + "   " + this.urlParam);
104
  }
105
  ngAfterViewChecked(){
106

    
107
  }
108

    
109
  private defineUrlParam() {
110
      if(this.entityType == "publication") {
111
          this.urlParam = "articleId";
112
      } else if(this.entityType == "dataset") {
113
          this.urlParam = "datasetId";
114
      } else if(this.entityType == "project") {
115
          this.urlParam = "projectId";
116
      } else if(this.entityType == "organization") {
117
          this.urlParam = "organizationId";
118
      } else if(this.entityType == "person") {
119
          this.urlParam = "personId";
120
      } else {
121
          this.urlParam = "datasourceId";
122
      }
123
  }
124

    
125
  public getQueryParametersFromUrl(params){
126
    // var parameters = "";
127
    var allFqs = "";
128

    
129
    for(var i=0; i< this.refineFields.length ; i++){
130
         var filterId =  this.refineFields[i];
131

    
132
          if(params[filterId] != undefined) {
133
            if(this.queryParameters == undefined){
134
              this.queryParameters = new Map<string,string>();
135
            }
136
             this.queryParameters[filterId]=StringUtils.URIDecode(params[filterId]);
137
             let values = (StringUtils.URIDecode(this.queryParameters[filterId])).split(/,(?=(?:[^\"]*\"[^\"]*\")*[^\"]*$)/,-1);
138
             var countvalues = 0;
139
             var fq = "";
140
             for(let value of values) {
141
               countvalues++;
142
               var paramId = this.fieldIdsMap[filterId].param;
143
              // parameters+='&' + paramId+ '='+ value;//+"&" + this.fieldIdsMap[paramId].operator + "="+((countvalues == 1)?"and":"or");
144
              fq+=(fq.length > 0 ? " " + "or" + " ":"" ) + filterId +" exact " +value;// StringUtils.quote(value) ;
145
             }
146
             if(countvalues > 0){
147
               fq="&fq="+fq;
148
             }
149
             allFqs += fq;
150
          }
151

    
152

    
153
   }
154
   var keyword = params['keyword'];
155
   var doiQuery = "";
156
   var keywordQuery = "";
157
   if((keyword && keyword.length > 0)){
158
      if((this.type == 'publications' ||this.type == 'datasets')){
159
        var DOIs:string[] = DOI.getDOIsFromString(keyword);
160
       var doisParams = "";
161

    
162
       for(var i =0 ;i < DOIs.length; i++){
163
         doisParams+=(doisParams.length > 0?"&":"")+'doi="'+ DOIs[i]+'"';
164
       }
165
       if(doisParams.length > 0){
166
         doiQuery += "&"+doisParams;
167
       }else {
168
        keywordQuery += "&q="+StringUtils.URIEncode(keyword);
169
       }
170
     }else{
171
        keywordQuery += "&q="+StringUtils.URIEncode(keyword);
172

    
173
     }
174
   }
175
   return (doiQuery.length > 0 ? doiQuery:keywordQuery) + allFqs;
176
 }
177
 public getIndexQueryParametersFromUrl(params){
178
  //  var parameters = "";
179
   var allFqs = "";
180

    
181
   for(var i=0; i< this.refineFields.length ; i++){
182
        var filterId =  this.refineFields[i];
183
        var fq = "";
184
         if(params[filterId] != undefined) {
185
           if(this.queryParameters == undefined){
186
             this.queryParameters = new Map<string,string>();
187
           }
188
            this.queryParameters[filterId]=decodeURIComponent(params[filterId]);
189
            let values = (decodeURIComponent(this.queryParameters[filterId])).split(/,(?=(?:[^\"]*\"[^\"]*\")*[^\"]*$)/,-1);
190
            var countvalues = 0
191
            for(let value of values) {
192
              countvalues++;
193
              // parameters+= ((countvalues == 1)?" and (":" or ")+ filterId+ '='+ value;
194
              fq+=(fq.length > 0 ? " " + "or" + " ":"" ) + filterId + " exact " + value;//StringUtils.quote(value);
195
            }
196
            // parameters+= " ) ";
197
            if(countvalues > 0){
198
              fq="&fq="+fq;
199
            }
200
            allFqs += fq;
201
        }
202

    
203
  }
204
  var keyword = params['keyword'];
205
  var doiQuery = "";
206
  var keywordQuery = "";
207
  if((keyword && keyword.length > 0)){
208
    if((this.type == 'publications' ||this.type == 'datasets')){
209
      var DOIs:string[] = DOI.getDOIsFromString(keyword);
210
      var doisParams = "";
211

    
212
      for(var i =0 ;i < DOIs.length; i++){
213
        doisParams+=(doisParams.length > 0?"&":"")+'doi="'+ DOIs[i]+'"';
214
      }
215
      if(doisParams.length > 0){
216
        doiQuery += "&"+doisParams;
217
      }
218
    }else{
219
       keywordQuery += "and ("+StringUtils.quote(StringUtils.URIEncode(keyword)) +")";
220

    
221
    }
222
  }
223
  return (doiQuery.length > 0 ? doiQuery:keywordQuery) + allFqs;
224

    
225
}
226
 /*
227
 * Mark as check the new filters that are selected, when you get them from search
228
 */
229
  public checkSelectedFilters(filters:Filter[]){
230
    this.filters = filters;
231
       for(var i=0; i< filters.length ; i++){
232
            var filter:Filter = filters[i];
233
            filter.countSelectedValues = 0;
234
              if(this.queryParameters[filter.filterId] != undefined) {
235
                let values = (decodeURIComponent(this.queryParameters[filter.filterId])).split(/,(?=(?:[^\"]*\"[^\"]*\")*[^\"]*$)/,-1);
236
                     for(let filterValue of filter.values) {
237
                       if(values.indexOf(StringUtils.quote(filterValue.id)) > -1) {
238
                            filterValue.selected = true;
239
                            filter.countSelectedValues++;
240
                         }else{
241
                           filterValue.selected = false;
242

    
243
                         }
244
                    }
245
            }else{
246
              for(let filterValue of filter.values) {
247
                 filterValue.selected = false;
248
              }
249
            }
250
        }
251

    
252
        return filters;
253
  }
254
  /*
255
  * Update the url with proper parameters. This is used as base url in Paging Component
256
  */
257
  public updateBaseUrlWithParameters(filters:Filter[]){
258
    this.baseURLWithParameters = this.baseUrl + this.createUrlParameters(filters,false);
259
  }
260
  /*
261
  *
262
  */
263
  private createUrlParameters(filters:Filter[], includePage:boolean){
264
    var allLimits="";//location.search.slice(1);
265
    this.parameterNames.splice(0,this.parameterNames.length);
266
    this.parameterValues.splice(0,this.parameterValues.length);
267

    
268
    for (let filter of filters){
269
      var filterLimits="";
270
      if(filter.countSelectedValues > 0){
271
        for (let value of filter.values){
272
          if(value.selected == true){
273
            filterLimits+=((filterLimits.length == 0)?'':',') +'"'+ StringUtils.URIEncode(value.id)+'"';
274
           }
275
        }
276
        this.queryParameters[filter.filterId]=filterLimits;
277
        if(filterLimits.length > 0){
278
          this.parameterNames.push(filter.filterId);
279
          this.parameterValues.push(filterLimits);
280
        }
281
        allLimits+=(allLimits.length==0?"?":"&")+((filterLimits.length == 0 )?'':filter.filterId + '='+ filterLimits) ;
282
      }
283
    }
284
    if(this.searchUtils.keyword.length > 0 ){
285
       allLimits+=(allLimits.length==0?"?":"&")+'keyword=' + this.searchUtils.keyword;
286
      this.parameterNames.push("keyword");
287
      this.parameterValues.push(this.searchUtils.keyword);
288
     }
289
    if(this.searchUtils.page != 1 && includePage){
290
       allLimits+=((allLimits.length == 0)?'?':'&') + 'page=' + this.searchUtils.page;
291
    }
292

    
293
    return allLimits;
294
  }
295
  /*
296
  *
297
  */
298
  private createSearchQueryParameters(filters:Filter[]){
299
    var allFqs = "";
300
    for (let filter of filters){
301
      if(filter.countSelectedValues > 0){
302
        var fq = "";
303
        var count_selected=0;
304
        for (let value of filter.values){
305
          if(value.selected == true){
306
              count_selected++;
307
              fq+=(fq.length > 0 ? " " + filter.filterOperator + " ":"" ) + filter.filterId +  " exact " + StringUtils.quote(StringUtils.URIEncode(value.id));
308
           }
309
        }
310
        fq="&fq="+fq;
311
        allFqs += fq;
312
      }
313
    }
314
    var doiQuery = "";
315
    var keywordQuery = "";
316
    if((this.searchUtils.keyword && this.searchUtils.keyword.length > 0)){
317
      if((this.type == 'publications' ||this.type == 'datasets')){
318
        var DOIs:string[] = DOI.getDOIsFromString(this.searchUtils.keyword);
319
        var doisParams = "";
320

    
321
        for(var i =0 ;i < DOIs.length; i++){
322
          doisParams+=(doisParams.length > 0?"&":"")+'doi="'+ DOIs[i]+'"';
323
        }
324
        if(doisParams.length > 0){
325
          doiQuery += "&"+doisParams;
326
        }else{
327
          keywordQuery += "&q="+StringUtils.URIEncode(this.searchUtils.keyword);
328
        }
329
      }else{
330
           keywordQuery += "&q="+StringUtils.URIEncode(this.searchUtils.keyword);
331
      }
332
    }
333

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

    
336
  }
337
  private createIndexQueryParameters(filters:Filter[]){
338
    var allFqs = "";
339
    for (let filter of filters){
340
      if(filter.countSelectedValues > 0){
341
        var count_selected=0;
342
        var fq = "";
343
        for (let value of filter.values){
344
          if(value.selected == true){
345
              count_selected++;
346
               fq+=(fq.length > 0 ? " " + filter.filterOperator + " ":"" ) + filter.filterId + " exact " + StringUtils.quote(StringUtils.URIEncode(value.id));
347
           }
348
        }
349
        if(count_selected > 0){
350
          fq="&fq="+fq;
351
          allFqs += fq;
352
        }
353
      }
354
    }
355
    var doiQuery = "";
356
    var keywordQuery = "";
357
    if((this.searchUtils.keyword && this.searchUtils.keyword.length > 0)){
358
      if((this.type == 'publications' ||this.type == 'datasets')){
359
        var DOIs:string[] = DOI.getDOIsFromString(this.searchUtils.keyword);
360
        var doisParams = "";
361
        for(var i =0 ;i < DOIs.length; i++){
362
          doisParams+=(doisParams.length > 0?"&":"")+'doi="'+ DOIs[i]+'"';
363
        }
364
        if(doisParams.length > 0){
365
          doiQuery += "&"+doisParams;
366
        }
367
      }else{
368
         keywordQuery += " and ("+StringUtils.quote(StringUtils.URIEncode(this.searchUtils.keyword)) +")"
369

    
370
      }
371
    }
372
    return (doiQuery.length > 0 ? doiQuery:keywordQuery) + allFqs;
373

    
374
  }
375
  private isFiltered(){
376
    var filtered=false;
377
    for (let filter of this.filters){
378
       if(filter.countSelectedValues > 0){
379
           filtered = true;
380
           break;
381
       }
382
     }
383
    if(this.searchUtils.keyword.length > 0 ){
384
      filtered = true;
385
    }
386
    return filtered;
387
  }
388
  private clearKeywords(){
389
    if(this.searchUtils.keyword.length > 0 ){
390
      this.searchUtils.keyword ='';
391
    }
392
    this.goTo(1);
393
  }
394
  private clearFilters(){
395
    for (var i =0 ; i <  this.filters.length; i++){
396
         for (var j=0; j <  this.filters[i].countSelectedValues; j++){
397
          if(this.filters[i].values[j].selected){
398
            this.filters[i].values[j].selected = false;
399
           }
400
        this.filters[i].countSelectedValues = 0;
401
      }
402
    }
403
    this.clearKeywords();
404

    
405
  }
406
  private removeFilter(value:Value,filter:Filter){
407
    filter.countSelectedValues--;
408
    if(value.selected == true){
409
      value.selected = false;
410
     }
411
    this.goTo(1);
412

    
413
  }
414
  goTo(page:number = 1){
415
    this.searchUtils.page = page;
416
    console.info("searchUtils.page goto = "+this.searchUtils.page);
417
    this.queryParameters = new Map<string,string>();
418
    var urlParameters = this.createUrlParameters(this.filters,true);
419
    console.info("urlParams : "+urlParameters);
420
    this.updateBaseUrlWithParameters(this.filters);
421
    var queryParameters = this.createSearchQueryParameters(this.filters);
422
    console.info("queryParams : "+queryParameters);
423
    var indexQuery = this.createIndexQueryParameters(this.filters);
424

    
425
    this.location.go(location.pathname,urlParameters);
426

    
427
    this.queryChange.emit({
428
        value: queryParameters,
429
        index:indexQuery
430

    
431
    });
432

    
433
  }
434
  filterChanged($event){
435
       this.goTo(1);
436
  }
437
  keywordChanged($event) {
438
       this.searchUtils.keyword = $event.value;
439
       this.goTo(1);
440
  }
441

    
442
	downloadClicked($event) {
443
		if($event.value == true) {
444
		    var queryParameters = this.createSearchQueryParameters(this.filters);
445

    
446
		    this.downloadClick.emit({
447
		        value: queryParameters
448
		    });
449
		}
450
	}
451

    
452
  /*
453
  * Get A sub-array of this.refineFields array, which contains the ids of the selected filters
454
  */
455
  public getSelectedFilters():string[] {
456
    var selected:string[] = [];
457
    for(var i=0; i <  this.filters.length; i++){
458
      var filter:Filter = this.filters[i];
459
      if(filter.countSelectedValues > 0){
460
          selected.push(filter.filterId);
461
      }
462
    }
463
    return selected;
464
  }
465
  /*
466
  * Get A sub-array of this.refineFields array, which contains the ids of the selected parameters
467
  */
468
  private getSelectedParameters():string[] {
469
    var selected:string[] = [];
470
    var params:string[] = Object.keys(this.queryParameters);
471
    for(var i=0; i <  params.length; i++){
472
       if(this.refineFields.indexOf(params[i]) > -1){
473
          selected.push(params[i]);
474
      }
475
    }
476
    return selected;
477
  }
478
  /*
479
  * 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 )
480
  */
481
  public getFields():string[] {
482
    var selected_filters:string[] = this.getSelectedFilters();
483
    if(selected_filters.length == 0){
484
      selected_filters = this.getSelectedParameters();
485
    }
486
    var fields:string[] = [];
487
    for(var i =0 ; i < this.refineFields.length;i++){
488
      var dependentTo = this.searchFieldsHelper.DEPENDENT_FIELDS[this.refineFields[i]];
489

    
490
      //if filter is not marked as hidden OR it is hidden but it is dependent to a field that it IS selected
491
      if(this.searchFieldsHelper.HIDDEN_FIELDS.indexOf(this.refineFields[i]) == -1 || (selected_filters.indexOf(dependentTo) != -1) ){
492
          fields.push(this.refineFields[i]);
493
       }
494
    }
495
    return fields;
496
  }
497
  /*
498
  * Get a query  string of all fields, that want to get from search (e.g. &fields=funderid&fields=projectstartyear&...))
499
  */
500
  public getRefineFieldsQuery():string{
501

    
502
    var fields:string[] = this.getFields();
503
    var fieldsStr = ""
504
    for(var i =0 ; i < fields.length  ;i++){
505
        fieldsStr+="&fields="+fields[i];
506
    }
507
    return "&refine=true"+fieldsStr;
508
  }
509

    
510
  // for loading
511
  public openLoading(){
512
    if(this.loading){
513
      this.loading.open();
514
    }
515
  }
516
  public closeLoading(){
517
    if(this.loading){
518
      this.loading.close();
519
    }
520
  }
521
  getSelectedValues(filter):any{
522
    var selected = [];
523
    if(filter.countSelectedValues >0){
524
      for (var i=0; i < filter.values.length; i++){
525
        if(filter.values[i].selected){
526
          selected.push(filter.values[i]);
527
        }
528
      }
529
    }
530
    return selected;
531

    
532
  }
533
}
(16-16/22)