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} 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 '../../../angular2-meta';
13
import{SearchFilterComponent} from './searchFilter.component';
14
import {SearchFilterModalComponent} from './searchFilterModal.component';
15
import {OpenaireProperties} from '../../utils/properties/openaireProperties';
16
import { ErrorCodes} from '../../utils/properties/openaireProperties';
17
import {PiwikService} from '../../utils/piwik/piwik.service';
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() tableViewLink: string;
42
  @Input() disableForms: boolean = false;
43
  @Input() loadPaging: boolean = true;
44
  @Input() oldTotalResults: number = 0;
45
  @Input() tableView: boolean = false;
46
  @Input() searchFormClass: string = "searchForm";
47
  @ViewChild (ModalLoading) loading : ModalLoading ;
48
  public fieldIdsMap;//:  { [key:string]:{ name:string, operator:string, type:string, indexField:string, equalityOperator:string  }};
49
  private searchFieldsHelper:SearchFields = new SearchFields();
50
  private queryParameters: Map<string, string>  = new Map<string,string>();
51
  private baseURLWithParameters:string = '';
52
  private sub: any; piwiksub: any;
53
  public countFilters= 0;
54
  public parameterNames:string[] =[];
55
  public parameterValues:string[] =[];
56
  public showUnknownFilters:boolean = false; // when a filter exists in query but has no results, so no filters returned from the query
57
  //@ViewChild (SearchFilterModalComponent) searchFilterModal : SearchFilterModalComponent ;
58
  public currentFilter: Filter;
59

    
60
  constructor (private location: Location , private _meta: Meta,private element: ElementRef,private _piwikService:PiwikService, private router: Router) {
61
   }
62

    
63
  ngOnInit() {
64
    if (typeof document !== 'undefined') {
65
       this.element.nativeElement.scrollIntoView();
66
    }
67
        // this.updateBaseUrlWithParameters(this.filters);
68
        this.updateTitle(this.pageTitle);
69
        this.updateDescription("Openaire, search, repositories, open access, type, content provider, funder, project, " + this.type + "," +this.pageTitle);
70
        if(typeof window !== 'undefined') {
71
          this.updateUrl(OpenaireProperties.getBaseLink()+location.pathname);
72
        }
73
        if(typeof document !== 'undefined' && OpenaireProperties.isPiwikTrackEnabled()){
74
          this.piwiksub = this._piwikService.trackView(this.pageTitle).subscribe();
75
        }
76
  }
77
  ngAfterViewChecked(){
78

    
79
  }
80
  ngOnDestroy() {
81
    if(this.piwiksub){
82
      this.piwiksub.unsubscribe();
83
    }
84
  }
85
  toggleModal($event) {
86
    this.currentFilter = $event.value;
87
    //this.searchFilterModal.open();
88
  }
89

    
90
  updateDescription(description:string){
91
    this._meta.updateMeta("description", description);
92
    this._meta.updateProperty("og:description", description);
93
  }
94
  updateTitle(title:string){
95
    var _prefix ="OpenAIRE | ";
96
    var _title = _prefix + ((title.length> 50 ) ?title.substring(0,50):title);
97
    this._meta.setTitle(_title );
98
    this._meta.updateProperty("og:title",_title);
99
  }
100
  updateUrl(url:string){
101
    this._meta.updateProperty("og:url", url);
102
  }
