Project

General

Profile

1
import {Component, Input}                 from '@angular/core';
2
import {ViewChild}                from '@angular/core';
3
import {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
import {Subject, Subscriber} from 'rxjs';
9
import {DataTableDirective }              from 'angular-datatables';
10
import {EnvProperties}                    from '../../utils/properties/env-properties';
11
import {Filter, Value}                    from './searchHelperClasses.class';
12
import {SearchFields}       from '../../utils/properties/searchFields';
13
import {SearchCustomFilter, SearchUtilsClass} from './searchUtils.class';
14
import {StringUtils}                 from '../../utils/string-utils.class';
15
import {ModalLoading}                     from '../../utils/modal/loading.component';
16
import {SearchFilterModalComponent}       from './searchFilterModal.component';
17
import {ErrorCodes}                       from '../../utils/properties/errorCodes';
18
import {PiwikService}                     from '../../utils/piwik/piwik.service';
19
import { SEOService } from '../../sharedComponents/SEO/SEO.service';
20
import {HelperService} from "../../utils/helper/helper.service";
21
import {Breadcrumb} from "../../utils/breadcrumbs/breadcrumbs.component";
22

    
23
@Component({
24
    selector: 'search-page-table',
25
    templateUrl:'searchPageTableView.component.html',
26
    styles: [`
27
      #dpTable_info, #dpTable_paginate,  #dpTable_length,  #dpTable_filter{
28
        display: none;
29
      }
30

    
31
      `],
32
      encapsulation: ViewEncapsulation.None // this used in order styles to work
33

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

    
65
  public isPiwikEnabled;
66

    
67

    
68
  @ViewChild (SearchFilterModalComponent) searchFilterModal : SearchFilterModalComponent ;
69
  public currentFilter: Filter;
70
  public errorCodes:ErrorCodes = new ErrorCodes();
71
  subscriptions = [];
72
  dtOptions: DataTables.Settings = {};
73
  showTable = false; filteringAdded = false;
74
  @ViewChild(DataTableDirective) datatableElement: DataTableDirective;
75
  dtTrigger: Subject<any> = new Subject(); //necessary
76
  properties:EnvProperties;
77
  url = null;
78
  public pageContents = null;
79
  @Input() customFilter: SearchCustomFilter = null;
80
  @Input() enableEntitySelection: boolean = false;
81
  @Input() includeOnlyResultsAndFilter:boolean = false;
82
  @Input() showBreadcrumb:boolean = false;
83
  breadcrumbs:Breadcrumb[] = [];
84

    
85
  constructor (private route: ActivatedRoute,
86
               private router: Router,
87
               private location: Location,
88
               private _meta: Meta,
89
               private _title: Title,
90
               private _piwikService:PiwikService,
91
             private seoService: SEOService,
92
               private helper: HelperService) { }
93

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

    
120

    
121
   }
122
  ngOnDestroy() {
123
    this.subscriptions.forEach(subscription => {
124
      if (subscription instanceof Subscriber) {
125
        subscription.unsubscribe();
126
      }
127
    });
128

    
129
      try{
130
        $.fn['dataTable'].ext.search.pop();
131
      }catch(e){
132
        console.error("An error occured in ngOnDestroy of SearchPageTableViewComponent ", e)
133
    }
134
  }
135
    ngAfterViewInit(): void {
136
      try{
137
       $.fn['dataTable'].ext.search.push((settings, data, dataIndex) => {
138
//console.info(dataIndex+": "+data);
139
//console.info(this.results);
140
          //if (this.filterData(this.results[dataIndex], this.searchUtils.keyword, this.filters)) {
141
          if(this.filterAll(this.results[dataIndex], this.searchUtils.keyword.toLowerCase(),this.filters)) {
142
            // console.info("filter true (keyword:"+this.searchUtils.keyword+")");
143

    
144
            return true;
145
          }
146
          // console.info("filter false (keyword:"+this.searchUtils.keyword+")");
147

    
148
          return false;
149
        });
150
      }catch(e){
151
        console.error("An error occured in ngAfterViewInit of SearchPageTableViewComponent ", e)
152
    }
153

    
154
    }
155

    
156

    
157
  totalPages(): number {
158
      let totalPages:any = this.searchUtils.totalResults/(this.searchUtils.size);
159
      if(!(Number.isInteger(totalPages))) {
160
          totalPages = (parseInt(totalPages, 10) + 1);
161
      }
162
      return totalPages;
163
  }
164

    
165
  toggleModal($event) {
166
    this.currentFilter = $event.value;
167
    this.searchFilterModal.open();
168

    
169
  }
170

    
171
  updateDescription(description:string) {
172
    this._meta.updateTag({content:description},"name='description'");
173
    this._meta.updateTag({content:description},"property='og:description'");
174
  }
175
  updateTitle(title:string) {
176
    var _prefix: string = "";
177
    if(this.hasPrefix) {
178
      _prefix = "OpenAIRE | ";
179
    }
180
    var _title = _prefix + ((title.length> 50 ) ?title.substring(0,50):title);
181
    this._title.setTitle(_title);
182
    this._meta.updateTag({content:_title},"property='og:title'");
183
  }
184
  updateUrl(url:string) {
185
    this._meta.updateTag({content:url},"property='og:url'");
186
  }
187

    
188
public getParametersFromUrl(params) {
189
  for(var i=0; i< this.refineFields.length ; i++) {
190
    var filterId =  this.refineFields[i];
191
    if(params[filterId] != undefined) {
192
      if(this.queryParameters == undefined){
193
        this.queryParameters = new Map<string,string>();
194
      }
195
      this.queryParameters[filterId]=decodeURIComponent(params[filterId]);
196
    }
197
  }
198
}
199
 /*
200
 * Mark as check the new filters that are selected, when you get them from search
201
 */
202
  public checkSelectedFilters(filters:Filter[]){
203

    
204
    this.filters = filters;
205
       for(var i=0; i< filters.length ; i++){
206
            var filter:Filter = filters[i];
207
            filter.countSelectedValues = 0;
208

    
209
              if(this.queryParameters[filter.filterId] != undefined) {
210
                let values = (decodeURIComponent(this.queryParameters[filter.filterId])).split(/,(?=(?:[^\"]*\"[^\"]*\")*[^\"]*$)/,-1);
211
                     for(let filterValue of filter.values) {
212
                       if(values.indexOf(StringUtils.quote(filterValue.id)) > -1) {
213
                            filterValue.selected = true;
214
                            filter.countSelectedValues++;
215
                         }else{
216
                           filterValue.selected = false;
217
                         }
218
                    }
219
            }else{
220
              for(let filterValue of filter.values) {
221
                 filterValue.selected = false;
222
              }
223
            }
224
        }
225

    
226
        return filters;
227
  }
228

    
229
  /*
230
  *
231
  */
232
  private createUrlParameters(filters:Filter[], includePage:boolean){
233
    var allLimits="";//location.search.slice(1);
234
    this.parameterNames.splice(0,this.parameterNames.length);
235
    this.parameterValues.splice(0,this.parameterValues.length);
236

    
237
    for (let filter of filters){
238
      var filterLimits="";
239
      if(filter.countSelectedValues > 0){
240
        for (let value of filter.values){
241
          if(value.selected == true){
242
            filterLimits+=((filterLimits.length == 0)?'':',') +'"'+ StringUtils.URIEncode(value.id)+'"';
243
           }
244
        }
245
        this.queryParameters[filter.filterId]=filterLimits;
246
        if(filterLimits.length > 0){
247
          this.parameterNames.push(filter.filterId);
248
          this.parameterValues.push(filterLimits);
249
        }
250
        allLimits+=(allLimits.length==0?"?":"&")+((filterLimits.length == 0 )?'':filter.filterId + '='+ filterLimits) ;
251
      }
252
    }
253
    if(this.searchUtils.keyword.length > 0 ){
254
       allLimits+=(allLimits.length==0?"?":"&")+'fv0=' + this.searchUtils.keyword;
255
      this.parameterNames.push("fv0");
256
      this.parameterValues.push(this.searchUtils.keyword);
257
     }
258

    
259
    return allLimits;
260
  }
261

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

    
292
  private removeFilter(value:Value,filter:Filter){
293
    filter.countSelectedValues--;
294
    if(value.selected == true){
295
      value.selected = false;
296
     }
297
    this.goTo(1);
298
  }
299
  goTo(page:number = 1){
300

    
301
    this.searchUtils.page=page;
302
   var table = $('#dpTable').DataTable();
303

    
304
   table.page( page - 1  ).draw( false );
305

    
306
   // Object { page: 0, pages: 3, start: 0, end: 10, length: 10, recordsTotal: 28, recordsDisplay: 21, serverSide: false }
307
   var info = table.page.info();
308
   this.searchUtils.totalResults = info.recordsDisplay;
309

    
310
    var urlParameters = this.createUrlParameters(this.filters,true);
311
    this.location.go(location.pathname,urlParameters);
312
  }
313

    
314
  filterChanged($event){
315
       this.goTo(1);
316
  }
317
  keywordChanged($event) {
318
       this.searchUtils.keyword = $event.value;
319
       this.goTo(1);
320
  }
321

    
322
  sizeChanged($event) {
323
    this.searchUtils.size = $event;
324
    var table = $('#dpTable').DataTable();
325
    table.page.len( this.searchUtils.size ).draw();
326
    this.goTo(1);
327
  }
328
/*
329
	downloadClicked($event) {
330
		if($event.value == true) {
331
		    var queryParameters = this.createSearchQueryParameters(this.filters);
332

    
333
		    this.downloadClick.emit({
334
		        value: queryParameters
335
		    });
336
		}
337
	}
338
*/
339

    
340

    
341
  getSelectedValues(filter):any{
342
    var selected = [];
343
    if(filter.countSelectedValues >0){
344
      for (var i=0; i < filter.values.length; i++){
345
        if(filter.values[i].selected){
346
          selected.push(filter.values[i]);
347
        }
348
      }
349
    }
350
    return selected;
351

    
352
  }
353
  /*
354
  Trigger a table draw in order to get the initial filtering
355
  */
356
  triggerInitialLoad(){
357
      setTimeout(function(){
358
        var table = $('#dpTable').DataTable();
359
        table.page( 0  ).draw( false );
360

    
361
      }, 500);
362
  }
363

    
364
/*
365
Transform initial - not filtered results to get the filtered number
366
*/
367
    transform(results, searchUtils:SearchUtilsClass = null  ): any {
368
      if(searchUtils!=null) {
369
        this.searchUtils = searchUtils;
370
      }
371
      if(results.length > 0) {
372
        var errorCodes:ErrorCodes = new ErrorCodes();
373
        this.searchUtils.status = errorCodes.LOADING;
374

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

    
377
        let oldTotal = this.searchUtils.totalResults;
378
        //console.info(result);
379
        this.searchUtils.totalResults = result.length;
380

    
381
        var errorCodes:ErrorCodes = new ErrorCodes();
382
        this.searchUtils.status = errorCodes.DONE;
383
        if(this.searchUtils.totalResults == 0 ){
384
          //this.searchUtils.status = errorCodes.NONE;
385
        }
386

    
387
        // if(oldTotal != this.searchUtils.totalResults) {
388
        //   args[3].detectChanges();
389
        // }
390
         return result;
391
      }
392
       return [];
393
    }
394

    
395
    filterAll(row: any, query: string, filters:Filter[]) {
396
      let returnValue: boolean = false;
397

    
398
      if(query) {
399
        if(row.title && row.title.name.toLowerCase().indexOf(query) > -1) {
400
          returnValue = true;
401
        }
402

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

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

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

    
420
        if(row.organizations && row.organizations.length > 0) {
421
          for(let organization of row.organizations) {
422
            if(organization.name.toLowerCase().indexOf(query) > -1) {
423
              returnValue = true;
424
              break;
425
            }
426
          }
427
        }
428

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

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

    
437
        if(row.grantId && row.grantId.toLowerCase().indexOf(query) > -1) {
438
          returnValue = true;
439
        }
440

    
441
        if(row.funder && row.funder.toLowerCase().indexOf(query) > -1) {
442
          returnValue = true;
443
        }
444

    
445
        if(!returnValue) {
446
          return false;
447
        }
448
      }
449

    
450
      for (let filter of filters){
451
        if(filter.countSelectedValues > 0){
452
          for (let value of filter.values){
453
            if(value.selected == true){
454

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

    
481
                returnValue = true;
482
                if(filter.filterOperator == "or") {
483
                  break;
484
                }
485
              } else {
486
                  if(filter.filterOperator == "and") {
487
                    return false;
488
                  }
489
                  returnValue = false;
490
              }
491
            }
492
          }
493
          if(!returnValue) {
494
            return false;
495
          }
496
        }
497
      }
498

    
499
      return true;
500
    }
501
    filterQuery(data, query){
502
      if(data.toLowerCase().indexOf(query.toLowerCase()) > -1){
503
        return true;
504
      }else{
505
        return false;
506
      }
507
    }
508
    filterData(row: any, query: string, filters:Filter[]) {
509

    
510

    
511
      let returnValue: boolean = false;
512

    
513
      if(query) {
514
        for(var i=0; i <this.columnNames.length; i++){
515
          var r= this.filterQuery(row[i], query);
516
          // console.log(query+" "+ row+" "+r);
517
          if(r) {
518
            returnValue = true;
519
            break;
520
          }
521
        }
522

    
523
        if(!returnValue) {
524
          return false;
525
        }
526
      }
527

    
528
      for (let filter of filters){
529
        if(filter.countSelectedValues > 0){
530
          for (let value of filter.values){
531
            if(value.selected == true){
532
              let field = 1;
533
              /*if(filter.title == "Type") {
534
                field = 1;
535
              } else if(filter.title == "Compatibility Level") {
536
                field = 4;
537
              } else if(filter.title == "Funder") {
538
                field = 3
539
              }*/
540
              for(let i=0; i<this.columnNames.length; i++) {
541
                if(filter.title == this.columnNames[i]) {
542
                  field = i;
543
                }
544
              }
545

    
546
              //if(row[field].trim() == value.name.trim()) {
547
              if((filter.valueIsExact && (row[field].trim() == value.name.trim()))
548
                || (!filter.valueIsExact && (row[field].includes(value.name)))){
549
                returnValue = true;
550
                if(filter.filterOperator == "or") {
551
                  break;
552
                }
553
              } else {
554
                  if(filter.filterOperator == "and") {
555
                    return false;
556
                  }
557
                  returnValue = false;
558
              }
559
            }
560
          }
561
          if(!returnValue) {
562
            return false;
563
          }
564
        }
565
      }
566

    
567
      return true;
568
    }
569

    
570
    public encode(param: string): string {
571
      return StringUtils.URIEncode(param);
572
    }
573
    public countFilters():number{
574
      var filters=0;
575
      for (let filter of this.filters){
576
         if(filter.countSelectedValues > 0){
577
             filters+=filter.countSelectedValues;
578
         }
579
       }
580
      return filters;
581
    }
582
  private getPageContents() {
583
    this.subscriptions.push(this.helper.getPageHelpContents(this.properties,  (this.customFilter) ? this.customFilter.valueId : null, this.router.url).subscribe(contents => {
584

    
585
      this.pageContents = contents;
586
    }));
587
  }
588
}
(33-33/47)