14686
14686
<img alt="View repo on GitHub" src="https://img.shields.io/badge/view-repo-orange?logo=github" style="max-width: 100%; margin: 20px 0 0 0;">
14687
14687
</a>
14688
14688
</div>
14689
+ <!-- here's an alternate clock location under title
14690
+ <div class="clock" style="margin-right: 5px; position: absolute; top: 40px;"></div>
14691
+ -->
14692
+ <div class="clock" style="margin-right: 5px; float: right;"></div>
14689
14693
</div>
14690
14694
<div class="slides"><section ><section >
14691
14695
<div class="jp-Cell jp-MarkdownCell jp-Notebook-cell">
@@ -14778,7 +14782,8 @@ <h2 id="Let's-get-started">Let's get started<a class="anchor-link" href="#Let's-
14778
14782
},
14779
14783
[
14780
14784
"https://unpkg.com/reveal.js@4.0.2/dist/reveal.js",
14781
- "https://unpkg.com/reveal.js@4.0.2/plugin/notes/notes.js"
14785
+ "https://unpkg.com/reveal.js@4.0.2/plugin/notes/notes.js",
14786
+ "https://cdn.jsdelivr.net/npm/luxon@3.2.1/build/global/luxon.min.js"
14782
14787
],
14783
14788
14784
14789
function(Reveal, RevealNotes){
@@ -14801,9 +14806,7 @@ <h2 id="Let's-get-started">Let's get started<a class="anchor-link" href="#Let's-
14801
14806
}
14802
14807
});
14803
14808
14804
- function isVisible(display) {
14805
- return display === 'none' ? 'block' : 'none';
14806
- }
14809
+ const isVisible = (display) => display === 'none' ? 'block' : 'none';
14807
14810
14808
14811
// add custom controls
14809
14812
Reveal.addKeyBinding(
@@ -14836,6 +14839,120 @@ <h2 id="Let's-get-started">Let's get started<a class="anchor-link" href="#Let's-
14836
14839
}
14837
14840
);
14838
14841
14842
+ // for working with dates/times
14843
+ const { DateTime, Duration } = luxon;
14844
+
14845
+ // add exercise timer
14846
+ let updateExerciseTimerInterval;
14847
+ Reveal.addKeyBinding(
14848
+ { keyCode: 84, key: "T", description: "Start the exercise timer" },
14849
+ () => {
14850
+ let exerciseTime = prompt("Timer duration in minutes (leave empty to cancel)");
14851
+ const cleanup = () => {
14852
+ clearInterval(updateExerciseTimerInterval);
14853
+ $('.exercise-timer').remove();
14854
+ }
14855
+ if (exerciseTime !== undefined && exerciseTime !== "" && exerciseTime !== null){
14856
+ if (!isNaN(exerciseTime) && exerciseTime >= 0.1) {
14857
+ exerciseTime = Duration.fromMillis(exerciseTime * 60 * 1000);
14858
+ const countDownTime = DateTime.now().plus(exerciseTime);
14859
+
14860
+ const getTimeText = (elapsedTime) => `⏱ ${elapsedTime.toFormat('mm:ss')}`;
14861
+
14862
+ if ($('.exercise-timer').length === 0) { // add to DOM if not already there
14863
+ $('.reveal').append(
14864
+ `<aside class="exercise-timer" style="display: block; position: absolute; `
14865
+ + `top: auto; left: 15px; right: auto; bottom: 36px;`
14866
+ + `font-size: 50px;"></aside>`
14867
+ );
14868
+ }
14869
+
14870
+ // in case the key is pressed while a timer is already running, clear the old one
14871
+ if (!isNaN(updateExerciseTimerInterval)) clearInterval(updateExerciseTimerInterval);
14872
+
14873
+ // write the starting time minus the 1 second delay before the update
14874
+ const updateFrequency = 1000;
14875
+ $('.exercise-timer').text(getTimeText(exerciseTime.minus({ milliseconds: updateFrequency })));
14876
+
14877
+ // update the remaining time each second
14878
+ const updateTimer = () => {
14879
+ const now = DateTime.now();
14880
+ const elapsedTime = countDownTime.diff(now);
14881
+ const secondsRemaining = elapsedTime.as('seconds')
14882
+
14883
+ if (secondsRemaining >= 1) $('.exercise-timer').text(getTimeText(elapsedTime));
14884
+ else if (secondsRemaining >= 0) {
14885
+ $('.exercise-timer').text(getTimeText(Duration.fromMillis(0)));
14886
+ const audio = new Audio('../../media/time_is_up.m4a'); // TODO: switch to URL of hosted version
14887
+ audio.play();
14888
+ }
14889
+ else if (secondsRemaining >= -5) $('.exercise-timer').text("TIME'S UP").css('color', 'red');
14890
+ else cleanup();
14891
+ }
14892
+ updateExerciseTimerInterval = setInterval(updateTimer, updateFrequency);
14893
+ }
14894
+ }
14895
+ else cleanup();
14896
+ }
14897
+ );
14898
+
14899
+ // add clock
14900
+ let updateClockInterval;
14901
+ Reveal.addKeyBinding(
14902
+ { keyCode: 67, key: "C", description: "Toggle the clock" },
14903
+ () => {
14904
+ if (!isNaN(updateClockInterval)) {
14905
+ clearInterval(updateClockInterval);
14906
+ $('.clock').text('');
14907
+ updateClockInterval = 'cleared';
14908
+ }
14909
+ else {
14910
+ const updateTime = () => $('.clock').text(DateTime.now().toFormat('hh:mm a'));
14911
+ updateTime();
14912
+ updateClockInterval = setInterval(updateTime, 1000);
14913
+ }
14914
+ }
14915
+ );
14916
+
14917
+ // show clock in red when 5 minutes from desired time
14918
+ let updateFMWInterval;
14919
+ Reveal.addKeyBinding(
14920
+ { keyCode: 90, key: "Z", description: "Set 5-minute warning" },
14921
+ () => {
14922
+ const input = prompt("What is the ending time? (leave empty to clear)");
14923
+ const cleanup = () => {
14924
+ clearInterval(updateFMWInterval);
14925
+ $('.clock').text('').css('color', 'black');
14926
+ updateFMWInterval = 'cleared';
14927
+ }
14928
+ if (input !== undefined && input !== "" && input !== null && input.includes(':')){
14929
+
14930
+ if (!isNaN(updateFMWInterval)) cleanup();
14931
+
14932
+ const [time, ampm] = input.split(' ');
14933
+ let [endHour, endMinute] = time.split(':').map((x) => parseInt(x));
14934
+ const militaryTime = ampm === undefined;
14935
+ let shiftHours = militaryTime ? 0 : (ampm.toLowerCase() === 'pm' ? 12 : 0);
14936
+
14937
+ const endAt = DateTime.now().startOf('minute').set({
14938
+ hour: endHour + shiftHours,
14939
+ minute: endMinute
14940
+ });
14941
+ const warnAt = endAt.minus({ minutes: 5 });
14942
+
14943
+ const checkTime = () => {
14944
+ const now = DateTime.now();
14945
+ if (now >= endAt) cleanup();
14946
+ else if (now >= warnAt) {
14947
+ $('.clock').text(now.toFormat('hh:mm a')).css('color', 'red');
14948
+ }
14949
+ }
14950
+ updateFMWInterval = setInterval(checkTime, 1000);
14951
+ }
14952
+ else cleanup();
14953
+ }
14954
+ );
14955
+
14839
14956
var update = function(event){
14840
14957
if(MathJax.Hub.getAllJax(Reveal.getCurrentSlide())){
14841
14958
MathJax.Hub.Rerender(Reveal.getCurrentSlide());
0 commit comments