mirror of
https://github.com/ionic-team/ionic-framework.git
synced 2026-03-13 10:22:08 +08:00
fix(popup): synchronously add/remove popups from stack, no matter the animation state
Closes #3131
This commit is contained in:
212
js/angular/service/popup.js
vendored
212
js/angular/service/popup.js
vendored
@@ -281,84 +281,79 @@ function($ionicTemplateLoader, $ionicBackdrop, $q, $timeout, $rootScope, $ionicB
|
||||
buttons: []
|
||||
}, options || {});
|
||||
|
||||
var popupPromise = $ionicTemplateLoader.compile({
|
||||
template: POPUP_TPL,
|
||||
scope: options.scope && options.scope.$new(),
|
||||
appendTo: $ionicBody.get()
|
||||
});
|
||||
var contentPromise = options.templateUrl ?
|
||||
$ionicTemplateLoader.load(options.templateUrl) :
|
||||
$q.when(options.template || options.content || '');
|
||||
var self = {};
|
||||
self.scope = (options.scope || $rootScope).$new();
|
||||
self.element = jqLite(POPUP_TPL);
|
||||
self.responseDeferred = $q.defer();
|
||||
|
||||
return $q.all([popupPromise, contentPromise]).then(function(results) {
|
||||
var self = results[0];
|
||||
var content = results[1];
|
||||
var responseDeferred = $q.defer();
|
||||
$ionicBody.get().appendChild(self.element[0]);
|
||||
$compile(self.element)(self.scope);
|
||||
|
||||
self.responseDeferred = responseDeferred;
|
||||
extend(self.scope, {
|
||||
title: options.title,
|
||||
buttons: options.buttons,
|
||||
subTitle: options.subTitle,
|
||||
cssClass: options.cssClass,
|
||||
$buttonTapped: function(button, event) {
|
||||
var result = (button.onTap || noop)(event);
|
||||
event = event.originalEvent || event; //jquery events
|
||||
|
||||
//Can't ng-bind-html for popup-body because it can be insecure html
|
||||
//(eg an input in case of prompt)
|
||||
var body = jqLite(self.element[0].querySelector('.popup-body'));
|
||||
if (content) {
|
||||
body.html(content);
|
||||
$compile(body.contents())(self.scope);
|
||||
} else {
|
||||
body.remove();
|
||||
}
|
||||
|
||||
extend(self.scope, {
|
||||
title: options.title,
|
||||
buttons: options.buttons,
|
||||
subTitle: options.subTitle,
|
||||
cssClass: options.cssClass,
|
||||
$buttonTapped: function(button, event) {
|
||||
var result = (button.onTap || noop)(event);
|
||||
event = event.originalEvent || event; //jquery events
|
||||
|
||||
if (!event.defaultPrevented) {
|
||||
responseDeferred.resolve(result);
|
||||
}
|
||||
if (!event.defaultPrevented) {
|
||||
self.responseDeferred.resolve(result);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
$q.when(
|
||||
options.templateUrl ?
|
||||
$ionicTemplateLoader.load(options.templateUrl) :
|
||||
(options.template || options.content || '')
|
||||
).then(function(template) {
|
||||
var popupBody = jqLite(self.element[0].querySelector('.popup-body'));
|
||||
if (template) {
|
||||
popupBody.html(template);
|
||||
$compile(popupBody.contents())(self.scope);
|
||||
} else {
|
||||
popupBody.remove();
|
||||
}
|
||||
});
|
||||
|
||||
self.show = function() {
|
||||
if (self.isShown || self.removed) return;
|
||||
|
||||
self.isShown = true;
|
||||
ionic.requestAnimationFrame(function() {
|
||||
//if hidden while waiting for raf, don't show
|
||||
if (!self.isShown) return;
|
||||
|
||||
self.element.removeClass('popup-hidden');
|
||||
self.element.addClass('popup-showing active');
|
||||
focusInput(self.element);
|
||||
});
|
||||
};
|
||||
|
||||
self.hide = function(callback) {
|
||||
callback = callback || noop;
|
||||
if (!self.isShown) return callback();
|
||||
|
||||
self.isShown = false;
|
||||
self.element.removeClass('active');
|
||||
self.element.addClass('popup-hidden');
|
||||
$timeout(callback, 250, false);
|
||||
};
|
||||
|
||||
self.remove = function() {
|
||||
if (self.removed) return;
|
||||
|
||||
self.hide(function() {
|
||||
self.element.remove();
|
||||
self.scope.$destroy();
|
||||
});
|
||||
|
||||
self.show = function() {
|
||||
if (self.isShown || self.removed) return;
|
||||
self.removed = true;
|
||||
};
|
||||
|
||||
self.isShown = true;
|
||||
ionic.requestAnimationFrame(function() {
|
||||
//if hidden while waiting for raf, don't show
|
||||
if (!self.isShown) return;
|
||||
|
||||
self.element.removeClass('popup-hidden');
|
||||
self.element.addClass('popup-showing active');
|
||||
focusInput(self.element);
|
||||
});
|
||||
};
|
||||
|
||||
self.hide = function(callback) {
|
||||
callback = callback || noop;
|
||||
if (!self.isShown) return callback();
|
||||
|
||||
self.isShown = false;
|
||||
self.element.removeClass('active');
|
||||
self.element.addClass('popup-hidden');
|
||||
$timeout(callback, 250);
|
||||
};
|
||||
|
||||
self.remove = function() {
|
||||
if (self.removed) return;
|
||||
|
||||
self.hide(function() {
|
||||
self.element.remove();
|
||||
self.scope.$destroy();
|
||||
});
|
||||
|
||||
self.removed = true;
|
||||
};
|
||||
|
||||
return self;
|
||||
});
|
||||
return self;
|
||||
}
|
||||
|
||||
function onHardwareBackButton() {
|
||||
@@ -367,69 +362,62 @@ function($ionicTemplateLoader, $ionicBackdrop, $q, $timeout, $rootScope, $ionicB
|
||||
}
|
||||
|
||||
function showPopup(options) {
|
||||
var resultDeferred;
|
||||
var popupPromise = $ionicPopup._createPopup(options);
|
||||
var popup = $ionicPopup._createPopup(options);
|
||||
var showDelay = 0;
|
||||
|
||||
if (popupStack.length > 0) {
|
||||
popupStack[popupStack.length - 1].hide();
|
||||
resultDeferred = $timeout(doShowPopup, config.stackPushDelay);
|
||||
showDelay = config.stackPushDelay;
|
||||
} else {
|
||||
//Add popup-open & backdrop if this is first popup
|
||||
$ionicBody.addClass('popup-open');
|
||||
console.log("RETAIN");
|
||||
$ionicBackdrop.retain();
|
||||
//only show the backdrop on the first popup
|
||||
$ionicPopup._backButtonActionDone = $ionicPlatform.registerBackButtonAction(
|
||||
onHardwareBackButton,
|
||||
IONIC_BACK_PRIORITY.popup
|
||||
);
|
||||
resultDeferred = doShowPopup();
|
||||
}
|
||||
|
||||
resultDeferred.close = function popupClose(result) {
|
||||
popupPromise.then(function(popup) {
|
||||
if (!popup.removed) popup.responseDeferred.resolve(result);
|
||||
});
|
||||
// Expose a 'close' method on the returned promise
|
||||
popup.responseDeferred.promise.close = function popupClose(result) {
|
||||
if (!popup.removed) popup.responseDeferred.resolve(result);
|
||||
};
|
||||
//DEPRECATED: notify the promise with an object with a close method
|
||||
popup.responseDeferred.notify({ close: popup.responseDeferred.close });
|
||||
|
||||
return resultDeferred;
|
||||
doShow();
|
||||
|
||||
function doShowPopup() {
|
||||
return popupPromise.then(function(popup) {
|
||||
popupStack.push(popup);
|
||||
popup.show();
|
||||
return popup.responseDeferred.promise;
|
||||
|
||||
//DEPRECATED: notify the promise with an object with a close method
|
||||
popup.responseDeferred.notify({
|
||||
close: resultDeferred.close
|
||||
});
|
||||
function doShow() {
|
||||
popupStack.push(popup);
|
||||
$timeout(popup.show, showDelay, false);
|
||||
|
||||
return popup.responseDeferred.promise.then(function(result) {
|
||||
var index = popupStack.indexOf(popup);
|
||||
if (index !== -1) {
|
||||
popupStack.splice(index, 1);
|
||||
}
|
||||
popup.remove();
|
||||
popup.responseDeferred.promise.then(function(result) {
|
||||
var index = popupStack.indexOf(popup);
|
||||
if (index !== -1) {
|
||||
popupStack.splice(index, 1);
|
||||
}
|
||||
|
||||
if (popupStack.length > 0) {
|
||||
popupStack[popupStack.length - 1].show();
|
||||
} else {
|
||||
$ionicBackdrop.release();
|
||||
//Remove popup-open & backdrop if this is last popup
|
||||
$timeout(function() {
|
||||
// wait to remove this due to a 300ms delay native
|
||||
// click which would trigging whatever was underneath this
|
||||
if (!popupStack.length) {
|
||||
$ionicBody.removeClass('popup-open');
|
||||
}
|
||||
}, 400, false);
|
||||
($ionicPopup._backButtonActionDone || noop)();
|
||||
}
|
||||
|
||||
if (popupStack.length > 0) {
|
||||
popupStack[popupStack.length - 1].show();
|
||||
} else {
|
||||
//Remove popup-open & backdrop if this is last popup
|
||||
$timeout(function() {
|
||||
// wait to remove this due to a 300ms delay native
|
||||
// click which would trigging whatever was underneath this
|
||||
if (!popupStack.length) {
|
||||
$ionicBody.removeClass('popup-open');
|
||||
}
|
||||
}, 400, false);
|
||||
|
||||
($ionicPopup._backButtonActionDone || noop)();
|
||||
}
|
||||
|
||||
return result;
|
||||
});
|
||||
popup.remove();
|
||||
|
||||
return result;
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
@@ -204,7 +204,7 @@ describe('$ionicPopup service', function() {
|
||||
show: jasmine.createSpy('show'),
|
||||
responseDeferred: $q.defer()
|
||||
};
|
||||
spyOn($ionicPopup, '_createPopup').andReturn($q.when(fakePopup));
|
||||
spyOn($ionicPopup, '_createPopup').andReturn(fakePopup);
|
||||
expect($ionicPopup._popupStack.length).toBe(0);
|
||||
$ionicPopup.show();
|
||||
expect(fakePopup.show).not.toHaveBeenCalled();
|
||||
@@ -215,9 +215,9 @@ describe('$ionicPopup service', function() {
|
||||
}));
|
||||
|
||||
it('should have close function which resolves promise with argument', inject(function($ionicPopup, $q, $rootScope) {
|
||||
var popup = TestUtil.unwrapPromise($ionicPopup._createPopup());
|
||||
spyOn($ionicPopup, '_createPopup').andReturn($q.when(popup));
|
||||
var result = $ionicPopup.show();
|
||||
var popup = TestUtil.unwrapPromise($ionicPopup._createPopup({template: 'foo'}));
|
||||
spyOn($ionicPopup, '_createPopup').andReturn(popup);
|
||||
var result = $ionicPopup.show();
|
||||
spyOn(popup.responseDeferred, 'resolve');
|
||||
result.close('foobar');
|
||||
$rootScope.$apply();
|
||||
@@ -230,7 +230,7 @@ describe('$ionicPopup service', function() {
|
||||
remove: jasmine.createSpy('remove'),
|
||||
responseDeferred: $q.defer()
|
||||
};
|
||||
spyOn($ionicPopup, '_createPopup').andReturn($q.when(fakePopup));
|
||||
spyOn($ionicPopup, '_createPopup').andReturn(fakePopup);
|
||||
var result = $ionicPopup.show();
|
||||
$timeout.flush();
|
||||
expect(fakePopup.remove).not.toHaveBeenCalled();
|
||||
@@ -251,7 +251,7 @@ describe('$ionicPopup service', function() {
|
||||
show: jasmine.createSpy('show'),
|
||||
hide: jasmine.createSpy('hide')
|
||||
};
|
||||
spyOn($ionicPopup, '_createPopup').andReturn($q.when(fakePopup));
|
||||
spyOn($ionicPopup, '_createPopup').andReturn(fakePopup);
|
||||
$ionicPopup._popupStack.unshift(previousPopup);
|
||||
$ionicPopup.show();
|
||||
fakePopup.responseDeferred.resolve();
|
||||
@@ -268,7 +268,7 @@ describe('$ionicPopup service', function() {
|
||||
var backDoneSpy = jasmine.createSpy('backDone');
|
||||
spyOn($ionicPlatform, 'registerBackButtonAction').andReturn(backDoneSpy);
|
||||
spyOn($ionicBackdrop, 'release');
|
||||
spyOn($ionicPopup, '_createPopup').andReturn($q.when(fakePopup));
|
||||
spyOn($ionicPopup, '_createPopup').andReturn(fakePopup);
|
||||
$ionicPopup.show();
|
||||
fakePopup.responseDeferred.resolve();
|
||||
$timeout.flush();
|
||||
|
||||
Reference in New Issue
Block a user