source: main/trunk/greenstone3/web/interfaces/default/js/utility_scripts.js@ 36906

Last change on this file since 36906 was 36906, checked in by kjdon, 18 months ago

check whether TKMetadataURL is defined before using it - get success result when doing ajax url to undefined.

File size: 25.6 KB
Line 
1/** JavaScript file of utility functions.
2 * At present contains functions for sanitising of URLs,
3 * since tomcat 8+, being more compliant with URL/URI standards, is more strict about URLs.
4 */
5
6/*
7 Given a string consisting of a single character, returns the %hex (%XX)
8 https://www.w3resource.com/javascript-exercises/javascript-string-exercise-27.php
9 https://stackoverflow.com/questions/40100096/what-is-equivalent-php-chr-and-ord-functions-in-javascript
10 https://www.w3resource.com/javascript-exercises/javascript-string-exercise-27.php
11*/
12function urlEncodeChar(single_char_string) {
13 /*var hex = Number(single_char_string.charCodeAt(0)).toString(16);
14 var str = "" + hex;
15 str = "%" + str.toUpperCase();
16 return str;
17 */
18
19 var hex = "%" + Number(single_char_string.charCodeAt(0)).toString(16).toUpperCase();
20 return hex;
21}
22
23/*
24 Tomcat 8 appears to be stricter in requiring unsafe and reserved chars
25 in URLs to be escaped with URL encoding
26 See section "Character Encoding Chart of
27 https://perishablepress.com/stop-using-unsafe-characters-in-urls/
28 Reserved chars:
29 ; / ? : @ = &
30 -----> %3B %2F %3F %3A %40 %3D %26
31 [Now also reserved, but no special meaning yet in URLs (https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/encodeURIComponent)
32 and not required to be enforced yet, so we're aren't at present dealing with these:
33 ! ' ( ) *
34 ]
35 Unsafe chars:
36 " < > # % { } | \ ^ ~ [ ] ` and SPACE/BLANK
37 ----> %22 %3C %3E %23 %25 %7B %7D %7C %5C %5E ~ %5B %5D %60 and %20
38 But the above conflicts with the reserved vs unreserved listings at
39 https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/encodeURI
40 Possibly more info: https://stackoverflow.com/questions/1547899/which-characters-make-a-url-invalid
41
42 And the bottom of https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/encodeURIComponent
43 lists additional characters that have been reserved since and which need encoding when in a URL component.
44
45 Javascript already provides functions encodeURI() and encodeURIComponent(), see https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/encodeURI
46 However, the set of chars they deal with only partially overlap with the set of chars that need encoding as per the RFC3986 for URIs and RFC1738 for URLs discussed at
47 https://perishablepress.com/stop-using-unsafe-characters-in-urls/
48 We want to handle all the characters listed as unsafe and reserved at https://perishablepress.com/stop-using-unsafe-characters-in-urls/
49 so we define and use our own conceptually equivalent methods for both existing JavaScript methods:
50 - makeSafeURL() for Javascript's encodeURI() to make sure all unsafe characters in URLs are escaped by being URL encoded
51 - and makeSafeURLComponent() for JavaScript's encodeURIComponent to additionally make sure all reserved characters in a URL portion are escaped by being URL encoded too
52
53 Function makeSafeURL() is passed a string that represents a URL and therefore only deals with characters that are unsafe in a URL and which therefore require escaping.
54 Function makeSafeURLComponent() deals with portions of a URL that when decoded need not represent a URL at all, for example data like inline templates passed in as a
55 URL query string's parameter values. As such makeSafeURLComponent() should escape both unsafe URL characters and characters that are reserved in URLs since reserved
56 characters in the query string part (as query param values representing data) may take on a different meaning from their reserved meaning in a URL context.
57*/
58
59/* URL encodes both
60 - UNSAFE characters to make URL safe, by calling makeSafeURL()
61 - and RESERVED characters (characters that have reserved meanings within a URL) to make URL valid, since the url component parameter could use reserved characters
62 in a non-URL sense. For example, the inline template (ilt) parameter value of a URL could use '=' and '&' signs where these would have XSLT rather than URL meanings.
63
64 See end of https://www.w3schools.com/jsref/jsref_replace.asp to use a callback passing each captured element of a regex in str.replace()
65*/
66function makeURLComponentSafe(url_part, encode_percentages) {
67 // https://stackoverflow.com/questions/12797118/how-can-i-declare-optional-function-parameters-in-javascript
68 encode_percentages = encode_percentages || 1; // this method forces the URL-encoding of any % in url_part, e.g. do this for inline-templates that haven't ever been encoded
69
70 var url_encoded = makeURLSafe(url_part, encode_percentages);
71 //return url_encoded.replace(/;/g, "%3B").replace(/\//g, "%2F").replace(/\?/g, "%3F").replace(/\:/g, "%3A").replace(/\@/g, "%40").replace(/=/g, "%3D").replace(/\&/g,"%26");
72 url_encoded = url_encoded.replace(/[\;\/\?\:\@\=\&]/g, function(s) {
73 return urlEncodeChar(s);
74 });
75 return url_encoded;
76}
77
78/*
79 URL encode UNSAFE characters to make URL passed in safe.
80 Set encode_percentages to 1 (true) if you don't want % signs encoded: you'd do so if the url is already partly URL encoded.
81*/
82function makeURLSafe(url, encode_percentages) {
83 encode_percentages = encode_percentages || 0; // https://stackoverflow.com/questions/12797118/how-can-i-declare-optional-function-parameters-in-javascript
84
85 var url_encoded = url;
86 if(encode_percentages) { url_encoded = url_encoded.replace(/\%/g,"%25"); } // encode % first
87 //url_encoded = url_encoded.replace(/ /g, "%20").replace(/\"/g,"%22").replace(/\</g,"%3C").replace(/\>/g,"%3E").replace(/\#/g,"%23").replace(/\{/g,"%7B").replace(/\}/g,"%7D");
88 //url_encoded = url_encoded.replace(/\|/g,"%7C").replace(/\\/g,"%5C").replace(/\^/g,"%5E").replace(/\[/g,"%5B").replace(/\]/g,"%5D").replace(/\`/g,"%60");
89 // Should we handle ~, but then what is its URL encoded value? Because https://meyerweb.com/eric/tools/dencoder/ URLencodes ~ to ~.
90 //return url_encoded;
91 url_encoded = url_encoded.replace(/[\ \"\<\>\#\{\}\|\\^\~\[\]\`]/g, function(s) {
92 return urlEncodeChar(s);
93 });
94 return url_encoded;
95}
96
97/***************
98* MENU SCRIPTS *
99***************/
100function moveScroller() {
101 var move = function() {
102 var editbar = $("#editBar");
103 var st = $(window).scrollTop();
104 var fa = $("#float-anchor").offset().top;
105 if(st > fa) {
106
107 editbar.css({
108 position: "fixed",
109 top: "0px",
110 width: editbar.data("width"),
111 //width: "30%"
112 });
113 } else {
114 editbar.data("width", editbar.css("width"));
115 editbar.css({
116 position: "relative",
117 top: "",
118 width: ""
119 });
120 }
121 };
122 $(window).scroll(move);
123 move();
124}
125
126
127function floatMenu(enabled)
128{
129 var menu = $(".tableOfContentsContainer");
130 if(enabled)
131 {
132 menu.data("position", menu.css("position"));
133 menu.data("width", menu.css("width"));
134 menu.data("right", menu.css("right"));
135 menu.data("top", menu.css("top"));
136 menu.data("max-height", menu.css("max-height"));
137 menu.data("overflow", menu.css("overflow"));
138 menu.data("z-index", menu.css("z-index"));
139
140 menu.css("position", "fixed");
141 menu.css("width", "300px");
142 menu.css("right", "0px");
143 menu.css("top", "100px");
144 menu.css("max-height", "600px");
145 menu.css("overflow", "auto");
146 menu.css("z-index", "200");
147
148 $("#unfloatTOCButton").show();
149 }
150 else
151 {
152 menu.css("position", menu.data("position"));
153 menu.css("width", menu.data("width"));
154 menu.css("right", menu.data("right"));
155 menu.css("top", menu.data("top"));
156 menu.css("max-height", menu.data("max-height"));
157 menu.css("overflow", menu.data("overflow"));
158 menu.css("z-index", menu.data("z-index"));
159
160 $("#unfloatTOCButton").hide();
161 $("#floatTOCToggle").prop("checked", false);
162 }
163
164 var url = gs.xsltParams.library_name + "?a=d&ftoc=" + (enabled ? "1" : "0") + "&c=" + gs.cgiParams.c;
165
166 $.ajax(url);
167}
168
169// TK Label Scripts
170
171var tkMetadataSetStatus = "needs-to-be-loaded";
172var tkMetadataElements = null;
173
174
175function addTKLabelToImage(labelName, definition, name, comment) {
176 // lists of tkLabels and their corresponding codes, in order
177 let tkLabels = ["Attribution","Clan","Family","MultipleCommunities","CommunityVoice","Creative","Verified","NonVerified","Seasonal","WomenGeneral","MenGeneral",
178 "MenRestricted","WomenRestricted","CulturallySensitive","SecretSacred","OpenToCommercialization","NonCommercial","CommunityUseOnly","Outreach","OpenToCollaboration"];
179 let tkCodes = ["tk_a","tk_cl","tk_f","tk_mc","tk_cv","tk_cr","tk_v","tk_nv","tk_s","tk_wg","tk_mg","tk_mr","tk_wr","tk_cs","tk_ss","tk_oc","tk_nc","tk_co","tk_o","tk_cb"];
180 for (let i = 0; i < tkLabels.length; i++) {
181 if (labelName == tkLabels[i]) {
182 let labeldiv = document.querySelectorAll(".tklabels img");
183 for (image of labeldiv) {
184 let labelCode = image.src.substr(image.src.lastIndexOf("/") + 1).replace(".png", ""); // get tk label code from image file name
185 if (labelCode == tkCodes[i]) {
186 image.title = "TK " + name + ": " + definition + " Click for more details."; // set tooltip
187 if (image.parentElement.parentElement.parentElement.classList[0] != "tocSectionTitle") { // disable onclick event in favourites section
188 image.addEventListener("click", function(e) {
189 let currPopup = document.getElementsByClassName("tkPopup")[0];
190 if (currPopup == undefined || (currPopup != undefined && currPopup.id != labelCode)) {
191 let popup = document.createElement("div");
192 popup.classList.add("tkPopup");
193 popup.id = labelCode;
194 let popupText = document.createElement("span");
195 let heading = "<h1>Traditional Knowledge Label:<br><h2>" + name + "</h2></h1>";
196 let moreInformation = "<br> For more information about TK Labels, ";
197 let link = document.createElement("a");
198 link.innerHTML = "click here.";
199 link.href = "https://localcontexts.org/labels/traditional-knowledge-labels/";
200 link.target = "_blank";
201 popupText.innerHTML = heading + comment + moreInformation;
202 popupText.appendChild(link);
203 let closeButton = document.createElement("span");
204 closeButton.innerHTML = "&#215;";
205 closeButton.id = "tkCloseButton";
206 closeButton.title = "Click to close window."
207 closeButton.addEventListener("click", function(e) {
208 closeButton.parentElement.remove();
209 });
210 popup.appendChild(closeButton);
211 popup.appendChild(popupText);
212 e.target.parentElement.appendChild(popup);
213 }
214 if (currPopup) currPopup.remove(); // remove existing popup div
215 });
216 }
217 }
218 }
219 }
220 }
221}
222
223function addTKLabelsToImages(lang) {
224 if (tkMetadataElements == null) {
225 console.error("ajax call not yet loaded tk label metadata set");
226 } else {
227 for (label of tkMetadataElements) { // for each tklabel element in tk.mds
228 let tkLabelName = label.attributes.name.value; // Element name=""
229 let attributes = label.querySelectorAll("[code=" + lang + "] Attribute"); // gets attributes for selected language
230 let tkName = attributes[0].textContent; // name="label"
231 let tkDefinition = attributes[1].textContent; // name="definition"
232 let tkComment = attributes[2].textContent; // name="comment"
233 addTKLabelToImage(tkLabelName, tkDefinition, tkName, tkComment);
234 }
235 }
236}
237
238function loadTKMetadataSetOld(lang) {
239 tkMetadataSetStatus = "loading";
240 $.ajax({
241 url: gs.variables["tkMetadataURL"],
242 success: function(xml) {
243 tkMetadataSetStatus = "loaded";
244 let parser = new DOMParser();
245 let tkmds = parser.parseFromString(xml, "text/xml");
246 tkMetadataElements = tkmds.querySelectorAll("Element");
247 if (document.readyState === "complete") {
248 addTKLabelsToImages(lang);
249 } else {
250 window.onload = function() {
251 addTKLabelsToImages(lang);
252 }
253 }
254 },
255 error: function() {
256 tkMetadataSetStatus = "no-metadata-set-for-this-collection";
257 console.log("No TK Label Metadata-set found for this collection");
258 }
259 });
260};
261function loadTKMetadataSet(lang, type) {
262 if (gs.variables["tkMetadataURL_"+type] == undefined) {
263 console.error("tkMetadataURL_"+type+" variable is not defined, can't load TK Metadata Set");
264 tkMetadataSetStatus = "no-metadata-set-for-this-"+type;
265 return;
266 }
267 tkMetadataSetStatus = "loading";
268 $.ajax({
269 url: gs.variables["tkMetadataURL_"+type],
270 async: false,
271 success: function(xml) {
272 tkMetadataSetStatus = "loaded";
273 let parser = new DOMParser();
274 let tkmds = parser.parseFromString(xml, "text/xml");
275 tkMetadataElements = tkmds.querySelectorAll("Element");
276 if (document.readyState === "complete") {
277 addTKLabelsToImages(lang);
278 } else {
279 window.onload = function() {
280 addTKLabelsToImages(lang);
281 }
282 }
283 },
284 error: function() {
285 tkMetadataSetStatus = "no-metadata-set-for-this-"+type;
286 console.log("No TK Label Metadata-set found for this "+type);
287 }
288 });
289};
290
291// Audio Scripts for Enriched Playback
292
293function loadAudio(audio, sectionData) {
294 var speakerObjects = [];
295 var uniqueSpeakers;
296 const inputFile = sectionData;
297 var itemType;
298
299 // var accentColour = "#4CA72D";
300 var accentColour = "#F8C537";
301 var regionTransparency = "59";
302
303 var waveformContainer = document.getElementById("waveform");
304
305 var wavesurfer = WaveSurfer.create({ // wavesurfer options
306 container: waveformContainer,
307 backend: "MediaElement",
308 backgroundColor: "rgb(54, 73, 78)",
309 waveColor: "white",
310 progressColor: accentColour,
311 barWidth: 2,
312 barHeight: 1.2,
313 barGap: 2,
314 barRadius: 1,
315 cursorColor: 'black',
316 plugins: [
317 WaveSurfer.regions.create(),
318 WaveSurfer.timeline.create({
319 container: "#wave-timeline",
320 secondaryColor: "white",
321 secondaryFontColor: "white",
322 notchPercentHeight: "0",
323 fontSize: "12"
324 }),
325 WaveSurfer.cursor.create({
326 showTime: true,
327 opacity: 1,
328 customShowTimeStyle: {
329 'background-color': '#000',
330 color: '#fff',
331 padding: '0.2em',
332 'font-size': '12px'
333 },
334 formatTimeCallback: (num) => { return minutize(num); }
335 }),
336 ],
337 });
338
339 wavesurfer.load(audio);
340
341 // wavesurfer events
342
343 wavesurfer.on('region-click', function(region, e) { // play region audio on click
344 e.stopPropagation();
345 handleRegionColours(region, true);
346 wavesurfer.play(region.start); // plays from start of region
347 // region.play(); // plays region only
348 });
349
350 wavesurfer.on('region-mouseenter', function(region) { handleRegionColours(region, true); });
351 wavesurfer.on('region-mouseleave', function(region) { if (!(wavesurfer.getCurrentTime() <= region.end && wavesurfer.getCurrentTime() >= region.start)) handleRegionColours(region, false); });
352 wavesurfer.on('region-in', function(region) {
353 handleRegionColours(region, true);
354 if (itemType == "chapter") {
355 document.getElementById("chapter" + region.id.replace("region", "")).scrollIntoView({
356 behavior: "smooth",
357 block: "nearest"
358 });
359 }
360 });
361 wavesurfer.on('region-out', function(region) { handleRegionColours(region, false); });
362
363 var loader = document.createElement("span"); // loading audio element
364 loader.innerHTML = "Loading audio";
365 loader.id = "waveform-loader";
366 document.querySelector("#waveform wave").prepend(loader);
367
368 wavesurfer.on('waveform-ready', function() { // retrieve regions once waveforms have loaded
369 if (inputFile.endsWith("csv")) { // diarization if csv
370 itemType = "chapter";
371 loadCSVFile(inputFile, ["speaker", "start", "end"]);
372 } else if (inputFile.endsWith("json")) { // transcription if json
373 itemType = "word";
374 loadJSONFile(inputFile);
375 } else {
376 console.log("Filetype of " + inputFile + " not supported.")
377 }
378 loader.remove(); // remove load text
379 });
380
381 function downloadURI(loc, name) {
382 var link = document.createElement("a");
383 link.download = name;
384 link.href = loc;
385 link.click();
386 }
387
388 // toolbar elements & event handlers
389 var chapters = document.getElementById("chapters");
390 var chapterButton = document.getElementById("chapterButton");
391 var backButton = document.getElementById("backButton");
392 var playPauseButton = document.getElementById("playPauseButton");
393 var forwardButton = document.getElementById("forwardButton");
394 var downloadButton = document.getElementById("downloadButton");
395 var muteButton = document.getElementById("muteButton");
396 var zoomSlider = document.getElementById("slider");
397 chapters.style.height = "0px";
398 chapterButton.addEventListener("click", function() { toggleChapters(); });
399 backButton.addEventListener("click", function() { wavesurfer.skipBackward(); });
400 playPauseButton.addEventListener("click", function() { wavesurfer.playPause() });
401 forwardButton.addEventListener("click", function() { wavesurfer.skipForward(); });
402 // audio = /greenstone3/library/sites/localsite/collect/tiriana-audio/index/assoc/HASHa6b7.dir/Te_Kakano_CH09_B.mp3
403 downloadButton.addEventListener("click", function() { downloadURI(audio, audio.split(".dir/")[1]) });
404 muteButton.addEventListener("click", function() { wavesurfer.toggleMute(); });
405 zoomSlider.style["accent-color"] = accentColour;
406
407 // path to toolbar images
408 var interface_bootstrap_images = "interfaces/" + gs.xsltParams.interface_name + "/images/bootstrap/";
409
410 wavesurfer.on("play", function() { playPauseButton.src = interface_bootstrap_images + "pause.svg"; });
411 wavesurfer.on("pause", function() { playPauseButton.src = interface_bootstrap_images + "play.svg"; });
412 wavesurfer.on("mute", function(mute) {
413 if (mute) {
414 muteButton.src = interface_bootstrap_images + "mute.svg";
415 muteButton.style.opacity = 0.6;
416 }
417 else {
418 muteButton.src = interface_bootstrap_images + "unmute.svg";
419 muteButton.style.opacity = 1;
420 }
421 });
422
423 zoomSlider.oninput = function () { // slider changes waveform zoom
424 wavesurfer.zoom(Number(this.value) / 4);
425 };
426 wavesurfer.zoom(zoomSlider.value / 4); // set default zoom point
427
428 var toggleChapters = function() { // show & hide chapter section
429 if (chapters.style.height == "0px") {
430 chapters.style.height = "30vh";
431 } else {
432 chapters.style.height = "0px";
433 }
434 }
435
436 function loadCSVFile(filename, manualHeader) { // based around: https://stackoverflow.com/questions/7431268/how-to-read-data-from-csv-file-using-javascript
437 $.ajax({
438 type: "GET",
439 url: filename,
440 dataType: "text",
441 }).then(function(data) {
442 var dataLines = data.split(/\r\n|\n/);
443 var headers;
444 var startIndex;
445 uniqueSpeakers = []; // used for obtaining unique colours
446 speakerObjects = []; // list of speaker items
447
448 if (manualHeader) { // headers for columns can be provided if not existent in csv
449 headers = manualHeader;
450 startIndex = 0;
451 } else {
452 headers = dataLines[0].split(',');
453 startIndex = 1;
454 }
455
456 for (var i = startIndex; i < dataLines.length; i++) {
457 var data = dataLines[i].split(',');
458 if (data.length == headers.length) {
459 var item = {};
460 for (var j = 0; j < headers.length; j++) {
461 item[headers[j]] = data[j];
462 if (j == 0) {
463 if (!uniqueSpeakers.includes(data[j])) {
464 uniqueSpeakers.push(data[j]);
465 }
466 }
467 }
468 speakerObjects.push(item);
469 }
470 }
471 populateChapters(speakerObjects);
472 });
473 }
474
475 function populateChapters(data) { // populates chapter section and adds regions to waveform
476 // colorbrewer is a web tool for guidance in choosing map colour schemes based on a variety of settings.
477 // this colour scheme is designed for qualitative data
478
479 if (uniqueSpeakers.length > 8) colourbrewerset = colorbrewer.Set2[8];
480 else if (uniqueSpeakers.length < 3) colourbrewerset = colorbrewer.Set2[3];
481 else colourbrewerset = colorbrewer.Set2[uniqueSpeakers.length];
482
483 for (var i = 0; i < data.length; i++) {
484 var chapter = document.createElement("div");
485 var speakerLetter = getLetter(data[i]);
486 chapter.id = "chapter" + i;
487 chapter.classList.add("chapter");
488 chapter.innerHTML = "Speaker " + speakerLetter + "<span class='speakerTime' id='" + "chapter" + i + "'>" + minutize(data[i].start) + " - " + minutize(data[i].end) + "</span>";
489 chapter.addEventListener("click", e => { chapterClicked(e.target.id) });
490 chapter.addEventListener("mouseover", e => { chapterEnter(e.target.id) });
491 chapter.addEventListener("mouseleave", e => { chapterLeave(e.target.id) });
492 chapters.appendChild(chapter);
493 // console.log("index: " + uniqueSpeakers.indexOf(data[i].speaker)%8);
494 // console.log("colour: " + colourbrewerset[uniqueSpeakers.indexOf(data[i].speaker)%8]);
495 wavesurfer.addRegion({
496 id: "region" + i,
497 start: data[i].start,
498 end: data[i].end,
499 drag: false,
500 resize: false,
501 color: colourbrewerset[uniqueSpeakers.indexOf(data[i].speaker)%8] + regionTransparency,
502 });
503 }
504 }
505
506 function loadJSONFile(filename) {
507 $.ajax({
508 type: "GET",
509 url: filename,
510 dataType: "text",
511 }).then(function(data){ populateWords(JSON.parse(data)) });
512 }
513
514 function populateWords(data) { // populates word section and adds regions to waveform
515 var transcription = data.transcription;
516 var words = data.words;
517 var wordContainer = document.createElement("div");
518 wordContainer.id = "word-container";
519 for (var i = 0; i < words.length; i++) {
520 var word = document.createElement("span");
521 word.id = "word" + i;
522 word.classList.add("word");
523 word.innerHTML = transcription.split(" ")[i];
524 word.addEventListener("click", e => { wordClicked(data, e.target.id) });
525 word.addEventListener("mouseover", e => { chapterEnter(e.target.id) });
526 word.addEventListener("mouseleave", e => { chapterLeave(e.target.id) });
527 wordContainer.appendChild(word);
528 wavesurfer.addRegion({
529 id: "region" + i,
530 start: words[i].startTime,
531 end: words[i].endTime,
532 drag: false,
533 resize: false,
534 color: "rgba(255, 255, 255, 0.1)",
535 });
536 }
537 chapters.appendChild(wordContainer);
538 }
539
540 var chapterClicked = function(id) { // plays audio from start of chapter
541 var index = id.replace("chapter", "");
542 var start = speakerObjects[index].start;
543 var end = speakerObjects[index].end;
544 // wavesurfer.play(start, end);
545 wavesurfer.play(start);
546 }
547
548 function wordClicked(data, id) { // plays audio from start of word
549 var index = id.replace("word", "");
550 var start = data.words[index].startTime;
551 var end = data.words[index].endTime;
552 // wavesurfer.play(start, end);
553 wavesurfer.play(start);
554 }
555
556 function chapterEnter(id) {
557 regionEnter(wavesurfer.regions.list["region" + id.replace(itemType, "")]);
558 }
559
560 function chapterLeave(id) {
561 regionLeave(wavesurfer.regions.list["region" + id.replace(itemType, "")]);
562 }
563
564 function handleRegionColours(region, highlight) { // handles region, chapter & word colours
565 var colour;
566 if (highlight) {
567 colour = "rgb(101, 116, 116)";
568 regionEnter(region);
569 } else {
570 colour = "";
571 regionLeave(region);
572 }
573 var regionIndex = region.id.replace("region","");
574 var corrItem = document.getElementById(itemType + regionIndex);
575 corrItem.style.backgroundColor = colour;
576 }
577
578 function regionEnter(region) {
579 region.update({ color: "rgba(255, 255, 255, 0.35)" });
580 }
581
582 function regionLeave(region) {
583 if (itemType == "chapter") {
584 if (!(wavesurfer.getCurrentTime() + 0.1 < region.end && wavesurfer.getCurrentTime() > region.start)) {
585 var index = region.id.replace("region", "");
586 region.update({ color: colourbrewerset[uniqueSpeakers.indexOf(speakerObjects[index].speaker)%8] + regionTransparency });
587 }
588 } else {
589 region.update({ color: "rgba(255, 255, 255, 0.1)" });
590 }
591 }
592
593 function minutize(num) { // converts seconds to m:ss for chapters & waveform hover
594 var seconds = Math.round(num % 60);
595 if (seconds.toString().length == 1) seconds = "0" + seconds;
596 return Math.floor(num / 60) + ":" + seconds;
597 }
598
599 function getLetter(val) {
600 var speakerNum = parseInt(val.speaker.replace("SPEAKER_",""));
601 return String.fromCharCode(65 + speakerNum); // 'A' == UTF-16 65
602 }
603}
604
605function formatAudioDuration(duration) {
606 console.log(duration);
607 var [hrs, mins, secs, ms] = duration.replace(".", ":").split(":");
608 return hrs + ":" + mins + ":" + secs;
609}
Note: See TracBrowser for help on using the repository browser.