Right, popup now appears where it should and has the right content.
Tutor sound is playing correctly. Student sound not yet wired up.
This commit is contained in:
parent
4a3bb586a4
commit
4f3b14339f
BIN
resources/public/img/github-logo-transparent.png
Normal file
BIN
resources/public/img/github-logo-transparent.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 7.7 KiB |
File diff suppressed because it is too large
Load diff
82
resources/public/scripts/muharni.js
Normal file
82
resources/public/scripts/muharni.js
Normal file
|
@ -0,0 +1,82 @@
|
|||
/**
|
||||
* muharni.js
|
||||
*
|
||||
* Custom JavaScript functions, some dependent on JQuery, used in the `muharni`
|
||||
* page.
|
||||
*/
|
||||
|
||||
/**
|
||||
* An array for client side sound recordings made by the student. We don't
|
||||
* strictly need one for each short and long character, but it will give a
|
||||
* better experience for people who really get into it.
|
||||
*
|
||||
* There are two tables each of 39 rows and 12 columns, but we're going to
|
||||
* pack both tables into the same array. So the long sounds will be rows 1
|
||||
* to 39 inclusive, and the short from 41 to 79 inclusive.
|
||||
*/
|
||||
const studentSounds = Array(80).fill(0).map(x => Array(13).fill(null));
|
||||
|
||||
|
||||
|
||||
function recordStudentSound() {
|
||||
if (currentCell) {
|
||||
$('#record-student').css('background-color', 'green');
|
||||
navigator.mediaDevices.getUserMedia({ audio: true })
|
||||
.then(stream => {
|
||||
const mediaRecorder = new MediaRecorder(stream);
|
||||
mediaRecorder.start();
|
||||
|
||||
const audioChunks = [];
|
||||
|
||||
mediaRecorder.addEventListener("dataavailable", event => {
|
||||
audioChunks.push(event.data);
|
||||
});
|
||||
|
||||
setTimeout(() => {
|
||||
mediaRecorder.stop();
|
||||
if (audioChunks.length > 0) {
|
||||
studentSounds[currentCell.row][currentCell.col] = new Blob(audioChunks);
|
||||
$('#play-student').prop('disabled', false);
|
||||
}
|
||||
$('#record-student').css('background-color', 'red');
|
||||
|
||||
}, 3000);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* If a student sound has been recorded for the current cell, play it.
|
||||
*/
|
||||
function playStudentSound() {
|
||||
if (currentCell) {
|
||||
if (studentSounds[currentCell.row][currentCell.col] != null) {
|
||||
new Audio(URL.createObjectURL(studentSounds[currentCell.row][currentCell.col])).play();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
$(document).ready(function() {
|
||||
$(".entry").on("click", function(e) {
|
||||
let cellId = e.currentTarget ? e.currentTarget.id : null;
|
||||
|
||||
if (cellId)
|
||||
{
|
||||
$("#popup").css({
|
||||
'left': e.pageX,
|
||||
'top': e.pageY
|
||||
});
|
||||
|
||||
$("#character").text(e.currentTarget.innerText);
|
||||
|
||||
$("#play-tutor").off("click"); /* trying to remove any previous click handler */
|
||||
$("#play-tutor").on("click", function(e){
|
||||
let audioUrl = "audio/" + cellId.slice(1) + ".mp3";
|
||||
new Audio( audioUrl).play();
|
||||
});
|
||||
|
||||
$("#popup").show();
|
||||
}
|
||||
});
|
||||
})
|
|
@ -50,4 +50,5 @@ th {
|
|||
position: absolute;
|
||||
display: none;
|
||||
background-color: whitesmoke;
|
||||
z-index: 10;
|
||||
}
|
|
@ -83,25 +83,28 @@
|
|||
"Emit a table cell describing one entry from entries with either the
|
||||
long or short audio clip available on click. "
|
||||
[^Integer row ^Integer col ^Boolean long?]
|
||||
(let [audio (format
|
||||
"audio/%02d%s.mp3"
|
||||
(inc row)
|
||||
((columns col) (if long? :upper-latin :lower-latin)))
|
||||
(let [r (inc row)
|
||||
c ((columns col) (if long? :upper-latin :lower-latin))
|
||||
audio (format "audio/%02d%s.mp3" r c)
|
||||
char ((entries row) col)]
|
||||
(vector :td {:class "entry"
|
||||
|
||||
:onclick (format
|
||||
"showPopup( '%s', '%s', '%s', '%s')"
|
||||
(if long? row (+ row 40))
|
||||
col
|
||||
char
|
||||
audio)}
|
||||
:id (format "%s%02d%s" (if long? "l" "s") r c)
|
||||
;; :onclick (format
|
||||
;; "showPopup( '%s', '%s', '%s', '%s')"
|
||||
;; (if long? row (+ row 40))
|
||||
;; col
|
||||
;; char
|
||||
;; audio)
|
||||
}
|
||||
;; (audio row col long?)
|
||||
char)))
|
||||
char)))
|
||||
|
||||
;; (entry-cell 3 4 true)
|
||||
|
||||
(defn all-entries-cell
|
||||
"Return a table cell which plays the sound for all entries in the specified
|
||||
`row`, concatenated from left to right if `ltr?` is true else right to left,
|
||||
and playing long recordings if `long?` is true else short recordings."
|
||||
[^Integer row ^Boolean ltr? ^Boolean long?]
|
||||
[:td {:class "play-row"
|
||||
:onclick (format "new Audio('audio/%s%s%02d_MP3WRAP.mp3').play();"
|
||||
|
@ -112,6 +115,8 @@
|
|||
|
||||
|
||||
(defn entries-row
|
||||
"Return a table row for the specified `row` number for long recordings if
|
||||
`long?` is true else short recordings."
|
||||
[^Integer row ^Boolean long?]
|
||||
(apply vector
|
||||
(concat [:tr]
|
||||
|
@ -122,9 +127,10 @@
|
|||
;; (entries-row 3 true)
|
||||
|
||||
(defn col-header-cell
|
||||
[^Integer col]
|
||||
"Return a header cell for the indicated `column`."
|
||||
[^Integer column]
|
||||
(vector :th
|
||||
(:name (columns col))))
|
||||
(:name (columns column))))
|
||||
|
||||
(defn col-headers-row
|
||||
[]
|
||||
|
@ -136,19 +142,21 @@
|
|||
;; (col-headers-row)
|
||||
|
||||
(defn play-column-row
|
||||
"Return a table row of cells which play concatenated sounds for each column,
|
||||
concatenating from top to bottom is `ttb?` is true, else bottom to top, and
|
||||
playing long recordings if `long?` is true else short recordings."
|
||||
[^Boolean ttb? ^Boolean long?]
|
||||
(apply vector
|
||||
(concat [:tr]
|
||||
[[:td]]
|
||||
(map #(vector
|
||||
:td {:class "play-column"
|
||||
:onclick
|
||||
:onclick
|
||||
(format
|
||||
"new Audio('audio/%s%s%s_MP3WRAP.mp3').play();"
|
||||
(if ttb? "ttb" "btt")
|
||||
(if long? "long" "short")
|
||||
((columns %) (if long? :upper-latin :lower-latin)))
|
||||
}
|
||||
"new Audio('audio/%s%s%s_MP3WRAP.mp3').play();"
|
||||
(if ttb? "ttb" "btt")
|
||||
(if long? "long" "short")
|
||||
((columns %) (if long? :upper-latin :lower-latin)))}
|
||||
(str "Play " (if ttb? "down" "up")))
|
||||
(range (count columns)))
|
||||
[[:td]])))
|
||||
|
@ -156,6 +164,8 @@
|
|||
;; (play-column-row true true)
|
||||
|
||||
(defn table
|
||||
"Lay out a muharni table, playing long recordings if `long?` is true else
|
||||
short recordings."
|
||||
[^Boolean long?]
|
||||
(apply
|
||||
vector
|
||||
|
@ -171,6 +181,7 @@
|
|||
;; (table true)
|
||||
|
||||
(defn page
|
||||
"Construct the complete muharni tables page."
|
||||
[title]
|
||||
[:html
|
||||
[:head
|
||||
|
@ -183,19 +194,19 @@
|
|||
:src "scripts/muharni.js"}]
|
||||
[:title (str title)]]
|
||||
[:body {:id "body"}
|
||||
[:div {:id "popup"
|
||||
[:div {:id "popup"
|
||||
:onmouseout "hidePopup();"
|
||||
:style "display: none; border: thin solid gray; width: 10%"}
|
||||
[:p {:id "character" :style "text-align: center; margin: 0; font-size: 4em;"} "?"]
|
||||
[:table {:id "controls" :summary "Controls for audio playback and recording"}
|
||||
[:tr
|
||||
[:th "Tutor"]
|
||||
[:td {:id "play-tutor"} [:button {:onclick "playTutorSound();"}
|
||||
[:td [:button {:id "play-tutor"}
|
||||
"►"]]]
|
||||
[:tr
|
||||
[:th "You"]
|
||||
[:td {:id "play-student"} [:button {:onclick "playStudentSound();"} "►"]]
|
||||
[:td {:id "record-stop"} [:button {:onclick "recordStudentSound();"} "⏺"]]]]]
|
||||
[:td [:button {:id "play-student"} "►"]]
|
||||
[:td [:button {:id "record-stop"} "⏺"]]]]]
|
||||
[:h1 (str title)]
|
||||
[:button {:onclick "var l = document.getElementById('long');
|
||||
var s = document.getElementById('short');
|
||||
|
@ -223,9 +234,7 @@
|
|||
[:a {:href "https://github.com/simon-brooke/muharni"} "GitHub"]]]]])
|
||||
|
||||
(defn tidy-page
|
||||
"Reads HTML as a string, emits cleaned-up HTML as a string. This is not yet
|
||||
working with HTML as produced by Hiccup, since Hiccup is currently
|
||||
entitifying single quotes within (JavaScript) strings."
|
||||
"Reads HTML from `page` as a string, returns cleaned-up HTML as a string."
|
||||
[^String page]
|
||||
(let [tidy (Tidy.)
|
||||
props (doto (Properties.)
|
||||
|
@ -239,14 +248,13 @@
|
|||
;; (set! (. config indentContent) true)
|
||||
;; (set! (. config smartIndent) true)
|
||||
(doto (.getConfiguration tidy) (.addProps props) (.adjust))
|
||||
(.parse tidy (input-stream (.getBytes page))
|
||||
;; NOTE: Hiccup is currently entitifying single quotes within
|
||||
;; (JavaScript) strings. This is NOT desirable behaviour!
|
||||
(.parse tidy (input-stream (.getBytes (s/replace page #"\'" "'")))
|
||||
output)
|
||||
(.toString output)))
|
||||
(str "<!DOCTYPE html>\n" (.toString output))))
|
||||
|
||||
(spit "resources/public/index.html"
|
||||
(tidy-page
|
||||
(s/replace
|
||||
(str (html
|
||||
;;{:escape-strings? false}
|
||||
(page "Muharni table")))
|
||||
#"\'" "'")))
|
||||
(str (html
|
||||
(page "Muharni table")))))
|
||||
|
|
Loading…
Reference in a new issue