diff --git a/README.md b/README.md index c05b0617..795b02a2 100644 --- a/README.md +++ b/README.md @@ -29,7 +29,7 @@ If you want to spin up an instance and start using immediately, see [Docker depl If you want to contribute to the project, start with [manual deployment](https://hackmd.io/c/codimd-documentation/%2Fs%2Fcodimd-manual-deployment). ### Configuration -CodiMD is highly customizable. Learn about all configuration options of networking, security, performance, resources, privilege, privacy, image storage, and authentication in [CodiMD Configuration](https://hackmd.io/c/codimd-documentation/%2Fs%2Fcodimd-configuration). +CodiMD is highly customizable, learn about all configuration options of networking, security, performance, resources, privilege, privacy, image storage, and authentication in [CodiMD Configuration](https://hackmd.io/c/codimd-documentation/%2Fs%2Fcodimd-configuration). ### Upgrading and Migration Upgrade CodiMD from previous version? See [this guide](https://hackmd.io/c/codimd-documentation/%2Fs%2Fcodimd-upgrade) diff --git a/public/build/reveal.js/plugin/elapsed-time-bar/elapsed-time-bar.js b/public/build/reveal.js/plugin/elapsed-time-bar/elapsed-time-bar.js new file mode 100644 index 00000000..0d7e8b93 --- /dev/null +++ b/public/build/reveal.js/plugin/elapsed-time-bar/elapsed-time-bar.js @@ -0,0 +1,144 @@ +var ElapsedTimeBar = { + // default value + barColor: 'rgb(200,0,0)', + pausedBarColor: 'rgba(200,0,0,.6)', + + isPaused: false, + isFinished: false, + + allottedTime: null, + timeProgressBar: null, + startTime: null, + pauseTime: null, + pauseTimeDuration: 0, + + /** + * initialize elements + */ + handleReady() { + var config = Reveal.getConfig(); + + // activate this plugin if config.allottedTime exists. + if (!config.allottedTime) { + console.warn('Failed to start ElapsedTimeBar plugin. "allottedTime" property is required.'); + return; + } + + // set configurations + this.barColor = config.barColor || this.barColor; + this.pausedBarColor = config.pausedBarColor || this.pausedBarColor; + + // calc barHeight from config.barHeight or page-progress container + var barHeight; + var pageProgressContainer = document.querySelector('.progress'); + if (config.progressBarHeight) { + barHeight = parseInt(config.progressBarHeight, 10) + 'px'; + + // override height of page-progress container + pageProgressContainer && (pageProgressContainer.style.height = barHeight); + } else if (config.progress && pageProgressContainer) { + // get height from page-progress container + barHeight = pageProgressContainer.getBoundingClientRect().height + 'px'; + } else { + // default + barHeight = '3px'; + } + + // create container of time-progress + var timeProgressContainer = document.createElement('div'); + timeProgressContainer.classList.add('progress'); + Object.entries({ + display: 'block', + position: 'fixed', + bottom: config.progress ? barHeight : 0, + width: '100%', + height: barHeight + }).forEach(([k, v]) => { + timeProgressContainer.style[k] = v; + }); + document.querySelector('.reveal').appendChild(timeProgressContainer); + + // create content of time-progress + this.timeProgressBar = document.createElement('div'); + Object.entries({ + height: '100%', + willChange: 'width' + }).forEach(([k, v]) => { + this.timeProgressBar.style[k] = v; + }); + timeProgressContainer.appendChild(this.timeProgressBar); + + // start timer + this.start(config.allottedTime); + }, + + /** + * update repeatedly using requestAnimationFrame. + */ + loop() { + if (this.isPaused) return; + var now = +new Date(); + var elapsedTime = now - this.startTime - this.pauseTimeDuration; + if (elapsedTime > this.allottedTime) { + this.timeProgressBar.style.width = '100%'; + this.isFinished = true; + } else { + this.timeProgressBar.style.width = elapsedTime / this.allottedTime * 100 + '%'; + requestAnimationFrame(this.loop.bind(this)); + } + }, + + /** + * set color of progress bar + */ + setBarColor() { + if (this.isPaused) { + this.timeProgressBar.style.backgroundColor = this.pausedBarColor; + } else { + this.timeProgressBar.style.backgroundColor = this.barColor; + } + }, + + /** + * start(reset) timer with new allotted time. + * @param {number} allottedTime + * @param {number} [elapsedTime=0] + */ + start(allottedTime, elapsedTime = 0) { + this.isFinished = false; + this.isPaused = false; + this.allottedTime = allottedTime; + this.startTime = +new Date() - elapsedTime; + this.pauseTimeDuration = 0; + this.setBarColor(); + this.loop(); + }, + + reset() { + this.start(this.allottedTime); + }, + + pause() { + if (this.isPaused) return; + this.isPaused = true; + this.pauseTime = +new Date(); + this.setBarColor(); + }, + + resume() { + if (!this.isPaused) return; + + // add paused time duration + this.isPaused = false; + this.pauseTimeDuration += new Date() - this.pauseTime; + this.pauseTime = null; + this.setBarColor(); + this.loop(); + } +}; + +if (Reveal.isReady()) { + ElapsedTimeBar.handleReady(); +} else { + Reveal.addEventListener('ready', () => ElapsedTimeBar.handleReady()); +} diff --git a/public/js/slide.js b/public/js/slide.js index 0993e9b2..d3019842 100644 --- a/public/js/slide.js +++ b/public/js/slide.js @@ -77,7 +77,16 @@ var options = meta.slideOptions || {} if (options.hasOwnProperty('spotlight')) { defaultOptions.dependencies.push({ src: `${serverurl}/build/reveal.js/plugin/spotlight/spotlight.js` - }); + }) +} + +if (options.hasOwnProperty('allottedTime') || options.hasOwnProperty('allottedMinutes')) { + defaultOptions.dependencies.push({ + src: `${serverurl}/build/reveal.js/plugin/elapsed-time-bar/elapsed-time-bar.js` + }) + if (options.hasOwnProperty('allottedMinutes')) { + options.allottedTime = options.allottedMinutes * 60 * 1000 + } } const view = $('.reveal')