Project

General

Profile

1
import {Component, Input}                 from '@angular/core';
2
import {ViewChild, Output}                from '@angular/core';
3
import {EventEmitter, ViewEncapsulation}  from '@angular/core';
4
import {OnInit, AfterViewInit}            from '@angular/core';
5
import {Location}                         from '@angular/common';
6
import {ActivatedRoute, Router}                   from '@angular/router';
7
import {Title, Meta}                      from '@angular/platform-browser';
8

    
9
import {Observable, Subject}                       from 'rxjs';
10

    
11
import {DataTableDirective }              from 'angular-datatables';
12

    
13
import {EnvProperties}                    from '../../utils/properties/env-properties';
14

    
15
import {Filter, Value}                    from './searchHelperClasses.class';
16
import {SearchResult}                     from '../../utils/entities/searchResult';
17
import {SearchFields, FieldDetails}       from '../../utils/properties/searchFields';
18
import {SearchUtilsClass}                 from './searchUtils.class';
19
import {DOI, StringUtils}                 from '../../utils/string-utils.class';
20
import {ModalLoading}                     from '../../utils/modal/loading.component';
21
import {SearchFilterComponent}            from './searchFilter.component';
22
import {SearchFilterModalComponent}       from './searchFilterModal.component';
23
import {ErrorCodes}                       from '../../utils/properties/errorCodes';
24
import {PiwikService}                     from '../../utils/piwik/piwik.service';
25
//import {SearchDataprovidersService} from '../../services/searchDataproviders.service';
26
import { SEOService } from '../../sharedComponents/SEO/SEO.service';
27

    
28
@Component({
29
    selector: 'search-page-table',
30
    templateUrl:'searchPageTableView.component.html',
31
    styles: [`
32
      #dpTable_info, #dpTable_paginate,  #dpTable_length,  #dpTable_filter{
33
        display: none;
34
      }
35

    
36
      `],
37
      encapsulation: ViewEncapsulation.None // this used in order styles to work
38

    
39
  })
