assets/themes/j1/core/js/template.js in j1-template-2023.9.0 vs assets/themes/j1/core/js/template.js in j1-template-2023.9.1

- old
+ new

@@ -4544,13 +4544,18 @@ */ /* Articulate.js (1.1.0). (C) 2017 Adam Coti. MIT @license: en.wikipedia.org/wiki/MIT_License See Github page at: https://github.com/acoti/articulate.js - See Web site at: http://articulate.purefreedom.com + See Web site at: https://purefreedom.com/articulate/ */ +/* Further reading + https://dev.to/jankapunkt/cross-browser-speech-synthesis-the-hard-way-and-the-easy-way-353 + https://github.com/jankapunkt/easy-speech +*/ + (function ($) { 'use strict'; const defaultOptions = __webpack_require__(633); const ParseContent = __webpack_require__(291); @@ -4942,35 +4947,41 @@ var chunks = []; // strip strange elements from text // unclear why a elements of ' >' is generated in text // may caused by a HTML tag + // text = text.replace(/^\s+>/gm, ''); text = text.replaceAll(' ..', '.'); // cleanup text + // text = text.replace(/(\r\n|\n|\r)/gm, ''); text = text.replace(/\s+/gm, ' '); chunks = text.split('.'); // 1st cleanup of chunks + // chunks.forEach((chunk, index) => { chunks[index] = chunks[index].replace(/^\s+/g, ''); chunks[index] = chunks[index].replaceAll('""', ''); }); // 2nd cleanup of chunks (delete chunks NOT speakable) + // chunks.forEach((chunk, index) => { if (chunks[index].length > 0) { chunks[index] = chunks[index] + '. '; } else { // remove empty text element from chunks array + // chunks.splice(index, 1); } }); // 3rd cleanup of chunks (delete empty chunks) + // chunks.forEach((chunk, index) => { if (chunks[index].length == 0) { // remove empty text element from chunks array chunks.splice(index, 1); } @@ -4995,49 +5006,49 @@ offsetTop: offset, $paragraph: $paragraph }); }); - // Get headings array + // create the headings array + // headingsArray = parseContent.selectHeadings(defaultOptions.contentSelector, defaultOptions.headingSelector); // parse the headingsArray to add missing offset values - // for headlines // chunkSet.forEach((chunk, index) => { var text; var innerText; if (chunk.offset === undefined) { // cleanup the spoken text for compare + // text = chunk.text.replaceAll('. ', ''); - - // jadams: - // for this type of loop, NOT all headings are found in the array if (headingsArray !== null) { // see: https://stackoverflow.com/questions/29285897/difference-between-for-in-and-for-of-statements // for in loops over enumerable property names of an object // for of (new in ES6) does use an object-specific iterator // and loops over the values generated by that. + // for (var node in headingsArray) { for (var node of headingsArray) { - // for (var node in headingsArray) { // cleanup the innerText for compare + // innerText = node.innerText.replaceAll('?', ''); - innerText = node.innerText; + innerText = node.innerText.replaceAll('!', ''); if (innerText == text) { var headline = $('#' + node.id); if (headline.length > 0) { var offsetTop = headline.offset().top; chunk.offsetTop = Math.round(offsetTop); // console.debug('speak2me, text: ' + node.innerText + ', offsetTop: ' + chunk.offsetTop); } else { // console.warn('speak2me, text: ' + node.innerText + ', offsetTop not caclulated.'); - } - } - } - } - } - }); + } // END if headline.length + } // END if innerText + } // END for headingsArray + } // END if headingsArray + } // END if chunk.offset + }); // END forEach chunkSet + return chunkSet; } // create a slice of text used later to identify the // containing paragraph @@ -5047,19 +5058,22 @@ var endSubString = startSubString + slicelenght; var subText = text.substr(startSubString, endSubString); var stringArray = subText.split(/(\s+)/); var words; - // Remove last two elements are a fraction of subText + // remove last two elements are a fraction of subText + // stringArray.pop(); stringArray.pop(); - // built the new string + // build the new string + // subText = stringArray.join(''); subText = subText.replaceAll('.', ''); - // at least two words required + // at least wordsMin words required + // words = wordCount(subText); if (words < wordsMin) { return undefined; console.warn('no search possible on this fraction of subText'); } else { @@ -5074,50 +5088,39 @@ // indicate active converter in the quicklinks bar // $('.mdib-speaker').addClass('mdib-spin'); - // manage scrolling and highlightning for the active spoken text + // listener to ENABLE highlightning and scrolling + // on active spoken elements // speaker.addEventListener('start', event => { - // store current scroll position + // scroll on ALL valid offsetTop for headings and paragraphs // if (speaker.offsetTop !== undefined) { - speaker.currentScrollPosition = speaker.offsetTop; - } - - // adjust scrolling position offsetTop for 'post series' - // - if ($('.bmd-layout-header').length) { - speaker.offsetTop = $('.bmd-layout-header')[0].offsetTop + (scrollBlockOffset / 2 + 3) + speaker.offsetTop; - speaker.previousScrollPosition = speaker.offsetTop; - } - - // add highlightning - // - if (speaker.$paragraph !== undefined) { - speaker.$paragraph.addClass('speak-highlighted'); - } - - // scroll to paragraph currently spoken if a valid - // offsetTop is available - // - if (speaker.offsetTop !== undefined) { + // skip scrolling if offsetTop position is LOWER than expected + // if (speaker.offsetTop >= speaker.previousScrollPosition) { window.scrollTo({ top: speaker.offsetTop - scrollBlockOffset, behavior: scrollBehavior }); } } + + // manage highlightning on currently spoken paragraph + // + if (speaker.$paragraph !== undefined) { + speaker.$paragraph.addClass('speak-highlighted'); + } }); - // listener to manage highlightning for spoken text elements - // and set next chunk to speak + // listener to STOP highlightning for already spoken + // text elements and set next chunk to speak // speaker.addEventListener('end', function (event) { - // workaround WRONG offsetTop positions (LOWER as expected) + // workaround to detect offsetTop positions LOWER than expected // if (speaker.offsetTop !== undefined) { if (speaker.offsetTop >= speaker.previousScrollPosition) { speaker.previousScrollPosition = speaker.offsetTop; } @@ -5130,11 +5133,11 @@ } chunkSpoken = false; chunkCounter++; }); - // loop to prepare chunks to speak or sto the voice output + // loop to prepare ALL chunks to speak or STOP the voice output // var speechMonitor = setInterval(function () { // check if all chunks (text) are spoken // if (chunkCounter == chunkCounterMax || userStoppedSpeaking) { @@ -5668,9 +5671,21 @@ // rather than resolving into their actual character. // var txt = document.createElement('textarea'); txt.innerHTML = final; final = txt.value; + + // Replace single word in line + // + final = final.replace(/^\s*(\b\w+\b)\s*$/gm, "$1. "); + + // Replace month year in line + // + final = final.replace(/^\s*(\b\w+\b\s*[0-9]{4})$/gm, "$1. "); + + // Replace multiple whitespaces + // + final = final.replace(/\s+/g, ' '); // split the final text in to chunks (sentences). // const textChunks = splitTextIntoChunks(final); chunkCounterMax = textChunks.length; \ No newline at end of file