ui-modules/utils/br-core/snackbar/snackbar.js (70 lines of code) (raw):
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
import angular from 'angular';
import angularAnimate from 'angular-animate';
import template from './snackbar.html';
const MODULE_NAME = 'core.snackbar';
const TEMPLATE_URL = 'templates/snackbar.html';
/**
* @ngdoc service
* @name brSnackbar
* @module brCore
*
* @description
* The brSnackbar service expose a simple method to create snackbars within your apps. This service make use of the
* `$animate` service by default
*
* @example
* ### Simple snackbar examples
* <example module="mySnackbar">
* <file name="index.html">
* <div ng-controller="myController" style="height: 500px">
* <br-button on-click="createSnackBar('This is my small snackbar')">Small snackbar</br-button>
* <br-button on-click="createSnackBar('This is my veeeeeery long snackbar with a lorem ipsum text: Lorem ipsum dolor sit amet, consectetur adipiscing elit. Donec dui ex, iaculis in arcu in, placerat iaculis dui. Vivamus interdum nisl non dignissim pulvinar.')">Looooooong snackbar</br-button>
* </div>
* </file>
* <file name="app.js">
* angular.module('mySnackbar', ['br.core'])
* .controller('myController', function($scope, brSnackbar) {
* $scope.createSnackBar = function(message) {
* brSnackbar.create(message);
* }
* });
* </file>
* </example>
*
* @example
* ### Snackbar example with callback
* <example module="mySnackbar">
* <file name="index.html">
* <div ng-controller="myController" style="height: 500px">
* <br-button on-click="createSnackBar('This is my snackbar with a callback')">Snackbar with callback</br-button>
* <div class="callbacks"></div>
* </div>
* </file>
* <file name="app.js">
* angular.module('mySnackbar', ['br.core'])
* .controller('myController', function($scope, brSnackbar) {
* var callbacks = angular.element(document.querySelector('.callbacks'));
* $scope.createSnackBar = function(message) {
* brSnackbar.create(message).then(function($element) {
* callbacks.append('<p>Closed snackback with message: ' + angular.element($element[0].querySelector('.snackbar-message')).html() + '</p>');
* });
* }
* });
* </file>
* </example>
*
* @example
* ### Snackbar examples with action
* <example module="mySnackbar">
* <file name="index.html">
* <div ng-controller="myController" style="height: 500px">
* <br-button on-click="createSnackBar('This is my snackbar with an UNDO action', {label: 'undo', callback: callback})">Snackbar with UNDO action</br-button>
* <br-button on-click="createSnackBar('This is my snackbar with another action', {label: 'Do that', callback: callback})">Snackbar with DO THAT action</br-button>
* <div class="callbacks"></div>
* </div>
* </file>
* <file name="app.js">
* angular.module('mySnackbar', ['br.core'])
* .controller('myController', function($scope, brSnackbar) {
* var callbacks = angular.element(document.querySelector('.callbacks'));
* $scope.createSnackBar = function(message, action) {
* brSnackbar.create(message, action);
* }
*
* $scope.callback = function($element) {
* callbacks.append('<p>Clicked on action: ' + angular.element($element[0].querySelector('.snackbar-action')).html() + '</p>');
* }
* });
* </file>
* </example>
*/
angular.module(MODULE_NAME, [angularAnimate])
.factory('brSnackbar', ['$rootScope', '$document', '$compile', '$templateCache', '$animate', '$timeout', '$q', brSnackbar])
.run(['$templateCache', snackbarRun]);
export default MODULE_NAME;
export function brSnackbar($rootScope, $document, $compile, $templateCache, $animate, $timeout, $q) {
$rootScope.snackbars = [];
$rootScope.$watchCollection('snackbars', function(newSnackbars, oldSnackbars) {
if (newSnackbars.length > oldSnackbars.length) {
// We added a snackbar
if (newSnackbars.length === 1) {
// That is the first one, let's display it
displaySnackbar(newSnackbars[0]);
}
} else {
// One snackbar down, check if there are still some to display
if (newSnackbars.length > 0) {
displaySnackbar(newSnackbars[0]);
}
}
});
function displaySnackbar(snackbar) {
// Add the snackbar to the dom
$animate.enter(snackbar.elm, $document.find('body'));
// Remove the snackbar after the timeout
snackbar.timeout = $timeout(function() {
removeSnackbar(snackbar);
}, snackbar.options.timeout || 5000);
}
function removeSnackbar(snackbar) {
$animate.leave(snackbar.elm).then(function() {
snackbar.promise.resolve(snackbar.elm);
$rootScope.snackbars.shift();
});
}
return {
/**
* @ngdoc method
* @name brSnackbar#create
*
* @description
* Create a snackbar that will be display on the bottom left of the screen. When you create a new snackbar, it will return
* a promise that will be resolve once this snackbar is dismissed. You can also add one action button that will trigger
* a callback.
*
* The snackbars are not stacked but displayed one after the other, as per as the [material design guidelines](https://www.google.com/design/spec/components/snackbars-toasts.html#snackbars-toasts-usage)
*
* @param {string} message The snackbar message
* @param {object} action An object containing the action `label` and `callback`. The callback function will take
* the current `$element` object of the snackbar
* @returns {promise} A promise that will be resolved once the snackbar is dismissed
*/
create: function(message, action, options) {
if (!options) options = {};
var scope = $rootScope.$new(true);
scope.message = message;
scope.action = angular.extend({}, action);
scope.hasAction = function() {
return !angular.isUndefined(scope.action.label) && !angular.isUndefined(scope.action.callback);
};
scope.extraClasses = options.class;
scope.performAction = function() {
var snackbar = $rootScope.snackbars[0];
scope.action.callback(snackbar.elm);
scope.close();
};
scope.closeText = options.closeText
scope.close = function() {
var snackbar = $rootScope.snackbars[0];
$timeout.cancel(snackbar.timeout);
removeSnackbar(snackbar);
}
var template = $templateCache.get(TEMPLATE_URL);
var elm = angular.element($compile(template)(scope));
var promise = $q.defer();
$rootScope.snackbars.push({
elm,
promise,
options,
});
return promise.promise;
}
};
}
export function snackbarRun($templateCache) {
$templateCache.put(TEMPLATE_URL, template);
}