fragments are now included in URL by default, even on named slides

master
Hakim El Hattab 2020-04-22 11:11:14 +02:00
parent d727509dbc
commit 9823be99f4
9 changed files with 123 additions and 30 deletions

View File

@ -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

4
dist/reveal.es5.js vendored

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

4
dist/reveal.js vendored

File diff suppressed because one or more lines are too long

2
dist/reveal.js.map vendored

File diff suppressed because one or more lines are too long

View File

@ -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

View File

@ -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();
}
} }

View File

@ -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.
* *

View File

@ -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