{"id":16956,"date":"2025-10-26T19:07:17","date_gmt":"2025-10-26T17:07:17","guid":{"rendered":"https:\/\/www.beseit.net\/?page_id=16956"},"modified":"2025-11-03T11:23:00","modified_gmt":"2025-11-03T09:23:00","slug":"speak_button-html","status":"publish","type":"page","link":"https:\/\/www.beseit.net\/?page_id=16956","title":{"rendered":"speak_button.html (codi)"},"content":{"rendered":"<!DOCTYPE html>\n<html lang=\"ca\">\n<head>\n  <meta charset=\"UTF-8\">\n  <title>Conversor de text a veu<\/title>\n  <style>\n    \/* Estil general de la p\u00e0gina *\/\n    body {\n      font-family: sans-serif;\n      padding: 2em;\n      background-color: lab(90.09% -0.67 -0.25);\n    }\n\n    \/* Editor de text editable *\/\n    #editor {\n      font-size: 1.2em;\n      padding: 0.5em;\n      margin-top: 1em;\n      width: 100%;\n      max-width: 500px;\n      height: 15em;\n      overflow-y: auto;\n      border: 1px solid #ccc;\n      white-space: pre-wrap;\n    }\n\n    \/* Estil dels selectors (idioma i pausa) *\/\n    select {\n      font-size: 1.2em;\n      padding: 0.5em;\n      margin-top: 1em;\n      width: 45%;\n      max-width: 220px;\n      height: 2.5em;\n      overflow-y: hidden;\n      display: inline-block;\n      vertical-align: top;\n    }\n\n    \/* Estil dels botons de control *\/\n    #speakBtn, #toggleBtn {\n      font-size: 2em;\n      background: none;\n      border: none;\n      cursor: pointer;\n      margin-top: 1em;\n    }\n\n    #speakBtn:hover, #toggleBtn:hover {\n      color: hsl(180, 1%, 72%);\n    }\n\n    \/* Estil de cada l\u00ednia destacable *\/\n    .linia {\n      display: block;\n      padding: 0.2em;\n      transition: background-color 0.3s ease;\n    }\n\n    \/* L\u00ednia activa mentre es llegeix *\/\n    .activa {\n      background-color: hsl(180, 1%, 72%);\n    }\n  <\/style>\n<\/head>\n<body>\n  <h2>? Conversor de text a veu<\/h2>\n\n  <!-- Editor de text on l'usuari pot escriure -->\n  <div id=\"editor\" contenteditable=\"true\" placeholder=\"Escriu el text que vols escoltar\">\nto run into somebody.<br>\nhave a good trip.<br>\nto pass on greetings.<br>\nthere\u2019s a restroom in the caf\u00e9.\n  <\/div>\n\n  <!-- Selectors d'idioma i pausa -->\n  <div>\n    <select id=\"voiceSelect\">\n      <option value=\"\">Selecciona idioma<\/option>\n      <option value=\"en-US\">?? Angl\u00e8s (US)<\/option>\n      <option value=\"en-GB\">?? Angl\u00e8s (UK)<\/option>\n      <option value=\"fr-FR\">?? Franc\u00e8s<\/option>\n      <option value=\"de-DE\">?? Alemany<\/option>\n      <option value=\"it-IT\">?? Itali\u00e0<\/option>\n      <option value=\"pt-PT\">?? Portugu\u00e8s<\/option>\n      <option value=\"es-ES\">?? Espanyol<\/option>\n      <option value=\"ca-ES\">?\ufe0f Catal\u00e0<\/option>\n    <\/select>\n\n    <select id=\"pauseSelect\">\n      <option value=\"1\">\u23f1\ufe0f Pausa x1<\/option>\n      <option value=\"2\">\u23f1\ufe0f Pausa x2<\/option>\n      <option value=\"3\">\u23f1\ufe0f Pausa x3<\/option>\n      <option value=\"4\">\u23f1\ufe0f Pausa x4<\/option>\n      <option value=\"10\">\u23f1\ufe0f Pausa x10<\/option>\n    <\/select>\n  <\/div>\n\n  <!-- Botons de control -->\n  <button id=\"speakBtn\" title=\"Escolta el text\">?<\/button>\n  <button id=\"toggleBtn\" title=\"Atura o repr\u00e8n\">\u23f9\ufe0f<\/button>\n\n  <script>\n    document.addEventListener('DOMContentLoaded', () => {\n      \/\/ Refer\u00e8ncies als elements HTML\n      const editor = document.getElementById('editor');\n      const speakBtn = document.getElementById('speakBtn');\n      const toggleBtn = document.getElementById('toggleBtn');\n      const voiceSelect = document.getElementById('voiceSelect');\n      const pauseSelect = document.getElementById('pauseSelect');\n\n      \/\/ Variables de control\n      let voices = [];\n      let isSpeaking = false;\n      let liniesGuardades = [];\n      let currentIndex = 0;\n\n      \/\/ Carrega les veus disponibles\n      function loadVoices() {\n        voices = speechSynthesis.getVoices();\n      }\n\n      speechSynthesis.onvoiceschanged = loadVoices;\n      loadVoices();\n\n      \/\/ Recupera l'idioma seleccionat anteriorment\n      const idiomaGuardat = localStorage.getItem('idiomaSeleccionat');\n      if (idiomaGuardat) {\n        voiceSelect.value = idiomaGuardat;\n      }\n\n      \/\/ Guarda l'idioma seleccionat\n      voiceSelect.addEventListener('change', () => {\n        localStorage.setItem('idiomaSeleccionat', voiceSelect.value);\n      });\n\n      \/\/ Obt\u00e9 les l\u00ednies del text\n      function getLinies() {\n        const text = editor.innerText || editor.textContent;\n        return text.split('\\n').map(l => l.trim()).filter(l => l);\n      }\n\n      \/\/ Marca visualment la l\u00ednia que s'est\u00e0 llegint\n      function marcarLinia(index) {\n        const linies = editor.querySelectorAll('.linia');\n        linies.forEach((el, i) => {\n          el.classList.toggle('activa', i === index);\n        });\n      }\n\n      \/\/ Converteix el text en elements <span> per poder destacar l\u00ednies\n      function prepararEditor() {\n        const linies = getLinies();\n        editor.innerHTML = '';\n        linies.forEach((text, i) => {\n          const span = document.createElement('span');\n          span.className = 'linia';\n          span.textContent = text;\n          editor.appendChild(span);\n          editor.appendChild(document.createElement('br'));\n        });\n      }\n\n      \/\/ Calcula la pausa entre l\u00ednies segons el selector\n      function getPausaEntreLinies() {\n        const factor = parseInt(pauseSelect.value || '1');\n        return 500 * factor;\n      }\n\n      \/\/ Llegeix una l\u00ednia i programa la seg\u00fcent\n      function speakLinia() {\n        if (currentIndex >= liniesGuardades.length) {\n          isSpeaking = false;\n          setTimeout(() => {\n            speakText(); \/\/ Reinicia autom\u00e0ticament\n          }, 2000);\n          return;\n        }\n\n        const linia = liniesGuardades[currentIndex];\n        const utterance = new SpeechSynthesisUtterance(linia);\n        const voice = voices.find(v => v.lang === voiceSelect.value);\n        if (voice) {\n          utterance.voice = voice;\n          utterance.lang = voice.lang;\n        }\n\n        utterance.rate = 1;\n        utterance.pitch = 1;\n\n        utterance.onstart = () => {\n          isSpeaking = true;\n          marcarLinia(currentIndex);\n        };\n\n        utterance.onend = () => {\n          currentIndex++;\n          setTimeout(() => {\n            speakLinia();\n          }, getPausaEntreLinies());\n        };\n\n        speechSynthesis.speak(utterance);\n      }\n\n      \/\/ Inicia la lectura des del principi\n      function speakText() {\n        if (isSpeaking) return;\n        prepararEditor();\n        liniesGuardades = getLinies();\n        currentIndex = 0;\n        speechSynthesis.cancel();\n        speakLinia();\n      }\n\n      \/\/ Bot\u00f3 ? per iniciar la lectura\n      speakBtn.addEventListener('click', speakText);\n\n      \/\/ Bot\u00f3 \u23f9\ufe0f per aturar o reprendre\n      toggleBtn.addEventListener('click', () => {\n        if (isSpeaking) {\n          speechSynthesis.cancel();\n          isSpeaking = false;\n        } else {\n          speakLinia();\n        }\n      });\n    });\n  <\/script>\n<\/body>\n<\/html>\n\n\n<!-- wp:separator MUT -->\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\" \/>\n\n<!-- \/wp:post-content --><!-- wp:enlighter\/codeblock -->\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">&lt;!DOCTYPE html&gt;\n&lt;html lang=\"ca\"&gt;\n&lt;head&gt;\n  &lt;meta charset=\"UTF-8\"&gt;\n  &lt;title&gt;Conversor de text a veu&lt;\/title&gt;\n  &lt;style&gt;\n    \/* Estil general de la p\u00e0gina *\/\n    body {\n      font-family: sans-serif;\n      padding: 2em;\n      background-color: lab(90.09% -0.67 -0.25);\n    }\n\n    \/* Editor de text editable *\/\n    #editor {\n      font-size: 1.2em;\n      padding: 0.5em;\n      margin-top: 1em;\n      width: 100%;\n      max-width: 500px;\n      height: 15em;\n      overflow-y: auto;\n      border: 1px solid #ccc;\n      white-space: pre-wrap;\n    }\n\n    \/* Estil dels selectors (idioma i pausa) *\/\n    select {\n      font-size: 1.2em;\n      padding: 0.5em;\n      margin-top: 1em;\n      width: 45%;\n      max-width: 220px;\n      height: 2.5em;\n      overflow-y: hidden;\n      display: inline-block;\n      vertical-align: top;\n    }\n\n    \/* Estil dels botons de control *\/\n    #speakBtn, #toggleBtn {\n      font-size: 2em;\n      background: none;\n      border: none;\n      cursor: pointer;\n      margin-top: 1em;\n    }\n\n    #speakBtn:hover, #toggleBtn:hover {\n      color: hsl(180, 1%, 72%);\n    }\n\n    \/* Estil de cada l\u00ednia destacable *\/\n    .linia {\n      display: block;\n      padding: 0.2em;\n      transition: background-color 0.3s ease;\n    }\n\n    \/* L\u00ednia activa mentre es llegeix *\/\n    .activa {\n      background-color: hsl(180, 1%, 72%);\n    }\n  &lt;\/style&gt;\n&lt;\/head&gt;\n&lt;body&gt;\n  &lt;h2&gt;? Conversor de text a veu&lt;\/h2&gt;\n\n  &lt;!-- Editor de text on l'usuari pot escriure --&gt;\n  &lt;div id=\"editor\" contenteditable=\"true\" placeholder=\"Escriu el text que vols escoltar\"&gt;\nto run into somebody.&lt;br&gt;\nhave a good trip.&lt;br&gt;\nto pass on greetings.&lt;br&gt;\nthere\u2019s a restroom in the caf\u00e9.\n  &lt;\/div&gt;\n\n  &lt;!-- Selectors d'idioma i pausa --&gt;\n  &lt;div&gt;\n    &lt;select id=\"voiceSelect\"&gt;\n      &lt;option value=\"\"&gt;Selecciona idioma&lt;\/option&gt;\n      &lt;option value=\"en-US\"&gt;?? Angl\u00e8s (US)&lt;\/option&gt;\n      &lt;option value=\"en-GB\"&gt;?? Angl\u00e8s (UK)&lt;\/option&gt;\n      &lt;option value=\"fr-FR\"&gt;?? Franc\u00e8s&lt;\/option&gt;\n      &lt;option value=\"de-DE\"&gt;?? Alemany&lt;\/option&gt;\n      &lt;option value=\"it-IT\"&gt;?? Itali\u00e0&lt;\/option&gt;\n      &lt;option value=\"pt-PT\"&gt;?? Portugu\u00e8s&lt;\/option&gt;\n      &lt;option value=\"es-ES\"&gt;?? Espanyol&lt;\/option&gt;\n      &lt;option value=\"ca-ES\"&gt;?\ufe0f Catal\u00e0&lt;\/option&gt;\n    &lt;\/select&gt;\n\n    &lt;select id=\"pauseSelect\"&gt;\n      &lt;option value=\"1\"&gt;\u23f1\ufe0f Pausa x1&lt;\/option&gt;\n      &lt;option value=\"2\"&gt;\u23f1\ufe0f Pausa x2&lt;\/option&gt;\n      &lt;option value=\"3\"&gt;\u23f1\ufe0f Pausa x3&lt;\/option&gt;\n      &lt;option value=\"4\"&gt;\u23f1\ufe0f Pausa x4&lt;\/option&gt;\n      &lt;option value=\"10\"&gt;\u23f1\ufe0f Pausa x10&lt;\/option&gt;\n    &lt;\/select&gt;\n  &lt;\/div&gt;\n\n  &lt;!-- Botons de control --&gt;\n  &lt;button id=\"speakBtn\" title=\"Escolta el text\"&gt;?&lt;\/button&gt;\n  &lt;button id=\"toggleBtn\" title=\"Atura o repr\u00e8n\"&gt;\u23f9\ufe0f&lt;\/button&gt;\n\n  &lt;script&gt;\n    document.addEventListener('DOMContentLoaded', () =&gt; {\n      \/\/ Refer\u00e8ncies als elements HTML\n      const editor = document.getElementById('editor');\n      const speakBtn = document.getElementById('speakBtn');\n      const toggleBtn = document.getElementById('toggleBtn');\n      const voiceSelect = document.getElementById('voiceSelect');\n      const pauseSelect = document.getElementById('pauseSelect');\n\n      \/\/ Variables de control\n      let voices = [];\n      let isSpeaking = false;\n      let liniesGuardades = [];\n      let currentIndex = 0;\n\n      \/\/ Carrega les veus disponibles\n      function loadVoices() {\n        voices = speechSynthesis.getVoices();\n      }\n\n      speechSynthesis.onvoiceschanged = loadVoices;\n      loadVoices();\n\n      \/\/ Recupera l'idioma seleccionat anteriorment\n      const idiomaGuardat = localStorage.getItem('idiomaSeleccionat');\n      if (idiomaGuardat) {\n        voiceSelect.value = idiomaGuardat;\n      }\n\n      \/\/ Guarda l'idioma seleccionat\n      voiceSelect.addEventListener('change', () =&gt; {\n        localStorage.setItem('idiomaSeleccionat', voiceSelect.value);\n      });\n\n      \/\/ Obt\u00e9 les l\u00ednies del text\n      function getLinies() {\n        const text = editor.innerText || editor.textContent;\n        return text.split('\\n').map(l =&gt; l.trim()).filter(l =&gt; l);\n      }\n\n      \/\/ Marca visualment la l\u00ednia que s'est\u00e0 llegint\n      function marcarLinia(index) {\n        const linies = editor.querySelectorAll('.linia');\n        linies.forEach((el, i) =&gt; {\n          el.classList.toggle('activa', i === index);\n        });\n      }\n\n      \/\/ Converteix el text en elements &lt;span&gt; per poder destacar l\u00ednies\n      function prepararEditor() {\n        const linies = getLinies();\n        editor.innerHTML = '';\n        linies.forEach((text, i) =&gt; {\n          const span = document.createElement('span');\n          span.className = 'linia';\n          span.textContent = text;\n          editor.appendChild(span);\n          editor.appendChild(document.createElement('br'));\n        });\n      }\n\n      \/\/ Calcula la pausa entre l\u00ednies segons el selector\n      function getPausaEntreLinies() {\n        const factor = parseInt(pauseSelect.value || '1');\n        return 500 * factor;\n      }\n\n      \/\/ Llegeix una l\u00ednia i programa la seg\u00fcent\n      function speakLinia() {\n        if (currentIndex &gt;= liniesGuardades.length) {\n          isSpeaking = false;\n          setTimeout(() =&gt; {\n            speakText(); \/\/ Reinicia autom\u00e0ticament\n          }, 2000);\n          return;\n        }\n\n        const linia = liniesGuardades[currentIndex];\n        const utterance = new SpeechSynthesisUtterance(linia);\n        const voice = voices.find(v =&gt; v.lang === voiceSelect.value);\n        if (voice) {\n          utterance.voice = voice;\n          utterance.lang = voice.lang;\n        }\n\n        utterance.rate = 1;\n        utterance.pitch = 1;\n\n        utterance.onstart = () =&gt; {\n          isSpeaking = true;\n          marcarLinia(currentIndex);\n        };\n\n        utterance.onend = () =&gt; {\n          currentIndex++;\n          setTimeout(() =&gt; {\n            speakLinia();\n          }, getPausaEntreLinies());\n        };\n\n        speechSynthesis.speak(utterance);\n      }\n\n      \/\/ Inicia la lectura des del principi\n      function speakText() {\n        if (isSpeaking) return;\n        prepararEditor();\n        liniesGuardades = getLinies();\n        currentIndex = 0;\n        speechSynthesis.cancel();\n        speakLinia();\n      }\n\n      \/\/ Bot\u00f3 ? per iniciar la lectura\n      speakBtn.addEventListener('click', speakText);\n\n      \/\/ Bot\u00f3 \u23f9\ufe0f per aturar o reprendre\n      toggleBtn.addEventListener('click', () =&gt; {\n        if (isSpeaking) {\n          speechSynthesis.cancel();\n          isSpeaking = false;\n        } else {\n          speakLinia();\n        }\n      });\n    });\n  &lt;\/script&gt;\n&lt;\/body&gt;\n&lt;\/html&gt;\n<\/pre>\n<!-- \/wp:enlighter\/codeblock -->\n\n<!-- \/wp:post-content -->","protected":false},"excerpt":{"rendered":"<p>Conversor de text a veu ? Conversor de text a veu to run into somebody. have a good trip. to pass on greetings. there\u2019s a restroom in the caf\u00e9. Selecciona idioma?? Angl\u00e8s (US)?? Angl\u00e8s (UK)?? Franc\u00e8s?? Alemany?? Itali\u00e0?? Portugu\u00e8s?? Espanyol?\ufe0f &hellip; <a href=\"https:\/\/www.beseit.net\/?page_id=16956\">Continua llegint <span class=\"meta-nav\">&rarr;<\/span><\/a><\/p>\n","protected":false},"author":2,"featured_media":3167,"parent":0,"menu_order":0,"comment_status":"closed","ping_status":"closed","template":"full-width-template.php","meta":{"footnotes":""},"categories":[],"class_list":["post-16956","page","type-page","status-publish","has-post-thumbnail","hentry"],"_links":{"self":[{"href":"https:\/\/www.beseit.net\/index.php?rest_route=\/wp\/v2\/pages\/16956","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.beseit.net\/index.php?rest_route=\/wp\/v2\/pages"}],"about":[{"href":"https:\/\/www.beseit.net\/index.php?rest_route=\/wp\/v2\/types\/page"}],"author":[{"embeddable":true,"href":"https:\/\/www.beseit.net\/index.php?rest_route=\/wp\/v2\/users\/2"}],"replies":[{"embeddable":true,"href":"https:\/\/www.beseit.net\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=16956"}],"version-history":[{"count":25,"href":"https:\/\/www.beseit.net\/index.php?rest_route=\/wp\/v2\/pages\/16956\/revisions"}],"predecessor-version":[{"id":17066,"href":"https:\/\/www.beseit.net\/index.php?rest_route=\/wp\/v2\/pages\/16956\/revisions\/17066"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/www.beseit.net\/index.php?rest_route=\/wp\/v2\/media\/3167"}],"wp:attachment":[{"href":"https:\/\/www.beseit.net\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=16956"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.beseit.net\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=16956"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}