Skip to content

Commit

Permalink
fixes #118. Please have a look at the Readme.md for the different beh…
Browse files Browse the repository at this point in the history
…aviour of the back button when dialogs are opened from dialogs
  • Loading branch information
Tobias Bosch committed Feb 22, 2013
1 parent edaa484 commit 63930f4
Show file tree
Hide file tree
Showing 8 changed files with 85 additions and 36 deletions.
23 changes: 21 additions & 2 deletions README.md
Expand Up @@ -374,13 +374,13 @@ Note: `pagerId.cache` stores the last result that was returns for a `list | page
Notes on the integration of some jqm widgets
----------------

### widget collapsible
### widget `collapsible`

- The attribute `data-collapsed` has bidirectional data binding, e.g.

<div data-role="collapsible" data-collapsed="someProperty">...</div>

### widget checkboxradio
### widget `checkboxradio`

- using `ng-repeat` with a checkbox or radio button without a wrapper element can be done like the following:

Expand All @@ -389,6 +389,25 @@ Notes on the integration of some jqm widgets
<input type="checkbox">
</label>

### widget `dialog`

- Same as in Jqm: if a page is navigated to from a dialog, and the user hits the back button, then the browser
navigates to the page before the dialog.

- Different to Jqm: if a dialog/popup is opened in another dialog, and the user hits the back button, then the browser navigates
to the page before the first dialog (same strategy as for normal pages).
In plain jquery mobile, this will only close the second dialog/popup.
This behaviour is due to the following implementation detail:
- We call `$.mobile.changePage` using routes in angular. When a route is executed, angular already updated the
browser url to a new value (after the `$locationChangeSuccess` event). To remove the dialog from the browser history
(for a link from a dialog to a normal page), we also need to do this when angular updates the browser url.
- However, the calculation whether a target page of a link is a dialog or a normal page is done
using routes.
- As a consequence, we are only able to implement one strategy for links to pages in dialogs,
no matter if the link goes to a dialog or a normal page.



Integration strategy
---------------------

Expand Down
14 changes: 11 additions & 3 deletions compiled/jquery-mobile-angular-adapter-1.2.1-SNAPSHOT.js
Expand Up @@ -1399,12 +1399,15 @@ factory(window.jQuery, window.angular);
onActivateParams = angular.extend({}, current.locals, $routeParams);
event.targetScope.$eval(current.onActivate, onActivateParams);
}
var isDialog = $.mobile.activePage && $.mobile.activePage.jqmData("role") === "dialog";
if (isDialog) {
if (activePageIsDialog()) {
dialogUrl(true);
}
}

function activePageIsDialog() {
return $.mobile.activePage && $.mobile.activePage.jqmData("role") === "dialog";
}

function onRouteChangeSuccess() {
var newRoute = $route.current;
var $document = $(document);
Expand Down Expand Up @@ -1465,9 +1468,14 @@ factory(window.jQuery, window.angular);

function instrumentPopupCloseToNavigateBackWhenDialogUrlIsSet() {
var popupProto = $.mobile.popup.prototype;
var _open = popupProto._open;
popupProto._open = function() {
this.firstPopup = !activePageIsDialog();
return _open.apply(this, arguments);
};
var _close = popupProto._close;
popupProto._close = function () {
if (dialogUrl()) {
if (dialogUrl() && this.firstPopup) {
$rootScope.$apply(function () {
$location.goBack();
});
Expand Down
Expand Up @@ -34409,12 +34409,15 @@ factory(window.jQuery, window.angular);
onActivateParams = angular.extend({}, current.locals, $routeParams);
event.targetScope.$eval(current.onActivate, onActivateParams);
}
var isDialog = $.mobile.activePage && $.mobile.activePage.jqmData("role") === "dialog";
if (isDialog) {
if (activePageIsDialog()) {
dialogUrl(true);
}
}

function activePageIsDialog() {
return $.mobile.activePage && $.mobile.activePage.jqmData("role") === "dialog";
}

function onRouteChangeSuccess() {
var newRoute = $route.current;
var $document = $(document);
Expand Down Expand Up @@ -34475,9 +34478,14 @@ factory(window.jQuery, window.angular);

function instrumentPopupCloseToNavigateBackWhenDialogUrlIsSet() {
var popupProto = $.mobile.popup.prototype;
var _open = popupProto._open;
popupProto._open = function() {
this.firstPopup = !activePageIsDialog();
return _open.apply(this, arguments);
};
var _close = popupProto._close;
popupProto._close = function () {
if (dialogUrl()) {
if (dialogUrl() && this.firstPopup) {
$rootScope.$apply(function () {
$location.goBack();
});
Expand Down

Large diffs are not rendered by default.

Large diffs are not rendered by default.

14 changes: 11 additions & 3 deletions src/main/webapp/integration/ngmRouting.js
Expand Up @@ -172,12 +172,15 @@
onActivateParams = angular.extend({}, current.locals, $routeParams);
event.targetScope.$eval(current.onActivate, onActivateParams);
}
var isDialog = $.mobile.activePage && $.mobile.activePage.jqmData("role") === "dialog";
if (isDialog) {
if (activePageIsDialog()) {
dialogUrl(true);
}
}

function activePageIsDialog() {
return $.mobile.activePage && $.mobile.activePage.jqmData("role") === "dialog";
}

function onRouteChangeSuccess() {
var newRoute = $route.current;
var $document = $(document);
Expand Down Expand Up @@ -238,9 +241,14 @@

function instrumentPopupCloseToNavigateBackWhenDialogUrlIsSet() {
var popupProto = $.mobile.popup.prototype;
var _open = popupProto._open;
popupProto._open = function() {
this.firstPopup = !activePageIsDialog();
return _open.apply(this, arguments);
};
var _close = popupProto._close;
popupProto._close = function () {
if (dialogUrl()) {
if (dialogUrl() && this.firstPopup) {
$rootScope.$apply(function () {
$location.goBack();
});
Expand Down
41 changes: 19 additions & 22 deletions src/test/webapp/devSnippetPage.html
Expand Up @@ -16,37 +16,34 @@
<script>
var mod = angular.module("ngm", []);

mod.config(['$routeProvider', function ($routeProvider) {
$routeProvider.when('/hello/:name', {
templateUrl: '#hello',
onActivate: 'onActivate(name)'
})
}]);

mod.controller('MainController', function ($scope) {

});

mod.controller('ControllerTwo', function ($scope) {
$scope.onActivate = function (name) {
this.name = name;
}

});</script>
</script>

</head>
<body ng-app="ngm">
<div id="main" data-role="page" ng-controller="MainController">
<div data-role="content"> <a href="hello/Tobias">Say Hello</a>
<a href="hello/Tobias_Again">Say Hello Again</a>
<div id="main" data-role="page">
<div data-role="content">
<a href="#dialog">Show Dialog</a>
</div>
</div>

<div id="dialog" data-role="dialog">
<div data-role="content">
<a href="#dialog2">Show dialog2</a>
<select data-native-menu="false">
<option>1</option>
<option>2</option>

</select>
</div>
</div>
<div id="hello" data-role="page" ng-controller="ControllerTwo">
<div data-role="header">Hello {{ name }}!</div>
<div data-role="content"> <a href="hello/Tobias_Again">Say Hello Again</a>

<div id="dialog2" data-role="dialog">
<div data-role="content">
</div>
</div>

</body>


Expand Down
11 changes: 10 additions & 1 deletion src/test/webapp/unit/integration/popupSpec.js
Expand Up @@ -29,6 +29,16 @@ describe('popup', function () {
c.popup("close");
expect($location.goBack).toHaveBeenCalled();
}));
it('should not go back in history when a popup in a dialog is closed and the url is the special dialog url', inject(function ($location) {
spyOn($location, 'goBack');
var page = testutils.compile('<div data-role="dialog"><div data-role="popup"></div></div>');
$.mobile.activePage = page;
var p = page.find(":jqmData(role=popup)");
$location.url("/&ui-state=dialog");
p.popup("open");
p.popup("close");
expect($location.goBack).not.toHaveBeenCalled();
}));
it('should not replace the $location with a special dialog url when a popup is opened without routing', inject(function ($location, $rootScope) {
var c = testutils.compileInPage('<div data-role="popup" id="popup1"></div>');
var popup = c.page.find("#popup1");
Expand All @@ -49,7 +59,6 @@ describe('popup', function () {
var closeBtn = popup.find("#close");
closeBtn.click();
expect($location.url()).toEqual("/");

}));
});
});

0 comments on commit 63930f4

Please sign in to comment.