Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Update the URL when a fragment link to that navigates the current doc is clicked #1461

Merged
merged 1 commit into from
Jan 19, 2016
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion examples/everything.amp.html
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,7 @@
<div class="logo"></div>

<h1 id="top">AMP #0</h1>
<a href="#amp-iframe">Go to iframe</a>
<p class="comic-amp">
Quisque ultricies id augue a convallis. Vivamus euismod est quis tellus laoreet lacinia. In quam tellus, mollis nec porta eget, volutpat sit amet nibh. Duis ac odio sem. Sed consequat, ante gravida fringilla suscipit, libero libero ullamcorper metus, nec porta est elit at est. Curabitur vel diam ligula. Nulla bibendum malesuada odio.
</p>
Expand Down Expand Up @@ -305,7 +306,7 @@ <h2>Instagram</h2>
layout="responsive">
</amp-instagram>

<h2>IFrame</h2>
<h2 id="amp-iframe">IFrame</h2>
<amp-iframe width=300 height=300
sandbox="allow-scripts allow-same-origin allow-popups allow-popups-to-escape-sandbox"
layout="responsive"
Expand Down
9 changes: 8 additions & 1 deletion src/document-click.js
Original file line number Diff line number Diff line change
Expand Up @@ -105,13 +105,14 @@ export function onDocumentElementClick_(e, viewport) {
let elem = null;
const docElement = e.currentTarget;
const doc = docElement.ownerDocument;
const win = doc.defaultView;

const tgtLoc = parseUrl(target.href);
if (!tgtLoc.hash) {
return;
}

const curLoc = parseUrl(doc.location.href);
const curLoc = parseUrl(win.location.href);
const tgtHref = `${tgtLoc.origin}${tgtLoc.pathname}${tgtLoc.search}`;
const curHref = `${curLoc.origin}${curLoc.pathname}${curLoc.search}`;

Expand Down Expand Up @@ -143,4 +144,10 @@ export function onDocumentElementClick_(e, viewport) {
log.warn('documentElement',
`failed to find element with id=${hash} or a[name=${hash}]`);
}
const history = win.history;
// If possible do update the URL with the hash. As explained above
// we do replaceState to avoid messing with the container's history.
if (history.replaceState) {
history.replaceState(null, '', `#${hash}`);
}
};
9 changes: 9 additions & 0 deletions src/platform.js
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,15 @@ export class Platform {
// Also true for MS Edge :)
return /Chrome|CriOS/i.test(this.navigator.userAgent);
}

/**
* Whether the current browser is a Chrome browser.
* @return {boolean}
*/
isFirefox() {
// Also true for MS Edge :)
return /Firefox/i.test(this.navigator.userAgent);
}
};


