Project

General

Profile

1
import {Component, Input, ViewChild, Output, EventEmitter} from '@angular/core';
2
import {Observable}       from 'rxjs/Observable';
3
import {Location} from '@angular/common';
4
import { Filter, Value} from './searchHelperClasses.class';
5
import {SearchResult}     from '../../utils/entities/searchResult';
6
import {SearchFields} from '../../utils/properties/searchFields';
7
import {SearchUtilsClass} from './searchUtils.class';
8
import {DOI} from '../../utils/string-utils.class';
9

    
10
@Component({
11
    selector: 'search-page',
12
    template: `
13

    
14
    <div class="container">
15
      <div class="searchUtils.page-header">
16
          <h1>{{pageTitle}} {{type}}</h1>
17
      </div>
18
      <div>
19
        <div *ngIf="showRefine" class="">
20
          <div  class="row row-offcanvas row-offcanvas-right">
21
            <div  class="col-xs-12 col-sm-10 text-center col-md-offset-1 ">
22

    
23
              <search-form [(keyword)]="searchUtils.keyword" (keywordChange)="keywordChanged($event)"></search-form>
24
              <div *ngIf="isFiltered()" class = "selected-filters-box">
25
                <span *ngIf = "searchUtils.keyword.length > 0">Keywords:
26
                  <span>{{searchUtils.keyword}}<a (click) = "clearKeywords() "> <span class="glyphicon glyphicon-remove clickable" aria-hidden="true"></span></a></span>
27
                </span>
28
                <span *ngFor="let filter of filters " >
29
                  <span *ngIf = "filter.countSelectedValues > 0"> {{filter.title}}: </span>
30
                  <span *ngFor="let value of filter.values.slice(0,filter.countSelectedValues); let i = index;  let end = last; " >
31
                     {{value.name}} <a (click) = "removeFilter(value, filter) "> <span class="glyphicon glyphicon-remove clickable" aria-hidden="true"></span></a>
32
                     <span *ngIf="!end">,</span>
33
                  </span>
34
                </span>
35
                <a  (click)="clearFilters()"  class = "btn text-right"> Clear Filters</a>
36
              </div>
37
            </div>
38
          </div>
39
          <div  class="row row-offcanvas row-offcanvas-right">
40
            <div class="col-xs-12 col-sm-3">
41
              <p *ngFor="let filter of filters " >
42
                <search-filter [filter]="filter"  [showResultCount]=showResultCount (change)="filterChanged($event)"></search-filter>
43
               </p>
44
            </div>
45

    
46
            <div class="col-xs-12 col-sm-9 " >
47
              <search-download [totalResults]="searchUtils.totalResults" (downloadClick)="downloadClicked($event)"></search-download>
48
              <search-paging [(searchUtils)] = "searchUtils"  [(results)] = "results"  [(baseUrl)] = "baseURLWithParameters"></search-paging>
49
              <search-result [results]="results" [totalResults]="searchUtils.totalResults" [status]=searchUtils.status [page]="searchUtils.page"></search-result>
50
            </div>
51
          </div>
52
        </div>
53
        <div *ngIf="!showRefine" >
54

    
55
            <search-form [(keyword)]="searchUtils.keyword" (keywordChange)="keywordChanged($event)"></search-form>
56
            <search-paging [(searchUtils)] = "searchUtils"  [(results)] = "results"   [(baseUrl)] = "baseURLWithParameters"></search-paging>
57
             <search-result [results]="results" [totalResults]="searchUtils.totalResults" [status]=searchUtils.status [page]="searchUtils.page"></search-result>
58

    
59
        </div>
60
      </div>
61
    </div>
62

    
63
    `
64
})
65
export class SearchPageComponent {
66
  @Input() pageTitle = "";
67
  @Input() results = [];
68
  @Input() filters = [];
69
  @Input() type:string = "";
70
  @Input() searchUtils:SearchUtilsClass = new SearchUtilsClass();
71
  @Output() queryChange  = new EventEmitter();
72
  @Output() downloadClick = new EventEmitter();
73
  @Input() baseUrl:string = '';
74
  @Input() showResultCount:boolean = true;
75
  @Input() showRefine:boolean = true;
76
  @Input() refineFields = [];
77
  public fieldIdsMap;//:  { [key:string]:{ name:string, operator:string, type:string, indexField:string, equalityOperator:string  }};
78
  private searchFieldsHelper:SearchFields = new SearchFields();
79
  private queryParameters: Map<string, string>  = new Map<string,string>();
80
  private baseURLWithParameters:string = '';
81
  private sub: any;
82

    
83
  constructor (private location: Location ) {
84

    
85
   }
86

    
87
  ngOnInit() {
88
        this.updateBaseUrlWithParameters(this.filters);
89
  }
90
  ngAfterViewChecked(){
91

    
92
  }
93

    
94
  public getQueryParametersFromUrl(params){
95
    //TODO when final search is done-allFqs/fq
96

    
97
    var parameters = "";
98
    var allFqs = "";
99

    
100
    for(var i=0; i< this.refineFields.length ; i++){
101
         var filterId =  this.refineFields[i];
102

    
103
          if(params[filterId] != undefined) {
104
            if(this.queryParameters == undefined){
105
              this.queryParameters = new Map<string,string>();
106
            }
107
             this.queryParameters[filterId]=decodeURIComponent(params[filterId]);
108
             let values = decodeURIComponent(this.queryParameters[filterId]).split(",");
109
             var countvalues = 0;
110
             var fq = "";
111
             for(let value of values) {
112
               countvalues++;
113
               var paramId = this.fieldIdsMap[filterId].param;
114
              parameters+='&' + paramId+ '='+ value+"&" + this.fieldIdsMap[paramId].operator + "="+((countvalues == 1)?"and":"or");
115
              fq+=(fq.length > 0 ? " " + "or" + " ":"" ) + filterId +" exact " + this.quote(value) ;
116
             }
117
             if(countvalues > 0){
118
               fq="&fq="+fq;
119
             }
120
             allFqs += fq;
121
          }
122

    
123

    
124
   }
125
   var keyword = params['keyword'];
126
   console.info("Type:" + this.type + "filters: "+allFqs);
127
   var doiQuery = "";
128
   var keywordQuery = "";
129
   if((keyword && keyword.length > 0)){
130
     if((this.type == 'publication' ||this.type == 'dataset')){
131
       var DOIs:string[] = DOI.getDOIsFromString(keyword);
132
       var doisParams = "";
133

    
134
       for(var i =0 ;i < DOIs.length; i++){
135
         doisParams+=(doisParams.length > 0?" or ":"")+'((pidclassid exact doi) and (pid exact "'+ DOIs[i]+'"))';
136
       }
137
       if(doisParams.length > 0){
138
         doiQuery += "q=("+doisParams+")"
139
       }
140
     }else{
141
        keywordQuery += "q=("+this.quote(keyword) +")"
142

    
143
     }
144
   }
145
   return (doiQuery.length > 0 ? doiQuery:keywordQuery) + allFqs;
146
 }
147
 public getIndexQueryParametersFromUrl(params){
148
   var parameters = "";
149
   var allFqs = "";
150

    
151
   for(var i=0; i< this.refineFields.length ; i++){
152
        var filterId =  this.refineFields[i];
153
        var fq = "";
154
         if(params[filterId] != undefined) {
155
           if(this.queryParameters == undefined){
156
             this.queryParameters = new Map<string,string>();
157
           }
158
            this.queryParameters[filterId]=decodeURIComponent(params[filterId]);
159
            let values = decodeURIComponent(this.queryParameters[filterId]).split(",");
160
            var countvalues = 0
161
            for(let value of values) {
162
              countvalues++;
163
              parameters+= ((countvalues == 1)?" and (":" or ")+ filterId+ '='+ value;
164
              fq+=(fq.length > 0 ? " " + "or" + " ":"" ) + filterId + " exact " + this.quote(value);
165
            }
166
            parameters+= " ) ";
167
            if(countvalues > 0){
168
              fq="&fq="+fq;
169
            }
170
            allFqs += fq;
171
        }
172

    
173
  }
174
  var keyword = params['keyword'];
175
  var doiQuery = "";
176
  var keywordQuery = "";
177
  if((keyword && keyword.length > 0)){
178
    if((this.type == 'publication' ||this.type == 'dataset')){
179
      var DOIs:string[] = DOI.getDOIsFromString(keyword);
180
      var doisParams = "";
181

    
182
      for(var i =0 ;i < DOIs.length; i++){
183
        doisParams+=(doisParams.length > 0?" or ":"")+'((pidclassid exact doi) and (pid exact "'+ DOIs[i]+'"))';
184
      }
185
      if(doisParams.length > 0){
186
        doiQuery += "and ("+doisParams+")"
187
      }
188
    }else{
189
       keywordQuery += "and ("+this.quote(keyword) +")"
190

    
191
    }
192
  }
193
  return (doiQuery.length > 0 ? doiQuery:keywordQuery) + allFqs;
194

    
195
}
196
 /*
197
 * Mark as check the new filters that are selected, when you get them from search
198
 */
199
  public checkSelectedFilters(filters:Filter[]){
200
    this.filters = filters;
201
       for(var i=0; i< filters.length ; i++){
202
            var filter:Filter = filters[i];
203
            filter.countSelectedValues = 0;
204
              if(this.queryParameters[filter.filterId] != undefined) {
205
                let values = decodeURIComponent(this.queryParameters[filter.filterId]).split(",");
206
                    for(let filterValue of filter.values) {
207
                      if(values.indexOf(filterValue.id) > -1) {
208
                            filterValue.selected = true;
209
                            filter.countSelectedValues++;
210
                         }else{
211
                           filterValue.selected = false;
212

    
213
                         }
214
                    }
215
            }else{
216
              for(let filterValue of filter.values) {
217
                 filterValue.selected = false;
218
              }
219
            }
220
        }
221

    
222
        return filters;
223
  }
224
  /*
225
  * Update the url with proper parameters. This is used as base url in Paging Component
226
  */
227
  public updateBaseUrlWithParameters(filters:Filter[]){
228
    this.baseURLWithParameters = this.baseUrl + this.createUrlParameters(filters,false);
229
  }
230
  /*
231
  *
232
  */
233
  private createUrlParameters(filters:Filter[], includePage:boolean){
234
    var allLimits="";//location.search.slice(1);
235
    for (let filter of filters){
236
      var filterLimits="";
237
      if(filter.countSelectedValues > 0){
238
        for (let value of filter.values){
239
          if(value.selected == true){
240
            filterLimits+=((filterLimits.length == 0)?'':',') + encodeURIComponent(value.id);
241
           }
242
        }
243
        this.queryParameters[filter.filterId]=filterLimits;
244
        allLimits+=((filterLimits.length == 0 )?'':"&" +filter.filterId + '='+ filterLimits) ;
245
      }
246
    }
247
    if(this.searchUtils.keyword.length > 0 ){
248
       allLimits+='&keyword=' + this.searchUtils.keyword;
249
    }
250
    if(this.searchUtils.page != 1 && includePage){
251
       allLimits+=((allLimits.length == 0)?'':'&') + 'page=' + this.searchUtils.page;
252
    }
253
    return allLimits;
254
  }
255
  /*
256
  *
257
  */
258
  private createSearchQueryParameters(filters:Filter[]){
259
    var allFqs = "";
260
    for (let filter of filters){
261
      if(filter.countSelectedValues > 0){
262
        var fq = "";
263
        var count_selected=0;
264
        for (let value of filter.values){
265
          if(value.selected == true){
266
              count_selected++;
267
              fq+=(fq.length > 0 ? " " + filter.filterOperator + " ":"" ) + filter.filterId +  " exact " + this.quote(value.id);
268
           }
269
        }
270
        fq="&fq="+fq;
271
        allFqs += fq;
272
      }
273
    }
274
    var doiQuery = "";
275
    var keywordQuery = "";
276
    console.info("keyyyyword::::"+ this.searchUtils.keyword )
277
    if((this.searchUtils.keyword && this.searchUtils.keyword.length > 0)){
278
      if((this.type == 'publication' ||this.type == 'dataset')){
279
        var DOIs:string[] = DOI.getDOIsFromString(this.searchUtils.keyword);
280
        var doisParams = "";
281

    
282
        for(var i =0 ;i < DOIs.length; i++){
283
          doisParams+=(doisParams.length > 0?" or ":"")+'((pidclassid exact doi) and (pid exact "'+ DOIs[i]+'"))';
284
        }
285
        if(doisParams.length > 0){
286
          doiQuery += "q=("+doisParams+")"
287
        }else{
288
          keywordQuery += "q=("+this.quote(this.searchUtils.keyword) +")"
289
        }
290
      }else{
291
         keywordQuery += "q=("+this.quote(this.searchUtils.keyword) +")"
292
      }
293
    }
294
    console.info("keyyyyword:::: doi:"+ doiQuery+ " keyword:"+keywordQuery )
295

    
296
    return (doiQuery.length > 0 ? doiQuery:keywordQuery) + allFqs;
297

    
298
  }
299
  private createIndexQueryParameters(filters:Filter[]){
300
    var allFqs = "";
301
    for (let filter of filters){
302
      if(filter.countSelectedValues > 0){
303
        var count_selected=0;
304
        var fq = "";
305
        for (let value of filter.values){
306
          if(value.selected == true){
307
              count_selected++;
308
               fq+=(fq.length > 0 ? " " + filter.filterOperator + " ":"" ) + filter.filterId + " exact " + this.quote(value.id);
309
           }
310
        }
311
        if(count_selected > 0){
312
          fq="&fq="+fq;
313
          allFqs += fq;
314
        }
315
      }
316
    }
317
    var doiQuery = "";
318
    var keywordQuery = "";
319
    if((this.searchUtils.keyword && this.searchUtils.keyword.length > 0)){
320
      if((this.type == 'publication' ||this.type == 'dataset')){
321
        var DOIs:string[] = DOI.getDOIsFromString(this.searchUtils.keyword);
322
        var doisParams = "";
323
        for(var i =0 ;i < DOIs.length; i++){
324
          doisParams+=(doisParams.length > 0?" or ":"")+'((pidclassid exact doi) and (pid exact "'+ DOIs[i]+'"))';
325
        }
326
        if(doisParams.length > 0){
327
          doiQuery += " and ("+doisParams+")"
328
        }
329
      }else{
330
         keywordQuery += " and ("+this.quote(this.searchUtils.keyword) +")"
331

    
332
      }
333
    }
334
    return (doiQuery.length > 0 ? doiQuery:keywordQuery) + allFqs;
335

    
336
  }
337
  private isFiltered(){
338
    var filtered=false;
339
    for (let filter of this.filters){
340
       if(filter.countSelectedValues > 0){
341
           filtered = true;
342
           break;
343
       }
344
     }
345
    if(this.searchUtils.keyword.length > 0 ){
346
      filtered = true;
347
    }
348
    return filtered;
349
  }
350
  private clearKeywords(){
351
    if(this.searchUtils.keyword.length > 0 ){
352
      this.searchUtils.keyword ='';
353
    }
354
    this.goTo(1);
355
  }
356
  private clearFilters(){
357
    for (var i =0 ; i <  this.filters.length; i++){
358
         for (var j=0; j <  this.filters[i].countSelectedValues; j++){
359
          if(this.filters[i].values[j].selected){
360
            this.filters[i].values[j].selected = false;
361
           }
362
        this.filters[i].countSelectedValues = 0;
363
      }
364
    }
365
    this.clearKeywords();
366

    
367
  }
368
  private removeFilter(value:Value,filter:Filter){
369
    filter.countSelectedValues--;
370
    if(value.selected == true){
371
      value.selected = false;
372
     }
373
    this.goTo(1);
374

    
375
  }
376
  goTo(page:number = 1){
377
    this.searchUtils.page = page;
378
    // console.info("searchUtils.page goto = "+this.searchUtils.page);
379
    this.queryParameters = new Map<string,string>();
380
    var urlParameters = this.createUrlParameters(this.filters,true);
381
    console.info("urlParams : "+urlParameters);
382
    this.updateBaseUrlWithParameters(this.filters);
383
    var queryParameters = this.createSearchQueryParameters(this.filters);
384
    console.info("queryParams : "+queryParameters);
385
    var indexQuery = this.createIndexQueryParameters(this.filters);
386

    
387
    this.location.go(location.pathname,urlParameters);
388
    // console.info("SearchPAGE::page "+this.searchUtils.page);
389

    
390
    this.queryChange.emit({
391
        value: queryParameters,
392
        index:indexQuery
393

    
394
    });
395

    
396
  }
397
  filterChanged($event){
398
       this.goTo(1);
399
  }
400
  keywordChanged($event) {
401
       this.searchUtils.keyword = $event.value;
402
       this.goTo(1);
403
  }
404

    
405
	downloadClicked($event) {
406
		if($event.value == true) {
407
		    var queryParameters = this.createSearchQueryParameters(this.filters);
408

    
409
		    this.downloadClick.emit({
410
		        value: queryParameters
411
		    });
412
		}
413
	}
414

    
415
  /*
416
  * Get A sub-array of this.refineFields array, which contains the ids of the selected filters
417
  */
418
  public getSelectedFilters():string[] {
419
    var selected:string[] = [];
420
    for(var i=0; i <  this.filters.length; i++){
421
      var filter:Filter = this.filters[i];
422
      if(filter.countSelectedValues > 0){
423
          selected.push(filter.filterId);
424
      }
425
    }
426
    return selected;
427
  }
428
  /*
429
  * Get A sub-array of this.refineFields array, which contains the ids of the selected parameters
430
  */
431
  private getSelectedParameters():string[] {
432
    var selected:string[] = [];
433
    var params:string[] = Object.keys(this.queryParameters);
434
    for(var i=0; i <  params.length; i++){
435
       if(this.refineFields.indexOf(params[i]) > -1){
436
          selected.push(params[i]);
437
      }
438
    }
439
    return selected;
440
  }
441
  /*
442
  * 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 )
443
  */
444
  public getFields():string[] {
445
    var selected_filters:string[] = this.getSelectedFilters();
446
    if(selected_filters.length == 0){
447
      selected_filters = this.getSelectedParameters();
448
    }
449
    var fields:string[] = [];
450
    for(var i =0 ; i < this.refineFields.length;i++){
451
      var dependentTo = this.searchFieldsHelper.DEPENDENT_FIELDS[this.refineFields[i]];
452

    
453
      //if filter is not marked as hidden OR it is hidden but it is dependent to a field that it IS selected
454
      if(this.searchFieldsHelper.HIDDEN_FIELDS.indexOf(this.refineFields[i]) == -1 || (selected_filters.indexOf(dependentTo) != -1) ){
455
          fields.push(this.refineFields[i]);
456
       }
457
    }
458
    return fields;
459
  }
460
  /*
461
  * Get a query  string of all fields, that want to get from search (e.g. &fields=funderid&fields=projectstartyear&...))
462
  */
463
  public getRefineFieldsQuery():string{
464

    
465
    var fields:string[] = this.getFields();
466
    var fieldsStr = ""
467
    for(var i =0 ; i < fields.length  ;i++){
468
        fieldsStr+="&fields="+fields[i];
469
    }
470
    return "&refine=true"+fieldsStr;
471
  }
472
  private quote(params: string):string {
473
      return encodeURIComponent('"'+params+'"');
474
  }
475

    
476
}
(7-7/10)