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
import { Meta} from '../../../angular2-meta';
11
import{SearchFilterComponent} from './searchFilter.component';
12
import {SearchFilterModalComponent} from './searchFilterModal.component';
13

    
14
@Component({
15
    selector: 'search-page',
16
    template: `
17

    
18
    <div class="uk-margin-top">
19
      <div class="page-header">
20
          <h1>{{pageTitle}}</h1>
21
      </div>
22
      <div>
23
        <div *ngIf="showRefine"  >
24
          <div  class="uk-width-1-1  uk-margin uk-padding uk-panel  uk-background-muted">
25
              <search-form [isDisabled]="disableForms" [(keyword)]="searchUtils.keyword" (keywordChange)="keywordChanged($event)"></search-form>
26
              <div *ngIf="isFiltered()" class = " uk-text-center ">
27
                <span *ngIf = "searchUtils.keyword.length > 0">Keywords: <span>{{searchUtils.keyword}}<a (click) = "clearKeywords() " [class]="(disableForms)?'uk-icon-button uk-disabled':'uk-icon-button'"><span class=" clickable " aria-hidden="true"><span uk-icon="icon: close"></span></span></a></span>
28
                </span>
29
                <span *ngFor="let filter of filters " >
30
                  <span *ngIf = "filter.countSelectedValues > 0"> {{filter.title}}:
31
                    <span *ngFor="let value of getSelectedValues(filter); let i = index;  let end = last; " >{{value.name}}<a (click) = "removeFilter(value, filter) " [class]="(disableForms)?'uk-icon-button uk-disabled':'uk-icon-button'"><span class=" clickable" aria-hidden="true"><span uk-icon="icon: close"></span></span></a>
32
                     <span *ngIf="!end">, </span>
33
                    </span>
34
                  </span>
35
                </span>
36
                <!--span>
37
                 Clear All
38
                <a  (click)="clearFilters()"  class="uk-icon-button uk-text-right"><span uk-icon="icon: close"></span></a></span-->
39
                <a (click)="clearFilters()" [class]="(disableForms)?'uk-disabled uk-link-muted':''">
40
                 Clear All
41
                </a>
42
              </div>
43
              <a *ngIf = "advancedSearchLink && advancedSearchLink.length > 0" routerLinkActive="router-link-active" [class]="(disableForms)?'uk-float-right uk-disabled uk-link-muted':'uk-float-right'" [routerLink]=advancedSearchLink >More search options <span uk-icon="icon: chevron-right"></span></a>
44
          </div>
45
          <div  class="uk-grid uk-width-1-1 uk-margin">
46
            <div class=" search-filters uk-width-1-4@l  uk-width-1-4@m  uk-width-1-1@s ">
47
               <search-filter  *ngFor="let filter of filters " [isDisabled]="disableForms" [filter]="filter"  [showResultCount]=showResultCount (change)="filterChanged($event)" (toggleModal)="toggleModal($event)"></search-filter>
48
            </div>
49

    
50
            <div class="uk-width-3-4@m  uk-width-3-4@l  uk-width-1-1@s uk-first-column" >
51
              <search-paging [type]="type" [(searchUtils)] = "searchUtils"  [(results)] = "results"  [(baseUrl)] = "baseUrl" [(parameterNames)] = "parameterNames" [(parameterValues)] = "parameterValues" ></search-paging>
52
              <search-download [type]="csvPath" [csvParams]="csvParams" [totalResults]="searchUtils.totalResults" (downloadClick)="downloadClicked($event)"></search-download>
53
              <search-result    [results]="results"
54
                                [status]=searchUtils.status
55
                                [type]="entityType" [urlParam]="urlParam"
56
                                [showLoading]="true">
57
              </search-result>
58
            </div>
59

    
60

    
61
          </div>
62
        </div>
63

    
64

    
65
        <div *ngIf="!showRefine" >
66
            <search-form [isDisabled]="disableForms" [(keyword)]="searchUtils.keyword" (keywordChange)="keywordChanged($event)"></search-form>
67
            <search-paging [type]="type" [(searchUtils)] = "searchUtils"  [(results)] = "results"   [(baseUrl)] = "baseUrl"  [(parameterNames)] = "parameterNames" [(parameterValues)] = "parameterValues"></search-paging>
68
            <search-download [type]="csvPath" [csvParams]="csvParams" [totalResults]="searchUtils.totalResults" (downloadClick)="downloadClicked($event)"></search-download>
69
            <search-result  [results]="results"
70
                            [status]=searchUtils.status
71
                            [type]="entityType" [urlParam]="urlParam"
72
                            [showLoading]="true">
73
            </search-result>
74
        </div>
75
      </div>
76
    </div>
77

    
78
    <!--modal-loading [message]= "'Loading results...'"></modal-loading-->
79

    
80
    <modal-search-filter [filter]="currentFilter" [showResultCount]=showResultCount (modalChange)="filterChanged($event)"></modal-search-filter>
81

    
82
    `
83
})
84
export class SearchPageComponent {
85
  @Input() pageTitle = "";
86
  @Input() results = [];
87
  @Input() filters = [];
88
  @Input() type:string = "";
89
  @Input() entityType: string = "";
90
  @Input() searchUtils:SearchUtilsClass = new SearchUtilsClass();
91
  @Output() queryChange  = new EventEmitter();
92
  @Output() downloadClick = new EventEmitter();
93
  @Input() baseUrl:string = '';
94
  @Input() showResultCount:boolean = true;
95
  @Input() showRefine:boolean = true;
96
  @Input() refineFields = [];
97
  @Input() csvParams: string;
98
  @Input() csvPath: string;
99
  @Input() advancedSearchLink: string = "";
100
  @Input() disableForms:boolean = false;
101

    
102
  @ViewChild (ModalLoading) loading : ModalLoading ;
103
  public fieldIdsMap;//:  { [key:string]:{ name:string, operator:string, type:string, indexField:string, equalityOperator:string  }};
104
  private searchFieldsHelper:SearchFields = new SearchFields();
105
  private queryParameters: Map<string, string>  = new Map<string,string>();
106
  private baseURLWithParameters:string = '';
107
  private sub: any;
108
  public countFilters= 0;
109
  public urlParam: string;
110
  public parameterNames:string[] =[];
111
  public parameterValues:string[] =[];
112

    
113
  @ViewChild (SearchFilterModalComponent) searchFilterModal : SearchFilterModalComponent ;
114
  public currentFilter: Filter;
115

    
116
  constructor (private location: Location , private _meta: Meta) {
117
   }
118

    
119
  ngOnInit() {
120
        this.updateBaseUrlWithParameters(this.filters);
121
        this.defineUrlParam();
122
        this.updateTitle(this.pageTitle);
123
        this.updateDescription("Openaire, search, repositories, open access, type, data provider, funder, project, " + this.type + "," +this.pageTitle);
124
        // console.info(this.entityType + "   " + this.urlParam + this.type);
125
  }
126
  ngAfterViewChecked(){
127

    
128
  }
129

    
130
  toggleModal($event) {
131
    this.currentFilter = $event.value;
132
    this.searchFilterModal.open();
133
  }
134

    
135
  updateDescription(description:string){
136
    this._meta.updateMeta("description", description);
137
    this._meta.updateMeta("og:description", description);
138
  }
139
  updateTitle(title:string){
140
    var _suffix ="| OpenAIRE";
141
    var _title = ((title.length> 50 ) ?title.substring(0,50):title) + _suffix;
142
    this._meta.setTitle(_title );
143
    this._meta.updateMeta("og:title",_title);
144
  }
145
  private defineUrlParam() {
146
      if(this.entityType == "publication") {
147
          this.urlParam = "articleId";
148
      } else if(this.entityType == "dataset") {
149
          this.urlParam = "datasetId";
150
      } else if(this.entityType == "project") {
151
          this.urlParam = "projectId";
152
      } else if(this.entityType == "organization") {
153
          this.urlParam = "organizationId";
154
      } else if(this.entityType == "person") {
155
          this.urlParam = "personId";
156
      } else {
157
          this.urlParam = "datasourceId";
158
      }
159
  }
160

    
161
  public getQueryParametersFromUrl(params){
162
    // var parameters = "";
163
    var allFqs = "";
164

    
165
    for(var i=0; i< this.refineFields.length ; i++){
166
         var filterId =  this.refineFields[i];
167

    
168
          if(params[filterId] != undefined) {
169
            if(this.queryParameters == undefined){
170
              this.queryParameters = new Map<string,string>();
171
            }
172
             this.queryParameters[filterId]=StringUtils.URIDecode(params[filterId]);
173
             let values = (StringUtils.URIDecode(this.queryParameters[filterId])).split(/,(?=(?:[^\"]*\"[^\"]*\")*[^\"]*$)/,-1);
174
             var countvalues = 0;
175
             var fq = "";
176
             for(let value of values) {
177
               countvalues++;
178
               var paramId = this.fieldIdsMap[filterId].param;
179
              // parameters+='&' + paramId+ '='+ value;//+"&" + this.fieldIdsMap[paramId].operator + "="+((countvalues == 1)?"and":"or");
180
              fq+=(fq.length > 0 ? " " + "or" + " ":"" ) + filterId +" exact " +value;// StringUtils.quote(value) ;
181
             }
182
             if(countvalues > 0){
183
               fq="&fq="+fq;
184
             }
185
             allFqs += fq;
186
          }
187

    
188

    
189
   }
190
   var keyword = params['keyword'];
191
   var doiQuery = "";
192
   var keywordQuery = "";
193
   if((keyword && keyword.length > 0)){
194
      if((this.type == 'publications' ||this.type == 'datasets')){
195
        var DOIs:string[] = DOI.getDOIsFromString(keyword);
196
       var doisParams = "";
197

    
198
       for(var i =0 ;i < DOIs.length; i++){
199
         doisParams+=(doisParams.length > 0?"&":"")+'doi="'+ DOIs[i]+'"';
200
       }
201
       if(doisParams.length > 0){
202
         doiQuery += "&"+doisParams;
203
       }else {
204
        keywordQuery += "&q="+StringUtils.URIEncode(keyword);
205
       }
206
     }else{
207
        keywordQuery += "&q="+StringUtils.URIEncode(keyword);
208

    
209
     }
210
   }
211
   return (doiQuery.length > 0 ? doiQuery:keywordQuery) + allFqs;
212
 }
213
 public getIndexQueryParametersFromUrl(params){
214
  //  var parameters = "";
215
   var allFqs = "";
216

    
217
   for(var i=0; i< this.refineFields.length ; i++){
218
        var filterId =  this.refineFields[i];
219
        var fq = "";
220
         if(params[filterId] != undefined) {
221
           if(this.queryParameters == undefined){
222
             this.queryParameters = new Map<string,string>();
223
           }
224
            this.queryParameters[filterId]=decodeURIComponent(params[filterId]);
225
            let values = (decodeURIComponent(this.queryParameters[filterId])).split(/,(?=(?:[^\"]*\"[^\"]*\")*[^\"]*$)/,-1);
226
            var countvalues = 0
227
            for(let value of values) {
228
              countvalues++;
229
              // parameters+= ((countvalues == 1)?" and (":" or ")+ filterId+ '='+ value;
230
              fq+=(fq.length > 0 ? " " + "or" + " ":"" ) + filterId + " exact " + value;//StringUtils.quote(value);
231
            }
232
            // parameters+= " ) ";
233
            if(countvalues > 0){
234
              fq="&fq="+fq;
235
            }
236
            allFqs += fq;
237
        }
238

    
239
  }
240
  var keyword = params['keyword'];
241
  var doiQuery = "";
242
  var keywordQuery = "";
243
  if((keyword && keyword.length > 0)){
244
    if((this.type == 'publications' ||this.type == 'datasets')){
245
      var DOIs:string[] = DOI.getDOIsFromString(keyword);
246
      var doisParams = "";
247

    
248
      for(var i =0 ;i < DOIs.length; i++){
249
        doisParams+=(doisParams.length > 0?"&":"")+'doi="'+ DOIs[i]+'"';
250
      }
251
      if(doisParams.length > 0){
252
        doiQuery += "&"+doisParams;
253
      }
254
    }else{
255
       keywordQuery += "and ("+StringUtils.quote(StringUtils.URIEncode(keyword)) +")";
256

    
257
    }
258
  }
259
  return (doiQuery.length > 0 ? doiQuery:keywordQuery) + allFqs;
260

    
261
}
262
 /*
263
 * Mark as check the new filters that are selected, when you get them from search
264
 */
265
  public checkSelectedFilters(filters:Filter[]){
266
    this.filters = filters;
267
       for(var i=0; i< filters.length ; i++){
268
            var filter:Filter = filters[i];
269
            filter.countSelectedValues = 0;
270
              if(this.queryParameters[filter.filterId] != undefined) {
271
                let values = (decodeURIComponent(this.queryParameters[filter.filterId])).split(/,(?=(?:[^\"]*\"[^\"]*\")*[^\"]*$)/,-1);
272
                     for(let filterValue of filter.values) {
273
                       if(values.indexOf(StringUtils.quote(filterValue.id)) > -1) {
274
                            filterValue.selected = true;
275
                            filter.countSelectedValues++;
276
                         }else{
277
                           filterValue.selected = false;
278

    
279
                         }
280
                    }
281
            }else{
282
              for(let filterValue of filter.values) {
283
                 filterValue.selected = false;
284
              }
285
            }
286
        }
287

    
288
        return filters;
289
  }
290
  /*
291
  * Update the url with proper parameters. This is used as base url in Paging Component
292
  */
293
  public updateBaseUrlWithParameters(filters:Filter[]){
294
    this.baseURLWithParameters = this.baseUrl + this.createUrlParameters(filters,false);
295
  }
296
  /*
297
  *
298
  */
299
  private createUrlParameters(filters:Filter[], includePage:boolean){
300
    var allLimits="";//location.search.slice(1);
301
    this.parameterNames.splice(0,this.parameterNames.length);
302
    this.parameterValues.splice(0,this.parameterValues.length);
303

    
304
    for (let filter of filters){
305
      var filterLimits="";
306
      if(filter.countSelectedValues > 0){
307
        for (let value of filter.values){
308
          if(value.selected == true){
309
            filterLimits+=((filterLimits.length == 0)?'':',') +'"'+ StringUtils.URIEncode(value.id)+'"';
310
           }
311
        }
312
        this.queryParameters[filter.filterId]=filterLimits;
313
        if(filterLimits.length > 0){
314
          this.parameterNames.push(filter.filterId);
315
          this.parameterValues.push(filterLimits);
316
        }
317
        allLimits+=(allLimits.length==0?"?":"&")+((filterLimits.length == 0 )?'':filter.filterId + '='+ filterLimits) ;
318
      }
319
    }
320
    if(this.searchUtils.keyword.length > 0 ){
321
       allLimits+=(allLimits.length==0?"?":"&")+'keyword=' + this.searchUtils.keyword;
322
      this.parameterNames.push("keyword");
323
      this.parameterValues.push(this.searchUtils.keyword);
324
     }
325
    if(this.searchUtils.page != 1 && includePage){
326
       allLimits+=((allLimits.length == 0)?'?':'&') + 'page=' + this.searchUtils.page;
327
    }
328

    
329
    return allLimits;
330
  }
331
  /*
332
  *
333
  */
334
  private createSearchQueryParameters(filters:Filter[]){
335
    var allFqs = "";
336
    for (let filter of filters){
337
      if(filter.countSelectedValues > 0){
338
        var fq = "";
339
        var count_selected=0;
340
        for (let value of filter.values){
341
          if(value.selected == true){
342
              count_selected++;
343
              fq+=(fq.length > 0 ? " " + filter.filterOperator + " ":"" ) + filter.filterId +  " exact " + StringUtils.quote(StringUtils.URIEncode(value.id));
344
           }
345
        }
346
        fq="&fq="+fq;
347
        allFqs += fq;
348
      }
349
    }
350
    var doiQuery = "";
351
    var keywordQuery = "";
352
    if((this.searchUtils.keyword && this.searchUtils.keyword.length > 0)){
353
      if((this.type == 'publications' ||this.type == 'datasets')){
354
        var DOIs:string[] = DOI.getDOIsFromString(this.searchUtils.keyword);
355
        var doisParams = "";
356

    
357
        for(var i =0 ;i < DOIs.length; i++){
358
          doisParams+=(doisParams.length > 0?"&":"")+'doi="'+ DOIs[i]+'"';
359
        }
360
        if(doisParams.length > 0){
361
          doiQuery += "&"+doisParams;
362
        }else{
363
          keywordQuery += "&q="+StringUtils.URIEncode(this.searchUtils.keyword);
364
        }
365
      }else{
366
           keywordQuery += "&q="+StringUtils.URIEncode(this.searchUtils.keyword);
367
      }
368
    }
369

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

    
372
  }
373
  private createIndexQueryParameters(filters:Filter[]){
374
    var allFqs = "";
375
    for (let filter of filters){
376
      if(filter.countSelectedValues > 0){
377
        var count_selected=0;
378
        var fq = "";
379
        for (let value of filter.values){
380
          if(value.selected == true){
381
              count_selected++;
382
               fq+=(fq.length > 0 ? " " + filter.filterOperator + " ":"" ) + filter.filterId + " exact " + StringUtils.quote(StringUtils.URIEncode(value.id));
383
           }
384
        }
385
        if(count_selected > 0){
386
          fq="&fq="+fq;
387
          allFqs += fq;
388
        }
389
      }
390
    }
391
    var doiQuery = "";
392
    var keywordQuery = "";
393
    if((this.searchUtils.keyword && this.searchUtils.keyword.length > 0)){
394
      if((this.type == 'publications' ||this.type == 'datasets')){
395
        var DOIs:string[] = DOI.getDOIsFromString(this.searchUtils.keyword);
396
        var doisParams = "";
397
        for(var i =0 ;i < DOIs.length; i++){
398
          doisParams+=(doisParams.length > 0?"&":"")+'doi="'+ DOIs[i]+'"';
399
        }
400
        if(doisParams.length > 0){
401
          doiQuery += "&"+doisParams;
402
        }
403
      }else{
404
         keywordQuery += " and ("+StringUtils.quote(StringUtils.URIEncode(this.searchUtils.keyword)) +")"
405

    
406
      }
407
    }
408
    return (doiQuery.length > 0 ? doiQuery:keywordQuery) + allFqs;
409

    
410
  }
411
  private isFiltered(){
412
    var filtered=false;
413
    for (let filter of this.filters){
414
       if(filter.countSelectedValues > 0){
415
           filtered = true;
416
           break;
417
       }
418
     }
419
    if(this.searchUtils.keyword.length > 0 ){
420
      filtered = true;
421
    }
422
    return filtered;
423
  }
424
  private clearKeywords(){
425
    if(this.searchUtils.keyword.length > 0 ){
426
      this.searchUtils.keyword ='';
427
    }
428
    this.goTo(1);
429
  }
430
  private clearFilters(){
431
    for (var i =0 ; i <  this.filters.length; i++){
432
         for (var j=0; j <  this.filters[i].countSelectedValues; j++){
433
          if(this.filters[i].values[j].selected){
434
            this.filters[i].values[j].selected = false;
435
           }
436
        this.filters[i].countSelectedValues = 0;
437
      }
438
    }
439
    this.clearKeywords();
440

    
441
  }
442
  private removeFilter(value:Value,filter:Filter){
443
    filter.countSelectedValues--;
444
    if(value.selected == true){
445
      value.selected = false;
446
     }
447
    this.goTo(1);
448

    
449
  }
450
  goTo(page:number = 1){
451
    this.searchUtils.page = page;
452
    console.info("searchUtils.page goto = "+this.searchUtils.page);
453
    this.queryParameters = new Map<string,string>();
454
    var urlParameters = this.createUrlParameters(this.filters,true);
455
    console.info("urlParams : "+urlParameters);
456
    this.updateBaseUrlWithParameters(this.filters);
457
    var queryParameters = this.createSearchQueryParameters(this.filters);
458
    console.info("queryParams : "+queryParameters);
459
    var indexQuery = this.createIndexQueryParameters(this.filters);
460

    
461
    this.location.go(location.pathname,urlParameters);
462

    
463
    this.queryChange.emit({
464
        value: queryParameters,
465
        index:indexQuery
466

    
467
    });
468

    
469
  }
470
  filterChanged($event){
471
    console.info("filter Changed");
472
       this.goTo(1);
473
  }
474
  keywordChanged($event) {
475
       this.searchUtils.keyword = $event.value;
476
       this.goTo(1);
477
  }
478

    
479
	downloadClicked($event) {
480
		if($event.value == true) {
481
		    var queryParameters = this.createSearchQueryParameters(this.filters);
482

    
483
		    this.downloadClick.emit({
484
		        value: queryParameters
485
		    });
486
		}
487
	}
488

    
489
  /*
490
  * Get A sub-array of this.refineFields array, which contains the ids of the selected filters
491
  */
492
  public getSelectedFilters():string[] {
493
    var selected:string[] = [];
494
    for(var i=0; i <  this.filters.length; i++){
495
      var filter:Filter = this.filters[i];
496
      if(filter.countSelectedValues > 0){
497
          selected.push(filter.filterId);
498
      }
499
    }
500
    return selected;
501
  }
502
  /*
503
  * Get A sub-array of this.refineFields array, which contains the ids of the selected parameters
504
  */
505
  private getSelectedParameters():string[] {
506
    var selected:string[] = [];
507
    var params:string[] = Object.keys(this.queryParameters);
508
    for(var i=0; i <  params.length; i++){
509
       if(this.refineFields.indexOf(params[i]) > -1){
510
          selected.push(params[i]);
511
      }
512
    }
513
    return selected;
514
  }
515
  /*
516
  * 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 )
517
  */
518
  public getFields():string[] {
519
    var selected_filters:string[] = this.getSelectedFilters();
520
    if(selected_filters.length == 0){
521
      selected_filters = this.getSelectedParameters();
522
    }
523
    var fields:string[] = [];
524
    for(var i =0 ; i < this.refineFields.length;i++){
525
      var dependentTo = this.searchFieldsHelper.DEPENDENT_FIELDS[this.refineFields[i]];
526

    
527
      //if filter is not marked as hidden OR it is hidden but it is dependent to a field that it IS selected
528
      if(this.searchFieldsHelper.HIDDEN_FIELDS.indexOf(this.refineFields[i]) == -1 || (selected_filters.indexOf(dependentTo) != -1) ){
529
          fields.push(this.refineFields[i]);
530
       }
531
    }
532
    return fields;
533
  }
534
  /*
535
  * Get a query  string of all fields, that want to get from search (e.g. &fields=funderid&fields=projectstartyear&...))
536
  */
537
  public getRefineFieldsQuery():string{
538

    
539
    var fields:string[] = this.getFields();
540
    var fieldsStr = ""
541
    for(var i =0 ; i < fields.length  ;i++){
542
        fieldsStr+="&fields="+fields[i];
543
    }
544
    return "&refine=true"+fieldsStr;
545
  }
546

    
547
  // for loading
548
  public openLoading(){
549
    if(this.loading){
550
      this.loading.open();
551
    }
552
  }
553
  public closeLoading(){
554
    if(this.loading){
555
      this.loading.close();
556
    }
557
  }
558
  getSelectedValues(filter):any{
559
    var selected = [];
560
    if(filter.countSelectedValues >0){
561
      for (var i=0; i < filter.values.length; i++){
562
        if(filter.values[i].selected){
563
          selected.push(filter.values[i]);
564
        }
565
      }
566
    }
567
    return selected;
568

    
569
  }
570
}
(17-17/25)