iTracker Reading App

Lass dir einfach die texte vorlesen. Lesegeschwindigkeit ist einstellbar

Der hier verwendete Code

<!DOCTYPE html> <html> <head> <title>iTracker Reading App | Remarkable Mark</title> <link rel="stylesheet" type="text/css" href="//" /> <style> textarea, .text { width: 100%; } textarea { font-size: 1em; font-size: 1.5rem; height: 18em; line-height: 1.5; } .text { color: #ddd; font-size: 1.35em; font-size: 2rem; letter-spacing: 0.05px; line-height: 1.5; margin-bottom: 8em; /* give some space so reading controls does not cover */ } .text > .active { color: #000; } .formatted-section { display: none; } /* make controls into a sticky footer */ .reading-controls { background: #fff; border-top: 1px solid #eee; bottom: 0; left: 0; padding-top: 1em; position: fixed; text-align: center; width: 100%; } /* read button */ .read:hover { border: 1px solid #33C3F0; } /* format button */ .format:hover { border: 1px solid #33C3F0; color: #22aeda; } /* reformat button */ .reformat { opacity: 0.5; } .reformat:hover { border: 1px solid #ffaeae; color: #df5e5e; opacity: 1; } /* disabled buttons */ .button[disabled], .button[disabeld]:hover { border: 1px solid #bbb; opacity: 0.5; } </style> </head> <body> <div class="container"> <h1>iTracker Reading App</h1> <section class="editable-section"> <textarea onclick="this.focus();;">The artist is the creator of beautiful things. To reveal art and conceal the artist is art's aim. The critic is he who can translate into another manner or a new material his impression of beautiful things. The highest as the lowest form of criticism is a mode of autobiography. Those who find ugly meanings in beautiful things are corrupt without being charming. This is a fault. Those who find beautiful meanings in beautiful things are the cultivated. For these there is hope. They are the elect to whom beautiful things mean only beauty. There is no such thing as a moral or an immoral book. Books are well written, or badly written. That is all. The nineteenth century dislike of realism is the rage of Caliban seeing his own face in a glass. The nineteenth century dislike of romanticism is the rage of Caliban not seeing his own face in a glass. The moral life of man forms part of the subject-matter of the artist, but the morality of art consists in the perfect use of an imperfect medium. No artist desires to prove anything. Even things that are true can be proved. No artist has ethical sympathies. An ethical sympathy in an artist is an unpardonable mannerism of style. No artist is ever morbid. The artist can express everything. Thought and language are to the artist instruments of an art. Vice and virtue are to the artist materials for an art. From the point of view of form, the type of all the arts is the art of the musician. From the point of view of feeling, the actor's craft is the type. All art is at once surface and symbol. Those who go beneath the surface do so at their peril. Those who read the symbol do so at their peril. It is the spectator, and not life, that art really mirrors. Diversity of opinion about a work of art shows that the work is new, complex, and vital. When critics disagree, the artist is in accord with himself. We can forgive a man for making a useful thing as long as he does not admire it. The only excuse for making a useless thing is that one admires it intensely.</textarea> <button class="format">Format</button> </section> <section class="formatted-section"> <hr /> <div class="text"></div> <div class="reading-controls"> <button class="read button">Read</button> <button class="pause button">Pause</button> <button class="reset button">Reset</button> <input class="delay" type="number" value="250" placeholder="Reading Speed" /> <input class="chunk" type="number" value="3" placeholder="Chunk Size" /> <button class="reformat button">Reformat</button> </div> </section> </div> <script> // The MIT License (MIT) // iTracker Reading App | Copyright (c) 2015 Menglin "Mark" Xu | // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal // in the Software without restriction, including without limitation the rights // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell // copies of the Software, and to permit persons to whom the Software is // furnished to do so, subject to the following conditions: // The above copyright notice and this permission notice shall be included in // all copies or substantial portions of the Software. // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN // THE SOFTWARE. (function(){ // Cache all the DOM elements var textareaNode = document.getElementsByTagName("textarea")[0]; var formatButton = document.getElementsByClassName("format")[0]; var textNode = document.getElementsByClassName("text")[0]; var readButton = document.getElementsByClassName("read")[0]; var pauseButton = document.getElementsByClassName("pause")[0]; var resetButton = document.getElementsByClassName("reset")[0]; var editableSection = document.getElementsByClassName("editable-section")[0]; var formattedSection = document.getElementsByClassName("formatted-section")[0]; var reformatButton = document.getElementsByClassName("reformat")[0]; // Splits text based on pattern function splitText(text, pattern) { // Do not continue if text is invalid if (typeof text !== "string" && text) { return []; } // Split text based on pattern var splitText = text.split(pattern); // Return array if no instance of pattern was found if (splitText.length === 1) { return splitText; } // Clean if at least one instance of pattern was found for (var i = splitText.length - 1; i > -1; i--) { // Remove empty arrays if (!splitText[i]) { splitText.splice(i, 1); } } return splitText; } // Formats the text in the textarea when button is clicked formatButton.onclick = function() { var raw, paragraphs, words, output = [], i, j, n = 0; // Extract raw text from textarea raw = textareaNode.value; paragraphs = splitText(raw, "\n"); // Iterate over the paragraphs for (i = 0; i < paragraphs.length; i++) { output[i] = []; words = splitText(paragraphs[i], " "); // Iterate over the words for (j = 0; j < words.length; j++) { output[i][j] = "<span class=" + n + ">" + words[j] + "</span>"; n++; } // Join the words array output[i] = output[i].join(" "); } // Join the paragraphs array textNode.innerHTML = output.join("<br /><br />"); // Show formatted section and hide editable section = "block"; = "none"; return; }; // Declare and initialize globals var spanNodes = [], index = 0, operation; // Executes the reading app's main operation readButton.onclick = function() { // Disable read button and enable pause button readButton.disabled = true; pauseButton.disabled = false; // Cache input values var delay = Number(document.getElementsByClassName("delay")[0].value); var chunk = Number(document.getElementsByClassName("chunk")[0].value); spanNodes = textNode.getElementsByTagName("span"); // Clear any highlighted words before the current index for (var i = 0; i < index - chunk; i++) { spanNodes[i].className = ""; } operation = setInterval(function() { // Ensure the unhighlighted words are within range for (var i = 0; i < chunk; i++) { if (index - i - 1 >= 0) { spanNodes[index - i - 1].className = ""; } } // Ensure the highlighted words are within range for (var i = 0; i < chunk; i++) { if (index + i < spanNodes.length) { spanNodes[index + i].className = "active"; } // If beyond scope, clear the timed interval operation else { clearInterval(operation); } } index += chunk; return; }, delay); return; }; // Pauses the reading app pauseButton.onclick = function() { // Disable pause button and enable read button readButton.disabled = false; pauseButton.disabled = true; clearInterval(operation); return; }; // Resets the reading app resetButton.onclick = function() { // Enable both read button and pause button readButton.disabled = false; pauseButton.disabled = false; // Clear any operation clearInterval(operation); if (typeof spanNodes === "object") { for (var i = 0; i < spanNodes.length; i++) { spanNodes[i].className = ""; } } index = 0; return; }; // Allow the text to be editable again reformatButton.onclick = function() { // Show editable section and hide formatted section = "block"; = "none"; return; }; })(); </script> </body> </html>