source: SRUAggregator/trunk/src/main/resources/assets/js/corpora.js @ 5959

Last change on this file since 5959 was 5959, checked in by emanuel.dima@uni-tuebingen.de, 9 years ago
  1. alpha16: added version page and better statistics
File size: 8.8 KB
Line 
1/** @jsx React.DOM */
2(function() {
3"use strict";
4
5window.MyAggregator = window.MyAggregator || {};
6
7var PT = React.PropTypes;
8var ReactCSSTransitionGroup = window.React.addons.CSSTransitionGroup;
9// own components
10var Panel = window.MyReact.Panel;
11
12
13/////////////////////////////////
14
15var SearchCorpusBox = React.createClass({displayName: 'SearchCorpusBox',
16        propTypes: {
17                search: PT.func.isRequired,
18        },
19
20        getInitialState: function () {
21                return {
22                        query: ""
23                };
24        },
25
26        handleChange: function(event) {
27                var query = event.target.value;
28                this.setState({query: query});
29
30                if (query.length === 0 || 2 <= query.length) {
31                        this.props.search(query);
32                }
33                event.stopPropagation();
34        },
35
36        handleKey: function(event) {
37                if (event.keyCode==13) {
38                        this.props.search(event.target.value);
39                }
40        },
41
42        render: function() {
43                return  React.createElement("div", {className: "form-group"}, 
44                                        React.createElement("input", {className: "form-control search search-collection", type: "text", 
45                                                value: this.state.query, placeholder: "Search for collection", 
46                                                onChange: this.handleChange})
47                                );
48        }
49});
50
51var CorpusView = window.MyAggregator.CorpusView = React.createClass({displayName: 'CorpusView',
52        propTypes: {
53                corpora: PT.object.isRequired,
54                languageMap: PT.object.isRequired,
55        },
56
57        toggleSelection: function (corpus, e) {
58                var s = !corpus.selected;
59                this.props.corpora.recurseCorpus(corpus, function(c) { c.selected = s; });
60                this.props.corpora.update();
61                this.stop(e);
62        },
63
64        toggleExpansion: function (corpus) {
65                corpus.expanded = !corpus.expanded;
66                this.props.corpora.update();
67        },
68
69        selectAll: function(value) {
70                this.props.corpora.recurse(function(c) { c.selected = value; });
71                this.props.corpora.update();
72        },
73
74        searchCorpus: function(query) {
75                // sort fn: descending priority, stable sort
76                var sortFn = function(a, b){
77                        if (b.priority === a.priority) {
78                                return b.index - a.index; // stable sort
79                        }
80                        return b.priority - a.priority;
81                };
82
83                query = query.toLowerCase();
84                if (!query) {
85                        this.props.corpora.recurse(function(corpus) {corpus.priority = 1; });
86                        this.props.corpora.update();
87                        return;
88                }
89
90                // clean up all priorities
91                this.props.corpora.recurse(function(corpus) {
92                        corpus.priority = 0;
93                });
94
95                // find priority for each corpus
96                var querytokens = query.split(" ").filter(function(x){ return x.length > 0; });
97                this.props.corpora.recurse(function(corpus){
98                        var title = corpus.title;
99                        querytokens.forEach(function(qtoken){
100                                if (title && title.toLowerCase().indexOf(qtoken) >= 0) {
101                                        corpus.priority ++;
102                                }
103                                if (corpus.description && corpus.description.toLowerCase().indexOf(qtoken) >= 0) {
104                                        corpus.priority ++;
105                                }
106                                if (corpus.institution && corpus.institution.name && 
107                                                corpus.institution.name.toLowerCase().indexOf(qtoken) >= 0) {
108                                        corpus.priority ++;
109                                }
110                                if (corpus.languages){
111                                        corpus.languages.forEach(function(lang){
112                                                if (lang.toLowerCase().indexOf(qtoken) >= 0){
113                                                        corpus.priority ++;
114                                                }
115                                        });
116                                        corpus.languages.forEach(function(lang){
117                                                if (this.props.languageMap[lang].toLowerCase().indexOf(qtoken) >= 0){
118                                                        corpus.priority ++;
119                                                }
120                                        }.bind(this));
121                                }
122                        }.bind(this));
123                }.bind(this));
124
125                // ensure parents of visible corpora are also visible; maximum depth = 3
126                var isVisibleFn = function(corpus){ return corpus.priority > 0; };
127                var parentBooster = function(corpus){
128                        if (corpus.priority <= 0 && corpus.subCorpora) {
129                                if (corpus.subCorpora.some(isVisibleFn)) {
130                                        corpus.priority = 0.5;
131                                }
132                        }
133                };
134                for (var i = 3; i > 0; i --) {
135                        this.props.corpora.recurse(parentBooster);
136                }
137
138                this.props.corpora.recurse(function(corpus) { corpus.subCorpora.sort(sortFn); });
139                this.props.corpora.corpora.sort(sortFn);
140
141                // display
142                this.props.corpora.update();
143        },
144
145        stop: function(e) {
146                e.stopPropagation();
147        },
148
149        getMinMaxPriority: function() {
150                var min = 1, max = 0;
151                this.props.corpora.recurse(function(c) { 
152                        if (c.priority < min) min = c.priority;
153                        if (max < c.priority) max = c.priority;
154                });
155                return [min, max];
156        },
157
158        renderCheckbox: function(corpus) {
159                return  React.createElement("button", {className: "btn btn-default"}, 
160                                         corpus.selected ?
161                                                React.createElement("span", {className: "glyphicon glyphicon-check", 'aria-hidden': "true"}) :
162                                                React.createElement("span", {className: "glyphicon glyphicon-unchecked", 'aria-hidden': "true"})
163                                       
164                                );
165        },
166
167        renderExpansion: function(corpus) {
168                if (!corpus.subCorpora || corpus.subCorpora.length === 0) {
169                        return false;
170                }
171                return  React.createElement("div", {className: "expansion-handle", style: {}}, 
172                                        React.createElement("a", null, 
173                                                corpus.expanded ?
174                                                        React.createElement("span", {className: "glyphicon glyphicon-minus", 'aria-hidden': "true"}):
175                                                        React.createElement("span", {className: "glyphicon glyphicon-plus", 'aria-hidden': "true"}), 
176                                               
177                                                corpus.expanded ? " Collapse ":" Expand ", " (", corpus.subCorpora.length, " subcollections)"
178                                        )
179                                );
180        },
181
182        renderLanguages: function(languages) {
183                return languages
184                                .map(function(l) { return this.props.languageMap[l]; }.bind(this))
185                                .sort()
186                                .join(", ");
187        },
188
189        renderFilteredMessage: function() {
190                var total = 0;
191                var visible = 0;
192                this.props.corpora.recurse(function(corpus){
193                        if (corpus.visible) {
194                                total ++;
195                                if (corpus.priority > 0) {
196                                        visible++;
197                                }
198                        }
199                });
200                if (visible === total) {
201                        return false;
202                }
203                return  React.createElement("div", null, " Showing ", visible, " out of ", total, " (sub)collections. ");
204        },
205
206        renderCorpus: function(level, minmaxp, corpus) {
207                if (!corpus.visible || corpus.priority <= 0) {
208                        return false;
209                }
210
211                var indent = {marginLeft:level*50};
212                var corpusContainerClass = "corpus-container "+(corpus.priority>0?"":"dimmed");
213
214                var hue = 120 * corpus.priority / minmaxp[1];
215                var color = minmaxp[0] === minmaxp[1] ? 'transparent' : 'hsl('+hue+', 50%, 50%)';
216                var priorityStyle = {paddingBottom: 4, paddingLeft: 2, borderBottom: '3px solid '+color };
217                var expansive = corpus.expanded ? {overflow:'hidden'} 
218                        : {whiteSpace:'nowrap', overflow:'hidden', textOverflow: 'ellipsis'};
219                return  React.createElement("div", {className: corpusContainerClass, key: corpus.title}, 
220                                        React.createElement("div", {className: "row corpus", onClick: this.toggleExpansion.bind(this, corpus)}, 
221                                                React.createElement("div", {className: "col-sm-1 vcenter"}, 
222                                                                React.createElement("div", {className: "inline", style: priorityStyle, onClick: this.toggleSelection.bind(this,corpus)}, 
223                                                                        this.renderCheckbox(corpus)
224                                                                )
225                                                ), 
226                                                React.createElement("div", {className: "col-sm-8 vcenter"}, 
227                                                        React.createElement("div", {style: indent}, 
228                                                                React.createElement("h3", {style: expansive}, 
229                                                                        corpus.title, 
230                                                                         corpus.landingPage ? 
231                                                                                React.createElement("a", {href: corpus.landingPage, onClick: this.stop}, 
232                                                                                        React.createElement("span", {style: {fontSize:12}}, " – Homepage "), 
233                                                                                        React.createElement("i", {className: "glyphicon glyphicon-home"})
234                                                                                ): false
235                                                                ), 
236
237
238                                                                React.createElement("p", {style: expansive}, corpus.description), 
239                                                                this.renderExpansion(corpus)
240                                                        )
241                                                ), 
242                                                React.createElement("div", {className: "col-sm-3 vcenter"}, 
243                                                        React.createElement("p", {style: expansive}, 
244                                                                React.createElement("i", {className: "fa fa-institution"}), " ", corpus.institution.name
245                                                        ), 
246                                                        React.createElement("p", {style: expansive}, 
247                                                                React.createElement("i", {className: "fa fa-language"}), " ", this.renderLanguages(corpus.languages)
248                                                        )
249                                                )
250                                        ), 
251                                        corpus.expanded ? corpus.subCorpora.map(this.renderCorpus.bind(this, level+1, minmaxp)) : false
252                                );
253        },
254
255        render: function() {
256                var minmaxp = this.getMinMaxPriority();
257                return  React.createElement("div", {style: {margin: "0 30px"}}, 
258                                        React.createElement("div", {className: "row"}, 
259                                                React.createElement("div", {className: "float-left inline"}, 
260                                                        React.createElement("h3", {style: {marginTop:10}}, 
261                                                                this.props.corpora.getSelectedMessage()
262                                                        )
263                                                ), 
264                                                React.createElement("div", {className: "float-right inline"}, 
265                                                        React.createElement("button", {className: "btn btn-default", style: { marginRight: 10}, onClick: this.selectAll.bind(this,true)}, 
266                                                                " Select all"), 
267                                                        React.createElement("button", {className: "btn btn-default", style: { marginRight: 20}, onClick: this.selectAll.bind(this,false)}, 
268                                                                " Deselect all")
269                                                ), 
270                                                React.createElement("div", {className: "float-right inline"}, 
271                                                        React.createElement("div", {className: "inline", style: { marginRight: 20}}, 
272                                                                React.createElement(SearchCorpusBox, {search: this.searchCorpus}), 
273                                                                this.renderFilteredMessage()
274                                                        )
275                                                )
276                                        ), 
277                                       
278                                        this.props.corpora.corpora.map(this.renderCorpus.bind(this, 0, minmaxp))
279                                );
280        }
281});
282
283})();
Note: See TracBrowser for help on using the repository browser.