Changeset 5919 for SRUAggregator/trunk/src/main/resources/assets/js/main.js
- Timestamp:
- 01/15/15 16:01:26 (9 years ago)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
SRUAggregator/trunk/src/main/resources/assets/js/main.js
r5900 r5919 5 5 var PT = React.PropTypes; 6 6 7 var SearchBox = window.MyAggregator.SearchBox;8 var CorpusSelection = window.MyAggregator.CorpusSelection;9 var HitNumber = window.MyAggregator.HitNumber;10 var Results = window.MyAggregator.Results;11 var CorpusView = window.MyAggregator.CorpusView;12 var Modal = window.MyReact.Modal;13 7 var ErrorPane = window.MyReact.ErrorPane; 14 15 var multipleLanguageCode = "mul"; // see ISO-693-3 16 17 var layers = [ 18 { 19 id: "sampa", 20 name: "Phonetics Resources", 21 searchPlaceholder: "stA:z", 22 searchLabel: "SAMPA query", 23 searchLabelBkColor: "#eef", 24 }, 25 { 26 id: "text", 27 name: "Text Resources", 28 searchPlaceholder: "Elephant", 29 searchLabel: "Search text", 30 searchLabelBkColor: "#fed", 31 }, 32 ]; 33 var layerMap = { 34 sampa: layers[0], 35 text: layers[1], 36 }; 37 38 function Corpora(corpora, updateFn) { 39 var that = this; 40 this.corpora = corpora; 41 this.update = function() { 42 updateFn(that); 43 }; 44 45 var sortFn = function(x, y) { 46 var r = x.institution.name.localeCompare(y.institution.name); 47 if (r !== 0) { 48 return r; 49 } 50 var t1 = x.title ? x.title : x.displayName; 51 var t2 = y.title ? y.title : y.displayName; 52 return t1.toLowerCase().localeCompare(t2.toLowerCase()); 53 }; 54 55 this.recurse(function(corpus) { corpus.subCorpora.sort(sortFn); }); 56 this.corpora.sort(sortFn); 57 58 this.recurse(function(corpus, index) { 59 corpus.visible = true; // visible in the corpus view 60 corpus.selected = true; // selected in the corpus view 61 corpus.expanded = false; // not expanded in the corpus view 62 corpus.priority = 1; // priority in corpus view 63 corpus.index = index; 64 }); 65 } 66 67 Corpora.prototype.recurseCorpus = function(corpus, fn) { 68 if (false === fn(corpus)) { 69 // no recursion 70 } else { 71 this.recurseCorpora(corpus.subCorpora, fn); 72 } 73 }; 74 75 Corpora.prototype.recurseCorpora = function(corpora, fn) { 76 var recfn = function(corpus, index){ 77 if (false === fn(corpus)) { 78 // no recursion 79 } else { 80 corpus.subCorpora.forEach(recfn); 81 } 82 }; 83 corpora.forEach(recfn); 84 }; 85 86 Corpora.prototype.recurse = function(fn) { 87 this.recurseCorpora(this.corpora, fn); 88 }; 89 90 Corpora.prototype.getLanguageCodes = function() { 91 var languages = {}; 92 this.recurse(function(corpus) { 93 corpus.languages.forEach(function(lang) { 94 languages[lang] = true; 95 }); 96 return true; 97 }); 98 return languages; 99 }; 100 101 Corpora.prototype.isCorpusVisible = function(corpus, layerId, languageCode) { 102 if (layerId !== "text") { 103 return false; 104 } 105 // yes for any language 106 if (languageCode === multipleLanguageCode) { 107 return true; 108 } 109 // yes if the corpus is in only that language 110 if (corpus.languages && corpus.languages.length === 1 && corpus.languages[0] === languageCode) { 111 return true; 112 } 113 114 // ? yes if the corpus also contains that language 115 if (corpus.languages && corpus.languages.indexOf(languageCode) >=0) { 116 return true; 117 } 118 119 // ? yes if the corpus has no language 120 // if (!corpus.languages || corpus.languages.length === 0) { 121 // return true; 122 // } 123 return false; 124 }; 125 126 Corpora.prototype.setVisibility = function(layerId, languageCode) { 127 // top level 128 this.corpora.forEach(function(corpus) { 129 corpus.visible = this.isCorpusVisible(corpus, layerId, languageCode); 130 this.recurseCorpora(corpus.subCorpora, function(c) { c.visible = corpus.visible; }); 131 }.bind(this)); 132 }; 133 134 Corpora.prototype.getSelectedIds = function() { 135 var ids = []; 136 this.recurse(function(corpus) { 137 if (corpus.visible && corpus.selected) { 138 ids.push(corpus.id); 139 return false; // top-most collection in tree, don't delve deeper 140 } 141 return true; 142 }); 143 144 // console.log("ids: ", ids.length, {ids:ids}); 145 return ids; 146 }; 147 148 Corpora.prototype.getSelectedMessage = function() { 149 var selected = this.getSelectedIds().length; 150 if (this.corpora.length === selected) { 151 return "All available collections"; 152 } else if (selected === 1) { 153 return "1 selected collection"; 154 } 155 return selected+" selected collections"; 156 }; 157 8 var AggregatorPage = window.MyAggregator.AggregatorPage; 158 9 159 10 var Main = React.createClass({displayName: 'Main', … … 163 14 navbarPageFn: this.renderAggregator, 164 15 errorMessages: [], 165 166 corpora: new Corpora([], this.updateCorpora),167 languageMap: {},168 16 }; 169 },170 171 componentDidMount: function() {172 this.refreshCorpora();173 this.refreshLanguages();174 17 }, 175 18 … … 214 57 }, 215 58 216 refreshCorpora: function() {217 this.ajax({218 url: 'rest/corpora',219 success: function(json, textStatus, jqXHR) {220 this.setState({corpora : new Corpora(json, this.updateCorpora)});221 }.bind(this),222 });223 },224 225 refreshLanguages: function() {226 this.ajax({227 url: 'rest/languages',228 success: function(json, textStatus, jqXHR) {229 this.setState({languageMap : json});230 }.bind(this),231 });232 },233 234 updateCorpora: function(corpora) {235 this.setState({corpora:corpora});236 },237 238 59 renderAggregator: function() { 239 60 return React.createElement(AggregatorPage, {ajax: this.ajax, corpora: this.state.corpora, languageMap: this.state.languageMap}); … … 264 85 React.createElement("a", {className: "link", tabIndex: "-1", 265 86 onClick: this.setNavbarPageFn.bind(this, this.renderAggregator)}, "Aggregator") 266 ),267 React.createElement("li", {className: this.state.navbarPageFn === this.renderStatistics ? "active":""},268 React.createElement("a", {className: "link", tabIndex: "-1",269 onClick: this.setNavbarPageFn.bind(this, this.renderStatistics)}, "Statistics")270 87 ), 271 88 React.createElement("li", {className: this.state.navbarPageFn === this.renderHelp ? "active":""}, … … 320 137 }); 321 138 322 var AggregatorPage = React.createClass({displayName: 'AggregatorPage', 323 propTypes: { 324 ajax: PT.func.isRequired, 325 corpora: PT.object.isRequired, 326 languageMap: PT.object.isRequired, 327 }, 328 329 mixins: [React.addons.LinkedStateMixin], 330 timeout: 0, 331 nohits: { 332 requests: [], 333 results: [], 334 }, 335 anyLanguage: [multipleLanguageCode, "Any Language"], 336 337 getInitialState: function () { 338 return { 339 searchLayerId: "text", 340 language: this.anyLanguage, 341 numberOfResults: 10, 342 343 searchId: null, 344 hits: this.nohits, 345 }; 346 }, 347 348 search: function(query) { 349 // console.log(query); 350 if (!query) { 351 this.setState({ hits: this.nohits, searchId: null }); 352 return; 353 } 354 this.props.ajax({ 355 url: 'rest/search', 356 type: "POST", 357 data: { 358 layer: this.state.searchLayerId, 359 language: this.state.language[0], 360 query: query, 361 numberOfResults: this.state.numberOfResults, 362 corporaIds: this.props.corpora.getSelectedIds(), 363 }, 364 success: function(searchId, textStatus, jqXHR) { 365 // console.log("search ["+query+"] ok: ", searchId, jqXHR); 366 this.setState({searchId : searchId}); 367 this.timeout = 250; 368 setTimeout(this.refreshSearchResults, this.timeout); 369 }.bind(this), 370 }); 371 }, 372 373 refreshSearchResults: function() { 374 if (!this.state.searchId) { 375 return; 376 } 377 this.props.ajax({ 378 url: 'rest/search/'+this.state.searchId, 379 success: function(json, textStatus, jqXHR) { 380 if (json.requests.length > 0) { 381 if (this.timeout < 10000) { 382 this.timeout = 1.5 * this.timeout; 383 } 384 setTimeout(this.refreshSearchResults, this.timeout); 385 // console.log("new search in: " + this.timeout+ "ms"); 386 } else { 387 // console.log("search ended"); 388 } 389 this.setState({hits:json}); 390 // console.log("hits:", json); 391 }.bind(this), 392 }); 393 }, 394 395 setLanguage: function(languageObj) { 396 this.props.corpora.setVisibility(this.state.searchLayerId, languageObj[0]); 397 this.setState({language: languageObj}); 398 this.props.corpora.update(); 399 }, 400 401 setLayer: function(layerId) { 402 this.props.corpora.setVisibility(layerId, this.state.language[0]); 403 this.props.corpora.update(); 404 this.setState({searchLayerId: layerId}); 405 }, 406 407 setNumberOfResults: function(e) { 408 var n = e.target.value; 409 if (n < 10) n = 10; 410 if (n > 250) n = 250; 411 this.setState({numberOfResults: n}); 412 e.preventDefault(); 413 e.stopPropagation(); 414 }, 415 416 stop: function(e) { 417 e.preventDefault(); 418 e.stopPropagation(); 419 }, 420 421 toggleCorpusSelection: function(e) { 422 $(this.refs.corporaModal.getDOMNode()).modal(); 423 e.preventDefault(); 424 e.stopPropagation(); 425 }, 426 427 renderAggregator: function() { 428 var layer = layerMap[this.state.searchLayerId]; 429 return ( 430 React.createElement("div", {className: "top-gap"}, 431 React.createElement("div", {className: "row"}, 432 React.createElement("div", {className: "aligncenter", style: {marginLeft:16, marginRight:16}}, 433 React.createElement("div", {className: "input-group"}, 434 React.createElement("span", {className: "input-group-addon", style: {backgroundColor:layer.searchLabelBkColor}}, 435 layer.searchLabel 436 ), 437 438 React.createElement(SearchBox, {search: this.search, placeholder: layer.searchPlaceholder}), 439 React.createElement("div", {className: "input-group-btn"}, 440 React.createElement("button", {className: "btn btn-default input-lg", type: "button", onClick: this.search}, 441 React.createElement("i", {className: "glyphicon glyphicon-search"}) 442 ) 443 ) 444 ) 445 ) 446 ), 447 448 React.createElement("div", {className: "wel", style: {marginTop:20}}, 449 React.createElement("div", {className: "aligncenter"}, 450 React.createElement("form", {className: "form-inline", role: "form"}, 451 452 React.createElement("div", {className: "input-group", style: {marginRight:10}}, 453 React.createElement("span", {className: "input-group-addon nobkg"}, "Search in"), 454 React.createElement("button", {type: "button", className: "btn btn-default", onClick: this.toggleCorpusSelection}, 455 this.props.corpora.getSelectedMessage(), " ", React.createElement("span", {className: "caret"}) 456 ) 457 ), 458 459 React.createElement("div", {className: "input-group", style: {marginRight:10}}, 460 461 React.createElement("span", {className: "input-group-addon nobkg"}, "of"), 462 463 React.createElement("div", {className: "input-group-btn"}, 464 React.createElement("button", {className: "form-control btn btn-default", 465 'aria-expanded': "false", 'data-toggle': "dropdown"}, 466 this.state.language[1], " ", React.createElement("span", {className: "caret"}) 467 ), 468 React.createElement("ul", {ref: "languageDropdownMenu", className: "dropdown-menu"}, 469 React.createElement("li", {key: this.anyLanguage[0]}, " ", React.createElement("a", {tabIndex: "-1", href: "#", 470 onClick: this.setLanguage.bind(this, this.anyLanguage)}, 471 this.anyLanguage[1]) 472 ), 473 _.pairs(this.props.languageMap).sort(function(l1, l2){ 474 return l1[1].localeCompare(l2[1]); 475 }).map(function(l) { 476 var desc = l[1] + " [" + l[0] + "]"; 477 return React.createElement("li", {key: l[0]}, " ", React.createElement("a", {tabIndex: "-1", href: "#", 478 onClick: this.setLanguage.bind(this, l)}, desc)); 479 }.bind(this)) 480 481 ) 482 ), 483 484 React.createElement("div", {className: "input-group-btn"}, 485 React.createElement("ul", {ref: "layerDropdownMenu", className: "dropdown-menu"}, 486 layers.map(function(l) { 487 return React.createElement("li", {key: l.id}, " ", React.createElement("a", {tabIndex: "-1", href: "#", 488 onClick: this.setLayer.bind(this, l.id)}, " ", l.name, " ")); 489 }.bind(this)) 490 491 ), 492 React.createElement("button", {className: "form-control btn btn-default", 493 'aria-expanded': "false", 'data-toggle': "dropdown"}, 494 layer.name, " ", React.createElement("span", {className: "caret"}) 495 ) 496 ) 497 498 ), 499 500 React.createElement("div", {className: "input-group"}, 501 React.createElement("span", {className: "input-group-addon nobkg"}, "and show up to"), 502 React.createElement("div", {className: "input-group-btn"}, 503 React.createElement("input", {type: "number", className: "form-control input", min: "10", max: "250", step: "5", 504 onChange: this.setNumberOfResults, value: this.state.numberOfResults, 505 onKeyPress: this.stop}) 506 ), 507 React.createElement("span", {className: "input-group-addon nobkg"}, "hits") 508 ) 509 ) 510 ) 511 ), 512 513 React.createElement(Modal, {ref: "corporaModal", title: "Collections"}, 514 React.createElement(CorpusView, {corpora: this.props.corpora, languageMap: this.props.languageMap}) 515 ), 516 517 React.createElement("div", {className: "top-gap"}, 518 React.createElement(Results, {requests: this.state.hits.requests, results: this.state.hits.results}) 519 ) 520 ) 521 ); 522 }, 523 render: function() { 524 return this.renderAggregator(); 525 } 526 }); 139 527 140 528 141 var StatisticsPage = React.createClass({displayName: 'StatisticsPage', … … 613 226 var HelpPage = React.createClass({displayName: 'HelpPage', 614 227 openHelpDesk: function() { 615 window.open('http://support.clarin-d.de/mail/form.php?queue=Aggregator ',228 window.open('http://support.clarin-d.de/mail/form.php?queue=Aggregator&lang=en', 616 229 '_blank', 'height=560,width=370'); 617 230 }, … … 656 269 }); 657 270 658 var _ = _ || {659 keys: function() {660 var ret = [];661 for (var x in o) {662 if (o.hasOwnProperty(x)) {663 ret.push(x);664 }665 }666 return ret;667 },668 669 pairs: function(o){670 var ret = [];671 for (var x in o) {672 if (o.hasOwnProperty(x)) {673 ret.push([x, o[x]]);674 }675 }676 return ret;677 },678 };679 680 681 271 React.render(React.createElement(Main, null), document.getElementById('reactMain') ); 682 272 })();
Note: See TracChangeset
for help on using the changeset viewer.