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 74c809ec4d09adc853939ab6cfaa6b8b02a5da08..09991c62335e81fc930c42bdbb78d2818771a158 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 3f422d62145b3f43ae7132a7b67032ce5572789c..2d977f74e85508505224c1d1d30c83ff6f6aa886 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 6b3bed96c32a2e41efc086673d1716593f98c1cb..7d1555c7c75a1d05aaf8772da2bc46c91037644e 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 cf5731a2a7687dd6ee09809f58bc12f0d559a46f..0000000000000000000000000000000000000000 --- 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 be6ba8e4d9d22b9873b7b8e0a5ed86ac0e792694..0000000000000000000000000000000000000000 --- 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 02c47730ad4c92eb442d891ba65e6d30dbf40e6f..0000000000000000000000000000000000000000 --- 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 5cfd37f8f617f20c07ddd0b9a0222acb6417e3c9..0000000000000000000000000000000000000000 --- 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 93769d7da4637c69e1990c8375c91b379c540e8d..0000000000000000000000000000000000000000 --- 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 ac769465dddb9a759f91388575b36a25caf6d737..0000000000000000000000000000000000000000 --- 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 458af103a1f6110847cd9274cdc7deb34c646d3c..365fc9a44d8c1cb06b4a1aa8fffa3c683fb1a3e4 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 54e4df82ee3865afcd9b8bd12376e248c19c4fb4..d6f1f4b694f22d2d00f42cb6924a89cb538b0970 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 a7343ea7476ff0db09d1c04401f2f969d820c168..9ba7c44e9c124de2d79e564032aae5fc8f59e4b7 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 e284dcbe4c74ec2bd7f1279289092c602777eea7..ab26863ecfcdcf564862ef3434f326f8259bbb52 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 398eb46434a5f4da6f0254fa7b6a963118597dc5..1963a78b23bb0a3a2ca3a2131caf771f297bf729 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 49ccb9e20545839284bb76e6f15aa5240fc6d337..7ad606fe8f90791a1f8b4db0f4d908b77ad73b0b 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 f6d7e25a2e284c75d982789798e6e5cbd256fa96..f925a7219bd3628b355028ab5a53309ef56677ee 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 d27f4c3d76b9edc4ffecaca272b574f4c56198af..e396195075a7cf9ebd660fcdf76133c4a029d9e6 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 8f75e4951ecc3977b1620c5316665058d31ec3a5..445a5473d25fb081b5dac52b3d5b0fe1006cbb43 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 a1708a91869d7242cd1ef896fa40bd81b0b48746..e1b09ea5fbb01e5b7d44a95618bf3c740e8fed03 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 e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..0000000000000000000000000000000000000000 diff --git a/vipra-ui/app/html/sequences/show.html b/vipra-ui/app/html/sequences/show.html deleted file mode 100644 index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..0000000000000000000000000000000000000000 diff --git a/vipra-ui/app/html/topics/articles.html b/vipra-ui/app/html/topics/articles.html index c7ecd073bd87f7782a620bbee998451e4b7a95ae..a95e384887f6579839cfe7af9414a6fa70796ec0 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 3a8babc5d093749827f395fb55930e6bbf233f0c..b58dd69069addb80201369f2376c70c7f7012fe1 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 e04ddc66714301e6b531db7a3c9a55d8fc89b1eb..afd55ae723f13ba8ef2e0d5902b5c869155882d3 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 49d4af3a0e4da3f0feb0647ebdc98e337dc89189..c39c42bec7338c08efb1ab66f3ffd92f441efb57 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 aa9d621acba83a58a94ab468a0133cd36b512947..9b0ad989a68b0419c619ac412378a22b7fc56960 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 5fb343e0e046eb6dd4de525f10677eb780f0dea4..4be0f3afa730721f61cf00eac93c2a1f0106271c 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 82900e4e00ac815addbd75d718f2ed7f70541cb8..ad6d4f1bca527a4d236cdc2023e8bb8114da285d 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 f5ff9043fdcb454be0d5120b7613136bc98e1b6d..978878623f3e5cb714610bf1d890e6a706952f76 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 d3e6ef59a2c32c076afa40709a24ab6029583c29..ed9d71d393994c08869c7a7d71b507696f706d72 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 40635289dfc27df38e24f7b4517e778235000583..374606845067f7c2a3b7b8dd22744ff2bd9a126f 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 179af17216756cc1ee5768784a54da5669cdea4f..692ca2ed5d8abefce8176423a32297e9f80ca4e9 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 64c13b17e18ded2617252c7c15d43093e7eb9844..4c012be26281bc08894641f5e001488dac278c8f 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 fe043792dec3887e0cafeec6a102441286b1b7ba..f0fc0cab9160b32f79601e622d08e5566b01d253 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 35752e9ea4d18601f0f7f4df092277998f8ed2a3..3d59fdcdc659efb1c9ce7d24a6eb79876a5d6caa 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 8efdbb74e5a892ad83bcac83a5a3b0be13209faa..a2124b5975f528f92cd0becaf7fb6ef6d7588af4 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 3f975ff81c1b33ced97bcc756734aa1b07a16330..4dab98473b321d3b93c7655e3a7a4d94b27fd37f 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 d0bba63fee5917c2a5db59047c972a126594108d..49dfe53d03506e67024f3bcc5b75cb92a92b3f73 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 b2291995bfb0aec6dd291334021b1618bdfa36ad..644520c842f505a3515de6f85605a19f408df7cc 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 f875db28a1e88ae195f5acbbdb130c97a3349eb0..d8538861ee0bb10606984f81569f6589ec73e796 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 e205a16b7dcf0c73d06b431284be5389f2f55274..781924d8f384a12086bed38b42e5b0c7df31bf32 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 b916ea46d704f8606c01484076c7a8fa5ce1a152..366972d664942ec0d96507e6b5b66c89e9ae3fd1 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 13a0a138faf8c6430beaa85591f5f8bfb8997b92..ad5572ab112f3f7aa426e76a86e8f8593419d936 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 5f604cf9ef373c25a7552ddf24d5256cdb66a3ca..6d065bbf0aae693c97ff288c3e28321433da1919 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 dad8de098b861f4941c90b517a69a6691a985935..4355d78abecb2aca05c93516cbb4f810278ea4b3 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 da4e4f5c9ebe41165b417946bf7fcd646cb7291a..3039ca0358f909be9c26e767c4498364846cdcc9 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 0000000000000000000000000000000000000000..c34086ad1da48c2f1b2a76e46e6593e970a9ad0d --- /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(); + } + +}