From 702f30f4dc61c5ca3c4747dd41170631716a414f Mon Sep 17 00:00:00 2001
From: Roberto Sánchez <roberto.sanchez@curisit.net>
Date: Wed, 08 Jan 2014 14:13:28 +0000
Subject: [PATCH] #394 feature - Added toaster for non intrusive messages
---
securis/src/main/resources/static/admin.html | 29
securis/src/main/resources/static/js/bootstrap-dialog.js | 654 +++++++++++++++++++++++++
securis/src/main/resources/static/js/catalogs.json | 2
securis/src/main/resources/static/js/commons.js | 224 ++++++++
securis/src/main/resources/static/js/admin.js | 129 +++-
securis/src/main/resources/static/js/toaster.js | 145 +++++
securis/src/main/resources/static/css/toaster.css | 207 +++++++
securis/src/main/resources/static/css/bootstrap-dialog.css | 120 ++++
8 files changed, 1,458 insertions(+), 52 deletions(-)
diff --git a/securis/src/main/resources/static/admin.html b/securis/src/main/resources/static/admin.html
index 5e04c00..5c6f344 100644
--- a/securis/src/main/resources/static/admin.html
+++ b/securis/src/main/resources/static/admin.html
@@ -5,12 +5,14 @@
<base href="/">
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
-<title></title>
+<title>SeCuris</title>
<meta name="description" content="">
<meta name="viewport" content="width=device-width">
-<link rel="stylesheet"
- href="http://netdna.bootstrapcdn.com/bootstrap/3.0.3/css/bootstrap.min.css">
+<link rel="stylesheet" href="//netdna.bootstrapcdn.com/bootstrap/3.0.3/css/bootstrap.min.css">
+<link rel="stylesheet" href="/css/bootstrap-dialog.css">
+<link rel="stylesheet" href="/css/toaster.css">
+
<style>
body {
padding-top: 50px;
@@ -103,8 +105,6 @@
<ul class="nav navbar-nav">
<li><a ng-click="editNew()"><span class="glyphicon glyphicon-plus"></span>
New</a></li>
- <li><a ng-click="edit()"><span class="glyphicon glyphicon-pencil"></span>
- Edit</a></li>
<li><a ng-click="cancel()"> <span
class="glyphicon glyphicon-ban-circle"></span> Cancel
</a></li>
@@ -164,11 +164,14 @@
</tr>
</thead>
<tbody>
- <tr ng-repeat="row in list | filter:searchText">
- <td ng-repeat="field in catalogMetadata.list_fields" ng-bind="row[field] "></td>
+ <tr ng-repeat="row in list | filter:searchText" ng-dblclick="edit(row)">
+ <td ng-repeat="field in catalogMetadata.list_fields" ng-bind="print(field, row[field])"></td>
- <td><span ng-click="editRow()"
- class="glyphicon glyphicon-pencil"></span></td>
+ <td><span ng-click="edit(row)"
+ class="glyphicon glyphicon-pencil"></span>
+ <span ng-click="delete(row)"
+ class="glyphicon glyphicon-remove"></span>
+ </td>
</tr>
</tbody>
<tfoot>
@@ -199,6 +202,12 @@
src="/js/angular-resource.min.js"></script>
<script type="text/javascript"
src="/js/angular-animate.min.js"></script>
+ <script type="text/javascript"
+ src="/js/bootstrap-dialog.js"></script>
+ <script type="text/javascript"
+ src="/js/toaster.js"></script>
+
+
<!--
<script
src="//ajax.googleapis.com/ajax/libs/jquery/1.10.1/jquery.min.js"></script>
@@ -222,5 +231,7 @@
});
</script>
+
+ <toaster-container toaster-options="{'time-out': 3000}"></toaster-container>
</body>
</html>
\ No newline at end of file
diff --git a/securis/src/main/resources/static/css/bootstrap-dialog.css b/securis/src/main/resources/static/css/bootstrap-dialog.css
new file mode 100644
index 0000000..32a001d
--- /dev/null
+++ b/securis/src/main/resources/static/css/bootstrap-dialog.css
@@ -0,0 +1,120 @@
+.bootstrap-dialog {
+
+}
+.bootstrap-dialog .modal-header {
+ border-top-left-radius: 4px;
+ border-top-right-radius: 4px;
+}
+.bootstrap-dialog .bootstrap-dialog-title {
+ color: #fff;
+ display: inline-block;
+}
+.bootstrap-dialog.type-default .bootstrap-dialog-title {
+ color: #333;
+}
+.bootstrap-dialog.size-normal .bootstrap-dialog-title {
+ font-size: 16px;
+}
+.bootstrap-dialog.size-large .bootstrap-dialog-title {
+ font-size: 24px;
+}
+.bootstrap-dialog .bootstrap-dialog-close-button {
+ float: right;
+ filter:alpha(opacity=90);
+ -moz-opacity:0.9;
+ -khtml-opacity: 0.9;
+ opacity: 0.9;
+}
+.bootstrap-dialog.size-normal .bootstrap-dialog-close-button {
+ font-size: 20px;
+}
+.bootstrap-dialog.size-large .bootstrap-dialog-close-button {
+ font-size: 30px;
+}
+.bootstrap-dialog .bootstrap-dialog-close-button:hover {
+ cursor: pointer;
+ filter: alpha(opacity=100);
+ -moz-opacity: 1;
+ -khtml-opacity: 1;
+ opacity: 1;
+}
+.bootstrap-dialog.size-normal .bootstrap-dialog-message {
+ font-size: 14px;
+}
+.bootstrap-dialog.size-large .bootstrap-dialog-message {
+ font-size: 18px;
+}
+.bootstrap-dialog.type-default .modal-header {
+ background-color: #fff;
+}
+.bootstrap-dialog.type-info .modal-header {
+ background-color: #5bc0de;
+}
+.bootstrap-dialog.type-primary .modal-header {
+ background-color: #428bca;
+}
+.bootstrap-dialog.type-success .modal-header {
+ background-color: #5cb85c;
+}
+.bootstrap-dialog.type-warning .modal-header {
+ background-color: #f0ad4e;
+}
+.bootstrap-dialog.type-danger .modal-header {
+ background-color: #d9534f;
+}
+.bootstrap-dialog .bootstrap-dialog-button-icon {
+ margin-right: 3px;
+}
+
+/**
+ * Icon animation
+ * Copied from font-awesome: http://fontawesome.io/
+ **/
+.icon-spin {
+ display: inline-block;
+ -moz-animation: spin 2s infinite linear;
+ -o-animation: spin 2s infinite linear;
+ -webkit-animation: spin 2s infinite linear;
+ animation: spin 2s infinite linear;
+}
+@-moz-keyframes spin {
+ 0% {
+ -moz-transform: rotate(0deg);
+}
+100% {
+ -moz-transform: rotate(359deg);
+}
+}
+@-webkit-keyframes spin {
+ 0% {
+ -webkit-transform: rotate(0deg);
+}
+100% {
+ -webkit-transform: rotate(359deg);
+}
+}
+@-o-keyframes spin {
+ 0% {
+ -o-transform: rotate(0deg);
+}
+100% {
+ -o-transform: rotate(359deg);
+}
+}
+@-ms-keyframes spin {
+ 0% {
+ -ms-transform: rotate(0deg);
+}
+100% {
+ -ms-transform: rotate(359deg);
+}
+}
+@keyframes spin {
+ 0% {
+ transform: rotate(0deg);
+}
+100% {
+ transform: rotate(359deg);
+}
+}
+/** End of icon animation **/
\ No newline at end of file
diff --git a/securis/src/main/resources/static/css/toaster.css b/securis/src/main/resources/static/css/toaster.css
new file mode 100644
index 0000000..b2afe4b
--- /dev/null
+++ b/securis/src/main/resources/static/css/toaster.css
@@ -0,0 +1,207 @@
+/*
+ * Toastr
+ * Version 2.0.1
+ * Copyright 2012 John Papa and Hans Fj�llemark.
+ * All Rights Reserved.
+ * Use, reproduction, distribution, and modification of this code is subject to the terms and
+ * conditions of the MIT license, available at http://www.opensource.org/licenses/mit-license.php
+ *
+ * Author: John Papa and Hans Fj�llemark
+ * Project: https://github.com/CodeSeven/toastr
+ */
+.toast-title {
+ font-weight: bold;
+}
+.toast-message {
+ -ms-word-wrap: break-word;
+ word-wrap: break-word;
+}
+.toast-message a,
+.toast-message label {
+ color: #ffffff;
+}
+.toast-message a:hover {
+ color: #cccccc;
+ text-decoration: none;
+}
+
+.toast-close-button {
+ position: relative;
+ right: -0.3em;
+ top: -0.3em;
+ float: right;
+ font-size: 20px;
+ font-weight: bold;
+ color: #ffffff;
+ -webkit-text-shadow: 0 1px 0 #ffffff;
+ text-shadow: 0 1px 0 #ffffff;
+ opacity: 0.8;
+ -ms-filter: progid:DXImageTransform.Microsoft.Alpha(Opacity=80);
+ filter: alpha(opacity=80);
+}
+.toast-close-button:hover,
+.toast-close-button:focus {
+ color: #000000;
+ text-decoration: none;
+ cursor: pointer;
+ opacity: 0.4;
+ -ms-filter: progid:DXImageTransform.Microsoft.Alpha(Opacity=40);
+ filter: alpha(opacity=40);
+}
+
+/*Additional properties for button version
+ iOS requires the button element instead of an anchor tag.
+ If you want the anchor version, it requires `href="#"`.*/
+button.toast-close-button {
+ padding: 0;
+ cursor: pointer;
+ background: transparent;
+ border: 0;
+ -webkit-appearance: none;
+}
+.toast-top-full-width {
+ top: 0;
+ right: 0;
+ width: 100%;
+}
+.toast-bottom-full-width {
+ bottom: 0;
+ right: 0;
+ width: 100%;
+}
+.toast-top-left {
+ top: 12px;
+ left: 12px;
+}
+.toast-top-right {
+ top: 12px;
+ right: 12px;
+}
+.toast-bottom-right {
+ right: 12px;
+ bottom: 12px;
+}
+.toast-bottom-left {
+ bottom: 12px;
+ left: 12px;
+}
+#toast-container {
+ position: fixed;
+ z-index: 999999;
+ /*overrides*/
+
+}
+#toast-container * {
+ -moz-box-sizing: border-box;
+ -webkit-box-sizing: border-box;
+ box-sizing: border-box;
+}
+#toast-container > div {
+ margin: 0 0 6px;
+ padding: 15px 15px 15px 50px;
+ width: 300px;
+ -moz-border-radius: 3px 3px 3px 3px;
+ -webkit-border-radius: 3px 3px 3px 3px;
+ border-radius: 3px 3px 3px 3px;
+ background-position: 15px center;
+ background-repeat: no-repeat;
+ -moz-box-shadow: 0 0 12px #999999;
+ -webkit-box-shadow: 0 0 12px #999999;
+ box-shadow: 0 0 12px #999999;
+ color: #ffffff;
+ opacity: 0.8;
+ -ms-filter: progid:DXImageTransform.Microsoft.Alpha(Opacity=80);
+ filter: alpha(opacity=80);
+}
+#toast-container > :hover {
+ -moz-box-shadow: 0 0 12px #000000;
+ -webkit-box-shadow: 0 0 12px #000000;
+ box-shadow: 0 0 12px #000000;
+ opacity: 1;
+ -ms-filter: progid:DXImageTransform.Microsoft.Alpha(Opacity=100);
+ filter: alpha(opacity=100);
+ cursor: pointer;
+}
+#toast-container > .toast-info {
+ background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABgAAAAYCAYAAADgdz34AAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAGwSURBVEhLtZa9SgNBEMc9sUxxRcoUKSzSWIhXpFMhhYWFhaBg4yPYiWCXZxBLERsLRS3EQkEfwCKdjWJAwSKCgoKCcudv4O5YLrt7EzgXhiU3/4+b2ckmwVjJSpKkQ6wAi4gwhT+z3wRBcEz0yjSseUTrcRyfsHsXmD0AmbHOC9Ii8VImnuXBPglHpQ5wwSVM7sNnTG7Za4JwDdCjxyAiH3nyA2mtaTJufiDZ5dCaqlItILh1NHatfN5skvjx9Z38m69CgzuXmZgVrPIGE763Jx9qKsRozWYw6xOHdER+nn2KkO+Bb+UV5CBN6WC6QtBgbRVozrahAbmm6HtUsgtPC19tFdxXZYBOfkbmFJ1VaHA1VAHjd0pp70oTZzvR+EVrx2Ygfdsq6eu55BHYR8hlcki+n+kERUFG8BrA0BwjeAv2M8WLQBtcy+SD6fNsmnB3AlBLrgTtVW1c2QN4bVWLATaIS60J2Du5y1TiJgjSBvFVZgTmwCU+dAZFoPxGEEs8nyHC9Bwe2GvEJv2WXZb0vjdyFT4Cxk3e/kIqlOGoVLwwPevpYHT+00T+hWwXDf4AJAOUqWcDhbwAAAAASUVORK5CYII=") !important;
+}
+#toast-container > .toast-error {
+ background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABgAAAAYCAYAAADgdz34AAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAHOSURBVEhLrZa/SgNBEMZzh0WKCClSCKaIYOED+AAKeQQLG8HWztLCImBrYadgIdY+gIKNYkBFSwu7CAoqCgkkoGBI/E28PdbLZmeDLgzZzcx83/zZ2SSXC1j9fr+I1Hq93g2yxH4iwM1vkoBWAdxCmpzTxfkN2RcyZNaHFIkSo10+8kgxkXIURV5HGxTmFuc75B2RfQkpxHG8aAgaAFa0tAHqYFfQ7Iwe2yhODk8+J4C7yAoRTWI3w/4klGRgR4lO7Rpn9+gvMyWp+uxFh8+H+ARlgN1nJuJuQAYvNkEnwGFck18Er4q3egEc/oO+mhLdKgRyhdNFiacC0rlOCbhNVz4H9FnAYgDBvU3QIioZlJFLJtsoHYRDfiZoUyIxqCtRpVlANq0EU4dApjrtgezPFad5S19Wgjkc0hNVnuF4HjVA6C7QrSIbylB+oZe3aHgBsqlNqKYH48jXyJKMuAbiyVJ8KzaB3eRc0pg9VwQ4niFryI68qiOi3AbjwdsfnAtk0bCjTLJKr6mrD9g8iq/S/B81hguOMlQTnVyG40wAcjnmgsCNESDrjme7wfftP4P7SP4N3CJZdvzoNyGq2c/HWOXJGsvVg+RA/k2MC/wN6I2YA2Pt8GkAAAAASUVORK5CYII=") !important;
+}
+#toast-container > .toast-success {
+ background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABgAAAAYCAYAAADgdz34AAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAADsSURBVEhLY2AYBfQMgf///3P8+/evAIgvA/FsIF+BavYDDWMBGroaSMMBiE8VC7AZDrIFaMFnii3AZTjUgsUUWUDA8OdAH6iQbQEhw4HyGsPEcKBXBIC4ARhex4G4BsjmweU1soIFaGg/WtoFZRIZdEvIMhxkCCjXIVsATV6gFGACs4Rsw0EGgIIH3QJYJgHSARQZDrWAB+jawzgs+Q2UO49D7jnRSRGoEFRILcdmEMWGI0cm0JJ2QpYA1RDvcmzJEWhABhD/pqrL0S0CWuABKgnRki9lLseS7g2AlqwHWQSKH4oKLrILpRGhEQCw2LiRUIa4lwAAAABJRU5ErkJggg==") !important;
+}
+#toast-container > .toast-warning {
+ background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABgAAAAYCAYAAADgdz34AAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAGYSURBVEhL5ZSvTsNQFMbXZGICMYGYmJhAQIJAICYQPAACiSDB8AiICQQJT4CqQEwgJvYASAQCiZiYmJhAIBATCARJy+9rTsldd8sKu1M0+dLb057v6/lbq/2rK0mS/TRNj9cWNAKPYIJII7gIxCcQ51cvqID+GIEX8ASG4B1bK5gIZFeQfoJdEXOfgX4QAQg7kH2A65yQ87lyxb27sggkAzAuFhbbg1K2kgCkB1bVwyIR9m2L7PRPIhDUIXgGtyKw575yz3lTNs6X4JXnjV+LKM/m3MydnTbtOKIjtz6VhCBq4vSm3ncdrD2lk0VgUXSVKjVDJXJzijW1RQdsU7F77He8u68koNZTz8Oz5yGa6J3H3lZ0xYgXBK2QymlWWA+RWnYhskLBv2vmE+hBMCtbA7KX5drWyRT/2JsqZ2IvfB9Y4bWDNMFbJRFmC9E74SoS0CqulwjkC0+5bpcV1CZ8NMej4pjy0U+doDQsGyo1hzVJttIjhQ7GnBtRFN1UarUlH8F3xict+HY07rEzoUGPlWcjRFRr4/gChZgc3ZL2d8oAAAAASUVORK5CYII=") !important;
+}
+#toast-container.toast-top-full-width > div,
+#toast-container.toast-bottom-full-width > div {
+ width: 96%;
+ margin: auto;
+}
+.toast {
+ background-color: #030303;
+}
+.toast-success {
+ background-color: #51a351;
+}
+.toast-error {
+ background-color: #bd362f;
+}
+.toast-info {
+ background-color: #2f96b4;
+}
+.toast-warning {
+ background-color: #f89406;
+}
+/*Responsive Design*/
+@media all and (max-width: 240px) {
+ #toast-container > div {
+ padding: 8px 8px 8px 50px;
+ width: 11em;
+ }
+ #toast-container .toast-close-button {
+ right: -0.2em;
+ top: -0.2em;
+}
+ }
+@media all and (min-width: 241px) and (max-width: 480px) {
+ #toast-container > div {
+ padding: 8px 8px 8px 50px;
+ width: 18em;
+ }
+ #toast-container .toast-close-button {
+ right: -0.2em;
+ top: -0.2em;
+}
+}
+@media all and (min-width: 481px) and (max-width: 768px) {
+ #toast-container > div {
+ padding: 15px 15px 15px 50px;
+ width: 25em;
+ }
+}
+
+ /*
+ * AngularJS-Toaster
+ * Version 0.3
+ */
+#toast-container > div.ng-enter,
+#toast-container > div.ng-leave
+{
+ -webkit-transition: 1000ms cubic-bezier(0.250, 0.250, 0.750, 0.750) all;
+ -moz-transition: 1000ms cubic-bezier(0.250, 0.250, 0.750, 0.750) all;
+ -ms-transition: 1000ms cubic-bezier(0.250, 0.250, 0.750, 0.750) all;
+ -o-transition: 1000ms cubic-bezier(0.250, 0.250, 0.750, 0.750) all;
+ transition: 1000ms cubic-bezier(0.250, 0.250, 0.750, 0.750) all;
+}
+
+#toast-container > div.ng-enter.ng-enter-active,
+#toast-container > div.ng-leave {
+ opacity: 0.8;
+}
+
+#toast-container > div.ng-leave.ng-leave-active,
+#toast-container > div.ng-enter {
+ opacity: 0;
+}
\ No newline at end of file
diff --git a/securis/src/main/resources/static/js/admin.js b/securis/src/main/resources/static/js/admin.js
index 759b8a2..7bd2645 100644
--- a/securis/src/main/resources/static/js/admin.js
+++ b/securis/src/main/resources/static/js/admin.js
@@ -1,7 +1,7 @@
(function() {
'use strict';
- var app = angular.module('app', [ 'ngRoute', 'ngAnimate', 'ngResource' ]);
+ var app = angular.module('app', [ 'ngRoute', 'ngAnimate', 'ngResource', 'toaster' ]);
app.directive(
'catalogField',
@@ -22,7 +22,7 @@
};
});
- app.factory('Catalogs', function($http, $resource) {
+ app.factory('Catalogs', function($http, $resource, toaster) {
var CatalogsService = {
resources : {
application : $resource('/application/:appId', {
@@ -68,7 +68,25 @@
return CatalogsService.data ? CatalogsService.data[index] : {};
},
save: function(catalog, data) {
- console.log('save ???? ' );
+ var resource = CatalogsService.resources[catalog.toLowerCase()];
+ function success(data) {
+ console.log('success')
+ console.log(data)
+ toaster.pop('success', "Data saved sucessfully in " + catalog);
+ }
+ function fail(data, status) {
+ var errorMsg = {500: 'Server error', 404: 'Item to modify was not found'}[data.status]
+ toaster.pop('error', "Error saving data in " + catalog, errorMsg);
+ console.log('error')
+ console.error(data)
+ console.error(status)
+ }
+ if (data.id && data.id !== '')
+ return resource.update(data, success, fail)
+ else
+ return resource.save(data, success, fail)
+ },
+ remove: function(catalog, data) {
var resource = CatalogsService.resources[catalog.toLowerCase()];
function success(data) {
console.log('success')
@@ -79,10 +97,7 @@
console.error(data)
console.error(status)
}
- if (data.id && data.id !== '')
- return resource.update(data, success, fail)
- else
- return resource.save(data, success, fail)
+ return resource.remove({}, data, success, fail)
},
query: function(catalog, callback) {
console.log('HI catalog ???? ' + catalog);
@@ -108,38 +123,58 @@
'$scope',
'$http',
'Catalogs',
- function($scope, $http, catalogs) {
+ function($scope, $http, Catalogs) {
$scope.formu = {};
$scope.catalogIndex = 0;
- $scope.catalogs = catalogs.list(function() {
- $scope.catalogMetadata = catalogs.getMetadata($scope.catalogIndex);
- $scope.list = catalogs.query(catalogs.getResource($scope.catalogIndex));
+ $scope.catalogs = Catalogs.list(function() {
+ $scope.catalogMetadata = Catalogs.getMetadata($scope.catalogIndex);
+ $scope.list = Catalogs.query(Catalogs.getResource($scope.catalogIndex));
});
$scope.catalogMetadata = {};
$scope.selectCatalog = function(index, $event) {
$scope.catalogIndex = index;
- $scope.catalogMetadata = catalogs.getMetadata($scope.catalogIndex);
- $scope.list = catalogs.query(catalogs.getResource($scope.catalogIndex));
+ $scope.catalogMetadata = Catalogs.getMetadata($scope.catalogIndex);
+ $scope.list = Catalogs.query(Catalogs.getResource($scope.catalogIndex));
console.log($event);
}
- } ]);
-
- app.controller('CatalogFormCtrl', [ '$scope', '$http', 'Catalogs',
- function($scope, $http, Catalogs) {
- $scope.showForm = false;
- $scope.scope = $scope;
- console.log('Form: currentCatalog:' + $scope.cataLogIndex);
- $scope.editNew = function() {
+ $scope.edit = function(data) {
$scope.showForm = true;
- $scope.isNew = true;
+ $scope.isNew = false;
+ for (var k in data) {
+ if (k.indexOf('$') !== 0) $scope.formu[k] = data[k]
+ }
+ // TODO: Load in formu values for Form
// $scope.formu = {};
}
- $scope.edit = function() {
- $scope.showForm = true;
+ $scope.delete = function(data) {
+ BootstrapDialog.confirm('The record will be deleted, are you sure?', function(result){
+ if(result) {
+ var catalogName = Catalogs.getResource($scope.catalogIndex);
+ var promise = Catalogs.remove(catalogName, data).$promise;
+ promise.then(function(data) {
+ $scope.list = Catalogs.query(catalogName);
+ });
+ }
+ });
+ $scope.showForm = false;
$scope.isNew = false;
// TODO: Load in formu values for Form
// $scope.formu = {};
+ }
+
+ } ]);
+
+ app.controller('CatalogFormCtrl', [ '$scope', '$http', 'toaster', 'Catalogs',
+ function($scope, $http, toaster, Catalogs) {
+ $scope.showForm = false;
+ $scope.scope = $scope;
+ console.log('Form: currentCatalog:' + $scope.cataLogIndex);
+
+ $scope.editNew = function() {
+ $scope.showForm = true;
+ $scope.isNew = true;
+ $scope.formu = {};
}
$scope.cancel = function() {
$scope.showForm = false;
@@ -151,34 +186,44 @@
} else {
var catalogName = Catalogs.getResource($scope.catalogIndex);
var promise = Catalogs.save(catalogName, $scope.formu).$promise;
- console.log('================================================================================================================================')
- console.log(promise)
- promise.then(function(data) {
- console.log('Command returned OK form promise')
- console.log(data)
+ promise.then(function(data, otro) {
+ if ($scope.isNew) {
+ $scope.formu = {}
+ $('#name').focus();
+ } else {
+ $scope.cancel();
+ }
+ // $scope.formu = {};
$scope.$parent.list = Catalogs.query(catalogName);
-
+ }, function(error, otro) {
+ console.log('then error');
+ console.log(error);
+ console.log(otro);
});
+
}
}
} ]);
- app.controller('CatalogListCtrl', [ '$scope', '$http', 'Catalogs',
- function($scope, $http, Catalogs) {
+ app.controller('CatalogListCtrl', [ '$scope', '$http', '$filter', 'Catalogs',
+ function($scope, $http, $filter, Catalogs) {
console.log('List: currentCatalog: ' + $scope.currentCatalog);
- $scope.myFilter = function(field) {
- if (field === 'creationTimestamp')
- return 'date';
- else '';
+ var _indexOfField = function(name) {
+ if (!$scope.catalogMetadata) return -1;
+ for (var i = $scope.catalogMetadata.fields.length - 1; i >= 0 && $scope.catalogMetadata.fields[i].name !== name; i--);
+ return i;
+ }
+
+ $scope.print = function(name, value) {
+ var index = _indexOfField(name);
+ if (index === -1) return value;
+ var type = $scope.catalogMetadata.fields[index].type;
+
+ return type === 'date' ? $filter('date')(value, 'yyyy-MM-dd') : value;
}
$scope.display = function(name) {
- var _indexOf = function(name) {
- if (!$scope.catalogMetadata) return -1;
- for (var i = $scope.catalogMetadata.fields.length - 1; i >= 0 && $scope.catalogMetadata.fields[i].name !== name; i--);
- return i;
- }
- var index = _indexOf(name);
+ var index = _indexOfField(name);
return index === -1 ? '' : $scope.catalogMetadata.fields[index].display;
}
diff --git a/securis/src/main/resources/static/js/bootstrap-dialog.js b/securis/src/main/resources/static/js/bootstrap-dialog.js
new file mode 100644
index 0000000..e4da030
--- /dev/null
+++ b/securis/src/main/resources/static/js/bootstrap-dialog.js
@@ -0,0 +1,654 @@
+/* ================================================
+ * Make use of Twitter Bootstrap's modal more monkey-friendly.
+ *
+ * For Bootstrap 3.
+ *
+ * javanoob@hotmail.com
+ *
+ * Licensed under The MIT License.
+ * ================================================ */
+var BootstrapDialog = null;
+!function($) {
+ "use strict";
+
+ BootstrapDialog = function(options) {
+ this.defaultOptions = {
+ id: BootstrapDialog.newGuid(),
+ type: BootstrapDialog.TYPE_PRIMARY,
+ size: BootstrapDialog.SIZE_NORMAL,
+ cssClass: '',
+ title: null,
+ message: null,
+ buttons: [],
+ closable: true,
+ spinicon: BootstrapDialog.ICON_SPINNER,
+ data: {},
+ onshow: null,
+ onhide: null,
+ autodestroy: true
+ };
+ this.indexedButtons = {};
+ this.realized = false;
+ this.opened = false;
+ this.initOptions(options);
+ this.holdThisInstance();
+ };
+
+ /**
+ * Some constants.
+ */
+ BootstrapDialog.NAMESPACE = 'bootstrap-dialog';
+
+ BootstrapDialog.TYPE_DEFAULT = 'type-default';
+ BootstrapDialog.TYPE_INFO = 'type-info';
+ BootstrapDialog.TYPE_PRIMARY = 'type-primary';
+ BootstrapDialog.TYPE_SUCCESS = 'type-success';
+ BootstrapDialog.TYPE_WARNING = 'type-warning';
+ BootstrapDialog.TYPE_DANGER = 'type-danger';
+
+ BootstrapDialog.DEFAULT_TEXTS = {};
+ BootstrapDialog.DEFAULT_TEXTS[BootstrapDialog.TYPE_DEFAULT] = 'Information';
+ BootstrapDialog.DEFAULT_TEXTS[BootstrapDialog.TYPE_INFO] = 'Information';
+ BootstrapDialog.DEFAULT_TEXTS[BootstrapDialog.TYPE_PRIMARY] = 'Information';
+ BootstrapDialog.DEFAULT_TEXTS[BootstrapDialog.TYPE_SUCCESS] = 'Success';
+ BootstrapDialog.DEFAULT_TEXTS[BootstrapDialog.TYPE_WARNING] = 'Warning';
+ BootstrapDialog.DEFAULT_TEXTS[BootstrapDialog.TYPE_DANGER] = 'Danger';
+
+ BootstrapDialog.SIZE_NORMAL = 'size-normal';
+ BootstrapDialog.SIZE_LARGE = 'size-large';
+
+ BootstrapDialog.BUTTON_SIZES = {};
+ BootstrapDialog.BUTTON_SIZES[BootstrapDialog.SIZE_NORMAL] = '';
+ BootstrapDialog.BUTTON_SIZES[BootstrapDialog.SIZE_LARGE] = 'btn-lg';
+
+ BootstrapDialog.ICON_SPINNER = 'glyphicon glyphicon-asterisk';
+
+ /**
+ * Open / Close all created dialogs all at once.
+ */
+ BootstrapDialog.dialogs = {};
+ BootstrapDialog.openAll = function() {
+ $.each(BootstrapDialog.dialogs, function(id, dialogInstance) {
+ dialogInstance.open();
+ });
+ };
+ BootstrapDialog.closeAll = function() {
+ $.each(BootstrapDialog.dialogs, function(id, dialogInstance) {
+ dialogInstance.close();
+ });
+ };
+
+ BootstrapDialog.prototype = {
+ constructor: BootstrapDialog,
+ initOptions: function(options) {
+ this.options = $.extend(true, this.defaultOptions, options);
+
+ return this;
+ },
+ holdThisInstance: function() {
+ BootstrapDialog.dialogs[this.getId()] = this;
+
+ return this;
+ },
+ initModalStuff: function() {
+ this.setModal(this.createModal())
+ .setModalDialog(this.createModalDialog())
+ .setModalContent(this.createModalContent())
+ .setModalHeader(this.createModalHeader())
+ .setModalBody(this.createModalBody())
+ .setModalFooter(this.createModalFooter());
+
+ this.getModal().append(this.getModalDialog());
+ this.getModalDialog().append(this.getModalContent());
+ this.getModalContent()
+ .append(this.getModalHeader())
+ .append(this.getModalBody())
+ .append(this.getModalFooter());
+
+ return this;
+ },
+ createModal: function() {
+ return $('<div class="modal fade" tabindex="-1" id="' + this.getId() + '"></div>');
+ },
+ getModal: function() {
+ return this.$modal;
+ },
+ setModal: function($modal) {
+ this.$modal = $modal;
+
+ return this;
+ },
+ createModalDialog: function() {
+ return $('<div class="modal-dialog"></div>');
+ },
+ getModalDialog: function() {
+ return this.$modalDialog;
+ },
+ setModalDialog: function($modalDialog) {
+ this.$modalDialog = $modalDialog;
+
+ return this;
+ },
+ createModalContent: function() {
+ return $('<div class="modal-content"></div>');
+ },
+ getModalContent: function() {
+ return this.$modalContent;
+ },
+ setModalContent: function($modalContent) {
+ this.$modalContent = $modalContent;
+
+ return this;
+ },
+ createModalHeader: function() {
+ return $('<div class="modal-header"></div>');
+ },
+ getModalHeader: function() {
+ return this.$modalHeader;
+ },
+ setModalHeader: function($modalHeader) {
+ this.$modalHeader = $modalHeader;
+
+ return this;
+ },
+ createModalBody: function() {
+ return $('<div class="modal-body"></div>');
+ },
+ getModalBody: function() {
+ return this.$modalBody;
+ },
+ setModalBody: function($modalBody) {
+ this.$modalBody = $modalBody;
+
+ return this;
+ },
+ createModalFooter: function() {
+ return $('<div class="modal-footer"></div>');
+ },
+ getModalFooter: function() {
+ return this.$modaFooter;
+ },
+ setModalFooter: function($modaFooter) {
+ this.$modaFooter = $modaFooter;
+
+ return this;
+ },
+ createDynamicContent: function(rawContent) {
+ var content = null;
+ if (typeof rawContent === 'function') {
+ content = rawContent.call(rawContent, this);
+ } else {
+ content = rawContent;
+ }
+ if (typeof content === 'string') {
+ content = this.formatStringContent(content);
+ }
+
+ return content;
+ },
+ formatStringContent: function(content) {
+ return content.replace(/\r\n/g, '<br />').replace(/[\r\n]/g, '<br />');
+ },
+ setData: function(key, value) {
+ this.options.data[key] = value;
+
+ return this;
+ },
+ getData: function(key) {
+ return this.options.data[key];
+ },
+ setId: function(id) {
+ this.options.id = id;
+
+ return this;
+ },
+ getId: function() {
+ return this.options.id;
+ },
+ getType: function() {
+ return this.options.type;
+ },
+ setType: function(type) {
+ this.options.type = type;
+
+ return this;
+ },
+ getSize: function() {
+ return this.options.size;
+ },
+ setSize: function(size) {
+ this.options.size = size;
+
+ return this;
+ },
+ getCssClass: function() {
+ return this.options.cssClass;
+ },
+ setCssClass: function(cssClass){
+ this.options.cssClass = cssClass;
+
+ return this;
+ },
+ getTitle: function() {
+ return this.options.title;
+ },
+ setTitle: function(title) {
+ this.options.title = title;
+
+ return this;
+ },
+ getMessage: function() {
+ return this.options.message;
+ },
+ setMessage: function(message) {
+ this.options.message = message;
+
+ return this;
+ },
+ isClosable: function() {
+ return this.options.closable;
+ },
+ setClosable: function(closable) {
+ this.options.closable = closable;
+ this.updateClosable();
+
+ return this;
+ },
+ getSpinicon: function() {
+ return this.options.spinicon;
+ },
+ setSpinicon: function(spinicon) {
+ this.options.spinicon = spinicon;
+
+ return this;
+ },
+ addButton: function(button) {
+ this.options.buttons.push(button);
+
+ return this;
+ },
+ addButtons: function(buttons) {
+ var that = this;
+
+ $.each(buttons, function(index, button) {
+ that.addButton(button);
+ });
+
+ return this;
+ },
+ getButtons: function() {
+ return this.options.buttons;
+ },
+ setButtons: function(buttons) {
+ this.options.buttons = buttons;
+
+ return this;
+ },
+ /**
+ * If there is id provided for a button option, it will be in dialog.indexedButtons list.
+ *
+ * In that case you can use dialog.getButton(id) to find the button.
+ *
+ * @param {type} id
+ * @returns {undefined}
+ */
+ getButton: function(id) {
+ if (typeof this.indexedButtons[id] !== 'undefined') {
+ return this.indexedButtons[id];
+ }
+
+ return null;
+ },
+ getButtonSize: function() {
+ if (typeof BootstrapDialog.BUTTON_SIZES[this.getSize()] !== 'undefined') {
+ return BootstrapDialog.BUTTON_SIZES[this.getSize()];
+ }
+
+ return '';
+ },
+ isAutodestroy: function() {
+ return this.options.autodestroy;
+ },
+ setAutodestroy: function(autodestroy) {
+ this.options.autodestroy = autodestroy;
+ },
+ getDefaultText: function() {
+ return BootstrapDialog.DEFAULT_TEXTS[this.getType()];
+ },
+ getNamespace: function(name) {
+ return BootstrapDialog.NAMESPACE + '-' + name;
+ },
+ createHeaderContent: function() {
+ var $container = $('<div></div>');
+ $container.addClass(this.getNamespace('header'));
+
+ // title
+ $container.append(this.createTitleContent());
+
+ // Close button
+ $container.append(this.createCloseButton());
+
+ return $container;
+ },
+ createTitleContent: function() {
+ var $title = $('<div></div>');
+ $title.addClass(this.getNamespace('title'));
+ $title.append(this.getTitle() !== null ? this.createDynamicContent(this.getTitle()) : this.getDefaultText());
+
+ return $title;
+ },
+ createCloseButton: function() {
+ var $container = $('<div></div>');
+ $container.addClass(this.getNamespace('close-button'));
+ var $icon = $('<button class="close">×</button>');
+ $container.append($icon);
+ $container.on('click', {dialog: this}, function(event) {
+ event.data.dialog.close();
+ });
+
+ return $container;
+ },
+ createBodyContent: function() {
+ var $container = $('<div></div>');
+ $container.addClass(this.getNamespace('body'));
+
+ // Message
+ $container.append(this.createMessageContent());
+
+ return $container;
+ },
+ createMessageContent: function() {
+ var $message = $('<div></div>');
+ $message.addClass(this.getNamespace('message'));
+ $message.append(this.createDynamicContent(this.getMessage()));
+
+ return $message;
+ },
+ createFooterContent: function() {
+ var $container = $('<div></div>');
+ $container.addClass(this.getNamespace('footer'));
+
+ // Buttons
+ $container.append(this.createFooterButtons());
+
+ return $container;
+ },
+ createFooterButtons: function() {
+ var that = this;
+ var $container = $('<div></div>');
+ $container.addClass(this.getNamespace('footer-buttons'));
+ this.indexedButtons = {};
+ $.each(this.options.buttons, function(index, button) {
+ var $button = that.createButton(button);
+ if (typeof button.id !== 'undefined') {
+ that.indexedButtons[button.id] = $button;
+ }
+ $container.append($button);
+ });
+
+ return $container;
+ },
+ createButton: function(button) {
+ var $button = $('<button class="btn"></button>');
+ $button.addClass(this.getButtonSize());
+
+ // Icon
+ if (typeof button.icon !== undefined && $.trim(button.icon) !== '') {
+ $button.append(this.createButtonIcon(button.icon));
+ }
+
+ // Label
+ if (typeof button.label !== undefined) {
+ $button.append(button.label);
+ }
+
+ // Css class
+ if (typeof button.cssClass !== undefined && $.trim(button.cssClass) !== '') {
+ $button.addClass(button.cssClass);
+ } else {
+ $button.addClass('btn-default');
+ }
+
+ // Button on click
+ $button.on('click', {dialog: this, button: button}, function(event) {
+ var dialog = event.data.dialog;
+ var button = event.data.button;
+ if (typeof button.action === 'function') {
+ button.action.call(this, dialog);
+ }
+
+ if (button.autospin) {
+ var $button = $(this);
+ $button.find('.' + dialog.getNamespace('button-icon')).remove();
+ $button.prepend(dialog.createButtonIcon(dialog.getSpinicon()).addClass('icon-spin'));
+ }
+ });
+
+ return $button;
+ },
+ createButtonIcon: function(icon) {
+ var $icon = $('<span></span>');
+ $icon.addClass(this.getNamespace('button-icon')).addClass(icon);
+
+ return $icon;
+ },
+ /**
+ * Invoke this only after the dialog is realized.
+ *
+ * @param {type} enable
+ * @returns {undefined}
+ */
+ enableButtons: function(enable) {
+ var $buttons = this.getModalFooter().find('.btn');
+ $buttons.prop("disabled", !enable).toggleClass('disabled', !enable);
+
+ return this;
+ },
+ /**
+ * Invoke this only after the dialog is realized.
+ *
+ * @param {type} enable
+ * @returns {undefined}
+ */
+ updateClosable: function() {
+ if (this.isRealized()) {
+ // Backdrop, I did't find a way to change bs3 backdrop option after the dialog is popped up, so here's a new wheel.
+ var $theBigMask = this.getModal();
+ $theBigMask.off('click').on('click', {dialog: this}, function(event) {
+ event.target === this && event.data.dialog.isClosable() && event.data.dialog.close();
+ });
+
+ // Close button
+ this.getModalHeader().find('.' + this.getNamespace('close-button')).toggle(this.isClosable());
+
+ // ESC key support
+ $theBigMask.off('keyup').on('keyup', {dialog: this}, function(event) {
+ event.which === 27 && event.data.dialog.isClosable() && event.data.dialog.close();
+ });
+ }
+
+ return this;
+ },
+ /**
+ * Set handler for modal event 'show'.
+ * This is a setter!
+ *
+ * @param {type} onopen
+ * @returns {_L9.BootstrapDialog.prototype}
+ */
+ onShow: function(onshow) {
+ this.options.onshow = onshow;
+
+ return this;
+ },
+ /**
+ * Set handler for modal event 'hide'.
+ * This is a setter!
+ *
+ * @param {type} onclose
+ * @returns {_L9.BootstrapDialog.prototype}
+ */
+ onHide: function(onhide) {
+ this.options.onhide = onhide;
+
+ return this;
+ },
+ isRealized: function() {
+ return this.realized;
+ },
+ setRealized: function(realized) {
+ this.realized = realized;
+
+ return this;
+ },
+ isOpened: function() {
+ return this.opened;
+ },
+ setOpened: function(opened) {
+ this.opened = opened;
+
+ return this;
+ },
+ handleModalEvents: function() {
+ this.getModal().on('show.bs.modal', {dialog: this}, function(event) {
+ var dialog = event.data.dialog;
+ typeof dialog.options.onshow === 'function' && dialog.options.onshow(dialog);
+ dialog.showPageScrollBar(true);
+ });
+ this.getModal().on('hide.bs.modal', {dialog: this}, function(event) {
+ var dialog = event.data.dialog;
+ typeof dialog.options.onhide === 'function' && dialog.options.onhide(dialog);
+ });
+ this.getModal().on('hidden.bs.modal', {dialog: this}, function(event) {
+ var dialog = event.data.dialog;
+ dialog.isAutodestroy() && $(this).remove();
+ dialog.showPageScrollBar(false);
+ });
+
+ return this;
+ },
+ showPageScrollBar: function(show) {
+ $(document.body).toggleClass('modal-open', show);
+ },
+ realize: function() {
+ this.initModalStuff();
+ this.getModal().addClass(BootstrapDialog.NAMESPACE)
+ .addClass(this.getType())
+ .addClass(this.getSize())
+ .addClass(this.getCssClass());
+ this.getModalHeader().append(this.createHeaderContent());
+ this.getModalBody().append(this.createBodyContent());
+ this.getModalFooter().append(this.createFooterContent());
+ this.getModal().modal({
+ backdrop: 'static',
+ keyboard: false,
+ show: false
+ });
+ this.handleModalEvents();
+ this.setRealized(true);
+
+ return this;
+ },
+ open: function() {
+ !this.isRealized() && this.realize();
+ this.updateClosable();
+ this.getModal().modal('show');
+ this.setOpened(true);
+
+ return this;
+ },
+ close: function() {
+ this.getModal().modal('hide');
+ if (this.isAutodestroy()) {
+ delete BootstrapDialog.dialogs[this.getId()];
+ }
+ this.setOpened(false);
+
+ return this;
+ }
+ };
+
+ /**
+ * RFC4122 version 4 compliant unique id creator.
+ *
+ * Added by https://github.com/tufanbarisyildirim/
+ *
+ * @returns {String}
+ */
+ BootstrapDialog.newGuid = function() {
+ return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function(c) {
+ var r = Math.random() * 16 | 0, v = c === 'x' ? r : (r & 0x3 | 0x8);
+ return v.toString(16);
+ });
+ };
+
+ /* ================================================
+ * For lazy people
+ * ================================================ */
+
+ /**
+ * Shortcut function: show
+ *
+ * @param {type} options
+ * @returns {undefined}
+ */
+ BootstrapDialog.show = function(options) {
+ new BootstrapDialog(options).open();
+ };
+
+ /**
+ * Alert window
+ *
+ * @param {type} message
+ * @param {type} callback
+ * @returns {undefined}
+ */
+ BootstrapDialog.alert = function(message, callback) {
+ new BootstrapDialog({
+ message: message,
+ data: {
+ 'callback': callback
+ },
+ closable: false,
+ buttons: [{
+ label: 'OK',
+ action: function(dialog) {
+ typeof dialog.getData('callback') === 'function' && dialog.getData('callback')(true);
+ dialog.close();
+ }
+ }]
+ }).open();
+ };
+
+ /**
+ * Confirm window
+ *
+ * @param {type} message
+ * @param {type} callback
+ * @returns {undefined}
+ */
+ BootstrapDialog.confirm = function(message, callback) {
+ new BootstrapDialog({
+ title: 'Confirmation',
+ message: message,
+ closable: false,
+ data: {
+ 'callback': callback
+ },
+ buttons: [{
+ label: 'Cancel',
+ action: function(dialog) {
+ typeof dialog.getData('callback') === 'function' && dialog.getData('callback')(false);
+ dialog.close();
+ }
+ }, {
+ label: 'OK',
+ cssClass: 'btn-primary',
+ action: function(dialog) {
+ typeof dialog.getData('callback') === 'function' && dialog.getData('callback')(true);
+ dialog.close();
+ }
+ }]
+ }).open();
+ };
+}(window.jQuery);
diff --git a/securis/src/main/resources/static/js/catalogs.json b/securis/src/main/resources/static/js/catalogs.json
index dd7cf93..33e2983 100644
--- a/securis/src/main/resources/static/js/catalogs.json
+++ b/securis/src/main/resources/static/js/catalogs.json
@@ -1,7 +1,7 @@
[ {
"name" : "Applications",
"resource" : "application",
- "list_fields" : [ "name", "description", "creation_timestamp" ],
+ "list_fields" : [ "name", "description", "creationTimestamp" ],
"fields" : [ {
"name" : "id",
"display" : "ID",
diff --git a/securis/src/main/resources/static/js/commons.js b/securis/src/main/resources/static/js/commons.js
new file mode 100644
index 0000000..692793b
--- /dev/null
+++ b/securis/src/main/resources/static/js/commons.js
@@ -0,0 +1,224 @@
+(function() {
+ 'use strict';
+
+ var app = angular.module('app', [ 'ngRoute', 'ngAnimate', 'ngResource' ]);
+
+ app.directive(
+ 'catalogField',
+ function() {
+ return {
+ restrict : 'A', // only activate on element
+ // attribute
+ require : '?ngModel', // get a hold of
+ // NgModelController
+ link : function(scope, element, attrs, ngModel) {
+ if (!ngModel)
+ return; // do nothing if no ng-model
+ // TODO: Replace the hard-coded form ID by the
+ // appropiate dynamic field
+ scope.catalogForm[attrs.name] = scope.catalogForm['{{field.name}}'];
+ scope.catalogForm[attrs.name].$name = attrs.name;
+ }
+ };
+ });
+
+ app.factory('Catalogs', function($http, $resource) {
+ var CatalogsService = {
+ resources : {
+ application : $resource('/application/:appId', {
+ appId : '@id'
+ }, {
+ update : {
+ method : "PUT"
+ },
+ test: {
+ url: '/application/:appId',
+ method : "DELETE",
+ params : {
+ appId : '@id'
+ }
+ }
+ }),
+ user : $resource('/user/:userId', {
+ userId : '@id'
+ }, {
+ update : {
+ method : "PUT"
+ }
+ }),
+ licensetype : $resource('/licenseType/:licenseTypeId', {
+ licenseTypeId : '@id'
+ }, {
+ update : {
+ method : "PUT"
+ }
+ })
+
+ },
+ list : function(initFn) {
+ $http.get('/js/catalogs.json').success(function(data) {
+ console.log(data);
+ CatalogsService.data = data;
+ initFn();
+ })
+ return CatalogsService;
+ },
+ getName : function(index) {
+ return CatalogsService.data ? CatalogsService.data[index].name
+ : '';
+ },
+ getResource : function(index) {
+ return CatalogsService.data ? CatalogsService.data[index].resource
+ : '';
+ },
+ getMetadata : function(index) {
+ return CatalogsService.data ? CatalogsService.data[index] : {};
+ },
+ save: function(catalog, data) {
+ var resource = CatalogsService.resources[catalog.toLowerCase()];
+ function success(data) {
+ console.log('success')
+ console.log(data)
+ }
+ function fail(data, status) {
+ console.log('error')
+ console.error(data)
+ console.error(status)
+ }
+ if (data.id && data.id !== '')
+ return resource.update(data, success, fail)
+ else
+ return resource.save(data, success, fail)
+ },
+ remove: function(catalog, data) {
+ var resource = CatalogsService.resources[catalog.toLowerCase()];
+ function success(data) {
+ console.log('success')
+ console.log(data)
+ }
+ function fail(data, status) {
+ console.log('error')
+ console.error(data)
+ console.error(status)
+ }
+ return resource.remove({}, data, success, fail)
+ },
+ query: function(catalog, callback) {
+ console.log('HI catalog ???? ' + catalog);
+ var resource = CatalogsService.resources[catalog.toLowerCase()];
+ function success(data) {
+ console.log('success')
+ console.log(data)
+ }
+ function fail(data, status) {
+ console.log('error')
+ console.error(data)
+ console.error(status)
+ }
+ return resource.query({}, success, fail);
+ }
+ }
+
+ return CatalogsService;
+
+ });
+
+ app.controller('CatalogsCtrl', [
+ '$scope',
+ '$http',
+ 'Catalogs',
+ function($scope, $http, Catalogs) {
+ $scope.formu = {};
+ $scope.catalogIndex = 0;
+ $scope.catalogs = Catalogs.list(function() {
+ $scope.catalogMetadata = Catalogs.getMetadata($scope.catalogIndex);
+ $scope.list = Catalogs.query(Catalogs.getResource($scope.catalogIndex));
+ });
+
+ $scope.catalogMetadata = {};
+ $scope.selectCatalog = function(index, $event) {
+ $scope.catalogIndex = index;
+ $scope.catalogMetadata = Catalogs.getMetadata($scope.catalogIndex);
+ $scope.list = Catalogs.query(Catalogs.getResource($scope.catalogIndex));
+ console.log($event);
+ }
+ $scope.edit = function(data) {
+ $scope.showForm = true;
+ $scope.isNew = false;
+ for (var k in data) {
+ if (k.indexOf('$') !== 0) $scope.formu[k] = data[k]
+ }
+ // TODO: Load in formu values for Form
+ // $scope.formu = {};
+ }
+ $scope.delete = function(data) {
+ BootstrapDialog.confirm('The record will be deleted, are you sure?', function(result){
+ if(result) {
+ var catalogName = Catalogs.getResource($scope.catalogIndex);
+ var promise = Catalogs.remove(catalogName, data).$promise;
+ promise.then(function(data) {
+ $scope.list = Catalogs.query(catalogName);
+ });
+ }
+ });
+ $scope.showForm = false;
+ $scope.isNew = false;
+ // TODO: Load in formu values for Form
+ // $scope.formu = {};
+ }
+
+ } ]);
+
+ app.controller('CatalogFormCtrl', [ '$scope', '$http', 'Catalogs',
+ function($scope, $http, Catalogs) {
+ $scope.showForm = false;
+ $scope.scope = $scope;
+ console.log('Form: currentCatalog:' + $scope.cataLogIndex);
+
+ $scope.editNew = function() {
+ $scope.showForm = true;
+ $scope.isNew = true;
+ // $scope.formu = {};
+ }
+ $scope.cancel = function() {
+ $scope.showForm = false;
+ }
+
+ $scope.saveCatalog = function() {
+ if ($scope.catalogForm.$invalid) {
+ alert(JSON.stringify($scope.catalogForm))
+ } else {
+ var catalogName = Catalogs.getResource($scope.catalogIndex);
+ var promise = Catalogs.save(catalogName, $scope.formu).$promise;
+ promise.then(function(data) {
+ $scope.$parent.list = Catalogs.query(catalogName);
+ });
+ }
+ }
+ } ]);
+
+ app.controller('CatalogListCtrl', [ '$scope', '$http', '$filter', 'Catalogs',
+ function($scope, $http, $filter, Catalogs) {
+ console.log('List: currentCatalog: ' + $scope.currentCatalog);
+ var _indexOfField = function(name) {
+ if (!$scope.catalogMetadata) return -1;
+ for (var i = $scope.catalogMetadata.fields.length - 1; i >= 0 && $scope.catalogMetadata.fields[i].name !== name; i--);
+ return i;
+ }
+
+ $scope.print = function(name, value) {
+ var index = _indexOfField(name);
+ if (index === -1) return value;
+ var type = $scope.catalogMetadata.fields[index].type;
+
+ return type === 'date' ? $filter('date')(value, 'yyyy-MM-dd') : value;
+ }
+
+ $scope.display = function(name) {
+ var index = _indexOfField(name);
+ return index === -1 ? '' : $scope.catalogMetadata.fields[index].display;
+ }
+
+ } ]);
+
+})();
diff --git a/securis/src/main/resources/static/js/toaster.js b/securis/src/main/resources/static/js/toaster.js
new file mode 100644
index 0000000..e5127d0
--- /dev/null
+++ b/securis/src/main/resources/static/js/toaster.js
@@ -0,0 +1,145 @@
+'use strict';
+
+/*
+ * AngularJS Toaster
+ * Version: 0.4.1
+ *
+ * Copyright 2013 Jiri Kavulak.
+ * All Rights Reserved.
+ * Use, reproduction, distribution, and modification of this code is subject to the terms and
+ * conditions of the MIT license, available at http://www.opensource.org/licenses/mit-license.php
+ *
+ * Author: Jiri Kavulak
+ * Related to project of John Papa and Hans Fjällemark
+ */
+
+angular.module('toaster', ['ngAnimate'])
+.service('toaster', ['$rootScope', function ($rootScope) {
+ this.pop = function (type, title, body, timeout, bodyOutputType) {
+ this.toast = {
+ type: type,
+ title: title,
+ body: body,
+ timeout: timeout,
+ bodyOutputType: bodyOutputType
+ };
+ $rootScope.$broadcast('toaster-newToast');
+ };
+}])
+.constant('toasterConfig', {
+ 'tap-to-dismiss': true,
+ 'newest-on-top': true,
+ //'fade-in': 1000, // done in css
+ //'on-fade-in': undefined, // not implemented
+ //'fade-out': 1000, // done in css
+ // 'on-fade-out': undefined, // not implemented
+ //'extended-time-out': 1000, // not implemented
+ 'time-out': 5000, // Set timeOut and extendedTimeout to 0 to make it sticky
+ 'icon-classes': {
+ error: 'toast-error',
+ info: 'toast-info',
+ success: 'toast-success',
+ warning: 'toast-warning'
+ },
+ 'body-output-type': '', // Options: '', 'trustedHtml', 'template'
+ 'body-template': 'toasterBodyTmpl.html',
+ 'icon-class': 'toast-info',
+ 'position-class': 'toast-top-right',
+ 'title-class': 'toast-title',
+ 'message-class': 'toast-message'
+ })
+.directive('toasterContainer', ['$compile', '$timeout', '$sce', 'toasterConfig', 'toaster',
+function ($compile, $timeout, $sce, toasterConfig, toaster) {
+ return {
+ replace: true,
+ restrict: 'EA',
+ link: function (scope, elm, attrs){
+
+ var id = 0;
+
+ var mergedConfig = toasterConfig;
+ if (attrs.toasterOptions) {
+ angular.extend(mergedConfig, scope.$eval(attrs.toasterOptions));
+ }
+
+ scope.config = {
+ position: mergedConfig['position-class'],
+ title: mergedConfig['title-class'],
+ message: mergedConfig['message-class'],
+ tap: mergedConfig['tap-to-dismiss']
+ };
+
+ function addToast (toast){
+ toast.type = mergedConfig['icon-classes'][toast.type];
+ if (!toast.type)
+ toast.type = mergedConfig['icon-class'];
+
+ id++;
+ angular.extend(toast, { id: id });
+
+ switch(toast.bodyOutputType)
+ {
+ case 'trustedHtml':
+ toast.html = $sce.trustAsHtml(toast.body);
+ break;
+ case 'template':
+ toast.bodyTemplate = mergedConfig['body-template'];
+ break;
+ }
+
+ var timeout = typeof(toast.timeout) == "number" ? toast.timeout : mergedConfig['time-out'];
+ if (timeout > 0)
+ setTimeout(toast, timeout);
+
+ if (mergedConfig['newest-on-top'] === true)
+ scope.toasters.unshift(toast);
+ else
+ scope.toasters.push(toast);
+ }
+
+ function setTimeout(toast, time){
+ toast.timeout= $timeout(function (){
+ scope.removeToast(toast.id);
+ }, time);
+ }
+
+ scope.toasters = [];
+ scope.$on('toaster-newToast', function () {
+ addToast(toaster.toast);
+ });
+ },
+ controller: ['$scope', '$element', '$attrs', function($scope, $element, $attrs) {
+
+ $scope.stopTimer = function(toast){
+ if(toast.timeout)
+ $timeout.cancel(toast.timeout);
+ };
+
+ $scope.removeToast = function (id){
+ var i = 0;
+ for (i; i < $scope.toasters.length; i++){
+ if($scope.toasters[i].id === id)
+ break;
+ }
+ $scope.toasters.splice(i, 1);
+ };
+
+ $scope.remove = function(id){
+ if ($scope.config.tap === true){
+ $scope.removeToast(id);
+ }
+ };
+ }],
+ template:
+ '<div id="toast-container" ng-class="config.position">' +
+ '<div ng-repeat="toaster in toasters" class="toast" ng-class="toaster.type" ng-click="remove(toaster.id)" ng-mouseover="stopTimer(toaster)">' +
+ '<div ng-class="config.title">{{toaster.title}}</div>' +
+ '<div ng-class="config.message" ng-switch on="toaster.bodyOutputType">' +
+ '<div ng-switch-when="trustedHtml" ng-bind-html="toaster.html"></div>' +
+ '<div ng-switch-when="template"><div ng-include="toaster.bodyTemplate"></div></div>' +
+ '<div ng-switch-default >{{toaster.body}}</div>' +
+ '</div>' +
+ '</div>' +
+ '</div>'
+ };
+}]);
--
Gitblit v1.3.2