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

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