Changeset 7221
- Timestamp:
- 10/21/18 18:24:09 (6 years ago)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
SRUAggregator/trunk/src/main/resources/assets/js/pages/aggregatorpage.jsx
r7148 r7221 17 17 var AggregatorPage = createReactClass({ 18 18 // fixme! - class AggregatorPage extends React.Component { 19 20 21 22 23 19 propTypes: { 20 ajax: PT.func.isRequired, 21 error: PT.func.isRequired, 22 embedded: PT.bool.isRequired 23 }, 24 24 25 25 nohits: { … … 29 29 30 30 getInitialState: function () { 31 var aggrContext = getQueryVariable('x-aggregation-context'); 32 aggrContext = aggrContext && JSON.parse(aggrContext); 33 31 34 return { 32 35 corpora: new Corpora([], this.updateCorpora), 33 36 languageMap: {}, 34 37 weblichtLanguages: [], 35 queryTypeId: getQueryVariable('queryType') || 'cql', 36 query: getQueryVariable('query') || '', 37 aggregationContext: getQueryVariable('x-aggregation-context') || '', 38 queryTypeId: getQueryVariable('queryType') || 'cql', 39 cqlQuery: ((getQueryVariable('queryType') || 'cql') === 'cql') && getQueryVariable('query') || '', 40 fcsQuery: ((getQueryVariable('queryType') || 'cql') === 'fcs') && getQueryVariable('query') || '', 41 aggregationContext: aggrContext || null, 38 42 language: this.anyLanguage, 39 43 languageFilter: 'byMeta', … … 45 49 46 50 zoomedCorpusHit: null, 47 _isMounted: false48 51 }; 49 52 }, 50 53 51 54 componentDidMount: function() { 52 this.setState({_isMounted: true});55 this._isMounted = true; 53 56 54 57 this.props.ajax({ 55 58 url: 'rest/init', 56 59 success: function(json, textStatus, jqXHR) { 57 if (this. state._isMounted) {60 if (this._isMounted) { 58 61 var corpora = new Corpora(json.corpora, this.updateCorpora); 59 window.MyAggregator.corpora = json.corpora; 60 this.setState({ 61 corpora : corpora, 62 languageMap: json.languages, 63 weblichtLanguages: json.weblichtLanguages, 64 query: this.state.query || json.query || '', 65 }); 62 66 63 // // for testing aggregation context 67 64 // json['x-aggregation-context'] = { … … 69 66 // }; 70 67 71 if (this.state.aggregationContext && !json['x-aggregation-context']) { 72 json['x-aggregation-context'] = JSON.parse(this.state.aggregationContext); 73 console.log(json['x-aggregation-context']); 74 } 75 if (json['x-aggregation-context']) { 76 window.MyAggregator.xAggregationContext = json["x-aggregation-context"]; 77 corpora.setAggregationContext(json["x-aggregation-context"]); 78 if (!corpora.getSelectedIds().length) { 79 this.props.error("Cannot find the required collection, will search all collections instead"); 80 corpora.recurse(function(corpus) { corpus.selected = true; }); 81 } 82 corpora.update(); 83 } 68 var aggregationContext = json['x-aggregation-context'] || this.state.aggregationContext; 69 70 window.MyAggregator.mode = getQueryVariable('mode') || json.mode; 71 window.MyAggregator.corpora = json.corpora; 72 window.MyAggregator.xAggregationContext = aggregationContext; 73 84 74 // Setting visibility, e.g. only corpora 85 // from v2.0 endpoints for fcs v2.0 86 this.state.corpora.setVisibility(this.state.queryTypeId, this.state.language[0]); 87 corpora.update(); 88 89 if (getQueryVariable('mode') === 'search' || 90 json.mode === 'search') { 91 window.MyAggregator.mode = 'search'; 92 this.search(); 93 } 75 // from v2.0 endpoints for fcs v2.0 76 corpora.setVisibility(this.state.queryTypeId, this.state.language[0]); 77 78 if (aggregationContext) { 79 const contextCorporaInfo = corpora.setAggregationContext(aggregationContext); 80 const unavailableCorporaHandles = contextCorporaInfo.unavailable; // list of unavailable aggregationContext 81 if (unavailableCorporaHandles.length > 0) { 82 this.props.error("Could not find requested collection handles:\n" + unavailableCorporaHandles.join('\n')); 83 } 84 85 const actuallySelectedCorpora = corpora.getSelectedIds(); 86 87 if (contextCorporaInfo.selected.length !== actuallySelectedCorpora.length) { 88 if (actuallySelectedCorpora.length === 0) { 89 this.props.error("This search does not support the required collection(s), will search all collections instead"); // TODO give detailed reason its not supported. 90 corpora.recurse(function(corpus) { corpus.selected = true; }); 91 } else { 92 var err = "Some required context collections are not supported for this search:\n" 93 err = err + contextCorpora.filter((c) => { 94 if (actuallySelectedCorpora.indexOf(c) === -1) { 95 console.warn("Requested corpus but not available for selection", c); 96 return true; 97 } 98 return false; 99 }).map((c) => c.title).join('\n') 100 this.props.error(err); 101 } 102 } 103 } 104 else { 105 // no context set all visibl to selected as default. 106 console.log("no context set, selecting all available"); 107 corpora.recurse(c => {c.visible ? c.selected=true : null}) 108 } 109 110 this.setState({ 111 corpora : corpora, 112 languageMap: json.languages, 113 weblichtLanguages: json.weblichtLanguages, 114 aggregationContext: aggregationContext, 115 }, this.postInit); 116 } 117 else { 118 console.warn("Got Aggregator init response, but not mounted!"); 94 119 } 95 120 }.bind(this), 96 121 }); 97 122 }, 123 124 postInit() { 125 if (window.MyAggregator.mode === 'search') { 126 this.search(); 127 } 128 }, 98 129 99 130 updateCorpora: function(corpora) { 100 131 this.setState({corpora:corpora}); 101 132 }, 102 103 search: function() { 104 var query = this.state.query; 133 134 getCurrentQuery() { 135 return this.state.queryTypeId === 'fcs' ? this.state.fcsQuery : this.state.cqlQuery; 136 }, 137 138 search() { 139 var query = this.getCurrentQuery(); 105 140 var queryTypeId = this.state.queryTypeId; 106 if (!query || this.props.embedded) {141 if (!query || (this.props.embedded && window.MyAggregator.mode !== 'search')) { 107 142 this.setState({ hits: this.nohits, searchId: null }); 108 143 return; … … 120 155 type: "POST", 121 156 data: { 122 123 157 query: query, 158 queryType: queryTypeId, 124 159 language: this.state.language[0], 125 160 numberOfResults: this.state.numberOfResults, … … 142 177 }); 143 178 }, 179 144 180 nextResults: function(corpusId) { 145 181 // console.log("searching next results in corpus:", corpusId); … … 161 197 162 198 refreshSearchResults: function() { 163 if (!this.state.searchId || !this. state._isMounted) {199 if (!this.state.searchId || !this._isMounted) { 164 200 return; 165 201 } … … 225 261 setQueryType: function(queryTypeId) { 226 262 this.state.corpora.setVisibility(queryTypeId, this.state.language[0]); 263 setQueryVariable('queryType', queryTypeId); 264 setQueryVariable('query', queryTypeId === 'cql' ? this.state.cqlQuery : this.state.fcsQuery) 227 265 this.setState({ 228 266 queryTypeId: queryTypeId, 229 267 hits: this.nohits, 230 268 searchId: null, 231 displayADV: queryTypeId == "fcs" ? true : false,232 corpora: this.state.corpora, // === this.state.corpora.update();233 269 }); 234 270 }, … … 308 344 }, 309 345 310 onQuery: function(event) { 311 this.setState({query: event.target.value}); 312 }, 313 314 onADVQuery: function(fcsql) { 315 this.setState({query: fcsql.target.value}); 346 onQueryChange: function(queryStr) { 347 if (this.state.queryTypeId === 'cql') { 348 this.setState({ 349 cqlQuery: queryStr || '', 350 }); 351 } else { 352 this.setState({ 353 fcsQuery: queryStr || '', 354 }); 355 } 356 setQueryVariable('query', queryStr); 316 357 }, 317 358 … … 320 361 this.search(); 321 362 } 322 },323 324 handleADVKey: function(event) {325 if (event.keyCode==13) {326 this.addADVToken();327 }328 363 }, 329 364 … … 343 378 renderSearchButtonOrLink: function() { 344 379 if (this.props.embedded) { 345 var query = this. state.query;380 var query = this.getCurrentQuery(); 346 381 var queryTypeId = this.state.queryTypeId; 347 382 var btnClass = classNames({ 348 383 'btn': true, 349 384 'btn-default': queryTypeId === 'cql', 385 'btn-primary': true, 350 386 'input-lg': true 351 387 }); … … 364 400 ); 365 401 }, 402 403 404 renderQueryInput() { 405 var queryType = queryTypeMap[this.state.queryTypeId]; 406 return ( 407 <QueryInput 408 searchedLanguages={this.state.searchedLanguages || [multipleLanguageCode]} 409 corpora={this.props.corpora} 410 queryTypeId={this.state.queryTypeId} 411 query={this.getCurrentQuery()===undefined ? queryType.searchPlaceholder : this.getCurrentQuery()} 412 embedded={this.props.embedded} 413 placeholder={queryType.searchPlaceholder} 414 onQueryChange={this.onQueryChange} 415 onKeyDown={this.handleKey} /> 416 ); 417 }, 418 419 renderEmbed () { 420 var queryType = queryTypeMap[this.state.queryTypeId]; 421 422 return <div className="aligncenter" style={{marginLeft:16, marginRight:16}}> 423 <div className={"input-group"}> 424 <span className="input-group-addon" style={{backgroundColor:queryType.searchLabelBkColor}}> 425 {queryType.searchLabel} 426 </span> 427 428 { this.renderQueryInput() } 429 430 <div className="input-group-btn"> 431 {this.renderSearchButtonOrLink()} 432 </div> 433 </div> 434 </div> 435 }, 436 437 renderGQB () { 438 var queryType = queryTypeMap[this.state.queryTypeId]; 439 440 return <div style={{marginLeft:16, marginRight:16}}> 441 <div className="panel panel-default"> 442 <div className="panel-heading" style={{backgroundColor:queryType.searchLabelBkColor, fontSize: "120%"}}> 443 {queryType.searchLabel} 444 </div> 445 446 <div className="panel-body"> 447 { this.renderQueryInput() } 448 </div> 449 450 <div className="panel-footer"> 451 <div className="input-group"> 452 453 <pre className="adv-query-preview aligncenter input-control input-lg">{this.getCurrentQuery()}</pre> 454 455 <div className="input-group-btn"> 456 {this.renderSearchButtonOrLink()} 457 </div> 458 </div> 459 </div> 460 </div> 461 </div> 462 }, 463 464 renderUnavailableCorporaMessage() { 465 if (!this.state.corpora) { 466 return; 467 } 468 const unavailable = []; 469 this.state.corpora.recurse((c) => { 470 if (c.selected && ! c.visible) { 471 unavailable.push(c); 472 } 473 if (c.selected) { 474 // apparently a selected corpus 475 } 476 }); 477 478 if (unavailable.length) { 479 return <div id="unavailable-corpora-message" className="text-muted"> 480 <div id="unavailable-corpora-message-message"> 481 <a role="button" data-toggle="dropdown">{unavailable.length} selected collection{unavailable.length > 1 ? 's are' : ' is'} disabled in this search mode.</a> 482 </div> 483 <ul id="unavailable-corpora-message-list" className="dropdown-menu"> 484 { 485 unavailable.map((c) => <li className="unavailable-corpora-message-item">{c.name}</li>) 486 } 487 </ul> 488 </div> 489 } 490 }, 366 491 367 492 render: function() { 493 368 494 var queryType = queryTypeMap[this.state.queryTypeId]; 369 495 return ( 370 496 <div className="top-gap"> 371 497 <div className="row"> 372 <div className="aligncenter" style={{marginLeft:16, marginRight:16}}> 373 <div className="input-group"> 374 <span className="input-group-addon" style={{backgroundColor:queryType.searchLabelBkColor}}> 375 {queryType.searchLabel} 376 </span> 377 <QueryInput 378 searchedLanguages={this.state.searchedLanguages || [multipleLanguageCode]} 379 queryTypeId={this.state.queryTypeId} 380 query={this.state.query} 381 embedded={this.props.embedded} 382 placeholder={queryType.searchPlaceholder} 383 onChange={this.onADVQuery} 384 onQuery={this.onQuery} 385 onKeyDown={this.handleKey} /> 386 387 <div className="input-group-btn"> 388 {this.renderSearchButtonOrLink()} 389 </div> 390 </div> 391 </div> 498 { (!this.props.embedded && this.state.queryTypeId == "fcs") ? this.renderGQB() : this.renderEmbed() } 392 499 </div> 393 500 394 <div className="wel " style={{marginTop:20}}>501 <div className="well" style={{marginTop:20}}> 395 502 <div className="aligncenter" > 503 { 504 //this.renderUnavailableCorporaMessage() 505 } 396 506 <form className="form-inline" role="form"> 397 507 … … 448 558 </div> 449 559 450 <Modal ref="corporaModal" title={<span>Collections </span>}>560 <Modal ref="corporaModal" title={<span>Collections <small className="text-muted">{this.props.corpora && this.props.corpora.getSelectedMessage()}</small></span>}> 451 561 <CorpusView corpora={this.state.corpora} languageMap={this.state.languageMap} /> 452 562 </Modal> … … 504 614 this.recurse(function(corpus, index) { 505 615 corpus.visible = true; // visible in the corpus view 506 corpus.selected = true; // selected in the corpus view616 corpus.selected = false; // not selected in the corpus view, assign later 507 617 corpus.expanded = false; // not expanded in the corpus view 508 618 corpus.priority = 1; // used for ordering search results in corpus view … … 586 696 this.corpora.forEach(selectSubTree.bind(this, false)); 587 697 698 var handlesNotFound = []; 588 699 var corporaToSelect = []; 589 _.pairs(endpoints2handles).forEach( function(endp){700 _.pairs(endpoints2handles).forEach((endp) => { 590 701 var endpoint = endp[0]; 591 702 var handles = endp[1]; 592 console.log(endp); 593 console.log(handles); 594 handles.forEach(function(handle){ 595 this.recurse(function(corpus){ 703 console.log('setAggregationContext: endpoint', endpoint); 704 console.log('setAggregationContext: handles', handles); 705 handles.forEach((handle) => { 706 var found = false; 707 this.recurse((corpus) => { 596 708 if (corpus.handle === handle) { 709 found = true; 597 710 corporaToSelect.push(corpus); 598 711 } 599 }.bind(this)); 600 }.bind(this)); 601 }.bind(this)); 712 }) 713 if (!found) { 714 console.warn("Handle not found in corpora", handle); 715 handlesNotFound.push(handle); 716 } 717 }) 718 }) 602 719 603 720 corporaToSelect.forEach(selectSubTree.bind(this, true)); 721 return {'selected': corporaToSelect, 'unavailable': handlesNotFound}; 604 722 }; 605 723 … … 609 727 if (corpus.visible && corpus.selected) { 610 728 ids.push(corpus.id); 611 return false; // top-most collection in tree, don't delve deeper 729 //eturn false; // top-most collection in tree, don't delve deeper 730 // But subcollections are also selectable on their own?... 612 731 } 613 732 return true; … … 628 747 }; 629 748 630 function Corpora(corpora, updateFn) {631 var that = this;632 this.corpora = corpora;633 this.update = function() {634 updateFn(that);635 };636 637 var sortFn = function(x, y) {638 var r = x.institution.name.localeCompare(y.institution.name);639 if (r !== 0) {640 return r;641 }642 return x.title.toLowerCase().localeCompare(y.title.toLowerCase());643 };644 645 this.recurse(function(corpus) { corpus.subCorpora.sort(sortFn); });646 this.corpora.sort(sortFn);647 648 this.recurse(function(corpus, index) {649 corpus.visible = true; // visible in the corpus view650 corpus.selected = true; // selected in the corpus view651 corpus.expanded = false; // not expanded in the corpus view652 corpus.priority = 1; // used for ordering search results in corpus view653 corpus.index = index; // original order, used for stable sort654 });655 }656 657 749 function getQueryVariable(variable) { 658 750 var query = window.location.search.substring(1); 659 751 var vars = query.split('&'); 660 console.log("vars: ", vars);661 752 for (var i = 0; i < vars.length; i++) { 662 753 var pair = vars[i].split('='); … … 669 760 } 670 761 671 function Corpora(corpora, updateFn) { 672 var that = this; 673 this.corpora = corpora; 674 this.update = function() { 675 updateFn(that); 676 }; 677 678 var sortFn = function(x, y) { 679 var r = x.institution.name.localeCompare(y.institution.name); 680 if (r !== 0) { 681 return r; 682 } 683 return x.title.toLowerCase().localeCompare(y.title.toLowerCase()); 684 }; 685 686 this.recurse(function(corpus) { corpus.subCorpora.sort(sortFn); }); 687 this.corpora.sort(sortFn); 688 689 this.recurse(function(corpus, index) { 690 corpus.visible = true; // visible in the corpus view 691 corpus.selected = true; // selected in the corpus view 692 corpus.expanded = false; // not expanded in the corpus view 693 corpus.priority = 1; // used for ordering search results in corpus view 694 corpus.index = index; // original order, used for stable sort 695 }); 762 /* setter opposite of getQueryVariable*/ 763 function setQueryVariable(qvar, value) { 764 var query = window.location.search.substring(1); 765 var vars = query.split('&'); 766 var d = {}; 767 d[qvar] = value; 768 var found = false; 769 for (var i = 0; i < vars.length; i++) { 770 var pair = vars[i].split('='); 771 if (decodeURIComponent(pair[0]) === qvar) { 772 773 vars[i] = encodeQueryData(d); 774 found=true; 775 break; 776 } 777 } 778 779 if (!found) { 780 // add to end of url 781 vars.push(encodeQueryData(d)); 782 } 783 784 var searchPart = vars.join('&'); 785 var newUrl = window.location.origin + window.location.pathname+'?'+searchPart; 786 console.log("set url", newUrl); 787 window.history.replaceState(window.history.state, null, newUrl); 696 788 } 789 697 790 698 791 function encodeQueryData(data)
Note: See TracChangeset
for help on using the changeset viewer.