Project

General

Profile

1
import {Component, Input, ViewChild, Output, EventEmitter,ElementRef} from '@angular/core';
2
import {Observable}       from 'rxjs/Observable';
3
import {Location} from '@angular/common';
4
import {Router,  ActivatedRoute} from '@angular/router';
5

    
6
import { Filter, Value} from './searchHelperClasses.class';
7
import {SearchResult}     from '../../utils/entities/searchResult';
8
import {SearchFields, FieldDetails} from '../../utils/properties/searchFields';
9
import {SearchUtilsClass} from './searchUtils.class';
10
import {DOI, StringUtils} from '../../utils/string-utils.class';
11
import {ModalLoading} from '../../utils/modal/loading.component';
12
import { Meta} from '../../sharedComponents/metaService';
13
import{SearchFilterComponent} from './searchFilter.component';
14
import {SearchFilterModalComponent} from './searchFilterModal.component';
15
import { ErrorCodes} from '../../utils/properties/errorCodes';
16
import {PiwikService} from '../../utils/piwik/piwik.service';
17
import{EnvProperties} from '../../utils/properties/env-properties';
18

    
19

    
20
@Component({
21
    selector: 'search-page',
22
    templateUrl: 'searchPage.component.html'
23

    
24
})
25
export class SearchPageComponent {
26
  @Input() pageTitle = "";
27
  @Input() formPlaceholderText = "Type Keywords...";
28
  @Input() results = [];
29
  @Input() filters = [];
30
  @Input() type:string = "";
31
  @Input() entityType: string = "";
32
  @Input() searchUtils:SearchUtilsClass = new SearchUtilsClass();
33
  @Output() queryChange  = new EventEmitter();
34
  @Input() baseUrl:string = '';
35
  @Input() showResultCount:boolean = true;
36
  @Input() showRefine:boolean = true;
37
  @Input() refineFields = [];
38
  @Input() csvParams: string;
39
  @Input() csvPath: string;
40
  @Input() advancedSearchLink: string = "";
41
  @Input() advancedSearchParameters;
42
  @Input() tableViewLink: string;
43
  @Input() disableForms: boolean = false;
44
  @Input() loadPaging: boolean = true;
45
  @Input() oldTotalResults: number = 0;
46
  @Input() tableView: boolean = false;
47
  @Input() searchFormClass: string = "searchForm";
48
  @Input() openaireLink: string;
49
  @Input() connectCommunityId: string;
50
  @ViewChild (ModalLoading) loading : ModalLoading ;
51
  public fieldIdsMap;//:  { [key:string]:{ name:string, operator:string, type:string, indexField:string, equalityOperator:string  }};
52
  private searchFieldsHelper:SearchFields = new SearchFields();
53
  private queryParameters: Map<string, string>  = new Map<string,string>();
54
  private baseURLWithParameters:string = '';
55
  private sub: any; piwiksub: any;
56
  public countFilters= 0;
57
  public parameterNames:string[] =[];
58
  public parameterValues:string[] =[];
59
  public showUnknownFilters:boolean = false; // when a filter exists in query but has no results, so no filters returned from the query
60
  //@ViewChild (SearchFilterModalComponent) searchFilterModal : SearchFilterModalComponent ;
61
  public currentFilter: Filter;
62
  public csvLimit: number = 0;
63
  public pagingLimit: number = 0;
64
  public resultsPerPage: number = 0;
65
  public isPiwikEnabled;
66
  properties:EnvProperties;
67

    
68
  constructor (private route: ActivatedRoute,private location: Location , private _meta: Meta,private element: ElementRef,private _piwikService:PiwikService, private router: Router) {
69
   }
70

    
71
  ngOnInit() {
72

    
73
    this.route.data
74
      .subscribe((data: { envSpecific: EnvProperties }) => {
75
        this.properties = data.envSpecific;
76
        this.pagingLimit = data.envSpecific.pagingLimit;
77
        this.resultsPerPage =data.envSpecific.resultsPerPage;
78
        this.csvLimit = data.envSpecific.csvLimit;
79
        this.isPiwikEnabled = data.envSpecific.enablePiwikTrack;
80
        if(typeof window !== 'undefined') {
81
          this.updateUrl(data.envSpecific.baseLink+location.pathname);
82
        }
83
        if(typeof document !== 'undefined' && this.isPiwikEnabled){
84
          this.piwiksub = this._piwikService.trackView(this.properties, this.pageTitle).subscribe();
85
        }
86
      });
87
    if (typeof document !== 'undefined') {
88
       this.element.nativeElement.scrollIntoView();
89
    }
90
        // this.updateBaseUrlWithParameters(this.filters);
91
        this.updateTitle(this.pageTitle);
92
        this.updateDescription("Openaire, search, repositories, open access, type, content provider, funder, project, " + this.type + "," +this.pageTitle);
93

    
94
  }
95
  ngAfterViewChecked(){
96

    
97
  }
98
  ngOnDestroy() {
99
    if(this.piwiksub){
100
      this.piwiksub.unsubscribe();
101
    }
102
  }
103
  toggleModal($event) {
104
    this.currentFilter = $event.value;
105
    //this.searchFilterModal.open();
106
  }
107

    
108
  updateDescription(description:string){
109
    this._meta.updateMeta("description", description);
110
    this._meta.updateProperty("og:description", description);
111
  }
112
  updateTitle(title:string){
113
    var _prefix ="OpenAIRE | ";
114
    var _title = _prefix + ((title.length> 50 ) ?title.substring(0,50):title);
115
    this._meta.setTitle(_title );
116
    this._meta.updateProperty("og:title",_title);
117
  }
118
  updateUrl(url:string){
119
    this._meta.updateProperty("og:url", url);
120
  }
121

    
122
  public getQueryParametersFromUrl(params){
123
    // var parameters = "";
124
    var allFqs = "";
125

    
126
    this.queryParameters = new Map<string,string>();
127
    for(var i=0; i< this.refineFields.length ; i++){
128
         var filterId =  this.refineFields[i];
129

    
130
          if(params[filterId] != undefined) {
131
             this.queryParameters.set(filterId, StringUtils.URIDecode(params[filterId]));
132
             let values = (StringUtils.URIDecode(this.queryParameters.get(filterId))).split(/,(?=(?:[^\"]*\"[^\"]*\")*[^\"]*$)/,-1);
133
             var countvalues = 0;
134
             var fq = "";
135
             for(let value of values) {
136
               countvalues++;
137
               var paramId = this.fieldIdsMap[filterId].param;
138
              // parameters+='&' + paramId+ '='+ value;//+"&" + this.fieldIdsMap[paramId].operator + "="+((countvalues == 1)?"and":"or");
139
              fq+=(fq.length > 0 ? " " + "or" + " ":"" ) + filterId +" exact " +StringUtils.URIEncode(value);
140
             }
141
             if(countvalues > 0){
142
               fq="&fq="+fq;
143
             }
144
             allFqs += fq;
145
          }
146
   }
147
   var keyword = params['keyword'];
148
   var doiQuery = "";
149
   var keywordQuery = "";
150
   if((keyword && keyword.length > 0)){
151
      if((this.type == 'publications' ||this.type == 'research data')){
152
        var DOIs:string[] = DOI.getDOIsFromString(keyword);
153
       var doisParams = "";
154

    
155
       for(var i =0 ;i < DOIs.length; i++){
156
         doisParams+=(doisParams.length > 0?"&":"")+'doi="'+ DOIs[i]+'"';
157
       }
158
       if(doisParams.length > 0){
159
         doiQuery += "&"+doisParams;
160
       }else {
161
        keywordQuery += "&q="+StringUtils.URIEncode(keyword);
162
       }
163
     }else{
164
        keywordQuery += "&q="+StringUtils.URIEncode(keyword);
165

    
166
     }
167
   }
168
   return (doiQuery.length > 0 ? doiQuery:keywordQuery) + allFqs;
169
 }
170
 public getIndexQueryParametersFromUrl(params){
171
  //  var parameters = "";
172
   var allFqs = "";
173

    
174
   for(var i=0; i< this.refineFields.length ; i++){
175
        var filterId =  this.refineFields[i];
176
        var fq = "";
177
         if(params[filterId] != undefined) {
178
            this.queryParameters.set(filterId,decodeURIComponent(params[filterId]));
179
            let values = (decodeURIComponent(this.queryParameters.get(filterId))).split(/,(?=(?:[^\"]*\"[^\"]*\")*[^\"]*$)/,-1);
180
            var countvalues = 0
181
            for(let value of values) {
182
              countvalues++;
183
              // parameters+= ((countvalues == 1)?" and (":" or ")+ filterId+ '='+ value;
184
              fq+=(fq.length > 0 ? " " + "or" + " ":"" ) + filterId + " exact " + value;//StringUtils.quote(value);
185
            }
186
            // parameters+= " ) ";
187
            if(countvalues > 0){
188
              fq="&fq="+fq;
189
            }
190
            allFqs += fq;
191
        }
192

    
193
  }
194
  var keyword = params['keyword'];
195
  var doiQuery = "";
196
  var keywordQuery = "";
197
  if((keyword && keyword.length > 0)){
198
    if((this.type == 'publications' ||this.type == 'research data')){
199
      var DOIs:string[] = DOI.getDOIsFromString(keyword);
200
      var doisParams = "";
201

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

    
211
    }
212
  }
213
  return (doiQuery.length > 0 ? doiQuery:keywordQuery) + allFqs;
214

    
215
}
216
 /*
217
 * Mark as check the new filters that are selected, when you get them from search
218
 */
219
  public checkSelectedFilters(filters:Filter[]){
220
    this.filters = filters;
221
       for(var i=0; i< filters.length ; i++){
222
            var filter:Filter = filters[i];
223
            filter.countSelectedValues = 0;
224
              if(this.queryParameters.get(filter.filterId) != undefined) {
225
                let values = (decodeURIComponent(this.queryParameters.get(filter.filterId))).split(/,(?=(?:[^\"]*\"[^\"]*\")*[^\"]*$)/,-1);
226
                     for(let filterValue of filter.values) {
227
                       if(values.indexOf(StringUtils.quote(filterValue.id)) > -1) {
228
                            filterValue.selected = true;
229
                            filter.countSelectedValues++;
230
                         }else{
231
                           filterValue.selected = false;
232

    
233
                         }
234
                    }
235
            }else{
236
              for(let filterValue of filter.values) {
237
                 filterValue.selected = false;
238
              }
239
            }
240
        }
241
        this.filterFilterValues(this.filters);
242
        return filters;
243
  }
244
  /*
245
  * For Funder filters - if funder selected
246
  */
247
   public filterFilterValues(filters:Filter[]){
248
     var funders = [];
249
     var funder_prefix = [];
250
        for(var i=0; i< filters.length ; i++){
251

    
252
             var filter:Filter = filters[i];
253
            //  console.log(filter.filterId);
254
             if(filter.filterId.indexOf("funder")!=-1 && this.queryParameters.get(filter.filterId) != undefined) {
255
                 let funders = (decodeURIComponent(this.queryParameters.get(filter.filterId))).split(/,(?=(?:[^\"]*\"[^\"]*\")*[^\"]*$)/,-1);
256
                      for(let funder of funders) {
257
                        console.log(funder);
258
                        funder_prefix.push(StringUtils.unquote(funder).split("____")[0]);
259
                     }
260
                    //  console.log(funder_prefix );
261
             }else if(filter.filterId.indexOf("funding")!=-1){
262
              //  console.log(" funding: "+filter.filterId );
263
               var filteredValues = []
264
               for(let filterValue of filter.values) {
265
                 var value_prefix = filterValue.id.split("____")[0];
266
                //  console.log("Value prefix: "+value_prefix );
267
                 if(funder_prefix.indexOf(value_prefix)!=-1){
268
                  //  console.log("here" + value_prefix);
269
                   filteredValues.push(filterValue);
270
                 }
271

    
272
               }
273
               console.log("From " +filter.values.length+ "to "+filteredValues.length);
274
               if(filteredValues.length > 0){
275
                 filter.values = filteredValues;
276
               }
277
             }else if(this.connectCommunityId && filter.filterId.indexOf("community")!=-1 ){
278
               var filteredValues = [];
279
               for(let filterValue of filter.values) {
280
                 if(this.connectCommunityId != filterValue.id){
281
                     filteredValues.push(filterValue);
282
                 }else{
283
                   filter.countSelectedValues-- ;
284
                 }
285
               }
286
               if(filteredValues.length > 0){
287
                 filter.values = filteredValues;
288
               }
289
         }
290
       }
291

    
292
         return filters;
293
   }
294
  /*
295
  * Update the url with proper parameters. This is used as base url in Paging Component
296
  */
297
  public updateBaseUrlWithParameters(filters:Filter[]){
298
    this.baseURLWithParameters = this.baseUrl + this.createUrlParameters(filters,false);
299

    
300
  }
301

    
302
  /*
303
  *Get The filters and create url parameters
304
  */
305
  private createUrlParameters(filters:Filter[], includePage:boolean){
306
    var allLimits="";//location.search.slice(1);
307
    this.queryParameters = new Map<string,string>();
308
    this.parameterNames.splice(0,this.parameterNames.length);
309
    this.parameterValues.splice(0,this.parameterValues.length);
310

    
311
    for (let filter of filters){
312
      var filterLimits="";
313
      if(filter.countSelectedValues > 0 || (this.connectCommunityId && filter.filterId.indexOf("community")!=-1)){
314
        for (let value of filter.values){
315
          if(value.selected == true){
316
            filterLimits+=((filterLimits.length == 0)?'':',') +'"'+ StringUtils.URIEncode(value.id)+'"';
317
          }
318
        }
319
        if(this.connectCommunityId && filter.filterId.indexOf("community")!=-1 ){
320
          filterLimits+=((filterLimits.length == 0)?'':',') +'"'+ StringUtils.URIEncode(this.connectCommunityId)+'"';
321
        }
322
        this.queryParameters.set(filter.filterId,filterLimits);
323
        if(filterLimits.length > 0){
324
          this.parameterNames.push(filter.filterId);
325
          this.parameterValues.push(filterLimits);
326
        }
327
        allLimits+=(allLimits.length==0?"?":"&")+((filterLimits.length == 0 )?'':filter.filterId + '='+ filterLimits) ;
328
      }
329
    }
330
    if(this.searchUtils.keyword.length > 0 ){
331
       allLimits+=(allLimits.length==0?"?":"&")+'keyword=' + this.searchUtils.keyword;
332
      this.parameterNames.push("keyword");
333
      this.parameterValues.push(this.searchUtils.keyword);
334
     }
335
    if(this.searchUtils.page != 1 && includePage){
336
       allLimits+=((allLimits.length == 0)?'?':'&') + 'page=' + this.searchUtils.page;
337
    }
338

    
339
    return allLimits;
340
  }
341
  /*
342
  *
343
  */
344
  private createSearchQueryParameters(filters:Filter[]){
345
    var allFqs = "";
346
    for (let filter of filters){
347
      if(filter.countSelectedValues > 0 || (this.connectCommunityId && filter.filterId.indexOf("community")!=-1)){
348
        var fq = "";
349
        var count_selected=0;
350
        for (let value of filter.values){
351
          if(value.selected == true){
352
              count_selected++;
353
              fq+=(fq.length > 0 ? " " + filter.filterOperator + " ":"" ) + filter.filterId +  " exact " + StringUtils.quote(StringUtils.URIEncode(value.id));
354
           }
355
        }
356
        if(this.connectCommunityId && filter.filterId.indexOf("community")!=-1){
357
          count_selected++;
358
          fq+=(fq.length > 0 ? " " + filter.filterOperator + " ":"" ) + filter.filterId +  " exact " + StringUtils.quote(StringUtils.URIEncode(this.connectCommunityId));
359
        }
360
        fq="&fq="+fq;
361
        allFqs += fq;
362
      }
363
    }
364
      //TODO --
365
    var doiQuery = "";
366
    var keywordQuery = "";
367
    if((this.searchUtils.keyword && this.searchUtils.keyword.length > 0)){
368
      if((this.type == 'publications' ||this.type == 'research data')){
369
        var DOIs:string[] = DOI.getDOIsFromString(this.searchUtils.keyword);
370
        var doisParams = "";
371

    
372
        for(var i =0 ;i < DOIs.length; i++){
373
          doisParams+=(doisParams.length > 0?"&":"")+'doi="'+ DOIs[i]+'"';
374
        }
375
        if(doisParams.length > 0){
376
          doiQuery += "&"+doisParams;
377
        }else{
378
          keywordQuery += "&q="+StringUtils.URIEncode(this.searchUtils.keyword);
379
        }
380
      }else{
381
           keywordQuery += "&q="+StringUtils.URIEncode(this.searchUtils.keyword);
382
      }
383
    }
384

    
385
    return (doiQuery.length > 0 ? doiQuery:keywordQuery) + allFqs;
386

    
387
  }
388
  /*private createIndexQueryParameters(filters:Filter[]){
389
    var allFqs = "";
390
    for (let filter of filters){
391
      if(filter.countSelectedValues > 0){
392
        var count_selected=0;
393
        var fq = "";
394
        for (let value of filter.values){
395
          if(value.selected == true){
396
              count_selected++;
397
               fq+=(fq.length > 0 ? " " + filter.filterOperator + " ":"" ) + filter.filterId + " exact " + StringUtils.quote(StringUtils.URIEncode(value.id));
398
           }
399
        }
400
        if(count_selected > 0){
401
          fq="&fq="+fq;
402
          allFqs += fq;
403
        }
404
      }
405
    }
406
    var doiQuery = "";
407
    var keywordQuery = "";
408
    if((this.searchUtils.keyword && this.searchUtils.keyword.length > 0)){
409
      if((this.type == 'publications' ||this.type == 'research data')){
410
        var DOIs:string[] = DOI.getDOIsFromString(this.searchUtils.keyword);
411
        var doisParams = "";
412
        for(var i =0 ;i < DOIs.length; i++){
413
          doisParams+=(doisParams.length > 0?"&":"")+'doi="'+ DOIs[i]+'"';
414
        }
415
        if(doisParams.length > 0){
416
          doiQuery += "&"+doisParams;
417
        }
418
      }else{
419
         keywordQuery += " and ("+StringUtils.quote(StringUtils.URIEncode(this.searchUtils.keyword)) +")"
420

    
421
      }
422
    }
423
    return (doiQuery.length > 0 ? doiQuery:keywordQuery) + allFqs;
424

    
425
  }*/
426
  public isFiltered(){
427
    var filtered=false;
428
    this.showUnknownFilters = false;
429
    for (let filter of this.filters){
430
       if(filter.countSelectedValues > 0){
431
           filtered = true;
432
           break;
433
       }
434
     }
435
    if(this.searchUtils.keyword.length > 0 ){
436
      filtered = true;
437
    }
438
    var errorCodes:ErrorCodes = new ErrorCodes();
439
    if(this.queryParameters.keys() && this.searchUtils.totalResults == 0 && this.searchUtils.status !=errorCodes.LOADING ){
440
      this.showUnknownFilters = true;
441
    }
442
    return filtered;
443
  }
444
  private clearKeywords(){
445
    if(this.searchUtils.keyword.length > 0 ){
446
      this.searchUtils.keyword ='';
447
    }
448
    this.goTo(1);
449
  }
450
  private clearFilters(){
451
    for (var i =0 ; i <  this.filters.length; i++){
452
         for (var j=0; j <  this.filters[i].countSelectedValues; j++){
453
          if(this.filters[i].values[j].selected){
454
            this.filters[i].values[j].selected = false;
455
           }
456
        this.filters[i].countSelectedValues = 0;
457
      }
458
    }
459
    this.clearKeywords();
460

    
461
  }
462
  private removeFilter(value:Value,filter:Filter){
463
    filter.countSelectedValues--;
464
    if(value.selected == true){
465
      value.selected = false;
466
     }
467
    this.goTo(1);
468

    
469
  }
470
  goTo(page:number = 1){
471
    this.searchUtils.page = page;
472
    console.info("searchUtils.page goto = "+this.searchUtils.page);
473
    var urlParameters = this.createUrlParameters(this.filters,true);
474
    console.info("urlParams : "+urlParameters);
475
    this.updateBaseUrlWithParameters(this.filters);
476
    var queryParameters = this.createSearchQueryParameters(this.filters);
477
    console.info("queryParams : "+queryParameters);
478
    // var indexQuery = this.createIndexQueryParameters(this.filters);
479

    
480
    this.location.go(location.pathname,urlParameters);
481
/* Code For Piwik*/
482
    if (typeof localStorage !== 'undefined') {
483
      localStorage.setItem('previousRoute', this.router.url);
484
    }
485
    if(this.isPiwikEnabled && (typeof document !== 'undefined')){
486
      this.piwiksub = this._piwikService.trackView(this.properties, this.pageTitle).subscribe();
487
    }
488
    /* End Piwik Code */
489
    this.queryChange.emit({
490
        value: queryParameters,
491
        // index:indexQuery
492

    
493
    });
494
    if (typeof document !== 'undefined') {
495
       this.element.nativeElement.scrollIntoView();
496
    }
497
  }
498
  filterChanged($event){
499
    console.info("filter Changed");
500
       this.goTo(1);
501
  }
502
  keywordChanged($event) {
503
       this.searchUtils.keyword = $event.value;
504
       this.goTo(1);
505
  }
506

    
507
  /*
508
  * Get A sub-array of this.refineFields array, which contains the ids of the selected filters
509
  */
510
  public getSelectedFilters():string[] {
511
    var selected:string[] = [];
512
    for(var i=0; i <  this.filters.length; i++){
513
      var filter:Filter = this.filters[i];
514
      if(filter.countSelectedValues > 0){
515
          selected.push(filter.filterId);
516
      }
517
    }
518
    return selected;
519
  }
520
  /*
521
  * Get A sub-array of this.refineFields array, which contains the ids of the selected parameters
522
  */
523
  private getSelectedParameters():string[] {
524
    var selected:string[] = [];
525
    var params:string[] = Object.keys(this.queryParameters);
526
    for(var i=0; i <  params.length; i++){
527
       if(this.refineFields.indexOf(params[i]) > -1){
528
          selected.push(params[i]);
529
      }
530
    }
531
    return selected;
532
  }
533
  /*
534
  * 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 )
535
  */
536
  public getFields():string[] {
537
    var selected_filters:string[] = this.getSelectedFilters();
538
    if(selected_filters.length == 0){
539
      selected_filters = this.getSelectedParameters();
540
    }
541
    var fields:string[] = [];
542
    for(var i =0 ; i < this.refineFields.length;i++){
543
      var dependentTo = this.searchFieldsHelper.DEPENDENT_FIELDS[this.refineFields[i]];
544

    
545
      //if filter is not marked as hidden OR it is hidden but it is dependent to a field that it IS selected
546
      if(this.searchFieldsHelper.HIDDEN_FIELDS.indexOf(this.refineFields[i]) == -1 || (selected_filters.indexOf(dependentTo) != -1) || (selected_filters.indexOf(this.refineFields[i]) != -1) ){
547
          fields.push(this.refineFields[i]);
548
       }
549
    }
550
    return fields;
551
  }
552
  /*
553
  * Get a query  string of all fields, that want to get from search (e.g. &fields=funderid&fields=projectstartyear&...))
554
  */
555
  public getRefineFieldsQuery():string{
556

    
557
    var fields:string[] = this.getFields();
558
    var fieldsStr = ""
559
    for(var i =0 ; i < fields.length  ;i++){
560
        fieldsStr+="&fields="+fields[i];
561
    }
562
    return "&refine=true"+fieldsStr;
563
  }
564

    
565
  // for loading
566
  public openLoading(){
567
    if(this.loading){
568
      this.loading.open();
569
    }
570
  }
571
  public closeLoading(){
572
    if(this.loading){
573
      this.loading.close();
574
    }
575
  }
576
  getSelectedValues(filter):any{
577
    var selected = [];
578
    if(filter.countSelectedValues >0){
579
      for (var i=0; i < filter.values.length; i++){
580
        if(filter.values[i].selected){
581
          selected.push(filter.values[i]);
582
        }
583
      }
584
    }
585
    return selected;
586

    
587
  }
588
}
(23-23/36)