-
Eike Cochu authoredEike Cochu authored
Code owners
Assign users and groups as approvers for specific file changes. Learn more.
directives.js 7.89 KiB
/******************************************************************************
* Vipra Application
* Directives
******************************************************************************/
(function() {
var app = angular.module('vipra.directives', [
'ui.router'
]);
var slideDuration = 250;
app.directive('topicLink', function() {
return {
scope: {
topic: '='
},
restrict: 'E',
replace: true,
transclude: true,
template: '<a class="topic-link" ui-sref="topics.show({id:topic.id})"><span ng-bind="topic.name"></span><ng-transclude/></a>'
}
});
app.directive('articleLink', function() {
return {
scope: {
article: '='
},
restrict: 'E',
replace: true,
transclude: true,
template: '<a class="article-link" ui-sref="articles.show({id:article.id})"><span ng-bind="article.title"></span><ng-transclude/></a>'
}
});
app.directive('queryTime', function() {
return {
restrict: 'E',
replace: true,
template: '<small class="text-muted">(took <span ng-bind-template="{{queryTime}}ms"></span>)</small>'
};
});
app.directive('pagination', function() {
return {
restrict: 'E',
replace: true,
scope: {
total: '=',
page: '=',
limit: '='
},
controller: 'PaginationController',
templateUrl: 'html/directives/pagination.html'
};
});
app.directive('visGraph', ['$state', '$timeout', 'ArticleFactory', 'TopicFactory',
function($state, $timeout, ArticleFactory, TopicFactory) {
return {
scope: {
ngModel: '=',
visType: '=',
visData: '=',
visOptions: '='
},
transclude: true,
template: '<ng-transclude/><div class="fullsize navpadding" id="visgraph"></div>',
link: function($scope, $element) {
var id = 0,
ids = {},
nodes = [],
edges = [],
articleColor = '#BBC9D2',
topicColor = '#DBB234',
container = $element.find("#visgraph")[0];
$scope.articleColor = articleColor;
$scope.topicColor = topicColor;
$scope.nodes = new vis.DataSet();
$scope.edges = new vis.DataSet();
$scope.data = {
nodes: $scope.nodes,
edges: $scope.edges
};
$scope.options = {
nodes: {
font: { size: 11 },
shape: 'dot',
borderWidth: 0
},
layout: { randomSeed: 1 },
physics: {
barnesHut: {
springConstant: 0.005,
gravitationalConstant: -5000
}
}
};
var topicNode = function(topic) {
return {
id: ++id,
title: topic.name,
label: topic.name.ellipsize(20),
type: 'topic',
topic: topic.id,
color: {
background: topicColor,
highlight: { background: topicColor }
}
};
};
var articleNode = function(article) {
return {
id: ++id,
title: article.title,
label: article.title.ellipsize(20),
type: 'article',
article: article.id,
color: {
background: articleColor,
highlight: { background: articleColor }
}
};
};
// on node select
var selectTimeout;
$scope.select = function(props) {
$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);
}
});
} 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);
}
});
}
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.show', {id:node.article});
else
$state.transitionTo('topics.show', {id:node.topic});
};
// watch for changes to model
$scope.$watch('ngModel', function(newVal, oldVal) {
if(!newVal) return;
// root node
if($scope.visType === 'articles')
nodes.push(articleNode($scope.ngModel));
else
nodes.push(topicNode($scope.ngModel));
ids[$scope.ngModel.id] = id;
// add nodes and edges
$scope.nodes.add(nodes);
$scope.edges.add(edges);
// create graph
$scope.visGraph = new vis.Network(container, $scope.data, $scope.options);
$scope.visGraph.on('selectNode', $scope.select);
$scope.visGraph.on('doubleClick', $scope.open);
});
}
};
}]);
app.directive('highcharts', function() {
return {
scope: {
highcharts: '='
},
link: function($scope, $element) {
$scope.$watch('highcharts', function(newVal) {
if(!newVal) return;
$element.highcharts($scope.highcharts);
});
}
};
});
app.directive('hideLink', function() {
return {
scope: {
target: '@'
},
replace: true,
template: '<a class="hide-link" href="#" ng-bind="text" ng-click="change($event)"></a>',
link: function($scope) {
var target = $($scope.target);
if(!target.length) return;
var setText = function(b) {
$scope.text = b ? 'hide' : 'show';
};
$scope.change = function(e) {
e.preventDefault();
setText(!target.is(':visible'));
target.slideToggle();
};
setText(target.is(':visible'));
}
};
});
})();