Expand Down
7 changes: 6 additions & 1 deletion src/service/viewport-impl.js
Original file line number Diff line number Diff line change
Expand Up @@ -645,7 +645,12 @@ export class ViewportBindingNatural_ {
if (doc./*OK*/scrollingElement) {
return doc./*OK*/scrollingElement;
}
if (doc.body) {
if (doc.body
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Are you sure this is correct? There are still lots of chromes out there with the old API...

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We may need to check the platform here - I looked around. This will definitely cause many problems.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Added.

// Firefox does not support scrollTop on doc.body for default
// scrolling.
// See https://github.com/ampproject/amphtml/issues/1398
// Unfortunately there is no way to feature detect this.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can't you scroll, and see if the scrolled?

const scrollTop = doc.body.scrollTop;
doc.body.scrollTop = 1;
const scrolled = doc.body.scrollTop === 1;
doc.body.scrollTop = scrollTop;

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@jridgewell we don't do feature testing if the feature testing would force layout or style recalc.

I'm also not sure that would actually work :)

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It'd certainly not work if the document is not presently scrollable (i.e. too short).

&& !platform.isFirefox()) {
return doc.body;
}
return doc.documentElement;
Expand Down
29 changes: 22 additions & 7 deletions test/functional/test-document-click.js
Original file line number Diff line number Diff line change
Expand Up @@ -19,18 +19,21 @@ import {onDocumentElementClick_} from '../../src/document-click';
describe('test-document-click onDocumentElementClick_', () => {
let evt;
let doc;
let win;
let tgt;
let elem;
let docElem;
let getElementByIdSpy;
let preventDefaultSpy;
let scrollIntoViewSpy;
let querySelectorSpy;
let replaceStateSpy;
let viewport;

beforeEach(() => {
preventDefaultSpy = sinon.spy();
scrollIntoViewSpy = sinon.spy();
replaceStateSpy = sinon.spy();
elem = {};
getElementByIdSpy = sinon.stub();
querySelectorSpy = sinon.stub();
Expand All @@ -39,10 +42,16 @@ describe('test-document-click onDocumentElementClick_', () => {
doc = {
getElementById: getElementByIdSpy,
querySelector: querySelectorSpy,
location: {
href: 'https://www.google.com/some-path?hello=world#link'
}
defaultView: {
location: {
href: 'https://www.google.com/some-path?hello=world#link'
},
history: {
replaceState: replaceStateSpy
},
},
};
win = doc.defaultView;
docElem = {
ownerDocument: doc
};
Expand Down Expand Up @@ -71,7 +80,7 @@ describe('test-document-click onDocumentElementClick_', () => {
describe('when linking to a different origin or path', () => {

beforeEach(() => {
doc.location.href = 'https://www.google.com/some-path?hello=world#link';
win.location.href = 'https://www.google.com/some-path?hello=world#link';
});

it('should not do anything on path change', () => {
Expand Down Expand Up @@ -118,7 +127,7 @@ describe('test-document-click onDocumentElementClick_', () => {
describe('when linking to identifier', () => {

beforeEach(() => {
doc.location.href = 'https://www.google.com/some-path?hello=world';
win.location.href = 'https://www.google.com/some-path?hello=world';
tgt.href = 'https://www.google.com/some-path?hello=world#test';
});

Expand Down Expand Up @@ -155,14 +164,16 @@ describe('test-document-click onDocumentElementClick_', () => {
});

it('should not call scrollIntoView if element with id is not found or ' +
'anchor with name is not found', () => {
'anchor with name is not found, but should still update URL', () => {
getElementByIdSpy.returns(null);
querySelectorSpy.returns(null);
expect(getElementByIdSpy.callCount).to.equal(0);

onDocumentElementClick_(evt, viewport);
expect(getElementByIdSpy.callCount).to.equal(1);
expect(scrollIntoViewSpy.callCount).to.equal(0);
expect(replaceStateSpy.callCount).to.equal(1);
expect(replaceStateSpy.args[0][2]).to.equal('#test');
});

it('should call scrollIntoView if element with id is found', () => {
Expand All @@ -171,15 +182,19 @@ describe('test-document-click onDocumentElementClick_', () => {
expect(scrollIntoViewSpy.callCount).to.equal(0);
onDocumentElementClick_(evt, viewport);
expect(scrollIntoViewSpy.callCount).to.equal(1);
expect(replaceStateSpy.callCount).to.equal(1);
expect(replaceStateSpy.args[0][2]).to.equal('#test');
});

it('should call scrollIntoView if element with id is found', () => {
it('should call scrollIntoView if element with name is found', () => {
getElementByIdSpy.returns(null);
querySelectorSpy.returns(elem);

expect(scrollIntoViewSpy.callCount).to.equal(0);
onDocumentElementClick_(evt, viewport);
expect(scrollIntoViewSpy.callCount).to.equal(1);
expect(replaceStateSpy.callCount).to.equal(1);
expect(replaceStateSpy.args[0][2]).to.equal('#test');
});
});
});
9 changes: 9 additions & 0 deletions test/functional/test-platform.js
Original file line number Diff line number Diff line change
Expand Up @@ -20,18 +20,21 @@ describe('Platform', () => {

let isIos;
let isChrome;
let isFirefox;

beforeEach(() => {
isIos = false;
isChrome = false;
isSafari = false;
isFirefox = false;
});

function testUserAgent(userAgentString) {
const platform = new Platform({navigator: {userAgent: userAgentString}});
expect(platform.isIos()).to.equal(isIos);
expect(platform.isChrome()).to.equal(isChrome);
expect(platform.isSafari()).to.equal(isSafari);
expect(platform.isFirefox()).to.equal(isFirefox);
}

it('iPhone 6 Plus', () => {
Expand Down Expand Up @@ -63,4 +66,10 @@ describe('Platform', () => {
' AppleWebKit/537.36 (KHTML, like Gecko) Chrome/44.0.2403.20' +
' Mobile Safari/537.36');
});

it('firefox', () => {
isFirefox = true;
testUserAgent('Mozilla/5.0 (Windows NT 6.1; WOW64; rv:40.0) ' +
'Gecko/20100101 Firefox/40.1');
});
});