40
export class SearchPageTableViewComponent  implements OnInit, AfterViewInit {
41
  @Input() piwikSiteId = null;
42
  @Input() pageTitle = "";
43
  @Input() results;
44
  @Input() filters = [];
45
  @Input() columnNames = [];
46
  @Input() type:string = "";
47
  @Input() entityType: string = "";
48
  @Input() searchUtils:SearchUtilsClass;// = new SearchUtilsClass();
49
  //@Output() downloadClick = new EventEmitter();
50
  @Input() showResultCount:boolean = true;
51
  @Input() showRefine:boolean = true;
52
  @Input() refineFields = [];
53
  //@Input() csvParams: string;
54
  //@Input() csvPath: string;
55
  @Input() openaireLink: string;
56
  @Input() searchViewLink: string;
57
  @Input() disableForms: boolean = false;
58
  @Input() enableSearchView: boolean = true;
59
  @Input() searchFormClass: string = "searchForm";
60
  @Input() formPlaceholderText = "Type Keywords...";
61
  @Input() mapUrl: string = "";
62
  @Input() mapTooltipType: string ="content providers";
63
  @ViewChild (ModalLoading) loading : ModalLoading ;
64
  private searchFieldsHelper:SearchFields = new SearchFields();
65
  private queryParameters: Map<string, string>  = new Map<string,string>();
66
  public parameterNames:string[] =[];
67
  public parameterValues:string[] =[];
68

    
69
  public isPiwikEnabled;
70

    
71

    
72
  @ViewChild (SearchFilterModalComponent) searchFilterModal : SearchFilterModalComponent ;
73
  public currentFilter: Filter;
74
  public errorCodes:ErrorCodes = new ErrorCodes();
75
  piwiksub: any;
76
  dtOptions: DataTables.Settings = {};
77
  showTable = false; filteringAdded = false;
78
  @ViewChild(DataTableDirective) datatableElement: DataTableDirective;
79
  dtTrigger: Subject<any> = new Subject(); //necessary
80
  properties:EnvProperties;
81
  url = null;
82
  constructor (private route: ActivatedRoute,
83
               private router: Router,
84
               private location: Location,
85
               private _meta: Meta,
86
               private _title: Title,
87
               private _piwikService:PiwikService,
88
             private seoService: SEOService) { }
89

    
90
  ngOnInit() {
91
    this.route.data
92
      .subscribe((data: { envSpecific: EnvProperties }) => {
93
        this.properties = data.envSpecific;
94

    
95
        this.isPiwikEnabled = data.envSpecific.enablePiwikTrack;
96
        if(typeof window !== 'undefined') {
97
          this.updateUrl(data.envSpecific.baseLink+location.pathname);
98
          this.url =data.envSpecific.baseLink+location.pathname;
99
        }
100
        if(typeof document !== 'undefined' && this.isPiwikEnabled){
101
          this.piwiksub = this._piwikService.trackView(data.envSpecific, this.pageTitle, this.piwikSiteId).subscribe();
102
        }
103
      });
104
        this.dtOptions = {
105
          "paging": true,
106
          "searching": false,
107
          "lengthChange": false,
108
          "pageLength": this.searchUtils.size
109
        };
110
        this.updateTitle(this.pageTitle);
111
        var description = "Openaire, search, repositories, open access, type, content provider, funder, project, " + this.type + "," +this.pageTitle;
112
        this.updateDescription(description);
113
        this.seoService.createLinkForCanonicalURL(this.properties.baseLink+this.router.url,false);
114

    
115

    
116
   }
117
  ngOnDestroy() {
118
     if(this.piwiksub){
119
        this.piwiksub.unsubscribe();
120
      }
121
      try{
122
        $.fn['dataTable'].ext.search.pop();
123
      }catch(e){
124
        console.error("An error occured in ngOnDestroy of SearchPageTableViewComponent ", e)
125
    }
126
  }
127
    ngAfterViewInit(): void {
128
      try{
129
       $.fn['dataTable'].ext.search.push((settings, data, dataIndex) => {
130
//console.info(dataIndex+": "+data);
131
//console.info(this.results);
132
          //if (this.filterData(this.results[dataIndex], this.searchUtils.keyword, this.filters)) {
133
          if(this.filterAll(this.results[dataIndex], this.searchUtils.keyword.toLowerCase(),this.filters)) {
134
            // console.info("filter true (keyword:"+this.searchUtils.keyword+")");
135

    
136
            return true;
137
          }
138
          // console.info("filter false (keyword:"+this.searchUtils.keyword+")");
139

    
140
          return false;
141
        });
142
      }catch(e){
143
        console.error("An error occured in ngAfterViewInit of SearchPageTableViewComponent ", e)
144
    }
145

    
146
    }
147

    
148

    
149
  totalPages(): number {
150
      let totalPages:any = this.searchUtils.totalResults/(this.searchUtils.size);
151
      if(!(Number.isInteger(totalPages))) {
152
          totalPages = (parseInt(totalPages, 10) + 1);
153
      }
154
      return totalPages;
155
  }
156

    
157
  toggleModal($event) {
158
    this.currentFilter = $event.value;
159
    this.searchFilterModal.open();
160

    
161
  }
162

    
163
  updateDescription(description:string) {
164
    this._meta.updateTag({content:description},"name='description'");
165
    this._meta.updateTag({content:description},"property='og:description'");
166
  }
167
  updateTitle(title:string) {
168
    var _prefix ="OpenAIRE | ";
169
    var _title = _prefix + ((title.length> 50 ) ?title.substring(0,50):title);
170
    this._title.setTitle(_title);
171
    this._meta.updateTag({content:_title},"property='og:title'");
172
  }
173
  updateUrl(url:string) {
174
    this._meta.updateTag({content:url},"property='og:url'");
175
  }
176

    
177
public getParametersFromUrl(params) {
178
  for(var i=0; i< this.refineFields.length ; i++) {
179
    var filterId =  this.refineFields[i];
180
    if(params[filterId] != undefined) {
181
      if(this.queryParameters == undefined){
182
        this.queryParameters = new Map<string,string>();
183
      }
184
      this.queryParameters[filterId]=decodeURIComponent(params[filterId]);
185
    }
186
  }
187
}
188
 /*
189
 * Mark as check the new filters that are selected, when you get them from search
190
 */
191
  public checkSelectedFilters(filters:Filter[]){
192

    
193
    this.filters = filters;
194
       for(var i=0; i< filters.length ; i++){
195
            var filter:Filter = filters[i];
196
            filter.countSelectedValues = 0;
197

    
198
              if(this.queryParameters[filter.filterId] != undefined) {
199
                let values = (decodeURIComponent(this.queryParameters[filter.filterId])).split(/,(?=(?:[^\"]*\"[^\"]*\")*[^\"]*$)/,-1);
200
                     for(let filterValue of filter.values) {
201
                       if(values.indexOf(StringUtils.quote(filterValue.id)) > -1) {
202
                            filterValue.selected = true;
203
                            filter.countSelectedValues++;
204
                         }else{
205
                           filterValue.selected = false;
206
                         }
207
                    }
208
            }else{
209
              for(let filterValue of filter.values) {
210
                 filterValue.selected = false;
211
              }
212
            }
213
        }
214

    
215
        return filters;
216
  }
217

    
218
  /*
219
  *
220
  */
221
  private createUrlParameters(filters:Filter[], includePage:boolean){
222
    var allLimits="";//location.search.slice(1);
223
    this.parameterNames.splice(0,this.parameterNames.length);
224
    this.parameterValues.splice(0,this.parameterValues.length);
225

    
226
    for (let filter of filters){
227
      var filterLimits="";
228
      if(filter.countSelectedValues > 0){
229
        for (let value of filter.values){
230
          if(value.selected == true){
231
            filterLimits+=((filterLimits.length == 0)?'':',') +'"'+ StringUtils.URIEncode(value.id)+'"';
232
           }
233
        }
234
        this.queryParameters[filter.filterId]=filterLimits;
235
        if(filterLimits.length > 0){
236
          this.parameterNames.push(filter.filterId);
237
          this.parameterValues.push(filterLimits);
238
        }
239
        allLimits+=(allLimits.length==0?"?":"&")+((filterLimits.length == 0 )?'':filter.filterId + '='+ filterLimits) ;
240
      }
241
    }
242
    if(this.searchUtils.keyword.length > 0 ){
243
       allLimits+=(allLimits.length==0?"?":"&")+'keyword=' + this.searchUtils.keyword;
244
      this.parameterNames.push("keyword");
245
      this.parameterValues.push(this.searchUtils.keyword);
246
     }
247

    
248
    return allLimits;
249
  }
250

    
251
  public isFiltered(){
252
    var filtered=false;
253
    for (let filter of this.filters){
254
       if(filter.countSelectedValues > 0){
255
           filtered = true;
256
           break;
257
       }
258
     }
259
    if(this.searchUtils.keyword.length > 0 ){
260
      filtered = true;
261
    }
262
    return filtered;
263
  }
264
  private clearKeywords(){
265
    if(this.searchUtils.keyword.length > 0 ){
266
      this.searchUtils.keyword ='';
267
    }
268
    this.goTo(1);
269
  }
270
  private clearFilters(){
271
    for (var i =0 ; i <  this.filters.length; i++) {
272
         for (var j=0; j <  this.filters[i].values.length; j++) {
273
          if(this.filters[i].values[j].selected) {
274
            this.filters[i].values[j].selected = false;
275
          }
276
         }
277
        this.filters[i].countSelectedValues = 0;
278
    }
279
    this.clearKeywords();
280
  }
281

    
282
  private removeFilter(value:Value,filter:Filter){
283
    filter.countSelectedValues--;
284
    if(value.selected == true){
285
      value.selected = false;
286
     }
287
    this.goTo(1);
288
  }
289
  goTo(page:number = 1){
290

    
291
    this.searchUtils.page=page;
292
   var table = $('#dpTable').DataTable();
293

    
294
   table.page( page - 1  ).draw( false );
295

    
296
   // Object { page: 0, pages: 3, start: 0, end: 10, length: 10, recordsTotal: 28, recordsDisplay: 21, serverSide: false }
297
   var info = table.page.info();
298
   this.searchUtils.totalResults = info.recordsDisplay;
299

    
300
    var urlParameters = this.createUrlParameters(this.filters,true);
301
    this.location.go(location.pathname,urlParameters);
302
  }
303

    
304
  filterChanged($event){
305
       this.goTo(1);
306
  }
307
  keywordChanged($event) {
308
       this.searchUtils.keyword = $event.value;
309
       this.goTo(1);
310
  }
311

    
312
  sizeChanged($event) {
313
    this.searchUtils.size = $event.value;
314
    var table = $('#dpTable').DataTable();
315
    table.page.len( this.searchUtils.size ).draw();
316
    this.goTo(1);
317
  }
318
/*
319
	downloadClicked($event) {
320
		if($event.value == true) {
321
		    var queryParameters = this.createSearchQueryParameters(this.filters);
322

    
323
		    this.downloadClick.emit({
324
		        value: queryParameters
325
		    });
326
		}
327
	}
328
*/
329

    
330

    
331
  getSelectedValues(filter):any{
332
    var selected = [];
333
    if(filter.countSelectedValues >0){
334
      for (var i=0; i < filter.values.length; i++){
335
        if(filter.values[i].selected){
336
          selected.push(filter.values[i]);
337
        }
338
      }
339
    }
340
    return selected;
341

    
342
  }
343
  /*
344
  Trigger a table draw in order to get the initial filtering
345
  */
346
  triggerInitialLoad(){
347
      setTimeout(function(){
348
        var table = $('#dpTable').DataTable();
349
        table.page( 0  ).draw( false );
350

    
351
      }, 500);
352
  }
353

    
354
/*
355
Transform initial - not filtered results to get the filtered number
356
*/
357
    transform(results): any {
358
      if(results.length > 0) {
359
        var errorCodes:ErrorCodes = new ErrorCodes();
360
        this.searchUtils.status = errorCodes.LOADING;
361

    
362
        var result = results.filter(row=>this.filterAll(row, this.searchUtils.keyword.toLowerCase(),this.filters));
363

    
364
        let oldTotal = this.searchUtils.totalResults;
365
        //console.info(result);
366
        this.searchUtils.totalResults = result.length;
367

    
368
        var errorCodes:ErrorCodes = new ErrorCodes();
369
        this.searchUtils.status = errorCodes.DONE;
370
        if(this.searchUtils.totalResults == 0 ){
371
          //this.searchUtils.status = errorCodes.NONE;
372
        }
373

    
374
        // if(oldTotal != this.searchUtils.totalResults) {
375
        //   args[3].detectChanges();
376
        // }
377
         return result;
378
      }
379
       return [];
380
    }
381

    
382
    filterAll(row: any, query: string, filters:Filter[]) {
383
      let returnValue: boolean = false;
384

    
385
      if(query) {
386
        if(row.title && row.title.name.toLowerCase().indexOf(query) > -1) {
387
          returnValue = true;
388
        }
389

    
390
        if(row.type && row.type.toLowerCase().indexOf(query) > -1) {
391
          returnValue = true;
392
        }
393

    
394
        if(row.countries && row.countries.length > 0) {
395
          for(let country of row.countries) {
396
            if(country.toLowerCase().indexOf(query) > -1) {
397
              returnValue = true;
398
              break;
399
            }
400
          }
401
        }
402

    
403
        if(row.compatibility && row.compatibility.toLowerCase().indexOf(query) > -1) {
404
          returnValue = true;
405
        }
406

    
407
        if(row.organizations && row.organizations.length > 0) {
408
          for(let organization of row.organizations) {
409
            if(organization.name.toLowerCase().indexOf(query) > -1) {
410
              returnValue = true;
411
              break;
412
            }
413
          }
414
        }
415

    
416
        if(row.name && row.name.toLowerCase().indexOf(query) > -1) {
417
          returnValue = true;
418
        }
419

    
420
        if(row.acronym && row.acronym.toLowerCase().indexOf(query) > -1) {
421
          returnValue = true;
422
        }
423

    
424
        if(row.grantId && row.grantId.toLowerCase().indexOf(query) > -1) {
425
          returnValue = true;
426
        }
427

    
428
        if(row.funder && row.funder.toLowerCase().indexOf(query) > -1) {
429
          returnValue = true;
430
        }
431

    
432
        if(!returnValue) {
433
          return false;
434
        }
435
      }
436

    
437
      for (let filter of filters){
438
        if(filter.countSelectedValues > 0){
439
          for (let value of filter.values){
440
            if(value.selected == true){
441

    
442
              // make it generic in future commit
443
              let field:string = "";
444
              /*
445
              let index: number = -1;
446
              for(let i=0; i<this.columnNames.length; i++) {
447
                if(filter.title == this.columnNames[i]) {
448
                  index = i;
449
                }
450
              }
451
              */
452
              if(filter.title == "Type") {
453
                field = "type";
454
              } else if(filter.title == "Compatibility") {
455
                field = "compatibility";
456
              } else if(filter.title == "Funder") {
457
                field = "funder";
458
              } else if(filter.title == "Country") {
459
                field = "countries";
460
              }
461
              //console.info(row);
462
//console.info("|"+row[field]+"|"+"   "+"|"+value.name+"|");
463
              //if(row[field] == value.name) {
464
              if(row[field] &&
465
                ((filter.valueIsExact && (row[field].trim() == value.name.trim()))
466
                || (!filter.valueIsExact && (row[field].includes(value.name))))){
467

    
468
                returnValue = true;
469
                if(filter.filterOperator == "or") {
470
                  break;
471
                }
472
              } else {
473
                  if(filter.filterOperator == "and") {
474
                    return false;
475
                  }
476
                  returnValue = false;
477
              }
478
            }
479
          }
480
          if(!returnValue) {
481
            return false;
482
          }
483
        }
484
      }
485

    
486
      return true;
487
    }
488
    filterQuery(data, query){
489
      if(data.toLowerCase().indexOf(query.toLowerCase()) > -1){
490
        return true;
491
      }else{
492
        return false;
493
      }
494
    }
495
    filterData(row: any, query: string, filters:Filter[]) {
496

    
497

    
498
      let returnValue: boolean = false;
499

    
500
      if(query) {
501
        for(var i=0; i <this.columnNames.length; i++){
502
          var r= this.filterQuery(row[i], query);
503
          // console.log(query+" "+ row+" "+r);
504
          if(r) {
505
            returnValue = true;
506
            break;
507
          }
508
        }
509

    
510
        if(!returnValue) {
511
          return false;
512
        }
513
      }
514

    
515
      for (let filter of filters){
516
        if(filter.countSelectedValues > 0){
517
          for (let value of filter.values){
518
            if(value.selected == true){
519
              let field = 1;
520
              /*if(filter.title == "Type") {
521
                field = 1;
522
              } else if(filter.title == "Compatibility Level") {
523
                field = 4;
524
              } else if(filter.title == "Funder") {
525
                field = 3
526
              }*/
527
              for(let i=0; i<this.columnNames.length; i++) {
528
                if(filter.title == this.columnNames[i]) {
529
                  field = i;
530
                }
531
              }
532

    
533
              //if(row[field].trim() == value.name.trim()) {
534
              if((filter.valueIsExact && (row[field].trim() == value.name.trim()))
535
                || (!filter.valueIsExact && (row[field].includes(value.name)))){
536
                returnValue = true;
537
                if(filter.filterOperator == "or") {
538
                  break;
539
                }
540
              } else {
541
                  if(filter.filterOperator == "and") {
542
                    return false;
543
                  }
544
                  returnValue = false;
545
              }
546
            }
547
          }
548
          if(!returnValue) {
549
            return false;
550
          }
551
        }
552
      }
553

    
554
      return true;
555
    }
556

    
557
    public encode(param: string): string {
558
      return StringUtils.URIEncode(param);
559
    }
560
    public countFilters():number{
561
      var filters=0;
562
      for (let filter of this.filters){
563
         if(filter.countSelectedValues > 0){
564
             filters+=filter.countSelectedValues;
565
         }
566
       }
567
      if(this.searchUtils.keyword.length > 0 ){
568
        filters++;
569
      }
570
      return filters;
571
    }
572
}
(31-31/45)