Skip to content

Commit

Permalink
Corrected relative links adjustment for external jqm pages. Added ent…
Browse files Browse the repository at this point in the history
…ry in Readme.md about relative links. Fixes #138
  • Loading branch information
Tobias Bosch committed Mar 16, 2013
1 parent 55a28e7 commit d46873b
Show file tree
Hide file tree
Showing 8 changed files with 116 additions and 73 deletions.
8 changes: 8 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -155,6 +155,14 @@ The adapter integrates angular routes with jquery mobile in the following way:
}
}

- relative links in pages are treated relative to the templateUrl of the route,
not the route path. E.g. given the mapping

$routeProvider.when('/someFolder/page1.html', { templateUrl:'#page1' });
$routeProvider.when('/someFolder/page2.html', { templateUrl:'/someTemplateFolder/page2.html' });

Page1 is embedded page, and therefore, all links within that page are relative to the initial url of the app. Page2 is an external page and all relative links in that page are relative to the folder `/someTemplateFolder`.

- Please also look at the extensions to the `$location` service for controlling history and changing route params for just one route call.

Default routing: `basePath+$location.url()`
Expand Down
29 changes: 16 additions & 13 deletions compiled/jquery-mobile-angular-adapter-standalone.js
Original file line number Diff line number Diff line change
Expand Up @@ -35751,7 +35751,7 @@ factory(window.jQuery, window.angular);
ng.config(["$precompileProvider", function($precompile) {
$precompile.addHandler(["jqmNgWidget", "element", precompilePageAndWidgets]);
}]);
ng.run(['$rootScope', '$compile', 'jqmNgWidget', initExternalJqmPagesOnLoad]);
ng.run(['$rootScope', '$compile', 'jqmNgWidget', '$browser', initExternalJqmPagesOnLoad]);

ng.directive('ngmPage', ["jqmNgWidget", "$timeout", ngmPageDirective]);

Expand Down Expand Up @@ -35926,7 +35926,7 @@ factory(window.jQuery, window.angular);
}

