Skip to content
This repository has been archived by the owner on Sep 5, 2024. It is now read-only.

Commit

Permalink
fix(toast): differentiate between hide action clicks and hide timeouts
Browse files Browse the repository at this point in the history
All interim elements now resolve with 'true' for hide or timeout responses; unless overridden in the `.hide(value)` call.
Updated toast docs and demos.

Fixes #3745.
  • Loading branch information
ThomasBurleson committed Jul 16, 2015
1 parent 0982c76 commit 285ac72
Show file tree
Hide file tree
Showing 4 changed files with 148 additions and 59 deletions.
6 changes: 4 additions & 2 deletions src/components/toast/demoBasicUsage/script.js
Original file line number Diff line number Diff line change
Expand Up @@ -41,8 +41,10 @@ angular.module('toastDemo1', ['ngMaterial'])
.highlightAction(false)
.position($scope.getToastPosition());

$mdToast.show(toast).then(function() {
alert('You clicked \'OK\'.');
$mdToast.show(toast).then(function(response) {
if ( response == 'ok' ) {
alert('You clicked \'OK\'.');
}
});
};

Expand Down
17 changes: 13 additions & 4 deletions src/components/toast/toast.js
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,8 @@ function MdToastDirective() {
* @returns {obj} a `$mdToastPreset` with the chainable configuration methods:
*
* - $mdToastPreset#content(string) - sets toast content to string
* - $mdToastPreset#action(string) - adds an action button, which resolves the promise returned from `show()` if clicked.
* - $mdToastPreset#action(string) - adds an action button. If clicked the promise (returned from `show()`) will resolve
* with value 'ok'; otherwise it promise is resolved with 'true' after a hideDelay timeout.
* - $mdToastPreset#highlightAction(boolean) - sets action button to be highlighted
* - $mdToastPreset#capsule(boolean) - adds 'md-capsule' class to the toast (curved corners)
* - $mdToastPreset#theme(string) - sets the theme on the toast to theme (default is `$mdThemingProvider`'s default theme)
Expand Down Expand Up @@ -136,7 +137,9 @@ function MdToastDirective() {
* to the root element of the application.
*
* @returns {promise} A promise that can be resolved with `$mdToast.hide()` or
* rejected with `$mdToast.cancel()`.
* rejected with `$mdToast.cancel()`. `$mdToast.hide()` will resolve either with a Boolean
* value == 'true' or the value passed as an argument to `$mdToast.hide()`.
* And `$mdToast.cancel()` will resolve the promise with a Boolean value == 'false'
*/

/**
Expand All @@ -148,7 +151,9 @@ function MdToastDirective() {
*
* @param {*=} response An argument for the resolved promise.
*
* @returns {promise} a promise that is called when the existing element is removed from the DOM
* @returns {promise} a promise that is called when the existing element is removed from the DOM.
* The promise is resolved with either a Boolean value == 'true' or the value passed as the
* argument to `.hide()`.
*
*/

Expand All @@ -163,10 +168,14 @@ function MdToastDirective() {
* @param {*=} response An argument for the rejected promise.
*
* @returns {promise} a promise that is called when the existing element is removed from the DOM
* The promise is resolved with a Boolean value == 'false'.
*
*/

function MdToastProvider($$interimElementProvider) {
// Differentiate promise resolves: hide timeout (value == true) and hide action clicks (value == ok).
var ACTION_RESOLVE = 'ok';

var activeToastContent;
var $mdToast = $$interimElementProvider('$mdToast')
.setDefaults({
Expand All @@ -192,7 +201,7 @@ function MdToastProvider($$interimElementProvider) {
self.content = activeToastContent;
});
this.resolve = function() {
$mdToast.hide();
$mdToast.hide( ACTION_RESOLVE );
};
},
theme: $mdTheming.defaultTheme(),
Expand Down
171 changes: 122 additions & 49 deletions src/components/toast/toast.spec.js
Original file line number Diff line number Diff line change
@@ -1,22 +1,30 @@
describe('$mdToast service', function() {
beforeEach(module('material.components.toast', function($provide) {
}));
afterEach(inject(function($timeout, $animate) {
$animate.triggerCallbacks();
$timeout.flush();
}));

function setup(options) {
var promise;
inject(function($mdToast, $rootScope, $animate) {
$animate.triggerCallbacks();
options = options || {};
$mdToast.show(options);
$animate.triggerCallbacks();

promise = $mdToast.show(options);

$rootScope.$apply();
$animate.triggerCallbacks();
});
return promise;
}

describe('simple()', function() {
hasConfigMethods(['content', 'action', 'capsule', 'highlightAction', 'theme']);

it('supports a basic toast', inject(function($mdToast, $rootScope, $timeout, $animate) {
var resolved = false;
var openAndclosed = false;
var parent = angular.element('<div>');
$mdToast.show(
$mdToast.simple({
Expand All @@ -26,7 +34,7 @@ describe('$mdToast service', function() {
capsule: true
})
).then(function() {
resolved = true;
openAndclosed = true;
});
$rootScope.$digest();
expect(parent.find('span').text()).toBe('Do something');
Expand All @@ -35,7 +43,7 @@ describe('$mdToast service', function() {
$animate.triggerCallbacks();
$timeout.flush();
$animate.triggerCallbacks();
expect(resolved).toBe(true);
expect(openAndclosed).toBe(true);
}));

it('supports dynamicly updating the content', inject(function($mdToast, $rootScope, $rootElement) {
Expand Down Expand Up @@ -125,41 +133,6 @@ describe('$mdToast service', function() {

describe('build()', function() {
describe('options', function() {
it('should hide current toast when showing new one', inject(function($rootElement) {
setup({
template: '<md-toast class="one">'
});
expect($rootElement[0].querySelector('md-toast.one')).toBeTruthy();
expect($rootElement[0].querySelector('md-toast.two')).toBeFalsy();
expect($rootElement[0].querySelector('md-toast.three')).toBeFalsy();

setup({
template: '<md-toast class="two">'
});
expect($rootElement[0].querySelector('md-toast.one')).toBeFalsy();
expect($rootElement[0].querySelector('md-toast.two')).toBeTruthy();
expect($rootElement[0].querySelector('md-toast.three')).toBeFalsy();

setup({
template: '<md-toast class="three">'
});
expect($rootElement[0].querySelector('md-toast.one')).toBeFalsy();
expect($rootElement[0].querySelector('md-toast.two')).toBeFalsy();
expect($rootElement[0].querySelector('md-toast.three')).toBeTruthy();
}));

it('should hide after duration', inject(function($timeout, $animate, $rootElement) {
var parent = angular.element('<div>');
var hideDelay = 1234;
setup({
template: '<md-toast />',
hideDelay: hideDelay
});
expect($rootElement.find('md-toast').length).toBe(1);
$timeout.flush(hideDelay);
expect($rootElement.find('md-toast').length).toBe(0);
}));

it('should have template', inject(function($timeout, $rootScope, $rootElement) {
var parent = angular.element('<div>');
setup({
Expand Down Expand Up @@ -191,9 +164,11 @@ describe('$mdToast service', function() {
expect(toast.hasClass('md-left')).toBe(true);
}));
});
});

describe('lifecycle', function() {
it('should hide current toast when showing new one', inject(function($rootElement) {
describe('lifecycle', function() {
describe('should hide',function() {
it('current toast when showing new one', inject(function($rootElement) {
setup({
template: '<md-toast class="one">'
});
Expand All @@ -216,18 +191,116 @@ describe('$mdToast service', function() {
expect($rootElement[0].querySelector('md-toast.three')).toBeTruthy();
}));

it('should add class to toastParent', inject(function($rootElement) {
it('after duration', inject(function($timeout, $animate, $rootElement) {
var parent = angular.element('<div>');
var hideDelay = 1234;
setup({
template: '<md-toast>'
template: '<md-toast />',
hideDelay: hideDelay
});
expect($rootElement.hasClass('md-toast-open-bottom')).toBe(true);
expect($rootElement.find('md-toast').length).toBe(1);
$timeout.flush(hideDelay);
expect($rootElement.find('md-toast').length).toBe(0);
}));

it('and resolve with default `true`', inject(function($timeout, $animate, $mdToast) {
var hideDelay = 1234, result, fault;
setup({
template: '<md-toast>',
position: 'top'
});
expect($rootElement.hasClass('md-toast-open-top')).toBe(true);
template: '<md-toast />',
hideDelay: 1234
}).then(
function(response){ result = response; },
function(error){ fault = error; }
);

$mdToast.hide();

$timeout.flush();
$animate.triggerCallbacks();

expect(result).toBe(true);
expect(angular.isUndefined(fault)).toBe(true);

}));

it('and resolve with specified value', inject(function($timeout, $animate, $mdToast) {
var hideDelay = 1234, result, fault;
setup({
template: '<md-toast />',
hideDelay: 1234
}).then(
function(response){ result = response; },
function(error){ fault = error; }
);

$mdToast.hide("secret");

$timeout.flush();
$animate.triggerCallbacks();

expect(result).toBe("secret");
expect(angular.isUndefined(fault)).toBe(true);

}));

it('and resolve `true` after timeout', inject(function($timeout, $animate) {
var hideDelay = 1234, result, fault;
setup({
template: '<md-toast />',
hideDelay: 1234
}).then(
function(response){ result = response; },
function(error){ fault = error; }
);

$timeout.flush();
$animate.triggerCallbacks();

expect(result).toBe(true);
expect(angular.isUndefined(fault)).toBe(true);

}));

it('and resolve `ok` with click on OK button', inject(function($mdToast, $rootScope, $timeout, $animate) {
var result, fault;
var parent = angular.element('<div>');
var toast = $mdToast.simple({
parent: parent,
content: 'Do something'
}).action('Close with "ok" response');

$mdToast
.show(toast)
.then(
function(response){ result = response; },
function(error){ fault = error; }
);
$rootScope.$digest();
$animate.triggerCallbacks();

parent.find('button').triggerHandler('click');

$timeout.flush();
$animate.triggerCallbacks();

expect(result).toBe('ok');
expect(angular.isUndefined(fault)).toBe(true);

}));
});

it('should add class to toastParent', inject(function($rootElement) {
setup({
template: '<md-toast>'
});
expect($rootElement.hasClass('md-toast-open-bottom')).toBe(true);

setup({
template: '<md-toast>',
position: 'top'
});
expect($rootElement.hasClass('md-toast-open-top')).toBe(true);
}));
});

});
13 changes: 9 additions & 4 deletions src/core/services/interimElement/interimElement.js
Original file line number Diff line number Diff line change
Expand Up @@ -193,7 +193,9 @@ function InterimElementProvider() {
function showInterimElement(opts) {
// opts is either a preset which stores its options on an _options field,
// or just an object made up of options
if (opts && opts._options) opts = opts._options;
opts = opts || { };
if (opts._options) opts = opts._options;

return interimElementService.show(
angular.extend({}, defaultOptions, opts)
);
Expand Down Expand Up @@ -281,12 +283,14 @@ function InterimElementProvider() {
*
*/
function hide(response) {
response = response || true;
var interimElement = stack.shift();
return !interimElement ? $q.when(true) :
return !interimElement ? $q.when(response) :
interimElement
.remove()
.then(function() {
interimElement.deferred.resolve(response);
return interimElement.deferred.promise;
});
}

Expand All @@ -303,8 +307,9 @@ function InterimElementProvider() {
*
*/
function cancel(reason) {
reason = reason || false;
var interimElement = stack.shift();
return !interimElement ? $q.when(true) :
return !interimElement ? $q.when(reason) :
interimElement
.remove()
.then(function() {
Expand Down Expand Up @@ -396,7 +401,7 @@ function InterimElementProvider() {
}
}
},
function(reason) { showDone = true; self.deferred.reject(reason); })
function(reason) { showDone = true; self.deferred.reject(reason || false); })
},
cancelTimeout: function() {
if (hideTimeout) {
Expand Down

0 comments on commit 285ac72

Please sign in to comment.