Changeset 5900 for SRUAggregator


Ignore:
Timestamp:
12/10/14 14:33:08 (9 years ago)
Author:
emanuel.dima@uni-tuebingen.de
Message:
  1. alpha 9: corpus view UI improvements, bug fixes
Location:
SRUAggregator/trunk
Files:
22 edited

Legend:

Unmodified
Added
Removed
  • SRUAggregator/trunk/aggregator.yml

    r5893 r5900  
    1515# use the simple server factory, run on a single port
    1616server:
    17   applicationContextPath: /
     17  applicationContextPath: /Aggregator-testing/
    1818  type: simple
    1919  connector:
    2020    type: http
    21     port: 8080
    22 
    23 #server:
    24 #  softNofileLimit: 1000
    25 #  hardNofileLimit: 1000
    26 #  applicationConnectors:
    27 #    - type: http
    28 #      port: 8080
    29 #    - type: https
    30 #      port: 8443
    31 #      keyStorePath: example.keystore
    32 #      keyStorePassword: example
    33 #      validateCerts: false
    34 # this requires the npn-boot library on the JVM's boot classpath
    35 #    - type: spdy3
    36 #      port: 8445
    37 #      keyStorePath: example.keystore
    38 #      keyStorePassword: example
    39 #      validateCerts: false
    40 #  adminConnectors:
    41 #    - type: http
    42 #      port: 8081
    43 #    - type: https
    44 #      port: 8444
    45 #      keyStorePath: example.keystore
    46 #      keyStorePassword: example
    47 #      validateCerts: false
     21    port: 4019
    4822
    4923# Logging settings.
  • SRUAggregator/trunk/aggregator_development.yml

    r5893 r5900  
    99  SCAN_TASK_TIME_UNIT: HOURS
    1010
    11   ENDPOINTS_SCAN_TIMEOUT_MS: 15000
     11  ENDPOINTS_SCAN_TIMEOUT_MS: 60000
    1212  ENDPOINTS_SEARCH_TIMEOUT_MS: 5000
    1313  EXECUTOR_SHUTDOWN_TIMEOUT_MS: 100
     
    1515# use the simple server factory, run on a single port
    1616server:
    17   applicationContextPath: /
     17  applicationContextPath: /Aggregator-testing
    1818  type: simple
    1919  connector:
    2020    type: http
    21     port: 8080
    22 
    23 #server:
    24 #  softNofileLimit: 1000
    25 #  hardNofileLimit: 1000
    26 #  applicationConnectors:
    27 #    - type: http
    28 #      port: 8080
    29 #    - type: https
    30 #      port: 8443
    31 #      keyStorePath: example.keystore
    32 #      keyStorePassword: example
    33 #      validateCerts: false
    34 # this requires the npn-boot library on the JVM's boot classpath
    35 #    - type: spdy3
    36 #      port: 8445
    37 #      keyStorePath: example.keystore
    38 #      keyStorePassword: example
    39 #      validateCerts: false
    40 #  adminConnectors:
    41 #    - type: http
    42 #      port: 8081
    43 #    - type: https
    44 #      port: 8444
    45 #      keyStorePath: example.keystore
    46 #      keyStorePassword: example
    47 #      validateCerts: false
     21    port: 4019
    4822
    4923# Logging settings.
  • SRUAggregator/trunk/pom.xml

    r5897 r5900  
    88        <groupId>eu.clarin.sru.fcs</groupId>
    99        <artifactId>Aggregator2</artifactId>
    10         <version>2.0.0-alpha-8</version>
     10        <version>2.0.0-alpha-9</version>
    1111        <name>FCS Aggregator</name>
    1212
     
    6262                        <groupId>eu.clarin.sru</groupId>
    6363                        <artifactId>sru-client</artifactId>
    64                         <version>0.9.5-DEBUG</version>
     64                        <version>0.9.4</version>
    6565                </dependency>
    6666
  • SRUAggregator/trunk/src/main/java/eu/clarin/sru/fcs/aggregator/app/Aggregator.java

    r5897 r5900  
    8080 * @author edima
    8181 *
    82  * TODO: make language show nicely in the UI
    83  *
    84  * TODO: use selected visible corpus for search
    85  *
    86  * TODO: use language selection to hide corpora
    87  *
    88  * TODO: support new spec-compatible centres, see Oliver's mail ...............
     82 * TODO: push footer down
     83 *
     84 * TODO: 1. support new spec-compatible centres, see Oliver's mail
     85 * (use SRUClient's extraResponseData POJOs)
     86 *
     87 * TODO: tri-state for parent collections; search + message implications
    8988 *
    9089 * TODO: disable popups easily
    9190 *
    92  * TODO: zoom into the results from a corpus, allow functionality only for the
    93  * view (search for next set of results)
     91 * TODO: 2. zoom into the results from a corpus, allow functionality only for
     92 * the view (search for next set of results)
    9493 *
    9594 * TODO: Fix activeSearch memory leak (gc searches older than...)
    9695 *
    97  * TODO: Use weblicht with results
     96 * TODO: 3. Use weblicht with results
    9897 *
    9998 * TODO: Export to personal workspace as csv, excel, tcf, plain text
     
    101100 * TODO: Download to personal workspace as csv, excel, tcf, plain text
    102101 *
    103  * TODO: use SRUClient's extraResponseData POJOs
     102 * TODO: 4. use a language guesser ?
    104103 *
    105104 * TODO: websockets
     
    108107 *
    109108 * TODO: show multiple hits on the same result in multiple rows, linked visually
     109 *
     110 * TODO: improve help page text
    110111 *
    111112 */
     
    281282                return model;
    282283        }
    283 
    284 //              filter = new EndpointUrlFilterAllow("lindat");
    285 //              filter = new EndpointUrlFilterDeny("leipzig");
    286 //              filter = new EndpointUrlFilterAllow("leipzig", "mpi.nl");
    287 //              filter = new EndpointUrlFilterAllow("lindat");
    288284}
  • SRUAggregator/trunk/src/main/java/eu/clarin/sru/fcs/aggregator/app/AggregatorConfiguration.java

    r5894 r5900  
    11package eu.clarin.sru.fcs.aggregator.app;
    22
     3import com.fasterxml.jackson.annotation.JsonIgnore;
    34import com.fasterxml.jackson.annotation.JsonProperty;
    45import io.dropwizard.Configuration;
     
    5152                long EXECUTOR_SHUTDOWN_TIMEOUT_MS;
    5253
     54                @JsonIgnore
    5355                public TimeUnit getScanTaskTimeUnit() {
    5456                        return TimeUnit.valueOf(SCAN_TASK_TIME_UNIT);
    5557                }
    5658
     59                @JsonIgnore
    5760                public int getENDPOINTS_SCAN_TIMEOUT_MS() {
    5861                        return ENDPOINTS_SCAN_TIMEOUT_MS;
    5962                }
    6063
     64                @JsonIgnore
    6165                public int getENDPOINTS_SEARCH_TIMEOUT_MS() {
    6266                        return ENDPOINTS_SEARCH_TIMEOUT_MS;
  • SRUAggregator/trunk/src/main/java/eu/clarin/sru/fcs/aggregator/lang/LanguagesISO693_3.java

    r5897 r5900  
    99import java.io.InputStreamReader;
    1010import java.util.HashMap;
    11 import java.util.HashSet;
    1211import java.util.Map;
    1312import java.util.Set;
     
    2221
    2322        private static final org.slf4j.Logger log = LoggerFactory.getLogger(LanguagesISO693_3.class);
    24         public static final String LANGUAGES_FILE_PATH = "/lang/ISO-639-3_20140320.tab";
     23        public static final String LANGUAGES_FILE_PATH = "/lang/iso-639-3_20140320.tab";
    2524        public static final String LANGUAGES_FILE_ENCODING = "UTF-8";
    2625
  • SRUAggregator/trunk/src/main/java/eu/clarin/sru/fcs/aggregator/rest/RestService.java

    r5897 r5900  
    1818import java.net.URI;
    1919import java.util.HashMap;
     20import java.util.HashSet;
    2021import java.util.List;
    2122import java.util.Map;
     
    2324import javax.servlet.ServletContext;
    2425import javax.servlet.http.HttpServletRequest;
     26import javax.ws.rs.Consumes;
    2527import javax.ws.rs.FormParam;
    2628import javax.ws.rs.GET;
     
    3234import javax.ws.rs.core.MediaType;
    3335import javax.ws.rs.core.Response;
     36import org.slf4j.LoggerFactory;
    3437
    3538/**
     
    4043@Path("/")
    4144public class RestService {
     45
     46        private static final org.slf4j.Logger log = LoggerFactory.getLogger(RestService.class);
    4247
    4348        ObjectWriter ow = new ObjectMapper().writerWithDefaultPrettyPrinter();
     
    9297                Map<String, String> languages = new HashMap<String, String>();
    9398                Set<String> codes = Aggregator.getInstance().getCorpora().getLanguages();
     99                log.info("get language codes", codes);
    94100                for (String code : codes) {
    95101                        String name = LanguagesISO693_3.getInstance().nameForCode(code);
     
    110116        public Response postSearch(
    111117                        @FormParam("query") String query,
    112                         @FormParam("corporaIds") Set<String> corporaIds,
    113118                        @FormParam("numberOfResults") Integer numberOfResults,
    114                         @FormParam("language") String language) throws Exception {
     119                        @FormParam("language") String language,
     120                        @FormParam("corporaIds[]") List<String> corporaIds) throws Exception {
    115121                if (query == null || query.isEmpty()) {
    116122                        return Response.status(400).entity("'query' parameter expected").build();
    117123                }
     124//              log.info("POST /search corporaIds: " + corporaIds);
    118125                if (corporaIds == null || corporaIds.isEmpty()) {
    119126                        return Response.status(400).entity("'corporaIds' parameter expected").build();
    120127                }
    121                 List<Corpus> corpora = Aggregator.getInstance().getCorpora().getCorporaByIds(corporaIds);
     128                List<Corpus> corpora = Aggregator.getInstance().getCorpora().getCorporaByIds(new HashSet<String>(corporaIds));
    122129                if (corpora == null || corpora.isEmpty()) {
    123130                        return Response.status(503).entity("No corpora, please wait for the server to finish scanning").build();
  • SRUAggregator/trunk/src/main/java/eu/clarin/sru/fcs/aggregator/scan/Corpora.java

    r5897 r5900  
    11package eu.clarin.sru.fcs.aggregator.scan;
    22
     3import com.fasterxml.jackson.annotation.JsonProperty;
    34import java.util.ArrayList;
    45import java.util.Collections;
    56import java.util.HashMap;
    67import java.util.HashSet;
    7 import java.util.LinkedHashSet;
    88import java.util.List;
    99import java.util.Map;
     
    2222        private static final org.slf4j.Logger log = LoggerFactory.getLogger(Corpora.class);
    2323
    24         private Map<String, Set<Corpus>> langToRootCorpora = new HashMap<String, Set<Corpus>>();
    25         private Map<String, Set<Corpus>> langToTopUniqueCorpora = new HashMap<String, Set<Corpus>>();
     24        @JsonProperty
    2625        private Map<String, Diagnostic> endpointDiagnostics = Collections.synchronizedMap(new HashMap<String, Diagnostic>());
     26        @JsonProperty
    2727        private List<Institution> institutions = Collections.synchronizedList(new ArrayList<Institution>());
     28        @JsonProperty
    2829        private List<Corpus> corpora = new ArrayList<Corpus>();
    2930
     
    5051                if (parentCorpus == null) { //i.e it's a root corpus
    5152                        corpora.add(c);
    52                         for (String lang : c.getLanguages()) {
    53                                 if (!langToRootCorpora.containsKey(lang)) {
    54                                         langToRootCorpora.put(lang, new HashSet<Corpus>());
    55                                 }
    56                                 langToRootCorpora.get(lang).add(c);
    57                         }
    5853                } else {
    5954                        parentCorpus.addCorpus(c);
    60                 }
    61 
    62                 // index top corpora with unique language as for their languages
    63                 if (c.getLanguages().size() == 1
    64                                 && (parentCorpus == null || parentCorpus.getLanguages().size() > 0)) {
    65                         String lang = c.getLanguages().iterator().next();
    66                         if (!langToTopUniqueCorpora.containsKey(lang)) {
    67                                 langToTopUniqueCorpora.put(lang, new LinkedHashSet<Corpus>());
    68                         }
    69                         langToTopUniqueCorpora.get(lang).add(c);
    7055                }
    7156                return true;
     
    7762
    7863        public Set<String> getLanguages() {
    79                 Set<String> languages = new HashSet<String>(this.langToRootCorpora.size());
    80                 languages.addAll(this.langToRootCorpora.keySet());
     64                final Set<String> languages = new HashSet<String>();
     65                visit(corpora, new CallCorpus() {
     66                        @Override
     67                        public void call(Corpus c) {
     68                                languages.addAll(c.getLanguages());
     69                        }
     70                });
    8171                return languages;
    8272        }
    8373
    84         public List<Corpus> getRootCorporaForLang(String lang) {
    85                 List<Corpus> ret = new ArrayList<Corpus>();
    86                 for (Corpus c : corpora) {
    87                         if (c.getLanguages().contains(lang)) {
    88                                 ret.add(c);
     74        public List<Corpus> getCorporaByIds(final Set<String> corporaIds) {
     75                final List<Corpus> found = new ArrayList<Corpus>();
     76                visit(corpora, new CallCorpus() {
     77                        @Override
     78                        public void call(Corpus c) {
     79                                if (corporaIds.contains(c.getId())) {
     80                                        found.add(c);
     81                                }
    8982                        }
    90                 }
    91                 return ret;
    92         }
    93 
    94         public List<Corpus> getTopUniqueLanguageCorpora(String lang) {
    95                 ArrayList<Corpus> corpora = new ArrayList<Corpus>();
    96                 corpora.addAll(langToTopUniqueCorpora.get(lang));
    97                 return corpora;
    98         }
    99 
    100         @Override
    101         public String toString() {
    102                 return "corpora{\n" + "institutions=" + institutions + "\n"
    103                                 + "\n corpora=" + corpora + "\n}";
     83                });
     84                return found;
    10485        }
    10586
     
    130111        }
    131112
    132         public List<Corpus> getCorporaByIds(final Set<String> corporaIds) {
    133                 final List<Corpus> found = new ArrayList<Corpus>();
    134                 visit(corpora, new CallCorpus() {
    135                         @Override
    136                         public void call(Corpus c) {
    137                                 if (corporaIds.contains(c.getId())) {
    138                                         found.add(c);
    139                                 }
    140                         }
    141                 });
    142                 return found;
    143         }
     113        public static interface CallCorpus {
    144114
    145         public static interface CallCorpus {
    146115                void call(Corpus c);
    147116        }
     
    153122                }
    154123        }
     124
     125        @Override
     126        public String toString() {
     127                return "corpora{\n" + "institutions=" + institutions + "\n"
     128                                + "\n corpora=" + corpora + "\n}";
     129        }
     130
    155131}
  • SRUAggregator/trunk/src/main/java/eu/clarin/sru/fcs/aggregator/scan/Corpus.java

    r5897 r5900  
    11package eu.clarin.sru.fcs.aggregator.scan;
    22
    3 import com.fasterxml.jackson.annotation.JsonIgnore;
    43import eu.clarin.sru.fcs.aggregator.lang.LanguagesISO693_3;
    54import java.util.ArrayList;
     
    98import java.util.Set;
    109import java.util.regex.Pattern;
     10import org.slf4j.LoggerFactory;
    1111
    1212/**
     
    1818 */
    1919public class Corpus {
     20        private static final org.slf4j.Logger log = LoggerFactory.getLogger(Corpus.class);
    2021
    2122        public static final String ROOT_HANDLE = "root";
     
    4142        }
    4243
    43         @JsonIgnore
    4444        public String getId() {
    4545                return endpointUrl + "#" + handle;
     46        }
     47
     48        public void setId(String id) { // dumb setter for JsonDeserialization
    4649        }
    4750
     
    112115                } else {
    113116                        String code = LanguagesISO693_3.getInstance().codeForName(language);
    114                         if (code != null) {
    115                                 this.languages.add(code);
    116                         } else {
    117                                 this.languages.add(language);
    118                         }
     117                        this.languages.add(code == null ? language : code);
    119118                }
    120119        }
     
    126125        public void setLandingPage(String landingPage) {
    127126                this.landingPage = landingPage;
     127        }
     128
     129        public String getTitle() {
     130                return title;
     131        }
     132
     133        void setTitle(String title) {
     134                this.title = title;
    128135        }
    129136
  • SRUAggregator/trunk/src/main/java/eu/clarin/sru/fcs/aggregator/scan/Diagnostic.java

    r5893 r5900  
    2828                return context;
    2929        }
     30
    3031        public String getMessage() {
    3132                return message;
     
    5152                this.diagnostic = diagnostic;
    5253        }
     54
     55        @Override
     56        public int hashCode() {
     57                https://primes.utm.edu/lists/small/1000.txt
     58                return uri.hashCode() * 967 + context.hashCode() * 797
     59                                + message.hashCode() * 1669 + diagnostic.hashCode();
     60        }
     61
     62        @Override
     63        public boolean equals(Object obj) {
     64                if (!(obj instanceof Diagnostic)) {
     65                        return false;
     66                }
     67                Diagnostic d = (Diagnostic) obj;
     68                return uri.equals(d.uri) && message.equals(d.message)
     69                                && context.equals(d.context) && diagnostic.equals(d.diagnostic);
     70        }
    5371}
  • SRUAggregator/trunk/src/main/java/eu/clarin/sru/fcs/aggregator/scan/Institution.java

    r5893 r5900  
    5151        }
    5252
     53        @Override
     54        public int hashCode() {
     55                https://primes.utm.edu/lists/small/1000.txt
     56                return name.hashCode() * 2953;
     57        }
     58
     59        @Override
     60        public boolean equals(Object obj) {
     61                if (!(obj instanceof Institution)) {
     62                        return false;
     63                }
     64                Institution i = (Institution) obj;
     65                return i.name.equals(name);
     66        }
    5367}
  • SRUAggregator/trunk/src/main/java/eu/clarin/sru/fcs/aggregator/scan/ScanCrawler.java

    r5894 r5900  
    162162                                return;
    163163                        }
    164                         try {
    165                                 log.error("--> " + request.makeURI(SRUVersion.VERSION_1_2) + " --> ", error);
    166                         } catch (SRUClientException nestedxc) {
    167                                 log.error(" xc on xc ", nestedxc);
    168                         }
     164                        log.error("--> " + request.getBaseURI() + "?" + request.getScanClause() + " --> ", error);
    169165                }
    170166        }
     
    197193        }
    198194
    199         // TODO: ask Oliver to add API support for the extra info in the
    200         // SRU client/server libraries, so that it's not necessary to work
    201         // with DocumentFragment
    202195        private static void addExtraInfo(Corpus c, SRUTerm term) {
    203196                DocumentFragment extraInfo = term.getExtraTermData();
    204                 String enDescription = null;
     197                String enDescription = null, enTitle = null;
    205198                if (extraInfo != null) {
    206199                        NodeList infoNodes = extraInfo.getChildNodes().item(0).getChildNodes();
     
    215208                                                                && languageNodes.item(j).getLocalName().equals("Language")) {
    216209                                                        Element languageNode = (Element) languageNodes.item(j);
    217                                                         String languageText = languageNode.getTextContent().trim();
    218                                                         if (!languageText.isEmpty()) {
     210                                                        String languageText = languageNode.getTextContent();
     211                                                        if (languageText != null && !languageText.trim().isEmpty()) {
    219212                                                                c.addLanguage(languageText.trim());
    220213                                                        }
    221214                                                }
     215                                        }
     216                                } else if (infoNode.getNodeType() == Node.ELEMENT_NODE && infoNode.getLocalName().equals("Title")) {
     217                                        Element element = (Element) infoNode;
     218                                        String descr = infoNode.getTextContent().replaceAll("&lt;br/&gt;", " ");
     219                                        descr = descr.replaceAll("<br/>", " ");
     220                                        descr = descr.replaceAll("[\t\n\r ]+", " ");
     221                                        c.setTitle(descr.trim());
     222                                        //String lang = element.getAttributeNS("http://clarin.eu/fcs/1.0/resource-info", "lang");
     223                                        //System.out.println("ATTRIBUTE LANG: " + lang);
     224                                        if ("en".equals(element.getAttribute("xml:lang"))) {
     225                                                enTitle = c.getDescription();
    222226                                        }
    223227                                } else if (infoNode.getNodeType() == Node.ELEMENT_NODE && infoNode.getLocalName().equals("Description")) {
     
    234238                                }
    235239                        }
     240                        // title in Engish has priority
     241                        if (enTitle != null && !enTitle.isEmpty()) {
     242                                c.setTitle(enTitle);
     243                        }
    236244                        // description in Engish has priority
    237245                        if (enDescription != null && !enDescription.isEmpty()) {
  • SRUAggregator/trunk/src/main/java/eu/clarin/sru/fcs/aggregator/search/Request.java

    r5893 r5900  
    3939        }
    4040
    41         public boolean hasCorpusHandler() {
     41        public boolean hasCorpusHandle() {
    4242                return corpus != null && corpus.getHandle() != null;
    4343        }
  • SRUAggregator/trunk/src/main/java/eu/clarin/sru/fcs/aggregator/search/Search.java

    r5893 r5900  
    6262                searchRequest.setQuery("\"" + searchString + "\"");
    6363                searchRequest.setStartRecord(startRecord);
    64                 if (request.hasCorpusHandler()) {
     64                if (request.hasCorpusHandle()) {
    6565                        searchRequest.setExtraRequestData(SRUCQL.SEARCH_CORPUS_HANDLE_PARAMETER, corpus.getHandle());
    6666                }
  • SRUAggregator/trunk/src/main/resources/assets/base.css

    r5897 r5900  
    176176}
    177177div.corpus-container:hover {
    178         background-color: #F5F5F5;
     178        box-shadow: 0 0 10px rgb(179,216,253) !important;
    179179}
    180180div.corpus-container.dimmed {
    181         font-weight: 300;
    182         opacity: 0.4;
     181        /*font-weight: 300;*/
     182        /*opacity: 0.8;*/
    183183}
    184184
  • SRUAggregator/trunk/src/main/resources/assets/index.html

    r5897 r5900  
    2424                                <a title="about" id="aboutlink">
    2525                                        <span class="glyphicon glyphicon-info-sign"></span>
    26                                         <span>VERSION 2.0.0.α8</span>
     26                                        <span>VERSION 2.0.0.α9</span>
    2727                                </a>
    2828                        </div>
  • SRUAggregator/trunk/src/main/resources/assets/js/corpora.js

    r5897 r5900  
    4646        propTypes: {
    4747                corpora: PT.object.isRequired,
     48                languageMap: PT.object.isRequired,
    4849        },
    4950
     
    6566
    6667        searchCorpus: function(query) {
     68                // sort fn: descending priority, stable sort
     69                var sortFn = function(a, b){
     70                        if (b.priority === a.priority) {
     71                                return b.index - a.index; // stable sort
     72                        }
     73                        return b.priority - a.priority;
     74                };
     75
     76                this.props.corpora.recurse(function(corpus) { corpus.subCorpora.sort(sortFn); });
     77                this.props.corpora.corpora.sort(sortFn);
     78
    6779                query = query.toLowerCase();
    6880                var querytokens = query.split(" ");
     
    8092                // find priority for each corpus
    8193                this.props.corpora.recurse(function(corpus){
     94                        var title = corpus.title ? corpus.title : corpus.displayName;
    8295                        querytokens.forEach(function(qtoken){
    83                                 if (corpus.displayName && corpus.displayName.toLowerCase().indexOf(qtoken) >= 0) {
     96                                if (title && title.toLowerCase().indexOf(qtoken) >= 0) {
    8497                                        corpus.priority ++;
    85                                         // console.log(corpus.displayName, "name ++");
    8698                                }
    8799                                if (corpus.description && corpus.description.toLowerCase().indexOf(qtoken) >= 0) {
    88100                                        corpus.priority ++;
    89                                         // console.log(corpus.displayName, "desc ++");
    90101                                }
    91102                                if (corpus.institution && corpus.institution.name &&
    92103                                                corpus.institution.name.toLowerCase().indexOf(qtoken) >= 0) {
    93104                                        corpus.priority ++;
    94                                         // console.log(corpus.displayName, "inst ++");
    95105                                }
    96106                                if (corpus.languages){
     
    98108                                                if (lang.toLowerCase().indexOf(qtoken) >= 0){
    99109                                                        corpus.priority ++;
    100                                                         // console.log(corpus.displayName, "lang ++");
    101110                                                }
    102111                                        });
    103                                 }
    104                         });
    105                 });
     112                                        corpus.languages.forEach(function(lang){
     113                                                if (this.props.languageMap[lang].toLowerCase().indexOf(qtoken) >= 0){
     114                                                        corpus.priority ++;
     115                                                }
     116                                        }.bind(this));
     117                                }
     118                        }.bind(this));
     119                }.bind(this));
    106120
    107121                // ensure root corpora have nonnull priority
     
    115129                });
    116130
    117                 // order (descending priority)
    118                 var sortFn = function(a, b){
    119                         if (b.priority === a.priority) {
    120                                 return b.index - a.index; // make it a stable sort
    121                         }
    122                         return b.priority - a.priority;
    123                 };
    124 
    125                 this.props.corpora.recurse(function(corpus){
    126                         if (corpus.subCorpora)
    127                                 corpus.subCorpora.sort(sortFn);
     131                this.props.corpora.recurse(function(corpus) { corpus.subCorpora.sort(sortFn); });
     132                this.props.corpora.corpora.sort(sortFn);
     133
     134                // display
     135                this.props.corpora.update();
     136                // console.log("corpus search done", query);
     137        },
     138
     139        getMinMaxPriority: function() {
     140                var min = 1, max = 0;
     141                this.props.corpora.recurse(function(c) {
     142                        if (c.priority < min) min = c.priority;
     143                        if (max < c.priority) max = c.priority;
    128144                });
    129                 this.props.corpora.corpora.sort(sortFn);
    130 
    131                 // display
    132                 this.props.corpora.update();
    133                 // console.log("corpus search done", query);
     145                return [min, max];
    134146        },
    135147
     
    157169        },
    158170
    159         renderCorpus: function(level, corpus) {
     171        renderLanguages: function(languages) {
     172                return languages
     173                                .map(function(l) { return this.props.languageMap[l]; }.bind(this))
     174                                .sort()
     175                                .join(" ");
     176        },
     177
     178        renderCorpus: function(level, minmaxp, corpus) {
     179                if (!corpus.visible) {
     180                        return false;
     181                }
     182
    160183                var indent = {marginLeft:level*50};
    161184                var corpusContainerClass = "corpus-container "+(corpus.priority>0?"":"dimmed");
     185
     186                var hue = 80 * corpus.priority / minmaxp[1];
     187                if (corpus.priority > 0) { hue += 40; }
     188                var color = minmaxp[0] === minmaxp[1] ? 'transparent' : 'hsl('+hue+', 50%, 50%)';
     189                var priorityStyle = {paddingBottom: 4, paddingLeft: 2, borderBottom: '2px solid '+color };
    162190                return  React.createElement("div", {className: corpusContainerClass, key: corpus.displayName},
    163191                                        React.createElement("div", {className: "row corpus"},
    164192                                                React.createElement("div", {className: "col-sm-1 vcenter", onClick: this.toggleSelection.bind(this,corpus)},
    165                                                         this.renderCheckbox(corpus)
     193                                                        React.createElement("div", {style: priorityStyle},
     194                                                                this.renderCheckbox(corpus)
     195                                                        )
    166196                                                ),
    167197                                                React.createElement("div", {className: "col-sm-8 vcenter"},
    168198                                                        React.createElement("div", {style: indent},
    169                                                                 React.createElement("h3", null, corpus.displayName, " :", corpus.priority),
     199                                                                React.createElement("h3", null, corpus.title ? corpus.title : corpus.displayName, " "),
    170200                                                                React.createElement("p", null, corpus.description),
    171201                                                                this.renderExpansion(corpus)
     
    174204                                                React.createElement("div", {className: "col-sm-3 vcenter"},
    175205                                                        React.createElement("p", null, React.createElement("i", {className: "fa fa-institution"}), " ", corpus.institution.name),
    176                                                         React.createElement("p", null, React.createElement("i", {className: "fa fa-language"}), " ", corpus.languages.join(" "))
     206                                                        React.createElement("p", null, React.createElement("i", {className: "fa fa-language"}), " ", this.renderLanguages(corpus.languages)),
     207                                                         corpus.landingPage ?
     208                                                                React.createElement("p", null, React.createElement("i", {className: "fa fa-home"}), " ", React.createElement("a", {href: corpus.landingPage}, corpus.landingPage)) :
     209                                                                false
    177210                                                )
    178211                                        ),
    179                                         corpus.expanded ? corpus.subCorpora.map(this.renderCorpus.bind(this,level+1)) : false
     212                                        corpus.expanded ? corpus.subCorpora.map(this.renderCorpus.bind(this, level+1, minmaxp)) : false
    180213                                );
    181214        },
    182215
    183216        render: function() {
     217                var minmaxp = this.getMinMaxPriority();
    184218                return  React.createElement("div", {style: {margin: "0 30px"}},
    185219                                        React.createElement("div", {className: "row"},
    186                                                 React.createElement("div", {className: "float-right"},
     220                                                React.createElement("div", {className: "float-left inline"},
     221                                                        React.createElement("h3", {style: {marginTop:10}},
     222                                                                this.props.corpora.getSelectedMessage()
     223                                                        )
     224                                                ),
     225                                                React.createElement("div", {className: "float-right inline"},
    187226                                                        React.createElement("div", {className: "inline", style: { marginRight: 20}},
    188227                                                                React.createElement(SearchCorpusBox, {search: this.searchCorpus})
     
    194233                                                )
    195234                                        ),
    196                                         this.props.corpora.corpora.map(this.renderCorpus.bind(this,0))
     235                                        this.props.corpora.corpora.map(this.renderCorpus.bind(this, 0, minmaxp))
    197236                                );
    198237        }
  • SRUAggregator/trunk/src/main/resources/assets/js/corpora.jsx

    r5897 r5900  
    4646        propTypes: {
    4747                corpora: PT.object.isRequired,
     48                languageMap: PT.object.isRequired,
    4849        },
    4950
     
    6566
    6667        searchCorpus: function(query) {
     68                // sort fn: descending priority, stable sort
     69                var sortFn = function(a, b){
     70                        if (b.priority === a.priority) {
     71                                return b.index - a.index; // stable sort
     72                        }
     73                        return b.priority - a.priority;
     74                };
     75
     76                this.props.corpora.recurse(function(corpus) { corpus.subCorpora.sort(sortFn); });
     77                this.props.corpora.corpora.sort(sortFn);
     78
    6779                query = query.toLowerCase();
    6880                var querytokens = query.split(" ");
     
    8092                // find priority for each corpus
    8193                this.props.corpora.recurse(function(corpus){
     94                        var title = corpus.title ? corpus.title : corpus.displayName;
    8295                        querytokens.forEach(function(qtoken){
    83                                 if (corpus.displayName && corpus.displayName.toLowerCase().indexOf(qtoken) >= 0) {
     96                                if (title && title.toLowerCase().indexOf(qtoken) >= 0) {
    8497                                        corpus.priority ++;
    85                                         // console.log(corpus.displayName, "name ++");
    8698                                }
    8799                                if (corpus.description && corpus.description.toLowerCase().indexOf(qtoken) >= 0) {
    88100                                        corpus.priority ++;
    89                                         // console.log(corpus.displayName, "desc ++");
    90101                                }
    91102                                if (corpus.institution && corpus.institution.name &&
    92103                                                corpus.institution.name.toLowerCase().indexOf(qtoken) >= 0) {
    93104                                        corpus.priority ++;
    94                                         // console.log(corpus.displayName, "inst ++");
    95105                                }
    96106                                if (corpus.languages){
     
    98108                                                if (lang.toLowerCase().indexOf(qtoken) >= 0){
    99109                                                        corpus.priority ++;
    100                                                         // console.log(corpus.displayName, "lang ++");
    101110                                                }
    102111                                        });
    103                                 }
    104                         });
    105                 });
     112                                        corpus.languages.forEach(function(lang){
     113                                                if (this.props.languageMap[lang].toLowerCase().indexOf(qtoken) >= 0){
     114                                                        corpus.priority ++;
     115                                                }
     116                                        }.bind(this));
     117                                }
     118                        }.bind(this));
     119                }.bind(this));
    106120
    107121                // ensure root corpora have nonnull priority
     
    115129                });
    116130
    117                 // order (descending priority)
    118                 var sortFn = function(a, b){
    119                         if (b.priority === a.priority) {
    120                                 return b.index - a.index; // make it a stable sort
    121                         }
    122                         return b.priority - a.priority;
    123                 };
    124 
    125                 this.props.corpora.recurse(function(corpus){
    126                         if (corpus.subCorpora)
    127                                 corpus.subCorpora.sort(sortFn);
     131                this.props.corpora.recurse(function(corpus) { corpus.subCorpora.sort(sortFn); });
     132                this.props.corpora.corpora.sort(sortFn);
     133
     134                // display
     135                this.props.corpora.update();
     136                // console.log("corpus search done", query);
     137        },
     138
     139        getMinMaxPriority: function() {
     140                var min = 1, max = 0;
     141                this.props.corpora.recurse(function(c) {
     142                        if (c.priority < min) min = c.priority;
     143                        if (max < c.priority) max = c.priority;
    128144                });
    129                 this.props.corpora.corpora.sort(sortFn);
    130 
    131                 // display
    132                 this.props.corpora.update();
    133                 // console.log("corpus search done", query);
     145                return [min, max];
    134146        },
    135147
     
    157169        },
    158170
    159         renderCorpus: function(level, corpus) {
     171        renderLanguages: function(languages) {
     172                return languages
     173                                .map(function(l) { return this.props.languageMap[l]; }.bind(this))
     174                                .sort()
     175                                .join(" ");
     176        },
     177
     178        renderCorpus: function(level, minmaxp, corpus) {
     179                if (!corpus.visible) {
     180                        return false;
     181                }
     182
    160183                var indent = {marginLeft:level*50};
    161184                var corpusContainerClass = "corpus-container "+(corpus.priority>0?"":"dimmed");
     185
     186                var hue = 80 * corpus.priority / minmaxp[1];
     187                if (corpus.priority > 0) { hue += 40; }
     188                var color = minmaxp[0] === minmaxp[1] ? 'transparent' : 'hsl('+hue+', 50%, 50%)';
     189                var priorityStyle = {paddingBottom: 4, paddingLeft: 2, borderBottom: '2px solid '+color };
    162190                return  <div className={corpusContainerClass} key={corpus.displayName}>
    163191                                        <div className="row corpus">
    164192                                                <div className="col-sm-1 vcenter" onClick={this.toggleSelection.bind(this,corpus)}>
    165                                                         {this.renderCheckbox(corpus)}
     193                                                        <div style={priorityStyle}>
     194                                                                {this.renderCheckbox(corpus)}
     195                                                        </div>
    166196                                                </div>
    167197                                                <div className="col-sm-8 vcenter">
    168198                                                        <div style={indent}>
    169                                                                 <h3>{corpus.displayName} :{corpus.priority}</h3>
     199                                                                <h3>{corpus.title ? corpus.title : corpus.displayName} </h3>
    170200                                                                <p>{corpus.description}</p>
    171201                                                                {this.renderExpansion(corpus)}
     
    174204                                                <div className="col-sm-3 vcenter">
    175205                                                        <p><i className="fa fa-institution"/> {corpus.institution.name}</p>
    176                                                         <p><i className="fa fa-language"/> {corpus.languages.join(" ")}</p>
     206                                                        <p><i className="fa fa-language"/> {this.renderLanguages(corpus.languages)}</p>
     207                                                        { corpus.landingPage ?
     208                                                                <p><i className="fa fa-home"/> <a href={corpus.landingPage}>{corpus.landingPage}</a></p> :
     209                                                                false }
    177210                                                </div>
    178211                                        </div>
    179                                         {corpus.expanded ? corpus.subCorpora.map(this.renderCorpus.bind(this,level+1)) : false}
     212                                        {corpus.expanded ? corpus.subCorpora.map(this.renderCorpus.bind(this, level+1, minmaxp)) : false}
    180213                                </div>;
    181214        },
    182215
    183216        render: function() {
     217                var minmaxp = this.getMinMaxPriority();
    184218                return  <div style={{margin: "0 30px"}}>
    185219                                        <div className="row">
    186                                                 <div className="float-right">
     220                                                <div className="float-left inline">
     221                                                        <h3 style={{marginTop:10}}>
     222                                                                {this.props.corpora.getSelectedMessage()}
     223                                                        </h3>
     224                                                </div>
     225                                                <div className="float-right inline">
    187226                                                        <div className="inline" style={{ marginRight: 20 }} >
    188227                                                                <SearchCorpusBox search={this.searchCorpus}/>
     
    194233                                                </div>
    195234                                        </div>
    196                                         {this.props.corpora.corpora.map(this.renderCorpus.bind(this,0))}
     235                                        {this.props.corpora.corpora.map(this.renderCorpus.bind(this, 0, minmaxp))}
    197236                                </div>;
    198237        }
  • SRUAggregator/trunk/src/main/resources/assets/js/main.js

    r5897 r5900  
    1313var ErrorPane = window.MyReact.ErrorPane;
    1414
     15var multipleLanguageCode = "mul"; // see ISO-693-3
     16
    1517var layers = [
    1618        {
     
    2022                searchLabel: "SAMPA query",
    2123                searchLabelBkColor: "#eef",
    22                 allCollections: "All collections",
    2324        },
    2425        {
     
    2829                searchLabel: "Search text",
    2930                searchLabelBkColor: "#fed",
    30                 allCollections: "All collections",
    3131        },
    3232];
     
    3939        var that = this;
    4040        this.corpora = corpora;
    41         this.recurse(function(corpus, index){
    42                 corpus.visible = true; // selected in the corpus view
     41        this.update = function() {
     42                updateFn(that);
     43        };
     44       
     45        var sortFn = function(x, y) {
     46                var r = x.institution.name.localeCompare(y.institution.name);
     47                if (r !== 0) {
     48                        return r;
     49                }
     50                var t1 = x.title ? x.title : x.displayName;
     51                var t2 = y.title ? y.title : y.displayName;
     52                return t1.toLowerCase().localeCompare(t2.toLowerCase());
     53        };
     54
     55        this.recurse(function(corpus) { corpus.subCorpora.sort(sortFn); });
     56        this.corpora.sort(sortFn);
     57
     58        this.recurse(function(corpus, index) {
     59                corpus.visible = true; // visible in the corpus view
    4360                corpus.selected = true; // selected in the corpus view
    44                 corpus.expanded = false; // expanded in the corpus view
     61                corpus.expanded = false; // not expanded in the corpus view
    4562                corpus.priority = 1; // priority in corpus view
    4663                corpus.index = index;
    4764        });
    48         this.update = function() {
    49                 updateFn(that);
    50         };
    5165}
    5266
    5367Corpora.prototype.recurseCorpus = function(corpus, fn) {
    54         fn(corpus);
    55         if (corpus.subCorpora)
     68        if (false === fn(corpus)) {             
     69                // no recursion
     70        } else {
    5671                this.recurseCorpora(corpus.subCorpora, fn);
     72        }
    5773};
    5874
    5975Corpora.prototype.recurseCorpora = function(corpora, fn) {
    6076        var recfn = function(corpus, index){
    61                 fn(corpus, index);
    62                 corpus.subCorpora.forEach(recfn);
     77                if (false === fn(corpus)) {
     78                        // no recursion
     79                } else {
     80                        corpus.subCorpora.forEach(recfn);
     81                }
    6382        };
    6483        corpora.forEach(recfn);
     
    7594                        languages[lang] = true;
    7695                });
     96                return true;
    7797        });
    7898        return languages;
    7999};
    80100
    81 
    82 var Main = React.createClass({
     101Corpora.prototype.isCorpusVisible = function(corpus, layerId, languageCode) {
     102        if (layerId !== "text") {
     103                return false;
     104        }
     105        // yes for any language
     106        if (languageCode === multipleLanguageCode) {
     107                return true;
     108        }
     109        // yes if the corpus is in only that language
     110        if (corpus.languages && corpus.languages.length === 1 && corpus.languages[0] === languageCode) {
     111                return true;
     112        }       
     113
     114        // ? yes if the corpus also contains that language
     115        if (corpus.languages && corpus.languages.indexOf(languageCode) >=0) {
     116                return true;
     117        }
     118
     119        // ? yes if the corpus has no language
     120        // if (!corpus.languages || corpus.languages.length === 0) {
     121        //      return true;
     122        // }
     123        return false;
     124};
     125
     126Corpora.prototype.setVisibility = function(layerId, languageCode) {
     127        // top level
     128        this.corpora.forEach(function(corpus) {
     129                corpus.visible = this.isCorpusVisible(corpus, layerId, languageCode);
     130                this.recurseCorpora(corpus.subCorpora, function(c) { c.visible = corpus.visible; });
     131        }.bind(this));
     132};
     133
     134Corpora.prototype.getSelectedIds = function() {
     135        var ids = [];
     136        this.recurse(function(corpus) {
     137                if (corpus.visible && corpus.selected) {
     138                        ids.push(corpus.id);
     139                        return false; // top-most collection in tree, don't delve deeper
     140                }
     141                return true;
     142        });
     143
     144        // console.log("ids: ", ids.length, {ids:ids});
     145        return ids;
     146};
     147
     148Corpora.prototype.getSelectedMessage = function() {
     149        var selected = this.getSelectedIds().length;
     150        if (this.corpora.length === selected) {
     151                return "All available collections";
     152        } else if (selected === 1) {
     153                return "1 selected collection";
     154        }
     155        return selected+" selected collections";
     156};
     157
     158
     159var Main = React.createClass({displayName: 'Main',
    83160        getInitialState: function () {
    84161                return {
     
    160237
    161238        renderAggregator: function() {
    162                 return <AggregatorPage ajax={this.ajax} corpora={this.state.corpora} languageMap={this.state.languageMap} />;
     239                return React.createElement(AggregatorPage, {ajax: this.ajax, corpora: this.state.corpora, languageMap: this.state.languageMap});
    163240        },
    164241
    165242        renderStatistics: function() {
    166                 return <StatisticsPage ajax={this.ajax} />;
     243                return React.createElement(StatisticsPage, {ajax: this.ajax});
    167244        },
    168245
    169246        renderHelp: function() {
    170                 return <HelpPage />;
     247                return React.createElement(HelpPage, null);
    171248        },
    172249
     
    182259                var classname = "navbar-collapse collapse " + (this.state.navbarCollapse?"in":"");
    183260                return (
    184                         <div className={classname}>
    185                                 <ul className="nav navbar-nav">
    186                                         <li className={this.state.navbarPageFn === this.renderAggregator ? "active":""}>
    187                                                 <a className="link" tabIndex="-1"
    188                                                         onClick={this.setNavbarPageFn.bind(this, this.renderAggregator)}>Aggregator</a>
    189                                         </li>
    190                                         <li className={this.state.navbarPageFn === this.renderStatistics ? "active":""}>
    191                                                 <a className="link" tabIndex="-1"
    192                                                         onClick={this.setNavbarPageFn.bind(this, this.renderStatistics)}>Statistics</a>
    193                                         </li>
    194                                         <li className={this.state.navbarPageFn === this.renderHelp ? "active":""}>
    195                                                 <a className="link" tabIndex="-1"
    196                                                         onClick={this.setNavbarPageFn.bind(this, this.renderHelp)}>Help</a>
    197                                         </li>
    198                                 </ul>
    199                                 <ul id="CLARIN_header_right" className="nav navbar-nav navbar-right">
    200                                         <li className="unauthenticated">
    201                                                 <a href="login" tabIndex="-1"><span className="glyphicon glyphicon-log-in"></span> LOGIN</a>
    202                                         </li>
    203                                 </ul>
    204                         </div>
     261                        React.createElement("div", {className: classname},
     262                                React.createElement("ul", {className: "nav navbar-nav"},
     263                                        React.createElement("li", {className: this.state.navbarPageFn === this.renderAggregator ? "active":""},
     264                                                React.createElement("a", {className: "link", tabIndex: "-1",
     265                                                        onClick: this.setNavbarPageFn.bind(this, this.renderAggregator)}, "Aggregator")
     266                                        ),
     267                                        React.createElement("li", {className: this.state.navbarPageFn === this.renderStatistics ? "active":""},
     268                                                React.createElement("a", {className: "link", tabIndex: "-1",
     269                                                        onClick: this.setNavbarPageFn.bind(this, this.renderStatistics)}, "Statistics")
     270                                        ),
     271                                        React.createElement("li", {className: this.state.navbarPageFn === this.renderHelp ? "active":""},
     272                                                React.createElement("a", {className: "link", tabIndex: "-1",
     273                                                        onClick: this.setNavbarPageFn.bind(this, this.renderHelp)}, "Help")
     274                                        )
     275                                ),
     276                                React.createElement("ul", {id: "CLARIN_header_right", className: "nav navbar-nav navbar-right"},
     277                                        React.createElement("li", {className: "unauthenticated"},
     278                                                React.createElement("a", {href: "login", tabIndex: "-1"}, React.createElement("span", {className: "glyphicon glyphicon-log-in"}), " LOGIN")
     279                                        )
     280                                )
     281                        )
    205282                );
    206283        },
     
    208285        render: function() {
    209286                return  (
    210                         <div>
    211                                 <div className="container">
    212                                         <div className="beta-tag">
    213                                                 <span>BETA</span>
    214                                         </div>
    215                                 </div>
     287                        React.createElement("div", null,
     288                                React.createElement("div", {className: "container"},
     289                                        React.createElement("div", {className: "beta-tag"},
     290                                                React.createElement("span", null, "BETA")
     291                                        )
     292                                ),
    216293                       
    217                                 <div className="navbar navbar-default navbar-static-top" role="navigation">
    218                                         <div className="container">
    219                                                 <div className="navbar-header">
    220                                                         <button type="button" className="navbar-toggle" onClick={this.toggleCollapse}>
    221                                                                 <span className="sr-only">Toggle navigation</span>
    222                                                                 <span className="icon-bar"></span>
    223                                                                 <span className="icon-bar"></span>
    224                                                                 <span className="icon-bar"></span>
    225                                                         </button>
    226                                                         <a className="navbar-brand" href="#" tabIndex="-1"><header>Federated Content Search</header></a>
    227                                                 </div>
    228                                                 {this.renderCollapsible()}
    229                                         </div>
    230                                 </div>
    231 
    232                                 <ErrorPane errorMessages={this.state.errorMessages} />
    233 
    234                                 <div id="push">
    235                                         <div className="container">
    236                                                 {this.state.navbarPageFn()}
    237                                         </div>
    238                                         <div className="top-gap" />
    239                                 </div>
    240                         </div>
     294                                React.createElement("div", {className: "navbar navbar-default navbar-static-top", role: "navigation"},
     295                                        React.createElement("div", {className: "container"},
     296                                                React.createElement("div", {className: "navbar-header"},
     297                                                        React.createElement("button", {type: "button", className: "navbar-toggle", onClick: this.toggleCollapse},
     298                                                                React.createElement("span", {className: "sr-only"}, "Toggle navigation"),
     299                                                                React.createElement("span", {className: "icon-bar"}),
     300                                                                React.createElement("span", {className: "icon-bar"}),
     301                                                                React.createElement("span", {className: "icon-bar"})
     302                                                        ),
     303                                                        React.createElement("a", {className: "navbar-brand", href: "#", tabIndex: "-1"}, React.createElement("header", null, "Federated Content Search"))
     304                                                ),
     305                                                this.renderCollapsible()
     306                                        )
     307                                ),
     308
     309                                React.createElement(ErrorPane, {errorMessages: this.state.errorMessages}),
     310
     311                                React.createElement("div", {id: "push"},
     312                                        React.createElement("div", {className: "container"},
     313                                                this.state.navbarPageFn()
     314                                        ),
     315                                        React.createElement("div", {className: "top-gap"})
     316                                )
     317                        )
    241318                );
    242319        }
    243320});
    244321
    245 var AggregatorPage = React.createClass({
     322var AggregatorPage = React.createClass({displayName: 'AggregatorPage',
    246323        propTypes: {
    247324                ajax: PT.func.isRequired,
     
    256333                results: [],
    257334        },
    258         anyLanguage: ["ANY", "Any Language"],
     335        anyLanguage: [multipleLanguageCode, "Any Language"],
    259336
    260337        getInitialState: function () {
     
    270347
    271348        search: function(query) {
    272                 console.log(query);
     349                // console.log(query);
    273350                if (!query) {
    274351                        this.setState({ hits: this.nohits, searchId: null });
     
    280357                        data: {
    281358                                layer: this.state.searchLayerId,
     359                                language: this.state.language[0],
    282360                                query: query,
    283361                                numberOfResults: this.state.numberOfResults,
     362                                corporaIds: this.props.corpora.getSelectedIds(),
    284363                        },
    285364                        success: function(searchId, textStatus, jqXHR) {
    286                                 console.log("search ["+query+"] ok: ", searchId, jqXHR);
     365                                // console.log("search ["+query+"] ok: ", searchId, jqXHR);
    287366                                this.setState({searchId : searchId});
    288367                                this.timeout = 250;
     
    309388                                }
    310389                                this.setState({hits:json});
    311                                 console.log("hits:", json);
     390                                // console.log("hits:", json);
    312391                        }.bind(this),
    313392                });
    314393        },
    315394
    316         setAState: function(id, value) {
    317                 var v = {};
    318                 v[id] = value;
    319                 this.setState(v);
     395        setLanguage: function(languageObj) {
     396                this.props.corpora.setVisibility(this.state.searchLayerId, languageObj[0]);
     397                this.setState({language: languageObj});
     398                this.props.corpora.update();
     399        },
     400
     401        setLayer: function(layerId) {
     402                this.props.corpora.setVisibility(layerId, this.state.language[0]);
     403                this.props.corpora.update();
     404                this.setState({searchLayerId: layerId});
    320405        },
    321406
     
    343428                var layer = layerMap[this.state.searchLayerId];
    344429                return  (
    345                         <div className="top-gap">
    346                                 <div className="row">
    347                                         <div className="aligncenter" style={{marginLeft:16, marginRight:16}}>
    348                                                 <div className="input-group">
    349                                                         <span className="input-group-addon" style={{backgroundColor:layer.searchLabelBkColor}}>
    350                                                                 {layer.searchLabel}
    351                                                         </span>
    352 
    353                                                         <SearchBox search={this.search} placeholder={layer.searchPlaceholder} />
    354                                                         <div className="input-group-btn">
    355                                                                 <button className="btn btn-default input-lg" type="button" onClick={this.search}>
    356                                                                         <i className="glyphicon glyphicon-search"></i>
    357                                                                 </button>
    358                                                         </div>
    359                                                 </div>
    360                                         </div>
    361                                 </div>
    362 
    363                                 <div className="wel" style={{marginTop:20}}>
    364                                         <div className="aligncenter" >
    365                                                 <form className="form-inline" role="form">
    366 
    367                                                         <div className="input-group" style={{marginRight:10}}>
    368                                                                 <span className="input-group-addon nobkg">Search in</span>
    369                                                                         <button type="button" className="btn btn-default" onClick={this.toggleCorpusSelection}>
    370                                                                                 {layer.allCollections} <span className="caret"/>
    371                                                                         </button>
    372                                                         </div>
    373 
    374                                                         <div className="input-group" style={{marginRight:10}}>
     430                        React.createElement("div", {className: "top-gap"},
     431                                React.createElement("div", {className: "row"},
     432                                        React.createElement("div", {className: "aligncenter", style: {marginLeft:16, marginRight:16}},
     433                                                React.createElement("div", {className: "input-group"},
     434                                                        React.createElement("span", {className: "input-group-addon", style: {backgroundColor:layer.searchLabelBkColor}},
     435                                                                layer.searchLabel
     436                                                        ),
     437
     438                                                        React.createElement(SearchBox, {search: this.search, placeholder: layer.searchPlaceholder}),
     439                                                        React.createElement("div", {className: "input-group-btn"},
     440                                                                React.createElement("button", {className: "btn btn-default input-lg", type: "button", onClick: this.search},
     441                                                                        React.createElement("i", {className: "glyphicon glyphicon-search"})
     442                                                                )
     443                                                        )
     444                                                )
     445                                        )
     446                                ),
     447
     448                                React.createElement("div", {className: "wel", style: {marginTop:20}},
     449                                        React.createElement("div", {className: "aligncenter"},
     450                                                React.createElement("form", {className: "form-inline", role: "form"},
     451
     452                                                        React.createElement("div", {className: "input-group", style: {marginRight:10}},
     453                                                                React.createElement("span", {className: "input-group-addon nobkg"}, "Search in"),
     454                                                                        React.createElement("button", {type: "button", className: "btn btn-default", onClick: this.toggleCorpusSelection},
     455                                                                                this.props.corpora.getSelectedMessage(), " ", React.createElement("span", {className: "caret"})
     456                                                                        )
     457                                                        ),
     458
     459                                                        React.createElement("div", {className: "input-group", style: {marginRight:10}},
    375460                                                               
    376                                                                 <span className="input-group-addon nobkg" >of</span>
     461                                                                React.createElement("span", {className: "input-group-addon nobkg"}, "of"),
    377462                                                               
    378                                                                 <div className="input-group-btn">
    379                                                                         <button className="form-control btn btn-default"
    380                                                                                         aria-expanded="false" data-toggle="dropdown">
    381                                                                                 {this.state.language[1]} <span className="caret"/>
    382                                                                         </button>
    383                                                                         <ul ref="languageDropdownMenu" className="dropdown-menu">
    384                                                                                 <li key={this.anyLanguage[0]}> <a tabIndex="-1" href="#"
    385                                                                                                 onClick={this.setAState.bind(this, "language", this.anyLanguage)}>
    386                                                                                         {this.anyLanguage[1]}</a>
    387                                                                                 </li>
    388                                                                                 {       _.pairs(this.props.languageMap).map(function(l) {
     463                                                                React.createElement("div", {className: "input-group-btn"},
     464                                                                        React.createElement("button", {className: "form-control btn btn-default",
     465                                                                                        'aria-expanded': "false", 'data-toggle': "dropdown"},
     466                                                                                this.state.language[1], " ", React.createElement("span", {className: "caret"})
     467                                                                        ),
     468                                                                        React.createElement("ul", {ref: "languageDropdownMenu", className: "dropdown-menu"},
     469                                                                                React.createElement("li", {key: this.anyLanguage[0]}, " ", React.createElement("a", {tabIndex: "-1", href: "#",
     470                                                                                                onClick: this.setLanguage.bind(this, this.anyLanguage)},
     471                                                                                        this.anyLanguage[1])
     472                                                                                ),
     473                                                                                        _.pairs(this.props.languageMap).sort(function(l1, l2){
     474                                                                                                return l1[1].localeCompare(l2[1]);
     475                                                                                        }).map(function(l) {
    389476                                                                                                var desc = l[1] + " [" + l[0] + "]";
    390                                                                                                 return <li key={l[0]}> <a tabIndex="-1" href="#"
    391                                                                                                         onClick={this.setAState.bind(this, "language", l)}>{desc}</a></li>;
     477                                                                                                return React.createElement("li", {key: l[0]}, " ", React.createElement("a", {tabIndex: "-1", href: "#",
     478                                                                                                        onClick: this.setLanguage.bind(this, l)}, desc));
    392479                                                                                        }.bind(this))
    393                                                                                 }
    394                                                                         </ul>
    395                                                                 </div>
    396 
    397                                                                 <div className="input-group-btn">
    398                                                                         <ul ref="layerDropdownMenu" className="dropdown-menu">
    399                                                                                 {       layers.map(function(l) {
    400                                                                                                 return <li key={l.id}> <a tabIndex="-1" href="#"
    401                                                                                                         onClick={this.setAState.bind(this, "searchLayerId", l.id)}> {l.name} </a></li>;
     480                                                                               
     481                                                                        )
     482                                                                ),
     483
     484                                                                React.createElement("div", {className: "input-group-btn"},
     485                                                                        React.createElement("ul", {ref: "layerDropdownMenu", className: "dropdown-menu"},
     486                                                                                        layers.map(function(l) {
     487                                                                                                return React.createElement("li", {key: l.id}, " ", React.createElement("a", {tabIndex: "-1", href: "#",
     488                                                                                                        onClick: this.setLayer.bind(this, l.id)}, " ", l.name, " "));
    402489                                                                                        }.bind(this))
    403                                                                                 }
    404                                                                         </ul>                                                           
    405                                                                         <button className="form-control btn btn-default"
    406                                                                                         aria-expanded="false" data-toggle="dropdown" >
    407                                                                                 {layer.name} <span className="caret"/>
    408                                                                         </button>
    409                                                                 </div>
    410 
    411                                                         </div>
    412 
    413                                                         <div className="input-group">
    414                                                                 <span className="input-group-addon nobkg">and show up to</span>
    415                                                                 <div className="input-group-btn">
    416                                                                         <input type="number" className="form-control input" min="10" max="250" step="5"
    417                                                                                 onChange={this.setNumberOfResults} value={this.state.numberOfResults}
    418                                                                                 onKeyPress={this.stop}/>
    419                                                                 </div>
    420                                                                 <span className="input-group-addon nobkg">hits</span>
    421                                                         </div>
    422                                                 </form>
    423                                         </div>
    424                                 </div>
    425 
    426                     <Modal ref="corporaModal" title="Collections">
    427                                         <CorpusView ref="corpusView" corpora={this.props.corpora} />
    428                     </Modal>
    429 
    430                                 <div className="top-gap">
    431                                         <Results requests={this.state.hits.requests} results={this.state.hits.results} />
    432                                 </div>
    433                         </div>
     490                                                                               
     491                                                                        ),                                                              
     492                                                                        React.createElement("button", {className: "form-control btn btn-default",
     493                                                                                        'aria-expanded': "false", 'data-toggle': "dropdown"},
     494                                                                                layer.name, " ", React.createElement("span", {className: "caret"})
     495                                                                        )
     496                                                                )
     497
     498                                                        ),
     499
     500                                                        React.createElement("div", {className: "input-group"},
     501                                                                React.createElement("span", {className: "input-group-addon nobkg"}, "and show up to"),
     502                                                                React.createElement("div", {className: "input-group-btn"},
     503                                                                        React.createElement("input", {type: "number", className: "form-control input", min: "10", max: "250", step: "5",
     504                                                                                onChange: this.setNumberOfResults, value: this.state.numberOfResults,
     505                                                                                onKeyPress: this.stop})
     506                                                                ),
     507                                                                React.createElement("span", {className: "input-group-addon nobkg"}, "hits")
     508                                                        )
     509                                                )
     510                                        )
     511                                ),
     512
     513                    React.createElement(Modal, {ref: "corporaModal", title: "Collections"},
     514                                        React.createElement(CorpusView, {corpora: this.props.corpora, languageMap: this.props.languageMap})
     515                    ),
     516
     517                                React.createElement("div", {className: "top-gap"},
     518                                        React.createElement(Results, {requests: this.state.hits.requests, results: this.state.hits.results})
     519                                )
     520                        )
    434521                        );
    435522        },
     
    439526});
    440527
    441 var StatisticsPage = React.createClass({
     528var StatisticsPage = React.createClass({displayName: 'StatisticsPage',
    442529        propTypes: {
    443530                ajax: PT.func.isRequired,
     
    469556
    470557        listItem: function(it) {
    471                 return <li>     {it[0]}:
    472                                         { typeof(it[1]) === "object" ?
    473                                                 <ul>{_.pairs(it[1]).map(this.listItem)}</ul> :
     558                return React.createElement("li", null, " ", it[0], ":",
     559                                        typeof(it[1]) === "object" ?
     560                                                React.createElement("ul", null, _.pairs(it[1]).map(this.listItem)) :
    474561                                                it[1]
    475                                         }
    476                                 </li>;
     562                                       
     563                                );
    477564        },
    478565
     
    506593
    507594        renderStatistics: function(stats) {
    508                 return <ul>{_.pairs(stats).map(this.listItem)}</ul>;
     595                return React.createElement("ul", null, _.pairs(stats).map(this.listItem));
    509596        },
    510597
    511598        render: function() {
    512599                return  (
    513                         <div>
    514                                 <div className="top-gap">
    515                                         <h1>Statistics</h1>
    516                                         <h2>Last Scan</h2>
    517                                         {this.renderStatistics(this.state.lastScanStats)}
    518                                         <h2>Search</h2>
    519                                         {this.renderStatistics(this.state.searchStats)}
    520                                 </div>
    521                         </div>
     600                        React.createElement("div", null,
     601                                React.createElement("div", {className: "top-gap"},
     602                                        React.createElement("h1", null, "Statistics"),
     603                                        React.createElement("h2", null, "Last Scan"),
     604                                        this.renderStatistics(this.state.lastScanStats),
     605                                        React.createElement("h2", null, "Search"),
     606                                        this.renderStatistics(this.state.searchStats)
     607                                )
     608                        )
    522609                        );
    523610        },
    524611});
    525612
    526 var HelpPage = React.createClass({
     613var HelpPage = React.createClass({displayName: 'HelpPage',
    527614        openHelpDesk: function() {
    528615                window.open('http://support.clarin-d.de/mail/form.php?queue=Aggregator',
     
    532619        render: function() {
    533620                return  (
    534                         <div>
    535                                 <div className="top-gap">
    536                                         <h3>Performing search in FCS corpora</h3>
    537                                         <p>To perform simple keyword search in all CLARIN-D Federated Content Search centers
    538                                         and their corpora, go to the search field at the top of the page,
    539                                         enter your query, and click 'search' button or press the 'Enter' key.</p>
     621                        React.createElement("div", null,
     622                                React.createElement("div", {className: "top-gap"},
     623                                        React.createElement("h3", null, "Performing search in FCS corpora"),
     624                                        React.createElement("p", null, "To perform simple keyword search in all CLARIN-D Federated Content Search centers" + ' ' +
     625                                        "and their corpora, go to the search field at the top of the page," + ' ' +
     626                                        "enter your query, and click 'search' button or press the 'Enter' key."),
    540627                                       
    541                                         <h3>Search Options - adjusting search criteria</h3>
    542                                         <p>To select specific corpora based on their name or language and to specify
    543                                         number of search results (hits) per corpus per page, click on the 'Search options'
    544                                         link. Here, you can filter resources based on the language, select specific resources,
    545                                         set the maximum number of hits.</p>
    546 
    547                                         <h3>Search Results - inspecting search results</h3>
    548                                         <p>When the search starts, the 'Search results' page is displayed
    549                                         and its content starts to get filled with the corpora responses.
    550                                         To save or process the displayed search result, in the 'Search results' page,
    551                                         go to the menu and select either 'Export to Personal Workspace',
    552                                         'Download' or 'Use WebLicht' menu item. This menu appears only after
    553                                         all the results on the page have been loaded. To get the next hits from each corpus,
    554                                         click the 'next' arrow at the bottom of 'Search results' page.</p>
    555 
    556 
    557                                         <h3>More help</h3>
    558                                         <p>More detailed information on using FCS Aggregator is available
    559                                         at the Aggegator wiki page. If you still cannot find an answer to your question,
    560                                         or if want to send a feedback, you can write to Clarin-D helpdesk: </p>
    561                                         <button type="button" className="btn btn-default btn-lg" onClick={this.openHelpDesk} >
    562                                                 <span className="glyphicon glyphicon-question-sign" aria-hidden="true"></span>
    563                                                 &nbsp;HelpDesk
    564                                         </button>                                       
    565                                 </div>
    566                         </div>
     628                                        React.createElement("h3", null, "Search Options - adjusting search criteria"),
     629                                        React.createElement("p", null, "To select specific corpora based on their name or language and to specify" + ' ' +
     630                                        "number of search results (hits) per corpus per page, click on the 'Search options'" + ' ' +
     631                                        "link. Here, you can filter resources based on the language, select specific resources," + ' ' +
     632                                        "set the maximum number of hits."),
     633
     634                                        React.createElement("h3", null, "Search Results - inspecting search results"),
     635                                        React.createElement("p", null, "When the search starts, the 'Search results' page is displayed" + ' ' +
     636                                        "and its content starts to get filled with the corpora responses." + ' ' +
     637                                        "To save or process the displayed search result, in the 'Search results' page," + ' ' +
     638                                        "go to the menu and select either 'Export to Personal Workspace'," + ' ' +
     639                                        "'Download' or 'Use WebLicht' menu item. This menu appears only after" + ' ' +
     640                                        "all the results on the page have been loaded. To get the next hits from each corpus," + ' ' +
     641                                        "click the 'next' arrow at the bottom of 'Search results' page."),
     642
     643
     644                                        React.createElement("h3", null, "More help"),
     645                                        React.createElement("p", null, "More detailed information on using FCS Aggregator is available" + ' ' +
     646                                        "at the Aggegator wiki page. If you still cannot find an answer to your question," + ' ' +
     647                                        "or if want to send a feedback, you can write to Clarin-D helpdesk: "),
     648                                        React.createElement("button", {type: "button", className: "btn btn-default btn-lg", onClick: this.openHelpDesk},
     649                                                React.createElement("span", {className: "glyphicon glyphicon-question-sign", 'aria-hidden': "true"}),
     650                                                " HelpDesk"
     651                                        )                                       
     652                                )
     653                        )
    567654                );
    568655        }
     
    592679
    593680
    594 React.render(<Main />, document.getElementById('reactMain') );
     681React.render(React.createElement(Main, null), document.getElementById('reactMain') );
    595682})();
  • SRUAggregator/trunk/src/main/resources/assets/js/main.jsx

    r5897 r5900  
    1313var ErrorPane = window.MyReact.ErrorPane;
    1414
     15var multipleLanguageCode = "mul"; // see ISO-693-3
     16
    1517var layers = [
    1618        {
     
    2022                searchLabel: "SAMPA query",
    2123                searchLabelBkColor: "#eef",
    22                 allCollections: "All collections",
    2324        },
    2425        {
     
    2829                searchLabel: "Search text",
    2930                searchLabelBkColor: "#fed",
    30                 allCollections: "All collections",
    3131        },
    3232];
     
    3939        var that = this;
    4040        this.corpora = corpora;
    41         this.recurse(function(corpus, index){
    42                 corpus.visible = true; // selected in the corpus view
     41        this.update = function() {
     42                updateFn(that);
     43        };
     44       
     45        var sortFn = function(x, y) {
     46                var r = x.institution.name.localeCompare(y.institution.name);
     47                if (r !== 0) {
     48                        return r;
     49                }
     50                var t1 = x.title ? x.title : x.displayName;
     51                var t2 = y.title ? y.title : y.displayName;
     52                return t1.toLowerCase().localeCompare(t2.toLowerCase());
     53        };
     54
     55        this.recurse(function(corpus) { corpus.subCorpora.sort(sortFn); });
     56        this.corpora.sort(sortFn);
     57
     58        this.recurse(function(corpus, index) {
     59                corpus.visible = true; // visible in the corpus view
    4360                corpus.selected = true; // selected in the corpus view
    44                 corpus.expanded = false; // expanded in the corpus view
     61                corpus.expanded = false; // not expanded in the corpus view
    4562                corpus.priority = 1; // priority in corpus view
    4663                corpus.index = index;
    4764        });
    48         this.update = function() {
    49                 updateFn(that);
    50         };
    5165}
    5266
    5367Corpora.prototype.recurseCorpus = function(corpus, fn) {
    54         fn(corpus);
    55         if (corpus.subCorpora)
     68        if (false === fn(corpus)) {             
     69                // no recursion
     70        } else {
    5671                this.recurseCorpora(corpus.subCorpora, fn);
     72        }
    5773};
    5874
    5975Corpora.prototype.recurseCorpora = function(corpora, fn) {
    6076        var recfn = function(corpus, index){
    61                 fn(corpus, index);
    62                 corpus.subCorpora.forEach(recfn);
     77                if (false === fn(corpus)) {
     78                        // no recursion
     79                } else {
     80                        corpus.subCorpora.forEach(recfn);
     81                }
    6382        };
    6483        corpora.forEach(recfn);
     
    7594                        languages[lang] = true;
    7695                });
     96                return true;
    7797        });
    7898        return languages;
     99};
     100
     101Corpora.prototype.isCorpusVisible = function(corpus, layerId, languageCode) {
     102        if (layerId !== "text") {
     103                return false;
     104        }
     105        // yes for any language
     106        if (languageCode === multipleLanguageCode) {
     107                return true;
     108        }
     109        // yes if the corpus is in only that language
     110        if (corpus.languages && corpus.languages.length === 1 && corpus.languages[0] === languageCode) {
     111                return true;
     112        }       
     113
     114        // ? yes if the corpus also contains that language
     115        if (corpus.languages && corpus.languages.indexOf(languageCode) >=0) {
     116                return true;
     117        }
     118
     119        // ? yes if the corpus has no language
     120        // if (!corpus.languages || corpus.languages.length === 0) {
     121        //      return true;
     122        // }
     123        return false;
     124};
     125
     126Corpora.prototype.setVisibility = function(layerId, languageCode) {
     127        // top level
     128        this.corpora.forEach(function(corpus) {
     129                corpus.visible = this.isCorpusVisible(corpus, layerId, languageCode);
     130                this.recurseCorpora(corpus.subCorpora, function(c) { c.visible = corpus.visible; });
     131        }.bind(this));
     132};
     133
     134Corpora.prototype.getSelectedIds = function() {
     135        var ids = [];
     136        this.recurse(function(corpus) {
     137                if (corpus.visible && corpus.selected) {
     138                        ids.push(corpus.id);
     139                        return false; // top-most collection in tree, don't delve deeper
     140                }
     141                return true;
     142        });
     143
     144        // console.log("ids: ", ids.length, {ids:ids});
     145        return ids;
     146};
     147
     148Corpora.prototype.getSelectedMessage = function() {
     149        var selected = this.getSelectedIds().length;
     150        if (this.corpora.length === selected) {
     151                return "All available collections";
     152        } else if (selected === 1) {
     153                return "1 selected collection";
     154        }
     155        return selected+" selected collections";
    79156};
    80157
     
    256333                results: [],
    257334        },
    258         anyLanguage: ["ANY", "Any Language"],
     335        anyLanguage: [multipleLanguageCode, "Any Language"],
    259336
    260337        getInitialState: function () {
     
    270347
    271348        search: function(query) {
    272                 console.log(query);
     349                // console.log(query);
    273350                if (!query) {
    274351                        this.setState({ hits: this.nohits, searchId: null });
     
    280357                        data: {
    281358                                layer: this.state.searchLayerId,
     359                                language: this.state.language[0],
    282360                                query: query,
    283361                                numberOfResults: this.state.numberOfResults,
     362                                corporaIds: this.props.corpora.getSelectedIds(),
    284363                        },
    285364                        success: function(searchId, textStatus, jqXHR) {
    286                                 console.log("search ["+query+"] ok: ", searchId, jqXHR);
     365                                // console.log("search ["+query+"] ok: ", searchId, jqXHR);
    287366                                this.setState({searchId : searchId});
    288367                                this.timeout = 250;
     
    309388                                }
    310389                                this.setState({hits:json});
    311                                 console.log("hits:", json);
     390                                // console.log("hits:", json);
    312391                        }.bind(this),
    313392                });
    314393        },
    315394
    316         setAState: function(id, value) {
    317                 var v = {};
    318                 v[id] = value;
    319                 this.setState(v);
     395        setLanguage: function(languageObj) {
     396                this.props.corpora.setVisibility(this.state.searchLayerId, languageObj[0]);
     397                this.setState({language: languageObj});
     398                this.props.corpora.update();
     399        },
     400
     401        setLayer: function(layerId) {
     402                this.props.corpora.setVisibility(layerId, this.state.language[0]);
     403                this.props.corpora.update();
     404                this.setState({searchLayerId: layerId});
    320405        },
    321406
     
    368453                                                                <span className="input-group-addon nobkg">Search in</span>
    369454                                                                        <button type="button" className="btn btn-default" onClick={this.toggleCorpusSelection}>
    370                                                                                 {layer.allCollections} <span className="caret"/>
     455                                                                                {this.props.corpora.getSelectedMessage()} <span className="caret"/>
    371456                                                                        </button>
    372457                                                        </div>
     
    383468                                                                        <ul ref="languageDropdownMenu" className="dropdown-menu">
    384469                                                                                <li key={this.anyLanguage[0]}> <a tabIndex="-1" href="#"
    385                                                                                                 onClick={this.setAState.bind(this, "language", this.anyLanguage)}>
     470                                                                                                onClick={this.setLanguage.bind(this, this.anyLanguage)}>
    386471                                                                                        {this.anyLanguage[1]}</a>
    387472                                                                                </li>
    388                                                                                 {       _.pairs(this.props.languageMap).map(function(l) {
     473                                                                                {       _.pairs(this.props.languageMap).sort(function(l1, l2){
     474                                                                                                return l1[1].localeCompare(l2[1]);
     475                                                                                        }).map(function(l) {
    389476                                                                                                var desc = l[1] + " [" + l[0] + "]";
    390477                                                                                                return <li key={l[0]}> <a tabIndex="-1" href="#"
    391                                                                                                         onClick={this.setAState.bind(this, "language", l)}>{desc}</a></li>;
     478                                                                                                        onClick={this.setLanguage.bind(this, l)}>{desc}</a></li>;
    392479                                                                                        }.bind(this))
    393480                                                                                }
     
    399486                                                                                {       layers.map(function(l) {
    400487                                                                                                return <li key={l.id}> <a tabIndex="-1" href="#"
    401                                                                                                         onClick={this.setAState.bind(this, "searchLayerId", l.id)}> {l.name} </a></li>;
     488                                                                                                        onClick={this.setLayer.bind(this, l.id)}> {l.name} </a></li>;
    402489                                                                                        }.bind(this))
    403490                                                                                }
     
    425512
    426513                    <Modal ref="corporaModal" title="Collections">
    427                                         <CorpusView ref="corpusView" corpora={this.props.corpora} />
     514                                        <CorpusView corpora={this.props.corpora} languageMap={this.props.languageMap} />
    428515                    </Modal>
    429516
  • SRUAggregator/trunk/src/main/resources/assets/js/search.js

    r5897 r5900  
    9090                var inline = {display:"inline-block"};
    9191                return  React.createElement("div", {style: inline},
    92                                         React.createElement("span", {className: "corpusName"}, " ", corpus.displayName),
     92                                        React.createElement("span", {className: "corpusName"}, " ", corpus.title ? corpus.title : corpus.displayName),
    9393                                        React.createElement("span", {className: "institutionName"}, " — ", corpus.institution.name)
    9494                                );
     
    9898                var inline = {display:"inline-block"};
    9999                return  React.createElement("div", null,
    100                                         React.createElement(InfoPopover, {placement: "left", title: corpus.displayName},
     100                                        React.createElement(InfoPopover, {placement: "left",
     101                                                        title: corpus.title ? corpus.title : corpus.displayName},
    101102                                                React.createElement("dl", {className: "dl-horizontal"},
    102103                                                        React.createElement("dt", null, "Institution"),
     
    165166        },
    166167
    167         renderFoundMessage: function() {
     168        renderFoundMessage: function(hits) {
    168169                if (this.props.results.length === 0)
    169170                        return false;
    170                 var hits = this.props.results.filter(function(corpusHit) { return corpusHit.kwics.length > 0; }).length;
    171171                var total = this.props.results.length;
    172172                return hits + " collections with results found in " + total + " searched collections";
     
    191191
    192192        render: function() {
     193                var hits = this.props.results.filter(function(corpusHit) { return corpusHit.kwics.length > 0; }).length;
    193194                var margintop = {marginTop:"10px"};
    194195                var margin = {marginTop:"0", padding:"20px"};
     
    198199                                        React.createElement(ReactCSSTransitionGroup, {transitionName: "fade"},
    199200                                                React.createElement("div", {key: "-searching-message-", style: margintop}, this.renderSearchingMessage(), " "),
    200                                                 React.createElement("div", {key: "-found-message-", style: margintop}, this.renderFoundMessage(), " "),
     201                                                React.createElement("div", {key: "-found-message-", style: margintop}, this.renderFoundMessage(hits), " "),
    201202                                                React.createElement("div", {key: "-progress-", style: margintop}, this.renderProgressBar()),
    202                                                 this.props.results.length > 0 ? this.renderKwicCheckbox() : false,
     203                                                hits > 0 ? this.renderKwicCheckbox() : false,
    203204                                                this.props.results.map(this.renderResultPanels)
    204205                                        )
  • SRUAggregator/trunk/src/main/resources/assets/js/search.jsx

    r5897 r5900  
    9090                var inline = {display:"inline-block"};
    9191                return  <div style={inline}>
    92                                         <span className="corpusName"> {corpus.displayName}</span>
     92                                        <span className="corpusName"> {corpus.title ? corpus.title : corpus.displayName}</span>
    9393                                        <span className="institutionName"> — {corpus.institution.name}</span>
    9494                                </div>;
     
    9898                var inline = {display:"inline-block"};
    9999                return  <div>
    100                                         <InfoPopover placement="left" title={corpus.displayName}>
     100                                        <InfoPopover placement="left"
     101                                                        title={corpus.title ? corpus.title : corpus.displayName}>
    101102                                                <dl className="dl-horizontal">
    102103                                                        <dt>Institution</dt>
     
    165166        },
    166167
    167         renderFoundMessage: function() {
     168        renderFoundMessage: function(hits) {
    168169                if (this.props.results.length === 0)
    169170                        return false;
    170                 var hits = this.props.results.filter(function(corpusHit) { return corpusHit.kwics.length > 0; }).length;
    171171                var total = this.props.results.length;
    172172                return hits + " collections with results found in " + total + " searched collections";
     
    191191
    192192        render: function() {
     193                var hits = this.props.results.filter(function(corpusHit) { return corpusHit.kwics.length > 0; }).length;
    193194                var margintop = {marginTop:"10px"};
    194195                var margin = {marginTop:"0", padding:"20px"};
     
    198199                                        <ReactCSSTransitionGroup transitionName="fade">
    199200                                                <div key="-searching-message-" style={margintop}>{this.renderSearchingMessage()} </div>
    200                                                 <div key="-found-message-" style={margintop}>{this.renderFoundMessage()} </div>
     201                                                <div key="-found-message-" style={margintop}>{this.renderFoundMessage(hits)} </div>
    201202                                                <div key="-progress-" style={margintop}>{this.renderProgressBar()}</div>
    202                                                 {this.props.results.length > 0 ? this.renderKwicCheckbox() : false}
     203                                                {hits > 0 ? this.renderKwicCheckbox() : false}
    203204                                                {this.props.results.map(this.renderResultPanels)}
    204205                                        </ReactCSSTransitionGroup>
Note: See TracChangeset for help on using the changeset viewer.