GUAC-932: Add Notification* classes. Clean up related JS.

This commit is contained in:
Michael Jumper
2014-11-30 17:50:21 -08:00
parent 10171ff1ba
commit aab0297d40
8 changed files with 386 additions and 219 deletions

View File

@@ -50,6 +50,21 @@ angular.module('index').controller('indexController', ['$scope', '$injector',
}
};
/**
* The current status notification, or false if no status is currently
* shown.
*
* @type Notification|Boolean
*/
$scope.status = false;
/**
* All currently-visible notifications.
*
* @type Notification[]
*/
$scope.notifications = [];
// Put some useful variables in the top level scope
$scope.page = {
title: '',
@@ -59,7 +74,6 @@ angular.module('index').controller('indexController', ['$scope', '$injector',
$scope.currentUserIsAdmin = false;
$scope.currentUserHasUpdate = false;
$scope.currentUserPermissions = null;
$scope.notifications = [];
var notificationUniqueID = 0;
// A promise to be fulfilled when all basic user permissions are loaded.
@@ -77,41 +91,8 @@ angular.module('index').controller('indexController', ['$scope', '$injector',
* notification is currently shown, no further statuses will be shown
* until the current status is hidden.
*
* @param {Object} status The status notification to show.
* @param {String} [status.title] The title of the notification.
* @param {String} [status.text] The body text of the notification.
* @param {String} [status.className] The CSS class name to apply.
*
* @param {String} [status.countdown.text]
* In the case that a countdown applies to the notification, the text to
* display while the countdown is active.
*
* @param {Function} [status.countdown.callback]
* The callback to call when the countdown expires.
*
* @param {String} [status.countdown.remaining]
* The number of seconds remaining before the countdown callback is
* called.
*
* @param {String} [status.progress.text]
* If this notification has associated progress, the text to display
* while the operation is occurring.
*
* @param {String} [status.progress.value]
* The current state of operation progress, as an arbitrary number
* which increases as the operation continues.
*
* @param {String} [status.progress.unit]
* The unit of the arbitrary status.progress.value, if that value has
* an associated unit.
*
* @param {String} [status.progress.ratio]
* If known, the current status of the operation as a value between
* 0 and 1 inclusive, where 0 is not yet started, and 1 is complete.
*
* @param {Object[]} [status.actions]
* Array of action objects which contain an action name and callback to
* be executed when that action is invoked.
* @param {Notification|Boolean|Object} status
* The status notification to show.
*
* @example
*
@@ -138,43 +119,10 @@ angular.module('index').controller('indexController', ['$scope', '$injector',
/**
* Adds a notification to the the list of notifications shown.
*
* @param {Object} notification The notification to add.
* @param {String} [notification.title] The title of the notification.
* @param {String} [notification.text] The body text of the notification.
* @param {String} [notification.className] The CSS class name to apply.
* @param {Notification|Object} notification The notification to add.
*
* @param {String} [notification.countdown.text]
* In the case that a countdown applies to the notification, the text to
* display while the countdown is active.
*
* @param {Function} [notification.countdown.callback]
* The callback to call when the countdown expires.
*
* @param {String} [notification.countdown.remaining]
* The number of seconds remaining before the countdown callback is
* called.
*
* @param {String} [notification.progress.text]
* If this notification has associated progress, the text to display
* while the operation is occurring.
*
* @param {String} [notification.progress.value]
* The current state of operation progress, as an arbitrary number
* which increases as the operation continues.
*
* @param {String} [notification.progress.unit]
* The unit of the arbitrary notification.progress.value, if that value
* has an associated unit.
*
* @param {String} [notification.progress.ratio]
* If known, the current status of the operation as a value between
* 0 and 1 inclusive, where 0 is not yet started, and 1 is complete.
*
* @param {Object[]} [notification.actions]
* Array of action objects which contain an action name and callback to
* be executed when that action is invoked.
*
* @returns {Number} A unique ID for the notification that's just been added.
* @returns {Number}
* A unique ID for the notification that's just been added.
*
* @example
*

View File

@@ -31,110 +31,11 @@ angular.module('notification').directive('guacNotification', [function guacNotif
scope: {
/**
* The CSS class to apply to the notification.
* The notification to display.
*
* @type String
* @type Notification|Object
*/
className : '=',
/**
* The title of the notification.
*
* @type String
*/
title : '=',
/**
* The body text of the notification.
*
* @type String
*/
text : '=',
/**
* The text to use for displaying the countdown. For the sake of
* i18n, the variable REMAINING will be applied within the
* translation string for formatting plurals, etc.
*
* @type String
* @example
* "Only {REMAINING} {REMAINING, plural, one{second} other{seconds}} remain."
*/
countdownText : '=',
/**
* The number of seconds to wait before automatically calling the
* default callback.
*
* @type Number
*/
countdown : '=',
/**
* The function to call when timeRemaining expires. If timeRemaining
* is not set, this does not apply.
*
* @type Function
*/
defaultCallback : '=',
/**
* The text to use for displaying the progress. For the sake of
* i18n, the variable PROGRESS will be applied within the
* translation string for formatting plurals, etc., while the
* variable UNIT will be applied, if needed, for whatever units
* are applicable to the progress display.
*
* @type String
* @example
* "{PROGRESS} {UNIT, select, b{B} kb{KB}} uploaded."
*/
progressText : '=',
/**
* The unit which applies to the progress indicator, if any. This
* will be substituted in the progressText string with the UNIT
* variable.
*
* @type String
*/
progressUnit : '=',
/**
* Arbitrary value denoting how much progress has been made
* in some ongoing task that this notification represents.
*
* @type Number
*/
progress : '=',
/**
* Value between 0 and 1 denoting what proportion of the operation
* has completed. If known, this value should be 0 if the operation
* has not started, and 1 if the operation is complete.
*
* @type Number
*/
progressRatio : '=',
/**
* Array of name/callback pairs for each action the user is allowed
* to take once the notification is shown.
*
* @type Array
* @example
* [
* {
* name : "Action 1 name",
* callback : actionCallback1
* },
* {
* name : "Action 2 text",
* callback : actionCallback2
* }
* ]
*/
actions : '='
notification : '='
},
@@ -142,21 +43,22 @@ angular.module('notification').directive('guacNotification', [function guacNotif
controller: ['$scope', '$interval', function guacNotificationController($scope, $interval) {
// Update progress bar if end known
$scope.$watch("progressRatio", function updateProgress(ratio) {
$scope.$watch("notification.progress.ratio", function updateProgress(ratio) {
$scope.progressPercent = ratio * 100;
});
// Set countdown interval when associated property is set
$scope.$watch("countdown", function resetTimeRemaining(countdown) {
$scope.$watch("notification", function resetTimeRemaining(notification) {
$scope.timeRemaining = countdown;
var countdown = notification.countdown;
// Clean up any existing interval
if ($scope.interval)
$interval.cancel($scope.interval);
// Update and handle countdown, if provided
if ($scope.timeRemaining) {
if (countdown) {
$scope.timeRemaining = countdown.remaining;
$scope.interval = $interval(function updateTimeRemaining() {
@@ -164,8 +66,8 @@ angular.module('notification').directive('guacNotification', [function guacNotif
$scope.timeRemaining--;
// Call countdown callback when time remaining expires
if ($scope.timeRemaining === 0 && $scope.defaultCallback)
$scope.defaultCallback();
if ($scope.timeRemaining === 0)
countdown.performAction();
}, 1000, $scope.timeRemaining);
@@ -184,4 +86,4 @@ angular.module('notification').directive('guacNotification', [function guacNotif
}]
};
}]);
}]);

View File

@@ -1,4 +1,4 @@
<div class="notification" ng-class="className">
<div class="notification" ng-class="notification.className">
<!--
Copyright (C) 2014 Glyptodon LLC
@@ -22,26 +22,26 @@
-->
<!-- Notification title -->
<div ng-show="title" class="title-bar">
<div class="title">{{title | translate}}</div>
<div ng-show="notification.title" class="title-bar">
<div class="title">{{notification.title | translate}}</div>
</div>
<div class="body">
<!-- Notification text -->
<p ng-show="text" class="text">{{text | translate}}</p>
<p ng-show="notification.text" class="text">{{notification.text | translate}}</p>
<!-- Current progress -->
<div ng-show="progressText" class="progress"><div ng-show="progressPercent" ng-style="{'width': progressPercent + '%'}" class="bar"></div><div class="text">{{progressText | translate:"{ PROGRESS: progress, UNIT: progressUnit }"}}</div></div>
<div ng-show="notification.progress" class="progress"><div ng-show="progressPercent" ng-style="{'width': progressPercent + '%'}" class="bar"></div><div ng-show="notification.progress.text" class="text">{{notification.progress.text | translate:"{ PROGRESS: notification.progress.value, UNIT: notification.progress.unit}"}}</div></div>
<!-- Default action countdown text -->
<p ng-show="countdownText" class="countdown-text">{{countdownText | translate:"{ REMAINING: timeRemaining }"}}</p>
<p ng-show="notification.countdown.text" class="countdown-text">{{notification.countdown.text | translate:"{ REMAINING: timeRemaining}"}}</p>
</div>
<!-- Buttons -->
<div ng-show="actions && actions.length" class="buttons">
<button ng-repeat="action in actions" ng-click="action.callback()">{{action.name | translate}}</button>
<div ng-show="notification.actions.length" class="buttons">
<button ng-repeat="action in notification.actions" ng-click="action.callback()">{{action.name | translate}}</button>
</div>
</div>
</div>

View File

@@ -0,0 +1,91 @@
/*
* Copyright (C) 2014 Glyptodon LLC
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
/**
* Provides the Notification class definition.
*/
angular.module('notification').factory('Notification', [function defineNotification() {
/**
* Creates a new Notification, initializing the properties of that
* Notification with the corresponding properties of the given template.
*
* @constructor
* @param {Notification|Object} [template={}]
* The object whose properties should be copied within the new
* Notification.
*/
var Notification = function Notification(template) {
// Use empty object by default
template = template || {};
/**
* The CSS class to associate with the notification, if any.
*
* @type String
*/
this.className = template.className;
/**
* The title of the notification.
*
* @type String
*/
this.title = template.title;
/**
* The body text of the notification.
*
* @type String
*/
this.text = template.text;
/**
* An array of all actions available to the user in response to this
* notification.
*
* @type NotificationAction[]
*/
this.actions = template.actions || [];
/**
* The current progress state of the ongoing action associated with this
* notification.
*
* @type NotificationProgress
*/
this.progress = template.progress;
/**
* The countdown and corresponding default action which applies to
* this notification, if any.
*
* @type NotificationCountdown
*/
this.countdown = template.countdown;
};
return Notification;
}]);

View File

@@ -0,0 +1,76 @@
/*
* Copyright (C) 2014 Glyptodon LLC
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
/**
* Provides the NotificationAction class definition.
*/
angular.module('notification').factory('NotificationAction', [function defineNotificationAction() {
/**
* Creates a new NotificationAction, which pairs an arbitrary callback with
* an action name. The name of this action will ultimately be presented to
* the user when the user is prompted to choose among available actions.
*
* @constructor
* @param {String} name The name of this action.
*
* @param {Function} callback
* The callback to call when the user elects to perform this action.
*/
var NotificationAction = function NotificationAction(name, callback) {
/**
* Reference to this NotificationAction.
*
* @type NotificationAction
*/
var action = this;
/**
* The name of this action.
*
* @type String
*/
this.name = name;
/**
* The callback to call when this action is performed.
*
* @type Function
*/
this.callback = callback;
/**
* Calls the callback associated with this NotificationAction, if any.
* If no callback is associated with this NotificationAction, this
* function has no effect.
*/
this.performAction = function performAction() {
if (action.callback)
action.callback();
};
};
return NotificationAction;
}]);

View File

@@ -0,0 +1,89 @@
/*
* Copyright (C) 2014 Glyptodon LLC
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
/**
* Provides the NotificationCountdown class definition.
*/
angular.module('notification').factory('NotificationCountdown', [function defineNotificationCountdown() {
/**
* Creates a new NotificationCountdown which describes an action that
* should be performed after a specific number of seconds has elapsed.
*
* @constructor
* @param {String} text The body text of the notification countdown.
*
* @param {Number} remaining
* The number of seconds remaining in the countdown.
*
* @param {Function} [callback]
* The callback to call when the countdown elapses.
*/
var NotificationCountdown = function NotificationCountdown(text, remaining, callback) {
/**
* Reference to this NotificationCountdown.
*
* @type NotificationCountdown
*/
var countdown = this;
/**
* The body text of the notification countdown. For the sake of i18n,
* the variable REMAINING should be applied within the translation
* string for formatting plurals, etc.
*
* @type String
*/
this.text = text;
/**
* The number of seconds remaining in the countdown. After this number
* of seconds elapses, the callback associated with this
* NotificationCountdown will be called.
*
* @type Number
*/
this.remaining = remaining;
/**
* The callback to call when this countdown expires.
*
* @type Function
*/
this.callback = callback;
/**
* Calls the callback associated with this NotificationCountdown, if any.
* If no callback is associated with this NotificationCountdown, this
* function has no effect.
*/
this.performAction = function performAction() {
if (countdown.callback)
countdown.callback();
};
};
return NotificationCountdown;
}]);

View File

@@ -0,0 +1,87 @@
/*
* Copyright (C) 2014 Glyptodon LLC
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
/**
* Provides the NotificationProgress class definition.
*/
angular.module('notification').factory('NotificationProgress', [function defineNotificationProgress() {
/**
* Creates a new NotificationProgress which describes the current status
* of an operation, and how much of that operation remains to be performed.
*
* @constructor
* @param {String} text The text describing the operation progress.
*
* @param {Number} value
* The current state of operation progress, as an arbitrary number
* which increases as the operation continues.
*
* @param {String} [unit]
* The unit of the arbitrary value, if that value has an associated
* unit.
*
* @param {Number} [ratio]
* If known, the current status of the operation as a value between 0
* and 1 inclusive, where 0 is not yet started, and 1 is complete.
*/
var NotificationProgress = function NotificationProgress(text, value, unit, ratio) {
/**
* The text describing the operation progress. For the sake of i18n,
* the variable PROGRESS should be applied within the translation
* string for formatting plurals, etc., while UNIT should be used
* for the progress unit, if any.
*
* @type String
*/
this.text = text;
/**
* The current state of operation progress, as an arbitrary number which
* increases as the operation continues.
*
* @type Number
*/
this.value = value;
/**
* The unit of the arbitrary value, if that value has an associated
* unit.
*
* @type String
*/
this.unit = unit;
/**
* If known, the current status of the operation as a value between 0
* and 1 inclusive, where 0 is not yet started, and 1 is complete.
*
* @type String
*/
this.ratio = ratio;
};
return NotificationProgress;
}]);

View File

@@ -37,20 +37,7 @@ THE SOFTWARE.
<!-- Global status/error dialog -->
<div ng-class="{shown: status}" class="status-outer">
<div class="status-middle">
<guac-notification
class-name="status.className"
title="status.title"
text="status.text"
progress-text="status.progress.text"
progress-unit="status.progress.unit"
progress-ratio="status.progress.ratio"
progress="status.progress.value"
actions="status.actions"
countdown-text="status.countdown.text"
countdown="status.countdown.remaining"
default-callback="status.countdown.callback"/>
<guac-notification notification="status"/>
</div>
</div>
@@ -60,20 +47,7 @@ THE SOFTWARE.
<!-- Notification area -->
<div id="notificationArea">
<div ng-repeat="wrapper in notifications">
<guac-notification
class-name="wrapper.notification.className"
title="wrapper.notification.title"
text="wrapper.notification.text"
progress-text="wrapper.notification.progress.text"
progress-unit="wrapper.notification.progress.unit"
progress-ratio="wrapper.notification.progress.ratio"
progress="wrapper.notification.progress.value"
actions="wrapper.notification.actions"
countdown-text="wrapper.notification.countdown.text"
countdown="wrapper.notification.countdown.remaining"
default-callback="wrapper.notification.countdown.callback"/>
<guac-notification notification="wrapper.notification"/>
<div>
</div>