(css,js) Improve progress feedback
This ads a "ripple" effect that blocks the context when login in or sending a message. Generic enough to be used elsewhere. Fixes #3765pull/216/merge
parent
0fe472b5e9
commit
6bbb56c386
6
NEWS
6
NEWS
|
@ -1,3 +1,9 @@
|
||||||
|
3.1.5 (2016-MM-DD)
|
||||||
|
------------------
|
||||||
|
|
||||||
|
Enhancements
|
||||||
|
- [web] improve action progress when login in or sending a message (#3765, #3761)
|
||||||
|
|
||||||
3.1.4 (2016-07-12)
|
3.1.4 (2016-07-12)
|
||||||
------------------
|
------------------
|
||||||
|
|
||||||
|
|
|
@ -305,7 +305,12 @@
|
||||||
"Error while uploading the file \"%{0}\":" = "Error while uploading the file \"%{0}\":";
|
"Error while uploading the file \"%{0}\":" = "Error while uploading the file \"%{0}\":";
|
||||||
"There is an active file upload. Closing the window will interrupt it." = "There is an active file upload. Closing the window will interrupt it.";
|
"There is an active file upload. Closing the window will interrupt it." = "There is an active file upload. Closing the window will interrupt it.";
|
||||||
|
|
||||||
/* Message sending */
|
/* Appears while sending the message */
|
||||||
|
"Sending" = "Sending";
|
||||||
|
|
||||||
|
/* Appears when the message is successfuly sent */
|
||||||
|
"Sent" = "Sent";
|
||||||
|
|
||||||
"cannot send message: (smtp) all recipients discarded" = "Cannot send message: all recipients are invalid.";
|
"cannot send message: (smtp) all recipients discarded" = "Cannot send message: all recipients are invalid.";
|
||||||
"cannot send message (smtp) - recipients discarded" = "Cannot send message. The following addresses are invalid";
|
"cannot send message (smtp) - recipients discarded" = "Cannot send message. The following addresses are invalid";
|
||||||
"cannot send message: (smtp) error when connecting" = "Cannot send message: error when connecting to the SMTP server.";
|
"cannot send message: (smtp) error when connecting" = "Cannot send message: error when connecting to the SMTP server.";
|
||||||
|
|
|
@ -6,6 +6,13 @@
|
||||||
"Domain" = "Domain";
|
"Domain" = "Domain";
|
||||||
"Remember username" = "Remember username";
|
"Remember username" = "Remember username";
|
||||||
"Connect" = "Connect";
|
"Connect" = "Connect";
|
||||||
|
|
||||||
|
/* Appears while authentication is in progress */
|
||||||
|
"Authenticating" = "Authenticating";
|
||||||
|
|
||||||
|
/* Appears when authentication succeeds */
|
||||||
|
"Success" = "Success";
|
||||||
|
|
||||||
"Authentication Failed" = "Authentication Failed";
|
"Authentication Failed" = "Authentication Failed";
|
||||||
"Wrong username or password." = "Wrong username or password.";
|
"Wrong username or password." = "Wrong username or password.";
|
||||||
"cookiesNotEnabled" = "You cannot login because your browser's cookies are disabled. Please enable cookies in your browser's settings and try again.";
|
"cookiesNotEnabled" = "You cannot login because your browser's cookies are disabled. Please enable cookies in your browser's settings and try again.";
|
||||||
|
|
|
@ -5,7 +5,7 @@
|
||||||
xmlns:const="http://www.skyrix.com/od/constant"
|
xmlns:const="http://www.skyrix.com/od/constant"
|
||||||
xmlns:label="OGo:label">
|
xmlns:label="OGo:label">
|
||||||
|
|
||||||
<md-dialog class="sg-mail-editor" flex="80" flex-sm="90" flex-xs="100"
|
<md-dialog id="mailEditor" class="sg-mail-editor" flex="80" flex-sm="90" flex-xs="100"
|
||||||
nv-file-drop="nv-file-drop"
|
nv-file-drop="nv-file-drop"
|
||||||
nv-file-over="nv-file-over"
|
nv-file-over="nv-file-over"
|
||||||
over-class="sg-over-dropzone"
|
over-class="sg-over-dropzone"
|
||||||
|
@ -26,7 +26,8 @@
|
||||||
</md-input-container>
|
</md-input-container>
|
||||||
<div flex="flex"><!-- spacer --></div>
|
<div flex="flex"><!-- spacer --></div>
|
||||||
<md-button class="sg-icon-button" ng-click="editor.send()"
|
<md-button class="sg-icon-button" ng-click="editor.send()"
|
||||||
ng-disabled="!(editor.message.editable.to.length > 0 || editor.message.editable.cc.length > 0 || editor.message.editable.bcc.length > 0) || messageForm.$invalid">
|
ng-disabled="!(editor.message.editable.to.length > 0 || editor.message.editable.cc.length > 0 || editor.message.editable.bcc.length > 0) || editor.uploader.isUploading || messageForm.$invalid"
|
||||||
|
sg-ripple-click="mailEditor">
|
||||||
<md-icon>send</md-icon>
|
<md-icon>send</md-icon>
|
||||||
</md-button>
|
</md-button>
|
||||||
<md-button class="sg-icon-button" ng-click="editor.save()">
|
<md-button class="sg-icon-button" ng-click="editor.save()">
|
||||||
|
@ -254,5 +255,43 @@
|
||||||
</div>
|
</div>
|
||||||
</md-dialog-actions>
|
</md-dialog-actions>
|
||||||
</form>
|
</form>
|
||||||
|
<sg-ripple class="md-default-theme md-accent md-bg"
|
||||||
|
ng-class="{ 'md-warn': editor.sendState == 'error' }"><!-- ripple background --></sg-ripple>
|
||||||
|
<sg-ripple-content class="md-default-theme md-accent md-hue-1 md-fg md-flex ng-hide"
|
||||||
|
layout="column" layout-align="center center" layout-fill="layout-fill"
|
||||||
|
ng-switch="editor.sendState">
|
||||||
|
|
||||||
|
<!-- Sending -->
|
||||||
|
<div layout="column" layout-align="center center"
|
||||||
|
ng-switch-when="sending">
|
||||||
|
<md-progress-circular class="md-hue-1"
|
||||||
|
md-mode="indeterminate"
|
||||||
|
md-diameter="48"><!-- mailbox loading progress --></md-progress-circular>
|
||||||
|
<div class="md-padding">
|
||||||
|
<var:string label:value="Sending"/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Sent -->
|
||||||
|
<div layout="column" layout-align="center center"
|
||||||
|
ng-switch-when="sent">
|
||||||
|
<md-icon class="md-accent md-hue-1 sg-icon--large">done</md-icon>
|
||||||
|
<div class="md-default-theme md-accent md-hue-1 md-fg md-padding">
|
||||||
|
<var:string label:value="Sent"/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Error -->
|
||||||
|
<div layout="column" layout-align="center center"
|
||||||
|
ng-switch-when="error">
|
||||||
|
<md-icon class="md-accent md-hue-1 sg-icon--large">error</md-icon>
|
||||||
|
<div class="md-padding">
|
||||||
|
{{editor.errorMessage}}
|
||||||
|
</div>
|
||||||
|
<md-button sg-ripple-click="mailEditor"><var:string label:value="Close"/></md-button>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</sg-ripple-content>
|
||||||
|
|
||||||
</md-dialog>
|
</md-dialog>
|
||||||
</container>
|
</container>
|
||||||
|
|
|
@ -9,30 +9,31 @@
|
||||||
xmlns:label="OGo:label"
|
xmlns:label="OGo:label"
|
||||||
const:jsFiles="Main.js, Common.js"
|
const:jsFiles="Main.js, Common.js"
|
||||||
>
|
>
|
||||||
|
<script type="text/javascript">
|
||||||
|
var cookieUsername = '<var:string var:value="cookieUsername" const:escapeHTML="NO"/>';
|
||||||
|
</script>
|
||||||
|
|
||||||
<!--
|
<!--
|
||||||
MAIN CONTENT ROW
|
MAIN CONTENT ROW
|
||||||
Content of the application view injected injected in the element bellow
|
Content of the application view injected injected in the element bellow
|
||||||
MUST be the first html element after body
|
MUST be the first html element after body
|
||||||
SHOULD be a main tag (with role="main")
|
SHOULD be a main tag (with role="main")
|
||||||
-->
|
-->
|
||||||
<main class="view layout-padding md-default-theme md-background md-hue-1 md-bg"
|
<main class="view md-default-theme md-background md-hue-1 md-bg"
|
||||||
layout="row" layout-align="center start" layout-fill="layout-fill"
|
layout-gt-md="row" layout-align-gt-md="center start" layout-fill="layout-fill"
|
||||||
ui-view="login"
|
ui-view="login"
|
||||||
ng-controller="LoginController as app">
|
ng-controller="LoginController as app">
|
||||||
<md-content class="ng-cloak md-whiteframe-z1"
|
<md-content id="loginContent" class="ng-cloak md-whiteframe-3dp" flex="100"
|
||||||
layout-gt-md="row" layout-align-gt-md="start center"
|
layout="column" layout-gt-md="row" layout-align="start stretch"
|
||||||
layout="column" layout-align="space-between center"
|
|
||||||
md-scroll-y="true"
|
|
||||||
ng-show="app.showLogin">
|
ng-show="app.showLogin">
|
||||||
<div id="logo" class="md-padding">
|
<div class="sg-logo" flex-gt-md="50">
|
||||||
<img const:alt="*" id="splash" rsrc:src="img/sogo-full.svg"/>
|
<div layout="row" class="md-padding">
|
||||||
|
<div class="md-flex hide show-gt-md"><!-- push logo to the right on larger screens --></div>
|
||||||
|
<img const:alt="*" class="md-margin" rsrc:src="img/sogo-full.svg"/>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="sg-login md-padding md-default-theme md-bg md-accent">
|
<div class="sg-login md-default-theme md-bg md-accent" flex-gt-md="50">
|
||||||
<script type="text/javascript">
|
<div id="login" class="sg-login-content md-padding">
|
||||||
var cookieUsername = '<var:string var:value="cookieUsername" const:escapeHTML="NO"/>';
|
|
||||||
</script>
|
|
||||||
<div id="login">
|
|
||||||
|
|
||||||
<form name="loginForm" layout="column"
|
<form name="loginForm" layout="column"
|
||||||
ng-cloak="ng-cloak"
|
ng-cloak="ng-cloak"
|
||||||
ng-submit="app.login()">
|
ng-submit="app.login()">
|
||||||
|
@ -52,7 +53,7 @@
|
||||||
|
|
||||||
<!-- CONNECT BUTTON -->
|
<!-- CONNECT BUTTON -->
|
||||||
<div layout="row" layout-align="end center">
|
<div layout="row" layout-align="end center">
|
||||||
<md-button class="md-raised md-accent md-hue-2" type="submit" ng-disabled='app.loginForm.$invalid'>
|
<md-button type="submit" ng-disabled='app.loginForm.$invalid' sg-ripple-click="loginContent">
|
||||||
<var:string label:value="Connect"/>
|
<var:string label:value="Connect"/>
|
||||||
</md-button>
|
</md-button>
|
||||||
</div>
|
</div>
|
||||||
|
@ -101,6 +102,43 @@
|
||||||
<md-icon class="md-fg">info</md-icon>
|
<md-icon class="md-fg">info</md-icon>
|
||||||
</md-button>
|
</md-button>
|
||||||
</div>
|
</div>
|
||||||
|
<sg-ripple class="md-default-theme md-accent md-bg"
|
||||||
|
ng-class="{ 'md-warn': app.loginState == 'error' }"><!-- ripple background --></sg-ripple>
|
||||||
|
<sg-ripple-content class="md-flex ng-hide"
|
||||||
|
layout="column" layout-align="center center" layout-fill="layout-fill"
|
||||||
|
ng-switch="app.loginState">
|
||||||
|
|
||||||
|
<!-- Authenticating -->
|
||||||
|
<div layout="column" layout-align="center center"
|
||||||
|
ng-switch-when="authenticating">
|
||||||
|
<md-progress-circular class="md-hue-1"
|
||||||
|
md-mode="indeterminate"
|
||||||
|
md-diameter="32"><!-- mailbox loading progress --></md-progress-circular>
|
||||||
|
<div class="md-default-theme md-accent md-hue-1 md-fg md-padding">
|
||||||
|
<var:string label:value="Authenticating"/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Logged in -->
|
||||||
|
<div layout="column" layout-align="center center"
|
||||||
|
ng-switch-when="logged">
|
||||||
|
<md-icon class="md-accent md-hue-1 sg-icon--large">done</md-icon>
|
||||||
|
<div class="md-default-theme md-accent md-hue-1 md-fg md-padding">
|
||||||
|
<var:string label:value="Success"/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Error -->
|
||||||
|
<div layout="column" layout-align="center center"
|
||||||
|
ng-switch-when="error">
|
||||||
|
<md-icon class="md-accent md-hue-1 sg-icon--large">error</md-icon>
|
||||||
|
<div class="md-default-theme md-accent md-hue-1 md-fg md-padding">
|
||||||
|
{{app.errorMessage}}
|
||||||
|
</div>
|
||||||
|
<md-button sg-ripple-click="loginContent"><var:string label:value="Retry"/></md-button>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</sg-ripple-content>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</md-content>
|
</md-content>
|
||||||
|
|
|
@ -0,0 +1,108 @@
|
||||||
|
/* -*- Mode: javascript; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||||
|
|
||||||
|
(function() {
|
||||||
|
'use strict';
|
||||||
|
|
||||||
|
angular
|
||||||
|
.module('SOGo.Common')
|
||||||
|
.directive('sgRippleClick', sgRippleClick);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* sgRippleClick - A ripple effect to cover the parent element.
|
||||||
|
* @memberof SOGo.Common
|
||||||
|
* @restrict attribute
|
||||||
|
*
|
||||||
|
* @example:
|
||||||
|
|
||||||
|
<md-dialog id="mailEditor">
|
||||||
|
<md-button ng-click="editor.send()"
|
||||||
|
sg-ripple-click="mailEditor">Send</md-button>
|
||||||
|
</md-dialog>
|
||||||
|
|
||||||
|
*/
|
||||||
|
sgRippleClick.$inject = ['$log', '$timeout'];
|
||||||
|
function sgRippleClick($log, $timeout) {
|
||||||
|
|
||||||
|
return {
|
||||||
|
restrict: 'A',
|
||||||
|
compile: compile
|
||||||
|
};
|
||||||
|
|
||||||
|
function compile(tElement, tAttrs) {
|
||||||
|
|
||||||
|
return function postLink(scope, element, attr) {
|
||||||
|
var ripple, content, container, containerId;
|
||||||
|
|
||||||
|
// Lookup container element
|
||||||
|
containerId = element.attr('sg-ripple-click');
|
||||||
|
container = element[0].parentNode;
|
||||||
|
while (container && container.id != containerId) {
|
||||||
|
container = container.parentNode;
|
||||||
|
}
|
||||||
|
if (!container) {
|
||||||
|
$log.error('No parent element found with id ' + containerId);
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Lookup sg-ripple-content element
|
||||||
|
content = container.querySelector('sg-ripple-content');
|
||||||
|
if (!content) {
|
||||||
|
$log.error('sg-ripple-content not found inside #' + containerId);
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Lookup sg-ripple element
|
||||||
|
ripple = container.querySelector('sg-ripple');
|
||||||
|
if (ripple) {
|
||||||
|
ripple = angular.element(ripple);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
// If ripple layer doesn't exit, create it with the primary background color
|
||||||
|
ripple = angular.element('<sg-ripple class="md-default-theme md-bg"></sg-ripple>');
|
||||||
|
container.appendChild(ripple[0]);
|
||||||
|
|
||||||
|
// Hide ripple content on initialization
|
||||||
|
if (!content.classList.contains('ng-hide'))
|
||||||
|
content.classList.add('ng-hide');
|
||||||
|
}
|
||||||
|
|
||||||
|
// Register listener
|
||||||
|
element.on('click', listener);
|
||||||
|
|
||||||
|
function listener(event) {
|
||||||
|
if (element[0].hasAttribute('disabled')) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (content.classList.contains('ng-hide')) {
|
||||||
|
// Show ripple
|
||||||
|
angular.element(container).css({ 'overflow': 'hidden' });
|
||||||
|
content.classList.remove('ng-hide');
|
||||||
|
angular.element(content).css({ top: container.scrollTop + 'px' });
|
||||||
|
ripple.css({
|
||||||
|
'top': (event.pageY - container.offsetTop + container.scrollTop) + 'px',
|
||||||
|
'left': (event.pageX - container.offsetLeft) + 'px',
|
||||||
|
'width': '400vmin',
|
||||||
|
'height': '400vmin'
|
||||||
|
});
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
// Hide ripple layer
|
||||||
|
ripple.css({
|
||||||
|
'top': (event.pageY - container.offsetTop + container.scrollTop) + 'px',
|
||||||
|
'left': (event.pageX - container.offsetLeft) + 'px',
|
||||||
|
'height': '0px',
|
||||||
|
'width': '0px'
|
||||||
|
});
|
||||||
|
// Hide ripple content
|
||||||
|
content.classList.add('ng-hide');
|
||||||
|
// Restore overflow of container once the animation is completed
|
||||||
|
$timeout(function() {
|
||||||
|
angular.element(container).css({ 'overflow': '' });
|
||||||
|
}, 800);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})();
|
|
@ -636,18 +636,18 @@
|
||||||
|
|
||||||
Message.$log.debug('send = ' + JSON.stringify(data, undefined, 2));
|
Message.$log.debug('send = ' + JSON.stringify(data, undefined, 2));
|
||||||
|
|
||||||
return Message.$$resource.post(this.$absolutePath({asDraft: true}), 'send', data).then(function(data) {
|
return Message.$$resource.post(this.$absolutePath({asDraft: true}), 'send', data).then(function(response) {
|
||||||
if (data.status == 'success') {
|
if (response.status == 'success') {
|
||||||
if (angular.isDefined(_this.origin)) {
|
if (angular.isDefined(_this.origin)) {
|
||||||
if (_this.origin.action.startsWith('reply'))
|
if (_this.origin.action.startsWith('reply'))
|
||||||
_this.origin.message.isanswered = true;
|
_this.origin.message.isanswered = true;
|
||||||
else if (_this.origin.action == 'forward')
|
else if (_this.origin.action == 'forward')
|
||||||
_this.origin.message.isforwarded = true;
|
_this.origin.message.isforwarded = true;
|
||||||
}
|
}
|
||||||
return data;
|
return response;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
return Message.$q.reject(data);
|
return Message.$q.reject(response.data);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
|
@ -6,9 +6,9 @@
|
||||||
/**
|
/**
|
||||||
* @ngInject
|
* @ngInject
|
||||||
*/
|
*/
|
||||||
MessageEditorController.$inject = ['$window', '$stateParams', '$mdConstant', '$mdDialog', '$mdToast', 'FileUploader', 'stateAccount', 'stateMessage', 'encodeUriFilter', '$timeout', 'Dialog', 'AddressBook', 'Card', 'Preferences'];
|
MessageEditorController.$inject = ['$scope', '$window', '$stateParams', '$mdConstant', '$mdDialog', '$mdToast', 'FileUploader', 'stateAccount', 'stateMessage', 'encodeUriFilter', '$timeout', 'Dialog', 'AddressBook', 'Card', 'Preferences'];
|
||||||
function MessageEditorController($window, $stateParams, $mdConstant, $mdDialog, $mdToast, FileUploader, stateAccount, stateMessage, encodeUriFilter, $timeout, Dialog, AddressBook, Card, Preferences) {
|
function MessageEditorController($scope, $window, $stateParams, $mdConstant, $mdDialog, $mdToast, FileUploader, stateAccount, stateMessage, encodeUriFilter, $timeout, Dialog, AddressBook, Card, Preferences) {
|
||||||
var vm = this, semicolon = 186;
|
var vm = this;
|
||||||
|
|
||||||
vm.addRecipient = addRecipient;
|
vm.addRecipient = addRecipient;
|
||||||
vm.autocomplete = {to: {}, cc: {}, bcc: {}};
|
vm.autocomplete = {to: {}, cc: {}, bcc: {}};
|
||||||
|
@ -19,10 +19,16 @@
|
||||||
vm.cancel = cancel;
|
vm.cancel = cancel;
|
||||||
vm.save = save;
|
vm.save = save;
|
||||||
vm.send = send;
|
vm.send = send;
|
||||||
|
vm.sendState = false;
|
||||||
vm.removeAttachment = removeAttachment;
|
vm.removeAttachment = removeAttachment;
|
||||||
vm.contactFilter = contactFilter;
|
vm.contactFilter = contactFilter;
|
||||||
vm.identities = _.map(stateAccount.identities, 'full');
|
vm.identities = _.map(stateAccount.identities, 'full');
|
||||||
vm.recipientSeparatorKeys = [$mdConstant.KEY_CODE.ENTER, $mdConstant.KEY_CODE.TAB, $mdConstant.KEY_CODE.COMMA, semicolon];
|
vm.recipientSeparatorKeys = [
|
||||||
|
$mdConstant.KEY_CODE.ENTER,
|
||||||
|
$mdConstant.KEY_CODE.TAB,
|
||||||
|
$mdConstant.KEY_CODE.COMMA,
|
||||||
|
$mdConstant.KEY_CODE.SEMICOLON
|
||||||
|
];
|
||||||
vm.uploader = new FileUploader({
|
vm.uploader = new FileUploader({
|
||||||
url: stateMessage.$absolutePath({asDraft: true}) + '/save',
|
url: stateMessage.$absolutePath({asDraft: true}) + '/save',
|
||||||
autoUpload: true,
|
autoUpload: true,
|
||||||
|
@ -54,6 +60,9 @@
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// Destroy file uploader when the controller is being deactivated
|
||||||
|
$scope.$on('$destroy', function() { vm.uploader.destroy(); });
|
||||||
|
|
||||||
if ($stateParams.actionName == 'reply') {
|
if ($stateParams.actionName == 'reply') {
|
||||||
stateMessage.$reply().then(function(msgObject) {
|
stateMessage.$reply().then(function(msgObject) {
|
||||||
vm.message = msgObject;
|
vm.message = msgObject;
|
||||||
|
@ -168,10 +177,13 @@
|
||||||
|
|
||||||
function send() {
|
function send() {
|
||||||
var ctrls = $parentControllers();
|
var ctrls = $parentControllers();
|
||||||
|
|
||||||
|
vm.sendState = 'sending';
|
||||||
if (vm.autosave)
|
if (vm.autosave)
|
||||||
$timeout.cancel(vm.autosave);
|
$timeout.cancel(vm.autosave);
|
||||||
|
|
||||||
vm.message.$send().then(function(data) {
|
vm.message.$send().then(function(data) {
|
||||||
|
vm.sendState = 'sent';
|
||||||
if (ctrls.draftMailboxCtrl) {
|
if (ctrls.draftMailboxCtrl) {
|
||||||
// We're sending a draft from a popup window and the draft mailbox is opened.
|
// We're sending a draft from a popup window and the draft mailbox is opened.
|
||||||
// Reload draft mailbox
|
// Reload draft mailbox
|
||||||
|
@ -192,7 +204,12 @@
|
||||||
.content(l('Your email has been sent'))
|
.content(l('Your email has been sent'))
|
||||||
.position('top right')
|
.position('top right')
|
||||||
.hideDelay(3000));
|
.hideDelay(3000));
|
||||||
$mdDialog.hide();
|
|
||||||
|
// Let the user see the succesfull message before closing the dialog
|
||||||
|
$timeout($mdDialog.hide, 1000);
|
||||||
|
}, function(response) {
|
||||||
|
vm.sendState = 'error';
|
||||||
|
vm.errorMessage = response.data? response.data.message : response.statusText;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -15,20 +15,29 @@
|
||||||
|
|
||||||
vm.creds = { username: cookieUsername, password: null };
|
vm.creds = { username: cookieUsername, password: null };
|
||||||
vm.login = login;
|
vm.login = login;
|
||||||
|
vm.loginState = false;
|
||||||
vm.showAbout = showAbout;
|
vm.showAbout = showAbout;
|
||||||
|
|
||||||
|
// Show login once everything is initialized
|
||||||
vm.showLogin = false;
|
vm.showLogin = false;
|
||||||
$timeout(function() { vm.showLogin = true; }, 100);
|
$timeout(function() { vm.showLogin = true; }, 100);
|
||||||
|
|
||||||
function login() {
|
function login() {
|
||||||
|
vm.loginState = 'authenticating';
|
||||||
Authentication.login(vm.creds)
|
Authentication.login(vm.creds)
|
||||||
.then(function(url) {
|
.then(function(url) {
|
||||||
if (window.location.href === url)
|
vm.loginState = 'logged';
|
||||||
window.location.reload(true);
|
|
||||||
else
|
// Let the user see the succesfull message before reloading the page
|
||||||
window.location.href = url;
|
$timeout(function() {
|
||||||
|
if (window.location.href === url)
|
||||||
|
window.location.reload(true);
|
||||||
|
else
|
||||||
|
window.location.href = url;
|
||||||
|
}, 1000);
|
||||||
}, function(msg) {
|
}, function(msg) {
|
||||||
Dialog.alert(l('Authentication Failed'), msg.error);
|
vm.loginState = 'error';
|
||||||
|
vm.errorMessage = msg.error;
|
||||||
});
|
});
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,21 @@
|
||||||
|
/// ripple.scss -*- Mode: scss; indent-tabs-mode: nil; basic-offset: 2 -*-
|
||||||
|
|
||||||
|
sg-ripple {
|
||||||
|
border-radius: 100%;
|
||||||
|
height: 0px;
|
||||||
|
width: 0px;
|
||||||
|
position: absolute;
|
||||||
|
transition: width 800ms linear, height 800ms linear, background-color 400ms linear;
|
||||||
|
transform: translate(-50%, -50%);
|
||||||
|
opacity: 1;
|
||||||
|
z-index: $z-index-toolbar + 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
sg-ripple-content {
|
||||||
|
bottom: 0;
|
||||||
|
left: 0;
|
||||||
|
position: absolute;
|
||||||
|
right: 0;
|
||||||
|
top: 0;
|
||||||
|
z-index: $z-index-toolbar + 2;
|
||||||
|
}
|
|
@ -29,16 +29,6 @@ html * {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.sg-logo {
|
|
||||||
background-image: url("../img/sogo-full.svg");
|
|
||||||
background-size: contain;
|
|
||||||
background-repeat: no-repeat;
|
|
||||||
height: 7 * $bl;
|
|
||||||
min-width: 18 * $bl;
|
|
||||||
//optical adjustement
|
|
||||||
transform: translateY(-10%);
|
|
||||||
}
|
|
||||||
|
|
||||||
.sg-category {
|
.sg-category {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
top: 0;
|
top: 0;
|
||||||
|
|
|
@ -66,6 +66,7 @@
|
||||||
@import 'components/whiteframe/whiteframe';
|
@import 'components/whiteframe/whiteframe';
|
||||||
|
|
||||||
// Inverse components
|
// Inverse components
|
||||||
|
@import 'components/ripple/ripple';
|
||||||
@import 'components/timepicker/timepicker';
|
@import 'components/timepicker/timepicker';
|
||||||
|
|
||||||
// @import '../angular-material/src/core/style/color-palette';
|
// @import '../angular-material/src/core/style/color-palette';
|
||||||
|
|
|
@ -1,46 +1,76 @@
|
||||||
/// LoginUI.scss -*- Mode: scss; indent-tabs-mode: nil; basic-offset: 2 -*-
|
/// LoginUI.scss -*- Mode: scss; indent-tabs-mode: nil; basic-offset: 2 -*-
|
||||||
|
|
||||||
|
$sg-login-width: grid-step(5);
|
||||||
|
|
||||||
[ui-view="login"] {
|
[ui-view="login"] {
|
||||||
md-content {
|
md-content {
|
||||||
padding: 0;
|
// Keep content centered
|
||||||
@include to(sm) {
|
margin: auto;
|
||||||
[id=logo] {
|
|
||||||
text-align: center;
|
.sg-logo img {
|
||||||
|
width: grid-step(5);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* On small screens, we dispose the logo and login form as column.
|
||||||
|
*/
|
||||||
|
@include to(md) {
|
||||||
|
& {
|
||||||
|
// Fill the screen
|
||||||
|
min-height: 100%;
|
||||||
|
}
|
||||||
|
.sg-logo {
|
||||||
|
// Center content
|
||||||
|
margin: auto;
|
||||||
img {
|
img {
|
||||||
|
margin: auto;
|
||||||
|
height: 100%;
|
||||||
max-width: 75%;
|
max-width: 75%;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
.sg-login {
|
||||||
|
// Let the form take all available space
|
||||||
|
flex-grow: 1;
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
.sg-login-content {
|
||||||
|
margin: auto;
|
||||||
|
max-width: $sg-login-width;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@include from(sm) {
|
|
||||||
|
/**
|
||||||
|
* On larger screen, we dispose the logo and login form as a row.
|
||||||
|
*/
|
||||||
|
@include from(md) {
|
||||||
&.ng-hide {
|
&.ng-hide {
|
||||||
[id=logo] {
|
.sg-logo img {
|
||||||
opacity: 0;
|
opacity: 0;
|
||||||
transform: translateX(50%);
|
transform: translateX($sg-login-width/2 + $baseline-grid + $baseline-grid*2);
|
||||||
}
|
}
|
||||||
.sg-login {
|
.sg-login {
|
||||||
opacity: 0;
|
opacity: 0;
|
||||||
transform: translateX(100%);
|
transform: translateX(100%);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
[id=logo], .sg-login {
|
.sg-logo img, .sg-login {
|
||||||
opacity: 1;
|
opacity: 1;
|
||||||
//transform: translateX(0%);
|
|
||||||
}
|
}
|
||||||
[id=logo] {
|
.sg-logo {
|
||||||
transition: transform $swift-ease-out-duration $swift-ease-out-timing-function 600ms,
|
max-height: 100%;
|
||||||
opacity 400ms linear;
|
max-width: 50%;
|
||||||
|
img {
|
||||||
|
transition: transform $swift-ease-out-duration $swift-ease-out-timing-function 600ms,
|
||||||
|
opacity 400ms linear;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
.sg-login {
|
.sg-login {
|
||||||
|
max-width: 50%;
|
||||||
transition: all $swift-ease-out-duration $swift-ease-out-timing-function 600ms;
|
transition: all $swift-ease-out-duration $swift-ease-out-timing-function 600ms;
|
||||||
}
|
}
|
||||||
}
|
.sg-login-content {
|
||||||
|
width: $sg-login-width;
|
||||||
|
}
|
||||||
|
} // from(md)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
[ui-view="login"] > md-content > div {
|
|
||||||
width: grid-step(5);
|
|
||||||
}
|
|
||||||
|
|
||||||
[id=logo] img {
|
|
||||||
max-width: 100%;
|
|
||||||
}
|
|
||||||
|
|
Loading…
Reference in New Issue