fragments are now included in URL by default, even on named slides
parent
d727509dbc
commit
9823be99f4
|
@ -263,7 +263,7 @@ Reveal.initialize({
|
||||||
|
|
||||||
// Flags whether to include the current fragment in the URL,
|
// Flags whether to include the current fragment in the URL,
|
||||||
// so that reloading brings you to the same fragment position
|
// so that reloading brings you to the same fragment position
|
||||||
fragmentInURL: false,
|
fragmentInURL: true,
|
||||||
|
|
||||||
// Flags if the presentation is running in an embedded mode,
|
// Flags if the presentation is running in an embedded mode,
|
||||||
// i.e. contained within a limited portion of the screen
|
// i.e. contained within a limited portion of the screen
|
||||||
|
|
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
|
@ -124,7 +124,7 @@ export default {
|
||||||
|
|
||||||
// Flags whether to include the current fragment in the URL,
|
// Flags whether to include the current fragment in the URL,
|
||||||
// so that reloading brings you to the same fragment position
|
// so that reloading brings you to the same fragment position
|
||||||
fragmentInURL: false,
|
fragmentInURL: true,
|
||||||
|
|
||||||
// Flags if the presentation is running in an embedded mode,
|
// Flags if the presentation is running in an embedded mode,
|
||||||
// i.e. contained within a limited portion of the screen
|
// i.e. contained within a limited portion of the screen
|
||||||
|
|
|
@ -12,6 +12,20 @@ export default class Location {
|
||||||
// Delays updates to the URL due to a Chrome thumbnailer bug
|
// Delays updates to the URL due to a Chrome thumbnailer bug
|
||||||
this.writeURLTimeout = 0;
|
this.writeURLTimeout = 0;
|
||||||
|
|
||||||
|
this.onWindowHashChange = this.onWindowHashChange.bind( this );
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
bind() {
|
||||||
|
|
||||||
|
window.addEventListener( 'hashchange', this.onWindowHashChange, false );
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
unbind() {
|
||||||
|
|
||||||
|
window.removeEventListener( 'hashchange', this.onWindowHashChange, false );
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -27,13 +41,22 @@ export default class Location {
|
||||||
|
|
||||||
// Attempt to parse the hash as either an index or name
|
// Attempt to parse the hash as either an index or name
|
||||||
let bits = hash.slice( 2 ).split( '/' ),
|
let bits = hash.slice( 2 ).split( '/' ),
|
||||||
name = hash.replace( /#|\//gi, '' );
|
name = hash.replace( /#\/?/gi, '' );
|
||||||
|
|
||||||
// If the first bit is not fully numeric and there is a name we
|
// If the first bit is not fully numeric and there is a name we
|
||||||
// can assume that this is a named link
|
// can assume that this is a named link
|
||||||
if( !/^[0-9]*$/.test( bits[0] ) && name.length ) {
|
if( !/^[0-9]*$/.test( bits[0] ) && name.length ) {
|
||||||
let element;
|
let element;
|
||||||
|
|
||||||
|
let f;
|
||||||
|
|
||||||
|
// Parse named links with fragments (#/named-link/2)
|
||||||
|
if( /\/[-\d]+$/g.test( name ) ) {
|
||||||
|
f = parseInt( name.split( '/' ).pop(), 10 );
|
||||||
|
f = isNaN(f) ? undefined : f;
|
||||||
|
name = name.split( '/' ).shift();
|
||||||
|
}
|
||||||
|
|
||||||
// Ensure the named link is a valid HTML ID attribute
|
// Ensure the named link is a valid HTML ID attribute
|
||||||
try {
|
try {
|
||||||
element = document.getElementById( decodeURIComponent( name ) );
|
element = document.getElementById( decodeURIComponent( name ) );
|
||||||
|
@ -45,10 +68,10 @@ export default class Location {
|
||||||
|
|
||||||
if( element ) {
|
if( element ) {
|
||||||
// If the slide exists and is not the current slide...
|
// If the slide exists and is not the current slide...
|
||||||
if ( !isSameNameAsCurrentSlide ) {
|
if ( !isSameNameAsCurrentSlide || typeof f !== 'undefined' ) {
|
||||||
// ...find the position of the named slide and navigate to it
|
// ...find the position of the named slide and navigate to it
|
||||||
let elementIndex = this.Reveal.getIndices(element);
|
let slideIndices = this.Reveal.getIndices( element );
|
||||||
this.Reveal.slide(elementIndex.h, elementIndex.v);
|
this.Reveal.slide( slideIndices.h, slideIndices.v, f );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// If the slide doesn't exist, navigate to the current slide
|
// If the slide doesn't exist, navigate to the current slide
|
||||||
|
@ -141,19 +164,34 @@ export default class Location {
|
||||||
|
|
||||||
// If the current slide has an ID, use that as a named link,
|
// If the current slide has an ID, use that as a named link,
|
||||||
// but we don't support named links with a fragment index
|
// but we don't support named links with a fragment index
|
||||||
if( typeof id === 'string' && id.length && index.f === undefined ) {
|
if( typeof id === 'string' && id.length ) {
|
||||||
url = '/' + id;
|
url = '/' + id;
|
||||||
|
|
||||||
|
// If there is also a fragment, append that at the end
|
||||||
|
// of the named link, like: #/named-link/2
|
||||||
|
if( index.f >= 0 ) url += '/' + index.f;
|
||||||
}
|
}
|
||||||
// Otherwise use the /h/v index
|
// Otherwise use the /h/v index
|
||||||
else {
|
else {
|
||||||
let hashIndexBase = this.Reveal.getConfig().hashOneBasedIndex ? 1 : 0;
|
let hashIndexBase = this.Reveal.getConfig().hashOneBasedIndex ? 1 : 0;
|
||||||
if( index.h > 0 || index.v > 0 || index.f !== undefined ) url += index.h + hashIndexBase;
|
if( index.h > 0 || index.v > 0 || index.f >= 0 ) url += index.h + hashIndexBase;
|
||||||
if( index.v > 0 || index.f !== undefined ) url += '/' + (index.v + hashIndexBase );
|
if( index.v > 0 || index.f >= 0 ) url += '/' + (index.v + hashIndexBase );
|
||||||
if( index.f !== undefined ) url += '/' + index.f;
|
if( index.f >= 0 ) url += '/' + index.f;
|
||||||
}
|
}
|
||||||
|
|
||||||
return url;
|
return url;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handler for the window level 'hashchange' event.
|
||||||
|
*
|
||||||
|
* @param {object} [event]
|
||||||
|
*/
|
||||||
|
onWindowHashChange( event ) {
|
||||||
|
|
||||||
|
this.readURL();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
15
js/reveal.js
15
js/reveal.js
|
@ -490,13 +490,13 @@ export default function( revealElement, options ) {
|
||||||
|
|
||||||
eventsAreBound = true;
|
eventsAreBound = true;
|
||||||
|
|
||||||
window.addEventListener( 'hashchange', onWindowHashChange, false );
|
|
||||||
window.addEventListener( 'resize', onWindowResize, false );
|
window.addEventListener( 'resize', onWindowResize, false );
|
||||||
|
|
||||||
if( config.touch ) touch.bind();
|
if( config.touch ) touch.bind();
|
||||||
if( config.keyboard ) keyboard.bind();
|
if( config.keyboard ) keyboard.bind();
|
||||||
if( config.progress ) progress.bind();
|
if( config.progress ) progress.bind();
|
||||||
controls.bind();
|
controls.bind();
|
||||||
|
location.bind();
|
||||||
|
|
||||||
dom.slides.addEventListener( 'transitionend', onTransitionEnd, false );
|
dom.slides.addEventListener( 'transitionend', onTransitionEnd, false );
|
||||||
dom.pauseOverlay.addEventListener( 'click', resume, false );
|
dom.pauseOverlay.addEventListener( 'click', resume, false );
|
||||||
|
@ -518,8 +518,8 @@ export default function( revealElement, options ) {
|
||||||
keyboard.unbind();
|
keyboard.unbind();
|
||||||
controls.unbind();
|
controls.unbind();
|
||||||
progress.unbind();
|
progress.unbind();
|
||||||
|
location.unbind();
|
||||||
|
|
||||||
window.removeEventListener( 'hashchange', onWindowHashChange, false );
|
|
||||||
window.removeEventListener( 'resize', onWindowResize, false );
|
window.removeEventListener( 'resize', onWindowResize, false );
|
||||||
|
|
||||||
dom.slides.removeEventListener( 'transitionend', onTransitionEnd, false );
|
dom.slides.removeEventListener( 'transitionend', onTransitionEnd, false );
|
||||||
|
@ -2288,17 +2288,6 @@ export default function( revealElement, options ) {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Handler for the window level 'hashchange' event.
|
|
||||||
*
|
|
||||||
* @param {object} [event]
|
|
||||||
*/
|
|
||||||
function onWindowHashChange( event ) {
|
|
||||||
|
|
||||||
location.readURL();
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Handler for the window level 'resize' event.
|
* Handler for the window level 'resize' event.
|
||||||
*
|
*
|
||||||
|
|
|
@ -59,7 +59,7 @@
|
||||||
<iframe data-src="http://example.com"></iframe>
|
<iframe data-src="http://example.com"></iframe>
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
<section>
|
<section id="fragments3">
|
||||||
<h1>3.3</h1>
|
<h1>3.3</h1>
|
||||||
<ul>
|
<ul>
|
||||||
<li class="fragment" data-fragment-index="1">3.3.1</li>
|
<li class="fragment" data-fragment-index="1">3.3.1</li>
|
||||||
|
@ -79,6 +79,8 @@
|
||||||
|
|
||||||
<script src="../dist/reveal.es5.js"></script>
|
<script src="../dist/reveal.es5.js"></script>
|
||||||
<script>
|
<script>
|
||||||
|
window.location.hash = '';
|
||||||
|
|
||||||
// These tests expect the DOM to contain a presentation
|
// These tests expect the DOM to contain a presentation
|
||||||
// with the following slide structure:
|
// with the following slide structure:
|
||||||
//
|
//
|
||||||
|
@ -311,6 +313,70 @@
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
|
// ---------------------------------------------------------------
|
||||||
|
// URL TESTS
|
||||||
|
|
||||||
|
QUnit.module( 'URL' );
|
||||||
|
|
||||||
|
QUnit.test( 'Write (fragmentInURL: false)', function( assert ) {
|
||||||
|
Reveal.configure({ hash: true, fragmentInURL: false });
|
||||||
|
|
||||||
|
Reveal.slide( 2, 0 );
|
||||||
|
assert.strictEqual( window.location.hash, '#/2' );
|
||||||
|
|
||||||
|
Reveal.slide( 2, 1 );
|
||||||
|
assert.strictEqual( window.location.hash, '#/2/1' );
|
||||||
|
|
||||||
|
Reveal.slide( 2, 0, 1 );
|
||||||
|
assert.strictEqual( window.location.hash, '#/2' );
|
||||||
|
|
||||||
|
Reveal.slide( 2, 2, 0 );
|
||||||
|
assert.strictEqual( window.location.hash, '#/fragments3' );
|
||||||
|
|
||||||
|
Reveal.slide( 2, 2, 1 );
|
||||||
|
assert.strictEqual( window.location.hash, '#/fragments3' );
|
||||||
|
});
|
||||||
|
|
||||||
|
QUnit.test( 'Write (fragmentInURL: true)', function( assert ) {
|
||||||
|
Reveal.configure({ hash: true, fragmentInURL: true });
|
||||||
|
|
||||||
|
Reveal.slide( 2, 0, -1 );
|
||||||
|
assert.strictEqual( window.location.hash, '#/2' );
|
||||||
|
|
||||||
|
Reveal.slide( 2, 1, -1 );
|
||||||
|
assert.strictEqual( window.location.hash, '#/2/1' );
|
||||||
|
|
||||||
|
Reveal.slide( 2, 0, 1 );
|
||||||
|
assert.strictEqual( window.location.hash, '#/2/0/1' );
|
||||||
|
|
||||||
|
Reveal.slide( 2, 2, -1 );
|
||||||
|
assert.strictEqual( window.location.hash, '#/fragments3' );
|
||||||
|
|
||||||
|
Reveal.slide( 2, 2, 1 );
|
||||||
|
assert.strictEqual( window.location.hash, '#/fragments3/1' );
|
||||||
|
});
|
||||||
|
|
||||||
|
QUnit.test( 'Read', async function( assert ) {
|
||||||
|
Reveal.configure({ hash: true, fragmentInURL: true });
|
||||||
|
|
||||||
|
let test = function( hash, indices ) {
|
||||||
|
return new Promise( resolve => {
|
||||||
|
window.onhashchange = () => {
|
||||||
|
assert.deepEqual( Reveal.getIndices(), indices );
|
||||||
|
resolve();
|
||||||
|
};
|
||||||
|
window.location.hash = hash;
|
||||||
|
} );
|
||||||
|
}
|
||||||
|
|
||||||
|
await test( '#/0', { h: 0, v: 0, f: undefined } ); // horizontal
|
||||||
|
await test( '#/1/1', { h: 1, v: 1, f: undefined } ); // vertical
|
||||||
|
await test( '#/0/', { h: 0, v: 0, f: undefined } ); // trailing /
|
||||||
|
await test( '#/1/1/', { h: 1, v: 1, f: undefined } ); // trailing /
|
||||||
|
await test( '#/2/0/1', { h: 2, v: 0, f: 1 } ); // fragment
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
// ---------------------------------------------------------------
|
// ---------------------------------------------------------------
|
||||||
// FRAGMENT TESTS
|
// FRAGMENT TESTS
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue