From 9e9dbf2f550dc6adfb90383394193e53a00f9f82 Mon Sep 17 00:00:00 2001 From: Eike Cochu <eike@cochu.com> Date: Thu, 24 Mar 2016 01:18:09 +0100 Subject: [PATCH] removed ws stuff, unused animating explorer sidebar valuebars fixed chart rendering when reloading page fixed topic word sorting in article show added index redirect on topic model change in id-loaded pages removed put/post methods from resources added put method to topic resource for renaming only --- .../vipra/rest/resource/ArticleResource.java | 68 ---- .../de/vipra/rest/resource/TopicResource.java | 4 +- .../vipra/rest/resource/WindowResource.java | 11 +- .../src/main/java/de/vipra/ws/State.java | 29 -- .../main/java/de/vipra/ws/StateSession.java | 51 --- .../java/de/vipra/ws/StateSessionMap.java | 20 -- .../src/main/java/de/vipra/ws/WebSocket.java | 79 ----- .../java/de/vipra/ws/msg/InitMessage.java | 15 - .../de/vipra/ws/msg/WebSocketMessage.java | 25 -- .../main/java/de/vipra/cmd/lda/Analyzer.java | 11 +- .../vipra/cmd/option/ListModelsCommand.java | 5 +- vipra-ui/app/html/about.html | 12 - vipra-ui/app/html/articles/index.html | 12 +- vipra-ui/app/html/articles/show.html | 3 +- vipra-ui/app/html/directives/topic-link.html | 2 +- vipra-ui/app/html/explorer.html | 36 +- vipra-ui/app/html/index.html | 2 +- vipra-ui/app/html/network.html | 2 +- vipra-ui/app/html/partials/topic-popover.html | 10 +- vipra-ui/app/html/sequences/index.html | 0 vipra-ui/app/html/sequences/show.html | 0 vipra-ui/app/html/topics/articles.html | 12 +- vipra-ui/app/html/topics/index.html | 12 +- vipra-ui/app/html/topics/show.html | 16 +- vipra-ui/app/index.html | 15 +- vipra-ui/app/js/app.js | 14 - vipra-ui/app/js/controllers.js | 310 +++++++++++------- vipra-ui/app/js/directives.js | 106 +++--- vipra-ui/app/js/factories.js | 71 +--- vipra-ui/app/less/app.less | 7 +- .../java/de/vipra/util/model/Article.java | 3 + .../java/de/vipra/util/model/ArticleFull.java | 3 + .../de/vipra/util/model/ArticleStats.java | 3 + .../java/de/vipra/util/model/ArticleWord.java | 3 + .../java/de/vipra/util/model/Sequence.java | 16 +- .../de/vipra/util/model/SequenceFull.java | 3 + .../de/vipra/util/model/SimilarArticle.java | 3 + .../java/de/vipra/util/model/TextEntity.java | 3 + .../main/java/de/vipra/util/model/Topic.java | 3 + .../java/de/vipra/util/model/TopicFull.java | 6 + .../java/de/vipra/util/model/TopicModel.java | 3 + .../de/vipra/util/model/TopicModelConfig.java | 3 + .../de/vipra/util/model/TopicModelFull.java | 3 + .../java/de/vipra/util/model/TopicShare.java | 3 + .../java/de/vipra/util/model/TopicWord.java | 2 + .../main/java/de/vipra/util/model/Window.java | 30 +- .../java/de/vipra/util/model/WindowFull.java | 80 +++++ 47 files changed, 445 insertions(+), 685 deletions(-) delete mode 100644 vipra-backend/src/main/java/de/vipra/ws/State.java delete mode 100644 vipra-backend/src/main/java/de/vipra/ws/StateSession.java delete mode 100644 vipra-backend/src/main/java/de/vipra/ws/StateSessionMap.java delete mode 100644 vipra-backend/src/main/java/de/vipra/ws/WebSocket.java delete mode 100644 vipra-backend/src/main/java/de/vipra/ws/msg/InitMessage.java delete mode 100644 vipra-backend/src/main/java/de/vipra/ws/msg/WebSocketMessage.java delete mode 100644 vipra-ui/app/html/sequences/index.html delete mode 100644 vipra-ui/app/html/sequences/show.html create mode 100644 vipra-util/src/main/java/de/vipra/util/model/WindowFull.java diff --git a/vipra-backend/src/main/java/de/vipra/rest/resource/ArticleResource.java b/vipra-backend/src/main/java/de/vipra/rest/resource/ArticleResource.java index 74c809ec..09991c62 100644 --- a/vipra-backend/src/main/java/de/vipra/rest/resource/ArticleResource.java +++ b/vipra-backend/src/main/java/de/vipra/rest/resource/ArticleResource.java @@ -1,19 +1,12 @@ package de.vipra.rest.resource; import java.io.IOException; -import java.net.MalformedURLException; -import java.net.URI; -import java.net.URISyntaxException; -import java.net.URL; import java.util.List; import javax.servlet.ServletContext; import javax.ws.rs.Consumes; -import javax.ws.rs.DELETE; import javax.ws.rs.DefaultValue; import javax.ws.rs.GET; -import javax.ws.rs.POST; -import javax.ws.rs.PUT; import javax.ws.rs.Path; import javax.ws.rs.PathParam; import javax.ws.rs.Produces; @@ -32,7 +25,6 @@ import de.vipra.util.Config; import de.vipra.util.MongoUtils; import de.vipra.util.StringUtils; import de.vipra.util.ex.ConfigException; -import de.vipra.util.ex.DatabaseException; import de.vipra.util.model.ArticleFull; import de.vipra.util.model.TopicModel; import de.vipra.util.service.MongoService; @@ -115,64 +107,4 @@ public class ArticleResource { } } - @POST - @Consumes(MediaType.APPLICATION_JSON) - @Produces(MediaType.APPLICATION_JSON) - public Response createArticle(ArticleFull article) { - final ResponseWrapper<ArticleFull> res = new ResponseWrapper<>(); - try { - article = dbArticles.createSingle(article); - final URI newUri = new URL(uri.getAbsolutePath().toURL(), article.getId().toString()).toURI(); - return res.created(article, newUri); - } catch (DatabaseException | MalformedURLException | URISyntaxException e) { - e.printStackTrace(); - res.addError(new APIError(Response.Status.INTERNAL_SERVER_ERROR, "item could not be created", - "item could not be created due to an internal server error")); - return res.serverError(); - } - } - - @DELETE - @Path("{id}") - public Response deleteArticle(@PathParam("id") final String id) { - final ResponseWrapper<ArticleFull> res = new ResponseWrapper<>(); - long deleted; - try { - deleted = dbArticles.deleteSingle(MongoUtils.objectId(id)); - } catch (final DatabaseException e) { - e.printStackTrace(); - res.addError(new APIError(Response.Status.INTERNAL_SERVER_ERROR, "item could not be deleted", - "item could not be created due to an internal server error")); - return res.serverError(); - } - final int del = deleted > Integer.MAX_VALUE ? Integer.MAX_VALUE : (int) deleted; - switch (del) { - case 0: - res.addError(new APIError(Response.Status.NOT_FOUND, "Article not found", String.format(Messages.NOT_FOUND, "article", id))); - return res.notFound(); - case 1: - return res.noContent(); - default: - return res.serverError(); - } - } - - @PUT - @Consumes(MediaType.APPLICATION_JSON) - @Produces(MediaType.APPLICATION_JSON) - @Path("{id}") - public Response replaceArticle(@PathParam("id") final String id, final ArticleFull article) { - final ResponseWrapper<ArticleFull> res = new ResponseWrapper<>(); - - try { - dbArticles.replaceSingle(article); - return res.ok(article); - } catch (final DatabaseException e) { - e.printStackTrace(); - res.addError(new APIError(Response.Status.INTERNAL_SERVER_ERROR, "item could not be updated", - "item could not be updated due to an internal server error")); - return res.serverError(); - } - } - } diff --git a/vipra-backend/src/main/java/de/vipra/rest/resource/TopicResource.java b/vipra-backend/src/main/java/de/vipra/rest/resource/TopicResource.java index 3f422d62..2d977f74 100644 --- a/vipra-backend/src/main/java/de/vipra/rest/resource/TopicResource.java +++ b/vipra-backend/src/main/java/de/vipra/rest/resource/TopicResource.java @@ -138,11 +138,11 @@ public class TopicResource { @Consumes(MediaType.APPLICATION_JSON) @Produces(MediaType.APPLICATION_JSON) @Path("{id}") - public Response replaceTopic(@PathParam("id") final String id, final TopicFull topic) { + public Response renameTopic(@PathParam("id") final String id, final TopicFull topic) { final ResponseWrapper<TopicFull> res = new ResponseWrapper<>(); try { - dbTopics.replaceSingle(topic); + dbTopics.updateSingle(topic, "name"); return res.ok(topic); } catch (final DatabaseException e) { e.printStackTrace(); diff --git a/vipra-backend/src/main/java/de/vipra/rest/resource/WindowResource.java b/vipra-backend/src/main/java/de/vipra/rest/resource/WindowResource.java index 6b3bed96..7d1555c7 100644 --- a/vipra-backend/src/main/java/de/vipra/rest/resource/WindowResource.java +++ b/vipra-backend/src/main/java/de/vipra/rest/resource/WindowResource.java @@ -19,18 +19,18 @@ import de.vipra.util.Config; import de.vipra.util.StringUtils; import de.vipra.util.ex.ConfigException; import de.vipra.util.model.TopicModel; -import de.vipra.util.model.Window; +import de.vipra.util.model.WindowFull; import de.vipra.util.service.MongoService; import de.vipra.util.service.Service.QueryBuilder; @Path("windows") public class WindowResource { - final MongoService<Window, Integer> dbWindows; + final MongoService<WindowFull, Integer> dbWindows; public WindowResource(@Context final ServletContext servletContext) throws ConfigException, IOException { final Config config = Config.getConfig(); - dbWindows = MongoService.getDatabaseService(config, Window.class); + dbWindows = MongoService.getDatabaseService(config, WindowFull.class); } @GET @@ -38,7 +38,7 @@ public class WindowResource { public Response getWindows(@QueryParam("topicModel") final String topicModel, @QueryParam("skip") final Integer skip, @QueryParam("limit") final Integer limit, @QueryParam("sort") @DefaultValue("startDate") final String sortBy, @QueryParam("fields") final String fields) { - final ResponseWrapper<List<Window>> res = new ResponseWrapper<>(); + final ResponseWrapper<List<WindowFull>> res = new ResponseWrapper<>(); if (res.hasErrors()) return Response.status(Response.Status.BAD_REQUEST).entity(res).build(); @@ -51,7 +51,7 @@ public class WindowResource { if (topicModel != null && !topicModel.isEmpty()) query.criteria("topicModel", new TopicModel(topicModel)); - final List<Window> windows = dbWindows.getMultiple(query); + final List<WindowFull> windows = dbWindows.getMultiple(query); if ((skip != null && skip > 0) || (limit != null && limit > 0)) res.addHeader("total", dbWindows.count(null)); @@ -65,4 +65,5 @@ public class WindowResource { return Response.status(Response.Status.BAD_REQUEST).entity(res).build(); } } + } \ No newline at end of file diff --git a/vipra-backend/src/main/java/de/vipra/ws/State.java b/vipra-backend/src/main/java/de/vipra/ws/State.java deleted file mode 100644 index cf5731a2..00000000 --- a/vipra-backend/src/main/java/de/vipra/ws/State.java +++ /dev/null @@ -1,29 +0,0 @@ -package de.vipra.ws; - -public enum State { - INDEX("index"), - ABOUT("about"), - NETWORK("network"), - ARTICLES("articles"), - TOPICS("topics"), - WORDS("words"), - ID(null); - - private final String state; - - State(final String state) { - this.state = state; - } - - public String getState() { - return state; - } - - public static State find(final String str) { - for (final State state : State.values()) - if (state.state.equalsIgnoreCase(str)) - return state; - return ID; - } - -} diff --git a/vipra-backend/src/main/java/de/vipra/ws/StateSession.java b/vipra-backend/src/main/java/de/vipra/ws/StateSession.java deleted file mode 100644 index be6ba8e4..00000000 --- a/vipra-backend/src/main/java/de/vipra/ws/StateSession.java +++ /dev/null @@ -1,51 +0,0 @@ -package de.vipra.ws; - -import javax.websocket.Session; - -public class StateSession { - - private final Session session; - private State state; - - public StateSession(final Session session) { - if (session == null) - throw new NullPointerException("session cannot be null"); - this.session = session; - } - - public State getState() { - return state; - } - - public void setState(final State state) { - this.state = state; - } - - public void setState(final String state) { - this.state = State.find(state); - } - - public Session getSession() { - return session; - } - - @Override - public boolean equals(Object o) { - if (o == null) - return false; - - if (o instanceof StateSession) - o = ((StateSession) o).getSession(); - - if (o instanceof Session) - return o.equals(session); - - return false; - } - - @Override - public int hashCode() { - return session.hashCode(); - } - -} diff --git a/vipra-backend/src/main/java/de/vipra/ws/StateSessionMap.java b/vipra-backend/src/main/java/de/vipra/ws/StateSessionMap.java deleted file mode 100644 index 02c47730..00000000 --- a/vipra-backend/src/main/java/de/vipra/ws/StateSessionMap.java +++ /dev/null @@ -1,20 +0,0 @@ -package de.vipra.ws; - -import java.util.HashMap; -import java.util.stream.Stream; - -import javax.websocket.Session; - -public class StateSessionMap extends HashMap<StateSession, StateSession> { - - private static final long serialVersionUID = 1L; - - public Stream<Session> stream(final State state) { - return entrySet().stream().filter(s -> s.getKey().getState() == state).map(s -> s.getKey().getSession()); - } - - public void add(final StateSession session) { - put(session, session); - } - -} diff --git a/vipra-backend/src/main/java/de/vipra/ws/WebSocket.java b/vipra-backend/src/main/java/de/vipra/ws/WebSocket.java deleted file mode 100644 index 5cfd37f8..00000000 --- a/vipra-backend/src/main/java/de/vipra/ws/WebSocket.java +++ /dev/null @@ -1,79 +0,0 @@ -package de.vipra.ws; - -import java.io.IOException; - -import javax.websocket.OnClose; -import javax.websocket.OnError; -import javax.websocket.OnMessage; -import javax.websocket.OnOpen; -import javax.websocket.Session; -import javax.websocket.server.ServerEndpoint; - -import org.apache.logging.log4j.LogManager; -import org.apache.logging.log4j.Logger; - -import com.fasterxml.jackson.core.JsonParseException; -import com.fasterxml.jackson.core.JsonProcessingException; -import com.fasterxml.jackson.databind.JsonMappingException; -import com.fasterxml.jackson.databind.ObjectMapper; - -import de.vipra.ws.msg.InitMessage; -import de.vipra.ws.msg.WebSocketMessage; - -@ServerEndpoint("/ws") -public class WebSocket { - - public static final Logger log = LogManager.getLogger(WebSocket.class); - - public static final ObjectMapper mapper = new ObjectMapper(); - public static final StateSessionMap sessions = new StateSessionMap(); - - @OnOpen - public void open(final Session session) { - log.debug("connect"); - sessions.add(new StateSession(session)); - } - - @OnClose - public void close(final Session session) { - log.debug("disconnect"); - sessions.remove(session); - } - - @OnError - public void onError(final Throwable error) { - log.error(error); - } - - @OnMessage - public void handleMessage(final String input, final Session session) throws JsonParseException, JsonMappingException, IOException { - log.trace("message received"); - try { - final WebSocketMessage msg = mapper.readValue(input, WebSocketMessage.class); - switch (msg.getType()) { - case 1: - handleInitMessage(mapper.readValue(msg.getData(), InitMessage.class), session); - break; - } - } catch (final IOException e) { - log.error(e); - } - } - - public void handleInitMessage(final InitMessage message, final Session session) { - log.debug("init message received. state = " + message.getState()); - sessions.get(session).setState(message.getState()); - } - - public static void sendToState(final State state, final Object message) { - String json; - try { - json = mapper.writeValueAsString(message); - } catch (final JsonProcessingException e) { - log.error(e); - return; - } - sessions.stream(state).forEach(s -> s.getAsyncRemote().sendText(json)); - } - -} diff --git a/vipra-backend/src/main/java/de/vipra/ws/msg/InitMessage.java b/vipra-backend/src/main/java/de/vipra/ws/msg/InitMessage.java deleted file mode 100644 index 93769d7d..00000000 --- a/vipra-backend/src/main/java/de/vipra/ws/msg/InitMessage.java +++ /dev/null @@ -1,15 +0,0 @@ -package de.vipra.ws.msg; - -public class InitMessage extends WebSocketMessage { - - private String state; - - public String getState() { - return state; - } - - public void setState(final String state) { - this.state = state; - } - -} diff --git a/vipra-backend/src/main/java/de/vipra/ws/msg/WebSocketMessage.java b/vipra-backend/src/main/java/de/vipra/ws/msg/WebSocketMessage.java deleted file mode 100644 index ac769465..00000000 --- a/vipra-backend/src/main/java/de/vipra/ws/msg/WebSocketMessage.java +++ /dev/null @@ -1,25 +0,0 @@ -package de.vipra.ws.msg; - -public class WebSocketMessage { - - private int type; - - private String data; - - public int getType() { - return type; - } - - public void setType(final int type) { - this.type = type; - } - - public String getData() { - return data; - } - - public void setData(final String data) { - this.data = data; - } - -} diff --git a/vipra-cmd/src/main/java/de/vipra/cmd/lda/Analyzer.java b/vipra-cmd/src/main/java/de/vipra/cmd/lda/Analyzer.java index 458af103..365fc9a4 100644 --- a/vipra-cmd/src/main/java/de/vipra/cmd/lda/Analyzer.java +++ b/vipra-cmd/src/main/java/de/vipra/cmd/lda/Analyzer.java @@ -39,6 +39,7 @@ import de.vipra.util.model.TopicModelFull; import de.vipra.util.model.TopicShare; import de.vipra.util.model.TopicWord; import de.vipra.util.model.Window; +import de.vipra.util.model.WindowFull; import de.vipra.util.service.MongoService; import de.vipra.util.service.Service.QueryBuilder; @@ -50,7 +51,7 @@ public class Analyzer { private final MongoService<ArticleFull, ObjectId> dbArticles; private final MongoService<TopicFull, ObjectId> dbTopics; private final MongoService<SequenceFull, ObjectId> dbSequences; - private final MongoService<Window, Integer> dbWindows; + private final MongoService<WindowFull, Integer> dbWindows; private final MongoService<TopicModelFull, String> dbTopicModels; public Analyzer() throws AnalyzerException, ConfigException { @@ -59,7 +60,7 @@ public class Analyzer { dbArticles = MongoService.getDatabaseService(config, ArticleFull.class); dbTopics = MongoService.getDatabaseService(config, TopicFull.class); dbSequences = MongoService.getDatabaseService(config, SequenceFull.class); - dbWindows = MongoService.getDatabaseService(config, Window.class); + dbWindows = MongoService.getDatabaseService(config, WindowFull.class); dbTopicModels = MongoService.getDatabaseService(config, TopicModelFull.class); // check for binary @@ -165,7 +166,7 @@ public class Analyzer { // read topic definition files and create topics final TopicModelFull topicModel = new TopicModelFull(modelConfig.getName(), modelConfig); - final List<Window> newWindows = new ArrayList<>(sequencesCount); + final List<WindowFull> newWindows = new ArrayList<>(sequencesCount); final List<SequenceFull> newSequences = new ArrayList<>(topicCount * sequencesCount); final List<TopicFull> newTopics = new ArrayList<>(topicCount); @@ -177,7 +178,7 @@ public class Analyzer { // create sequence windows for (int idxSeq = 0; idxSeq < sequencesCount; idxSeq++) { - final Window newWindow = new Window(); + final WindowFull newWindow = new WindowFull(); newWindow.setId(idxSeq); newWindow.setStartDate(windowIndex.startDate(idxSeq)); newWindow.setEndDate(windowIndex.endDate(idxSeq)); @@ -259,7 +260,7 @@ public class Analyzer { // create sequence final SequenceFull newSequenceFull = new SequenceFull(); - newSequenceFull.setWindow(newWindows.get(idxSeq)); + newSequenceFull.setWindow(new Window(newWindows.get(idxSeq))); newSequenceFull.setWords(newSeqTopicWords); newSequenceFull.setRelevance(relevance); newSequenceFull.setRelevanceChange(relevance - prevRelevance); diff --git a/vipra-cmd/src/main/java/de/vipra/cmd/option/ListModelsCommand.java b/vipra-cmd/src/main/java/de/vipra/cmd/option/ListModelsCommand.java index 54e4df82..d6f1f4b6 100644 --- a/vipra-cmd/src/main/java/de/vipra/cmd/option/ListModelsCommand.java +++ b/vipra-cmd/src/main/java/de/vipra/cmd/option/ListModelsCommand.java @@ -19,9 +19,8 @@ public class ListModelsCommand implements Command { for (final Entry<String, TopicModelConfig> entry : config.getTopicModelConfigs().entrySet()) longestModelName = Math.max(longestModelName, entry.getValue().getName().length()); for (final Entry<String, TopicModelConfig> entry : config.getTopicModelConfigs().entrySet()) - ConsoleUtils - .info(" " + Ansi.ansi().a(Ansi.Attribute.INTENSITY_BOLD).a(StringUtils.pad(entry.getValue().getName(), longestModelName)).reset() - + " " + entry.getValue().toString()); + ConsoleUtils.info(Ansi.ansi().a(Ansi.Attribute.INTENSITY_BOLD).a(StringUtils.pad(entry.getValue().getName(), longestModelName)).reset() + + " " + entry.getValue().toString()); } } diff --git a/vipra-ui/app/html/about.html b/vipra-ui/app/html/about.html index a7343ea7..9ba7c44e 100644 --- a/vipra-ui/app/html/about.html +++ b/vipra-ui/app/html/about.html @@ -74,23 +74,11 @@ <th># of topics</th> <td ng-bind-template="{{::info.db.topics}}"></td> </tr> - <tr> - <th># of words</th> - <td ng-bind-template="{{::info.db.words}}"></td> - </tr> </tbody> </table> <h3>Constants</h3> <table class="table table-bordered table-fixed"> <tbody> - <tr> - <th style="width:33%">Analyzer</th> - <td ng-bind-template="{{::info.const.analyzer}}"></td> - </tr> - <tr> - <th>Processor</th> - <td ng-bind-template="{{::info.const.processor}}"></td> - </tr> <tr> <th>Window resolution</th> <td ng-bind-template="{{::info.const.windowres}}"></td> diff --git a/vipra-ui/app/html/articles/index.html b/vipra-ui/app/html/articles/index.html index e284dcbe..ab26863e 100644 --- a/vipra-ui/app/html/articles/index.html +++ b/vipra-ui/app/html/articles/index.html @@ -1,7 +1,7 @@ -<div class="container" ng-cloak ng-hide="$state.current.name !== 'articles'"> +<div class="container" ng-cloak ng-hide="!rootModels.topicModel || $state.current.name !== 'articles'"> <div class="row"> <div class="col-md-12"> - <pagination total="articlesTotal" page="page" limit="limit" /> + <pagination total="articlesTotal" page="articlesIndexModels.page" limit="articlesIndexModels.limit" /> </div> </div> <div class="row"> @@ -12,12 +12,12 @@ <ng-pluralize count="articlesTotal||0" when="{0:'no articles',1:'1 article',other:'{} articles'}"></ng-pluralize> in the database. <span ng-show="articlesTotal"> Sort by - <ol class="nya-bs-select nya-bs-condensed" ng-model="opts.sortkey"> + <ol class="nya-bs-select nya-bs-condensed" ng-model="articlesIndexModels.sortkey"> <li value="title" class="nya-bs-option"><a>Title</a></li> <li value="date" class="nya-bs-option"><a>Date</a></li> <li value="created" class="nya-bs-option"><a>Added</a></li> </ol> - <sort-dir ng-model="opts.sortdir" /> + <sort-dir ng-model="articlesIndexModels.sortdir" /> </span> </div> <table class="table table-hover table-condensed"> @@ -30,14 +30,14 @@ </tbody> </table> <div class="panel-footer"> - Page <span ng-bind="page||1"></span> of <span ng-bind="maxPage||1"></span> + Page <span ng-bind="articlesIndexModels.page||1"></span> of <span ng-bind="maxPage||1"></span> </div> </div> </div> </div> <div class="row"> <div class="col-md-12"> - <pagination total="articlesTotal" page="page" limit="limit" /> + <pagination total="articlesTotal" page="articlesIndexModels.page" limit="articlesIndexModels.limit" /> </div> </div> </div> diff --git a/vipra-ui/app/html/articles/show.html b/vipra-ui/app/html/articles/show.html index 398eb464..1963a78b 100644 --- a/vipra-ui/app/html/articles/show.html +++ b/vipra-ui/app/html/articles/show.html @@ -1,4 +1,4 @@ -<div class="container" ng-cloak ng-hide="$state.current.name !== 'articles.show'"> +<div class="container" ng-cloak ng-hide="!rootModels.topicModel || $state.current.name !== 'articles.show'"> <div class="row"> <div class="col-md-12"> <div class="page-header"> @@ -74,7 +74,6 @@ <tr ng-repeat="topic in article.topics | orderBy:topicSort:topicSortRev"> <td> <topic-link topic="topic.topic" /> - <span class="colorbox" style="background:{{::topic.color}}"></span> </td> <td class="text-right" ng-bind-template="{{(topic.share*100).toFixed(1)}}%"></td> </tr> diff --git a/vipra-ui/app/html/directives/topic-link.html b/vipra-ui/app/html/directives/topic-link.html index 49ccb9e2..7ad606fe 100644 --- a/vipra-ui/app/html/directives/topic-link.html +++ b/vipra-ui/app/html/directives/topic-link.html @@ -1,7 +1,7 @@ <span> + <topic-menu topic="topic" right="true" /> <a class="topic-link" ui-sref="topics.show({id:topic.id})"> <span ng-bind="topic.name"></span> <ng-transclude/> </a> - <topic-menu topic="topic" right="true" /> </span> diff --git a/vipra-ui/app/html/explorer.html b/vipra-ui/app/html/explorer.html index f6d7e25a..f925a721 100644 --- a/vipra-ui/app/html/explorer.html +++ b/vipra-ui/app/html/explorer.html @@ -1,4 +1,4 @@ -<div class="fullsize navpadding explorer" ng-cloak ng-hide="$state.current.name !== 'explorer'"> +<div class="fullsize navpadding explorer" ng-cloak ng-hide="!rootModels.topicModel || $state.current.name !== 'explorer'"> <div class="sidebar"> <div class="btn-group btn-group-justified" role="group" aria-label="..."> <a class="btn btn-sm btn-default" ng-click="checkTopics(true)" title="Select all topics">All</a> @@ -6,14 +6,14 @@ <a class="btn btn-sm btn-default" ng-click="checkTopics()" title="Toggle all topics">Toggle</a> </div> <div class="btn-group btn-group-justified"> - <a class="btn btn-sm btn-default" ng-model="opts.sorttopics" bs-radio="'name'" title="Sort by name">α</a> - <a class="btn btn-sm btn-default" ng-model="opts.sorttopics" bs-radio="'avgRelevance'" title="Sort by average relevance">μ</a> - <a class="btn btn-sm btn-default" ng-model="opts.sorttopics" bs-radio="'varRelevance'" title="Sort by variance in relevance">σ</a> - <a class="btn btn-sm btn-default" ng-model="opts.sorttopics" bs-radio="'fallingRelevance'" title="Sort by falling relevance">↘</a> - <a class="btn btn-sm btn-default" ng-model="opts.sorttopics" bs-radio="'risingRelevance'" title="Sort by rising relevance">↗</a> - <a class="btn btn-sm btn-default" ng-model="opts.sorttopics" bs-radio="'risingDecayRelevance'" title="Sort by rising relevance with decay">↝</a> - <a class="btn btn-sm btn-link btn-plain" ng-click="opts.sortdir=!opts.sortdir"> - <sort-dir ng-model="opts.sortdir" /> + <a class="btn btn-sm btn-default" ng-model="explorerModels.sorttopics" bs-radio="'name'" title="Sort by name">α</a> + <a class="btn btn-sm btn-default" ng-model="explorerModels.sorttopics" bs-radio="'avgRelevance'" title="Sort by average relevance">μ</a> + <a class="btn btn-sm btn-default" ng-model="explorerModels.sorttopics" bs-radio="'varRelevance'" title="Sort by variance in relevance">σ</a> + <a class="btn btn-sm btn-default" ng-model="explorerModels.sorttopics" bs-radio="'fallingRelevance'" title="Sort by falling relevance">↘</a> + <a class="btn btn-sm btn-default" ng-model="explorerModels.sorttopics" bs-radio="'risingRelevance'" title="Sort by rising relevance">↗</a> + <a class="btn btn-sm btn-default" ng-model="explorerModels.sorttopics" bs-radio="'risingDecayRelevance'" title="Sort by rising relevance with decay">↝</a> + <a class="btn btn-sm btn-link btn-plain" ng-click="explorerModels.sortdir=!explorerModels.sortdir"> + <sort-dir ng-model="explorerModels.sortdir" /> </a> </div> <div class="btn-group btn-group-justified"> @@ -21,9 +21,9 @@ <span class="glyphicon glyphicon-remove-circle searchclear" ng-click="search=''"></span> </div> <ul class="list-unstyled topic-choice"> - <li ng-repeat="topic in topics | orderBy:opts.sorttopics:opts.sortdir | filter:search"> + <li ng-repeat="topic in topics | orderBy:explorerModels.sorttopics:explorerModels.sortdir | filter:search"> <div class="checkbox checkbox-condensed" ng-class="{selected:topic.selected}"> - <span class="valuebar" ng-style="{width:topicCurrValue(topic)}"></span> + <span class="valuebar" ng-style="{width:topic.topicCurrValue}"></span> <input type="checkbox" ng-model="topic.selected" ng-attr-id="{{::topic.id}}" ng-change="redrawGraph()"> <label class="check" ng-attr-for="{{::topic.id}}"> <topic-menu topic="topic" /> @@ -41,21 +41,21 @@ <div class="topbar"> <small>Values:</small> <div class="btn-group"> - <a class="btn btn-sm btn-default" ng-model="opts.seqstyle" bs-radio="'absolute'">Absolute</a> - <a class="btn btn-sm btn-default" ng-model="opts.seqstyle" bs-radio="'relative'">Relative</a> + <a class="btn btn-sm btn-default" ng-model="explorerModels.seqstyle" bs-radio="'absolute'">Absolute</a> + <a class="btn btn-sm btn-default" ng-model="explorerModels.seqstyle" bs-radio="'relative'">Relative</a> </div> <small>Chart:</small> <div class="btn-group"> - <a class="btn btn-sm btn-default" ng-model="opts.chartstyle" bs-radio="'areaspline'">Area</a> - <a class="btn btn-sm btn-default" ng-model="opts.chartstyle" bs-radio="'spline'">Line</a> + <a class="btn btn-sm btn-default" ng-model="explorerModels.chartstyle" bs-radio="'areaspline'">Area</a> + <a class="btn btn-sm btn-default" ng-model="explorerModels.chartstyle" bs-radio="'spline'">Line</a> </div> <small>Stacking:</small> <div class="btn-group"> - <a class="btn btn-sm btn-default" ng-model="opts.chartstack" bs-radio="'none'">None</a> - <a class="btn btn-sm btn-default" ng-model="opts.chartstack" bs-radio="'normal'">Value</a> - <a class="btn btn-sm btn-default" ng-model="opts.chartstack" bs-radio="'percent'">Percent</a> + <a class="btn btn-sm btn-default" ng-model="explorerModels.chartstack" bs-radio="'none'">None</a> + <a class="btn btn-sm btn-default" ng-model="explorerModels.chartstack" bs-radio="'normal'">Value</a> + <a class="btn btn-sm btn-default" ng-model="explorerModels.chartstack" bs-radio="'percent'">Percent</a> </div> </div> <div class="chart" highcharts="topicSeq"></div> diff --git a/vipra-ui/app/html/index.html b/vipra-ui/app/html/index.html index d27f4c3d..e3961950 100644 --- a/vipra-ui/app/html/index.html +++ b/vipra-ui/app/html/index.html @@ -1,4 +1,4 @@ -<div class="container" ng-cloak ng-hide="$state.current.name !== 'index'"> +<div class="container" ng-cloak ng-hide="!rootModels.topicModel || $state.current.name !== 'index'"> <div class="row" ng-hide="search"> <div class="col-md-12 text-center"> <svg class="logo hover heading" viewBox="0 0 200 120"> diff --git a/vipra-ui/app/html/network.html b/vipra-ui/app/html/network.html index 8f75e495..445a5473 100644 --- a/vipra-ui/app/html/network.html +++ b/vipra-ui/app/html/network.html @@ -1,4 +1,4 @@ -<div ng-cloak ng-hide="$state.current.name !== 'network'"> +<div ng-cloak ng-hide="!rootModels.topicModel || $state.current.name !== 'network'"> <div class="fullsize navpadding"> <div class="graph-legend overlay"> <div class="checkbox"> diff --git a/vipra-ui/app/html/partials/topic-popover.html b/vipra-ui/app/html/partials/topic-popover.html index a1708a91..e1b09ea5 100644 --- a/vipra-ui/app/html/partials/topic-popover.html +++ b/vipra-ui/app/html/partials/topic-popover.html @@ -8,11 +8,11 @@ <th class="text-center">↝</th> </tr> <tr> - <td class="text-center" ng-bind-template="{{::topic.avgRelevance.toFixed(2)}}" ng-class="{'active text-primary':opts.sorttopics==='avgRelevance'}"></td> - <td class="text-center" ng-bind-template="{{::topic.varRelevance.toFixed(2)}}" ng-class="{'active text-primary':opts.sorttopics==='varRelevance'}"></td> - <td class="text-center" ng-bind-template="{{::topic.fallingRelevance.toFixed(2)}}" ng-class="{'active text-primary':opts.sorttopics==='fallingRelevance'}"></td> - <td class="text-center" ng-bind-template="{{::topic.risingRelevance.toFixed(2)}}" ng-class="{'active text-primary':opts.sorttopics==='risingRelevance'}"></td> - <td class="text-center" ng-bind-template="{{::topic.risingDecayRelevance.toFixed(2)}}" ng-class="{'active text-primary':opts.sorttopics==='risingDecayRelevance'}"></td> + <td class="text-center" ng-bind-template="{{::topic.avgRelevance.toFixed(2)}}" ng-class="{'active text-primary':explorerModels.sorttopics==='avgRelevance'}"></td> + <td class="text-center" ng-bind-template="{{::topic.varRelevance.toFixed(2)}}" ng-class="{'active text-primary':explorerModels.sorttopics==='varRelevance'}"></td> + <td class="text-center" ng-bind-template="{{::topic.fallingRelevance.toFixed(2)}}" ng-class="{'active text-primary':explorerModels.sorttopics==='fallingRelevance'}"></td> + <td class="text-center" ng-bind-template="{{::topic.risingRelevance.toFixed(2)}}" ng-class="{'active text-primary':explorerModels.sorttopics==='risingRelevance'}"></td> + <td class="text-center" ng-bind-template="{{::topic.risingDecayRelevance.toFixed(2)}}" ng-class="{'active text-primary':explorerModels.sorttopics==='risingDecayRelevance'}"></td> </tr> </tbody> </table> diff --git a/vipra-ui/app/html/sequences/index.html b/vipra-ui/app/html/sequences/index.html deleted file mode 100644 index e69de29b..00000000 diff --git a/vipra-ui/app/html/sequences/show.html b/vipra-ui/app/html/sequences/show.html deleted file mode 100644 index e69de29b..00000000 diff --git a/vipra-ui/app/html/topics/articles.html b/vipra-ui/app/html/topics/articles.html index c7ecd073..a95e3848 100644 --- a/vipra-ui/app/html/topics/articles.html +++ b/vipra-ui/app/html/topics/articles.html @@ -1,4 +1,4 @@ -<div class="container" ng-cloak ng-hide="$state.current.name !== 'topics.show.articles'"> +<div class="container" ng-cloak ng-hide="!rootModels.topicModel || $state.current.name !== 'topics.show.articles'"> <div class="row"> <div class="col-md-12"> <div class="page-header"> @@ -15,7 +15,7 @@ </div> <div class="row"> <div class="col-md-12"> - <pagination total="articlesTotal" page="page" limit="limit" change="changePage" /> + <pagination total="articlesTotal" page="topicsArticlesModels.page" limit="topicsArticlesModels.limit" change="changePage" /> </div> </div> <div class="row"> @@ -26,12 +26,12 @@ <ng-pluralize count="articlesTotal||0" when="{0:'no articles',1:'1 article',other:'{} articles'}"></ng-pluralize> in the database. <span ng-show="articlesTotal"> Sort by - <ol class="nya-bs-select nya-bs-condensed" ng-model="opts.sortkey"> + <ol class="nya-bs-select nya-bs-condensed" ng-model="topicsArticlesModels.sortkey"> <li value="title" class="nya-bs-option"><a>Title</a></li> <li value="date" class="nya-bs-option"><a>Date</a></li> <li value="created" class="nya-bs-option"><a>Added</a></li> </ol> - <sort-dir ng-model="opts.sortdir" /> + <sort-dir ng-model="topicsArticlesModels.sortdir" /> </span> </div> <table class="table table-hover table-condensed"> @@ -44,14 +44,14 @@ </tbody> </table> <div class="panel-footer"> - Page <span ng-bind="page||1"></span> of <span ng-bind="maxPage||1"></span> + Page <span ng-bind="topicsArticlesModels.page||1"></span> of <span ng-bind="maxPage||1"></span> </div> </div> </div> </div> <div class="row"> <div class="col-md-12"> - <pagination total="articlesTotal" page="page" limit="limit" change="changePage" /> + <pagination total="articlesTotal" page="topicsArticlesModels.page" limit="topicsArticlesModels.limit" change="changePage" /> </div> </div> </div> diff --git a/vipra-ui/app/html/topics/index.html b/vipra-ui/app/html/topics/index.html index 3a8babc5..b58dd690 100644 --- a/vipra-ui/app/html/topics/index.html +++ b/vipra-ui/app/html/topics/index.html @@ -1,7 +1,7 @@ -<div class="container" ng-cloak ng-hide="$state.current.name !== 'topics'"> +<div class="container" ng-cloak ng-hide="!rootModels.topicModel || $state.current.name !== 'topics'"> <div class="row"> <div class="col-md-12"> - <pagination total="topicsTotal" page="page" limit="limit" /> + <pagination total="topicsTotal" page="topicsIndexModels.page" limit="topicsIndexModels.limit" /> </div> </div> <div class="row"> @@ -12,11 +12,11 @@ <ng-pluralize count="topicsTotal||0" when="{0:'no topics',1:'1 topic',other:'{} topics'}"></ng-pluralize> in the database. <span ng-show="topicsTotal"> Sort by - <ol class="nya-bs-select nya-bs-condensed" ng-model="opts.sortkey"> + <ol class="nya-bs-select nya-bs-condensed" ng-model="topicsIndexModels.sortkey"> <li value="name" class="nya-bs-option"><a>Name</a></li> <li value="created" class="nya-bs-option"><a>Added</a></li> </ol> - <sort-dir ng-model="opts.sortdir" /> + <sort-dir ng-model="topicsIndexModels.sortdir" /> </span> </div> <table class="table table-hover table-condensed"> @@ -29,14 +29,14 @@ </tbody> </table> <div class="panel-footer"> - Page <span ng-bind="page||1"></span> of <span ng-bind="maxPage||1"></span> + Page <span ng-bind="topicsIndexModels.page||1"></span> of <span ng-bind="maxPage||1"></span> </div> </div> </div> </div> <div class="row"> <div class="col-md-12"> - <pagination total="topicsTotal" page="page" limit="limit" /> + <pagination total="topicsTotal" page="topicsIndexModels.page" limit="topicsIndexModels.limit" /> </div> </div> </div> diff --git a/vipra-ui/app/html/topics/show.html b/vipra-ui/app/html/topics/show.html index e04ddc66..afd55ae7 100644 --- a/vipra-ui/app/html/topics/show.html +++ b/vipra-ui/app/html/topics/show.html @@ -1,4 +1,4 @@ -<div class="container" ng-cloak ng-hide="$state.current.name !== 'topics.show'"> +<div class="container" ng-cloak ng-hide="!rootModels.topicModel || $state.current.name !== 'topics.show'"> <div class="row"> <div class="col-md-12"> <div class="page-header"> @@ -60,14 +60,14 @@ <div class="panel-heading"> <small>Values:</small> <div class="btn-group"> - <a class="btn btn-sm btn-default" ng-model="opts.seqstyle" bs-radio="'absolute'">Absolute</a> - <a class="btn btn-sm btn-default" ng-model="opts.seqstyle" bs-radio="'relative'">Relative</a> + <a class="btn btn-sm btn-default" ng-model="topicsShowModels.seqstyle" bs-radio="'absolute'">Absolute</a> + <a class="btn btn-sm btn-default" ng-model="topicsShowModels.seqstyle" bs-radio="'relative'">Relative</a> </div> <small>Chart:</small> <div class="btn-group"> - <a class="btn btn-sm btn-default" ng-model="opts.chartstyle" bs-radio="'areaspline'">Area</a> - <a class="btn btn-sm btn-default" ng-model="opts.chartstyle" bs-radio="'spline'">Line</a> + <a class="btn btn-sm btn-default" ng-model="topicsShowModels.chartstyle" bs-radio="'areaspline'">Area</a> + <a class="btn btn-sm btn-default" ng-model="topicsShowModels.chartstyle" bs-radio="'spline'">Line</a> </div> </div> <div class="panel-body"> @@ -87,12 +87,12 @@ <table class="table table-condensed table-bordered table-hover" ng-show="sequence"> <thead> <tr> - <th ng-model="opts.sortwords" sort-by="id">Word</th> - <th ng-model="opts.sortwords" sort-by="likeliness">Likeliness</th> + <th ng-model="topicsShowModels.sortwords" sort-by="id">Word</th> + <th ng-model="topicsShowModels.sortwords" sort-by="likeliness">Likeliness</th> </tr> </thead> <tbody> - <tr ng-repeat="word in sequence.words | orderBy:opts.sortwords"> + <tr ng-repeat="word in sequence.words | orderBy:topicsShowModels.sortwords"> <td ng-bind="word.id"></td> <td ng-bind="word.likeliness.toFixed(4)"></td> </tr> diff --git a/vipra-ui/app/index.html b/vipra-ui/app/index.html index 49d4af3a..c39c42be 100644 --- a/vipra-ui/app/index.html +++ b/vipra-ui/app/index.html @@ -65,9 +65,6 @@ <li ui-sref-active="active"> <a ui-sref="topics">Topics</a> </li> - <li ui-sref-active="active"> - <a ui-sref="sequences">Sequences</a> - </li> </ul> <ul class="nav navbar-nav navbar-right"> <li> @@ -86,20 +83,20 @@ </div> <!-- /.container-fluid --> </nav> - <div class="main" ui-view ng-cloak ng-show="topicModel"></div> + <div class="main" ui-view ng-cloak></div> - <div id="topicModelModal" class="modal fade" tabindex="-1" role="dialog" data-backdrop="static" data-keyboard="false" bs-modal> + <div id="topicModelModal" class="modal fade" tabindex="-1" role="dialog" data-backdrop="static" data-keyboard="false"> <div class="modal-dialog modal-lg"> <div class="modal-content"> <div class="modal-header"> - <button type="button" class="close" data-dismiss="modal" aria-label="Close" ng-show="topicModel"><span aria-hidden="true">×</span></button> + <button type="button" class="close" data-dismiss="modal" aria-label="Close" ng-show="rootModels.topicModel"><span aria-hidden="true">×</span></button> <h4 class="modal-title">Topic Models</h4> </div> <div class="modal-body"> <ul class="list-group" ng-show="topicModels.length"> - <button type="button" class="list-group-item" ng-repeat="model in topicModels" ng-click="changeTopicModel(model)" ng-class="{active:topicModel.id===model.id}"> - <span class="badge" ng-bind="model.modelConfig.kTopics"></span> - <span ng-bind="model.id"></span> + <button type="button" class="list-group-item" ng-repeat="topicModel in topicModels" ng-click="changeTopicModel(topicModel)" ng-class="{active:rootModels.topicModel.id===topicModel.id}"> + <span class="badge" ng-bind="topicModel.modelConfig.kTopics"></span> + <span ng-bind="topicModel.id"></span> </button> </ul> <p class="text-center" ng-show="loading.any"> diff --git a/vipra-ui/app/js/app.js b/vipra-ui/app/js/app.js index aa9d621a..9b0ad989 100644 --- a/vipra-ui/app/js/app.js +++ b/vipra-ui/app/js/app.js @@ -82,20 +82,6 @@ controller: 'TopicsArticlesController' }); - // states: sequences - - $stateProvider.state('sequences', { - url: '/sequences', - templateUrl: 'html/sequences/index.html', - controller: 'SequencesIndexController' - }); - - $stateProvider.state('sequences.show', { - url: '/:id', - templateUrl: 'html/sequences/show.html', - controller: 'SequencesShowController' - }); - }]); app.config(['$httpProvider', function($httpProvider) { diff --git a/vipra-ui/app/js/controllers.js b/vipra-ui/app/js/controllers.js index 5fb343e0..4be0f3af 100644 --- a/vipra-ui/app/js/controllers.js +++ b/vipra-ui/app/js/controllers.js @@ -16,6 +16,20 @@ function($scope, $state, TopicModelFactory) { $scope.$state = $state; + $scope.rootModels = { + topicModel: null + }; + + if(localStorage.topicModel) { + try { + var topicModel = JSON.parse(localStorage.topicModel); + TopicModelFactory.get({ + id: topicModel.id + }, function(data) { + $scope.rootModels.topicModel = data; + }); + } catch(e) {} + } TopicModelFactory.query({ fields: 'modelConfig' @@ -25,8 +39,13 @@ $scope.errors = err; }); + $scope.chooseTopicModel = function() { + $('#topicModelModal').modal(); + }; + $scope.changeTopicModel = function(topicModel) { - $scope.topicModel = topicModel; + $scope.rootModels.topicModel = topicModel; + localStorage.topicModel = JSON.stringify(topicModel); $('#topicModelModal').modal('hide'); }; @@ -39,13 +58,17 @@ app.controller('IndexController', ['$scope', '$location', 'ArticleFactory', 'TopicFactory', 'SearchFactory', function($scope, $location, ArticleFactory, TopicFactory, SearchFactory) { + // page was reloaded, choose topic model + if(!$scope.rootModels.topicModel) + $scope.chooseTopicModel(); + $scope.search = $location.search().query; - $scope.$watch('topicModel', function(topicModel) { - if(!topicModel) return; + $scope.$watch('rootModels.topicModel', function() { + if(!$scope.rootModels.topicModel) return; ArticleFactory.query({ - topicModel: topicModel.id, + topicModel: $scope.rootModels.topicModel.id, limit: 3, sort: '-created' }, function(data) { @@ -55,7 +78,7 @@ }); TopicFactory.query({ - topicModel: topicModel.id, + topicModel: $scope.rootModels.topicModel.id, limit: 3, sort: '-created' }, function(data) { @@ -65,13 +88,13 @@ }); }); - $scope.$watchGroup(['search', 'topicModel'], function() { - if ($scope.search && $scope.topicModel) { + $scope.$watchGroup(['search', 'rootModels.topicModel'], function() { + if ($scope.search && $scope.rootModels.topicModel) { $location.search('query', $scope.search); $scope.searching = true; SearchFactory.query({ - topicModel: $scope.topicModel.id, + topicModel: $scope.rootModels.topicModel.id, limit: 10, query: $scope.search }, function(data) { @@ -162,8 +185,17 @@ return; } + // if the topic model is not set, the page was refreshed + // set to true, id of current node decides topic model + if(!$scope.rootModels.topicModel) + $scope.rootModels.topicModel = true; + // get root node - factory.get({ id: $stateParams.id }, function(data) { + factory.get({ + id: $stateParams.id + }, function(data) { + $scope.rootNode = data; + // add root node if ($stateParams.type === 'articles') $scope.nodes.add([articleNode(data)]); @@ -176,6 +208,12 @@ $scope.graph = new vis.Network(container, $scope.data, $scope.options); $scope.graph.on('selectNode', $scope.select); $scope.graph.on('doubleClick', $scope.open); + + // take topic model from node + if(!angular.isObject($scope.rootModels.topicModel)) + $scope.rootModels.topicModel = data.topicModel; + }, function(err) { + $scope.errors = err; }); var newNode = function(title, type, show, dbid, color, shape) { @@ -290,11 +328,19 @@ $state.transitionTo(node.show, { id: node.dbid }); }; + $scope.$watch('rootModels.topicModel', function(newVal) { + if($scope.rootNode && $scope.rootNode.topicModel.id !== newVal.id) + $state.transitionTo('index'); + }); } ]); - app.controller('ExplorerController', ['$scope', '$templateCache', '$compile', 'TopicFactory', - function($scope, $templateCache, $compile, TopicFactory) { + app.controller('ExplorerController', ['$scope', '$templateCache', '$timeout', 'TopicFactory', + function($scope, $templateCache, $timeout, TopicFactory) { + + // page was reloaded, choose topic model + if(!$scope.rootModels.topicModel) + $scope.chooseTopicModel(); var avgMax = 0, varMax = 0, @@ -303,7 +349,7 @@ risingDecayMax = 0, risingDecayMin = 0; - $scope.opts = { + $scope.explorerModels = { sorttopics: 'name', sortdir: false, seqstyle: 'absolute', @@ -311,25 +357,30 @@ chartstack: 'none' }; - TopicFactory.query({ - fields: 'name,sequences,avgRelevance,varRelevance,risingRelevance,fallingRelevance,risingDecayRelevance' - }, function(data) { - $scope.topics = data; - var colors = randomColor({ count: $scope.topics.length, seed: 1 }); - for (var i = 0, t; i < $scope.topics.length; i++) { - t = $scope.topics[i]; - t.color = colors[i]; - avgMax = Math.max(t.avgRelevance, avgMax); - varMax = Math.max(t.varRelevance, varMax); - fallingMax = Math.max(t.fallingRelevance, fallingMax); - risingMax = Math.max(t.risingRelevance, risingMax); - risingDecayMax = Math.max(t.risingDecayRelevance, risingDecayMax); - risingDecayMin = Math.max(t.risingDecayRelevance, risingDecayMin); - } - risingDecayMin = Math.abs(risingDecayMin); - risingDecayMax = risingDecayMin + Math.abs(risingDecayMax); - }, function(err) { - $scope.errors = err; + $scope.$watch('rootModels.topicModel', function() { + if(!$scope.rootModels.topicModel) return; + + TopicFactory.query({ + fields: 'name,sequences,avgRelevance,varRelevance,risingRelevance,fallingRelevance,risingDecayRelevance', + topicModel: $scope.rootModels.topicModel.id + }, function(data) { + $scope.topics = data; + var colors = randomColor({ count: $scope.topics.length, seed: 1 }); + for (var i = 0, t; i < $scope.topics.length; i++) { + t = $scope.topics[i]; + t.color = colors[i]; + avgMax = Math.max(t.avgRelevance, avgMax); + varMax = Math.max(t.varRelevance, varMax); + fallingMax = Math.max(t.fallingRelevance, fallingMax); + risingMax = Math.max(t.risingRelevance, risingMax); + risingDecayMax = Math.max(t.risingDecayRelevance, risingDecayMax); + risingDecayMin = Math.max(t.risingDecayRelevance, risingDecayMin); + } + risingDecayMin = Math.abs(risingDecayMin); + risingDecayMax = risingDecayMin + Math.abs(risingDecayMax); + }, function(err) { + $scope.errors = err; + }); }); $scope.checkTopics = function(to) { @@ -354,7 +405,7 @@ // data array with relevances and min/max for (var j = 0, sequence, relevance; j < topic.sequences.length; j++) { sequence = topic.sequences[j]; - relevance = $scope.opts.seqstyle === 'relative' ? sequence.relevanceChange : sequence.relevance; + relevance = $scope.explorerModels.seqstyle === 'relative' ? sequence.relevanceChange : sequence.relevance; relevances.push({ x: new Date(sequence.window.startDate).getTime(), y: relevance, @@ -372,20 +423,14 @@ } // highcharts configuration - $scope.topicSeq = areaRelevanceChart(series, $scope.selectNode, $scope.opts.chartstyle, - $scope.opts.chartstack); + $scope.topicSeq = areaRelevanceChart(series, $scope.explorerModels.chartstyle, + $scope.explorerModels.chartstack); $scope.topicsSelected = series.length; }; - $scope.selectNode = function(node) { - $scope.$apply(function() { - - }); - }; - $scope.topicCurrValue = function(topic) { var percent = 0; - switch ($scope.opts.sorttopics) { + switch ($scope.explorerModels.sorttopics) { case 'avgRelevance': percent = topic.avgRelevance / avgMax; break; @@ -405,7 +450,16 @@ return (percent * 100) + '%'; }; - $scope.$watchGroup(['opts.seqstyle', 'opts.chartstyle', 'opts.chartstack'], $scope.redrawGraph); + $scope.$watchGroup(['explorerModels.seqstyle', 'explorerModels.chartstyle', 'explorerModels.chartstack'], $scope.redrawGraph); + + $scope.$watch('explorerModels.sorttopics', function() { + if(!$scope.topics) return; + + $timeout(function() { + for(var i = 0; i < $scope.topics.length; i++) + $scope.topics[i].topicCurrValue = $scope.topicCurrValue($scope.topics[i]); + }, 100); + }); } ]); @@ -419,23 +473,29 @@ app.controller('ArticlesIndexController', ['$scope', '$state', '$location', 'ArticleFactory', function($scope, $state, $location, ArticleFactory) { - $scope.opts = { + // page was reloaded, choose topic model + if(!$scope.rootModels.topicModel && $state.current.name === 'articles') + $scope.chooseTopicModel(); + + $scope.articlesIndexModels = { sortkey: 'date', - sortdir: true + sortdir: true, + page: Math.max($location.search().page || 1, 1), + limit: 100 }; - $scope.page = Math.max($location.search().page || 1, 1); - $scope.limit = 100; + $scope.$watchGroup(['articlesIndexModels.page', 'articlesIndexModels.sortkey', 'articlesIndexModels.sortdir', 'rootModels.topicModel'], function() { + if(!$scope.rootModels.topicModel) return; - $scope.$watchGroup(['page', 'opts.sortkey', 'opts.sortdir'], function() { ArticleFactory.query({ - skip: ($scope.page - 1) * $scope.limit, - limit: $scope.limit, - sort: ($scope.opts.sortdir ? '' : '-') + $scope.opts.sortkey + skip: ($scope.articlesIndexModels.page - 1) * $scope.articlesIndexModels.limit, + limit: $scope.articlesIndexModels.limit, + sort: ($scope.articlesIndexModels.sortdir ? '' : '-') + $scope.articlesIndexModels.sortkey, + topicModel: $scope.rootModels.topicModel.id }, function(data, headers) { $scope.articles = data; $scope.articlesTotal = headers("V-Total"); - $scope.maxPage = Math.ceil($scope.articlesTotal / $scope.limit); + $scope.maxPage = Math.ceil($scope.articlesTotal / $scope.articlesIndexModels.limit); }, function(err) { $scope.errors = err; }); @@ -447,8 +507,8 @@ /** * Article Show route */ - app.controller('ArticlesShowController', ['$scope', '$stateParams', 'ArticleFactory', - function($scope, $stateParams, ArticleFactory) { + app.controller('ArticlesShowController', ['$scope', '$state', '$stateParams', '$timeout', 'ArticleFactory', + function($scope, $state, $stateParams, $timeout, ArticleFactory) { $scope.topicSort = $scope.topicSort || 'share'; $scope.topicSortRev = typeof $scope.topicSortRev === 'undefined' ? true : $scope.topicSortRev; @@ -462,6 +522,10 @@ $scope.articleCreated = Vipra.formatDateTime($scope.article.created); $scope.articleModified = Vipra.formatDateTime($scope.article.modified); + // take topic model from article + if(!angular.isObject($scope.rootModels.topicModel)) + $scope.rootModels.topicModel = data.topicModel; + // calculate percentage share if ($scope.article.topics) { var topicShareSeries = [], @@ -485,26 +549,23 @@ // preselect biggest value maximum.selected = maximum.sliced = true; - // highcharts data - $scope.topicShare = topicShareChart([{ - name: 'Topic Share', - colorByPoint: true, - data: topicShareSeries - }]); + $timeout(function() { + // highcharts data + $scope.topicShare = topicShareChart([{ + name: 'Topic Share', + colorByPoint: true, + data: topicShareSeries + }]); + }, 0); } }, function(err) { $scope.errors = err; }); - } - ]); - - /** - * Article Similar route - */ - app.controller('ArticlesSimilarController', [ - function() { - + $scope.$watch('rootModels.topicModel', function(newVal) { + if($scope.article && $scope.article.topicModel.id !== newVal.id) + $state.transitionTo('index'); + }); } ]); @@ -515,29 +576,32 @@ /** * Topic Index route */ - app.controller('TopicsIndexController', ['$scope', '$location', 'TopicFactory', - function($scope, $location, TopicFactory) { + app.controller('TopicsIndexController', ['$scope', '$state', '$location', 'TopicFactory', + function($scope, $state, $location, TopicFactory) { - $scope.opts = { + // page was reloaded, choose topic model + if(!$scope.rootModels.topicModel && $state.current.name === 'topics') + $scope.chooseTopicModel(); + + $scope.topicsIndexModels = { sortkey: 'name', - sortdir: true + sortdir: true, + page: Math.max($location.search().page || 1, 1), + limit: 100 }; - $scope.page = Math.max($location.search().page || 1, 1); - $scope.limit = 100; - - $scope.$watchGroup(['page', 'opts.sortkey', 'opts.sortdir', 'topicModel'], function() { - if(!$scope.topicModel) return; + $scope.$watchGroup(['topicsIndexModels.page', 'topicsIndexModels.sortkey', 'topicsIndexModels.sortdir', 'rootModels.topicModel'], function() { + if(!$scope.rootModels.topicModel) return; TopicFactory.query({ - topicModel: $scope.topicModel.id, - skip: ($scope.page - 1) * $scope.limit, - limit: $scope.limit, - sort: ($scope.opts.sortdir ? '' : '-') + $scope.opts.sortkey + topicModel: $scope.rootModels.topicModel.id, + skip: ($scope.topicsIndexModels.page - 1) * $scope.topicsIndexModels.limit, + limit: $scope.topicsIndexModels.limit, + sort: ($scope.topicsIndexModels.sortdir ? '' : '-') + $scope.topicsIndexModels.sortkey }, function(data, headers) { $scope.topics = data; $scope.topicsTotal = headers("V-Total"); - $scope.maxPage = Math.ceil($scope.topicsTotal / $scope.limit); + $scope.maxPage = Math.ceil($scope.topicsTotal / $scope.topicsIndexModels.limit); }, function(err) { $scope.errors = err; }); @@ -549,45 +613,46 @@ /** * Topic Show route */ - app.controller('TopicsShowController', ['$scope', '$stateParams', '$timeout', 'TopicFactory', 'SequenceFactory', - function($scope, $stateParams, $timeout, TopicFactory, SequenceFactory) { + app.controller('TopicsShowController', ['$scope', '$state', '$stateParams', '$timeout', 'TopicFactory', 'SequenceFactory', + function($scope, $state, $stateParams, $timeout, TopicFactory, SequenceFactory) { - $scope.opts = { + $scope.topicsShowModels = { seqstyle: 'absolute', chartstyle: 'areaspline', sortwords: '-likeliness' }; - $scope.$watch('topicModel', function() { - if(!$scope.topicModel) return; + TopicFactory.get({ + id: $stateParams.id + }, function(data) { + $scope.topic = data; + $scope.topicCreated = Vipra.formatDateTime($scope.topic.created); + $scope.topicModified = Vipra.formatDateTime($scope.topic.modified); + + // take topic model from topic + if(!angular.isObject($scope.rootModels.topicModel)) + $scope.rootModels.topicModel = data.topicModel; - TopicFactory.get({ - id: $stateParams.id, - topicModel: $scope.topicModel.id - }, function(data) { - $scope.topic = data; - $scope.topicCreated = Vipra.formatDateTime($scope.topic.created); - $scope.topicModified = Vipra.formatDateTime($scope.topic.modified); + $timeout(function() { $scope.redrawGraph(); - }, function(err) { - $scope.errors = err; - }); + }, 0); + }, function(err) { + $scope.errors = err; }); $scope.redrawGraph = function() { if (!$scope.topic || !$scope.topic.sequences) return; - console.log('redraw relevance chart'); var relevances = []; // create series for (var i = 0, sequence, relevance; i < $scope.topic.sequences.length; i++) { sequence = $scope.topic.sequences[i]; - relevance = $scope.opts.seqstyle === 'relative' ? sequence.relevanceChange : sequence.relevance; + relevance = $scope.topicsShowModels.seqstyle === 'relative' ? sequence.relevanceChange : sequence.relevance; relevances.push([new Date(sequence.window.startDate).getTime(), relevance]); } // highcharts configuration - $scope.topicSeq = areaRelevanceChart([{ name: $scope.topic.name, data: relevances }], null, $scope.opts.chartstyle); + $scope.topicSeq = areaRelevanceChart([{ name: $scope.topic.name, data: relevances }], $scope.topicsShowModels.chartstyle); }; $scope.startRename = function() { @@ -622,15 +687,14 @@ } }; - $scope.$watch('opts.seqstyle', $scope.redrawGraph); - $scope.$watch('opts.chartstyle', $scope.redrawGraph); + $scope.$watch('topicsShowModels.seqstyle', $scope.redrawGraph); + $scope.$watch('topicsShowModels.chartstyle', $scope.redrawGraph); - $scope.$watchGroup(['sequenceId', 'topicModel'], function() { - if(!$scope.sequenceId || !$scope.topicModel) return; + $scope.$watchGroup(['sequenceId'], function() { + if(!$scope.sequenceId) return; SequenceFactory.get({ id: $scope.sequenceId, - topicModel: $scope.topicModel.id, topWords: 20 }, function(data) { $scope.sequence = data; @@ -638,6 +702,11 @@ $scope.errors = err; }); }); + + $scope.$watch('rootModels.topicModel', function(newVal) { + if($scope.topic && $scope.topic.topicModel.id !== newVal.id) + $state.transitionTo('index'); + }); } ]); @@ -647,27 +716,23 @@ app.controller('TopicsArticlesController', ['$scope', '$stateParams', '$location', 'TopicFactory', function($scope, $stateParams, $location, TopicFactory) { - $scope.opts = { + $scope.topicsArticlesModels = { sortkey: 'title', - sortdir: true + sortdir: true, + page: Math.max($location.search().page || 1, 1), + limit: 100 }; - $scope.page = Math.max($location.search().page || 1, 1); - $scope.limit = 100; - - $scope.$watchGroup(['page', 'opts.sortkey', 'opts.sortdir', 'topicModel'], function() { - if(!$scope.topicModel) return; - + $scope.$watchGroup(['topicsArticlesModels.page', 'topicsArticlesModels.sortkey', 'topicsArticlesModels.sortdir'], function() { TopicFactory.articles({ id: $stateParams.id, - topicModel: $scope.topicModel.id, - skip: ($scope.page - 1) * $scope.limit, - limit: $scope.limit, - sort: ($scope.opts.sortdir ? '' : '-') + $scope.opts.sortkey + skip: ($scope.topicsArticlesModels.page - 1) * $scope.topicsArticlesModels.limit, + limit: $scope.topicsArticlesModels.limit, + sort: ($scope.topicsArticlesModels.sortdir ? '' : '-') + $scope.topicsArticlesModels.sortkey }, function(data, headers) { $scope.articles = data; $scope.articlesTotal = headers("V-Total"); - $scope.maxPage = Math.ceil($scope.articlesTotal / $scope.limit); + $scope.maxPage = Math.ceil($scope.articlesTotal / $scope.topicsArticlesModels.limit); }, function(err) { $scope.errors = err; }); @@ -727,7 +792,7 @@ * Shared Highcharts configurations ****************************************************************************/ - function areaRelevanceChart(series, clickCallback, chartType, chartStack) { + function areaRelevanceChart(series, chartType, chartStack) { return { chart: { type: (chartType || 'areaspline'), @@ -768,13 +833,6 @@ animation: false, cursor: 'pointer', allowPointSelect: true, - point: { - events: { - click: function(e) { - clickCallback(e.point); - } - } - }, states: { hover: { halo: { diff --git a/vipra-ui/app/js/directives.js b/vipra-ui/app/js/directives.js index 82900e4e..ad6d4f1b 100644 --- a/vipra-ui/app/js/directives.js +++ b/vipra-ui/app/js/directives.js @@ -11,7 +11,7 @@ 'ui.router' ]); - app.directive('topicLink', function() { + app.directive('topicLink', [function() { return { scope: { topic: '=' @@ -21,9 +21,9 @@ transclude: true, templateUrl: 'html/directives/topic-link.html' }; - }); + }]); - app.directive('articleLink', function() { + app.directive('articleLink', [function() { return { scope: { article: '=' @@ -33,9 +33,9 @@ transclude: true, templateUrl: 'html/directives/article-link.html' }; - }); + }]); - app.directive('pagination', function() { + app.directive('pagination', [function() { return { restrict: 'E', replace: true, @@ -48,9 +48,9 @@ controller: 'PaginationController', templateUrl: 'html/directives/pagination.html' }; - }); + }]); - app.directive('highcharts', function() { + app.directive('highcharts', [function() { return { scope: { highcharts: '=' @@ -63,38 +63,9 @@ }); } }; - }); - - app.directive('ngModelStore', ['Store', function(Store) { - return { - restrict: 'A', - require: 'ngModel', - link: function($scope, $elem, $attrs, $ctrl) { - if (!$attrs.ngModel) { - console.log('no model given'); - return; - } - if (typeof $attrs.ngModelStore === 'undefined') { - console.log('no store key given'); - return; - } - var key = $attrs.ngModelStore || $attrs.ngModel; - var value = Store(key); - if (value !== null) { - $ctrl.$setViewValue(value); - $ctrl.$render(); - } else if ($attrs.ngModelDefault) { - $ctrl.$setViewValue($scope.$eval($attrs.ngModelDefault)); - $ctrl.$render(); - } - $scope.$watch($attrs.ngModel, function() { - Store(key, typeof $ctrl.$viewValue === 'undefined' ? null : $ctrl.$viewValue); - }); - } - }; }]); - app.directive('bsRadio', function() { + app.directive('bsRadio', [function() { return { scope: { bsRadio: '=', @@ -118,7 +89,7 @@ }); } }; - }); + }]); app.directive('bsPopover', ['$templateCache', '$compile', function($templateCache, $compile) { @@ -146,14 +117,6 @@ } ]); - app.directive('bsModal', [function() { - return { - link: function($scope, $elem) { - $elem.modal(); - } - }; - }]); - app.directive('sequenceDropdown', [function() { return { scope: { @@ -174,7 +137,7 @@ }; }]); - app.directive('sortBy', function() { + app.directive('sortBy', [function() { return { restrict: 'A', scope: { @@ -183,32 +146,28 @@ }, link: function($scope, $elem) { $elem.click(function() { - $scope.$apply($scope.check); + $scope.$apply(function() { + $scope.reverse = false; + if ($scope.ngModel === $scope.sortBy) { + $scope.ngModel = '-' + $scope.sortBy; + $scope.reverse = true; + } else { + $scope.ngModel = $scope.sortBy; + $scope.reverse = false; + } + }); }); $scope.showCaret = function() { return $scope.ngModel === $scope.sortBy || $scope.ngModel === '-' + $scope.sortBy; }; - - $scope.check = function() { - $scope.reverse = false; - if ($scope.ngModel === $scope.sortBy) { - $scope.ngModel = '-' + $scope.sortBy; - $scope.reverse = true; - } else { - $scope.ngModel = $scope.sortBy; - $scope.reverse = false; - } - }; - - $scope.check(); }, transclude: true, template: '<span ng-transclude></span> <i class="fa" ng-class="{\'fa-caret-down\':!reverse, \'fa-caret-up\':reverse}" ng-show="showCaret()"></i>' }; - }); + }]); - app.directive('topicMenu', function() { + app.directive('topicMenu', ['TopicFactory', function(TopicFactory) { return { scope: { topic: '=', @@ -224,16 +183,27 @@ value: $scope.topic.name, callback: function(name) { if (name && name.length && name !== $scope.topic.name) { - + var oldName = $scope.topic.name; + $scope.topic.name = name; + $scope.$apply(function() { + TopicFactory.update({ + id: $scope.topic.id + }, $scope.topic, function(data) { + $scope.topic = data; + }, function(err) { + $scope.topic.name = oldName; + $scope.errors = err; + }); + }); } } }); }; } }; - }); + }]); - app.directive('sortDir', function() { + app.directive('sortDir', [function() { return { scope: { ngModel: '=' @@ -241,7 +211,7 @@ restrict: 'E', replace: true, templateUrl: 'html/directives/sort-dir.html' - } - }); + }; + }]); })(); diff --git a/vipra-ui/app/js/factories.js b/vipra-ui/app/js/factories.js index f5ff9043..97887862 100644 --- a/vipra-ui/app/js/factories.js +++ b/vipra-ui/app/js/factories.js @@ -35,76 +35,7 @@ }]); app.factory('TopicModelFactory', ['$resource', function($resource) { - return $resource(Vipra.config.restUrl + '/topicmodels'); - }]); - - // https://gist.github.com/Fluidbyte/4718380 - app.factory('Store', ['$state', function($state) { - return function(key, value) { - key += '-' + $state.current.name; - var lsSupport = false; - - // Check for native support - if (localStorage) - lsSupport = true; - - // If value is detected, set new or modify store - if (typeof value !== "undefined" && value !== null) { - // Convert object values to JSON - if (typeof value === 'object') - value = JSON.stringify(value); - // Set the store - if (lsSupport) - localStorage.setItem(key, value); - else - createCookie(key, value, 30); - } - - // No value supplied, return value - if (typeof value === "undefined") { - var data; - if (lsSupport) - data = localStorage.getItem(key); - else - data = readCookie(key); - - try { - data = JSON.parse(data); - } catch (e) { - data = data; - } - - return data; - } - - // Null specified, remove store - if (value === null) { - if (lsSupport) - localStorage.removeItem(key); - else - createCookie(key, '', -1); - } - - // Creates new cookie or removes cookie with negative expiration - function createCookie(key, value, exp) { - var date = new Date(); - date.setTime(date.getTime() + (exp * 24 * 60 * 60 * 1000)); - var expires = "; expires=" + date.toGMTString(); - document.cookie = key + "=" + value + expires + "; path=/"; - } - - // Returns contents of cookie - function readCookie(key) { - var nameEQ = key + "="; - var ca = document.cookie.split(';'); - for (var i = 0, max = ca.length; i < max; i++) { - var c = ca[i]; - while (c.charAt(0) === ' ') c = c.substring(1, c.length); - if (c.indexOf(nameEQ) === 0) return c.substring(nameEQ.length, c.length); - } - return null; - } - }; + return $resource(Vipra.config.restUrl + '/topicmodels/:id'); }]); })(); diff --git a/vipra-ui/app/less/app.less b/vipra-ui/app/less/app.less index d3e6ef59..ed9d71d3 100644 --- a/vipra-ui/app/less/app.less +++ b/vipra-ui/app/less/app.less @@ -125,7 +125,7 @@ a:hover { } .overlay { - z-index: 9999; + z-index: 1040; } .item-actions { @@ -204,7 +204,7 @@ a:hover { .colorbox { display: inline-block; width: 10px; - height: 100%; + height: 20px; vertical-align: middle; float: right; border-radius: 3px; @@ -217,7 +217,10 @@ a:hover { top: 0; left: 0; height: 100%; + width: 0px; background: @valuebg; + transition: width .5s linear; + transition-delay: .2s; *:hover > & { background: darken(@valuebg, 5%); } diff --git a/vipra-util/src/main/java/de/vipra/util/model/Article.java b/vipra-util/src/main/java/de/vipra/util/model/Article.java index 40635289..37460684 100644 --- a/vipra-util/src/main/java/de/vipra/util/model/Article.java +++ b/vipra-util/src/main/java/de/vipra/util/model/Article.java @@ -8,6 +8,9 @@ import org.mongodb.morphia.annotations.Id; import org.mongodb.morphia.annotations.Index; import org.mongodb.morphia.annotations.Indexes; +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; + +@JsonIgnoreProperties(ignoreUnknown = true) @SuppressWarnings("serial") @Entity(value = "articles", noClassnameStored = true) @Indexes({ @Index("title"), @Index("date"), @Index("-created") }) 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 179af172..692ca2ed 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 @@ -20,6 +20,8 @@ import org.mongodb.morphia.annotations.Transient; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; + import de.vipra.util.Constants; import de.vipra.util.MongoUtils; import de.vipra.util.NestedMap; @@ -27,6 +29,7 @@ import de.vipra.util.StringUtils; import de.vipra.util.an.ElasticIndex; import de.vipra.util.an.QueryIgnore; +@JsonIgnoreProperties(ignoreUnknown = true) @SuppressWarnings("serial") @Entity(value = "articles", noClassnameStored = true) @Indexes({ @Index("title"), @Index("date"), @Index("-created") }) diff --git a/vipra-util/src/main/java/de/vipra/util/model/ArticleStats.java b/vipra-util/src/main/java/de/vipra/util/model/ArticleStats.java index 64c13b17..4c012be2 100644 --- a/vipra-util/src/main/java/de/vipra/util/model/ArticleStats.java +++ b/vipra-util/src/main/java/de/vipra/util/model/ArticleStats.java @@ -4,6 +4,9 @@ import java.io.Serializable; import org.mongodb.morphia.annotations.Embedded; +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; + +@JsonIgnoreProperties(ignoreUnknown = true) @Embedded public class ArticleStats implements Serializable { diff --git a/vipra-util/src/main/java/de/vipra/util/model/ArticleWord.java b/vipra-util/src/main/java/de/vipra/util/model/ArticleWord.java index fe043792..f0fc0cab 100644 --- a/vipra-util/src/main/java/de/vipra/util/model/ArticleWord.java +++ b/vipra-util/src/main/java/de/vipra/util/model/ArticleWord.java @@ -4,6 +4,9 @@ import java.io.Serializable; import org.mongodb.morphia.annotations.Embedded; +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; + +@JsonIgnoreProperties(ignoreUnknown = true) @SuppressWarnings("serial") @Embedded public class ArticleWord implements Comparable<ArticleWord>, Serializable { diff --git a/vipra-util/src/main/java/de/vipra/util/model/Sequence.java b/vipra-util/src/main/java/de/vipra/util/model/Sequence.java index 35752e9e..3d59fdcd 100644 --- a/vipra-util/src/main/java/de/vipra/util/model/Sequence.java +++ b/vipra-util/src/main/java/de/vipra/util/model/Sequence.java @@ -6,10 +6,10 @@ import org.bson.types.ObjectId; import org.mongodb.morphia.annotations.Embedded; import org.mongodb.morphia.annotations.Entity; import org.mongodb.morphia.annotations.Id; -import org.mongodb.morphia.annotations.Reference; -import de.vipra.util.an.QueryIgnore; +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +@JsonIgnoreProperties(ignoreUnknown = true) @SuppressWarnings("serial") @Entity(value = "sequences", noClassnameStored = true) public class Sequence implements Model<ObjectId>, Comparable<Sequence>, Serializable { @@ -17,10 +17,6 @@ public class Sequence implements Model<ObjectId>, Comparable<Sequence>, Serializ @Id private ObjectId id = new ObjectId(); - @Reference - @QueryIgnore(multi = true) - private TopicModel topicModel; - @Embedded private Window window; @@ -44,14 +40,6 @@ public class Sequence implements Model<ObjectId>, Comparable<Sequence>, Serializ this.id = id; } - public TopicModel getTopicModel() { - return topicModel; - } - - public void setTopicModel(final TopicModel topicModel) { - this.topicModel = topicModel; - } - public Window getWindow() { return window; } diff --git a/vipra-util/src/main/java/de/vipra/util/model/SequenceFull.java b/vipra-util/src/main/java/de/vipra/util/model/SequenceFull.java index 8efdbb74..a2124b59 100644 --- a/vipra-util/src/main/java/de/vipra/util/model/SequenceFull.java +++ b/vipra-util/src/main/java/de/vipra/util/model/SequenceFull.java @@ -9,8 +9,11 @@ import org.mongodb.morphia.annotations.Entity; import org.mongodb.morphia.annotations.Id; import org.mongodb.morphia.annotations.Reference; +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; + import de.vipra.util.an.QueryIgnore; +@JsonIgnoreProperties(ignoreUnknown = true) @SuppressWarnings("serial") @Entity(value = "sequences", noClassnameStored = true) public class SequenceFull implements Model<ObjectId>, Comparable<SequenceFull>, Serializable { diff --git a/vipra-util/src/main/java/de/vipra/util/model/SimilarArticle.java b/vipra-util/src/main/java/de/vipra/util/model/SimilarArticle.java index 3f975ff8..4dab9847 100644 --- a/vipra-util/src/main/java/de/vipra/util/model/SimilarArticle.java +++ b/vipra-util/src/main/java/de/vipra/util/model/SimilarArticle.java @@ -5,6 +5,9 @@ import java.io.Serializable; import org.mongodb.morphia.annotations.Embedded; import org.mongodb.morphia.annotations.Reference; +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; + +@JsonIgnoreProperties(ignoreUnknown = true) @SuppressWarnings("serial") @Embedded public class SimilarArticle implements Comparable<SimilarArticle>, Serializable { diff --git a/vipra-util/src/main/java/de/vipra/util/model/TextEntity.java b/vipra-util/src/main/java/de/vipra/util/model/TextEntity.java index d0bba63f..49dfe53d 100644 --- a/vipra-util/src/main/java/de/vipra/util/model/TextEntity.java +++ b/vipra-util/src/main/java/de/vipra/util/model/TextEntity.java @@ -4,6 +4,9 @@ import java.io.Serializable; import org.mongodb.morphia.annotations.Embedded; +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; + +@JsonIgnoreProperties(ignoreUnknown = true) @SuppressWarnings("serial") @Embedded public class TextEntity implements Serializable { diff --git a/vipra-util/src/main/java/de/vipra/util/model/Topic.java b/vipra-util/src/main/java/de/vipra/util/model/Topic.java index b2291995..644520c8 100644 --- a/vipra-util/src/main/java/de/vipra/util/model/Topic.java +++ b/vipra-util/src/main/java/de/vipra/util/model/Topic.java @@ -8,8 +8,11 @@ import org.mongodb.morphia.annotations.Id; import org.mongodb.morphia.annotations.Index; import org.mongodb.morphia.annotations.Indexes; +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; + import de.vipra.util.MongoUtils; +@JsonIgnoreProperties(ignoreUnknown = true) @SuppressWarnings("serial") @Entity(value = "topics", noClassnameStored = true) @Indexes({ @Index("name"), @Index("-created") }) diff --git a/vipra-util/src/main/java/de/vipra/util/model/TopicFull.java b/vipra-util/src/main/java/de/vipra/util/model/TopicFull.java index f875db28..d8538861 100644 --- a/vipra-util/src/main/java/de/vipra/util/model/TopicFull.java +++ b/vipra-util/src/main/java/de/vipra/util/model/TopicFull.java @@ -8,15 +8,21 @@ import java.util.List; import org.bson.types.ObjectId; import org.mongodb.morphia.annotations.Entity; import org.mongodb.morphia.annotations.Id; +import org.mongodb.morphia.annotations.Index; +import org.mongodb.morphia.annotations.Indexes; import org.mongodb.morphia.annotations.PrePersist; import org.mongodb.morphia.annotations.Reference; +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; + import de.vipra.util.MongoUtils; import de.vipra.util.StringUtils; import de.vipra.util.an.QueryIgnore; +@JsonIgnoreProperties(ignoreUnknown = true) @SuppressWarnings("serial") @Entity(value = "topics", noClassnameStored = true) +@Indexes({ @Index("name"), @Index("-created") }) public class TopicFull implements Model<ObjectId>, Serializable { @Id diff --git a/vipra-util/src/main/java/de/vipra/util/model/TopicModel.java b/vipra-util/src/main/java/de/vipra/util/model/TopicModel.java index e205a16b..781924d8 100644 --- a/vipra-util/src/main/java/de/vipra/util/model/TopicModel.java +++ b/vipra-util/src/main/java/de/vipra/util/model/TopicModel.java @@ -5,6 +5,9 @@ import java.io.Serializable; import org.mongodb.morphia.annotations.Entity; import org.mongodb.morphia.annotations.Id; +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; + +@JsonIgnoreProperties(ignoreUnknown = true) @SuppressWarnings("serial") @Entity(value = "topicmodels", noClassnameStored = true) public class TopicModel implements Model<String>, Comparable<TopicModel>, Serializable { diff --git a/vipra-util/src/main/java/de/vipra/util/model/TopicModelConfig.java b/vipra-util/src/main/java/de/vipra/util/model/TopicModelConfig.java index b916ea46..366972d6 100644 --- a/vipra-util/src/main/java/de/vipra/util/model/TopicModelConfig.java +++ b/vipra-util/src/main/java/de/vipra/util/model/TopicModelConfig.java @@ -5,10 +5,13 @@ import java.io.Serializable; import org.mongodb.morphia.annotations.Embedded; +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; + import de.vipra.util.Constants; import de.vipra.util.Constants.ProcessorMode; import de.vipra.util.Constants.WindowResolution; +@JsonIgnoreProperties(ignoreUnknown = true) @SuppressWarnings("serial") @Embedded public class TopicModelConfig implements Serializable { diff --git a/vipra-util/src/main/java/de/vipra/util/model/TopicModelFull.java b/vipra-util/src/main/java/de/vipra/util/model/TopicModelFull.java index 13a0a138..ad5572ab 100644 --- a/vipra-util/src/main/java/de/vipra/util/model/TopicModelFull.java +++ b/vipra-util/src/main/java/de/vipra/util/model/TopicModelFull.java @@ -6,8 +6,11 @@ import org.mongodb.morphia.annotations.Embedded; import org.mongodb.morphia.annotations.Entity; import org.mongodb.morphia.annotations.Id; +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; + import de.vipra.util.an.QueryIgnore; +@JsonIgnoreProperties(ignoreUnknown = true) @SuppressWarnings("serial") @Entity(value = "topicmodels", noClassnameStored = true) public class TopicModelFull implements Model<String>, Comparable<TopicModelFull>, Serializable { diff --git a/vipra-util/src/main/java/de/vipra/util/model/TopicShare.java b/vipra-util/src/main/java/de/vipra/util/model/TopicShare.java index 5f604cf9..6d065bbf 100644 --- a/vipra-util/src/main/java/de/vipra/util/model/TopicShare.java +++ b/vipra-util/src/main/java/de/vipra/util/model/TopicShare.java @@ -5,6 +5,9 @@ import java.io.Serializable; import org.mongodb.morphia.annotations.Embedded; import org.mongodb.morphia.annotations.Reference; +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; + +@JsonIgnoreProperties(ignoreUnknown = true) @SuppressWarnings("serial") @Embedded public class TopicShare implements Comparable<TopicShare>, Serializable { diff --git a/vipra-util/src/main/java/de/vipra/util/model/TopicWord.java b/vipra-util/src/main/java/de/vipra/util/model/TopicWord.java index dad8de09..4355d78a 100644 --- a/vipra-util/src/main/java/de/vipra/util/model/TopicWord.java +++ b/vipra-util/src/main/java/de/vipra/util/model/TopicWord.java @@ -6,8 +6,10 @@ import org.mongodb.morphia.annotations.Embedded; import com.fasterxml.jackson.annotation.JsonGetter; import com.fasterxml.jackson.annotation.JsonIgnore; +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import com.fasterxml.jackson.annotation.JsonSetter; +@JsonIgnoreProperties(ignoreUnknown = true) @SuppressWarnings("serial") @Embedded public class TopicWord implements Comparable<TopicWord>, Serializable { diff --git a/vipra-util/src/main/java/de/vipra/util/model/Window.java b/vipra-util/src/main/java/de/vipra/util/model/Window.java index da4e4f5c..3039ca03 100644 --- a/vipra-util/src/main/java/de/vipra/util/model/Window.java +++ b/vipra-util/src/main/java/de/vipra/util/model/Window.java @@ -5,11 +5,12 @@ import java.util.Date; import org.mongodb.morphia.annotations.Entity; import org.mongodb.morphia.annotations.Id; -import org.mongodb.morphia.annotations.Reference; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import de.vipra.util.Constants.WindowResolution; -import de.vipra.util.an.QueryIgnore; +@JsonIgnoreProperties(ignoreUnknown = true) @SuppressWarnings("serial") @Entity(value = "windows", noClassnameStored = true) public class Window implements Model<Integer>, Serializable, Comparable<Window> { @@ -17,16 +18,25 @@ public class Window implements Model<Integer>, Serializable, Comparable<Window> @Id private Integer id; - @Reference - @QueryIgnore(multi = true) - private TopicModel topicModel; - private Date startDate; private Date endDate; private WindowResolution windowResolution; + public Window() {} + + public Window(Integer id) { + this.id = id; + } + + public Window(WindowFull window) { + this.id = window.getId(); + this.startDate = window.getStartDate(); + this.endDate = window.getEndDate(); + this.windowResolution = window.getWindowResolution(); + } + @Override public Integer getId() { return id; @@ -37,14 +47,6 @@ public class Window implements Model<Integer>, Serializable, Comparable<Window> this.id = id; } - public TopicModel getTopicModel() { - return topicModel; - } - - public void setTopicModel(final TopicModel model) { - topicModel = model; - } - public Date getStartDate() { return startDate; } diff --git a/vipra-util/src/main/java/de/vipra/util/model/WindowFull.java b/vipra-util/src/main/java/de/vipra/util/model/WindowFull.java new file mode 100644 index 00000000..c34086ad --- /dev/null +++ b/vipra-util/src/main/java/de/vipra/util/model/WindowFull.java @@ -0,0 +1,80 @@ +package de.vipra.util.model; + +import java.io.Serializable; +import java.util.Date; + +import org.mongodb.morphia.annotations.Entity; +import org.mongodb.morphia.annotations.Id; +import org.mongodb.morphia.annotations.Reference; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; + +import de.vipra.util.Constants.WindowResolution; +import de.vipra.util.an.QueryIgnore; + +@JsonIgnoreProperties(ignoreUnknown = true) +@SuppressWarnings("serial") +@Entity(value = "windows", noClassnameStored = true) +public class WindowFull implements Model<Integer>, Comparable<WindowFull>, Serializable { + + @Id + private Integer id; + + @Reference + @QueryIgnore(multi = true) + private TopicModel topicModel; + + private Date startDate; + + private Date endDate; + + private WindowResolution windowResolution; + + @Override + public Integer getId() { + return id; + } + + @Override + public void setId(final Integer id) { + this.id = id; + } + + public TopicModel getTopicModel() { + return topicModel; + } + + public void setTopicModel(final TopicModel model) { + topicModel = model; + } + + public Date getStartDate() { + return startDate; + } + + public void setStartDate(final Date startDate) { + this.startDate = startDate; + } + + public Date getEndDate() { + return endDate; + } + + public void setEndDate(final Date endDate) { + this.endDate = endDate; + } + + public WindowResolution getWindowResolution() { + return windowResolution; + } + + public void setWindowResolution(final WindowResolution windowResolution) { + this.windowResolution = windowResolution; + } + + @Override + public int compareTo(final WindowFull o) { + return id - o.getId(); + } + +} -- GitLab