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() hasPrefix: boolean = true;
43
  @Input() pageTitle = "";
44
  @Input() results;
45
  @Input() filters = [];
46
  @Input() columnNames = [];
47
  @Input() type:string = "";
48
  @Input() entityType: string = "";
49
  @Input() searchUtils:SearchUtilsClass;// = new SearchUtilsClass();
50
  //@Output() downloadClick = new EventEmitter();
51
  @Input() showResultCount:boolean = true;
52
  @Input() showRefine:boolean = true;
53
  @Input() refineFields = [];
54
  //@Input() csvParams: string;
55
  //@Input() csvPath: string;
56
  @Input() openaireLink: string;
57
  @Input() searchViewLink: string;
58
  @Input() disableForms: boolean = false;
59
  @Input() enableSearchView: boolean = true;
60
  @Input() searchFormClass: string = "searchForm";
61
  @Input() formPlaceholderText = "Type Keywords...";
62
  @Input() mapUrl: string = "";
63
  @Input() mapTooltipType: string ="content providers";
64
  @ViewChild (ModalLoading) loading : ModalLoading ;
65
  private searchFieldsHelper:SearchFields = new SearchFields();
66
  private queryParameters: Map<string, string>  = new Map<string,string>();
67
  public parameterNames:string[] =[];
68
  public parameterValues:string[] =[];
69

    
70
  public isPiwikEnabled;
71

    
72

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

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

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

    
116

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

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

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

    
147
    }
148

    
149

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

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

    
162
  }
163

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

    
181
public getParametersFromUrl(params) {
182
  for(var i=0; i< this.refineFields.length ; i++) {
183
    var filterId =  this.refineFields[i];
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
    }
190
  }
191
}
192
 /*
193
 * Mark as check the new filters that are selected, when you get them from search
194
 */
195
  public checkSelectedFilters(filters:Filter[]){
196

    
197
    this.filters = filters;
198
       for(var i=0; i< filters.length ; i++){
199
            var filter:Filter = filters[i];
200
            filter.countSelectedValues = 0;
201

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

    
219
        return filters;
220
  }
221

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

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

    
252
    return allLimits;
253
  }
254

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

    
286
  private removeFilter(value:Value,filter:Filter){
287
    filter.countSelectedValues--;
288
    if(value.selected == true){
289
      value.selected = false;
290
     }
291
    this.goTo(1);
292
  }
293
  goTo(page:number = 1){
294

    
295
    this.searchUtils.page=page;
296
   var table = $('#dpTable').DataTable();
297

    
298
   table.page( page - 1  ).draw( false );
299

    
300
   // Object { page: 0, pages: 3, start: 0, end: 10, length: 10, recordsTotal: 28, recordsDisplay: 21, serverSide: false }
301
   var info = table.page.info();
302
   this.searchUtils.totalResults = info.recordsDisplay;
303

    
304
    var urlParameters = this.createUrlParameters(this.filters,true);
305
    this.location.go(location.pathname,urlParameters);
306
  }
307

    
308
  filterChanged($event){
309
       this.goTo(1);
310
  }
311
  keywordChanged($event) {
312
       this.searchUtils.keyword = $event.value;
313
       this.goTo(1);
314
  }
315

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

    
327
		    this.downloadClick.emit({
328
		        value: queryParameters
329
		    });
330
		}
331
	}
332
*/
333

    
334

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

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

    
355
      }, 500);
356
  }
357

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

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

    
368
        let oldTotal = this.searchUtils.totalResults;
369
        //console.info(result);
370
        this.searchUtils.totalResults = result.length;
371

    
372
        var errorCodes:ErrorCodes = new ErrorCodes();
373
        this.searchUtils.status = errorCodes.DONE;
374
        if(this.searchUtils.totalResults == 0 ){
375
          //this.searchUtils.status = errorCodes.NONE;
376
        }
377

    
378
        // if(oldTotal != this.searchUtils.totalResults) {
379
        //   args[3].detectChanges();
380
        // }
381
         return result;
382
      }
383
       return [];
384
    }
385

    
386
    filterAll(row: any, query: string, filters:Filter[]) {
387
      let returnValue: boolean = false;
388

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

    
394
        if(row.type && row.type.toLowerCase().indexOf(query) > -1) {
395
          returnValue = true;
396
        }
397

    
398
        if(row.countries && row.countries.length > 0) {
399
          for(let country of row.countries) {
400
            if(country.toLowerCase().indexOf(query) > -1) {
401
              returnValue = true;
402
              break;
403
            }
404
          }
405
        }
406

    
407
        if(row.compatibility && row.compatibility.toLowerCase().indexOf(query) > -1) {
408
          returnValue = true;
409
        }
410

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

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

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

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

    
432
        if(row.funder && row.funder.toLowerCase().indexOf(query) > -1) {
433
          returnValue = true;
434
        }
435

    
436
        if(!returnValue) {
437
          return false;
438
        }
439
      }
440

    
441
      for (let filter of filters){
442
        if(filter.countSelectedValues > 0){
443
          for (let value of filter.values){
444
            if(value.selected == true){
445

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

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

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

    
501

    
502
      let returnValue: boolean = false;
503

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

    
514
        if(!returnValue) {
515
          return false;
516
        }
517
      }
518

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

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

    
558
      return true;
559
    }
560

    
561
    public encode(param: string): string {
562
      return StringUtils.URIEncode(param);
563
    }
564
    public countFilters():number{
565
      var filters=0;
566
      for (let filter of this.filters){
567
         if(filter.countSelectedValues > 0){
568
             filters+=filter.countSelectedValues;
569
         }
570
       }
571
      if(this.searchUtils.keyword.length > 0 ){
572
        filters++;
573
      }
574
      return filters;
575
    }
576
}
(39-39/54)