blob: ba124c0d9023e02a30e682ca78db465c33eebee9 [file] [log] [blame]
Christophe Dervieuxe1893ae2021-10-07 17:09:02 +02001/**
2 * Handles the display of reveal.js' optional slide number.
3 */
4export default class SlideNumber {
5
6 constructor( Reveal ) {
7
8 this.Reveal = Reveal;
9
10 }
11
12 render() {
13
14 this.element = document.createElement( 'div' );
15 this.element.className = 'slide-number';
16 this.Reveal.getRevealElement().appendChild( this.element );
17
18 }
19
20 /**
21 * Called when the reveal.js config is updated.
22 */
23 configure( config, oldConfig ) {
24
25 let slideNumberDisplay = 'none';
26 if( config.slideNumber && !this.Reveal.isPrintingPDF() ) {
27 if( config.showSlideNumber === 'all' ) {
28 slideNumberDisplay = 'block';
29 }
30 else if( config.showSlideNumber === 'speaker' && this.Reveal.isSpeakerNotes() ) {
31 slideNumberDisplay = 'block';
32 }
33 }
34
35 this.element.style.display = slideNumberDisplay;
36
37 }
38
39 /**
40 * Updates the slide number to match the current slide.
41 */
42 update() {
43
44 // Update slide number if enabled
45 if( this.Reveal.getConfig().slideNumber && this.element ) {
46 this.element.innerHTML = this.getSlideNumber();
47 }
48
49 }
50
51 /**
52 * Returns the HTML string corresponding to the current slide
53 * number, including formatting.
54 */
55 getSlideNumber( slide = this.Reveal.getCurrentSlide() ) {
56
57 let config = this.Reveal.getConfig();
58 let value;
59 let format = 'h.v';
60
61 if ( typeof config.slideNumber === 'function' ) {
62 value = config.slideNumber( slide );
63 } else {
64 // Check if a custom number format is available
65 if( typeof config.slideNumber === 'string' ) {
66 format = config.slideNumber;
67 }
68
69 // If there are ONLY vertical slides in this deck, always use
70 // a flattened slide number
71 if( !/c/.test( format ) && this.Reveal.getHorizontalSlides().length === 1 ) {
72 format = 'c';
73 }
74
75 // Offset the current slide number by 1 to make it 1-indexed
76 let horizontalOffset = slide && slide.dataset.visibility === 'uncounted' ? 0 : 1;
77
78 value = [];
79 switch( format ) {
80 case 'c':
81 value.push( this.Reveal.getSlidePastCount( slide ) + horizontalOffset );
82 break;
83 case 'c/t':
84 value.push( this.Reveal.getSlidePastCount( slide ) + horizontalOffset, '/', this.Reveal.getTotalSlides() );
85 break;
86 default:
87 let indices = this.Reveal.getIndices( slide );
88 value.push( indices.h + horizontalOffset );
89 let sep = format === 'h/v' ? '/' : '.';
90 if( this.Reveal.isVerticalSlide( slide ) ) value.push( sep, indices.v + 1 );
91 }
92 }
93
94 let url = '#' + this.Reveal.location.getHash( slide );
95 return this.formatNumber( value[0], value[1], value[2], url );
96
97 }
98
99 /**
100 * Applies HTML formatting to a slide number before it's
101 * written to the DOM.
102 *
103 * @param {number} a Current slide
104 * @param {string} delimiter Character to separate slide numbers
105 * @param {(number|*)} b Total slides
106 * @param {HTMLElement} [url='#'+locationHash()] The url to link to
107 * @return {string} HTML string fragment
108 */
109 formatNumber( a, delimiter, b, url = '#' + this.Reveal.location.getHash() ) {
110
111 if( typeof b === 'number' && !isNaN( b ) ) {
112 return `<a href="${url}">
113 <span class="slide-number-a">${a}</span>
114 <span class="slide-number-delimiter">${delimiter}</span>
115 <span class="slide-number-b">${b}</span>
116 </a>`;
117 }
118 else {
119 return `<a href="${url}">
120 <span class="slide-number-a">${a}</span>
121 </a>`;
122 }
123
124 }
125
126}