diff --git a/vipra-ui/app/html/articles/index.html b/vipra-ui/app/html/articles/index.html index 5f2bea4bbf5967fda77744308451f1b7ed6e9e0c..5560bfaff51ace0ddeb7c818e2d572d2fa7270fd 100644 --- a/vipra-ui/app/html/articles/index.html +++ b/vipra-ui/app/html/articles/index.html @@ -4,7 +4,7 @@ <ul class="list-unstyled"> <li ng-repeat="article in articles"> - <a ui-sref="articles.detail.show({id: article.id})" ng-bind="::article.title"></a> + <a ui-sref="articles.show({id: article.id})" ng-bind="::article.title"></a> </li> </ul> diff --git a/vipra-ui/app/html/articles/detail/show.html b/vipra-ui/app/html/articles/show.html similarity index 92% rename from vipra-ui/app/html/articles/detail/show.html rename to vipra-ui/app/html/articles/show.html index 98016a43904610c24ec3cf3a32012795d834053f..2eb45fbbe1b93b12374da912f15a6e11968e3b17 100644 --- a/vipra-ui/app/html/articles/detail/show.html +++ b/vipra-ui/app/html/articles/show.html @@ -37,7 +37,7 @@ <tr> <th>Links</th> <td> - <a ui-sref="articles.detail.network({id:article.id})">Network graph</a> + <a ui-sref="network({type:'articles', id:article.id})">Network graph</a> </td> </tr> </tbody> diff --git a/vipra-ui/app/html/index.html b/vipra-ui/app/html/index.html index a1b589f3c65b813c7c7dc0ea28614f0356c3afbf..336e7d2f348a602b8c83c30c000aec72297eac34 100644 --- a/vipra-ui/app/html/index.html +++ b/vipra-ui/app/html/index.html @@ -11,7 +11,7 @@ <h4>Latest articles</h4> <ul class="list-unstyled"> <li class="ellipsize" ng-repeat="article in latestArticles"> - <a ui-sref="articles.detail.show({id:article.id})" ng-bind="article.title"></a> + <a ui-sref="articles.show({id:article.id})" ng-bind="article.title"></a> </li> </ul> </div> @@ -50,7 +50,7 @@ <h4>Results <query-time/></h4> <ul class="list-unstyled search-results"> <li class="search-result" ng-repeat="article in searchResults"> - <a ui-sref="articles.detail.show({id:article.id})" ng-bind="article.title"></a> + <a ui-sref="articles.show({id:article.id})" ng-bind="article.title"></a> <p> <span class="text" ng-bind="article.text"></span> <br> diff --git a/vipra-ui/app/html/articles/detail/network.html b/vipra-ui/app/html/network.html similarity index 65% rename from vipra-ui/app/html/articles/detail/network.html rename to vipra-ui/app/html/network.html index d1e0899b9cfa204a2380a963424719d8224104dd..316ed30991ebb8d53ba2637dd744dc7f2e141ea3 100644 --- a/vipra-ui/app/html/articles/detail/network.html +++ b/vipra-ui/app/html/network.html @@ -1,8 +1,4 @@ -<div class="graph" - vis-graph - vis-type="article" - ng-model="article"> - +<div class="fullsize navpadding" vis-graph vis-type="type" ng-model="model"> <div class="graph-legend"> <span style="color:#BBC9D2">Articles</span><br> <span style="color:#DBB234">Topics</span><br> diff --git a/vipra-ui/app/html/topics/show.html b/vipra-ui/app/html/topics/show.html index 38d1648ede547bad61d2c42d76e7ef2003194cba..0d21fb0817a71a93e3b89ab82a78d9f968cddd71 100644 --- a/vipra-ui/app/html/topics/show.html +++ b/vipra-ui/app/html/topics/show.html @@ -18,6 +18,12 @@ <th>Last modified</th> <td ng-bind="::topic.modified"></td> </tr> + <tr> + <th>Links</th> + <td> + <a ui-sref="network({type:'topics', id:topic.id})">Network graph</a> + </td> + </tr> </tbody> </table> diff --git a/vipra-ui/app/js/app.js b/vipra-ui/app/js/app.js index 29554595c0f76352ac2df53efea8b433c2e5eaee..1de6e116ec9bd86377d19698abf4f84a7865615b 100644 --- a/vipra-ui/app/js/app.js +++ b/vipra-ui/app/js/app.js @@ -29,6 +29,12 @@ controller: 'IndexController' }); + $stateProvider.state('network', { + url: '/network/:type/:id', + templateUrl: tplBase + '/network.html', + controller: 'NetworkController' + }); + // states: articles $stateProvider.state('articles', { @@ -43,24 +49,12 @@ controller: 'ArticlesIndexController' }); - $stateProvider.state('articles.detail', { + $stateProvider.state('articles.show', { url: '/:id', - abstract: true, - template: '<ui-view/>' - }); - - $stateProvider.state('articles.detail.show', { - url: '', - templateUrl: tplBase + '/articles/detail/show.html', + templateUrl: tplBase + '/articles/show.html', controller: 'ArticlesShowController' }); - $stateProvider.state('articles.detail.network', { - url: '/network', - templateUrl: tplBase + '/articles/detail/network.html', - controller: 'ArticlesNetworkController' - }); - // states: topics $stateProvider.state('topics', { diff --git a/vipra-ui/app/js/controllers.js b/vipra-ui/app/js/controllers.js index 7928303720add6d0f173554c9cfc08eb10059450..9f7c3db157569e7a6846bc5c0fc7851b9c46a514 100644 --- a/vipra-ui/app/js/controllers.js +++ b/vipra-ui/app/js/controllers.js @@ -48,6 +48,27 @@ }]); + app.controller('NetworkController', ['$scope', '$state', '$stateParams', 'ArticleFactory', 'TopicFactory', + function($scope, $state, $stateParams, ArticleFactory, TopicFactory) { + + $scope.type = $stateParams.type; + + var factory; + if($stateParams.type === 'articles') + factory = ArticleFactory; + else if($stateParams.type === 'topics') + factory = TopicFactory; + else { + console.log('unknown network type'); + return; + } + + factory.get({id: $stateParams.id}, function(response) { + $scope.model = response.data; + }); + + }]); + /* * Article Controllers */ @@ -83,15 +104,6 @@ }]); - app.controller('ArticlesNetworkController', ['$scope', '$state', '$stateParams', 'ArticleFactory', 'TopicFactory', - function($scope, $state, $stateParams, ArticleFactory, TopicFactory) { - - ArticleFactory.get({id: $stateParams.id}, function(response) { - $scope.article = response.data; - }); - - }]); - /* * Topic Controllers */ diff --git a/vipra-ui/app/js/directives.js b/vipra-ui/app/js/directives.js index f86e7fcd735e3638b49447090b9d9036ca706575..867fd6e4d5edd2211b3897e217065b71c5a0125f 100644 --- a/vipra-ui/app/js/directives.js +++ b/vipra-ui/app/js/directives.js @@ -30,7 +30,7 @@ restrict: 'E', replace: true, transclude: true, - template: '<a class="article-link" ui-sref="articles.detail.show({id:article.id})"><span ng-bind="article.title"></span><ng-transclude/></a>' + template: '<a class="article-link" ui-sref="articles.show({id:article.id})"><span ng-bind="article.title"></span><ng-transclude/></a>' } }); @@ -56,18 +56,18 @@ }; }); - app.directive('visGraph', ['$state', 'ArticleFactory', 'TopicFactory', - function($state, ArticleFactory, TopicFactory) { + app.directive('visGraph', ['$state', '$timeout', 'ArticleFactory', 'TopicFactory', + function($state, $timeout, ArticleFactory, TopicFactory) { return { scope: { ngModel: '=', - visType: '@', + visType: '=', visData: '=', visOptions: '=' }, transclude: true, - template: '<ng-transclude/><div class="graph" id="visgraph"></div>', + template: '<ng-transclude/><div class="fullsize navpadding" id="visgraph"></div>', link: function($scope, $element) { var id = 0, ids = {}, @@ -130,64 +130,69 @@ }; // on node select + var selectTimeout; $scope.select = function(props) { - var node = $scope.nodes.get(props.nodes[0]); - if(node && !node.loaded) { - if(node.type === 'article') { - // node is article, load article to get topics - ArticleFactory.get({id:node.article}, function(res) { - if(res.data && res.data.topics) { - var topics = res.data.topics, - newNodes = [], - newEdges = []; - for(var i = 0; i < topics.length; i++) { - var topic = topics[i].topic; - if(ids.hasOwnProperty(topic.id)) { - if(!$scope.nodes.get(ids[topic.id]).loaded) - newEdges.push({from:node.id, to:ids[topic.id]}); - } else { - newNodes.push(topicNode(topic)); - newEdges.push({from:node.id, to:id}); - ids[topic.id] = id; + $timeout.cancel(selectTimeout); + selectTimeout = $timeout(function() { + var node = $scope.nodes.get(props.nodes[0]); + if(node && !node.loaded) { + if(node.type === 'article') { + // node is article, load article to get topics + ArticleFactory.get({id:node.article}, function(res) { + if(res.data && res.data.topics) { + var topics = res.data.topics, + newNodes = [], + newEdges = []; + for(var i = 0; i < topics.length; i++) { + var topic = topics[i].topic; + if(ids.hasOwnProperty(topic.id)) { + if(!$scope.nodes.get(ids[topic.id]).loaded) + newEdges.push({from:node.id, to:ids[topic.id]}); + } else { + newNodes.push(topicNode(topic)); + newEdges.push({from:node.id, to:id}); + ids[topic.id] = id; + } } + if(newNodes.length) $scope.nodes.add(newNodes); + if(newEdges.length) $scope.edges.add(newEdges); } - if(newNodes.length) $scope.nodes.add(newNodes); - if(newEdges.length) $scope.edges.add(newEdges); - } - }); - } else { - // node is topic, load topic to get articles - TopicFactory.get({id:node.topic}, function(res) { - if(res.data && res.data.articles) { - var articles = res.data.articles, - newNodes = [], - newEdges = []; - for(var i = 0; i < articles.length; i++) { - var article = articles[i]; - if(ids.hasOwnProperty(article.id)) { - if(!$scope.nodes.get(ids[article.id]).loaded) - newEdges.push({from:ids[article.id], to:node.id}); - } else { - newNodes.push(articleNode(article)); - newEdges.push({from:id, to:node.id}); - ids[article.id] = id; + }); + } else { + // node is topic, load topic to get articles + TopicFactory.get({id:node.topic}, function(res) { + if(res.data && res.data.articles) { + var articles = res.data.articles, + newNodes = [], + newEdges = []; + for(var i = 0; i < articles.length; i++) { + var article = articles[i]; + if(ids.hasOwnProperty(article.id)) { + if(!$scope.nodes.get(ids[article.id]).loaded) + newEdges.push({from:ids[article.id], to:node.id}); + } else { + newNodes.push(articleNode(article)); + newEdges.push({from:id, to:node.id}); + ids[article.id] = id; + } } + if(newNodes.length) $scope.nodes.add(newNodes); + if(newEdges.length) $scope.edges.add(newEdges); } - if(newNodes.length) $scope.nodes.add(newNodes); - if(newEdges.length) $scope.edges.add(newEdges); - } - }); + }); + } + node.loaded = true; + $scope.nodes.update(node); } - node.loaded = true; - $scope.nodes.update(node); - } + }, 500); }; // on node open $scope.open = function(props) { + $timeout.cancel(selectTimeout); var node = $scope.nodes.get(props.nodes[0]); if(node.type === 'article') - $state.transitionTo('articles.detail.show', {id:node.article}); + $state.transitionTo('articles.show', {id:node.article}); else $state.transitionTo('topics.show', {id:node.topic}); }; @@ -197,7 +202,7 @@ if(!newVal) return; // root node - if($scope.visType === 'article') + if($scope.visType === 'articles') nodes.push(articleNode($scope.ngModel)); else nodes.push(topicNode($scope.ngModel)); diff --git a/vipra-ui/app/less/app.less b/vipra-ui/app/less/app.less index 9d966708c902291a24bd5a1b8d3305ee4cfed3c4..313bcd09d99686450621c94930766a75f1e2226f 100644 --- a/vipra-ui/app/less/app.less +++ b/vipra-ui/app/less/app.less @@ -101,7 +101,7 @@ body { .graph { position: absolute; - top: 10px; + top: 50px; left: 0; right: 0; bottom: 50px; @@ -126,6 +126,19 @@ body { cursor: default; } +.fullsize { + position: absolute; + top: 0; + left: 0; + right: 0; + bottom: 0; +} + +.navpadding { + padding-top: 50px; + padding-bottom: 50px; +} + @-moz-keyframes spin { 100% { -moz-transform: rotateY(360deg); } } @-webkit-keyframes spin { 100% { -webkit-transform: rotateY(360deg); } } @keyframes spin { 100% { -webkit-transform: rotateY(360deg); transform:rotateY(360deg); } } \ No newline at end of file