{"name":"Tap Word to Hear (Cloud)","key":"tapwordtohearcloud","version":"1.0.0","instructions":"This will read aloud words in the enclosed text block when tapped. Currently does not support \"sentence\" mode. (Uses Cloud Poodll)  ","showatto":"1","showplayers":"0","requirecss":"","requirejs":"","shim":"","defaults":"playmode=\"word|sentence\",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":"<audio id='@@AUTOID@@_audio' class=\"nomediaplugin\"></audio>\n<!-- @@CLOUDPOODLLTOKEN@@ -->\n<div id='@@AUTOID@@_textblock' ><div class='tbr_innerdiv'>","bodyend":"</div></div>","script":"//DECLARATIONS and INITs ...........................\nvar thesentence_number =0;\nvar lettered= false;\n\n//audio player declarations\nvar aplayer = $('#' + @@AUTOID@@ + '_audio');\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 = $('#' + @@AUTOID@@ + '_textblock');\nvar usetext = useblock.text();\n\n//some common selectors\nvar wordselector = '#' + @@AUTOID@@+ '_textblock span.tbr_word';\nvar sentenceselector = '#' + @@AUTOID@@+ '_textblock span.tbr_sentence';\n\n//FUNCTIONS ...........................\n\n\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                + '&region=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[^>]*>(.*?)</\\\\1>\");\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(@@playmode@@=='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 + '<span class=\"tbr_word\" data-wordindex=\"'+ itemcount +'\">' + thewords[theword] + '</span> ';\n                 }//end of for loop\n             }else{\n                //for sentences\n                //something is wrong in sentence mode. For now, just use word mode.\n                var thesentences = split_into_sentences($(this).text());\n                for (var thesentence=0; thesentence < thesentences.length; thesentence++){\n                      itemcount++;\n                     retpieces =  retpieces + '<span class=\"tbr_sentence\" data-sentenceindex=\"'+ itemcount +'\">' + thesentences[thesentence] + '</span>&nbsp;';\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(@@playmode@@){\n      case 'word':\n          $(wordselector).removeClass('activesentence');\n          break;\n      case 'sentence':\n         $(sentenceselector).removeClass('activesentence');\n      case 'none':\n      default:\n         //do nothing\n  }\n};\n\n//FUNCTION:  highlight a word as active\nvar highlight_word = function(theword){\n   $(wordselector).removeClass('activesentence');\n    theword.addClass('activesentence');\n};\n\n//FUNCTION:  highlight a sentence as active\nvar highlight_sentence = function(thesentence){\n    $(sentenceselector).removeClass('activesentence');\n     $(sentenceselector + '[data-sentenceindex=' + thesentence + ']').addClass('activesentence');\n};\n\n//FUNCTION: play a single sentence and mark it active for display purposes\nvar doplaysentence = function(thesentence){\n     highlight_sentence(thesentence);\n     aplayer.attr('src', instancedata[@@AUTOID@@].sentenceURLs[thesentence]);\n     aplayer[0].play();\n};\n\nvar doplayword = function(theword){\n  highlight_word(theword);\n  fetch_polly_url(theword.text(),voice,function(pollyurl){\n     aplayer.attr('src', pollyurl);\n     aplayer[0].play();\n  });\n  \n};\n\n//AUDIO PLAYER events\naplayer[0].addEventListener('ended', function(){\n      dehighlight_all();\n      aplayer[0].pause();\n});\n\n//handle sentence or word clicks\n$('#' + @@AUTOID@@ + '_textblock  .tbr_innerdiv').on('click', '.tbr_sentence, .tbr_word',function(){\n var clickeditem= $(this);\n   var startnewplay = function(){ switch(@@playmode@@){\n        case 'sentence':\n            var index = clickeditem.attr('data-sentenceindex');\n            doplaysentence(index);\n            break;\n        case 'word':\n        default:\n            //var index = clickeditem.attr('data-wordindex');\n            doplayword(clickeditem);\n    }//end of switch\n      \n   };//end of startnewplay function\n\n   if(aplayer[0].playing){\n      console.log('was playing but then got iterrupted');\n       aplayer[0].pause().then(startnewplay);\n   }else{ \n       startnewplay();\n   }//end of if\n});//end of on click handler\n\n//PROCEDURAL stuff ...........................\n//break it into sentences, and fetch data + TTS URL for each sentence\nvar sentences = split_into_sentences(usetext);\nwordstarts=[];\nwordcounts=[];\nsentenceURLs=[];\nvar previousend=0;\n\nfor (var currentsentence=0;currentsentence<sentences.length;currentsentence++){\n  wordstarts[currentsentence]= previousend;\n  wordcounts[currentsentence]= split_into_words(sentences[currentsentence]).length;\n  previousend = previousend + wordcounts[currentsentence];\n\nvar speaktext = sentences[currentsentence];\nfetch_polly_url(speaktext,voice,\n  function(sentenceindex){return function(pollyurl){sentenceURLs[sentenceindex]= pollyurl;}}(currentsentence)\n);\n\n}\n\n//now we need to ensure multiple passages on same page work, so we store sentences in array by autoid\nif(!instancedata) {\n     var instancedata = {};\n} \ninstancedata[@@AUTOID@@] = {\n  sentenceURLs: sentenceURLs,\n  wordcounts: wordcounts,\n  wordstarts: wordstarts\n}\n\n//mark up the passage\nspanify_text_passage();\n","style":".activesentence {\n    background: #c5efcf;\n}","dataset":"","datasetvars":"","alternate":"","alternateend":""}