103

    
104
  public getQueryParametersFromUrl(params){
105
    // var parameters = "";
106
    var allFqs = "";
107

    
108
    this.queryParameters = new Map<string,string>();
109
    for(var i=0; i< this.refineFields.length ; i++){
110
         var filterId =  this.refineFields[i];
111

    
112
          if(params[filterId] != undefined) {
113
             this.queryParameters.set(filterId, StringUtils.URIDecode(params[filterId]));
114
             let values = (StringUtils.URIDecode(this.queryParameters.get(filterId))).split(/,(?=(?:[^\"]*\"[^\"]*\")*[^\"]*$)/,-1);
115
             var countvalues = 0;
116
             var fq = "";
117
             for(let value of values) {
118
               countvalues++;
119
               var paramId = this.fieldIdsMap[filterId].param;
120
              // parameters+='&' + paramId+ '='+ value;//+"&" + this.fieldIdsMap[paramId].operator + "="+((countvalues == 1)?"and":"or");
121
              fq+=(fq.length > 0 ? " " + "or" + " ":"" ) + filterId +" exact " +StringUtils.URIEncode(value);
122
             }
123
             if(countvalues > 0){
124
               fq="&fq="+fq;
125
             }
126
             allFqs += fq;
127
          }
128
   }
129
   var keyword = params['keyword'];
130
   var doiQuery = "";
131
   var keywordQuery = "";
132
   if((keyword && keyword.length > 0)){
133
      if((this.type == 'publications' ||this.type == 'research data')){
134
        var DOIs:string[] = DOI.getDOIsFromString(keyword);
135
       var doisParams = "";
136

    
137
       for(var i =0 ;i < DOIs.length; i++){
138
         doisParams+=(doisParams.length > 0?"&":"")+'doi="'+ DOIs[i]+'"';
139
       }
140
       if(doisParams.length > 0){
141
         doiQuery += "&"+doisParams;
142
       }else {
143
        keywordQuery += "&q="+StringUtils.URIEncode(keyword);
144
       }
145
     }else{
146
        keywordQuery += "&q="+StringUtils.URIEncode(keyword);
147

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

    
156
   for(var i=0; i< this.refineFields.length ; i++){
157
        var filterId =  this.refineFields[i];
158
        var fq = "";
159
         if(params[filterId] != undefined) {
160
            this.queryParameters.set(filterId,decodeURIComponent(params[filterId]));
161
            let values = (decodeURIComponent(this.queryParameters.get(filterId))).split(/,(?=(?:[^\"]*\"[^\"]*\")*[^\"]*$)/,-1);
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 " + value;//StringUtils.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 == 'research data')){
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?"&":"")+'doi="'+ DOIs[i]+'"';
186
      }
187
      if(doisParams.length > 0){
188
        doiQuery += "&"+doisParams;
189
      }
190
    }else{
191
       keywordQuery += "and ("+StringUtils.quote(StringUtils.URIEncode(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.get(filter.filterId) != undefined) {
207
                let values = (decodeURIComponent(this.queryParameters.get(filter.filterId))).split(/,(?=(?:[^\"]*\"[^\"]*\")*[^\"]*$)/,-1);
208
                     for(let filterValue of filter.values) {
209
                       if(values.indexOf(StringUtils.quote(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
        this.filterFilterValues(this.filters);
224
        return filters;
225
  }
226
  /*
227
  * For Funder filters - if funder selected
228
  */
229
   public filterFilterValues(filters:Filter[]){
230
     var funders = [];
231
     var funder_prefix = [];
232
        for(var i=0; i< filters.length ; i++){
233

    
234
             var filter:Filter = filters[i];
235
            //  console.log(filter.filterId);
236
             if(filter.filterId.indexOf("funder")!=-1 && this.queryParameters.get(filter.filterId) != undefined) {
237
                 let funders = (decodeURIComponent(this.queryParameters.get(filter.filterId))).split(/,(?=(?:[^\"]*\"[^\"]*\")*[^\"]*$)/,-1);
238
                      for(let funder of funders) {
239
                        console.log(funder);
240
                        funder_prefix.push(StringUtils.unquote(funder).split("____")[0]);
241
                     }
242
                    //  console.log(funder_prefix );
243
             }else if(filter.filterId.indexOf("funding")!=-1){
244
              //  console.log(" funding: "+filter.filterId );
245
               var filteredValues = []
246
               for(let filterValue of filter.values) {
247
                 var value_prefix = filterValue.id.split("____")[0];
248
                //  console.log("Value prefix: "+value_prefix );
249
                 if(funder_prefix.indexOf(value_prefix)!=-1){
250
                  //  console.log("here" + value_prefix);
251
                   filteredValues.push(filterValue);
252
                 }
253

    
254
               }
255
               console.log("From " +filter.values.length+ "to "+filteredValues.length);
256
               if(filteredValues.length > 0){
257
                 filter.values = filteredValues;
258
               }
259
             }
260

    
261
         }
262

    
263
         return filters;
264
   }
265
  /*
266
  * Update the url with proper parameters. This is used as base url in Paging Component
267
  */
268
  public updateBaseUrlWithParameters(filters:Filter[]){
269
    this.baseURLWithParameters = this.baseUrl + this.createUrlParameters(filters,false);
270

    
271
  }
272

    
273
  /*
274
  *Get The filters and create url parameters
275
  */
276
  private createUrlParameters(filters:Filter[], includePage:boolean){
277
    var allLimits="";//location.search.slice(1);
278
    this.queryParameters = new Map<string,string>();
279
    this.parameterNames.splice(0,this.parameterNames.length);
280
    this.parameterValues.splice(0,this.parameterValues.length);
281

    
282
    for (let filter of filters){
283
      var filterLimits="";
284
      if(filter.countSelectedValues > 0){
285
        for (let value of filter.values){
286
          if(value.selected == true){
287
            filterLimits+=((filterLimits.length == 0)?'':',') +'"'+ StringUtils.URIEncode(value.id)+'"';
288
           }
289
        }
290
        this.queryParameters.set(filter.filterId,filterLimits);
291
        if(filterLimits.length > 0){
292
          this.parameterNames.push(filter.filterId);
293
          this.parameterValues.push(filterLimits);
294
        }
295
        allLimits+=(allLimits.length==0?"?":"&")+((filterLimits.length == 0 )?'':filter.filterId + '='+ filterLimits) ;
296
      }
297
    }
298
    if(this.searchUtils.keyword.length > 0 ){
299
       allLimits+=(allLimits.length==0?"?":"&")+'keyword=' + this.searchUtils.keyword;
300
      this.parameterNames.push("keyword");
301
      this.parameterValues.push(this.searchUtils.keyword);
302
     }
303
    if(this.searchUtils.page != 1 && includePage){
304
       allLimits+=((allLimits.length == 0)?'?':'&') + 'page=' + this.searchUtils.page;
305
    }
306

    
307
    return allLimits;
308
  }
309
  /*
310
  *
311
  */
312
  private createSearchQueryParameters(filters:Filter[]){
313
    var allFqs = "";
314
    for (let filter of filters){
315
      if(filter.countSelectedValues > 0){
316
        var fq = "";
317
        var count_selected=0;
318
        for (let value of filter.values){
319
          if(value.selected == true){
320
              count_selected++;
321
              fq+=(fq.length > 0 ? " " + filter.filterOperator + " ":"" ) + filter.filterId +  " exact " + StringUtils.quote(StringUtils.URIEncode(value.id));
322
           }
323
        }
324
        fq="&fq="+fq;
325
        allFqs += fq;
326
      }
327
    }
328
    var doiQuery = "";
329
    var keywordQuery = "";
330
    if((this.searchUtils.keyword && this.searchUtils.keyword.length > 0)){
331
      if((this.type == 'publications' ||this.type == 'research data')){
332
        var DOIs:string[] = DOI.getDOIsFromString(this.searchUtils.keyword);
333
        var doisParams = "";
334

    
335
        for(var i =0 ;i < DOIs.length; i++){
336
          doisParams+=(doisParams.length > 0?"&":"")+'doi="'+ DOIs[i]+'"';
337
        }
338
        if(doisParams.length > 0){
339
          doiQuery += "&"+doisParams;
340
        }else{
341
          keywordQuery += "&q="+StringUtils.URIEncode(this.searchUtils.keyword);
342
        }
343
      }else{
344
           keywordQuery += "&q="+StringUtils.URIEncode(this.searchUtils.keyword);
345
      }
346
    }
347

    
348
    return (doiQuery.length > 0 ? doiQuery:keywordQuery) + allFqs;
349

    
350
  }
351
  private createIndexQueryParameters(filters:Filter[]){
352
    var allFqs = "";
353
    for (let filter of filters){
354
      if(filter.countSelectedValues > 0){
355
        var count_selected=0;
356
        var fq = "";
357
        for (let value of filter.values){
358
          if(value.selected == true){
359
              count_selected++;
360
               fq+=(fq.length > 0 ? " " + filter.filterOperator + " ":"" ) + filter.filterId + " exact " + StringUtils.quote(StringUtils.URIEncode(value.id));
361
           }
362
        }
363
        if(count_selected > 0){
364
          fq="&fq="+fq;
365
          allFqs += fq;
366
        }
367
      }
368
    }
369
    var doiQuery = "";
370
    var keywordQuery = "";
371
    if((this.searchUtils.keyword && this.searchUtils.keyword.length > 0)){
372
      if((this.type == 'publications' ||this.type == 'research data')){
373
        var DOIs:string[] = DOI.getDOIsFromString(this.searchUtils.keyword);
374
        var doisParams = "";
375
        for(var i =0 ;i < DOIs.length; i++){
376
          doisParams+=(doisParams.length > 0?"&":"")+'doi="'+ DOIs[i]+'"';
377
        }
378
        if(doisParams.length > 0){
379
          doiQuery += "&"+doisParams;
380
        }
381
      }else{
382
         keywordQuery += " and ("+StringUtils.quote(StringUtils.URIEncode(this.searchUtils.keyword)) +")"
383

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

    
388
  }
389
  public isFiltered(){
390
    var filtered=false;
391
    this.showUnknownFilters = false;
392
    for (let filter of this.filters){
393
       if(filter.countSelectedValues > 0){
394
           filtered = true;
395
           break;
396
       }
397
     }
398
    if(this.searchUtils.keyword.length > 0 ){
399
      filtered = true;
400
    }
401
    var errorCodes:ErrorCodes = new ErrorCodes();
402
    if(this.queryParameters.keys() && this.searchUtils.totalResults == 0 && this.searchUtils.status !=errorCodes.LOADING ){
403
      this.showUnknownFilters = true;
404
    }
405
    return filtered;
406
  }
407
  private clearKeywords(){
408
    if(this.searchUtils.keyword.length > 0 ){
409
      this.searchUtils.keyword ='';
410
    }
411
    this.goTo(1);
412
  }
413
  private clearFilters(){
414
    for (var i =0 ; i <  this.filters.length; i++){
415
         for (var j=0; j <  this.filters[i].countSelectedValues; j++){
416
          if(this.filters[i].values[j].selected){
417
            this.filters[i].values[j].selected = false;
418
           }
419
        this.filters[i].countSelectedValues = 0;
420
      }
421
    }
422
    this.clearKeywords();
423

    
424
  }
425
  private removeFilter(value:Value,filter:Filter){
426
    filter.countSelectedValues--;
427
    if(value.selected == true){
428
      value.selected = false;
429
     }
430
    this.goTo(1);
431

    
432
  }
433
  goTo(page:number = 1){
434
    this.searchUtils.page = page;
435
    console.info("searchUtils.page goto = "+this.searchUtils.page);
436
    var urlParameters = this.createUrlParameters(this.filters,true);
437
    console.info("urlParams : "+urlParameters);
438
    this.updateBaseUrlWithParameters(this.filters);
439
    var queryParameters = this.createSearchQueryParameters(this.filters);
440
    console.info("queryParams : "+queryParameters);
441
    var indexQuery = this.createIndexQueryParameters(this.filters);
442

    
443
    this.location.go(location.pathname,urlParameters);
444
/* Code For Piwik*/
445
    if (typeof localStorage !== 'undefined') {
446
      localStorage.setItem('previousRoute', this.router.url);
447
    }
448
    if(OpenaireProperties.isPiwikTrackEnabled() && (typeof document !== 'undefined')){
449
      this.piwiksub = this._piwikService.trackView(this.pageTitle).subscribe();
450
    }
451
    /* End Piwik Code */
452
    this.queryChange.emit({
453
        value: queryParameters,
454
        index:indexQuery
455

    
456
    });
457
    if (typeof document !== 'undefined') {
458
       this.element.nativeElement.scrollIntoView();
459
    }
460
  }
461
  filterChanged($event){
462
    console.info("filter Changed");
463
       this.goTo(1);
464
  }
465
  keywordChanged($event) {
466
       this.searchUtils.keyword = $event.value;
467
       this.goTo(1);
468
  }
469

    
470
  /*
471
  * Get A sub-array of this.refineFields array, which contains the ids of the selected filters
472
  */
473
  public getSelectedFilters():string[] {
474
    var selected:string[] = [];
475
    for(var i=0; i <  this.filters.length; i++){
476
      var filter:Filter = this.filters[i];
477
      if(filter.countSelectedValues > 0){
478
          selected.push(filter.filterId);
479
      }
480
    }
481
    return selected;
482
  }
483
  /*
484
  * Get A sub-array of this.refineFields array, which contains the ids of the selected parameters
485
  */
486
  private getSelectedParameters():string[] {
487
    var selected:string[] = [];
488
    var params:string[] = Object.keys(this.queryParameters);
489
    for(var i=0; i <  params.length; i++){
490
       if(this.refineFields.indexOf(params[i]) > -1){
491
          selected.push(params[i]);
492
      }
493
    }
494
    return selected;
495
  }
496
  /*
497
  * 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 )
498
  */
499
  public getFields():string[] {
500
    var selected_filters:string[] = this.getSelectedFilters();
501
    if(selected_filters.length == 0){
502
      selected_filters = this.getSelectedParameters();
503
    }
504
    var fields:string[] = [];
505
    for(var i =0 ; i < this.refineFields.length;i++){
506
      var dependentTo = this.searchFieldsHelper.DEPENDENT_FIELDS[this.refineFields[i]];
507

    
508
      //if filter is not marked as hidden OR it is hidden but it is dependent to a field that it IS selected
509
      if(this.searchFieldsHelper.HIDDEN_FIELDS.indexOf(this.refineFields[i]) == -1 || (selected_filters.indexOf(dependentTo) != -1) || (selected_filters.indexOf(this.refineFields[i]) != -1) ){
510
          fields.push(this.refineFields[i]);
511
       }
512
    }
513
    return fields;
514
  }
515
  /*
516
  * Get a query  string of all fields, that want to get from search (e.g. &fields=funderid&fields=projectstartyear&...))
517
  */
518
  public getRefineFieldsQuery():string{
519

    
520
    var fields:string[] = this.getFields();
521
    var fieldsStr = ""
522
    for(var i =0 ; i < fields.length  ;i++){
523
        fieldsStr+="&fields="+fields[i];
524
    }
525
    return "&refine=true"+fieldsStr;
526
  }
527

    
528
  // for loading
529
  public openLoading(){
530
    if(this.loading){
531
      this.loading.open();
532
    }
533
  }
534
  public closeLoading(){
535
    if(this.loading){
536
      this.loading.close();
537
    }
538
  }
539
  getSelectedValues(filter):any{
540
    var selected = [];
541
    if(filter.countSelectedValues >0){
542
      for (var i=0; i < filter.values.length; i++){
543
        if(filter.values[i].selected){
544
          selected.push(filter.values[i]);
545
        }
546
      }
547
    }
548
    return selected;
549

    
550
  }
551
}
(23-23/36)