diff --git a/.gitignore b/.gitignore index b1560f30bd683b1965da24debdc6572a10556488..c1b2f25afd8086eb8bdcfae699eb60df23b123fa 100644 --- a/.gitignore +++ b/.gitignore @@ -5,3 +5,4 @@ .vagrant/ vm/webapps/ vm/data/ +vm/test/ diff --git a/vipra-cmd/src/main/java/de/vipra/cmd/Main.java b/vipra-cmd/src/main/java/de/vipra/cmd/Main.java index 5aa791b0622b3c23c716b7aa598f51d446ef02a3..f1ae2a5e2c6832060e2fefb75f808064b62ae224 100644 --- a/vipra-cmd/src/main/java/de/vipra/cmd/Main.java +++ b/vipra-cmd/src/main/java/de/vipra/cmd/Main.java @@ -1,6 +1,7 @@ package de.vipra.cmd; import static de.vipra.cmd.CmdOptions.OPT_CLEAR; +import static de.vipra.cmd.CmdOptions.OPT_CONFIG; import static de.vipra.cmd.CmdOptions.OPT_DEBUG; import static de.vipra.cmd.CmdOptions.OPT_DEFAULTS; import static de.vipra.cmd.CmdOptions.OPT_HELP; @@ -9,7 +10,6 @@ import static de.vipra.cmd.CmdOptions.OPT_SHELL; import static de.vipra.cmd.CmdOptions.OPT_SILENT; import static de.vipra.cmd.CmdOptions.OPT_STATS; import static de.vipra.cmd.CmdOptions.OPT_TEST; -import static de.vipra.cmd.CmdOptions.OPT_CONFIG; import java.util.ArrayList; import java.util.List; diff --git a/vipra-cmd/src/main/java/de/vipra/cmd/ex/AnalyzerException.java b/vipra-cmd/src/main/java/de/vipra/cmd/ex/AnalyzerException.java new file mode 100644 index 0000000000000000000000000000000000000000..70b6207b65a7e148c98cb7344b7535bc4bb529df --- /dev/null +++ b/vipra-cmd/src/main/java/de/vipra/cmd/ex/AnalyzerException.java @@ -0,0 +1,15 @@ +package de.vipra.cmd.ex; + +public class AnalyzerException extends Exception { + + private static final long serialVersionUID = 1L; + + public AnalyzerException(String msg) { + super(msg); + } + + public AnalyzerException(Exception e) { + super(e); + } + +} diff --git a/vipra-cmd/src/main/java/de/vipra/cmd/ex/LDAAnalyzerException.java b/vipra-cmd/src/main/java/de/vipra/cmd/ex/LDAAnalyzerException.java deleted file mode 100644 index bf55ee835d9827c5c78d77a099b0f0aedae22078..0000000000000000000000000000000000000000 --- a/vipra-cmd/src/main/java/de/vipra/cmd/ex/LDAAnalyzerException.java +++ /dev/null @@ -1,15 +0,0 @@ -package de.vipra.cmd.ex; - -public class LDAAnalyzerException extends Exception { - - private static final long serialVersionUID = 1L; - - public LDAAnalyzerException(String msg) { - super(msg); - } - - public LDAAnalyzerException(Exception e) { - super(e); - } - -} diff --git a/vipra-cmd/src/main/java/de/vipra/cmd/ex/PreprocessorException.java b/vipra-cmd/src/main/java/de/vipra/cmd/ex/PreprocessorException.java deleted file mode 100644 index 1b4f6ade0e0a299e38c65220ab07ec95201ba605..0000000000000000000000000000000000000000 --- a/vipra-cmd/src/main/java/de/vipra/cmd/ex/PreprocessorException.java +++ /dev/null @@ -1,15 +0,0 @@ -package de.vipra.cmd.ex; - -public class PreprocessorException extends Exception { - - private static final long serialVersionUID = 1L; - - public PreprocessorException(String msg) { - super(msg); - } - - public PreprocessorException(Exception e) { - super(e); - } - -} diff --git a/vipra-cmd/src/main/java/de/vipra/cmd/ex/ProcessorException.java b/vipra-cmd/src/main/java/de/vipra/cmd/ex/ProcessorException.java new file mode 100644 index 0000000000000000000000000000000000000000..4889e6fcac0f66993e4126b836a4991034c5d6d1 --- /dev/null +++ b/vipra-cmd/src/main/java/de/vipra/cmd/ex/ProcessorException.java @@ -0,0 +1,15 @@ +package de.vipra.cmd.ex; + +public class ProcessorException extends Exception { + + private static final long serialVersionUID = 1L; + + public ProcessorException(String msg) { + super(msg); + } + + public ProcessorException(Exception e) { + super(e); + } + +} diff --git a/vipra-cmd/src/main/java/de/vipra/cmd/file/DynNMFFilebase.java b/vipra-cmd/src/main/java/de/vipra/cmd/file/DynNMFFilebase.java new file mode 100644 index 0000000000000000000000000000000000000000..321d542b606261816af1d6375dcaac625437aab0 --- /dev/null +++ b/vipra-cmd/src/main/java/de/vipra/cmd/file/DynNMFFilebase.java @@ -0,0 +1,63 @@ +package de.vipra.cmd.file; + +import java.io.File; +import java.io.IOException; +import java.util.Calendar; +import java.util.Date; +import java.util.GregorianCalendar; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import de.vipra.cmd.ex.FilebaseException; +import de.vipra.util.Constants.WindowResolution; +import de.vipra.util.FileUtils; +import de.vipra.util.model.ArticleFull; + +public class DynNMFFilebase extends Filebase { + + private final File modelDir; + private final WindowResolution windowResolution; + private final Map<String, File> dirMap; + + public DynNMFFilebase(File dataDir, WindowResolution windowResolution) throws FilebaseException { + super(dataDir, "dynlda"); + this.modelDir = super.getModelDir(); + this.windowResolution = windowResolution; + this.dirMap = new HashMap<>(); + } + + @Override + public void write(List<ArticleFull> articles) throws IOException { + if (!articles.isEmpty()) { + for (ArticleFull article : articles) { + File windowDir = getWindowDir(article.getDate()); + File articleFile = new File(windowDir, article.getId().toString()); + FileUtils.writeStringToFile(articleFile, article.getTitle() + "\n" + article.getProcessedText()); + } + } + } + + private File getWindowDir(Date date) { + Calendar c = new GregorianCalendar(); + c.setTime(date); + String dirName = "" + c.get(Calendar.YEAR); + switch (windowResolution) { + case MONTHLY: + break; + case QUARTERLY: + break; + case YEARLY: + default: + break; + } + File dir = dirMap.get(dirName); + if (dir == null) { + dir = new File(modelDir, dirName); + dir.mkdirs(); + dirMap.put(dirName, dir); + } + return dir; + } + +} diff --git a/vipra-cmd/src/main/java/de/vipra/cmd/file/Filebase.java b/vipra-cmd/src/main/java/de/vipra/cmd/file/Filebase.java index 9730d4059970d6f35e2a2ee82e34164457b3042c..58c0f596a17ec749b88aa4768561d1fc1869e406 100644 --- a/vipra-cmd/src/main/java/de/vipra/cmd/file/Filebase.java +++ b/vipra-cmd/src/main/java/de/vipra/cmd/file/Filebase.java @@ -3,6 +3,8 @@ package de.vipra.cmd.file; import java.io.Closeable; import java.io.File; import java.io.IOException; +import java.util.ArrayList; +import java.util.List; import de.vipra.cmd.ex.FilebaseException; import de.vipra.util.Config; @@ -12,12 +14,16 @@ import de.vipra.util.model.ArticleFull; public abstract class Filebase implements Closeable { + private final String modelName; private final File modelDir; - private final File modelFile; private final FilebaseIndex index; private final FilebaseVocabulary vocab; + private final List<ArticleFull> articles; + + private final int bufferMaxSize = 100; public Filebase(File dataDir, String modelName) throws FilebaseException { + this.modelName = modelName; this.modelDir = new File(dataDir, modelName); if (!modelDir.exists()) { if (!modelDir.mkdirs()) { @@ -25,16 +31,20 @@ public abstract class Filebase implements Closeable { } } try { - this.modelFile = new File(modelDir, modelName); this.index = new FilebaseIndex(new File(modelDir, Constants.INDEX_FILE)); this.vocab = new FilebaseVocabulary(new File(modelDir, Constants.VOCAB_FILE)); } catch (IOException e) { throw new FilebaseException("could not read index: " + e.getMessage()); } + this.articles = new ArrayList<>(bufferMaxSize); + } + + public File getModelDir() { + return modelDir; } public File getModelFile() { - return modelFile; + return new File(modelDir, modelName); } public FilebaseIndex getIndex() { @@ -45,30 +55,43 @@ public abstract class Filebase implements Closeable { return vocab; } - public void remove(ArticleFull article) throws FilebaseException { - remove(article.getId().toString()); + public List<ArticleFull> getArticles() { + return articles; } @Override public void close() throws IOException { - write(); + write(articles); index.close(); vocab.close(); } - public abstract void add(ArticleFull article) throws FilebaseException; + public void add(ArticleFull article) throws FilebaseException { + String[] words = article.getProcessedText().split("\\s+"); + vocab.addVocabulary(words); + index.add(article.getId().toString()); + articles.add(article); - public abstract void remove(String id) throws FilebaseException; + if (articles.size() >= bufferMaxSize) { + try { + write(articles); + } catch (IOException e) { + throw new FilebaseException(e); + } + } + } - public abstract void write() throws IOException; + public abstract void write(List<ArticleFull> articles) throws IOException; public static Filebase getFilebase(Config config) throws FilebaseException, ConfigException { File dataDir = config.getDataDirectory(); switch (config.analyzer) { + case DYNNMF: + return new DynNMFFilebase(dataDir, config.windowResolution); case JGIBB: - case DEFAULT: - default: return new JGibbFilebase(dataDir); + default: + return null; } } diff --git a/vipra-cmd/src/main/java/de/vipra/cmd/file/JGibbFilebase.java b/vipra-cmd/src/main/java/de/vipra/cmd/file/JGibbFilebase.java index 1fb52be44e2265bd33d3730eee3f7098e9ecbb4e..0883a698b4212a3b37a8161dd9817416fc85ef4f 100644 --- a/vipra-cmd/src/main/java/de/vipra/cmd/file/JGibbFilebase.java +++ b/vipra-cmd/src/main/java/de/vipra/cmd/file/JGibbFilebase.java @@ -3,53 +3,22 @@ package de.vipra.cmd.file; import java.io.File; import java.io.IOException; import java.io.RandomAccessFile; -import java.util.ArrayList; import java.util.List; import de.vipra.cmd.ex.FilebaseException; -import de.vipra.util.ex.NotImplementedException; import de.vipra.util.model.ArticleFull; public class JGibbFilebase extends Filebase { private final File modelFile; - private final FilebaseIndex index; - private final FilebaseVocabulary vocab; - private final List<ArticleFull> articles; - - private final int bufferMaxSize = 100; public JGibbFilebase(File dataDir) throws FilebaseException { super(dataDir, "jgibb"); this.modelFile = getModelFile(); - this.index = getIndex(); - this.vocab = getVocab(); - this.articles = new ArrayList<>(); - } - - @Override - public void add(ArticleFull article) throws FilebaseException { - String[] words = article.getProcessedText().split("\\s+"); - vocab.addVocabulary(words); - index.add(article.getId().toString()); - articles.add(article); - - if (articles.size() >= bufferMaxSize) { - try { - write(); - } catch (IOException e) { - throw new FilebaseException(e); - } - } - } - - @Override - public void remove(String id) { - throw new NotImplementedException(); } @Override - public void write() throws IOException { + public void write(List<ArticleFull> articles) throws IOException { if (!articles.isEmpty()) { boolean linesep = modelFile.exists(); RandomAccessFile raf = new RandomAccessFile(modelFile, "rw"); diff --git a/vipra-cmd/src/main/java/de/vipra/cmd/lda/LDAAnalyzer.java b/vipra-cmd/src/main/java/de/vipra/cmd/lda/Analyzer.java similarity index 69% rename from vipra-cmd/src/main/java/de/vipra/cmd/lda/LDAAnalyzer.java rename to vipra-cmd/src/main/java/de/vipra/cmd/lda/Analyzer.java index d69375d39b31768cfb3fa1f06e56d43e519ebb1b..0e1c87c7ffe1245794732209401bdd6e0c731f81 100644 --- a/vipra-cmd/src/main/java/de/vipra/cmd/lda/LDAAnalyzer.java +++ b/vipra-cmd/src/main/java/de/vipra/cmd/lda/Analyzer.java @@ -2,18 +2,18 @@ package de.vipra.cmd.lda; import java.util.List; -import de.vipra.cmd.ex.LDAAnalyzerException; +import de.vipra.cmd.ex.AnalyzerException; import de.vipra.util.Config; import de.vipra.util.ConvertStream; import de.vipra.util.WordMap; import de.vipra.util.model.TopicFull; import de.vipra.util.model.TopicRef; -public abstract class LDAAnalyzer { +public abstract class Analyzer { private final String name; - protected LDAAnalyzer(String name) { + protected Analyzer(String name) { this.name = name; } @@ -21,9 +21,9 @@ public abstract class LDAAnalyzer { return name; } - public abstract void init(Config config, WordMap wordMap) throws LDAAnalyzerException; + public abstract void init(Config config, WordMap wordMap) throws AnalyzerException; - public abstract void analyze() throws LDAAnalyzerException; + public abstract void analyze() throws AnalyzerException; /** * Returns a converting stream of topics, read from the topic definition @@ -31,9 +31,9 @@ public abstract class LDAAnalyzer { * assigned to that topic with a certain likeliness. * * @return topic definition stream - * @throws LDAAnalyzerException + * @throws AnalyzerException */ - public abstract ConvertStream<TopicFull> getTopicDefinitions() throws LDAAnalyzerException; + public abstract ConvertStream<TopicFull> getTopicDefinitions() throws AnalyzerException; /** * Returns a converting stream of lists of topic references. Normally, topic @@ -42,18 +42,21 @@ public abstract class LDAAnalyzer { * * @return stream of lists of topic references per document (ordered by * index) - * @throws LDAAnalyzerException + * @throws AnalyzerException */ - public abstract ConvertStream<List<TopicRef>> getTopics() throws LDAAnalyzerException; + public abstract ConvertStream<List<TopicRef>> getTopics() throws AnalyzerException; - public static LDAAnalyzer getAnalyzer(Config config, WordMap wordMap) throws LDAAnalyzerException { - LDAAnalyzer analyzer = null; + public static Analyzer getAnalyzer(Config config, WordMap wordMap) throws AnalyzerException { + Analyzer analyzer = null; switch (config.analyzer) { + case DYNNMF: + analyzer = new DynNMFAnalyzer(); + break; case JGIBB: - case DEFAULT: - default: - analyzer = new JGibbLDAAnalyzer(); + analyzer = new JGibbAnalyzer(); break; + default: + return null; } analyzer.init(config, wordMap); return analyzer; diff --git a/vipra-cmd/src/main/java/de/vipra/cmd/lda/DynNMFAnalyzer.java b/vipra-cmd/src/main/java/de/vipra/cmd/lda/DynNMFAnalyzer.java new file mode 100644 index 0000000000000000000000000000000000000000..8112c8667f6f72bc11332b8ef2424bd34f04c659 --- /dev/null +++ b/vipra-cmd/src/main/java/de/vipra/cmd/lda/DynNMFAnalyzer.java @@ -0,0 +1,42 @@ +package de.vipra.cmd.lda; + +import java.util.List; + +import de.vipra.cmd.ex.AnalyzerException; +import de.vipra.util.Config; +import de.vipra.util.ConvertStream; +import de.vipra.util.WordMap; +import de.vipra.util.model.TopicFull; +import de.vipra.util.model.TopicRef; + +public class DynNMFAnalyzer extends Analyzer { + + protected DynNMFAnalyzer() { + super("Dynamic NMF Analyzer"); + } + + @Override + public void init(Config config, WordMap wordMap) throws AnalyzerException { + // TODO Auto-generated method stub + + } + + @Override + public void analyze() throws AnalyzerException { + // TODO Auto-generated method stub + + } + + @Override + public ConvertStream<TopicFull> getTopicDefinitions() throws AnalyzerException { + // TODO Auto-generated method stub + return null; + } + + @Override + public ConvertStream<List<TopicRef>> getTopics() throws AnalyzerException { + // TODO Auto-generated method stub + return null; + } + +} diff --git a/vipra-cmd/src/main/java/de/vipra/cmd/lda/JGibbLDAAnalyzer.java b/vipra-cmd/src/main/java/de/vipra/cmd/lda/JGibbAnalyzer.java similarity index 86% rename from vipra-cmd/src/main/java/de/vipra/cmd/lda/JGibbLDAAnalyzer.java rename to vipra-cmd/src/main/java/de/vipra/cmd/lda/JGibbAnalyzer.java index 65a012c8f48861a05dd795db154ee25d73fc6c7f..d1c486c15eb3dfe9d76e99c3150a1137b7a32a79 100644 --- a/vipra-cmd/src/main/java/de/vipra/cmd/lda/JGibbLDAAnalyzer.java +++ b/vipra-cmd/src/main/java/de/vipra/cmd/lda/JGibbAnalyzer.java @@ -12,7 +12,7 @@ import java.util.Map.Entry; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; -import de.vipra.cmd.ex.LDAAnalyzerException; +import de.vipra.cmd.ex.AnalyzerException; import de.vipra.util.Config; import de.vipra.util.Constants; import de.vipra.util.ConvertStream; @@ -29,9 +29,9 @@ import jgibblda.Inferencer; import jgibblda.LDACmdOption; import jgibblda.Model; -public class JGibbLDAAnalyzer extends LDAAnalyzer { +public class JGibbAnalyzer extends Analyzer { - public static final Logger log = LogManager.getLogger(JGibbLDAAnalyzer.class); + public static final Logger log = LogManager.getLogger(JGibbAnalyzer.class); public static final String NAME = "jgibb"; private File dataDir; @@ -40,18 +40,18 @@ public class JGibbLDAAnalyzer extends LDAAnalyzer { private LDACmdOption options; private WordMap wordMap; - protected JGibbLDAAnalyzer() { + protected JGibbAnalyzer() { super("JGibb Analyzer"); } @Override - public void init(Config config, WordMap wordMap) throws LDAAnalyzerException { + public void init(Config config, WordMap wordMap) throws AnalyzerException { options = new LDACmdOption(); try { dataDir = config.getDataDirectory(); } catch (ConfigException e) { - throw new LDAAnalyzerException(e); + throw new AnalyzerException(e); } modelDir = new File(dataDir, NAME); @@ -83,15 +83,15 @@ public class JGibbLDAAnalyzer extends LDAAnalyzer { } @Override - public void analyze() throws LDAAnalyzerException { + public void analyze() throws AnalyzerException { if (!modelFile.exists()) { - throw new LDAAnalyzerException("model file does not exist: " + modelFile.getAbsolutePath()); + throw new AnalyzerException("model file does not exist: " + modelFile.getAbsolutePath()); } estimate(); } @Override - public ConvertStream<TopicFull> getTopicDefinitions() throws LDAAnalyzerException { + public ConvertStream<TopicFull> getTopicDefinitions() throws AnalyzerException { File twords = new File(modelDir, NAME + ".twords"); try { return new ConvertStream<TopicFull>(twords) { @@ -139,12 +139,12 @@ public class JGibbLDAAnalyzer extends LDAAnalyzer { } }; } catch (FileNotFoundException e) { - throw new LDAAnalyzerException(e); + throw new AnalyzerException(e); } } @Override - public ConvertStream<List<TopicRef>> getTopics() throws LDAAnalyzerException { + public ConvertStream<List<TopicRef>> getTopics() throws AnalyzerException { File tassign = new File(modelDir, NAME + ".tassign"); try { return new ConvertStream<List<TopicRef>>(tassign) { @@ -177,7 +177,7 @@ public class JGibbLDAAnalyzer extends LDAAnalyzer { } }; } catch (FileNotFoundException e) { - throw new LDAAnalyzerException(e); + throw new AnalyzerException(e); } } diff --git a/vipra-cmd/src/main/java/de/vipra/cmd/option/ImportCommand.java b/vipra-cmd/src/main/java/de/vipra/cmd/option/ImportCommand.java index 4d87987548557d5fc715bf4632b9ef68200e28f2..6eeed9e277c5f9f67e1c2cb5ea10ada951aadf6f 100644 --- a/vipra-cmd/src/main/java/de/vipra/cmd/option/ImportCommand.java +++ b/vipra-cmd/src/main/java/de/vipra/cmd/option/ImportCommand.java @@ -20,7 +20,7 @@ import org.json.simple.parser.JSONParser; import de.vipra.cmd.file.Filebase; import de.vipra.cmd.file.FilebaseIndex; -import de.vipra.cmd.lda.LDAAnalyzer; +import de.vipra.cmd.lda.Analyzer; import de.vipra.cmd.text.ProcessedText; import de.vipra.cmd.text.Processor; import de.vipra.util.Config; @@ -58,7 +58,7 @@ public class ImportCommand implements Command { private Filebase filebase; private Processor preprocessor; private WordMap wordMap; - private LDAAnalyzer analyzer; + private Analyzer analyzer; private Client elasticClient; private ElasticSerializer<ArticleFull> elasticSerializer; @@ -187,7 +187,7 @@ public class ImportCommand implements Command { filebase = Filebase.getFilebase(config); preprocessor = Processor.getProcessor(config); wordMap = new WordMap(dbWords); - analyzer = LDAAnalyzer.getAnalyzer(config, wordMap); + analyzer = Analyzer.getAnalyzer(config, wordMap); elasticClient = ESClient.getClient(config); elasticSerializer = new ElasticSerializer<>(ArticleFull.class); diff --git a/vipra-cmd/src/main/java/de/vipra/cmd/text/CoreNLPProcessor.java b/vipra-cmd/src/main/java/de/vipra/cmd/text/CoreNLPProcessor.java index b2b4605beea50cbb13d183ff17a2d21603920ec7..620c9189c615474b86806761253ce7503e52f203 100644 --- a/vipra-cmd/src/main/java/de/vipra/cmd/text/CoreNLPProcessor.java +++ b/vipra-cmd/src/main/java/de/vipra/cmd/text/CoreNLPProcessor.java @@ -3,7 +3,7 @@ package de.vipra.cmd.text; import java.util.List; import java.util.Properties; -import de.vipra.cmd.ex.PreprocessorException; +import de.vipra.cmd.ex.ProcessorException; import edu.stanford.nlp.ling.CoreAnnotations.SentencesAnnotation; import edu.stanford.nlp.ling.CoreAnnotations.TokensAnnotation; import edu.stanford.nlp.ling.CoreLabel; @@ -28,7 +28,7 @@ public class CoreNLPProcessor extends Processor { } @Override - public ProcessedText process(String input) throws PreprocessorException { + public ProcessedText process(String input) throws ProcessorException { Annotation doc = new Annotation(input.toLowerCase()); nlp.annotate(doc); StringBuilder sb = new StringBuilder(); diff --git a/vipra-cmd/src/main/java/de/vipra/cmd/text/Processor.java b/vipra-cmd/src/main/java/de/vipra/cmd/text/Processor.java index 51498e5be87b107f348bcee178519187f44a6132..6ea52b604972b155160ccdbfd00bbb64d6225d3a 100644 --- a/vipra-cmd/src/main/java/de/vipra/cmd/text/Processor.java +++ b/vipra-cmd/src/main/java/de/vipra/cmd/text/Processor.java @@ -2,7 +2,7 @@ package de.vipra.cmd.text; import java.util.List; -import de.vipra.cmd.ex.PreprocessorException; +import de.vipra.cmd.ex.ProcessorException; import de.vipra.util.Config; import de.vipra.util.Constants; @@ -18,7 +18,7 @@ public abstract class Processor { return name; } - public abstract ProcessedText process(String input) throws PreprocessorException; + public abstract ProcessedText process(String input) throws ProcessorException; public static Processor getProcessor(Config config) { List<String> stopWords = Constants.STOPWORDS; diff --git a/vipra-rest/src/main/java/de/vipra/rest/resource/SearchResource.java b/vipra-rest/src/main/java/de/vipra/rest/resource/SearchResource.java index faf5f0e78b3a154d089ecc8933e54034c46fe2f3..49f27b9d0f090c9fe9bc7d7703b68e46cbb750d7 100644 --- a/vipra-rest/src/main/java/de/vipra/rest/resource/SearchResource.java +++ b/vipra-rest/src/main/java/de/vipra/rest/resource/SearchResource.java @@ -29,7 +29,6 @@ import de.vipra.rest.model.Wrapper; import de.vipra.util.Config; import de.vipra.util.ESClient; import de.vipra.util.MongoUtils; -import de.vipra.util.StringUtils; import de.vipra.util.ex.ConfigException; import de.vipra.util.model.ArticleFull; @@ -50,8 +49,7 @@ public class SearchResource { @GET @Produces(MediaType.APPLICATION_JSON) public Response doSearch(@QueryParam("skip") Integer skip, @QueryParam("limit") Integer limit, - @QueryParam("excerpt") Integer excerpt, @QueryParam("fields") String fields, - @QueryParam("query") String query) { + @QueryParam("fields") String fields, @QueryParam("query") String query) { Wrapper<List<ArticleFull>> res = new Wrapper<>(); if (skip == null || skip < 0) @@ -60,9 +58,6 @@ public class SearchResource { if (limit == null || limit < 0) limit = 20; - if (excerpt == null || excerpt < 0) - excerpt = 250; - if (query == null || query.isEmpty() || limit == 0) return res.noContent(); @@ -88,10 +83,10 @@ public class SearchResource { article.setId(MongoUtils.objectId(hit.getId())); if (allowedFields == null || allowedFields.contains("title")) article.setTitle(source.get("title").toString()); - if (allowedFields == null || allowedFields.contains("text")) - article.setText(StringUtils.ellipsize(source.get("text").toString(), excerpt)); if (allowedFields == null || allowedFields.contains("date")) article.setDate(source.get("date").toString()); + if (allowedFields == null || allowedFields.contains("excerpt")) + article.setText(source.get("excerpt").toString()); article.addMeta("score", hit.getScore()); articles.add(article); } diff --git a/vipra-ui/css/app.css b/vipra-ui/css/app.css index 26bd0d5bdfb0ccce4dc5ccb25721f3907329829a..02ae7baff2ce3d300f2abc19665ab11bccdc583e 100644 --- a/vipra-ui/css/app.css +++ b/vipra-ui/css/app.css @@ -1,2 +1,2 @@ -html{position:relative;min-height:100%}body{padding-bottom:20px;margin-bottom:60px}.heading{-webkit-touch-callout:none;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;cursor:default;background:transparent url(/img/logo.svg) no-repeat 50% 50%;background-size:contain;height:125px;margin:25px 0}.search-results{padding:15px}.search-results .search-result{margin-bottom:20px}.search-results .search-result a{font-size:1.5rem}.ellipsize{white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.navbar-default .collapse:not(.in) .navbar-nav>.active>a,.navbar-default .collapse:not(.in) .navbar-nav>.active>a:focus,.navbar-default .collapse:not(.in) .navbar-nav>.active>a:hover{border-bottom:3px solid;padding-bottom:12px}.navbar-default .navbar-header{padding:0 10px}.navbar-default .navbar-brand{background:transparent url(/img/logo.svg) no-repeat 50% 50%;background-size:contain}.navbar-default .navbar-brand.spin,.navbar-default .navbar-brand:hover:not(.spin){-webkit-animation:a 4s linear infinite;animation:a 4s linear infinite}.row-spaced{margin-top:15px;margin-bottom:15px}.footer{position:absolute;bottom:0;width:100%;height:50px;border-top-width:1px;border-top-style:solid}.noselect{-webkit-touch-callout:none;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;cursor:default}@-webkit-keyframes a{to{-webkit-transform:rotateY(1turn)}}@keyframes a{to{-webkit-transform:rotateY(1turn);transform:rotateY(1turn)}} -/*# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbImFwcC5sZXNzIiwiYXBwLmNzcyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxLQUNFLGtCQUFBLEFBQ0EsZUFBQSxDQ0NELEFERUQsS0FDRSxvQkFBQSxBQUVBLGtCQUFBLENDQUQsQURHRCxTQXNFRSwyQkFBQSxBQUNBLHlCQUFBLEFBQ0Esc0JBQUEsQUFDQSxxQkFBQSxBQUNBLGlCQUFBLEFBQ0EsZUFBQSxBQXpFQSw0REFBQSxBQUNBLHdCQUFBLEFBQ0EsYUFBQSxBQUNBLGFBQUEsQ0NJRCxBRERELGdCQUNFLFlBQUEsQ0NHRCxBREpELCtCQUlJLGtCQUFBLENDR0gsQURQRCxpQ0FPTSxnQkFBQSxDQ0dMLEFERUQsV0FDRSxtQkFBQSxBQUNBLGdCQUFBLEFBQ0Esc0JBQUEsQ0NBRCxBRE1LLHVMQUdFLHdCQUFBLEFBQ0EsbUJBQUEsQ0NKUCxBREhELCtCQWFJLGNBQUEsQ0NQSCxBRE5ELDhCQWlCSSw0REFBQSxBQUNBLHVCQUFBLENDUkgsQURTRyxrRkFFRSx1Q0FBQSxBQUVBLDhCQUFBLENDUEwsQURZRCxZQUNFLGdCQUFBLEFBQ0Esa0JBQUEsQ0NWRCxBRGFELFFBQ0Usa0JBQUEsQUFDQSxTQUFBLEFBQ0EsV0FBQSxBQUVBLFlBQUEsQUFDQSxxQkFBQSxBQUNBLHNCQUFBLENDWEQsQURjRCxVQUNFLDJCQUFBLEFBQ0EseUJBQUEsQUFDQSxzQkFBQSxBQUNBLHFCQUFBLEFBQ0EsaUJBQUEsQUFDQSxjQUFBLENDWkQsQURnQkQscUJBQTBCLEdBQU8sZ0NBQUEsQ0NQOUIsQ0FDRixBRE9ELGFBQWtCLEdBQU8saUNBQUEsQUFBb0Msd0JBQUEsQ0NGMUQsQ0FDRiIsImZpbGUiOiJhcHAuY3NzIiwic291cmNlc0NvbnRlbnQiOlsiaHRtbCB7XG4gIHBvc2l0aW9uOiByZWxhdGl2ZTtcbiAgbWluLWhlaWdodDogMTAwJTtcbn1cblxuYm9keSB7XG4gIHBhZGRpbmctYm90dG9tOiAyMHB4O1xuICAvKiBNYXJnaW4gYm90dG9tIGJ5IGZvb3RlciBoZWlnaHQgKi9cbiAgbWFyZ2luLWJvdHRvbTogNjBweDtcbn1cblxuLmhlYWRpbmcge1xuICAubm9zZWxlY3Q7XG4gIGJhY2tncm91bmQ6IHRyYW5zcGFyZW50IHVybCgvaW1nL2xvZ28uc3ZnKSBuby1yZXBlYXQgNTAlIDUwJTtcbiAgYmFja2dyb3VuZC1zaXplOiBjb250YWluO1xuICBoZWlnaHQ6IDEyNXB4O1xuICBtYXJnaW46IDI1cHggMDtcbn1cblxuLnNlYXJjaC1yZXN1bHRzIHtcbiAgcGFkZGluZzogMTVweDtcblxuICAuc2VhcmNoLXJlc3VsdCB7XG4gICAgbWFyZ2luLWJvdHRvbTogMjBweDtcblxuICAgIGEge1xuICAgICAgZm9udC1zaXplOiAxLjVyZW07XG4gICAgfVxuICB9XG59XG5cbi5lbGxpcHNpemUge1xuICB3aGl0ZS1zcGFjZTogbm93cmFwO1xuICBvdmVyZmxvdzogaGlkZGVuO1xuICB0ZXh0LW92ZXJmbG93OiBlbGxpcHNpcztcbn1cblxuLm5hdmJhci1kZWZhdWx0IHtcbiAgLmNvbGxhcHNlOm5vdCguaW4pIHtcbiAgICAubmF2YmFyLW5hdiA+IC5hY3RpdmUge1xuICAgICAgJj4gYSxcbiAgICAgICY+IGE6aG92ZXIsXG4gICAgICAmPiBhOmZvY3VzIHtcbiAgICAgICAgYm9yZGVyLWJvdHRvbTogM3B4IHNvbGlkO1xuICAgICAgICBwYWRkaW5nLWJvdHRvbTogMTJweDtcbiAgICAgIH1cbiAgICB9XG4gIH1cblxuICAubmF2YmFyLWhlYWRlciB7XG4gICAgcGFkZGluZzogMCAxMHB4O1xuICB9XG5cbiAgLm5hdmJhci1icmFuZCB7XG4gICAgYmFja2dyb3VuZDogdHJhbnNwYXJlbnQgdXJsKC9pbWcvbG9nby5zdmcpIG5vLXJlcGVhdCA1MCUgNTAlO1xuICAgIGJhY2tncm91bmQtc2l6ZTogY29udGFpbjtcbiAgICAmLnNwaW4sXG4gICAgJjpob3Zlcjpub3QoLnNwaW4pIHtcbiAgICAgIC13ZWJraXQtYW5pbWF0aW9uOnNwaW4gNHMgbGluZWFyIGluZmluaXRlO1xuICAgICAgLW1vei1hbmltYXRpb246c3BpbiA0cyBsaW5lYXIgaW5maW5pdGU7XG4gICAgICBhbmltYXRpb246c3BpbiA0cyBsaW5lYXIgaW5maW5pdGU7XG4gICAgfVxuICB9XG59XG5cbi5yb3ctc3BhY2VkIHtcbiAgbWFyZ2luLXRvcDogMTVweDtcbiAgbWFyZ2luLWJvdHRvbTogMTVweDtcbn1cblxuLmZvb3RlciB7XG4gIHBvc2l0aW9uOiBhYnNvbHV0ZTtcbiAgYm90dG9tOiAwO1xuICB3aWR0aDogMTAwJTtcbiAgLyogU2V0IHRoZSBmaXhlZCBoZWlnaHQgb2YgdGhlIGZvb3RlciBoZXJlICovXG4gIGhlaWdodDogNTBweDtcbiAgYm9yZGVyLXRvcC13aWR0aDogMXB4O1xuICBib3JkZXItdG9wLXN0eWxlOiBzb2xpZDtcbn1cblxuLm5vc2VsZWN0IHtcbiAgLXdlYmtpdC10b3VjaC1jYWxsb3V0OiBub25lO1xuICAtd2Via2l0LXVzZXItc2VsZWN0OiBub25lO1xuICAtbW96LXVzZXItc2VsZWN0OiBub25lO1xuICAtbXMtdXNlci1zZWxlY3Q6IG5vbmU7XG4gIHVzZXItc2VsZWN0OiBub25lO1xuICBjdXJzb3I6IGRlZmF1bHQ7XG59XG5cbkAtbW96LWtleWZyYW1lcyBzcGluIHsgMTAwJSB7IC1tb3otdHJhbnNmb3JtOiByb3RhdGVZKDM2MGRlZyk7IH0gfVxuQC13ZWJraXQta2V5ZnJhbWVzIHNwaW4geyAxMDAlIHsgLXdlYmtpdC10cmFuc2Zvcm06IHJvdGF0ZVkoMzYwZGVnKTsgfSB9XG5Aa2V5ZnJhbWVzIHNwaW4geyAxMDAlIHsgLXdlYmtpdC10cmFuc2Zvcm06IHJvdGF0ZVkoMzYwZGVnKTsgdHJhbnNmb3JtOnJvdGF0ZVkoMzYwZGVnKTsgfSB9IiwiaHRtbCB7XG4gIHBvc2l0aW9uOiByZWxhdGl2ZTtcbiAgbWluLWhlaWdodDogMTAwJTtcbn1cbmJvZHkge1xuICBwYWRkaW5nLWJvdHRvbTogMjBweDtcbiAgLyogTWFyZ2luIGJvdHRvbSBieSBmb290ZXIgaGVpZ2h0ICovXG4gIG1hcmdpbi1ib3R0b206IDYwcHg7XG59XG4uaGVhZGluZyB7XG4gIC13ZWJraXQtdG91Y2gtY2FsbG91dDogbm9uZTtcbiAgLXdlYmtpdC11c2VyLXNlbGVjdDogbm9uZTtcbiAgLW1vei11c2VyLXNlbGVjdDogbm9uZTtcbiAgLW1zLXVzZXItc2VsZWN0OiBub25lO1xuICB1c2VyLXNlbGVjdDogbm9uZTtcbiAgY3Vyc29yOiBkZWZhdWx0O1xuICBiYWNrZ3JvdW5kOiB0cmFuc3BhcmVudCB1cmwoL2ltZy9sb2dvLnN2Zykgbm8tcmVwZWF0IDUwJSA1MCU7XG4gIGJhY2tncm91bmQtc2l6ZTogY29udGFpbjtcbiAgaGVpZ2h0OiAxMjVweDtcbiAgbWFyZ2luOiAyNXB4IDA7XG59XG4uc2VhcmNoLXJlc3VsdHMge1xuICBwYWRkaW5nOiAxNXB4O1xufVxuLnNlYXJjaC1yZXN1bHRzIC5zZWFyY2gtcmVzdWx0IHtcbiAgbWFyZ2luLWJvdHRvbTogMjBweDtcbn1cbi5zZWFyY2gtcmVzdWx0cyAuc2VhcmNoLXJlc3VsdCBhIHtcbiAgZm9udC1zaXplOiAxLjVyZW07XG59XG4uZWxsaXBzaXplIHtcbiAgd2hpdGUtc3BhY2U6IG5vd3JhcDtcbiAgb3ZlcmZsb3c6IGhpZGRlbjtcbiAgdGV4dC1vdmVyZmxvdzogZWxsaXBzaXM7XG59XG4ubmF2YmFyLWRlZmF1bHQgLmNvbGxhcHNlOm5vdCguaW4pIC5uYXZiYXItbmF2ID4gLmFjdGl2ZSA+IGEsXG4ubmF2YmFyLWRlZmF1bHQgLmNvbGxhcHNlOm5vdCguaW4pIC5uYXZiYXItbmF2ID4gLmFjdGl2ZSA+IGE6aG92ZXIsXG4ubmF2YmFyLWRlZmF1bHQgLmNvbGxhcHNlOm5vdCguaW4pIC5uYXZiYXItbmF2ID4gLmFjdGl2ZSA+IGE6Zm9jdXMge1xuICBib3JkZXItYm90dG9tOiAzcHggc29saWQ7XG4gIHBhZGRpbmctYm90dG9tOiAxMnB4O1xufVxuLm5hdmJhci1kZWZhdWx0IC5uYXZiYXItaGVhZGVyIHtcbiAgcGFkZGluZzogMCAxMHB4O1xufVxuLm5hdmJhci1kZWZhdWx0IC5uYXZiYXItYnJhbmQge1xuICBiYWNrZ3JvdW5kOiB0cmFuc3BhcmVudCB1cmwoL2ltZy9sb2dvLnN2Zykgbm8tcmVwZWF0IDUwJSA1MCU7XG4gIGJhY2tncm91bmQtc2l6ZTogY29udGFpbjtcbn1cbi5uYXZiYXItZGVmYXVsdCAubmF2YmFyLWJyYW5kLnNwaW4sXG4ubmF2YmFyLWRlZmF1bHQgLm5hdmJhci1icmFuZDpob3Zlcjpub3QoLnNwaW4pIHtcbiAgLXdlYmtpdC1hbmltYXRpb246IHNwaW4gNHMgbGluZWFyIGluZmluaXRlO1xuICAtbW96LWFuaW1hdGlvbjogc3BpbiA0cyBsaW5lYXIgaW5maW5pdGU7XG4gIGFuaW1hdGlvbjogc3BpbiA0cyBsaW5lYXIgaW5maW5pdGU7XG59XG4ucm93LXNwYWNlZCB7XG4gIG1hcmdpbi10b3A6IDE1cHg7XG4gIG1hcmdpbi1ib3R0b206IDE1cHg7XG59XG4uZm9vdGVyIHtcbiAgcG9zaXRpb246IGFic29sdXRlO1xuICBib3R0b206IDA7XG4gIHdpZHRoOiAxMDAlO1xuICAvKiBTZXQgdGhlIGZpeGVkIGhlaWdodCBvZiB0aGUgZm9vdGVyIGhlcmUgKi9cbiAgaGVpZ2h0OiA1MHB4O1xuICBib3JkZXItdG9wLXdpZHRoOiAxcHg7XG4gIGJvcmRlci10b3Atc3R5bGU6IHNvbGlkO1xufVxuLm5vc2VsZWN0IHtcbiAgLXdlYmtpdC10b3VjaC1jYWxsb3V0OiBub25lO1xuICAtd2Via2l0LXVzZXItc2VsZWN0OiBub25lO1xuICAtbW96LXVzZXItc2VsZWN0OiBub25lO1xuICAtbXMtdXNlci1zZWxlY3Q6IG5vbmU7XG4gIHVzZXItc2VsZWN0OiBub25lO1xuICBjdXJzb3I6IGRlZmF1bHQ7XG59XG5ALW1vei1rZXlmcmFtZXMgc3BpbiB7XG4gIDEwMCUge1xuICAgIC1tb3otdHJhbnNmb3JtOiByb3RhdGVZKDM2MGRlZyk7XG4gIH1cbn1cbkAtd2Via2l0LWtleWZyYW1lcyBzcGluIHtcbiAgMTAwJSB7XG4gICAgLXdlYmtpdC10cmFuc2Zvcm06IHJvdGF0ZVkoMzYwZGVnKTtcbiAgfVxufVxuQGtleWZyYW1lcyBzcGluIHtcbiAgMTAwJSB7XG4gICAgLXdlYmtpdC10cmFuc2Zvcm06IHJvdGF0ZVkoMzYwZGVnKTtcbiAgICB0cmFuc2Zvcm06IHJvdGF0ZVkoMzYwZGVnKTtcbiAgfVxufVxuIl0sInNvdXJjZVJvb3QiOiIvc291cmNlLyJ9 */ +html{position:relative;min-height:100%}body{padding-bottom:20px;margin-bottom:60px}.heading{-webkit-touch-callout:none;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;cursor:default;background:transparent url(/img/logo.svg) no-repeat 50% 50%;background-size:contain;height:125px;margin:25px 0}.search-results{padding:15px}.search-results .search-result{margin-bottom:20px}.search-results .search-result a{font-size:1.5rem}.ellipsize{white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.navbar-default .collapse:not(.in) .navbar-nav>.active>a,.navbar-default .collapse:not(.in) .navbar-nav>.active>a:focus,.navbar-default .collapse:not(.in) .navbar-nav>.active>a:hover{border-bottom:3px solid;padding-bottom:12px}.navbar-default .navbar-header{padding:0 10px}.navbar-default .navbar-brand,.navbar-default .navbar-brand.spin,.navbar-default .navbar-brand:hover:not(.spin){background:transparent url(/img/logo.svg) no-repeat 50% 50%;background-size:contain}.navbar-default .navbar-brand.spin,.navbar-default .navbar-brand:hover:not(.spin){-webkit-animation:a 4s linear infinite;animation:a 4s linear infinite}.navbar-default .navbar-brand.spin.spinner-small,.navbar-default .navbar-brand:hover:not(.spin).spinner-small{padding:20px}.row-spaced{margin-top:15px;margin-bottom:15px}.footer{width:100%;height:50px;border-top-width:1px;border-top-style:solid}.footer,.loading:before{position:absolute;bottom:0}.loading:before{top:0;left:0;right:0;background:rgba(0,0,0,.2);content:" ";z-index:1}.spinner{background:transparent url(/img/logo.svg) no-repeat 50% 50%;background-size:contain;-webkit-animation:a 4s linear infinite;animation:a 4s linear infinite}.spinner.spinner-small{padding:20px}.noselect{-webkit-touch-callout:none;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;cursor:default}@-webkit-keyframes a{to{-webkit-transform:rotateY(1turn)}}@keyframes a{to{-webkit-transform:rotateY(1turn);transform:rotateY(1turn)}} +/*# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbImFwcC5sZXNzIiwiYXBwLmNzcyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxLQUNFLGtCQUFBLEFBQ0EsZUFBQSxDQ0NELEFERUQsS0FDRSxvQkFBQSxBQUVBLGtCQUFBLENDQUQsQURHRCxTQTJGRSwyQkFBQSxBQUNBLHlCQUFBLEFBQ0Esc0JBQUEsQUFDQSxxQkFBQSxBQUNBLGlCQUFBLEFBQ0EsZUFBQSxBQTlGQSw0REFBQSxBQUNBLHdCQUFBLEFBQ0EsYUFBQSxBQUNBLGFBQUEsQ0NJRCxBRERELGdCQUNFLFlBQUEsQ0NHRCxBREpELCtCQUlJLGtCQUFBLENDR0gsQURQRCxpQ0FPTSxnQkFBQSxDQ0dMLEFERUQsV0FDRSxtQkFBQSxBQUNBLGdCQUFBLEFBQ0Esc0JBQUEsQ0NBRCxBRE1LLHVMQUdFLHdCQUFBLEFBQ0EsbUJBQUEsQ0NKUCxBREhELCtCQWFJLGNBQUEsQ0NQSCxBRGFHLGdIQUZBLDREQUFBLEFBQ0EsdUJBQUEsQ0FDQSxBQ0RILGtGRHFDQyx1Q0FBQSxBQUVBLDhCQUFBLENDdkNELEFEeUNDLDhHQUNFLFlBQUEsQ0N0Q0gsQURJRCxZQUNFLGdCQUFBLEFBQ0Esa0JBQUEsQ0NGRCxBREtELFFBR0UsV0FBQSxBQUVBLFlBQUEsQUFDQSxxQkFBQSxBQUNBLHNCQUFBLENDSEQsQURNRCx3QkFURSxrQkFBQSxBQUNBLFFBQUEsQ0FRRixBQ0lDLGdCREZDLE1BQUEsQUFDQSxPQUFBLEFBQ0EsUUFBQSxBQUVBLDBCQUFBLEFBQ0EsWUFBQSxBQUNBLFNBQUEsQ0NKRCxBRE9ELFNBQ0UsNERBQUEsQUFDQSx3QkFBQSxBQUNBLHVDQUFBLEFBRUEsOEJBQUEsQ0NMRCxBRE9DLHVCQUNFLFlBQUEsQ0NMSCxBRFNELFVBQ0UsMkJBQUEsQUFDQSx5QkFBQSxBQUNBLHNCQUFBLEFBQ0EscUJBQUEsQUFDQSxpQkFBQSxBQUNBLGNBQUEsQ0NQRCxBRFdELHFCQUEwQixHQUFPLGdDQUFBLENDRjlCLENBQ0YsQURFRCxhQUFrQixHQUFPLGlDQUFBLEFBQW9DLHdCQUFBLENDRzFELENBQ0YiLCJmaWxlIjoiYXBwLmNzcyIsInNvdXJjZXNDb250ZW50IjpbImh0bWwge1xuICBwb3NpdGlvbjogcmVsYXRpdmU7XG4gIG1pbi1oZWlnaHQ6IDEwMCU7XG59XG5cbmJvZHkge1xuICBwYWRkaW5nLWJvdHRvbTogMjBweDtcbiAgLyogTWFyZ2luIGJvdHRvbSBieSBmb290ZXIgaGVpZ2h0ICovXG4gIG1hcmdpbi1ib3R0b206IDYwcHg7XG59XG5cbi5oZWFkaW5nIHtcbiAgLm5vc2VsZWN0O1xuICBiYWNrZ3JvdW5kOiB0cmFuc3BhcmVudCB1cmwoL2ltZy9sb2dvLnN2Zykgbm8tcmVwZWF0IDUwJSA1MCU7XG4gIGJhY2tncm91bmQtc2l6ZTogY29udGFpbjtcbiAgaGVpZ2h0OiAxMjVweDtcbiAgbWFyZ2luOiAyNXB4IDA7XG59XG5cbi5zZWFyY2gtcmVzdWx0cyB7XG4gIHBhZGRpbmc6IDE1cHg7XG5cbiAgLnNlYXJjaC1yZXN1bHQge1xuICAgIG1hcmdpbi1ib3R0b206IDIwcHg7XG5cbiAgICBhIHtcbiAgICAgIGZvbnQtc2l6ZTogMS41cmVtO1xuICAgIH1cbiAgfVxufVxuXG4uZWxsaXBzaXplIHtcbiAgd2hpdGUtc3BhY2U6IG5vd3JhcDtcbiAgb3ZlcmZsb3c6IGhpZGRlbjtcbiAgdGV4dC1vdmVyZmxvdzogZWxsaXBzaXM7XG59XG5cbi5uYXZiYXItZGVmYXVsdCB7XG4gIC5jb2xsYXBzZTpub3QoLmluKSB7XG4gICAgLm5hdmJhci1uYXYgPiAuYWN0aXZlIHtcbiAgICAgICY+IGEsXG4gICAgICAmPiBhOmhvdmVyLFxuICAgICAgJj4gYTpmb2N1cyB7XG4gICAgICAgIGJvcmRlci1ib3R0b206IDNweCBzb2xpZDtcbiAgICAgICAgcGFkZGluZy1ib3R0b206IDEycHg7XG4gICAgICB9XG4gICAgfVxuICB9XG5cbiAgLm5hdmJhci1oZWFkZXIge1xuICAgIHBhZGRpbmc6IDAgMTBweDtcbiAgfVxuXG4gIC5uYXZiYXItYnJhbmQge1xuICAgIGJhY2tncm91bmQ6IHRyYW5zcGFyZW50IHVybCgvaW1nL2xvZ28uc3ZnKSBuby1yZXBlYXQgNTAlIDUwJTtcbiAgICBiYWNrZ3JvdW5kLXNpemU6IGNvbnRhaW47XG4gICAgJi5zcGluLFxuICAgICY6aG92ZXI6bm90KC5zcGluKSB7XG4gICAgICAuc3Bpbm5lcjtcbiAgICB9XG4gIH1cbn1cblxuLnJvdy1zcGFjZWQge1xuICBtYXJnaW4tdG9wOiAxNXB4O1xuICBtYXJnaW4tYm90dG9tOiAxNXB4O1xufVxuXG4uZm9vdGVyIHtcbiAgcG9zaXRpb246IGFic29sdXRlO1xuICBib3R0b206IDA7XG4gIHdpZHRoOiAxMDAlO1xuICAvKiBTZXQgdGhlIGZpeGVkIGhlaWdodCBvZiB0aGUgZm9vdGVyIGhlcmUgKi9cbiAgaGVpZ2h0OiA1MHB4O1xuICBib3JkZXItdG9wLXdpZHRoOiAxcHg7XG4gIGJvcmRlci10b3Atc3R5bGU6IHNvbGlkO1xufVxuXG4ubG9hZGluZzpiZWZvcmUge1xuICBwb3NpdGlvbjogYWJzb2x1dGU7XG4gIHRvcDogMDtcbiAgbGVmdDogMDtcbiAgcmlnaHQ6IDA7XG4gIGJvdHRvbTogMDtcbiAgYmFja2dyb3VuZDogcmdiYSgwLDAsMCwwLjIpO1xuICBjb250ZW50OiBcIiBcIjtcbiAgei1pbmRleDogOTk5OTtcbn1cblxuLnNwaW5uZXIge1xuICBiYWNrZ3JvdW5kOiB0cmFuc3BhcmVudCB1cmwoL2ltZy9sb2dvLnN2Zykgbm8tcmVwZWF0IDUwJSA1MCU7XG4gIGJhY2tncm91bmQtc2l6ZTogY29udGFpbjtcbiAgLXdlYmtpdC1hbmltYXRpb246c3BpbiA0cyBsaW5lYXIgaW5maW5pdGU7XG4gIC1tb3otYW5pbWF0aW9uOnNwaW4gNHMgbGluZWFyIGluZmluaXRlO1xuICBhbmltYXRpb246c3BpbiA0cyBsaW5lYXIgaW5maW5pdGU7XG5cbiAgJi5zcGlubmVyLXNtYWxsIHtcbiAgICBwYWRkaW5nOiAyMHB4O1xuICB9XG59XG5cbi5ub3NlbGVjdCB7XG4gIC13ZWJraXQtdG91Y2gtY2FsbG91dDogbm9uZTtcbiAgLXdlYmtpdC11c2VyLXNlbGVjdDogbm9uZTtcbiAgLW1vei11c2VyLXNlbGVjdDogbm9uZTtcbiAgLW1zLXVzZXItc2VsZWN0OiBub25lO1xuICB1c2VyLXNlbGVjdDogbm9uZTtcbiAgY3Vyc29yOiBkZWZhdWx0O1xufVxuXG5ALW1vei1rZXlmcmFtZXMgc3BpbiB7IDEwMCUgeyAtbW96LXRyYW5zZm9ybTogcm90YXRlWSgzNjBkZWcpOyB9IH1cbkAtd2Via2l0LWtleWZyYW1lcyBzcGluIHsgMTAwJSB7IC13ZWJraXQtdHJhbnNmb3JtOiByb3RhdGVZKDM2MGRlZyk7IH0gfVxuQGtleWZyYW1lcyBzcGluIHsgMTAwJSB7IC13ZWJraXQtdHJhbnNmb3JtOiByb3RhdGVZKDM2MGRlZyk7IHRyYW5zZm9ybTpyb3RhdGVZKDM2MGRlZyk7IH0gfSIsImh0bWwge1xuICBwb3NpdGlvbjogcmVsYXRpdmU7XG4gIG1pbi1oZWlnaHQ6IDEwMCU7XG59XG5ib2R5IHtcbiAgcGFkZGluZy1ib3R0b206IDIwcHg7XG4gIC8qIE1hcmdpbiBib3R0b20gYnkgZm9vdGVyIGhlaWdodCAqL1xuICBtYXJnaW4tYm90dG9tOiA2MHB4O1xufVxuLmhlYWRpbmcge1xuICAtd2Via2l0LXRvdWNoLWNhbGxvdXQ6IG5vbmU7XG4gIC13ZWJraXQtdXNlci1zZWxlY3Q6IG5vbmU7XG4gIC1tb3otdXNlci1zZWxlY3Q6IG5vbmU7XG4gIC1tcy11c2VyLXNlbGVjdDogbm9uZTtcbiAgdXNlci1zZWxlY3Q6IG5vbmU7XG4gIGN1cnNvcjogZGVmYXVsdDtcbiAgYmFja2dyb3VuZDogdHJhbnNwYXJlbnQgdXJsKC9pbWcvbG9nby5zdmcpIG5vLXJlcGVhdCA1MCUgNTAlO1xuICBiYWNrZ3JvdW5kLXNpemU6IGNvbnRhaW47XG4gIGhlaWdodDogMTI1cHg7XG4gIG1hcmdpbjogMjVweCAwO1xufVxuLnNlYXJjaC1yZXN1bHRzIHtcbiAgcGFkZGluZzogMTVweDtcbn1cbi5zZWFyY2gtcmVzdWx0cyAuc2VhcmNoLXJlc3VsdCB7XG4gIG1hcmdpbi1ib3R0b206IDIwcHg7XG59XG4uc2VhcmNoLXJlc3VsdHMgLnNlYXJjaC1yZXN1bHQgYSB7XG4gIGZvbnQtc2l6ZTogMS41cmVtO1xufVxuLmVsbGlwc2l6ZSB7XG4gIHdoaXRlLXNwYWNlOiBub3dyYXA7XG4gIG92ZXJmbG93OiBoaWRkZW47XG4gIHRleHQtb3ZlcmZsb3c6IGVsbGlwc2lzO1xufVxuLm5hdmJhci1kZWZhdWx0IC5jb2xsYXBzZTpub3QoLmluKSAubmF2YmFyLW5hdiA+IC5hY3RpdmUgPiBhLFxuLm5hdmJhci1kZWZhdWx0IC5jb2xsYXBzZTpub3QoLmluKSAubmF2YmFyLW5hdiA+IC5hY3RpdmUgPiBhOmhvdmVyLFxuLm5hdmJhci1kZWZhdWx0IC5jb2xsYXBzZTpub3QoLmluKSAubmF2YmFyLW5hdiA+IC5hY3RpdmUgPiBhOmZvY3VzIHtcbiAgYm9yZGVyLWJvdHRvbTogM3B4IHNvbGlkO1xuICBwYWRkaW5nLWJvdHRvbTogMTJweDtcbn1cbi5uYXZiYXItZGVmYXVsdCAubmF2YmFyLWhlYWRlciB7XG4gIHBhZGRpbmc6IDAgMTBweDtcbn1cbi5uYXZiYXItZGVmYXVsdCAubmF2YmFyLWJyYW5kIHtcbiAgYmFja2dyb3VuZDogdHJhbnNwYXJlbnQgdXJsKC9pbWcvbG9nby5zdmcpIG5vLXJlcGVhdCA1MCUgNTAlO1xuICBiYWNrZ3JvdW5kLXNpemU6IGNvbnRhaW47XG59XG4ubmF2YmFyLWRlZmF1bHQgLm5hdmJhci1icmFuZC5zcGluLFxuLm5hdmJhci1kZWZhdWx0IC5uYXZiYXItYnJhbmQ6aG92ZXI6bm90KC5zcGluKSB7XG4gIGJhY2tncm91bmQ6IHRyYW5zcGFyZW50IHVybCgvaW1nL2xvZ28uc3ZnKSBuby1yZXBlYXQgNTAlIDUwJTtcbiAgYmFja2dyb3VuZC1zaXplOiBjb250YWluO1xuICAtd2Via2l0LWFuaW1hdGlvbjogc3BpbiA0cyBsaW5lYXIgaW5maW5pdGU7XG4gIC1tb3otYW5pbWF0aW9uOiBzcGluIDRzIGxpbmVhciBpbmZpbml0ZTtcbiAgYW5pbWF0aW9uOiBzcGluIDRzIGxpbmVhciBpbmZpbml0ZTtcbn1cbi5uYXZiYXItZGVmYXVsdCAubmF2YmFyLWJyYW5kLnNwaW4uc3Bpbm5lci1zbWFsbCxcbi5uYXZiYXItZGVmYXVsdCAubmF2YmFyLWJyYW5kOmhvdmVyOm5vdCguc3Bpbikuc3Bpbm5lci1zbWFsbCB7XG4gIHBhZGRpbmc6IDIwcHg7XG59XG4ucm93LXNwYWNlZCB7XG4gIG1hcmdpbi10b3A6IDE1cHg7XG4gIG1hcmdpbi1ib3R0b206IDE1cHg7XG59XG4uZm9vdGVyIHtcbiAgcG9zaXRpb246IGFic29sdXRlO1xuICBib3R0b206IDA7XG4gIHdpZHRoOiAxMDAlO1xuICAvKiBTZXQgdGhlIGZpeGVkIGhlaWdodCBvZiB0aGUgZm9vdGVyIGhlcmUgKi9cbiAgaGVpZ2h0OiA1MHB4O1xuICBib3JkZXItdG9wLXdpZHRoOiAxcHg7XG4gIGJvcmRlci10b3Atc3R5bGU6IHNvbGlkO1xufVxuLmxvYWRpbmc6YmVmb3JlIHtcbiAgcG9zaXRpb246IGFic29sdXRlO1xuICB0b3A6IDA7XG4gIGxlZnQ6IDA7XG4gIHJpZ2h0OiAwO1xuICBib3R0b206IDA7XG4gIGJhY2tncm91bmQ6IHJnYmEoMCwgMCwgMCwgMC4yKTtcbiAgY29udGVudDogXCIgXCI7XG4gIHotaW5kZXg6IDk5OTk7XG59XG4uc3Bpbm5lciB7XG4gIGJhY2tncm91bmQ6IHRyYW5zcGFyZW50IHVybCgvaW1nL2xvZ28uc3ZnKSBuby1yZXBlYXQgNTAlIDUwJTtcbiAgYmFja2dyb3VuZC1zaXplOiBjb250YWluO1xuICAtd2Via2l0LWFuaW1hdGlvbjogc3BpbiA0cyBsaW5lYXIgaW5maW5pdGU7XG4gIC1tb3otYW5pbWF0aW9uOiBzcGluIDRzIGxpbmVhciBpbmZpbml0ZTtcbiAgYW5pbWF0aW9uOiBzcGluIDRzIGxpbmVhciBpbmZpbml0ZTtcbn1cbi5zcGlubmVyLnNwaW5uZXItc21hbGwge1xuICBwYWRkaW5nOiAyMHB4O1xufVxuLm5vc2VsZWN0IHtcbiAgLXdlYmtpdC10b3VjaC1jYWxsb3V0OiBub25lO1xuICAtd2Via2l0LXVzZXItc2VsZWN0OiBub25lO1xuICAtbW96LXVzZXItc2VsZWN0OiBub25lO1xuICAtbXMtdXNlci1zZWxlY3Q6IG5vbmU7XG4gIHVzZXItc2VsZWN0OiBub25lO1xuICBjdXJzb3I6IGRlZmF1bHQ7XG59XG5ALW1vei1rZXlmcmFtZXMgc3BpbiB7XG4gIDEwMCUge1xuICAgIC1tb3otdHJhbnNmb3JtOiByb3RhdGVZKDM2MGRlZyk7XG4gIH1cbn1cbkAtd2Via2l0LWtleWZyYW1lcyBzcGluIHtcbiAgMTAwJSB7XG4gICAgLXdlYmtpdC10cmFuc2Zvcm06IHJvdGF0ZVkoMzYwZGVnKTtcbiAgfVxufVxuQGtleWZyYW1lcyBzcGluIHtcbiAgMTAwJSB7XG4gICAgLXdlYmtpdC10cmFuc2Zvcm06IHJvdGF0ZVkoMzYwZGVnKTtcbiAgICB0cmFuc2Zvcm06IHJvdGF0ZVkoMzYwZGVnKTtcbiAgfVxufVxuIl0sInNvdXJjZVJvb3QiOiIvc291cmNlLyJ9 */ diff --git a/vipra-ui/css/app.less b/vipra-ui/css/app.less index e64406743dd5e10f5c96c395a9ff54e1e64ef5f8..537ff232c056c30fa94ca042ca28010f6b8d7442 100644 --- a/vipra-ui/css/app.less +++ b/vipra-ui/css/app.less @@ -56,9 +56,7 @@ body { background-size: contain; &.spin, &:hover:not(.spin) { - -webkit-animation:spin 4s linear infinite; - -moz-animation:spin 4s linear infinite; - animation:spin 4s linear infinite; + .spinner; } } } @@ -78,14 +76,27 @@ body { border-top-style: solid; } -.loading { +.loading:before { position: absolute; top: 0; left: 0; right: 0; bottom: 0; - background rgba(0,0,0,0.2); + background: rgba(0,0,0,0.2); + content: " "; + z-index: 9999; +} +.spinner { + background: transparent url(/img/logo.svg) no-repeat 50% 50%; + background-size: contain; + -webkit-animation:spin 4s linear infinite; + -moz-animation:spin 4s linear infinite; + animation:spin 4s linear infinite; + + &.spinner-small { + padding: 20px; + } } .noselect { diff --git a/vipra-ui/html/articles/index.html b/vipra-ui/html/articles/index.html index 9ce005c39cc7e6dbc211f9004debe94299888663..5560bfaff51ace0ddeb7c818e2d572d2fa7270fd 100644 --- a/vipra-ui/html/articles/index.html +++ b/vipra-ui/html/articles/index.html @@ -4,7 +4,7 @@ <ul class="list-unstyled"> <li ng-repeat="article in articles"> - <a ui-sref="articles.show({id: article.id})">{{article.title}}</a> + <a ui-sref="articles.show({id: article.id})" ng-bind="::article.title"></a> </li> </ul> diff --git a/vipra-ui/html/articles/show.html b/vipra-ui/html/articles/show.html index e8ed5e3454fc2558ff2994dff6e2d86c3dc0d453..13c354fed285907d6d71498d6aa9e97483a918bf 100644 --- a/vipra-ui/html/articles/show.html +++ b/vipra-ui/html/articles/show.html @@ -1,16 +1,18 @@ -<h1 ng-bind="article.title"></h1> - -<p ng-bind="(article.date | formatDate)"></p> +<h1 ng-bind="::article.title"></h1> <table class="table table-bordered table-condensed"> <tbody> <tr> <th>ID</th> - <td ng-bind="article.id"></td> + <td ng-bind="::article.id"></td> + </tr> + <tr> + <th>Date</th> + <td ng-bind="::article.date"></td> </tr> <tr> <th>URL</th> - <td><a ng-href="{{article.url}}" ng-bind="article.url"></a></td> + <td><a ng-href="{{::article.url}}" ng-bind="::article.url"></a></td> </tr> <tr> <th>Topics</th> @@ -22,17 +24,17 @@ </tr> <tr> <th>Created</th> - <td ng-bind="(article.created | formatDateTime)"></td> + <td ng-bind="::article.created"></td> </tr> <tr> <th>Last modified</th> - <td ng-bind="(article.modified | formatDateTime)"></td> + <td ng-bind="::article.modified"></td> </tr> <tr> <th>Word count</th> - <td ng-bind="article.stats.wordCount"></td> + <td ng-bind="::article.stats.wordCount"></td> </tr> </tbody> </table> -<p ng-bind="article.text"></p> \ No newline at end of file +<p ng-bind="::article.text"></p> \ No newline at end of file diff --git a/vipra-ui/html/index.html b/vipra-ui/html/index.html index bb5516f33c6cb90de3ded38df9b6cf93b4024fa1..6d4c4c0f97d41be2318f1ff9482b93b3da106a2a 100644 --- a/vipra-ui/html/index.html +++ b/vipra-ui/html/index.html @@ -1,12 +1,12 @@ <div class="container"> - <div class="row"> + <div class="row" slide-on="search"> <div class="col-md-12"> <div class="heading"></div> </div> </div> - <div class="row"> + <div class="row" slide-on="search"> <div class="col-md-6 text-center"> <h4>Latest articles</h4> <ul class="list-unstyled"> @@ -39,8 +39,14 @@ </div> </div> - <div class="row row-spaced" ng-show="searchResults.length > 0"> - <div class="col-md-12"> + <div class="row row-spaced"> + <div class="text-center" ng-show="searching"> + Searching... + </div> + <div class="col-md-12" ng-show="!searching && search && searchResults.length == 0"> + <h4>No Results <query-time/></h4> + </div> + <div class="col-md-12" ng-show="searchResults.length > 0"> <h4>Results <query-time/></h4> <ul class="list-unstyled search-results"> <li class="search-result" ng-repeat="article in searchResults"> diff --git a/vipra-ui/html/topics/show.html b/vipra-ui/html/topics/show.html index 08b2633990c5eeb8210fae60e03a8f03eb0c8b12..45b6595814b7f04d7ce8788b4e79e849f4e983c8 100644 --- a/vipra-ui/html/topics/show.html +++ b/vipra-ui/html/topics/show.html @@ -1,22 +1,22 @@ -<h1 ng-bind="topic.name"></h1> +<h1 ng-bind="::topic.name"></h1> <table class="table table-bordered table-condensed"> <tbody> <tr> <th>ID</th> - <td ng-bind="topic.id"></td> + <td ng-bind="::topic.id"></td> </tr> <tr> <th>Index</th> - <td ng-bind="topic.index"></td> + <td ng-bind="::topic.index"></td> </tr> <tr> <th>Created</th> - <td ng-bind="(topic.created | formatDateTime)"></td> + <td ng-bind="::topic.created"></td> </tr> <tr> <th>Last modified</th> - <td ng-bind="(topic.modified | formatDateTime)"></td> + <td ng-bind="::topic.modified"></td> </tr> </tbody> </table> @@ -31,7 +31,7 @@ </tr> </thead> <tbody> - <tr ng-repeat="word in topic.words"> + <tr ng-repeat="word in ::topic.words"> <td><a ui-sref="words.show({id:word.word})" ng-bind="word.word"></a></td> <td ng-bind="word.likeliness"></td> </tr> diff --git a/vipra-ui/index.html b/vipra-ui/index.html index e9759f89731f6d1f6e3120c7602bccc964c8aa89..b6c4dc9a970d37a971ee8700bd30ddbd0e817878 100644 --- a/vipra-ui/index.html +++ b/vipra-ui/index.html @@ -42,6 +42,7 @@ <script src="js/directives.js"></script> <script src="js/factories.js"></script> <script src="js/filters.js"></script> + <script src="js/helpers.js"></script> <script src="js/services.js"></script> </head> <body> diff --git a/vipra-ui/js/app.js b/vipra-ui/js/app.js index fcb3999b45884125492c3b177f98dc6257c8d059..3215a9d97d3cb8a5c0851e4785e5a1a269f9d572 100644 --- a/vipra-ui/js/app.js +++ b/vipra-ui/js/app.js @@ -21,8 +21,7 @@ $stateProvider.state('index', { url: '/', templateUrl: tplBase + '/index.html', - controller: 'IndexController', - reloadOnSearch: false + controller: 'IndexController' }); // states: articles diff --git a/vipra-ui/js/controllers.js b/vipra-ui/js/controllers.js index 2572c6aebc5ce955f691f158b40b3455ef516a05..7a5b23e5704bd782bcdf6f252d550586a42c0777 100644 --- a/vipra-ui/js/controllers.js +++ b/vipra-ui/js/controllers.js @@ -27,7 +27,9 @@ $scope.$watch('search', function() { if($scope.search) { + $scope.searching = true; SearchFactory.query({limit:searchItemsCount, query:$scope.search}, function(response) { + $scope.searching = false; $scope.searchResults = response.data; $scope.queryTime = response.$queryTime; }); @@ -43,7 +45,7 @@ */ app.controller('ArticlesIndexController', ['$scope', '$stateParams', 'ArticleFactory', - function($scope, $stateParams, ArticleFactory) { + function($scope, $stateParams, ArticleFactory, testService) { $scope.page = Math.max($stateParams.page || 1, 1); $scope.limit = pageSize; @@ -60,10 +62,13 @@ }]); app.controller('ArticlesShowController', ['$scope', '$stateParams', 'ArticleFactory', - function($scope, $stateParams, ArticleFactory) { + function($scope, $stateParams, ArticleFactory, testService) { ArticleFactory.get({id: $stateParams.id}, function(response) { $scope.article = response.data; + $scope.article.date = formatDate($scope.article.date); + $scope.article.created = formatDateTime($scope.article.created); + $scope.article.modified = formatDateTime($scope.article.modified); $scope.articleMeta = response.meta; $scope.queryTime = response.$queryTime; }); @@ -90,6 +95,8 @@ TopicFactory.get({id: $stateParams.id}, function(response) { $scope.topic = response.data; + $scope.topic.created = formatDateTime($scope.topic.created); + $scope.topic.modified = formatDateTime($scope.topic.modified); $scope.topicMeta = response.meta; $scope.queryTime = response.$queryTime; }); diff --git a/vipra-ui/js/directives.js b/vipra-ui/js/directives.js index b049382822e1aa7c35bbe4b4aa1cbeeebb09f763..9b8dda0a49c1b243818c811695f34c81eb201db9 100644 --- a/vipra-ui/js/directives.js +++ b/vipra-ui/js/directives.js @@ -4,6 +4,8 @@ 'ui.router' ]); + var slideDuration = 250; + app.directive('topicLink', function() { return { scope: { @@ -38,4 +40,23 @@ }; }); + app.directive('slideOn', function() { + return { + scope: { + slideOn: '=' + }, + link: function($scope, $elem) { + $scope.$watch('slideOn', function(newVal, oldVal) { + if(newVal != oldVal) { + if(newVal) { + $elem.slideUp(slideDuration); + } else { + $elem.slideDown(slideDuration); + } + } + }); + } + }; + }); + })(); \ No newline at end of file diff --git a/vipra-ui/js/filters.js b/vipra-ui/js/filters.js index a4233098d28b5e1984301ff35c61ee44861256c6..192f846992f3eb6ee8d32326a2ed87f8d698265f 100644 --- a/vipra-ui/js/filters.js +++ b/vipra-ui/js/filters.js @@ -3,24 +3,15 @@ var app = angular.module('vipra.filters', []); app.filter('toPercent', function() { - return function(input) { - if(typeof input !== 'number') - input = parseInt(input, 10); - return Math.round(input * 100); - }; + return toPercent; }); app.filter('formatDate', function() { - return function(input) { - return new Date(input).toLocaleDateString(); - }; + return formatDate; }); app.filter('formatDateTime', function() { - return function(input) { - var date = new Date(input); - return date.toLocaleDateString() + " " + date.toLocaleTimeString(); - }; + return formatDateTime; }); })(); \ No newline at end of file diff --git a/vipra-ui/js/helpers.js b/vipra-ui/js/helpers.js new file mode 100644 index 0000000000000000000000000000000000000000..14980a3641014cddae33cb15c451db261023ba1a --- /dev/null +++ b/vipra-ui/js/helpers.js @@ -0,0 +1,18 @@ +(function() { + + window.formatDate = function(date) { + return new Date(date).toLocaleDateString(); + }; + + window.formatDateTime = function(date) { + date = new Date(date); + return date.toLocaleDateString() + " " + date.toLocaleTimeString(); + }; + + window.toPercent = function(input) { + if(typeof input !== 'number') + input = parseInt(input, 10); + return Math.round(input * 100); + }; + +})(); \ No newline at end of file diff --git a/vipra-util/src/main/java/de/vipra/util/Config.java b/vipra-util/src/main/java/de/vipra/util/Config.java index 77417165150a5700226a6f94569c38a7c279c6ad..95f77ab8436ef29ba9db0ad66432ee91a7291b54 100644 --- a/vipra-util/src/main/java/de/vipra/util/Config.java +++ b/vipra-util/src/main/java/de/vipra/util/Config.java @@ -7,9 +7,9 @@ import java.io.OutputStream; import java.io.PrintWriter; import java.lang.reflect.Field; import java.lang.reflect.Modifier; -import java.util.Map.Entry; import java.util.HashMap; import java.util.Map; +import java.util.Map.Entry; import java.util.Properties; import java.util.Set; @@ -18,6 +18,7 @@ import org.slf4j.LoggerFactory; import de.vipra.util.Constants.Analyzer; import de.vipra.util.Constants.Processor; +import de.vipra.util.Constants.WindowResolution; import de.vipra.util.an.ConfigKey; import de.vipra.util.ex.ConfigException; import de.vipra.util.model.Model; @@ -44,6 +45,9 @@ public class Config { @ConfigKey("tm.analyzer") public Analyzer analyzer = Constants.Analyzer.DEFAULT; + @ConfigKey("tm.windowresolution") + public WindowResolution windowResolution = Constants.WindowResolution.DEFAULT; + @ConfigKey("tm.saveallwords") public boolean saveAllWords = Constants.SAVE_ALL_WORDS; diff --git a/vipra-util/src/main/java/de/vipra/util/Constants.java b/vipra-util/src/main/java/de/vipra/util/Constants.java index ca915f4c37676455f629bfe405439fe8b56b3165..a9b232ed9f163cd4446a6d31076400820da81472 100644 --- a/vipra-util/src/main/java/de/vipra/util/Constants.java +++ b/vipra-util/src/main/java/de/vipra/util/Constants.java @@ -181,6 +181,16 @@ public class Constants { */ public static final String REGEX_SINGLECHAR = "\\b\\w\\b"; + /* + * INDEX + */ + + /** + * The length of the text excerpt used for indexing and displaying text in + * search results. + */ + public static final int EXCERPT_LENGTH = 250; + /* * OTHER */ @@ -225,6 +235,7 @@ public class Constants { */ public static enum Analyzer { JGIBB("jgibb"), + DYNNMF("dynnmf"), DEFAULT(JGIBB); public final String name; @@ -249,4 +260,35 @@ public class Constants { } } + /** + * Describes the window size, when using dynamic topic modeling + */ + public static enum WindowResolution { + MONTHLY("monthly"), + QUARTERLY("quarterly"), + YEARLY("yearly"), + DEFAULT(MONTHLY); + + public final String name; + + private WindowResolution(String name) { + this.name = name; + } + + private WindowResolution(WindowResolution def) { + this.name = def.name; + } + + public static WindowResolution fromString(String text) { + if (text != null) { + for (WindowResolution b : WindowResolution.values()) { + if (text.equalsIgnoreCase(b.name)) { + return b; + } + } + } + return DEFAULT; + } + } + } diff --git a/vipra-util/src/main/java/de/vipra/util/model/ArticleFull.java b/vipra-util/src/main/java/de/vipra/util/model/ArticleFull.java index d5dd234f9ba9d9d3f361b6f80897fa75caf977b3..d2effd84b4e28315107e7e23a7546aacea6c60ed 100644 --- a/vipra-util/src/main/java/de/vipra/util/model/ArticleFull.java +++ b/vipra-util/src/main/java/de/vipra/util/model/ArticleFull.java @@ -103,6 +103,11 @@ public class ArticleFull extends FileModel<ObjectId> implements Serializable { this.text = text; } + @ElasticIndex("excerpt") + public String serializeText() { + return StringUtils.ellipsize(text, Constants.EXCERPT_LENGTH); + } + public String getProcessedText() { return processedText; }