Some user interface improvements
Close control on popup, progress bar when recording.
This commit is contained in:
parent
950eec5fed
commit
353e37cff5
|
@ -16,6 +16,7 @@ src="https://ajax.googleapis.com/ajax/libs/jquery/3.6.0/jquery.min.js"
|
||||||
<body id="body">
|
<body id="body">
|
||||||
<div id="popup"
|
<div id="popup"
|
||||||
style="display: none; border: thin solid gray; width: 10%">
|
style="display: none; border: thin solid gray; width: 10%">
|
||||||
|
<div id="closebox" onclick="$('#popup').hide();">✖</div>
|
||||||
<p id="character"
|
<p id="character"
|
||||||
style="text-align: center; margin: 0; font-size: 4em;">?</p>
|
style="text-align: center; margin: 0; font-size: 4em;">?</p>
|
||||||
<table id="controls"
|
<table id="controls"
|
||||||
|
@ -23,23 +24,26 @@ src="https://ajax.googleapis.com/ajax/libs/jquery/3.6.0/jquery.min.js"
|
||||||
<tr>
|
<tr>
|
||||||
<th>Tutor</th>
|
<th>Tutor</th>
|
||||||
<td>
|
<td>
|
||||||
<button id="play-tutor">►</button>
|
<span id="play-tutor">►</span>
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<th>You</th>
|
<th>You</th>
|
||||||
<td>
|
<td>
|
||||||
<button id="play-student">►</button>
|
<span id="play-student">►</span>
|
||||||
</td>
|
</td>
|
||||||
<td>
|
<td>
|
||||||
<button id="record-stop">⏺</button>
|
<span id="record-stop">⏺</span>
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td colspan="3" id="progress"></td>
|
||||||
|
</tr>
|
||||||
</table>
|
</table>
|
||||||
</div>
|
</div>
|
||||||
<h1>Muharni table</h1>
|
<h1>Muharni table</h1>
|
||||||
<button
|
<button
|
||||||
onclick="var l = document.getElementById('long'); var s = document.getElementById('short'); if (l.style.display == 'none') { l.style.display = 'block'; s.style.display = 'none'; } else { l.style.display = 'none'; s.style.display = 'block'; }">Toggle
|
onclick="var l = document.getElementById('long'); var s = document.getElementById('short'); if (l.style.display == 'none') { l.style.display = 'block'; s.style.display = 'none'; } else { l.style.display = 'none'; s.style.display = 'block'; } $('#popup').hide();">Toggle
|
||||||
short/long</button>
|
short/long</button>
|
||||||
<div id="long" style="display: block;">
|
<div id="long" style="display: block;">
|
||||||
<h2>Long forms</h2>
|
<h2>Long forms</h2>
|
||||||
|
|
|
@ -16,13 +16,57 @@
|
||||||
*/
|
*/
|
||||||
const studentSounds = Array(80).fill(0).map(x => Array(13).fill(null));
|
const studentSounds = Array(80).fill(0).map(x => Array(13).fill(null));
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a progressbar. Adapted from
|
||||||
|
* https://stackoverflow.com/questions/31109581/javascript-timer-progress-bar
|
||||||
|
*
|
||||||
|
* @param id the id of the div we want to transform in a progressbar
|
||||||
|
* @param duration the duration of the timer example: '10s'
|
||||||
|
* @param callback, optional function which is called when the progressbar reaches 0.
|
||||||
|
*/
|
||||||
|
function createProgressbar(id, duration) {
|
||||||
|
// We select the div that we want to turn into a progressbar
|
||||||
|
try {
|
||||||
|
const progressbar = document.getElementById(id);
|
||||||
|
progressbar.className = 'progressbar';
|
||||||
|
|
||||||
|
// We create the div that changes width to show progress
|
||||||
|
let progressbarinner = progressbar.querySelector('.inner');
|
||||||
|
|
||||||
|
if (progressbarinner == null) {
|
||||||
|
progressbarinner = document.createElement('div');
|
||||||
|
progressbarinner.className = 'inner';
|
||||||
|
|
||||||
|
// Now we set the animation parameters
|
||||||
|
progressbarinner.style.animationDuration = duration;
|
||||||
|
|
||||||
|
// Append the progressbar to the main progressbardiv
|
||||||
|
progressbar.appendChild(progressbarinner);
|
||||||
|
}
|
||||||
|
progressbarinner.addEventListener('animationend', () => {
|
||||||
|
while (progressbar.hasChildNodes()) {
|
||||||
|
progressbar.removeChild(progressbar.lastChild);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// When everything is set up we start the animation
|
||||||
|
progressbarinner.style.animationPlayState = 'running';
|
||||||
|
} catch (e) {
|
||||||
|
console.warn("Failed to create progress bar because " +
|
||||||
|
e.message +
|
||||||
|
". This does not, cosmically speaking, matter.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
function recordStudentSound(r, c) {
|
function recordStudentSound(r, c) {
|
||||||
console.info("Entered recordStudentSound for row " + r + ", column " + c);
|
console.info("Entered recordStudentSound for row " + r + ", column " + c);
|
||||||
|
|
||||||
if (Number.isInteger(r) && Number.isInteger(c)) {
|
if (Number.isInteger(r) && Number.isInteger(c)) {
|
||||||
$('#record-student').css('color', 'green');
|
$('#record-stop').css('color', 'green');
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
createProgressbar('progress', '5s');
|
||||||
|
|
||||||
navigator.mediaDevices.getUserMedia({ audio: true })
|
navigator.mediaDevices.getUserMedia({ audio: true })
|
||||||
.then(stream => {
|
.then(stream => {
|
||||||
const mediaRecorder = new MediaRecorder(stream);
|
const mediaRecorder = new MediaRecorder(stream);
|
||||||
|
@ -42,18 +86,19 @@ function recordStudentSound(r, c) {
|
||||||
|
|
||||||
if (audioChunks.length > 0) {
|
if (audioChunks.length > 0) {
|
||||||
studentSounds[r][c] = new Blob(audioChunks);
|
studentSounds[r][c] = new Blob(audioChunks);
|
||||||
|
|
||||||
$('#play-student').prop('disabled', false);
|
$('#play-student').prop('disabled', false);
|
||||||
|
$('#play-student').css('color', 'black');
|
||||||
$("#play-student").on("click", function (e) {
|
$("#play-student").on("click", function (e) {
|
||||||
console.log("Playing student sound for row " + r + ", column " + c);
|
console.log("Playing student sound for row " + r + ", column " + c);
|
||||||
new Audio(URL.createObjectURL(studentSounds[r][c])).play();
|
new Audio(URL.createObjectURL(studentSounds[r][c])).play();
|
||||||
});
|
});
|
||||||
console.log("Successfully recorded student sound for row " + r + ", column " + c);
|
console.log("Successfully recorded student sound for row " + r + ", column " + c);
|
||||||
} else {
|
} else {
|
||||||
console.warn("Failed to record student sound for row " + r + ", column " + c);
|
console.warn("Failed to record student sound for row " + r + ", column " + c);
|
||||||
window.alert("No sound detected. Check your microphone?");
|
window.alert("No sound detected. Check your microphone?");
|
||||||
}
|
}
|
||||||
$('#record-student').css('color', 'red');
|
$('#record-stop').css('color', 'red');
|
||||||
};
|
};
|
||||||
|
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
|
@ -115,7 +160,9 @@ $(document).ready(function () {
|
||||||
});
|
});
|
||||||
|
|
||||||
$("#play-student").off("click");
|
$("#play-student").off("click");
|
||||||
|
$('#play-student').css('color', 'gray');
|
||||||
if (studentAudio != null) {
|
if (studentAudio != null) {
|
||||||
|
$('#play-student').css('color', 'black');
|
||||||
$("#play-student").on("click", function (e) {
|
$("#play-student").on("click", function (e) {
|
||||||
console.log("Playing student sound for row " + row + ", column " + col);
|
console.log("Playing student sound for row " + row + ", column " + col);
|
||||||
new Audio(URL.createObjectURL(studentAudio)).play();
|
new Audio(URL.createObjectURL(studentAudio)).play();
|
||||||
|
|
|
@ -29,11 +29,49 @@ th {
|
||||||
font-size: 3em;
|
font-size: 3em;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.progressbar {
|
||||||
|
width: 80%;
|
||||||
|
margin: 25px auto;
|
||||||
|
border: solid 1px #000;
|
||||||
|
}
|
||||||
|
|
||||||
|
.progressbar .inner {
|
||||||
|
height: 15px;
|
||||||
|
animation: progressbar-countdown;
|
||||||
|
/* Placeholder, this will be updated using javascript */
|
||||||
|
animation-duration: 40s;
|
||||||
|
/* We stop in the end */
|
||||||
|
animation-iteration-count: 1;
|
||||||
|
/* Stay on pause when the animation is finished finished */
|
||||||
|
animation-fill-mode: forwards;
|
||||||
|
/* We start paused, we start the animation using javascript */
|
||||||
|
animation-play-state: paused;
|
||||||
|
/* We want a linear animation, ease-out is standard */
|
||||||
|
animation-timing-function: linear;
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes progressbar-countdown {
|
||||||
|
0% {
|
||||||
|
width: 100%;
|
||||||
|
background: #0F0;
|
||||||
|
}
|
||||||
|
|
||||||
|
100% {
|
||||||
|
width: 0%;
|
||||||
|
background: #F00;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#bug {
|
#bug {
|
||||||
width: 1em;
|
width: 1em;
|
||||||
height: 1em;
|
height: 1em;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#closebox {
|
||||||
|
color: red;
|
||||||
|
float: right;
|
||||||
|
}
|
||||||
|
|
||||||
#footer {
|
#footer {
|
||||||
margin-top: 2em;
|
margin-top: 2em;
|
||||||
border-top: thin solid gray;
|
border-top: thin solid gray;
|
||||||
|
@ -51,4 +89,8 @@ th {
|
||||||
display: none;
|
display: none;
|
||||||
background-color: whitesmoke;
|
background-color: whitesmoke;
|
||||||
z-index: 10;
|
z-index: 10;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#record-stop {
|
||||||
|
color: red;
|
||||||
|
}
|
||||||
|
|
|
@ -4,7 +4,7 @@
|
||||||
(:require [hiccup.core :refer [html]]
|
(:require [hiccup.core :refer [html]]
|
||||||
[clojure.java.io :refer [input-stream]]
|
[clojure.java.io :refer [input-stream]]
|
||||||
[clojure.string :as s])
|
[clojure.string :as s])
|
||||||
(:import [java.io StringWriter PrintWriter]
|
(:import [java.io StringWriter]
|
||||||
[java.util Properties]
|
[java.util Properties]
|
||||||
[org.w3c.tidy Tidy]))
|
[org.w3c.tidy Tidy]))
|
||||||
|
|
||||||
|
@ -192,16 +192,20 @@
|
||||||
[:body {:id "body"}
|
[:body {:id "body"}
|
||||||
[:div {:id "popup"
|
[:div {:id "popup"
|
||||||
:style "display: none; border: thin solid gray; width: 10%"}
|
:style "display: none; border: thin solid gray; width: 10%"}
|
||||||
|
[:div {:id "closebox"
|
||||||
|
:onclick "$('#popup').hide();"} "✖"]
|
||||||
[:p {:id "character" :style "text-align: center; margin: 0; font-size: 4em;"} "?"]
|
[:p {:id "character" :style "text-align: center; margin: 0; font-size: 4em;"} "?"]
|
||||||
[:table {:id "controls" :summary "Controls for audio playback and recording"}
|
[:table {:id "controls" :summary "Controls for audio playback and recording"}
|
||||||
[:tr
|
[:tr
|
||||||
[:th "Tutor"]
|
[:th "Tutor"]
|
||||||
[:td [:button {:id "play-tutor"}
|
[:td [:span {:id "play-tutor"}
|
||||||
"►"]]]
|
"►"]]]
|
||||||
[:tr
|
[:tr
|
||||||
[:th "You"]
|
[:th "You"]
|
||||||
[:td [:button {:id "play-student"} "►"]]
|
[:td [:span {:id "play-student"} "►"]]
|
||||||
[:td [:button {:id "record-stop"} "⏺"]]]]]
|
[:td [:span {:id "record-stop"} "⏺"]]]
|
||||||
|
[:tr
|
||||||
|
[:td {:colspan 3 :id "progress"}]]]]
|
||||||
[:h1 (str title)]
|
[:h1 (str title)]
|
||||||
[:button {:onclick "var l = document.getElementById('long');
|
[:button {:onclick "var l = document.getElementById('long');
|
||||||
var s = document.getElementById('short');
|
var s = document.getElementById('short');
|
||||||
|
@ -211,7 +215,8 @@
|
||||||
} else {
|
} else {
|
||||||
l.style.display = 'none';
|
l.style.display = 'none';
|
||||||
s.style.display = 'block';
|
s.style.display = 'block';
|
||||||
}"} "Toggle short/long"]
|
}
|
||||||
|
$('#popup').hide();"} "Toggle short/long"]
|
||||||
[:div {:id "long"
|
[:div {:id "long"
|
||||||
:style "display: block;"}
|
:style "display: block;"}
|
||||||
[:h2 "Long forms"]
|
[:h2 "Long forms"]
|
||||||
|
|
Loading…
Reference in a new issue