Changeset 5931 for SRUAggregator


Ignore:
Timestamp:
01/16/15 19:24:55 (9 years ago)
Author:
emanuel.dima@uni-tuebingen.de
Message:
  1. alpha12: better language filtering using detection, collections view improvements
Location:
SRUAggregator/trunk
Files:
16 edited

Legend:

Unmodified
Added
Removed
  • SRUAggregator/trunk/pom.xml

    r5919 r5931  
    88        <groupId>eu.clarin.sru.fcs</groupId>
    99        <artifactId>Aggregator2</artifactId>
    10         <version>2.0.0-alpha-11</version>
     10        <version>2.0.0-alpha-12</version>
    1111        <name>FCS Aggregator</name>
    1212
  • SRUAggregator/trunk/src/main/java/eu/clarin/sru/fcs/aggregator/app/Aggregator.java

    r5919 r5931  
    8686 * @author edima
    8787 *
    88  * TODO: try to refine results by language using a language library, with UI
    89  * element
    90  *
    91  * TODO: condensed list of corpora
    92  *
    93  * TODO: group the list of corpora by institution?
    94  *
    9588 * TODO: fix ordering of corpora in corpora view
    9689 *
    9790 * TODO: corpora search should not indicate the ones that don't match
    98  *
    99  * TODO: Collections view: home link (make a single consistent text for it)
    10091 *
    10192 * TODO: tri-state for parent collections; search + message implications
     
    267258
    268259        // this function should be thread-safe
    269         public Search startSearch(SRUVersion version, List<Corpus> corpora, String searchString, String searchLang, int maxRecords) throws Exception {
     260        public Search startSearch(SRUVersion version, List<Corpus> corpora,
     261                        String searchString, String searchLang, int maxRecords) throws Exception {
    270262                if (corpora.isEmpty()) {
    271263                        // No corpora
  • SRUAggregator/trunk/src/main/java/eu/clarin/sru/fcs/aggregator/lang/LanguagesISO693_3.java

    r5900 r5931  
    2828        public static class Language {
    2929
    30                 String code, name;
     30                // code is ISO-639-3 (3 letters) while code_2 is ISO-639-2 (2 letters)
     31                String code, code_2, name;
    3132
    32                 public Language(String code, String name) {
     33                public Language(String code, String code_2, String name) {
    3334                        this.code = code;
     35                        this.code_2 = code_2;
    3436                        this.name = name;
    3537                }
    3638        }
    3739
    38         private Map<String, Language> code2Lang = new HashMap<String, Language>();
    39         private Map<String, Language> name2Lang = new HashMap<String, Language>();
     40        private Map<String, Language> codeToLang = new HashMap<String, Language>();
     41        private Map<String, Language> nameToLang = new HashMap<String, Language>();
     42        private Map<String, Language> code_2ToLang = new HashMap<String, Language>();
    4043
    4144        private LanguagesISO693_3() {
    4245                InputStream is = LanguagesISO693_3.class.getResourceAsStream(LANGUAGES_FILE_PATH);
    4346                try (BufferedReader br = new BufferedReader(new InputStreamReader(is, LANGUAGES_FILE_ENCODING))) {
    44                         String line;
     47                        String line = br.readLine(); // ignore first line
    4548                        while ((line = br.readLine()) != null) {
    4649                                if (line.length() > 0) {
     
    5053                                                continue;
    5154                                        }
    52                                         String code = toks[0];
    53                                         String name = toks[6];
    54                                         Language l = new Language(code, name);
    55                                         code2Lang.put(code, l);
    56                                         name2Lang.put(name, l);
     55                                        String code = toks[0].trim();
     56                                        String code_2 = toks[3].trim().isEmpty() ? null : toks[3].trim();
     57                                        if (code_2 != null && code_2.length() != 2) {
     58                                                throw new RuntimeException("bad code_2 code: " + code_2);
     59                                        }
     60                                        String name = toks[6].trim();
     61                                        Language l = new Language(code, code_2, name);
     62                                        codeToLang.put(code, l);
     63                                        if (code_2 != null) {
     64                                                code_2ToLang.put(code_2, l);
     65                                        }
     66                                        nameToLang.put(name, l);
    5767                                }
    5868                        }
     
    6373                ObjectWriter ow = new ObjectMapper().writerWithDefaultPrettyPrinter();
    6474                try {
    65                         System.out.println(ow.writeValueAsString(code2Lang));
     75                        System.out.println(ow.writeValueAsString(codeToLang));
    6676                } catch (JsonProcessingException ex) {
    6777                }
     
    7686
    7787        public Set<String> getCodes() {
    78                 return code2Lang.keySet();
     88                return codeToLang.keySet();
     89        }
     90
     91        public String codeForCode639_2(String code639_2) {
     92                if (code639_2 == null) {
     93                        return null;
     94                }
     95                Language l = code_2ToLang.get(code639_2);
     96                if (l == null) {
     97                        log.error("Unknown 639-2 code: " + code639_2);
     98                        return null;
     99                }
     100                return l.code;
    79101        }
    80102
    81103        public String codeForName(String name) {
    82                 Language l = name2Lang.get(name);
     104                Language l = nameToLang.get(name);
    83105                if (l == null) {
    84106                        log.error("Unknown language name: " + name);
     
    89111
    90112        public String nameForCode(String code) {
    91                 Language l = code2Lang.get(code);
     113                Language l = codeToLang.get(code);
    92114                if (l == null) {
    93115                        log.error("Unknown language code: " + code);
  • SRUAggregator/trunk/src/main/java/eu/clarin/sru/fcs/aggregator/rest/RestService.java

    r5901 r5931  
    120120                        @FormParam("numberOfResults") Integer numberOfResults,
    121121                        @FormParam("language") String language,
     122                        @FormParam("useLanguageGuesser") boolean useLanguageGuesser,
    122123                        @FormParam("corporaIds[]") List<String> corporaIds) throws Exception {
    123124                if (query == null || query.isEmpty()) {
     
    137138                if (numberOfResults > 250) {
    138139                        numberOfResults = 250;
    139                 }
    140                 for (String c : corporaIds) {
    141 
    142140                }
    143141                Search search = Aggregator.getInstance().startSearch(SRUVersion.VERSION_1_2, corpora, query, language, numberOfResults);
  • SRUAggregator/trunk/src/main/java/eu/clarin/sru/fcs/aggregator/search/Kwic.java

    r5919 r5931  
    33import eu.clarin.sru.client.fcs.DataViewHits;
    44import eu.clarin.sru.fcs.aggregator.app.Aggregator;
     5import eu.clarin.sru.fcs.aggregator.lang.LanguagesISO693_3;
    56import java.util.ArrayList;
    67import java.util.List;
     
    6364                }
    6465
    65                 language = Aggregator.getInstance().detectLanguage(hits.getText());
     66                String code_iso639_2 = Aggregator.getInstance().detectLanguage(hits.getText());
     67                language = code_iso639_2 == null ? null
     68                                : LanguagesISO693_3.getInstance().codeForCode639_2(code_iso639_2);
    6669        }
    6770
  • SRUAggregator/trunk/src/main/java/eu/clarin/sru/fcs/aggregator/search/Result.java

    r5893 r5931  
    3737        }
    3838
    39         public Result(Request request, SRUSearchRetrieveResponse response, SRUClientException xc) {
     39        public Result(Request request, SRUSearchRetrieveResponse response,
     40                        SRUClientException xc) {
    4041                this.request = request;
    4142                this.exception = xc;
  • SRUAggregator/trunk/src/main/java/eu/clarin/sru/fcs/aggregator/search/Search.java

    r5900 r5931  
    4141
    4242        public Search(ThrottledClient searchClient, SRUVersion version,
    43                         Statistics statistics, List<Corpus> corpora,
    44                         String searchString, String searchLanguage, int startRecord, int maxRecords
     43                        Statistics statistics, List<Corpus> corpora, String searchString,
     44                        String searchLanguage, int startRecord, int maxRecords
    4545        ) {
    4646                this.id = counter.getAndIncrement();
  • SRUAggregator/trunk/src/main/resources/assets/CLARIN.css

    r5784 r5931  
    2323}
    2424a:visited {
    25   color: #c0a37c;
     25  /*color: #c0a37c;*/
    2626}
    2727
  • SRUAggregator/trunk/src/main/resources/assets/base.css

    r5919 r5931  
    1313
    1414.unselectable {
    15         -webkit-touch-callout: none;
     15        -ms-touch-action: manipulation;
     16        touch-action: manipulation;
     17        cursor: pointer;
    1618        -webkit-user-select: none;
    17         -khtml-user-select: none;
    1819        -moz-user-select: none;
    1920        -ms-user-select: none;
    2021        user-select: none;
     22        -webkit-touch-callout: none;
     23        -khtml-user-select: none;
    2124}
    2225
     
    181184
    182185div.corpus-container {
    183         margin: 10px 0;
     186        margin: 5px 0;
     187        border-bottom: 1px solid #eee;
    184188}
    185189div.corpus-container:hover {
     
    196200
    197201div.corpus h3 {
    198         margin-top: 10px;
     202        margin: 0px 0 5px 0;
    199203        font-size: 18px;
     204}
     205
     206div.corpus p {
     207        margin: 0;
    200208}
    201209
    202210div.corpus button {
    203211        /*border: none;*/
     212}
     213
     214div.corpus .glyphicon {
     215        font-size: 12px;
     216        color: rgb(128,107,82); /*gold*/
     217
     218        -ms-touch-action: manipulation;
     219        touch-action: manipulation;
     220        cursor: pointer;
     221        -webkit-user-select: none;
     222        -moz-user-select: none;
     223        -ms-user-select: none;
     224        user-select: none;
    204225}
    205226
     
    222243
    223244div.corpus div.expansion-handle {
    224         margin: 5px 0;
     245        margin: 0 0 5px 0;
    225246        cursor: pointer;
    226247}
     
    278299        color: #00406F;
    279300        font-weight: bold;
    280         font-size: 12px;
    281301        font-weight: bold;
    282302        white-space: nowrap;
  • SRUAggregator/trunk/src/main/resources/assets/index.html

    r5919 r5931  
    4646                                                <a title="about" id="aboutlink" href="about">
    4747                                                <span class="glyphicon glyphicon-info-sign"></span>
    48                                                 <span>VERSION 2.0.0.α11</span>
     48                                                <span>VERSION 2.0.0.α12</span>
    4949                                        </a>
    5050                                </div>
  • SRUAggregator/trunk/src/main/resources/assets/js/components.js

    r5897 r5931  
    109109
    110110
    111 var PopoverMixin = {
     111var PopoverMixin = window.MyReact.PopoverMixin = {
    112112        getDefaultProps: function(){
    113113                return {hasPopover: true};
     
    115115 
    116116        componentDidMount: function() {
     117                this.refresh();
     118        },
     119        componentDidUpdate: function() {
     120                this.refresh();
     121        },
     122
     123        refresh: function() {
     124                $(this.getDOMNode()).popover('destroy');
     125
    117126                var content;
    118127                if (Array.isArray(this.props.children))
     
    120129                else
    121130                        content = React.renderToString(this.props.children);
     131                // console.log("children: ", this.props.children);
     132                // console.log("content: ", content);
    122133                $(this.getDOMNode()).popover({
    123134                        content: content,
     
    128139                        html: true,
    129140                });
    130         }
     141        },
     142
     143        componentWillUnmount: function() {
     144                $(this.getDOMNode()).popover('destroy');
     145        },     
    131146};
     147
     148window.MyReact.Popover = React.createClass({displayName: 'Popover',
     149        propTypes: {
     150                placement: PT.string,
     151                title: PT.string,
     152                triggerButtonClass: PT.string,
     153                triggerButtonContent: PT.element.isRequired
     154        },
     155        mixins: [PopoverMixin],
     156
     157        handleClick: function(e) {
     158                e.stopPropagation();
     159        },
     160
     161        render: function() {
     162                return  React.createElement("button", {className: this.props.triggerButtonClass, onClick: this.handleClick},
     163                                        this.props.triggerButtonContent
     164                                );
     165        }
     166});
    132167
    133168window.MyReact.InfoPopover = React.createClass({displayName: 'InfoPopover',
  • SRUAggregator/trunk/src/main/resources/assets/js/components.jsx

    r5897 r5931  
    109109
    110110
    111 var PopoverMixin = {
     111var PopoverMixin = window.MyReact.PopoverMixin = {
    112112        getDefaultProps: function(){
    113113                return {hasPopover: true};
     
    115115 
    116116        componentDidMount: function() {
     117                this.refresh();
     118        },
     119        componentDidUpdate: function() {
     120                this.refresh();
     121        },
     122
     123        refresh: function() {
     124                $(this.getDOMNode()).popover('destroy');
     125
    117126                var content;
    118127                if (Array.isArray(this.props.children))
     
    120129                else
    121130                        content = React.renderToString(this.props.children);
     131                // console.log("children: ", this.props.children);
     132                // console.log("content: ", content);
    122133                $(this.getDOMNode()).popover({
    123134                        content: content,
     
    128139                        html: true,
    129140                });
    130         }
     141        },
     142
     143        componentWillUnmount: function() {
     144                $(this.getDOMNode()).popover('destroy');
     145        },     
    131146};
     147
     148window.MyReact.Popover = React.createClass({
     149        propTypes: {
     150                placement: PT.string,
     151                title: PT.string,
     152                triggerButtonClass: PT.string,
     153                triggerButtonContent: PT.element.isRequired
     154        },
     155        mixins: [PopoverMixin],
     156
     157        handleClick: function(e) {
     158                e.stopPropagation();
     159        },
     160
     161        render: function() {
     162                return  <button className={this.props.triggerButtonClass} onClick={this.handleClick}>
     163                                        {this.props.triggerButtonContent}
     164                                </button>;
     165        }
     166});
    132167
    133168window.MyReact.InfoPopover = React.createClass({
  • SRUAggregator/trunk/src/main/resources/assets/js/corpora.js

    r5919 r5931  
    161161                        return false;
    162162                }
    163                 return  React.createElement("div", {className: "expansion-handle", onClick: this.toggleExpansion.bind(this,corpus)},
    164                                         React.createElement("a", null, " ", corpus.expanded ?
    165                                                         React.createElement("span", {className: "glyphicon glyphicon-collapse-down", 'aria-hidden': "true"}):
    166                                                         React.createElement("span", {className: "glyphicon glyphicon-expand", 'aria-hidden': "true"}),
     163                return  React.createElement("div", {className: "expansion-handle", style: {}},
     164                                        React.createElement("a", null,
     165                                                corpus.expanded ?
     166                                                        React.createElement("span", {className: "glyphicon glyphicon-minus", 'aria-hidden': "true"}):
     167                                                        React.createElement("span", {className: "glyphicon glyphicon-plus", 'aria-hidden': "true"}),
    167168                                               
    168169                                                corpus.expanded ? " Collapse ":" Expand ", " ", corpus.subCorpora.length, " subcollections"
     
    175176                                .map(function(l) { return this.props.languageMap[l]; }.bind(this))
    176177                                .sort()
    177                                 .join(" ");
     178                                .join(", ");
    178179        },
    179180
     
    190191                var color = minmaxp[0] === minmaxp[1] ? 'transparent' : 'hsl('+hue+', 50%, 50%)';
    191192                var priorityStyle = {paddingBottom: 4, paddingLeft: 2, borderBottom: '2px solid '+color };
     193                var expansive = corpus.expanded ? {}
     194                        : {whiteSpace:'nowrap', overflow:'hidden', textOverflow: 'ellipsis'};
     195                var title = corpus.title || corpus.displayName;
    192196                return  React.createElement("div", {className: corpusContainerClass, key: corpus.displayName},
    193                                         React.createElement("div", {className: "row corpus"},
    194                                                 React.createElement("div", {className: "col-sm-1 vcenter", onClick: this.toggleSelection.bind(this,corpus)},
    195                                                         React.createElement("div", {style: priorityStyle},
    196                                                                 this.renderCheckbox(corpus)
    197                                                         )
     197                                        React.createElement("div", {className: "row corpus", onClick: this.toggleExpansion.bind(this, corpus)},
     198                                                React.createElement("div", {className: "col-sm-1 vcenter"},
     199                                                                React.createElement("div", {className: "inline", style: priorityStyle, onClick: this.toggleSelection.bind(this,corpus)},
     200                                                                        this.renderCheckbox(corpus)
     201                                                                )
    198202                                                ),
    199203                                                React.createElement("div", {className: "col-sm-8 vcenter"},
    200204                                                        React.createElement("div", {style: indent},
    201                                                                 React.createElement("h3", null, corpus.title ? corpus.title : corpus.displayName, " "),
    202                                                                 React.createElement("p", null, corpus.description),
    203                                                                 this.renderExpansion(corpus)
    204                                                         )
     205                                                                React.createElement("h3", {style: expansive},
     206                                                                         corpus.landingPage ? React.createElement("a", {href: corpus.landingPage}, title): title
     207                                                                ),
     208
     209                                                                React.createElement("p", {style: expansive}, corpus.description)
     210                                                        ),
     211                                                        this.renderExpansion(corpus)
    205212                                                ),
    206213                                                React.createElement("div", {className: "col-sm-3 vcenter"},
    207                                                         React.createElement("p", null, React.createElement("i", {className: "fa fa-institution"}), " ", corpus.institution.name),
    208                                                         React.createElement("p", null, React.createElement("i", {className: "fa fa-language"}), " ", this.renderLanguages(corpus.languages)),
    209                                                          corpus.landingPage ?
    210                                                                 React.createElement("p", null, React.createElement("i", {className: "fa fa-home"}), " ", React.createElement("a", {href: corpus.landingPage}, corpus.landingPage)) :
    211                                                                 false
     214                                                        React.createElement("p", {style: expansive},
     215                                                                React.createElement("i", {className: "fa fa-institution"}), " ", corpus.institution.name
     216                                                        ),
     217                                                        React.createElement("p", {style: expansive},
     218                                                                React.createElement("i", {className: "fa fa-language"}), " ", this.renderLanguages(corpus.languages)
     219                                                        )
    212220                                                )
    213221                                        ),
  • SRUAggregator/trunk/src/main/resources/assets/js/corpora.jsx

    r5919 r5931  
    161161                        return false;
    162162                }
    163                 return  <div className="expansion-handle" onClick={this.toggleExpansion.bind(this,corpus)}>
    164                                         <a> {corpus.expanded ?
    165                                                         <span className="glyphicon glyphicon-collapse-down" aria-hidden="true"/>:
    166                                                         <span className="glyphicon glyphicon-expand" aria-hidden="true"/>
     163                return  <div className="expansion-handle" style={{}}>
     164                                        <a>
     165                                                {corpus.expanded ?
     166                                                        <span className="glyphicon glyphicon-minus" aria-hidden="true"/>:
     167                                                        <span className="glyphicon glyphicon-plus" aria-hidden="true"/>
    167168                                                }
    168169                                                {corpus.expanded ? " Collapse ":" Expand "} {corpus.subCorpora.length} subcollections
     
    175176                                .map(function(l) { return this.props.languageMap[l]; }.bind(this))
    176177                                .sort()
    177                                 .join(" ");
     178                                .join(", ");
    178179        },
    179180
     
    190191                var color = minmaxp[0] === minmaxp[1] ? 'transparent' : 'hsl('+hue+', 50%, 50%)';
    191192                var priorityStyle = {paddingBottom: 4, paddingLeft: 2, borderBottom: '2px solid '+color };
     193                var expansive = corpus.expanded ? {}
     194                        : {whiteSpace:'nowrap', overflow:'hidden', textOverflow: 'ellipsis'};
     195                var title = corpus.title || corpus.displayName;
    192196                return  <div className={corpusContainerClass} key={corpus.displayName}>
    193                                         <div className="row corpus">
    194                                                 <div className="col-sm-1 vcenter" onClick={this.toggleSelection.bind(this,corpus)}>
    195                                                         <div style={priorityStyle}>
    196                                                                 {this.renderCheckbox(corpus)}
    197                                                         </div>
     197                                        <div className="row corpus" onClick={this.toggleExpansion.bind(this, corpus)}>
     198                                                <div className="col-sm-1 vcenter">
     199                                                                <div className="inline" style={priorityStyle} onClick={this.toggleSelection.bind(this,corpus)}>
     200                                                                        {this.renderCheckbox(corpus)}
     201                                                                </div>
    198202                                                </div>
    199203                                                <div className="col-sm-8 vcenter">
    200204                                                        <div style={indent}>
    201                                                                 <h3>{corpus.title ? corpus.title : corpus.displayName} </h3>
    202                                                                 <p>{corpus.description}</p>
    203                                                                 {this.renderExpansion(corpus)}
     205                                                                <h3 style={expansive}>
     206                                                                        { corpus.landingPage ? <a href={corpus.landingPage}>{title}</a>: title }
     207                                                                </h3>
     208
     209                                                                <p style={expansive}>{corpus.description}</p>
    204210                                                        </div>
     211                                                        {this.renderExpansion(corpus)}
    205212                                                </div>
    206213                                                <div className="col-sm-3 vcenter">
    207                                                         <p><i className="fa fa-institution"/> {corpus.institution.name}</p>
    208                                                         <p><i className="fa fa-language"/> {this.renderLanguages(corpus.languages)}</p>
    209                                                         { corpus.landingPage ?
    210                                                                 <p><i className="fa fa-home"/> <a href={corpus.landingPage}>{corpus.landingPage}</a></p> :
    211                                                                 false }
     214                                                        <p style={expansive}>
     215                                                                <i className="fa fa-institution"/> {corpus.institution.name}
     216                                                        </p>
     217                                                        <p style={expansive}>
     218                                                                <i className="fa fa-language"/> {this.renderLanguages(corpus.languages)}
     219                                                        </p>
    212220                                                </div>
    213221                                        </div>
  • SRUAggregator/trunk/src/main/resources/assets/js/search.js

    r5919 r5931  
    1212var HitNumber = window.MyAggregator.HitNumber;
    1313var CorpusView = window.MyAggregator.CorpusView;
     14var Popover = window.MyReact.Popover;
    1415var InfoPopover = window.MyReact.InfoPopover;
    1516var Panel = window.MyReact.Panel;
     
    165166        },
    166167
    167         mixins: [React.addons.LinkedStateMixin],
    168168        timeout: 0,
    169169        nohits: {
     
    178178                        languageMap: {},
    179179                        language: this.anyLanguage,
     180                        languageFilter: 'byMeta',
    180181                        searchLayerId: "text",
    181182                        numberOfResults: 10,
     
    260261        },
    261262
    262         setLanguage: function(languageObj) {
    263                 this.state.corpora.setVisibility(this.state.searchLayerId, languageObj[0]);
    264                 this.setState({language: languageObj});
     263        setLanguageAndFilter: function(languageObj, languageFilter) {
     264                this.state.corpora.setVisibility(this.state.searchLayerId,
     265                        languageFilter === 'byGuess' ? multipleLanguageCode : languageObj[0]);
     266                this.setState({language: languageObj, languageFilter: languageFilter});
    265267                this.state.corpora.update();
    266268        },
     
    282284
    283285        stop: function(e) {
     286                e.preventDefault();
     287                e.stopPropagation();
     288        },
     289
     290        filterResults: function() {
     291                var langCode = this.state.language[0];
     292                return this.state.hits.results.map(function(corpusHit) {
     293                        return {
     294                                corpus: corpusHit.corpus,
     295                                startRecord: corpusHit.startRecord,
     296                                endRecord: corpusHit.endRecord,
     297                                exception: corpusHit.exception,
     298                                searchString: corpusHit.searchString,
     299                                kwics: corpusHit.kwics.filter(function(kwic){
     300                                        return kwic.language === langCode || langCode === multipleLanguageCode || langCode === null;
     301                                }),
     302                        };
     303                });
     304        },
     305
     306        toggleLanguageSelection: function(e) {
     307                $(this.refs.languageModal.getDOMNode()).modal();
    284308                e.preventDefault();
    285309                e.stopPropagation();
     
    323347                                                                React.createElement("div", {className: "input-group-btn"},
    324348                                                                        React.createElement("button", {className: "form-control btn btn-default",
    325                                                                                         'aria-expanded': "false", 'data-toggle': "dropdown"},
     349                                                                                        onClick: this.toggleLanguageSelection},
    326350                                                                                this.state.language[1], " ", React.createElement("span", {className: "caret"})
    327351                                                                        ),
    328                                                                         React.createElement("ul", {ref: "languageDropdownMenu", className: "dropdown-menu"},
    329                                                                                 React.createElement("li", {key: this.anyLanguage[0]}, " ", React.createElement("a", {tabIndex: "-1", href: "#",
    330                                                                                                 onClick: this.setLanguage.bind(this, this.anyLanguage)},
    331                                                                                         this.anyLanguage[1])
    332                                                                                 ),
    333                                                                                         _.pairs(this.state.languageMap).sort(function(l1, l2){
    334                                                                                                 return l1[1].localeCompare(l2[1]);
    335                                                                                         }).map(function(l) {
    336                                                                                                 var desc = l[1] + " [" + l[0] + "]";
    337                                                                                                 return React.createElement("li", {key: l[0]}, " ", React.createElement("a", {tabIndex: "-1", href: "#",
    338                                                                                                         onClick: this.setLanguage.bind(this, l)}, desc));
    339                                                                                         }.bind(this))
    340                                                                                
    341                                                                         )
     352                                                                        React.createElement("span", null)
    342353                                                                ),
    343354
     
    360371                                                        React.createElement("div", {className: "input-group"},
    361372                                                                React.createElement("span", {className: "input-group-addon nobkg"}, "in"),
    362                                                                         React.createElement("button", {type: "button", className: "btn btn-default", onClick: this.toggleCorpusSelection},
    363                                                                                 this.state.corpora.getSelectedMessage(), " ", React.createElement("span", {className: "caret"})
    364                                                                         )
     373                                                                React.createElement("button", {type: "button", className: "btn btn-default", onClick: this.toggleCorpusSelection},
     374                                                                        this.state.corpora.getSelectedMessage(), " ", React.createElement("span", {className: "caret"})
     375                                                                )
    365376                                                        ),                                                     
    366377
     
    383394                    ),
    384395
     396                    React.createElement(Modal, {ref: "languageModal", title: "Select Language"},
     397                                        React.createElement(LanguageSelector, {anyLanguage: this.anyLanguage,
     398                                                                          languageMap: this.state.languageMap,
     399                                                                          selectedLanguage: this.state.language,
     400                                                                          languageFilter: this.state.languageFilter,
     401                                                                          languageChangeHandler: this.setLanguageAndFilter})
     402                    ),
     403
    385404                                React.createElement("div", {className: "top-gap"},
    386                                         React.createElement(Results, {requests: this.state.hits.requests, results: this.state.hits.results})
     405                                        React.createElement(Results, {requests: this.state.hits.requests,
     406                                                 results: this.filterResults(),
     407                                                 searchedLanguage: this.state.language})
    387408                                )
    388409                        )
     
    396417
    397418
     419/////////////////////////////////
     420
     421var LanguageSelector = React.createClass({displayName: 'LanguageSelector',
     422        propTypes: {
     423                anyLanguage: PT.array.isRequired,
     424                languageMap: PT.object.isRequired,
     425                selectedLanguage: PT.array.isRequired,
     426                languageFilter: PT.string.isRequired,
     427                languageChangeHandler: PT.func.isRequired,
     428        },
     429        mixins: [React.addons.LinkedStateMixin],
     430
     431        selectLang: function(language) {
     432                this.props.languageChangeHandler(language, this.props.languageFilter);
     433        },
     434
     435        setFilter: function(filter) {
     436                this.props.languageChangeHandler(this.props.selectedLanguage, filter);
     437        },
     438
     439        renderLanguageObject: function(lang) {
     440                var desc = lang[1] + " [" + lang[0] + "]";
     441                var style = {
     442                        whiteSpace: "nowrap",
     443                        fontWeight: lang[0] === this.props.selectedLanguage[0] ? "bold":"normal",
     444                };
     445                return  React.createElement("div", {key: lang[0]},
     446                                        React.createElement("a", {tabIndex: "-1", href: "#", style: style, onClick: this.selectLang.bind(this, lang)}, desc)
     447                                );
     448        },
     449
     450        renderRadio: function(option) {
     451                return  this.props.languageFilter === option ?
     452                                React.createElement("input", {type: "radio", name: "filterOpts", value: option, checked: true, onChange: this.setFilter.bind(this, option)})
     453                                : React.createElement("input", {type: "radio", name: "filterOpts", value: option, onChange: this.setFilter.bind(this, option)});
     454        },
     455
     456        render: function() {
     457                var languages = _.pairs(this.props.languageMap)
     458                                 .sort(function(l1, l2){return l1[1].localeCompare(l2[1]); });
     459                languages.unshift(this.props.anyLanguage);
     460                languages = languages.map(this.renderLanguageObject);
     461                var third = Math.round(languages.length/3);
     462                var l1 = languages.slice(0, third);
     463                var l2 = languages.slice(third, 2*third);
     464                var l3 = languages.slice(2*third, languages.length);
     465
     466                return  React.createElement("div", null,
     467                                        React.createElement("div", {className: "row"},
     468                                                React.createElement("div", {className: "col-sm-4"}, l1),
     469                                                React.createElement("div", {className: "col-sm-4"}, l2),
     470                                                React.createElement("div", {className: "col-sm-4"}, l3),
     471                                                React.createElement("div", {className: "col-sm-12", style: {marginTop:10, marginBottom:10, borderBottom:"1px solid #eee"}})
     472                                        ),
     473                                        React.createElement("form", {className: "form", role: "form"},
     474                                                React.createElement("div", {className: "input-group"},
     475                                                        React.createElement("div", null,
     476                                                        React.createElement("label", {style: {color:'black'}},
     477                                                                 this.renderRadio('byMeta'), " ",
     478                                                                "Use the collections", "'", " specified language to filter results"
     479                                                        )
     480                                                        ),
     481                                                        React.createElement("div", null,
     482                                                        React.createElement("label", {style: {color:'black'}},
     483                                                                 this.renderRadio('byGuess'), " ",
     484                                                                "Filter results by using a language detector"
     485                                                        )
     486                                                        ),
     487                                                        React.createElement("div", null,
     488                                                        React.createElement("label", {style: {color:'black'}},
     489                                                                 this.renderRadio('byMetaAndGuess'), " ",
     490                                                                "First use the collections", "'", " specified language then also use a language detector"
     491                                                        )
     492                                                        )
     493                                                )
     494                                        )
     495                                );
     496        }
     497});
    398498/////////////////////////////////
    399499
     
    442542                requests: PT.array.isRequired,
    443543                results: PT.array.isRequired,
     544                searchedLanguage: PT.array.isRequired,
    444545        },
    445546
    446547        getInitialState: function () {
    447                 return { displayKwic: false };
     548                return {
     549                        displayKwic: false,
     550                };
    448551        },
    449552
     
    453556
    454557        renderRowLanguage: function(hit) {
    455                 return React.createElement("span", {style: {fontFace:"Courier",color:"black"}}, hit.language);
     558                return React.createElement("span", {style: {fontFace:"Courier",color:"black"}}, hit.language, " ") ;
    456559        },
    457560
     
    467570
    468571        renderRowsAsKwic: function(hit,i) {
    469                 var sleft={textAlign:"left", verticalAlign:"middle", width:"50%"};
    470                 var scenter={textAlign:"center", verticalAlign:"middle", maxWidth:"50%"};
    471                 var sright={textAlign:"right", verticalAlign:"middle", maxWidth:"50%"};
     572                var sleft={textAlign:"left", verticalAlign:"top", width:"50%"};
     573                var scenter={textAlign:"center", verticalAlign:"top", maxWidth:"50%"};
     574                var sright={textAlign:"right", verticalAlign:"top", maxWidth:"50%"};
    472575                return  React.createElement("tr", {key: i, className: "hitrow"},
    473576                                        React.createElement("td", null, this.renderRowLanguage(hit)),
     
    565668
    566669        renderKwicCheckbox: function() {
    567                 return  React.createElement("div", {key: "-option-KWIC-", className: "row"},
    568                                         React.createElement("div", {className: "float-right", style: {marginRight:17}},
    569                                                 React.createElement("div", {className: "btn-group", style: {display:"inline-block"}},
    570                                                         React.createElement("label", {forHtml: "inputKwic", className: "btn-default"},
    571                                                                  this.state.displayKwic ?
    572                                                                         React.createElement("input", {id: "inputKwic", type: "checkbox", value: "kwic", checked: true, onChange: this.toggleKwic}) :
    573                                                                         React.createElement("input", {id: "inputKwic", type: "checkbox", value: "kwic", onChange: this.toggleKwic}),
    574                                                                
    575                                                                 " " + ' ' +
    576                                                                 "Display as Key Word In Context"
    577                                                         )
     670                return  React.createElement("div", {className: "float-right", style: {marginRight:17}},
     671                                        React.createElement("div", {className: "btn-group", style: {display:"inline-block"}},
     672                                                React.createElement("label", {forHtml: "inputKwic", className: "btn-default"},
     673                                                         this.state.displayKwic ?
     674                                                                React.createElement("input", {id: "inputKwic", type: "checkbox", value: "kwic", checked: true, onChange: this.toggleKwic}) :
     675                                                                React.createElement("input", {id: "inputKwic", type: "checkbox", value: "kwic", onChange: this.toggleKwic}),
     676                                                       
     677                                                        " " + ' ' +
     678                                                        "Display as Key Word In Context"
    578679                                                )
    579680                                        )
     
    592693                                                React.createElement("div", {key: "-found-message-", style: margintop}, this.renderFoundMessage(hits), " "),
    593694                                                React.createElement("div", {key: "-progress-", style: margintop}, this.renderProgressBar()),
    594                                                 hits > 0 ? this.renderKwicCheckbox() : false,
     695                                                hits > 0 ?
     696                                                        React.createElement("div", {key: "-option-KWIC-", className: "row"},
     697                                                                this.renderKwicCheckbox()
     698                                                        )
     699                                                        : false,
    595700                                                this.props.results.map(this.renderResultPanels)
    596701                                        )
  • SRUAggregator/trunk/src/main/resources/assets/js/search.jsx

    r5919 r5931  
    1212var HitNumber = window.MyAggregator.HitNumber;
    1313var CorpusView = window.MyAggregator.CorpusView;
     14var Popover = window.MyReact.Popover;
    1415var InfoPopover = window.MyReact.InfoPopover;
    1516var Panel = window.MyReact.Panel;
     
    165166        },
    166167
    167         mixins: [React.addons.LinkedStateMixin],
    168168        timeout: 0,
    169169        nohits: {
     
    178178                        languageMap: {},
    179179                        language: this.anyLanguage,
     180                        languageFilter: 'byMeta',
    180181                        searchLayerId: "text",
    181182                        numberOfResults: 10,
     
    260261        },
    261262
    262         setLanguage: function(languageObj) {
    263                 this.state.corpora.setVisibility(this.state.searchLayerId, languageObj[0]);
    264                 this.setState({language: languageObj});
     263        setLanguageAndFilter: function(languageObj, languageFilter) {
     264                this.state.corpora.setVisibility(this.state.searchLayerId,
     265                        languageFilter === 'byGuess' ? multipleLanguageCode : languageObj[0]);
     266                this.setState({language: languageObj, languageFilter: languageFilter});
    265267                this.state.corpora.update();
    266268        },
     
    282284
    283285        stop: function(e) {
     286                e.preventDefault();
     287                e.stopPropagation();
     288        },
     289
     290        filterResults: function() {
     291                var langCode = this.state.language[0];
     292                return this.state.hits.results.map(function(corpusHit) {
     293                        return {
     294                                corpus: corpusHit.corpus,
     295                                startRecord: corpusHit.startRecord,
     296                                endRecord: corpusHit.endRecord,
     297                                exception: corpusHit.exception,
     298                                searchString: corpusHit.searchString,
     299                                kwics: corpusHit.kwics.filter(function(kwic){
     300                                        return kwic.language === langCode || langCode === multipleLanguageCode || langCode === null;
     301                                }),
     302                        };
     303                });
     304        },
     305
     306        toggleLanguageSelection: function(e) {
     307                $(this.refs.languageModal.getDOMNode()).modal();
    284308                e.preventDefault();
    285309                e.stopPropagation();
     
    323347                                                                <div className="input-group-btn">
    324348                                                                        <button className="form-control btn btn-default"
    325                                                                                         aria-expanded="false" data-toggle="dropdown">
     349                                                                                        onClick={this.toggleLanguageSelection}>
    326350                                                                                {this.state.language[1]} <span className="caret"/>
    327351                                                                        </button>
    328                                                                         <ul ref="languageDropdownMenu" className="dropdown-menu">
    329                                                                                 <li key={this.anyLanguage[0]}> <a tabIndex="-1" href="#"
    330                                                                                                 onClick={this.setLanguage.bind(this, this.anyLanguage)}>
    331                                                                                         {this.anyLanguage[1]}</a>
    332                                                                                 </li>
    333                                                                                 {       _.pairs(this.state.languageMap).sort(function(l1, l2){
    334                                                                                                 return l1[1].localeCompare(l2[1]);
    335                                                                                         }).map(function(l) {
    336                                                                                                 var desc = l[1] + " [" + l[0] + "]";
    337                                                                                                 return <li key={l[0]}> <a tabIndex="-1" href="#"
    338                                                                                                         onClick={this.setLanguage.bind(this, l)}>{desc}</a></li>;
    339                                                                                         }.bind(this))
    340                                                                                 }
    341                                                                         </ul>
     352                                                                        <span/>
    342353                                                                </div>
    343354
     
    360371                                                        <div className="input-group">
    361372                                                                <span className="input-group-addon nobkg">in</span>
    362                                                                         <button type="button" className="btn btn-default" onClick={this.toggleCorpusSelection}>
    363                                                                                 {this.state.corpora.getSelectedMessage()} <span className="caret"/>
    364                                                                         </button>
     373                                                                <button type="button" className="btn btn-default" onClick={this.toggleCorpusSelection}>
     374                                                                        {this.state.corpora.getSelectedMessage()} <span className="caret"/>
     375                                                                </button>
    365376                                                        </div>                                                 
    366377
     
    383394                    </Modal>
    384395
     396                    <Modal ref="languageModal" title="Select Language">
     397                                        <LanguageSelector anyLanguage={this.anyLanguage}
     398                                                                          languageMap={this.state.languageMap}
     399                                                                          selectedLanguage={this.state.language}
     400                                                                          languageFilter={this.state.languageFilter}
     401                                                                          languageChangeHandler={this.setLanguageAndFilter} />
     402                    </Modal>
     403
    385404                                <div className="top-gap">
    386                                         <Results requests={this.state.hits.requests} results={this.state.hits.results} />
     405                                        <Results requests={this.state.hits.requests}
     406                                                 results={this.filterResults()}
     407                                                 searchedLanguage={this.state.language}/>
    387408                                </div>
    388409                        </div>
     
    396417
    397418
     419/////////////////////////////////
     420
     421var LanguageSelector = React.createClass({
     422        propTypes: {
     423                anyLanguage: PT.array.isRequired,
     424                languageMap: PT.object.isRequired,
     425                selectedLanguage: PT.array.isRequired,
     426                languageFilter: PT.string.isRequired,
     427                languageChangeHandler: PT.func.isRequired,
     428        },
     429        mixins: [React.addons.LinkedStateMixin],
     430
     431        selectLang: function(language) {
     432                this.props.languageChangeHandler(language, this.props.languageFilter);
     433        },
     434
     435        setFilter: function(filter) {
     436                this.props.languageChangeHandler(this.props.selectedLanguage, filter);
     437        },
     438
     439        renderLanguageObject: function(lang) {
     440                var desc = lang[1] + " [" + lang[0] + "]";
     441                var style = {
     442                        whiteSpace: "nowrap",
     443                        fontWeight: lang[0] === this.props.selectedLanguage[0] ? "bold":"normal",
     444                };
     445                return  <div key={lang[0]}>
     446                                        <a tabIndex="-1" href="#" style={style} onClick={this.selectLang.bind(this, lang)}>{desc}</a>
     447                                </div>;
     448        },
     449
     450        renderRadio: function(option) {
     451                return  this.props.languageFilter === option ?
     452                                <input type="radio" name="filterOpts" value={option} checked onChange={this.setFilter.bind(this, option)}/>
     453                                : <input type="radio" name="filterOpts" value={option} onChange={this.setFilter.bind(this, option)} />;
     454        },
     455
     456        render: function() {
     457                var languages = _.pairs(this.props.languageMap)
     458                                 .sort(function(l1, l2){return l1[1].localeCompare(l2[1]); });
     459                languages.unshift(this.props.anyLanguage);
     460                languages = languages.map(this.renderLanguageObject);
     461                var third = Math.round(languages.length/3);
     462                var l1 = languages.slice(0, third);
     463                var l2 = languages.slice(third, 2*third);
     464                var l3 = languages.slice(2*third, languages.length);
     465
     466                return  <div>
     467                                        <div className="row">
     468                                                <div className="col-sm-4">{l1}</div>
     469                                                <div className="col-sm-4">{l2}</div>
     470                                                <div className="col-sm-4">{l3}</div>
     471                                                <div className="col-sm-12" style={{marginTop:10, marginBottom:10, borderBottom:"1px solid #eee"}}/>
     472                                        </div>
     473                                        <form className="form" role="form">
     474                                                <div className="input-group">
     475                                                        <div>
     476                                                        <label style={{color:'black'}}>
     477                                                                { this.renderRadio('byMeta') }{" "}
     478                                                                Use the collections{"'"} specified language to filter results
     479                                                        </label>
     480                                                        </div>
     481                                                        <div>
     482                                                        <label style={{color:'black'}}>
     483                                                                { this.renderRadio('byGuess') }{" "}
     484                                                                Filter results by using a language detector
     485                                                        </label>
     486                                                        </div>
     487                                                        <div>
     488                                                        <label style={{color:'black'}}>
     489                                                                { this.renderRadio('byMetaAndGuess') }{" "}
     490                                                                First use the collections{"'"} specified language then also use a language detector
     491                                                        </label>
     492                                                        </div>
     493                                                </div>
     494                                        </form>
     495                                </div>;
     496        }
     497});
    398498/////////////////////////////////
    399499
     
    442542                requests: PT.array.isRequired,
    443543                results: PT.array.isRequired,
     544                searchedLanguage: PT.array.isRequired,
    444545        },
    445546
    446547        getInitialState: function () {
    447                 return { displayKwic: false };
     548                return {
     549                        displayKwic: false,
     550                };
    448551        },
    449552
     
    453556
    454557        renderRowLanguage: function(hit) {
    455                 return <span style={{fontFace:"Courier",color:"black"}}>{hit.language}</span>;
     558                return <span style={{fontFace:"Courier",color:"black"}}>{hit.language} </span> ;
    456559        },
    457560
     
    467570
    468571        renderRowsAsKwic: function(hit,i) {
    469                 var sleft={textAlign:"left", verticalAlign:"middle", width:"50%"};
    470                 var scenter={textAlign:"center", verticalAlign:"middle", maxWidth:"50%"};
    471                 var sright={textAlign:"right", verticalAlign:"middle", maxWidth:"50%"};
     572                var sleft={textAlign:"left", verticalAlign:"top", width:"50%"};
     573                var scenter={textAlign:"center", verticalAlign:"top", maxWidth:"50%"};
     574                var sright={textAlign:"right", verticalAlign:"top", maxWidth:"50%"};
    472575                return  <tr key={i} className="hitrow">
    473576                                        <td>{this.renderRowLanguage(hit)}</td>
     
    565668
    566669        renderKwicCheckbox: function() {
    567                 return  <div key="-option-KWIC-" className="row">
    568                                         <div className="float-right" style={{marginRight:17}}>
    569                                                 <div className="btn-group" style={{display:"inline-block"}}>
    570                                                         <label forHtml="inputKwic" className="btn-default">
    571                                                                 { this.state.displayKwic ?
    572                                                                         <input id="inputKwic" type="checkbox" value="kwic" checked onChange={this.toggleKwic} /> :
    573                                                                         <input id="inputKwic" type="checkbox" value="kwic" onChange={this.toggleKwic} />
    574                                                                 }
    575                                                                 &nbsp;
    576                                                                 Display as Key Word In Context
    577                                                         </label>
    578                                                 </div>
     670                return  <div className="float-right" style={{marginRight:17}}>
     671                                        <div className="btn-group" style={{display:"inline-block"}}>
     672                                                <label forHtml="inputKwic" className="btn-default">
     673                                                        { this.state.displayKwic ?
     674                                                                <input id="inputKwic" type="checkbox" value="kwic" checked onChange={this.toggleKwic} /> :
     675                                                                <input id="inputKwic" type="checkbox" value="kwic" onChange={this.toggleKwic} />
     676                                                        }
     677                                                        &nbsp;
     678                                                        Display as Key Word In Context
     679                                                </label>
    579680                                        </div>
    580681                                </div>;
     
    592693                                                <div key="-found-message-" style={margintop}>{this.renderFoundMessage(hits)} </div>
    593694                                                <div key="-progress-" style={margintop}>{this.renderProgressBar()}</div>
    594                                                 {hits > 0 ? this.renderKwicCheckbox() : false}
     695                                                {hits > 0 ?
     696                                                        <div key="-option-KWIC-" className="row">
     697                                                                {this.renderKwicCheckbox()}
     698                                                        </div>
     699                                                        : false }
    595700                                                {this.props.results.map(this.renderResultPanels)}
    596701                                        </ReactCSSTransitionGroup>
Note: See TracChangeset for help on using the changeset viewer.