// If jqm loads a page from an external source, angular needs to compile it too!
function initExternalJqmPagesOnLoad($rootScope, $compile, jqmNgWidget) {
function initExternalJqmPagesOnLoad($rootScope, $compile, jqmNgWidget, $browser) {
jqmNgWidget.patchJq('page', function () {
if (!jqmNgWidget.preventJqmWidgetCreation() && !this.data($.mobile.page.prototype.widgetFullName)) {
if (this.attr("data-" + $.mobile.ns + "external-page")) {
Expand All @@ -35937,21 +35937,24 @@ factory(window.jQuery, window.angular);
return $.fn.orig.page.apply(this, arguments);
});

var base = $.mobile.base.element.attr("href");
function correctRelativeLinks(page) {
// correct the relative links in this page relative
// to the page url.
// Jqm does this when a link is clicked (using link.attr("href"),
// but we want to use link.prop("href")
var url = page.jqmData( "url" );
if ( !url || !$.mobile.path.isPath( url ) ) {
url = base;
}
var pageUrl = $.mobile.path.makeUrlAbsolute( url, base);
page.find( "a:not([rel='external'], [target])" ).each(function() {
// For external links, jqm already does this when
// the page is loaded. However, normal links
// are adjusted in jqm via their default jqm click handler.
// As we use our own default click handler (see ngmRouting.js),
// we need to adjust normal links ourselves.
var pageUrl = page.jqmData( "url" ),
pagePath = $.mobile.path.get(pageUrl),
ABSOULTE_URL_RE = /^(\w+:|#|\/)/;

page.find( "a" ).each(function() {
var $this = $(this),
thisUrl = $this.attr( 'href' );
$this.attr('href', $.mobile.path.makeUrlAbsolute(thisUrl, pageUrl));
thisUrl = $this.attr( "href" );
if ( !ABSOULTE_URL_RE.test( thisUrl ) ) {
$this.attr( "href", pagePath + thisUrl );
}
});
}
}
Expand Down
2 changes: 1 addition & 1 deletion compiled/jquery-mobile-angular-adapter-standalone.min.js

Large diffs are not rendered by default.

29 changes: 16 additions & 13 deletions compiled/jquery-mobile-angular-adapter.js
Original file line number Diff line number Diff line change
Expand Up @@ -315,7 +315,7 @@ factory(window.jQuery, window.angular);
ng.config(["$precompileProvider", function($precompile) {
$precompile.addHandler(["jqmNgWidget", "element", precompilePageAndWidgets]);
}]);
ng.run(['$rootScope', '$compile', 'jqmNgWidget', initExternalJqmPagesOnLoad]);
ng.run(['$rootScope', '$compile', 'jqmNgWidget', '$browser', initExternalJqmPagesOnLoad]);

ng.directive('ngmPage', ["jqmNgWidget", "$timeout", ngmPageDirective]);

Expand Down Expand Up @@ -490,7 +490,7 @@ factory(window.jQuery, window.angular);
}

// If jqm loads a page from an external source, angular needs to compile it too!
function initExternalJqmPagesOnLoad($rootScope, $compile, jqmNgWidget) {
function initExternalJqmPagesOnLoad($rootScope, $compile, jqmNgWidget, $browser) {
jqmNgWidget.patchJq('page', function () {
if (!jqmNgWidget.preventJqmWidgetCreation() && !this.data($.mobile.page.prototype.widgetFullName)) {
if (this.attr("data-" + $.mobile.ns + "external-page")) {
Expand All @@ -501,21 +501,24 @@ factory(window.jQuery, window.angular);
return $.fn.orig.page.apply(this, arguments);
});

var base = $.mobile.base.element.attr("href");
function correctRelativeLinks(page) {
// correct the relative links in this page relative
// to the page url.
// Jqm does this when a link is clicked (using link.attr("href"),
// but we want to use link.prop("href")
var url = page.jqmData( "url" );
if ( !url || !$.mobile.path.isPath( url ) ) {
url = base;
}
var pageUrl = $.mobile.path.makeUrlAbsolute( url, base);
page.find( "a:not([rel='external'], [target])" ).each(function() {
// For external links, jqm already does this when
// the page is loaded. However, normal links
// are adjusted in jqm via their default jqm click handler.
// As we use our own default click handler (see ngmRouting.js),
// we need to adjust normal links ourselves.
var pageUrl = page.jqmData( "url" ),
pagePath = $.mobile.path.get(pageUrl),
ABSOULTE_URL_RE = /^(\w+:|#|\/)/;

page.find( "a" ).each(function() {
var $this = $(this),
thisUrl = $this.attr( 'href' );
$this.attr('href', $.mobile.path.makeUrlAbsolute(thisUrl, pageUrl));
thisUrl = $this.attr( "href" );
if ( !ABSOULTE_URL_RE.test( thisUrl ) ) {
$this.attr( "href", pagePath + thisUrl );
}
});
}
}
Expand Down
2 changes: 1 addition & 1 deletion compiled/jquery-mobile-angular-adapter.min.js

Large diffs are not rendered by default.

29 changes: 16 additions & 13 deletions src/integration/compileIntegration.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
ng.config(["$precompileProvider", function($precompile) {
$precompile.addHandler(["jqmNgWidget", "element", precompilePageAndWidgets]);
}]);
ng.run(['$rootScope', '$compile', 'jqmNgWidget', initExternalJqmPagesOnLoad]);
ng.run(['$rootScope', '$compile', 'jqmNgWidget', '$browser', initExternalJqmPagesOnLoad]);

ng.directive('ngmPage', ["jqmNgWidget", "$timeout", ngmPageDirective]);

Expand Down Expand Up @@ -187,7 +187,7 @@
}

// If jqm loads a page from an external source, angular needs to compile it too!
function initExternalJqmPagesOnLoad($rootScope, $compile, jqmNgWidget) {
function initExternalJqmPagesOnLoad($rootScope, $compile, jqmNgWidget, $browser) {
jqmNgWidget.patchJq('page', function () {
if (!jqmNgWidget.preventJqmWidgetCreation() && !this.data($.mobile.page.prototype.widgetFullName)) {
if (this.attr("data-" + $.mobile.ns + "external-page")) {
Expand All @@ -198,21 +198,24 @@
return $.fn.orig.page.apply(this, arguments);
});

var base = $.mobile.base.element.attr("href");
function correctRelativeLinks(page) {
// correct the relative links in this page relative
// to the page url.
// Jqm does this when a link is clicked (using link.attr("href"),
// but we want to use link.prop("href")
var url = page.jqmData( "url" );
if ( !url || !$.mobile.path.isPath( url ) ) {
url = base;
}
var pageUrl = $.mobile.path.makeUrlAbsolute( url, base);
page.find( "a:not([rel='external'], [target])" ).each(function() {
// For external links, jqm already does this when
// the page is loaded. However, normal links
// are adjusted in jqm via their default jqm click handler.
// As we use our own default click handler (see ngmRouting.js),
// we need to adjust normal links ourselves.
var pageUrl = page.jqmData( "url" ),
pagePath = $.mobile.path.get(pageUrl),
ABSOULTE_URL_RE = /^(\w+:|#|\/)/;

page.find( "a" ).each(function() {
var $this = $(this),
thisUrl = $this.attr( 'href' );
$this.attr('href', $.mobile.path.makeUrlAbsolute(thisUrl, pageUrl));
thisUrl = $this.attr( "href" );
if ( !ABSOULTE_URL_RE.test( thisUrl ) ) {
$this.attr( "href", pagePath + thisUrl );
}
});
}
}
Expand Down
49 changes: 28 additions & 21 deletions test/devSnippetPage.html
Original file line number Diff line number Diff line change
Expand Up @@ -5,43 +5,50 @@
-->
<head>
<meta name="viewport" content="width=device-width,initial-scale=1.0,maximum-scale=1.0,user-scalable=0"/>

<link rel="stylesheet" href="../lib/jquery.mobile.css"/>
<base href="/">

<script src="../lib/jquery.js"></script>
<script src="../lib/jquery.mobile.js"></script>
<script src="../lib/angular.js"></script>
<script src="../compiled/jquery-mobile-angular-adapter.js"></script>

<script>
var myApp = angular.module('myApp',[]);

myApp.directive('myWidget', function(){
return {
replace: true,
templateUrl: 'MyWidget.html',
link: function() {}
}
var ngm = angular.module('ngm',[]);
ngm.config(function($routeProvider) {
$routeProvider.when('/page1', {
templateUrl: '#page1'
});
$routeProvider.when('/someFolder/page2.html', {
templateUrl: '#page2'
});
});

function Controller ($scope) {
$scope.checked = true;
}
</script>

</head>
<body ng-app="myApp">
<body ng-app="ngm">

<div data-role="page">
<div data-role="content">
<a href="ui/fixtures/someFolder/externalPage.html?test#asdf">Test</a>
<a href="page1">Page1</a>
</div>
</div>

<script type="text/ng-template" id="MyWidget.html">
<div>
<input data-role="none" id="c" type="checkbox" name="c" ng-model="checked" ng-checked="checked"/><label for="c">Checkbox - globalCheck: {{checked}}</label>
<div data-role="page" id="page1">
<div data-role="header">
<h1>Page1</h1>
<a href="someFolder/page2.html">Page2</a>
</div>
</script>
</div>

<div data-role="page" ng-controller="Controller">
<div class="test-widget" my-widget></div>
<select data-role="none"></select>
</div>
<div data-role="page" id="page2">
<div data-role="header">
<h1>Page2</h1>
<a href="page1">Page1</a>
</div>
</div>

</body>

Expand Down
41 changes: 30 additions & 11 deletions test/unit/integration/compileIntegrationUnitSpec.js
Original file line number Diff line number Diff line change
Expand Up @@ -64,16 +64,36 @@ describe('compileIntegrationUnit', function () {
expect(page.scope()).toBe(container.scope());
});

it("should angular compile pages loaded by jquery from external sources", function() {
var container = testutils.compile("<div></div>");
var page = $('<div data-role="page">{{1+2}}</div>');
page.attr("data-" + $.mobile.ns + "external-page", "someUrl");
container.append(page);
page.page();
$.mobile.activePage = page;
page.scope().$root.$digest();
expect(page.text()).toBe('3');
expect(page.scope().$parent).toBe(container.scope());
describe('pages loaded by jquery from externa resources', function() {
var container, page;
function init(url, content) {
container = testutils.compile("<div></div>");
page = $('<div data-role="page">'+content+'</div>');
page.attr("data-" + $.mobile.ns + "external-page", url);
page.jqmData("url", url);
container.append(page);
page.page();
$.mobile.activePage = page;
page.scope().$root.$digest();
}

it("should angular compile", function() {
init('someUrl', '{{1+2}}');
expect(page.text()).toBe('3');
expect(page.scope().$parent).toBe(container.scope());
});

it("should adjust relative links", function() {
init('somePath/someUrl.html', '<a href="test.html">');
var link = page.find("a");
expect(link.attr("href")).toBe('somePath/test.html');
});

it("should not adjust absolute links", function() {
init('somePath/someUrl.html', '<a href="/test.html">');
var link = page.find("a");
expect(link.attr("href")).toBe('/test.html');
});
});

describe("partials loaded by angular", function() {
Expand Down Expand Up @@ -103,7 +123,6 @@ describe('compileIntegrationUnit', function () {
it("should enhance the partial content", function() {
var c = compileInPartialInPage('<a href="" data-role="button">Test</a>');
expect(c.container.children(".ui-btn").length).toBe(1);

});

it("should stamp stateless markup without calling jqm", function () {
Expand Down

0 comments on commit d46873b

Please sign in to comment.