diff --git a/vipra-ui/app/html/about.html b/vipra-ui/app/html/about.html index d040c3ea7c57da5d43146321b6cc698b890e154e..ea3d126ed77be79200725345e05ea4c38356d63a 100644 --- a/vipra-ui/app/html/about.html +++ b/vipra-ui/app/html/about.html @@ -1,4 +1,4 @@ -<div ui-view ng-cloak> +<div ng-cloak> <div class="page-header"> <h1>About</h1> </div> @@ -261,4 +261,6 @@ </tr> </tbody> </table> -</div> \ No newline at end of file +</div> + +<div ui-view ng-cloak></div> \ No newline at end of file diff --git a/vipra-ui/app/html/articles/index.html b/vipra-ui/app/html/articles/index.html index 56c9970a6b708d062c15cb007f736b2d4a00cc4d..9cee6b1cec0ca6b302c17066db11670bb05a6dab 100644 --- a/vipra-ui/app/html/articles/index.html +++ b/vipra-ui/app/html/articles/index.html @@ -1,13 +1,30 @@ -<div ui-view ng-cloak> - <div class="well"> - Found <span ng-bind="articlesTotal"></span> articles in the database.<br> +<div ng-cloak> + <div class="text-muted list-header"> + Found <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="sort" ng-model-store="sort" ng-model-default="'date'"> + <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> + Direction + <ol class="nya-bs-select nya-bs-condensed" ng-model="order" ng-model-store="order" ng-model-default="'+'"> + <li value="+" class="nya-bs-option"><a>Ascending</a></li> + <li value="-" class="nya-bs-option"><a>Descending</a></li> + </ol> + </span> + <br> + Page <span ng-bind="page||1"></span> of <span ng-bind="maxPage||1"></span>. </div> - <ul class="dashed"> + <ol ng-attr-start="{{(page-1)*limit+1}}"> <li ng-repeat="article in articles"> <a ui-sref="articles.show({id: article.id})" ng-bind="::article.title"></a> </li> - </ul> + </ol> <pagination total="articlesTotal" page="page" limit="limit" change="changePage"/> -</div> \ No newline at end of file +</div> + +<div ui-view ng-cloak></div> \ No newline at end of file diff --git a/vipra-ui/app/html/articles/show.html b/vipra-ui/app/html/articles/show.html index e2e4fff58f74487c70bc079683823cddf4181cc3..be469f5e7d003b9f8d1572fe949cccad7b718f6e 100644 --- a/vipra-ui/app/html/articles/show.html +++ b/vipra-ui/app/html/articles/show.html @@ -1,4 +1,4 @@ -<div ui-view ng-cloak> +<div ng-cloak> <div class="page-header"> <h1 ng-bind="::article.title"></h1> @@ -81,4 +81,6 @@ <hr> <p ng-bind-html="::article.text" class="text-justify"></p> -</div> \ No newline at end of file +</div> + +<div ui-view ng-cloak></div> \ No newline at end of file diff --git a/vipra-ui/app/html/directives/checkbox.html b/vipra-ui/app/html/directives/checkbox.html new file mode 100644 index 0000000000000000000000000000000000000000..86e0cf2d8141e40eb9e480eec15b933e4df57daf --- /dev/null +++ b/vipra-ui/app/html/directives/checkbox.html @@ -0,0 +1,3 @@ +<input type="checkbox" ng-model="ngModel" style="display:none"> + +<span class="glyphicon" ng-class="{'glyphicon-unchecked':!ngModel,'glyphicon-check':ngModel}" ng-click="ngModel=!ngModel"></span> \ No newline at end of file diff --git a/vipra-ui/app/html/network.html b/vipra-ui/app/html/network.html index 449bed477f4ed888002790bdd41f7233cbddd95e..2ee3327a7e20ac8a46dbf177735693b2ba03fc88 100644 --- a/vipra-ui/app/html/network.html +++ b/vipra-ui/app/html/network.html @@ -2,15 +2,17 @@ <div class="fullsize navpadding"> <div class="graph-legend overlay"> <label style="color:{{colors.articles}}"> - <input type="checkbox" ng-model="shown.articles" store-value="showArticles" store-default="type == 'articles'" ng-disabled="type == 'articles'"> Articles + <input type="checkbox" ng-model="shown.articles" ng-model-store="showArticles" ng-model-default="type == 'articles'" ng-disabled="type == 'articles'"> Articles </label> <label style="color:{{colors.topics}}"> - <input type="checkbox" ng-model="shown.topics" store-value="showTopics" store-default="true" ng-disabled="type == 'topics'"> Topics + <input type="checkbox" ng-model="shown.topics" ng-model-store="showTopics" ng-model-default="true" ng-disabled="type == 'topics'"> Topics </label> <label style="color:{{colors.words}}"> - <input type="checkbox" ng-model="shown.words" store-value="showWords" store-default="true" ng-disabled="type == 'words'"> Words + <input type="checkbox" ng-model="shown.words" ng-model-store="showWords" ng-model-default="true" ng-disabled="type == 'words'"> Words </label> </div> <div class="fullsize navpadding" id="visgraph"></div> </div> -</div> \ No newline at end of file +</div> + +<div ui-view ng-cloak></div> \ No newline at end of file diff --git a/vipra-ui/app/html/topics/articles.html b/vipra-ui/app/html/topics/articles.html index 40c7f7b7914f4f1d708b501a51dde6c8c44b9584..6151b621ce3dbe07904273c2360f91df03a4b43a 100644 --- a/vipra-ui/app/html/topics/articles.html +++ b/vipra-ui/app/html/topics/articles.html @@ -1,4 +1,4 @@ -<div ui-view ng-cloak> +<div ng-cloak> <div class="page-header"> <h1> <div ng-bind="topic.name" ng-hide="isRename"></div> @@ -29,17 +29,33 @@ </div> <h3>Articles</h3> - - <div class="well"> - Found <span ng-bind="articlesTotal"></span> articles in the database.<br> + + <div class="text-muted list-header"> + Found <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="sort"> + <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> + Direction + <ol class="nya-bs-select nya-bs-condensed" ng-model="order"> + <li value="+" class="nya-bs-option"><a>Ascending</a></li> + <li value="-" class="nya-bs-option"><a>Descending</a></li> + </ol> + </span> + <br> + Page <span ng-bind="page||1"></span> of <span ng-bind="maxPage||1"></span>. </div> - <ul class="dashed"> + <ol ng-attr-start="{{(page-1)*limit+1}}"> <li ng-repeat="article in articles"> <a ui-sref="articles.show({id: article.id})" ng-bind="::article.title"></a> </li> - </ul> + </ol> <pagination total="articlesTotal" page="page" limit="limit" change="changePage"/> +</div> -</div> \ No newline at end of file +<div ui-view ng-cloak></div> \ No newline at end of file diff --git a/vipra-ui/app/html/topics/index.html b/vipra-ui/app/html/topics/index.html index bf4b95edc2a8b7604134d25116ca2a24c6b7ec91..5b12c06af43c55ceef402045e0ba197b71f983ea 100644 --- a/vipra-ui/app/html/topics/index.html +++ b/vipra-ui/app/html/topics/index.html @@ -1,13 +1,29 @@ -<div ui-view ng-cloak> - <div class="well"> - Found <span ng-bind="topicsTotal"></span> topics in the database. +<div ng-cloak> + <div class="text-muted list-header"> + Found <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="sort"> + <li value="name" class="nya-bs-option"><a>Name</a></li> + <li value="created" class="nya-bs-option"><a>Added</a></li> + </ol> + Direction + <ol class="nya-bs-select nya-bs-condensed" ng-model="order"> + <li value="+" class="nya-bs-option"><a>Ascending</a></li> + <li value="-" class="nya-bs-option"><a>Descending</a></li> + </ol> + </span> + <br> + Page <span ng-bind="page||1"></span> of <span ng-bind="maxPage||1"></span>. </div> - <ul class="dashed"> + <ol ng-attr-start="{{(page-1)*limit+1}}"> <li ng-repeat="topic in topics"> <a ui-sref="topics.show({id: topic.id})">{{topic.name}}</a> </li> - </ul> + </ol> <pagination total="topicsTotal" page="page" limit="limit" change="changePage"/> -</div> \ No newline at end of file +</div> + +<div ui-view ng-cloak></div> \ No newline at end of file diff --git a/vipra-ui/app/html/topics/show.html b/vipra-ui/app/html/topics/show.html index 0ebb0cf608cdc7fcd319413cb515dcad773d1ecf..24a75e58ea999ca4f7b6fa53657323baba659d2f 100644 --- a/vipra-ui/app/html/topics/show.html +++ b/vipra-ui/app/html/topics/show.html @@ -1,4 +1,4 @@ -<div ui-view ng-cloak> +<div ng-cloak> <div class="page-header"> <h1> <div ng-bind="topic.name" ng-hide="isRename"></div> @@ -87,4 +87,6 @@ </table> </div> </div> -</div> \ No newline at end of file +</div> + +<div ui-view ng-cloak></div> \ No newline at end of file diff --git a/vipra-ui/app/html/words/index.html b/vipra-ui/app/html/words/index.html index 7e129d75dd43cde067fc23adfcebc4f7d2db35c8..3a8b497da307a21c67b40de23e70c58ca1da034e 100644 --- a/vipra-ui/app/html/words/index.html +++ b/vipra-ui/app/html/words/index.html @@ -1,6 +1,20 @@ -<div ui-view ng-cloak> - <div class="well"> - Found <span ng-bind="wordsTotal"></span> words in the database. +<div ng-cloak> + <div class="text-muted list-header"> + Found <ng-pluralize count="wordsTotal||0" when="{0:'no words',1:'1 word',other:'{} words'}"></ng-pluralize> in the database. + <span ng-show="wordsTotal"> + Sort by + <ol class="nya-bs-select nya-bs-condensed" ng-model="sort"> + <li value="id" class="nya-bs-option"><a>Word</a></li> + <li value="created" class="nya-bs-option"><a>Added</a></li> + </ol> + Direction + <ol class="nya-bs-select nya-bs-condensed" ng-model="order"> + <li value="+" class="nya-bs-option"><a>Ascending</a></li> + <li value="-" class="nya-bs-option"><a>Descending</a></li> + </ol> + </span> + <br> + Page <span ng-bind="page||1"></span> of <span ng-bind="maxPage||1"></span>. </div> <div class="row"> @@ -28,4 +42,6 @@ </div> <pagination total="wordsTotal" page="page" limit="limit" change="changePage"/> -</div> \ No newline at end of file +</div> + +<div ui-view ng-cloak></div> \ No newline at end of file diff --git a/vipra-ui/app/html/words/show.html b/vipra-ui/app/html/words/show.html index 6174e8c3554e362f7ed5560f5a9bdf0fb4deef49..7745702e67bd856f3f49fe000ef6a575fd622ca0 100644 --- a/vipra-ui/app/html/words/show.html +++ b/vipra-ui/app/html/words/show.html @@ -1,4 +1,4 @@ -<div ui-view ng-cloak> +<div ng-cloak> <div class="page-header"> <h1 ng-bind="::word.id"></h1> </div> @@ -29,4 +29,6 @@ </ul> </div> </div> -</div> \ No newline at end of file +</div> + +<div ui-view ng-cloak></div> \ No newline at end of file diff --git a/vipra-ui/app/js/app.js b/vipra-ui/app/js/app.js index acc34073d027839af03eb7ae73c397a12b3152e9..ad8233a300a5827026acbccacafb9b6ba2de7f84 100644 --- a/vipra-ui/app/js/app.js +++ b/vipra-ui/app/js/app.js @@ -9,6 +9,7 @@ 'ngSanitize', 'ngWebSocket', 'ui.router', + 'nya.bootstrap.select', 'vipra.controllers', 'vipra.directives', 'vipra.factories', @@ -43,10 +44,9 @@ // states: articles $stateProvider.state('articles', { - url: '/articles?page', + url: '/articles', templateUrl: Vipra.const.tplBase + '/articles/index.html', - controller: 'ArticlesIndexController', - reloadOnSearch: false + controller: 'ArticlesIndexController' }); $stateProvider.state('articles.show', { @@ -58,10 +58,9 @@ // states: topics $stateProvider.state('topics', { - url: '/topics?page', + url: '/topics', templateUrl: Vipra.const.tplBase + '/topics/index.html', - controller: 'TopicsIndexController', - reloadOnSearch: false + controller: 'TopicsIndexController' }); $stateProvider.state('topics.show', { @@ -71,7 +70,7 @@ }); $stateProvider.state('topics.show.articles', { - url: '/articles?page', + url: '/articles', templateUrl: Vipra.const.tplBase + '/topics/articles.html', controller: 'TopicsArticlesController' }); @@ -79,10 +78,9 @@ // states: words $stateProvider.state('words', { - url: '/words?page', + url: '/words', templateUrl: Vipra.const.tplBase + '/words/index.html', - controller: 'WordsIndexController', - reloadOnSearch: false + controller: 'WordsIndexController' }); $stateProvider.state('words.show', { diff --git a/vipra-ui/app/js/controllers.js b/vipra-ui/app/js/controllers.js index ee2b2baf4f4efdd05999447a79d187086d8d4fc0..7e948452d243745f9a081576826f10f742cb42e9 100644 --- a/vipra-ui/app/js/controllers.js +++ b/vipra-ui/app/js/controllers.js @@ -260,15 +260,17 @@ /** * Article Index route */ - app.controller('ArticlesIndexController', ['$scope', '$state', '$stateParams', 'ArticleFactory', 'Store', - function($scope, $state, $stateParams, ArticleFactory, Store) { + app.controller('ArticlesIndexController', ['$scope', '$state', '$location', 'ArticleFactory', 'Store', + function($scope, $state, $location, ArticleFactory, Store) { - $scope.page = Math.max($stateParams.page || 1, 1); + $scope.page = Math.max($location.search().page || 1, 1); $scope.limit = Vipra.const.pageSize; - $scope.sort = Store('sortarticles') || 'date'; - $scope.order = Store('orderarticles') || ''; - $scope.reload = function() { + $scope.changePage = function(page) { + $scope.page = page; + }; + + $scope.$watchGroup(['page','sort','order'], function() { ArticleFactory.query({ skip: ($scope.page-1)*$scope.limit, limit: $scope.limit, @@ -276,15 +278,9 @@ }, function(data, headers) { $scope.articles = data; $scope.articlesTotal = headers("V-Total"); + $scope.maxPage = Math.ceil($scope.articlesTotal / $scope.limit); }); - }; - - $scope.changePage = function(page) { - $scope.page = page; - $scope.reload(); - }; - - $scope.reload(); + }); }]); @@ -344,15 +340,19 @@ /** * Topic Index route */ - app.controller('TopicsIndexController', ['$scope', '$stateParams', 'Store', 'TopicFactory', - function($scope, $stateParams, Store, TopicFactory) { + app.controller('TopicsIndexController', ['$scope', '$location', 'Store', 'TopicFactory', + function($scope, $location, Store, TopicFactory) { - $scope.page = Math.max($stateParams.page || 1, 1); + $scope.page = Math.max($location.search().page || 1, 1); $scope.limit = Vipra.const.pageSize; $scope.sort = Store('sorttopics') || 'name'; - $scope.order = Store('ordertopics') || ''; + $scope.order = Store('ordertopics') || '+'; - $scope.reload = function() { + $scope.changePage = function(page) { + $scope.page = page; + }; + + $scope.$watchGroup(['page','sort','order'], function() { TopicFactory.query({ skip: ($scope.page-1)*$scope.limit, limit: $scope.limit, @@ -360,15 +360,9 @@ }, function(data, headers) { $scope.topics = data; $scope.topicsTotal = headers("V-Total"); + $scope.maxPage = Math.ceil($scope.topicsTotal / $scope.limit); }); - }; - - $scope.changePage = function(page) { - $scope.page = page; - $scope.reload(); - }; - - $scope.reload(); + }); }]); @@ -421,15 +415,19 @@ /** * Topic Show Articles route */ - app.controller('TopicsArticlesController', ['$scope', '$stateParams', 'Store', 'TopicFactory', - function($scope, $stateParams, Store, TopicFactory) { + app.controller('TopicsArticlesController', ['$scope', '$stateParams', '$location', 'Store', 'TopicFactory', + function($scope, $stateParams, $location, Store, TopicFactory) { - $scope.page = Math.max($stateParams.page || 1, 1); + $scope.page = Math.max($location.search().page || 1, 1); $scope.limit = Vipra.const.pageSize; $scope.sort = Store('sortarticles') || 'title'; - $scope.order = Store('orderarticles') || ''; + $scope.order = Store('orderarticles') || '+'; - $scope.reload = function() { + $scope.changePage = function(page) { + $scope.page = page; + }; + + $scope.$watchGroup(['page','sort','order'], function() { TopicFactory.articles({ id: $stateParams.id, skip: ($scope.page-1)*$scope.limit, @@ -438,15 +436,9 @@ }, function(data, headers) { $scope.articles = data; $scope.articlesTotal = headers("V-Total"); + $scope.maxPage = Math.ceil($scope.articlesTotal / $scope.limit); }); - }; - - $scope.changePage = function(page) { - $scope.page = page; - $scope.reload(); - }; - - $scope.reload(); + }); }]); @@ -457,15 +449,19 @@ /** * Word Index route */ - app.controller('WordsIndexController', ['$scope', '$state', '$stateParams', 'Store', 'WordFactory', - function($scope, $state, $stateParams, Store, WordFactory) { + app.controller('WordsIndexController', ['$scope', '$state', '$location', 'Store', 'WordFactory', + function($scope, $state, $location, Store, WordFactory) { - $scope.page = Math.max($stateParams.page || 1, 1); + $scope.page = Math.max($location.search().page || 1, 1); $scope.limit = 300; $scope.sort = Store('sortwords') || 'id'; - $scope.order = Store('orderwords') || ''; + $scope.order = Store('orderwords') || '+'; - $scope.reload = function() { + $scope.changePage = function(page) { + $scope.page = page; + }; + + $scope.$watchGroup(['page','sort','order'], function() { WordFactory.query({ skip: ($scope.page-1)*$scope.limit, limit: $scope.limit, @@ -474,15 +470,9 @@ }, function(data, headers) { $scope.words = data; $scope.wordsTotal = headers("V-Total"); + $scope.maxPage = Math.ceil($scope.wordsTotal / $scope.limit); }); - }; - - $scope.changePage = function(page) { - $scope.page = page; - $scope.reload(); - }; - - $scope.reload(); + }); }]); diff --git a/vipra-ui/app/js/directives.js b/vipra-ui/app/js/directives.js index 49bb69f92f8f138db052bec2937f57b052cb6aaf..3d7b93fc03c03ac32ae6580eb0583e54deb5c673 100644 --- a/vipra-ui/app/js/directives.js +++ b/vipra-ui/app/js/directives.js @@ -109,26 +109,25 @@ } }); - app.directive('storeValue', ['Store', function(Store) { + app.directive('ngModelStore', ['Store', function(Store) { return { restrict: 'A', require: 'ngModel', link: function($scope, $elem, $attrs, $ctrl) { - if(!$attrs.storeValue) { + if(!$attrs.ngModelStore) { console.log("no store key given"); return; } - var value = Store($attrs.storeValue); - if(typeof value !== 'undefined') { - if($attrs.storeDefault) { - $ctrl.$setViewValue($scope.$eval($attrs.storeDefault)); - } else { - $ctrl.$setViewValue(value); - } + var value = Store($attrs.ngModelStore); + if(value != null) { + $ctrl.$setViewValue(value); + $ctrl.$render(); + } else if($attrs.ngModelDefault) { + $ctrl.$setViewValue($scope.$eval($attrs.ngModelDefault)); $ctrl.$render(); } $ctrl.$viewChangeListeners.push(function() { - Store($attrs.storeValue, $ctrl.$viewValue); + Store($attrs.ngModelStore, $ctrl.$viewValue); }); } }; @@ -174,6 +173,19 @@ }; }); + app.directive('bsCheckbox', function() { + return { + scope: { + ngModel: '=' + }, + restrict: 'E', + templateUrl: 'html/directives/checkbox.html', + link: function($scope) { + + } + }; + }); + app.directive('sortBy', ['Store', function(Store) { return { scope: { diff --git a/vipra-ui/app/less/app.less b/vipra-ui/app/less/app.less index 4ed64e66f96434abaee9f07d9fba3682e1cdee03..78a3d3586afd16087d8903c469e0a41c9e59c9e5 100644 --- a/vipra-ui/app/less/app.less +++ b/vipra-ui/app/less/app.less @@ -229,6 +229,23 @@ ul.dashed { } } +.nya-bs-condensed { + width: auto !important; + margin-top: -2px; + + .dropdown-toggle { + padding: 0px 25px 0px 12px; + } + + .dropdown-menu li a { + padding: 2px 12px; + } +} + +.list-header { + padding-bottom: 10px; +} + [sort-by] { .noselect; cursor: pointer; @@ -238,6 +255,10 @@ ul.dashed { display: none; } +bs-checkbox { + cursor: pointer; +} + @-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 diff --git a/vipra-ui/bower.json b/vipra-ui/bower.json index 53906a9c0f53189a6b885080bfbfcd1cd076d157..5389febe402d9676daf3db23635ca6421396c3c2 100644 --- a/vipra-ui/bower.json +++ b/vipra-ui/bower.json @@ -27,6 +27,7 @@ "nprogress": "^0.2.0", "vis": "https://github.com/almende/vis.git#^4.14.0", "angular-websocket": "^1.0.14", - "moment": "^2.11.2" + "moment": "^2.11.2", + "nya-bootstrap-select": "^2.1.3" } } diff --git a/vipra-ui/gulpfile.js b/vipra-ui/gulpfile.js index 0ab4b7f617f0330b05e96b4584ed66ee5fdd6083..4492076aeb769beeb4c7d40d78af24d173687b70 100644 --- a/vipra-ui/gulpfile.js +++ b/vipra-ui/gulpfile.js @@ -19,12 +19,14 @@ var assets = { 'bower_components/highcharts/highcharts.js', 'bower_components/vis/dist/vis.min.js', 'bower_components/nprogress/nprogress.js', - 'bower_components/moment/min/moment.min.js' + 'bower_components/moment/min/moment.min.js', + 'bower_components/nya-bootstrap-select/dist/js/nya-bs-select.min.js' ], css: [ 'bower_components/bootstrap/dist/css/bootstrap.min.css', 'bower_components/vis/dist/vis.min.css', - 'bower_components/nprogress/nprogress.css' + 'bower_components/nprogress/nprogress.css', + 'bower_components/nya-bootstrap-select/dist/css/nya-bs-select.min.css' ], fonts: [ 'bower_components/bootstrap/dist/fonts/*' diff --git a/vipra-util/src/main/java/de/vipra/util/service/Service.java b/vipra-util/src/main/java/de/vipra/util/service/Service.java index d14eba74e88586bc2fc4c5e1c19c3eb60e56bb8f..df287617c27a17ec64a1d254da21e588fd4622ab 100644 --- a/vipra-util/src/main/java/de/vipra/util/service/Service.java +++ b/vipra-util/src/main/java/de/vipra/util/service/Service.java @@ -264,7 +264,7 @@ public interface Service<Type extends Model<IdType>, IdType, E extends Exception } public String getSortBy() { - return sortBy; + return sortBy.startsWith("+") ? sortBy.substring(1) : sortBy; } public List<Pair<String, Object>> getCriteria() {