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}                       from 'rxjs/Observable';
10
import {Subject}                          from 'rxjs/Subject';
11

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

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

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

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

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

    
40
  })
41
export class SearchPageTableViewComponent  implements OnInit, AfterViewInit {
42
  @Input() piwikSiteId = null;
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 ="OpenAIRE | ";
170
    var _title = _prefix + ((title.length> 50 ) ?title.substring(0,50):title);
171
    this._title.setTitle(_title);
172
    this._meta.updateTag({content:_title},"property='og:title'");
173
  }
174
  updateUrl(url:string) {
175
    this._meta.updateTag({content:url},"property='og:url'");
176
  }
177

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

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

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

    
216
        return filters;
217
  }
218

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

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

    
249
    return allLimits;
250
  }
251

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

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

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

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

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

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

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

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

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

    
331

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

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

    
352
      }, 500);
353
  }
354

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
498

    
499
      let returnValue: boolean = false;
500

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

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

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

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

    
555
      return true;
556
    }
557

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