Changeset 6043


Ignore:
Timestamp:
02/24/15 16:58:55 (9 years ago)
Author:
emanuel.dima@uni-tuebingen.de
Message:
  1. alpha 21: downloading as text, csv, excel and tcf works
Location:
SRUAggregator/trunk
Files:
18 edited
1 moved

Legend:

Unmodified
Added
Removed
  • SRUAggregator/trunk/aggregator.yml

    r5976 r6043  
    11aggregatorParams:
    2   CENTER_REGISTRY_URL: http://centres.clarin.eu/restxml/
    3  # additionalCQLEndpoints:
    4  #    - https://clarin.ids-mannheim.de/digibibsru-new
    5  #    - https://lux17.mpi.nl/ds/cqlsearch
    6  #    - http://www.meertens.knaw.nl/mimore/srucql/
    7  #    - http://gysseling.corpus.taalbanknederlands.inl.nl/gyssru/
    8  #    - http://brievenalsbuit.inl.nl/zbsru/
    9  #    - http://corpus3.aac.ac.at/ddconsru/
    10 #      - http://dspin.dwds.de:8088/ddc-sru/dta/
     2  # CENTER_REGISTRY_URL: http://centres.clarin.eu/restxml/
     3  additionalCQLEndpoints:
     4    # - http://cqlservlet.mpi.nl/
     5    - http://dspin.dwds.de:8088/ddc-sru/dingler/
     6    - https://clarin.ids-mannheim.de/digibibsru-new
     7    - https://lux17.mpi.nl/ds/cqlsearch
     8    # - http://www.meertens.knaw.nl/mimore/srucql/
     9    # - http://gysseling.corpus.taalbanknederlands.inl.nl/gyssru/
     10    # - http://brievenalsbuit.inl.nl/zbsru/
     11    # - http://corpus3.aac.ac.at/ddconsru/
     12    #  - http://dspin.dwds.de:8088/ddc-sru/dta/
    1113
    1214  # AGGREGATOR_FILE_PATH: /data/fcsAggregator/fcsAggregatorCorpora.json
     
    4143  # Logger-specific levels.
    4244  loggers:
    43     eu.clarin.sru.fcs.aggregator: WARN
     45    eu.clarin.sru.fcs.aggregator: INFO
    4446    eu.clarin.sru.client: WARN
    4547
  • SRUAggregator/trunk/pom.xml

    r5976 r6043  
    88        <groupId>eu.clarin.sru.fcs</groupId>
    99        <artifactId>Aggregator2</artifactId>
    10         <version>2.0.0-alpha-20</version>
     10        <version>2.0.0-alpha-21</version>
    1111        <name>FCS Aggregator</name>
    1212
     
    2626                        <url>http://oss.sonatype.org/content/repositories/snapshots</url>
    2727                </repository>
    28                 <repository>
    29                         <id>sardine-google-svn-repo</id>
    30                         <snapshots>
    31                                 <enabled>true</enabled>
    32                         </snapshots>
    33                         <name>Sardine maven repo at Google Code</name>
    34                         <url>http://sardine.googlecode.com/svn/maven/</url>
    35                 </repository>
    3628        </repositories>
    3729
     
    6355                        <artifactId>sru-client</artifactId>
    6456                        <version>0.9.5-DEBUG</version>
     57                        <exclusions>
     58                                <exclusion>
     59                                        <groupId>org.slf4j</groupId>
     60                                        <artifactId>slf4j-api</artifactId>
     61                                </exclusion>
     62                                <exclusion>
     63                                        <groupId>commons-codec</groupId>
     64                                        <artifactId>commons-codec</artifactId>
     65                                </exclusion>
     66                        </exclusions>
    6567                </dependency>
    6668
     
    7476                        <artifactId>connectors</artifactId>
    7577                        <version>1.0.6</version>
     78                        <exclusions>
     79                                <exclusion>
     80                                        <groupId>com.sun.jersey</groupId>
     81                                        <artifactId>jersey-client</artifactId>
     82                                </exclusion>
     83                        </exclusions>
    7684                </dependency>
    7785                <dependency>
     
    8997                    <groupId>com.optimaize.languagedetector</groupId>
    9098                    <artifactId>language-detector</artifactId>
    91                     <version>0.4</version>
     99                        <version>0.4</version>
     100                        <exclusions>
     101                                <exclusion>
     102                                        <groupId>com.google.guava</groupId>
     103                                        <artifactId>guava</artifactId>
     104                                </exclusion>
     105                        </exclusions>
    92106                </dependency>
    93107               
    94                 <dependency>
    95                         <groupId>com.googlecode.sardine</groupId>
    96                         <artifactId>sardine</artifactId>
    97                         <version>314</version>
    98                         <type>jar</type>
    99                         <exclusions>
    100                                 <exclusion>
    101                                         <groupId>org.apache.httpcomponents</groupId>
    102                                         <artifactId>httpcore</artifactId>
    103                                 </exclusion>
    104                                 <exclusion>
    105                                         <artifactId>commons-codec</artifactId>
    106                                         <groupId>commons-codec</groupId>
    107                                 </exclusion>
    108                         </exclusions>
    109                 </dependency>
    110108                <dependency>
    111109                        <groupId>org.apache.poi</groupId>
    112110                        <artifactId>poi-ooxml</artifactId>
    113111                        <version>3.11-beta2</version>
     112                </dependency>
     113                <dependency>
     114                        <groupId>com.sun.jersey</groupId>
     115                        <artifactId>jersey-client</artifactId>
     116                        <version>1.18.1</version>
     117                        <type>jar</type>
    114118                </dependency>
    115119        </dependencies>
     
    130134                                                </configuration>
    131135                                                <goals>
    132                                                         <!--<goal>enforce</goal>-->
     136                                                        <goal>enforce</goal>
    133137                                                </goals>
    134138                                        </execution>
  • SRUAggregator/trunk/src/main/java/eu/clarin/sru/fcs/aggregator/app/Aggregator.java

    r5976 r6043  
    8888 * @author edima
    8989 *
    90  * TODO: Download search results as csv, excel, tcf, plain text
    91  *
    9290 * TODO: Use weblicht with results
    9391 *
    94  * TODO: Export search results to personal workspace as csv, excel, tcf, plain
    95  * text
    96  *
    9792 * TODO: disable popups easily
    98  *
    99  * TODO: websockets
    100  *
     93 *
    10194 * TODO: atomic replace of cached corpora (file)
    102  *
    103  * TODO: show multiple hits on the same result in multiple rows, linked visually
    10495 *
    10596 * TODO: zoom into the results from a corpus, allow functionality only for
    10697 * the view (search for next set of results)
     98 *
     99 * TODO: fix search bug after going to stats
     100 *
     101 * TODO: Export search results to personal workspace as csv, excel, tcf, plain
     102 * text: ask Marie/Wei about oauth ways to do that ndg oauth; ask Menzo, Willem,
     103 * Twan (they did a test, it worked)
     104 *
     105 * TODO: websockets
     106 *
     107 * TODO: show multiple hits on the same result in multiple rows, linked visually
    107108 *
    108109 * TODO: optimise page load
  • SRUAggregator/trunk/src/main/java/eu/clarin/sru/fcs/aggregator/lang/LanguagesISO693_3.java

    r5931 r6043  
    2828        public static class Language {
    2929
    30                 // code is ISO-639-3 (3 letters) while code_2 is ISO-639-2 (2 letters)
    31                 String code, code_2, name;
     30                // code is ISO-639-3 (3 letters) while code_2 is ISO-639-1 (2 letters)
     31                String code_3, code_1, name;
    3232
    33                 public Language(String code, String code_2, String name) {
    34                         this.code = code;
    35                         this.code_2 = code_2;
     33                public Language(String code_3, String code_1, String name) {
     34                        this.code_3 = code_3;
     35                        this.code_1 = code_1;
    3636                        this.name = name;
    3737                }
    3838        }
    3939
    40         private Map<String, Language> codeToLang = new HashMap<String, Language>();
     40        private Map<String, Language> code_3ToLang = new HashMap<String, Language>();
    4141        private Map<String, Language> nameToLang = new HashMap<String, Language>();
    42         private Map<String, Language> code_2ToLang = new HashMap<String, Language>();
     42        private Map<String, Language> code_1ToLang = new HashMap<String, Language>();
    4343
    4444        private LanguagesISO693_3() {
     
    5353                                                continue;
    5454                                        }
    55                                         String code = toks[0].trim();
    56                                         String code_2 = toks[3].trim().isEmpty() ? null : toks[3].trim();
    57                                         if (code_2 != null && code_2.length() != 2) {
    58                                                 throw new RuntimeException("bad code_2 code: " + code_2);
     55                                        String code_3 = toks[0].trim();
     56                                        String code_1 = toks[3].trim().isEmpty() ? null : toks[3].trim();
     57                                        if (code_1 != null && code_1.length() != 2) {
     58                                                throw new RuntimeException("bad ISO-639-1 code: " + code_1);
    5959                                        }
    6060                                        String name = toks[6].trim();
    61                                         Language l = new Language(code, code_2, name);
    62                                         codeToLang.put(code, l);
    63                                         if (code_2 != null) {
    64                                                 code_2ToLang.put(code_2, l);
     61                                        Language l = new Language(code_3, code_1, name);
     62                                        code_3ToLang.put(code_3, l);
     63                                        if (code_1 != null) {
     64                                                code_1ToLang.put(code_1, l);
    6565                                        }
    6666                                        nameToLang.put(name, l);
     
    7373                ObjectWriter ow = new ObjectMapper().writerWithDefaultPrettyPrinter();
    7474                try {
    75                         System.out.println(ow.writeValueAsString(codeToLang));
     75                        System.out.println(ow.writeValueAsString(code_3ToLang));
    7676                } catch (JsonProcessingException ex) {
    7777                }
     
    8585        }
    8686
    87         public Set<String> getCodes() {
    88                 return codeToLang.keySet();
     87        public Set<String> getCodes_3() {
     88                return code_3ToLang.keySet();
    8989        }
    9090
    91         public String codeForCode639_2(String code639_2) {
    92                 if (code639_2 == null) {
     91        public String code_3ForCode_1(String code639_1) {
     92                if (code639_1 == null) {
    9393                        return null;
    9494                }
    95                 Language l = code_2ToLang.get(code639_2);
     95                Language l = code_1ToLang.get(code639_1);
    9696                if (l == null) {
    97                         log.error("Unknown 639-2 code: " + code639_2);
     97                        log.error("Unknown ISO-639-1 code: " + code639_1);
    9898                        return null;
    9999                }
    100                 return l.code;
     100                return l.code_3;
    101101        }
    102102
    103         public String codeForName(String name) {
     103        public String code_1ForCode_3(String code639_3) {
     104                if (code639_3 == null) {
     105                        return null;
     106                }
     107                Language l = code_3ToLang.get(code639_3);
     108                if (l == null) {
     109                        log.error("Unknown ISO-639-3 code: " + code639_3);
     110                        return null;
     111                }
     112                return l.code_1;
     113        }
     114
     115        public String code_3ForName(String name) {
    104116                Language l = nameToLang.get(name);
    105117                if (l == null) {
     
    107119                        return null;
    108120                }
    109                 return l.code;
     121                return l.code_3;
    110122        }
    111123
    112         public String nameForCode(String code) {
    113                 Language l = codeToLang.get(code);
     124        public String nameForCode_3(String code) {
     125                Language l = code_3ToLang.get(code);
    114126                if (l == null) {
    115127                        log.error("Unknown language code: " + code);
  • SRUAggregator/trunk/src/main/java/eu/clarin/sru/fcs/aggregator/rest/DataTransfer.java

    r5937 r6043  
    1 package eu.clarin.sru.fcs.aggregator.search;
     1package eu.clarin.sru.fcs.aggregator.rest;
    22
    3 import com.googlecode.sardine.Sardine;
    4 import com.googlecode.sardine.SardineFactory;
    5 import com.googlecode.sardine.impl.SardineException;
    63import com.sun.jersey.api.client.Client;
    74import com.sun.jersey.api.client.ClientResponse;
     
    107import com.sun.jersey.api.client.config.DefaultClientConfig;
    118import java.util.logging.*;
    12 import java.io.IOException;
    139import java.text.SimpleDateFormat;
    1410import java.util.Date;
     
    2723        private static final String WSPACE_AGGREGATOR_DIR = "aggregator_results/";
    2824        private static final String DROP_OFF_URL = "http://ws1-clarind.esc.rzg.mpg.de/drop-off/storage/";
    29 
    30         static void uploadToPW(String user, String pass, byte[] bytes, String mimeType, String fileExtention) {
    31                 try {
    32                         Sardine sardine = SardineFactory.begin();
    33                         sardine.setCredentials(user, pass);
    34                         String outputDir = WSPACE_SERVER_URL + WSPACE_WEBDAV_DIR + WSPACE_AGGREGATOR_DIR;
    35                         if (!sardine.exists(outputDir)) {
    36                                 sardine.createDirectory(outputDir);
    37                         }
    38                         Date currentDate = new Date();
    39                         SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd-HH-mm-ss-SSS");
    40                         Random generator = new Random();
    41                         int rn1 = generator.nextInt(1000000000);
    42                         String createdFilePath = outputDir + format.format(currentDate) + "-" + rn1 + fileExtention;
    43                         while (sardine.exists(createdFilePath)) {
    44                                 rn1 = generator.nextInt(1000000000);
    45                                 createdFilePath = outputDir + format.format(currentDate) + "-" + rn1 + fileExtention;
    46                         }
    47                         sardine.put(createdFilePath, bytes, mimeType);
    48                         // "Export complete!\nCreated file:\n" + createdFilePath
    49                 } catch (SardineException ex) {
    50                         LOGGER.log(Level.SEVERE, "Error accessing " + WSPACE_SERVER_URL + WSPACE_WEBDAV_DIR, ex);
    51                         //"Wrong name or password!"
    52                 } catch (IOException ex) {
    53                         LOGGER.log(Level.SEVERE, "Error exporting {0} {1} {2}", new String[]{fileExtention, ex.getClass().getName(), ex.getMessage()});
    54                         //"Sorry, export error!"
    55                 }
    56         }
    5725
    5826        static String uploadToDropOff(byte[] bytes, String mimeType, String fileExtention) {
  • SRUAggregator/trunk/src/main/java/eu/clarin/sru/fcs/aggregator/rest/RestService.java

    r5976 r6043  
    1313import eu.clarin.sru.fcs.aggregator.search.Search;
    1414import eu.clarin.sru.fcs.aggregator.lang.LanguagesISO693_3;
     15import eu.clarin.sru.fcs.aggregator.search.ExportException;
    1516import eu.clarin.sru.fcs.aggregator.search.Exports;
    1617import java.io.IOException;
     
    2122import java.util.Map;
    2223import java.util.Set;
     24import java.util.logging.Level;
     25import java.util.logging.Logger;
    2326import javax.servlet.ServletContext;
    2427import javax.servlet.http.HttpServletRequest;
     
    3336import javax.ws.rs.core.MediaType;
    3437import javax.ws.rs.core.Response;
     38import opennlp.tools.tokenize.TokenizerModel;
    3539import org.slf4j.LoggerFactory;
    3640
     
    4246@Path("/")
    4347public class RestService {
     48
    4449        private static final String EXPORT_FILENAME_PREFIX = "ClarinDFederatedContentSearch-";
    4550        private static final String TCF_MEDIA_TYPE = "text/tcf+xml";
    4651        private static final String EXCEL_MEDIA_TYPE = "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet";
     52        private static final String SEARCH_RESULTS_ENCODING = "UTF-8";
    4753
    4854        private static final org.slf4j.Logger log = LoggerFactory.getLogger(RestService.class);
     
    8288                                                put("isScan", true);
    8389                                                put("institutions", scan.getInstitutions());
     90                                                put("date", scan.getDate());
    8491                                        }
    8592                                });
     
    9198                                                put("isScan", false);
    9299                                                put("institutions", search.getInstitutions());
     100                                                put("date", scan.getDate());
    93101                                        }
    94102                                });
     
    105113                log.info("get language codes", codes);
    106114                for (String code : codes) {
    107                         String name = LanguagesISO693_3.getInstance().nameForCode(code);
     115                        String name = LanguagesISO693_3.getInstance().nameForCode_3(code);
    108116                        languages.put(code, name != null ? name : code);
    109117                }
     
    184192                }
    185193
    186                 if (format == null || format.trim().isEmpty() || format.trim().equals("text")) {
     194        if (format == null || format.trim().isEmpty() || format.trim().equals("text")) {
    187195                        String text = Exports.getExportText(search.getResults());
    188196                        return download(text, MediaType.TEXT_PLAIN, search.getQuery() + ".txt");
     
    215223                                .build();
    216224        }
     225
     226        @GET
     227        @Path("search/{id}/toWeblicht")
     228        public Response sendSearchResultsToWeblicht(@PathParam("id") Long searchId,
     229                        @QueryParam("format") String format) throws Exception {
     230                Search search = Aggregator.getInstance().getSearchById(searchId);
     231                if (search == null) {
     232                        return Response.status(Response.Status.NOT_FOUND).entity("Search job not found").build();
     233                }
     234
     235                String url = null;
     236                if (format == null || format.isEmpty() || format.trim().equals("text")) {
     237                        String text = Exports.getExportText(search.getResults());
     238                        if (text != null) {
     239                                byte[] bytes = text.getBytes(SEARCH_RESULTS_ENCODING);
     240                                url = DataTransfer.uploadToDropOff(bytes, "text/plan", ".txt");
     241                        }
     242                } else if (format.equals("tokens")) {
     243                        byte[] bytes = Exports.getExportTokenizedTCF(
     244                                        search.getResults(), search.getSearchLanguage(),
     245                                        Aggregator.getInstance().getTokenizerModel());
     246                        if (bytes != null) {
     247                                url = DataTransfer.uploadToDropOff(bytes, "text/tcf+xml", ".tcf");
     248                        }
     249                } else {
     250                        return Response.status(400).entity("incorrect format parameter").build();
     251                }
     252
     253                return url == null ? Response.status(503).entity("error while exporting to weblicht").build()
     254                                : Response.ok().entity(url).build();
     255        }
    217256}
  • SRUAggregator/trunk/src/main/java/eu/clarin/sru/fcs/aggregator/scan/Corpus.java

    r5957 r6043  
    102102
    103103        public void addLanguage(String language) {
    104                 if (LanguagesISO693_3.getInstance().getCodes().contains(language)) {
     104                if (LanguagesISO693_3.getInstance().getCodes_3().contains(language)) {
    105105                        this.languages.add(language);
    106106                } else {
    107                         String code = LanguagesISO693_3.getInstance().codeForName(language);
     107                        String code = LanguagesISO693_3.getInstance().code_3ForName(language);
    108108                        this.languages.add(code == null ? language : code);
    109109                }
  • SRUAggregator/trunk/src/main/java/eu/clarin/sru/fcs/aggregator/scan/ScanCrawler.java

    r5976 r6043  
    368368                                } else if (infoNode.getNodeType() == Node.ELEMENT_NODE && infoNode.getLocalName().equals("Title")) {
    369369                                        Element element = (Element) infoNode;
    370                                         String descr = infoNode.getTextContent().replaceAll("&lt;br/&gt;", " ");
    371                                         descr = descr.replaceAll("<br/>", " ");
    372                                         descr = descr.replaceAll("[\t\n\r ]+", " ");
    373                                         c.setTitle(descr.trim());
     370                                        String x = cleanup(infoNode.getTextContent());
     371                                        if (!x.isEmpty()) {
     372                                                c.setTitle(x);
     373                                                if ("en".equals(element.getAttribute("xml:lang"))) {
     374                                                        enTitle = x;
     375                                                }
     376                                        }
     377                                } else if (infoNode.getNodeType() == Node.ELEMENT_NODE && infoNode.getLocalName().equals("Description")) {
     378                                        Element element = (Element) infoNode;
     379                                        String x = cleanup(infoNode.getTextContent());
     380                                        c.setDescription(x);
    374381                                        //String lang = element.getAttributeNS("http://clarin.eu/fcs/1.0/resource-info", "lang");
    375382                                        //System.out.println("ATTRIBUTE LANG: " + lang);
    376383                                        if ("en".equals(element.getAttribute("xml:lang"))) {
    377                                                 enTitle = c.getDescription();
    378                                         }
    379                                 } else if (infoNode.getNodeType() == Node.ELEMENT_NODE && infoNode.getLocalName().equals("Description")) {
    380                                         Element element = (Element) infoNode;
    381                                         String descr = infoNode.getTextContent().replaceAll("&lt;br/&gt;", " ");
    382                                         descr = descr.replaceAll("<br/>", " ");
    383                                         descr = descr.replaceAll("[\t\n\r ]+", " ");
    384                                         c.setDescription(descr.trim());
    385                                         //String lang = element.getAttributeNS("http://clarin.eu/fcs/1.0/resource-info", "lang");
    386                                         //System.out.println("ATTRIBUTE LANG: " + lang);
    387                                         if ("en".equals(element.getAttribute("xml:lang"))) {
    388                                                 enDescription = c.getDescription();
    389                                         }
    390                                 }
    391                         }
    392                         // title in Engish has priority
     384                                                enDescription = x;
     385                                        }
     386                                }
     387                        }
     388                        // title in English has priority
    393389                        if (enTitle != null && !enTitle.isEmpty()) {
    394390                                c.setTitle(enTitle);
    395391                        }
    396                         // description in Engish has priority
     392                        // description in English has priority
    397393                        if (enDescription != null && !enDescription.isEmpty()) {
    398394                                c.setDescription(enDescription);
     
    400396                }
    401397        }
     398
     399        private static String cleanup(String x) {
     400                if (x == null) {
     401                        return "";
     402                }
     403                x = x.replaceAll("&lt;br/&gt;", " ");
     404                x = x.replaceAll("<br/>", " ");
     405                x = x.replaceAll("[\t\n\r ]+", " ");
     406                return x.trim();
     407        }
    402408}
  • SRUAggregator/trunk/src/main/java/eu/clarin/sru/fcs/aggregator/scan/Statistics.java

    r5971 r6043  
    44import java.util.ArrayList;
    55import java.util.Collections;
     6import java.util.Date;
    67import java.util.HashMap;
    78import java.util.List;
     
    109110        private final Object lock = new Object();
    110111
     112        Date date = new Date();
     113
     114        public Date getDate() {
     115                return date;
     116        }
     117
    111118        // institution to endpoint to statistics_per_endpoint map
    112119        Map<String, Map<String, EndpointStats>> institutions
     
    186193                return stats;
    187194        }
     195
    188196}
  • SRUAggregator/trunk/src/main/java/eu/clarin/sru/fcs/aggregator/search/ExportException.java

    r5718 r6043  
    1111        }
    1212
     13        public ExportException(String message) {
     14                super(message);
     15        }
    1316}
  • SRUAggregator/trunk/src/main/java/eu/clarin/sru/fcs/aggregator/search/Exports.java

    r5957 r6043  
    22
    33import eu.clarin.sru.fcs.aggregator.lang.LanguagesISO693_2;
     4import eu.clarin.sru.fcs.aggregator.lang.LanguagesISO693_3;
    45import eu.clarin.weblicht.wlfxb.io.WLDObjector;
    56import eu.clarin.weblicht.wlfxb.io.WLFormatException;
     
    1213import java.io.IOException;
    1314import java.util.ArrayList;
     15import java.util.Collections;
    1416import java.util.HashSet;
    1517import java.util.List;
     
    225227                        String searchLanguage, TokenizerModel tokenizerModel) throws ExportException {
    226228        StringBuilder text = new StringBuilder();
    227         Set<String> resultsLangs = new HashSet<String>();
    228         if (resultsProcessed != null && !resultsProcessed.isEmpty()) {
    229             for (Result result : resultsProcessed) {
    230                 resultsLangs.addAll(result.getCorpus().getLanguages());
    231                 for (Kwic kwic : result.getKwics()) {
    232                     text.append(kwic.getLeft());
    233                     text.append(" ");
    234                     text.append(kwic.getKeyword());
    235                     text.append(" ");
    236                     text.append(kwic.getRight());
    237                     text.append("\n");
     229        if (resultsProcessed != null && !resultsProcessed.isEmpty()) {
     230                        for (Result result : resultsProcessed) {
     231                                for (Kwic kwic : result.getKwics()) {
     232                                        int i = kwic.getFragments().size() - 1;
     233                                        for (Kwic.TextFragment tf : kwic.getFragments()) {
     234                                                text.append(tf.text);
     235                                                if (i > 0) {
     236                                                        text.append(" ");
     237                                                }
     238                                                i--;
     239                                        }
     240                                        text.append("\n");
    238241                }
    239242            }
     
    244247        } else {
    245248            WLData data;
    246             MetaData md = new MetaData();
    247             String resultsLang = "unknown";
    248             if (resultsLangs.size() == 1) {
    249                 resultsLang = resultsLangs.iterator().next();
    250                                 String code2 = LanguagesISO693_2.getInstance().langForCode(resultsLang).getCode_639_1();
    251                 if (code2 != null) {
    252                     resultsLang = code2;
    253                 }
    254             } else if (!searchLanguage.equals("anylang")) {
    255                                 String code2 = LanguagesISO693_2.getInstance().langForCode(resultsLang).getCode_639_1();
    256                 if (code2 == null) {
    257                     resultsLang = searchLanguage;
    258                 } else {
    259                     resultsLang = code2;
    260                 }
    261             }
    262             TextCorpusStored tc = new TextCorpusStored(resultsLang);
     249                        MetaData md = new MetaData();
     250                        String languageCode = LanguagesISO693_3.getInstance().code_1ForCode_3(searchLanguage);
     251                        TextCorpusStored tc = new TextCorpusStored(languageCode);
    263252            tc.createTextLayer().addText(text.toString());
    264253                        addTokensSentencesMatches(resultsProcessed, tc, tokenizerModel);
     
    276265
    277266        private static void addTokensSentencesMatches(List<Result> resultsProcessed, TextCorpusStored tc, TokenizerModel model) {
    278         if (model == null || !tc.getLanguage().equals("de")) {
     267                if (model == null || !"de".equals(tc.getLanguage())) {
    279268            return;
    280269        }
  • SRUAggregator/trunk/src/main/java/eu/clarin/sru/fcs/aggregator/search/Kwic.java

    r5931 r6043  
    6464                }
    6565
    66                 String code_iso639_2 = Aggregator.getInstance().detectLanguage(hits.getText());
    67                 language = code_iso639_2 == null ? null
    68                                 : LanguagesISO693_3.getInstance().codeForCode639_2(code_iso639_2);
     66                String code_iso639_1 = Aggregator.getInstance().detectLanguage(hits.getText());
     67                language = code_iso639_1 == null ? null
     68                                : LanguagesISO693_3.getInstance().code_3ForCode_1(code_iso639_1);
    6969        }
    7070
  • SRUAggregator/trunk/src/main/java/eu/clarin/sru/fcs/aggregator/search/Search.java

    r5976 r6043  
    1717import java.util.Random;
    1818import java.util.concurrent.atomic.AtomicLong;
    19 import java.util.logging.Level;
    20 import java.util.logging.Logger;
    21 import opennlp.tools.tokenize.TokenizerModel;
    2219import org.slf4j.LoggerFactory;
    2320
     
    6865                                ? ClarinFCSRecordData.LEGACY_RECORD_SCHEMA
    6966                                : ClarinFCSRecordData.RECORD_SCHEMA);
    70                 searchRequest.setQuery("\"" + searchString + "\"");
     67                searchRequest.setQuery(searchString);
    7168                searchRequest.setStartRecord(startRecord);
    7269                if (corpus.getHandle() != null) {
     
    149146        }
    150147
    151         private void exportPWText(String user, String pass) {
    152                 byte[] bytes = null;
    153                 try {
    154                         String text = Exports.getExportText(results);
    155                         if (text != null) {
    156                                 bytes = text.getBytes(SEARCH_RESULTS_ENCODING);
    157                         }
    158                 } catch (Exception ex) {
    159                         Logger.getLogger(Search.class.getName()).log(Level.SEVERE, null, ex);
    160                 }
    161                 if (bytes != null) {
    162                         DataTransfer.uploadToPW(user, pass, bytes, "text/plan", ".txt");
    163                 }
    164         }
    165 
    166         private String useWebLichtOnText() {
    167                 String url = null;
    168                 try {
    169                         String text = Exports.getExportText(results);
    170                         if (text != null) {
    171                                 byte[] bytes = text.getBytes(SEARCH_RESULTS_ENCODING);
    172                                 url = DataTransfer.uploadToDropOff(bytes, "text/plan", ".txt");
    173                         }
    174                 } catch (Exception ex) {
    175                         Logger.getLogger(Search.class.getName()).log(Level.SEVERE, null, ex);
    176                 }
    177                 return url;
    178         }
    179 
    180         private String useWebLichtOnToks(TokenizerModel tokenizerModel) throws ExportException {
    181                 String url = null;
    182                 byte[] bytes = Exports.getExportTokenizedTCF(results, searchLanguage, tokenizerModel);
    183                 if (bytes != null) {
    184                         url = DataTransfer.uploadToDropOff(bytes, "text/tcf+xml", ".tcf");
    185                 }
    186                 return url;
    187         }
    188 
    189         private void exportPWExcel(String user, String pass) throws ExportException {
    190                 byte[] bytes = Exports.getExportExcel(results);
    191                 if (bytes != null) {
    192                         DataTransfer.uploadToPW(user, pass, bytes, "application/vnd.ms-excel", ".xls");
    193                 }
    194         }
    195 
    196         private void exportPWTCF(String user, String pass, TokenizerModel tokenizerModel) throws ExportException {
    197                 byte[] bytes = Exports.getExportTokenizedTCF(results, searchLanguage, tokenizerModel);
    198                 if (bytes != null) {
    199                         DataTransfer.uploadToPW(user, pass, bytes, "text/tcf+xml", ".tcf");
    200                 }
    201         }
    202 
    203         private void exportPWCSV(String user, String pass) {
    204                 String csv = Exports.getExportCSV(results, ";");
    205                 if (csv != null) {
    206                         DataTransfer.uploadToPW(user, pass, csv.getBytes(), "text/csv", ".csv");
    207                 }
    208         }
    209 
    210148        public void shutdown() {
    211149                // nothing to do
  • SRUAggregator/trunk/src/main/resources/assets/js/corpora.js

    r5959 r6043  
    1212
    1313/////////////////////////////////
    14 
    15 var SearchCorpusBox = React.createClass({displayName: 'SearchCorpusBox',
    16         propTypes: {
    17                 search: PT.func.isRequired,
    18         },
    19 
    20         getInitialState: function () {
    21                 return {
    22                         query: ""
    23                 };
    24         },
    25 
    26         handleChange: function(event) {
    27                 var query = event.target.value;
    28                 this.setState({query: query});
    29 
    30                 if (query.length === 0 || 2 <= query.length) {
    31                         this.props.search(query);
    32                 }
    33                 event.stopPropagation();
    34         },
    35 
    36         handleKey: function(event) {
    37                 if (event.keyCode==13) {
    38                         this.props.search(event.target.value);
    39                 }
    40         },
    41 
    42         render: function() {
    43                 return  React.createElement("div", {className: "form-group"},
    44                                         React.createElement("input", {className: "form-control search search-collection", type: "text",
    45                                                 value: this.state.query, placeholder: "Search for collection",
    46                                                 onChange: this.handleChange})
    47                                 );
    48         }
    49 });
    5014
    5115var CorpusView = window.MyAggregator.CorpusView = React.createClass({displayName: 'CorpusView',
     
    281245});
    282246
     247var SearchCorpusBox = React.createClass({displayName: 'SearchCorpusBox',
     248        propTypes: {
     249                search: PT.func.isRequired,
     250        },
     251
     252        getInitialState: function () {
     253                return {
     254                        query: ""
     255                };
     256        },
     257
     258        handleChange: function(event) {
     259                var query = event.target.value;
     260                this.setState({query: query});
     261
     262                if (query.length === 0 || 2 <= query.length) {
     263                        this.props.search(query);
     264                }
     265                event.stopPropagation();
     266        },
     267
     268        handleKey: function(event) {
     269                if (event.keyCode==13) {
     270                        this.props.search(event.target.value);
     271                }
     272        },
     273
     274        render: function() {
     275                return  React.createElement("div", {className: "form-group"},
     276                                        React.createElement("input", {className: "form-control search search-collection", type: "text",
     277                                                value: this.state.query, placeholder: "Search for collection",
     278                                                onChange: this.handleChange})
     279                                );
     280        }
     281});
     282
    283283})();
  • SRUAggregator/trunk/src/main/resources/assets/js/corpora.jsx

    r5959 r6043  
    1212
    1313/////////////////////////////////
    14 
    15 var SearchCorpusBox = React.createClass({
    16         propTypes: {
    17                 search: PT.func.isRequired,
    18         },
    19 
    20         getInitialState: function () {
    21                 return {
    22                         query: ""
    23                 };
    24         },
    25 
    26         handleChange: function(event) {
    27                 var query = event.target.value;
    28                 this.setState({query: query});
    29 
    30                 if (query.length === 0 || 2 <= query.length) {
    31                         this.props.search(query);
    32                 }
    33                 event.stopPropagation();
    34         },
    35 
    36         handleKey: function(event) {
    37                 if (event.keyCode==13) {
    38                         this.props.search(event.target.value);
    39                 }
    40         },
    41 
    42         render: function() {
    43                 return  <div className="form-group">
    44                                         <input className="form-control search search-collection" type="text"
    45                                                 value={this.state.query} placeholder="Search for collection"
    46                                                 onChange={this.handleChange} />
    47                                 </div>;
    48         }
    49 });
    5014
    5115var CorpusView = window.MyAggregator.CorpusView = React.createClass({
     
    281245});
    282246
     247var SearchCorpusBox = React.createClass({
     248        propTypes: {
     249                search: PT.func.isRequired,
     250        },
     251
     252        getInitialState: function () {
     253                return {
     254                        query: ""
     255                };
     256        },
     257
     258        handleChange: function(event) {
     259                var query = event.target.value;
     260                this.setState({query: query});
     261
     262                if (query.length === 0 || 2 <= query.length) {
     263                        this.props.search(query);
     264                }
     265                event.stopPropagation();
     266        },
     267
     268        handleKey: function(event) {
     269                if (event.keyCode==13) {
     270                        this.props.search(event.target.value);
     271                }
     272        },
     273
     274        render: function() {
     275                return  <div className="form-group">
     276                                        <input className="form-control search search-collection" type="text"
     277                                                value={this.state.query} placeholder="Search for collection"
     278                                                onChange={this.handleChange} />
     279                                </div>;
     280        }
     281});
     282
    283283})();
  • SRUAggregator/trunk/src/main/resources/assets/js/main.js

    r5976 r6043  
    33"use strict";
    44
    5 var VERSION = "VERSION 2.0.0.α20";
     5var VERSION = "VERSION 2.0.0.α21";
    66var URLROOT = "/Aggregator-testing";
    77
     
    1313var Main = React.createClass({displayName: 'Main',
    1414        componentWillMount: function() {
    15                 routeFromLocation(this);
     15                routeFromLocation.bind(this);
    1616        },
    1717
     
    102102                        }
    103103                        this.setState({navbarPageFn: pageFn});
    104                         console.log("new page: " + document.location + ", name: " + pageFnName);
     104                        // console.log("new page: " + document.location + ", name: " + pageFnName);
    105105                }
    106106        },
     
    193193                        success: function(json, textStatus, jqXHR) {
    194194                                this.setState({stats: json});
    195                                 console.log("stats:", json);
     195                                // console.log("stats:", json);
    196196                        }.bind(this),
    197197                });
     
    294294
    295295        renderInstitution: function(isScan, inst) {
    296                 return  React.createElement("div", {style: {marginBottom:30}, key: inst[0]},
     296                return  React.createElement("div", {style: {marginTop:30}, key: inst[0]},
    297297                                        React.createElement("h4", null, inst[0]),
    298298                                        React.createElement("div", {style: {marginLeft:20}}, " ", _.pairs(inst[1]).map(this.renderEndpoint.bind(this, isScan)) )
     
    302302        renderStatistics: function(stats) {
    303303                return  React.createElement("div", {className: "container statistics", style: {marginTop:20}},
    304                                         React.createElement("ul", {className: "list-inline list-unstyled"},
    305                                                  stats.maxConcurrentScanRequestsPerEndpoint ?
    306                                                         React.createElement("li", null, "max concurrent scan requests per endpoint:", " ",
    307                                                                 React.createElement("kbd", null, stats.maxConcurrentScanRequestsPerEndpoint), ","
    308                                                         ) : false,
     304                                        React.createElement("div", null,
     305                                                React.createElement("div", null, "Start date: ", new Date(stats.date).toLocaleString()),
     306                                                 stats.isScan ?
     307                                                        React.createElement("div", null, "Max concurrent scan requests per endpoint:", " ",
     308                                                                React.createElement("kbd", null, stats.maxConcurrentScanRequestsPerEndpoint)
     309                                                        )
     310                                                        :
     311                                                        React.createElement("div", null, "Max concurrent search requests per endpoint:", " ",
     312                                                                React.createElement("kbd", null, stats.maxConcurrentSearchRequestsPerEndpoint)
     313                                                        ),
    309314                                               
    310                                                  stats.maxConcurrentSearchRequestsPerEndpoint ?
    311                                                         React.createElement("li", null, "max concurrent search requests per endpoint:", " ",
    312                                                                 React.createElement("kbd", null, stats.maxConcurrentSearchRequestsPerEndpoint), ","
    313                                                         ) : false,
    314                                                
    315                                                 React.createElement("li", null, "timeout:", " ", React.createElement("kbd", null, stats.timeout, " seconds"))
     315                                                React.createElement("div", null, "Timeout: ", " ", React.createElement("kbd", null, stats.timeout, " seconds"))
    316316                                        ),
    317317                                        React.createElement("div", null, " ",  _.pairs(stats.institutions).map(this.renderInstitution.bind(this, stats.isScan)), " ")
     
    508508}
    509509
    510 var routeFromLocation = function(com) {
     510var routeFromLocation = function() {
     511        // console.log("routeFromLocation: " + document.location);
     512        if (!this) throw "routeFromLocation must be bound to main";
    511513        var path = window.location.pathname.split('/');
    512514        if (path.length === 3) {
    513515                var p = path[2];
    514516                if (p === 'help') {
    515                         com.toHelp(false);
     517                        this.toHelp(false);
    516518                } else if (p === 'about') {
    517                         com.toAbout(false);
     519                        this.toAbout(false);
    518520                } else if (p === 'stats') {
    519                         com.toStatistics(false);
     521                        this.toStatistics(false);
    520522                } else {
    521                         com.toAggregator(false);
     523                        this.toAggregator(false);
    522524                }
    523525        } else {
    524                 com.toAggregator(false);
     526                this.toAggregator(false);
    525527        }
    526528};
     
    529531React.render(React.createElement(Footer, null), document.getElementById('footer') );
    530532
    531 window.onpopstate = function(event) {
    532         console.log("popped location: " + document.location + ", state: " + JSON.stringify(event.state));
    533         routeFromLocation(main);
    534 };
    535 
    536 window.main = main;
     533window.onpopstate = routeFromLocation.bind(main);
     534
     535routeFromLocation.bind(main)();
    537536
    538537})();
     
    544543
    545544
    546 
    547 
    548 
    549 
    550 
    551 
    552 
    553 
    554 
    555 
    556 
    557 
  • SRUAggregator/trunk/src/main/resources/assets/js/main.jsx

    r5976 r6043  
    33"use strict";
    44
    5 var VERSION = "VERSION 2.0.0.α20";
     5var VERSION = "VERSION 2.0.0.α21";
    66var URLROOT = "/Aggregator-testing";
    77
     
    1313var Main = React.createClass({
    1414        componentWillMount: function() {
    15                 routeFromLocation(this);
     15                routeFromLocation.bind(this);
    1616        },
    1717
     
    102102                        }
    103103                        this.setState({navbarPageFn: pageFn});
    104                         console.log("new page: " + document.location + ", name: " + pageFnName);
     104                        // console.log("new page: " + document.location + ", name: " + pageFnName);
    105105                }
    106106        },
     
    193193                        success: function(json, textStatus, jqXHR) {
    194194                                this.setState({stats: json});
    195                                 console.log("stats:", json);
     195                                // console.log("stats:", json);
    196196                        }.bind(this),
    197197                });
     
    294294
    295295        renderInstitution: function(isScan, inst) {
    296                 return  <div style={{marginBottom:30}} key={inst[0]}>
     296                return  <div style={{marginTop:30}} key={inst[0]}>
    297297                                        <h4>{inst[0]}</h4>
    298298                                        <div style={{marginLeft:20}}> {_.pairs(inst[1]).map(this.renderEndpoint.bind(this, isScan)) }</div>
     
    302302        renderStatistics: function(stats) {
    303303                return  <div className="container statistics" style={{marginTop:20}}>
    304                                         <ul className='list-inline list-unstyled'>
    305                                                 { stats.maxConcurrentScanRequestsPerEndpoint ?
    306                                                         <li>max concurrent scan requests per endpoint:{" "}
    307                                                                 <kbd>{stats.maxConcurrentScanRequestsPerEndpoint}</kbd>,
    308                                                         </li> : false
     304                                        <div>
     305                                                <div>Start date: {new Date(stats.date).toLocaleString()}</div>
     306                                                { stats.isScan ?
     307                                                        <div>Max concurrent scan requests per endpoint:{" "}
     308                                                                <kbd>{stats.maxConcurrentScanRequestsPerEndpoint}</kbd>
     309                                                        </div>
     310                                                        :
     311                                                        <div>Max concurrent search requests per endpoint:{" "}
     312                                                                <kbd>{stats.maxConcurrentSearchRequestsPerEndpoint}</kbd>
     313                                                        </div>
    309314                                                }
    310                                                 { stats.maxConcurrentSearchRequestsPerEndpoint ?
    311                                                         <li>max concurrent search requests per endpoint:{" "}
    312                                                                 <kbd>{stats.maxConcurrentSearchRequestsPerEndpoint}</kbd>,
    313                                                         </li> : false
    314                                                 }
    315                                                 <li>timeout:{" "}<kbd>{stats.timeout} seconds</kbd></li>
    316                                         </ul>
     315                                                <div>Timeout: {" "}<kbd>{stats.timeout} seconds</kbd></div>
     316                                        </div>
    317317                                        <div> { _.pairs(stats.institutions).map(this.renderInstitution.bind(this, stats.isScan)) } </div>
    318318                                </div>
     
    508508}
    509509
    510 var routeFromLocation = function(com) {
     510var routeFromLocation = function() {
     511        // console.log("routeFromLocation: " + document.location);
     512        if (!this) throw "routeFromLocation must be bound to main";
    511513        var path = window.location.pathname.split('/');
    512514        if (path.length === 3) {
    513515                var p = path[2];
    514516                if (p === 'help') {
    515                         com.toHelp(false);
     517                        this.toHelp(false);
    516518                } else if (p === 'about') {
    517                         com.toAbout(false);
     519                        this.toAbout(false);
    518520                } else if (p === 'stats') {
    519                         com.toStatistics(false);
     521                        this.toStatistics(false);
    520522                } else {
    521                         com.toAggregator(false);
     523                        this.toAggregator(false);
    522524                }
    523525        } else {
    524                 com.toAggregator(false);
     526                this.toAggregator(false);
    525527        }
    526528};
     
    529531React.render(<Footer />, document.getElementById('footer') );
    530532
    531 window.onpopstate = function(event) {
    532         console.log("popped location: " + document.location + ", state: " + JSON.stringify(event.state));
    533         routeFromLocation(main);
    534 };
    535 
    536 window.main = main;
     533window.onpopstate = routeFromLocation.bind(main);
     534
     535routeFromLocation.bind(main)();
    537536
    538537})();
     
    544543
    545544
    546 
    547 
    548 
    549 
    550 
    551 
    552 
    553 
    554 
    555 
    556 
    557 
  • SRUAggregator/trunk/src/main/resources/assets/js/search.js

    r5971 r6043  
    6262                corpus.selected = true; // selected in the corpus view
    6363                corpus.expanded = false; // not expanded in the corpus view
    64                 corpus.priority = 1; // priority in corpus view
     64                corpus.priority = 1; // used for ordering search results in corpus view
    6565                corpus.index = index; // original order, used for stable sort
    6666        });
     
    164164        },
    165165
    166         timeout: 0,
    167166        nohits: {
    168167                requests: [],
     
    182181
    183182                        searchId: null,
    184                         hits: this.nohits,
     183                        timeout: 0,
     184                        hits: this.nohits,                     
    185185                };
    186186        },
     
    195195                        url: 'rest/corpora',
    196196                        success: function(json, textStatus, jqXHR) {
    197                                 this.setState({corpora : new Corpora(json, this.updateCorpora)});
     197                                if (this.isMounted()) {
     198                                        this.setState({corpora : new Corpora(json, this.updateCorpora)});
     199                                }
    198200                        }.bind(this),
    199201                });
     
    204206                        url: 'rest/languages',
    205207                        success: function(json, textStatus, jqXHR) {
    206                                 this.setState({languageMap : json});
     208                                if (this.isMounted()) {
     209                                        this.setState({languageMap : json});
     210                                }
    207211                        }.bind(this),
    208212                });
     
    233237                        success: function(searchId, textStatus, jqXHR) {
    234238                                // console.log("search ["+query+"] ok: ", searchId, jqXHR);
    235                                 this.setState({searchId : searchId});
    236                                 this.timeout = 250;
    237                                 setTimeout(this.refreshSearchResults, this.timeout);
     239                                var timeout = 250;
     240                                setTimeout(this.refreshSearchResults, timeout);
     241                                this.setState({ searchId: searchId, timeout: timeout });
    238242                        }.bind(this),
    239243                });
     
    241245
    242246        refreshSearchResults: function() {
    243                 if (!this.state.searchId) {
     247                if (!this.state.searchId || !this.isMounted()) {
    244248                        return;
    245249                }
     
    247251                        url: 'rest/search/'+this.state.searchId,
    248252                        success: function(json, textStatus, jqXHR) {
     253                                var timeout = this.state.timeout;
    249254                                if (json.requests.length > 0) {
    250                                         if (this.timeout < 10000) {
    251                                                 this.timeout = 1.5 * this.timeout;
     255                                        if (timeout < 10000) {
     256                                                timeout = 1.5 * timeout;
    252257                                        }
    253                                         setTimeout(this.refreshSearchResults, this.timeout);
    254                                         // console.log("new search in: " + this.timeout+ "ms");
     258                                        setTimeout(this.refreshSearchResults, timeout);
     259                                        // console.log("new search in: " + this.timeout + "ms");
    255260                                } else {
    256261                                        console.log("search ended; hits:", json);
    257262                                }
    258                                 this.setState({hits:json});
     263                                this.setState({ hits: json, timeout: timeout });
    259264                        }.bind(this),
    260265                });
     
    656661        },
    657662
    658         renderToolbox: function() {
    659                 if (this.props.requests.length > 0) {
    660                         return false;
    661                 }
    662                 return  React.createElement("div", {className: "toolbox float-left"},
    663                                         React.createElement("a", {className: "btn btn-default", href: this.props.getDownloadLink("text")},
    664                                                 React.createElement("span", {className: "glyphicon glyphicon-download-alt", 'aria-hidden': "true"}), " Download"
    665                                         )
    666                                 );
    667         },
    668 
    669663        renderProgressBar: function() {
    670664                var percents = 100 * this.props.results.length / (this.props.requests.length + this.props.results.length);
     
    693687        },
    694688
    695         renderKwicCheckbox: function() {
    696                 return  React.createElement("div", {className: "float-right", style: {marginRight:17}},
    697                                         React.createElement("div", {className: "btn-group", style: {display:"inline-block"}},
    698                                                 React.createElement("label", {forHtml: "inputKwic", className: "btn-default"},
    699                                                          this.state.displayKwic ?
    700                                                                 React.createElement("input", {id: "inputKwic", type: "checkbox", value: "kwic", checked: true, onChange: this.toggleKwic}) :
    701                                                                 React.createElement("input", {id: "inputKwic", type: "checkbox", value: "kwic", onChange: this.toggleKwic}),
    702                                                        
    703                                                         " " + ' ' +
    704                                                         "Display as Key Word In Context"
     689        renderDownloadLinks: function() {
     690                return (
     691                        React.createElement("div", {className: "dropdown"},
     692                                React.createElement("button", {className: "btn btn-default", 'aria-expanded': "false", 'data-toggle': "dropdown"},
     693                                        React.createElement("span", {className: "glyphicon glyphicon-download-alt", 'aria-hidden': "true"}),
     694                                        " ", " Download ", " ",
     695                                        React.createElement("span", {className: "caret"})
     696                                ),
     697                                React.createElement("ul", {className: "dropdown-menu"},
     698                                        React.createElement("li", null, " ", React.createElement("a", {href: this.props.getDownloadLink("csv")},
     699                                                        " ", " As CSV file")),
     700                                        React.createElement("li", null, " ", React.createElement("a", {href: this.props.getDownloadLink("excel")},
     701                                                        " ", " As Excel file")),
     702                                        React.createElement("li", null, " ", React.createElement("a", {href: this.props.getDownloadLink("tcf")},
     703                                                        " ", " As TCF file")),
     704                                        React.createElement("li", null, " ", React.createElement("a", {href: this.props.getDownloadLink("text")},
     705                                                        " ", " As Plain Text file"))
     706                                )
     707                        )
     708                );
     709        },
     710
     711        renderToolbox: function(hits) {
     712                if (hits <= 0) {
     713                        return false;
     714                }
     715                return  React.createElement("div", {key: "-toolbox-", style: {marginBottom:10}},
     716                                        React.createElement("div", {className: "toolbox float-left inline"},
     717                                                this.renderDownloadLinks()
     718                                        ),
     719                                        React.createElement("div", {className: "float-right inline", style: {marginTop:15}},
     720                                                React.createElement("div", {className: "btn-group", style: {display:"inline-block"}},
     721                                                        React.createElement("label", {forHtml: "inputKwic", className: "btn-default"},
     722                                                                 this.state.displayKwic ?
     723                                                                        React.createElement("input", {id: "inputKwic", type: "checkbox", value: "kwic", checked: true, onChange: this.toggleKwic}) :
     724                                                                        React.createElement("input", {id: "inputKwic", type: "checkbox", value: "kwic", onChange: this.toggleKwic}),
     725                                                               
     726                                                                " " + ' ' +
     727                                                                "Display as Key Word In Context"
     728                                                        )
    705729                                                )
    706730                                        )
     
    719743                                                React.createElement("div", {key: "-found-message-", style: margintop}, this.renderFoundMessage(hits), " "),
    720744                                                React.createElement("div", {key: "-progress-", style: margintop}, this.renderProgressBar()),
    721                                                 hits > 0 ?
    722                                                         React.createElement("div", {key: "-option-KWIC-", className: "row"},
    723                                                                 this.renderToolbox(),
    724                                                                 this.renderKwicCheckbox()
    725                                                         )
    726                                                         : false,
     745                                                this.renderToolbox(hits),
    727746                                                this.props.results.map(this.renderResultPanels)
    728747                                        )
  • SRUAggregator/trunk/src/main/resources/assets/js/search.jsx

    r5971 r6043  
    6262                corpus.selected = true; // selected in the corpus view
    6363                corpus.expanded = false; // not expanded in the corpus view
    64                 corpus.priority = 1; // priority in corpus view
     64                corpus.priority = 1; // used for ordering search results in corpus view
    6565                corpus.index = index; // original order, used for stable sort
    6666        });
     
    164164        },
    165165
    166         timeout: 0,
    167166        nohits: {
    168167                requests: [],
     
    182181
    183182                        searchId: null,
    184                         hits: this.nohits,
     183                        timeout: 0,
     184                        hits: this.nohits,                     
    185185                };
    186186        },
     
    195195                        url: 'rest/corpora',
    196196                        success: function(json, textStatus, jqXHR) {
    197                                 this.setState({corpora : new Corpora(json, this.updateCorpora)});
     197                                if (this.isMounted()) {
     198                                        this.setState({corpora : new Corpora(json, this.updateCorpora)});
     199                                }
    198200                        }.bind(this),
    199201                });
     
    204206                        url: 'rest/languages',
    205207                        success: function(json, textStatus, jqXHR) {
    206                                 this.setState({languageMap : json});
     208                                if (this.isMounted()) {
     209                                        this.setState({languageMap : json});
     210                                }
    207211                        }.bind(this),
    208212                });
     
    233237                        success: function(searchId, textStatus, jqXHR) {
    234238                                // console.log("search ["+query+"] ok: ", searchId, jqXHR);
    235                                 this.setState({searchId : searchId});
    236                                 this.timeout = 250;
    237                                 setTimeout(this.refreshSearchResults, this.timeout);
     239                                var timeout = 250;
     240                                setTimeout(this.refreshSearchResults, timeout);
     241                                this.setState({ searchId: searchId, timeout: timeout });
    238242                        }.bind(this),
    239243                });
     
    241245
    242246        refreshSearchResults: function() {
    243                 if (!this.state.searchId) {
     247                if (!this.state.searchId || !this.isMounted()) {
    244248                        return;
    245249                }
     
    247251                        url: 'rest/search/'+this.state.searchId,
    248252                        success: function(json, textStatus, jqXHR) {
     253                                var timeout = this.state.timeout;
    249254                                if (json.requests.length > 0) {
    250                                         if (this.timeout < 10000) {
    251                                                 this.timeout = 1.5 * this.timeout;
     255                                        if (timeout < 10000) {
     256                                                timeout = 1.5 * timeout;
    252257                                        }
    253                                         setTimeout(this.refreshSearchResults, this.timeout);
    254                                         // console.log("new search in: " + this.timeout+ "ms");
     258                                        setTimeout(this.refreshSearchResults, timeout);
     259                                        // console.log("new search in: " + this.timeout + "ms");
    255260                                } else {
    256261                                        console.log("search ended; hits:", json);
    257262                                }
    258                                 this.setState({hits:json});
     263                                this.setState({ hits: json, timeout: timeout });
    259264                        }.bind(this),
    260265                });
     
    656661        },
    657662
    658         renderToolbox: function() {
    659                 if (this.props.requests.length > 0) {
    660                         return false;
    661                 }
    662                 return  <div className="toolbox float-left">
    663                                         <a className="btn btn-default" href={this.props.getDownloadLink("text")}>
    664                                                 <span className="glyphicon glyphicon-download-alt" aria-hidden="true"/> Download
    665                                         </a>
    666                                 </div>;
    667         },
    668 
    669663        renderProgressBar: function() {
    670664                var percents = 100 * this.props.results.length / (this.props.requests.length + this.props.results.length);
     
    693687        },
    694688
    695         renderKwicCheckbox: function() {
    696                 return  <div className="float-right" style={{marginRight:17}}>
    697                                         <div className="btn-group" style={{display:"inline-block"}}>
    698                                                 <label forHtml="inputKwic" className="btn-default">
    699                                                         { this.state.displayKwic ?
    700                                                                 <input id="inputKwic" type="checkbox" value="kwic" checked onChange={this.toggleKwic} /> :
    701                                                                 <input id="inputKwic" type="checkbox" value="kwic" onChange={this.toggleKwic} />
    702                                                         }
    703                                                         &nbsp;
    704                                                         Display as Key Word In Context
    705                                                 </label>
     689        renderDownloadLinks: function() {
     690                return (
     691                        <div className="dropdown">
     692                                <button className="btn btn-default" aria-expanded="false" data-toggle="dropdown" >
     693                                        <span className="glyphicon glyphicon-download-alt" aria-hidden="true"/>
     694                                        {" "} Download {" "}
     695                                        <span className="caret"/>
     696                                </button>
     697                                <ul className="dropdown-menu">
     698                                        <li> <a href={this.props.getDownloadLink("csv")}>
     699                                                        {" "} As CSV file</a></li>
     700                                        <li> <a href={this.props.getDownloadLink("excel")}>
     701                                                        {" "} As Excel file</a></li>
     702                                        <li> <a href={this.props.getDownloadLink("tcf")}>
     703                                                        {" "} As TCF file</a></li>
     704                                        <li> <a href={this.props.getDownloadLink("text")}>
     705                                                        {" "} As Plain Text file</a></li>
     706                                </ul>
     707                        </div>
     708                );
     709        },
     710
     711        renderToolbox: function(hits) {
     712                if (hits <= 0) {
     713                        return false;
     714                }
     715                return  <div key="-toolbox-" style={{marginBottom:10}}>
     716                                        <div className="toolbox float-left inline">
     717                                                {this.renderDownloadLinks()}
     718                                        </div>
     719                                        <div className="float-right inline" style={{marginTop:15}}>
     720                                                <div className="btn-group" style={{display:"inline-block"}}>
     721                                                        <label forHtml="inputKwic" className="btn-default">
     722                                                                { this.state.displayKwic ?
     723                                                                        <input id="inputKwic" type="checkbox" value="kwic" checked onChange={this.toggleKwic} /> :
     724                                                                        <input id="inputKwic" type="checkbox" value="kwic" onChange={this.toggleKwic} />
     725                                                                }
     726                                                                &nbsp;
     727                                                                Display as Key Word In Context
     728                                                        </label>
     729                                                </div>
    706730                                        </div>
    707731                                </div>;
     
    719743                                                <div key="-found-message-" style={margintop}>{this.renderFoundMessage(hits)} </div>
    720744                                                <div key="-progress-" style={margintop}>{this.renderProgressBar()}</div>
    721                                                 {hits > 0 ?
    722                                                         <div key="-option-KWIC-" className="row">
    723                                                                 {this.renderToolbox()}
    724                                                                 {this.renderKwicCheckbox()}
    725                                                         </div>
    726                                                         : false }
     745                                                {this.renderToolbox(hits)}
    727746                                                {this.props.results.map(this.renderResultPanels)}
    728747                                        </ReactCSSTransitionGroup>
Note: See TracChangeset for help on using the changeset viewer.