From 7e9c5594b84f580d7f71b479d1ae6dc11e7bfd71 Mon Sep 17 00:00:00 2001 From: justinhunt Date: Thu, 9 Dec 2021 07:44:14 +0000 Subject: [PATCH] fixed issues with php 8 compat --- CHANGES.txt | 3 +++ classes/awsremote.php | 2 +- classes/poodlltools.php | 12 ++++++------ presets/textblockreader.txt | 2 +- version.php | 4 ++-- 5 files changed, 13 insertions(+), 10 deletions(-) diff --git a/CHANGES.txt b/CHANGES.txt index 78ecc942..28283168 100644 --- a/CHANGES.txt +++ b/CHANGES.txt @@ -1,5 +1,8 @@ Change List ========= +Version 3.1.50 (Build 2021120900) +- Fixed issues causing errors in php 8 on poodlltools + Version 3.1.49 (Build 2021082700) - Fixed issue with mimetype and extension on whiteboard drawings diff --git a/classes/awsremote.php b/classes/awsremote.php index 950f9d18..d98ed269 100644 --- a/classes/awsremote.php +++ b/classes/awsremote.php @@ -257,7 +257,7 @@ function s3_put_filedata($mediatype, $key, $filepath) { } //called from poodlltools->getAMDRecordercode. Has matching function in awstools - function get_presignedupload_url($mediatype, $minutes = 30, $key, $iosvideo = false) { + function get_presignedupload_url($mediatype, $minutes, $key, $iosvideo = false) { $params = Array(); $params['region'] = $this->region; $params['mediatype'] = $mediatype; diff --git a/classes/poodlltools.php b/classes/poodlltools.php index ca624639..24c9c783 100644 --- a/classes/poodlltools.php +++ b/classes/poodlltools.php @@ -193,13 +193,13 @@ public static function fetch_placeholder_duration($mediatype) { } //this is just a temporary function, until the PoodLL filter client plugins are upgraded to not use simpleaudioplayer - public static function fetchSimpleAudioPlayer($param1 = 'auto', $url, $param3 = 'http', $param4 = 'width', $param5 = 'height') { + public static function fetchSimpleAudioPlayer($param1 = 'auto', $url="", $param3 = 'http', $param4 = 'width', $param5 = 'height') { $html_snippet = \html_writer::tag('a', 'audiofile.mp3', array('href' => $url)); return format_text($html_snippet); } //this is just a temporary function, until the PoodLL filter client plugins are upgraded to not use simpleaudioplayer - public static function fetchSimpleVideoPlayer($param1 = 'auto', $url, $param3 = 'http', $param4 = 'width', $param5 = 'height') { + public static function fetchSimpleVideoPlayer($param1 = 'auto', $url="", $param3 = 'http', $param4 = 'width', $param5 = 'height') { $html_snippet = \html_writer::tag('a', 'videofile.mp4', array('href' => $url)); return format_text($html_snippet); } @@ -1301,21 +1301,21 @@ public static function convert_with_ffmpeg($filerecord, $tempfilename, $convfile }//end of convert with FFMPEG //This a legacy call from client plugins, that ais mapped to amd recorder code - public static function fetchAudioRecorderForSubmission($runtime, $assigname, $updatecontrol = "saveflvvoice", $contextid, + public static function fetchAudioRecorderForSubmission($runtime, $assigname, $updatecontrol, $contextid, $component, $filearea, $itemid, $timelimit = "0", $callbackjs = false, $hints = []) { return self::fetchAMDRecorderCode('audio', $updatecontrol, $contextid, $component, $filearea, $itemid, $timelimit, $callbackjs, $hints); } //This a legacy call from client plugins, that ais mapped to amd recorder code - public static function fetchVideoRecorderForSubmission($runtime, $assigname, $updatecontrol = "saveflvvoice", $contextid, + public static function fetchVideoRecorderForSubmission($runtime, $assigname, $updatecontrol, $contextid, $component, $filearea, $itemid, $timelimit = "0", $callbackjs = false, $hints = []) { return self::fetchAMDRecorderCode('video', $updatecontrol, $contextid, $component, $filearea, $itemid, $timelimit, $callbackjs, $hints); } //This a legacy call from client plugins, that ais mapped to amd recorder code - public static function fetchHTML5SnapshotCamera($updatecontrol = "saveflvvoice", $width, $height, $contextid, $component, + public static function fetchHTML5SnapshotCamera($updatecontrol, $width, $height, $contextid, $component, $filearea, $itemid, $callbackjs = false, $hints = []) { $mediatype = "snapshot"; return self::fetchAMDRecorderCode($mediatype, $updatecontrol, $contextid, $component, $filearea, $itemid, 0, $callbackjs, @@ -1323,7 +1323,7 @@ public static function fetchHTML5SnapshotCamera($updatecontrol = "saveflvvoice", } //This a legacy call from client plugins, that ais mapped to amd recorder code - public static function fetch_HTML5RecorderForSubmission($updatecontrol = "saveflvvoice", $contextid, $component, $filearea, + public static function fetch_HTML5RecorderForSubmission($updatecontrol, $contextid, $component, $filearea, $itemid, $mediatype = "image", $fromrepo = false, $callbackjs = false, $hints = []) { return self::fetchAMDRecorderCode($mediatype, $updatecontrol, $contextid, $component, $filearea, $itemid, 0, $callbackjs, $hints); diff --git a/presets/textblockreader.txt b/presets/textblockreader.txt index 2b697b2b..772a0b31 100644 --- a/presets/textblockreader.txt +++ b/presets/textblockreader.txt @@ -1 +1 @@ -{"name":"Passage reader","key":"textblockreader","version":"1.0.11","instructions":"This is a small html5 audio player that will read aloud the enclosed text block. There are text to speech options as well as the option to highlight words or sentences. Sentences works better. (Uses Cloud Poodll) ","showatto":"1","showplayers":"0","requirecss":"//maxcdn.bootstrapcdn.com/font-awesome/4.3.0/css/font-awesome.min.css","requirejs":"","shim":"","defaults":"highlightmode=\"sentence|word|none\",pause=\"fa-stop\",play=\"fa-volume-up\",stoporpause=\"stop|pause\", background=\"red\",color=\"#fff\",width=\"40\",height=\"40\",speaker=\"Male|Female\",language=\"English(US)|English(GB)|English(AU)|English(In)|English(Welsh)|Danish|Dutch|French(FR)|French(CA)|German|Icelandic|Italian|Japanese|Korean|Norwegian|Polish|Portugese(BR)|Portugese(PT)|Romanian|Russian|Spanish(ES)|Spanish(US)|Swedish|Turkish|Welsh\"","amd":"1","body":"\n
\n\n
","bodyend":"
\n
","script":"//now we need to ensure multiple passages so we wrap it all in a function and call it at the end.\n//start of instance wrapper\nvar passagereader = function(PASSAGEID){\n\n//DECLARATIONS and INITs ...........................\nvar thesentence_number =0;\nvar lettered= false;\n\n//audio player declarations\nvar aplayer = $('#' + PASSAGEID + '_player');\nvar fa = $('#' + PASSAGEID + ' .fa');\n\n//text to audio preparation\nvar format = \"text\";\n\n//determine the voice\nvar mf=@@speaker@@\nswitch(@@language@@){\ncase \"English(US)\": voice = mf=='Male'?'Joey':'Kendra';break;\ncase \"English(GB)\": voice = mf=='Male'?'Brian':'Amy';break;\ncase \"English(AU)\": voice = mf=='Male'?'Russell':'Nicole';break;\ncase \"English(IN)\": voice = mf=='Male'?'Aditi':'Raveena';break;\ncase \"English(WELSH)\": voice = mf=='Male'? 'Geraint':'Geraint';break;\ncase \"Danish\": voice = mf=='Male'?'Mads':'Naja';break;\ncase \"Dutch\": voice = mf=='Male'?'Ruben':'Lotte';break;\ncase \"French(FR)\": voice = mf=='Male'?'Mathieu':'Celine';break;\ncase \"French(CA)\": voice = mf=='Male'?'Chantal':'Chantal';break;\ncase \"German\": voice = mf=='Male'?'Hans':'Marlene';break;\ncase \"Icelandic\": voice = mf=='Male'?'Karl':'Dora';break;\ncase \"Italian\": voice = mf=='Male'?'Carla':'Giorgio';break;\ncase \"Japanese\": voice = mf=='Male'?'Takumi':'Mizuki';break;\ncase \"Korean\": voice = mf=='Male'?'Seoyan':'Seoyan';break;\ncase \"Norwegian\": voice = mf=='Male'?'Liv':'Liv';break;\ncase \"Polish\": voice = mf=='Male'?'Jacek':'Ewa';break;\ncase \"Portugese(BR)\": voice = mf=='Male'?'Ricardo':'Vitoria';break;\ncase \"Portugese(PT)\": voice = mf=='Male'?'Cristiano':'Ines';break;\ncase \"Romanian\": voice = mf=='Male'?'Carmen':'Carmen';break;\ncase \"Russian\": voice = mf=='Male'?'Maxim':'Tatyana';break;\ncase \"Spanish(ES)\": voice = mf=='Male'?'Enrique':'Conchita';break;\ncase \"Spanish(US)\": voice = mf=='Male'?'Miguel':'Penelope';break;\ncase \"Swedish\": voice = mf=='Male'?'Astrid':'Astrid';break;\ncase \"Turkish\": voice = mf=='Male'?'Filiz':'Filiz';break;\ncase \"Welsh\": voice = mf=='Male'?'Gwyneth':'Gwyneth';break;\ndefault: voice = mf=='Male'?'Brian':'Amy';\n}\n\n\n//fetch the text to read\nvar useblock = $('#' + PASSAGEID + '_textblock');\nvar usetext = useblock.text();\n\n//some common selectors\nvar wordselector = '#' + PASSAGEID+ '_textblock span.tbr_word';\nvar sentenceselector = '#' + PASSAGEID+ '_textblock span.tbr_sentence';\n\n//FUNCTIONS ...........................\n//FUNCTION fetch polly url\n var fetch_polly_url = function(speaktext, voice, callback) {\n\n //The REST API we are calling\n var functionname = 'local_cpapi_fetch_polly_url';\n\n //fetch the Posturl. We need this.\n //set up our ajax request\n var xhr = new XMLHttpRequest();\n var that = this;\n\n //set up our handler for the response\n xhr.onreadystatechange = function (e) {\n if (this.readyState === 4) {\n if (xhr.status == 200) {\n\n //get a yes or forgetit or tryagain\n var payload = xhr.responseText;\n var payloadobject = JSON.parse(payload);\n if (payloadobject) {\n //returnCode > 0 indicates an error\n if (payloadobject.returnCode > 0) {\n console.log(payloadobject.returnMessage);\n return false;\n //if all good, then lets do the embed\n } else if (payloadobject.returnCode === 0){\n var pollyurl = payloadobject.returnMessage;\n callback(pollyurl);\n } else {\n console.log('Polly Signed URL Request failed:');\n console.log(payloadobject);\n }\n } else {\n console.log('Polly Signed URL Request something bad happened');\n }\n } else {\n console.log('Polly Signed URL Request Not 200 response:' + xhr.status);\n }\n }\n };\n\n //make our request\n var xhrparams = \"wstoken=\" + @@CLOUDPOODLLTOKEN@@\n + \"&wsfunction=\" + functionname\n + \"&moodlewsrestformat=\" + 'json'\n + \"&text=\" + encodeURIComponent(speaktext)\n + '&texttype=text'\n + '&voice=' + voice\n + '&appid=' + 'filter_poodll'\n + '&owner=poodll'\n + '®ion=useast1';\n\n var serverurl = 'https://cloud.poodll.com' + \"/webservice/rest/server.php\";\n xhr.open(\"POST\", serverurl, true);\n xhr.setRequestHeader(\"Cache-Control\", \"no-cache\");\n xhr.setRequestHeader(\"Content-Type\", \"application/x-www-form-urlencoded\");\n xhr.send(xhrparams);\n };\n\n//FUNCTION: determine if the string is text or HTML\nvar isHTML = function (testString) {\n var htmlRegex = new RegExp(\"<([A-Za-z][A-Za-z0-9]*)\\\\b[^>]*>(.*?)\");\n return htmlRegex.test(testString);\n};\n\n//FUNCTION: split a text passage into words\nvar split_into_words= function(thetext){\n thetext = thetext.replace(/\\s+/g,' ').trim();\n if(thetext==''){return[]};\n return thetext.split(' '); \n};\n\n//FUNCTION: split a text passage into sentences\nvar split_into_sentences = function(thetext){\n thetext = thetext.replace(/\\s+/g,' ').trim();\n if(thetext ==''){return[]};\n return thetext.match(/([^\\.!\\?]+[\\.!\\?\"']+)|([^\\.!\\?\"']+$)/g); \n};\n\n//FUNCTION: break a text passage into words/sentences, and surround the words with marker tags\nvar spanify_text_passage = function(){\n //the itemcount er\n var itemcount = -1;\n\n //get all the text nodes in the useblock\n var textnodes = useblock.find('*').contents().filter(function(){ return this.nodeType == 3; });\n //wrap sentence or words in text block with spans\n textnodes.each(function(){\n var retpieces = ''; \n if(@@highlightmode@@=='word'){\n //for words\n var thewords = split_into_words($(this).text());\n for (var theword=0; theword < thewords.length; theword++){\n itemcount++;\n retpieces = retpieces + '' + thewords[theword] + ' ';\n }//end of for loop\n }else{\n //for sentences\n var thesentences = split_into_sentences($(this).text());\n for (var thesentence=0; thesentence < thesentences.length; thesentence++){\n itemcount++;\n retpieces = retpieces + '' + thesentences[thesentence] + ' ';\n }//end of for loop\n }\n $(this).replaceWith(retpieces);\n });//end of textnodes each\n};\n\n//FUNCTION: unhighlight a sentence as active\nvar dehighlight_all = function(){\n switch(@@highlightmode@@){\n case 'word':\n $(wordselector,useblock).removeClass('activesentence');\n break;\n case 'sentence':\n $(sentenceselector,useblock).removeClass('activesentence');\n break;\n case 'none':\n default:\n //do nothing\n }\n}\n\n//FUNCTION: highlight a sentence as active\nvar highlight_sentence = function(thesentence){\n switch(@@highlightmode@@){\n case 'word':\n $(wordselector,useblock).removeClass('activesentence');\n $(wordselector,useblock).slice(wordstarts[thesentence],\n wordstarts[thesentence] + \n wordcounts[thesentence]).addClass('activesentence');\n break;\n case 'sentence':\n $(sentenceselector).removeClass('activesentence');\n $(sentenceselector + '[data-sentenceindex=' + thesentence + ']').addClass('activesentence');\n break;\n case 'none':\n default:\n //do nothing\n }\n}\n\n//FUNCTION: play a single sentence and mark it active for display purposes\nvar doplayaudio = function(thesentence){\n highlight_sentence(thesentence);\n aplayer.attr('src',sentenceURLs[thesentence]);\n aplayer[0].play();\n};\n\n//AUDIO PLAYER events\naplayer[0].addEventListener('ended', function(){\n if(thesentence_number< sentences.length -1){\n thesentence_number++;\n doplayaudio(thesentence_number);\n }else{\n dehighlight_all();\n $(fa).removeClass(@@pause@@);\n $(fa).addClass(@@play@@);\n aplayer[0].pause();\n }\n});\n\n//handle audio player button clicks\n$('#' + PASSAGEID).click(function(){\n if(!aplayer[0].paused && !aplayer[0].ended){\n aplayer[0].pause();\n if(@@stoporpause@@=='stop'){\n aplayer[0].load();\n thesentence_number=0;\n }\n $(fa).removeClass(@@pause@@);\n $(fa).addClass(@@play@@);\n\n //if paused and in limbo no src state\n }else if(aplayer[0].paused && aplayer.attr('src')){\n aplayer[0].play();\n $(fa).removeClass(@@play@@);\n $(fa).addClass(@@pause@@);\n//play \n}else{\n if(!lettered){\n spanify_text_passage();\n lettered=true;\n };//end of if lettered\n if(@@stoporpause@@=='stop'){\n thesentence_number=0;\n } \n doplayaudio(thesentence_number);\n $(fa).removeClass(@@play@@);\n $(fa).addClass(@@pause@@);\n }//end of if paused ended\n});\n\n//handle sentence clicks\n$('#' + PASSAGEID + '_textblock .tbr_innerdiv').on('click', '.tbr_sentence',function(){\naplayer[0].pause();\n var sentenceindex = $(this).attr('data-sentenceindex');\n $(fa).removeClass(@@play@@);\n $(fa).addClass(@@pause@@);\n thesentence_number = sentenceindex; \n doplayaudio(sentenceindex );\n});\n\n//PROCEDURAL stuff ...........................\n//break it into sentences, and fetch data + TTS URL for each sentence\nvar sentences = split_into_sentences(usetext);\nvar wordstarts=[];\nvar wordcounts=[];\nvar sentenceURLs=[];\nvar previousend=0;\nfor (var currentsentence=0;currentsentence\n\t\n\t\n\n
\n\n
","bodyend":"
\n
","script":"//now we need to ensure multiple passages so we wrap it all in a function and call it at the end.\n//start of instance wrapper\nvar passagereader = function(PASSAGEID){\n\n//DECLARATIONS and INITs ...........................\nvar thesentence_number =0;\nvar lettered= false;\n\n//audio player declarations\nvar aplayer = $('#' + PASSAGEID + '_player');\nvar fa = $('#' + PASSAGEID + ' .fa');\n\n//text to audio preparation\nvar format = \"text\";\n\n//determine the voice\nvar mf=@@speaker@@\nswitch(@@language@@){\ncase \"English(US)\": voice = mf=='Male'?'Joey':'Kendra';break;\ncase \"English(GB)\": voice = mf=='Male'?'Brian':'Amy';break;\ncase \"English(AU)\": voice = mf=='Male'?'Russell':'Nicole';break;\ncase \"English(IN)\": voice = mf=='Male'?'Aditi':'Raveena';break;\ncase \"English(WELSH)\": voice = mf=='Male'? 'Geraint':'Geraint';break;\ncase \"Danish\": voice = mf=='Male'?'Mads':'Naja';break;\ncase \"Dutch\": voice = mf=='Male'?'Ruben':'Lotte';break;\ncase \"French(FR)\": voice = mf=='Male'?'Mathieu':'Celine';break;\ncase \"French(CA)\": voice = mf=='Male'?'Chantal':'Chantal';break;\ncase \"German\": voice = mf=='Male'?'Hans':'Marlene';break;\ncase \"Icelandic\": voice = mf=='Male'?'Karl':'Dora';break;\ncase \"Italian\": voice = mf=='Male'?'Carla':'Giorgio';break;\ncase \"Japanese\": voice = mf=='Male'?'Takumi':'Mizuki';break;\ncase \"Korean\": voice = mf=='Male'?'Seoyan':'Seoyan';break;\ncase \"Norwegian\": voice = mf=='Male'?'Liv':'Liv';break;\ncase \"Polish\": voice = mf=='Male'?'Jacek':'Ewa';break;\ncase \"Portugese(BR)\": voice = mf=='Male'?'Ricardo':'Vitoria';break;\ncase \"Portugese(PT)\": voice = mf=='Male'?'Cristiano':'Ines';break;\ncase \"Romanian\": voice = mf=='Male'?'Carmen':'Carmen';break;\ncase \"Russian\": voice = mf=='Male'?'Maxim':'Tatyana';break;\ncase \"Spanish(ES)\": voice = mf=='Male'?'Enrique':'Conchita';break;\ncase \"Spanish(US)\": voice = mf=='Male'?'Miguel':'Penelope';break;\ncase \"Swedish\": voice = mf=='Male'?'Astrid':'Astrid';break;\ncase \"Turkish\": voice = mf=='Male'?'Filiz':'Filiz';break;\ncase \"Welsh\": voice = mf=='Male'?'Gwyneth':'Gwyneth';break;\ndefault: voice = mf=='Male'?'Brian':'Amy';\n}\n\n\n//fetch the text to read\nvar useblock = $('#' + PASSAGEID + '_textblock');\nvar usetext = useblock.text();\n\n//some common selectors\nvar wordselector = '#' + PASSAGEID+ '_textblock span.tbr_word';\nvar sentenceselector = '#' + PASSAGEID+ '_textblock span.tbr_sentence';\n\n//FUNCTIONS ...........................\n//FUNCTION fetch polly url\n var fetch_polly_url = function(speaktext, voice, callback) {\n\n //The REST API we are calling\n var functionname = 'local_cpapi_fetch_polly_url';\n\n //fetch the Posturl. We need this.\n //set up our ajax request\n var xhr = new XMLHttpRequest();\n var that = this;\n\n //set up our handler for the response\n xhr.onreadystatechange = function (e) {\n if (this.readyState === 4) {\n if (xhr.status == 200) {\n\n //get a yes or forgetit or tryagain\n var payload = xhr.responseText;\n var payloadobject = JSON.parse(payload);\n if (payloadobject) {\n //returnCode > 0 indicates an error\n if (payloadobject.returnCode > 0) {\n console.log(payloadobject.returnMessage);\n return false;\n //if all good, then lets do the embed\n } else if (payloadobject.returnCode === 0){\n var pollyurl = payloadobject.returnMessage;\n callback(pollyurl);\n } else {\n console.log('Polly Signed URL Request failed:');\n console.log(payloadobject);\n }\n } else {\n console.log('Polly Signed URL Request something bad happened');\n }\n } else {\n console.log('Polly Signed URL Request Not 200 response:' + xhr.status);\n }\n }\n };\n\n //make our request\n var xhrparams = \"wstoken=\" + @@CLOUDPOODLLTOKEN@@\n + \"&wsfunction=\" + functionname\n + \"&moodlewsrestformat=\" + 'json'\n + \"&text=\" + encodeURIComponent(speaktext)\n + '&texttype=text'\n + '&voice=' + voice\n + '&appid=' + 'filter_poodll'\n + '&owner=poodll'\n + '®ion=useast1';\n\n var serverurl = 'https://cloud.poodll.com' + \"/webservice/rest/server.php\";\n xhr.open(\"POST\", serverurl, true);\n xhr.setRequestHeader(\"Cache-Control\", \"no-cache\");\n xhr.setRequestHeader(\"Content-Type\", \"application/x-www-form-urlencoded\");\n xhr.send(xhrparams);\n };\n\n//FUNCTION: determine if the string is text or HTML\nvar isHTML = function (testString) {\n var htmlRegex = new RegExp(\"<([A-Za-z][A-Za-z0-9]*)\\\\b[^>]*>(.*?)\");\n return htmlRegex.test(testString);\n};\n\n//FUNCTION: split a text passage into words\nvar split_into_words= function(thetext){\n thetext = thetext.replace(/\\s+/g,' ').trim();\n if(thetext==''){return[]};\n return thetext.split(' '); \n};\n\n//FUNCTION: split a text passage into sentences\nvar split_into_sentences = function(thetext){\n thetext = thetext.replace(/\\s+/g,' ').trim();\n if(thetext ==''){return[]};\n return thetext.match(/([^\\.!\\?]+[\\.!\\?\"']+)|([^\\.!\\?\"']+$)/g); \n};\n\n//FUNCTION: break a text passage into words/sentences, and surround the words with marker tags\nvar spanify_text_passage = function(){\n //the itemcount er\n var itemcount = -1;\n\n //get all the text nodes in the useblock\n var textnodes = useblock.find('*').contents().filter(function(){ return this.nodeType == 3; });\n //wrap sentence or words in text block with spans\n textnodes.each(function(){\n var retpieces = ''; \n if(@@highlightmode@@=='word'){\n //for words\n var thewords = split_into_words($(this).text());\n for (var theword=0; theword < thewords.length; theword++){\n itemcount++;\n retpieces = retpieces + '' + thewords[theword] + ' ';\n }//end of for loop\n }else{\n //for sentences\n var thesentences = split_into_sentences($(this).text());\n for (var thesentence=0; thesentence < thesentences.length; thesentence++){\n itemcount++;\n retpieces = retpieces + '' + thesentences[thesentence] + ' ';\n }//end of for loop\n }\n $(this).replaceWith(retpieces);\n });//end of textnodes each\n};\n\n//FUNCTION: unhighlight a sentence as active\nvar dehighlight_all = function(){\n switch(@@highlightmode@@){\n case 'word':\n $(wordselector,useblock).removeClass('activesentence');\n break;\n case 'sentence':\n $(sentenceselector).removeClass('activesentence');\n break;\n case 'none':\n default:\n //do nothing\n }\n}\n\n//FUNCTION: highlight a sentence as active\nvar highlight_sentence = function(thesentence){\n switch(@@highlightmode@@){\n case 'word':\n $(wordselector,useblock).removeClass('activesentence');\n $(wordselector,useblock).slice(wordstarts[thesentence],\n wordstarts[thesentence] + \n wordcounts[thesentence]).addClass('activesentence');\n break;\n case 'sentence':\n $(sentenceselector).removeClass('activesentence');\n $(sentenceselector + '[data-sentenceindex=' + thesentence + ']').addClass('activesentence');\n break;\n case 'none':\n default:\n //do nothing\n }\n}\n\n//FUNCTION: play a single sentence and mark it active for display purposes\nvar doplayaudio = function(thesentence){\n highlight_sentence(thesentence);\n aplayer.attr('src',sentenceURLs[thesentence]);\n aplayer[0].play();\n};\n\n\n//AUDIO PLAYER events\naplayer[0].addEventListener('ended', function(){\n if(thesentence_number< sentences.length -1){\n thesentence_number++;\n doplayaudio(thesentence_number);\n }else{\n dehighlight_all();\n $(fa).removeClass('fa-stop');\n $(fa).addClass('fa-volume-up');\n thesentence_number=0;\n aplayer.removeAttr('src');\n }\n});\n\n//handle audio player button clicks\n$('#' + PASSAGEID).click(function(){\n if(!aplayer[0].paused && !aplayer[0].ended){\n aplayer[0].pause();\n if(@@stoporpause@@=='stop'){\n aplayer[0].load();\n thesentence_number=0;\n }\n $(fa).removeClass(@@pause@@);\n $(fa).addClass(@@play@@);\n\n //if paused and in limbo no src state\n }else if(aplayer[0].paused && aplayer.attr('src')){\n aplayer[0].play();\n $(fa).removeClass(@@play@@);\n $(fa).addClass(@@pause@@);\n//play \n}else{\n if(!lettered){\n spanify_text_passage();\n lettered=true;\n };//end of if lettered\n if(@@stoporpause@@=='stop'){\n thesentence_number=0;\n } \n doplayaudio(thesentence_number);\n $(fa).removeClass(@@play@@);\n $(fa).addClass(@@pause@@);\n }//end of if paused ended\n});\n\n//handle sentence clicks\n$('#' + PASSAGEID + '_textblock .tbr_innerdiv').on('click', '.tbr_sentence',function(){\naplayer[0].pause();\n var sentenceindex = $(this).attr('data-sentenceindex');\n $(fa).removeClass(@@play@@);\n $(fa).addClass(@@pause@@);\n thesentence_number = sentenceindex; \n doplayaudio(sentenceindex );\n});\n\n//PROCEDURAL stuff ...........................\n//break it into sentences, and fetch data + TTS URL for each sentence\nvar sentences = split_into_sentences(usetext);\nvar wordstarts=[];\nvar wordcounts=[];\nvar sentenceURLs=[];\nvar previousend=0;\nfor (var currentsentence=0;currentsentenceversion = 2021082700; +$plugin->version = 2021120900; $plugin->requires = 2016052300;//moodle 3.1.0 $plugin->component = 'filter_poodll'; $plugin->maturity = MATURITY_STABLE; -$plugin->release = '3.1.49 (Build 2021082700)'; +$plugin->release = '3.1.50 (Build 2021120900)';