<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<link rel="stylesheet" href="style.css" />
<title>Project #20 - The Text Reader App</title>
</head>
<body>
<div class="container">
<textarea name="text" id="text"></textarea>
<!-- controls wrapper -->
<div class="controls-wrapper">
<div>
<label for="speed">Speed</label>
<input
type="number"
name="speed"
id="speed"
min="0.1"
max="10"
step="0.1"
value="1"
/>
</div>
<button class="read">Read</button>
<button class="pause">Pause</button>
<button class="stop">Stop</button>
</div>
</div>
<!-- -------------------------- -->
<!-- JS File -->
<script src="app.js"></script>
</body>
</html>
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
body {
font-family: Arial, Helvetica, sans-serif;
background-color: #221f3b;
color: white;
min-height: 100vh;
display: flex;
align-items: center;
justify-content: center;
}
textarea {
height: 500px;
width: 1000px;
color: black;
border: none;
outline: none;
padding: 15px;
font-size: 20px;
margin-bottom: 25px;
}
textarea:focus {
background-color: #5d54a4;
color: white;
}
.controls-wrapper {
display: flex;
justify-content: center;
align-items: center;
}
.controls-wrapper > * {
margin-right: 25px;
}
.controls-wrapper label {
font-size: 25px;
margin-right: 8px;
}
.controls-wrapper input {
padding: 7px 15px;
outline: 0;
border: 0;
color: white;
background-color: #5d54a4;
font-size: 20px;
}
.controls-wrapper button {
background: none;
border: none;
outline: none;
color: white;
background-color: #5d54a4;
padding: 10px 20px;
cursor: pointer;
font-size: 20px;
}
const textDisplay = document.querySelector("#text");
const speedBtn = document.querySelector("#speed");
const readBtn = document.querySelector(".read");
const pauseBtn = document.querySelector(".pause");
const stopBtn = document.querySelector(".stop");
let currentChar;
// Rreading Functionality
readBtn.addEventListener("click", function () {
readText(textDisplay.value);
});
// Pausing Functionality
pauseBtn.addEventListener("click", pauseText);
// Stopping Functionality
stopBtn.addEventListener("click", stopText);
// Speed Input Functionality
speedBtn.addEventListener("input", function () {
stopText();//현재 속도로 읽는 건 멈추고
readText(utterance.text.substring(currentChar));
});
/*
https://developer.mozilla.org/en-US/docs/Web/API/SpeechSynthesisUtterance
*/
const utterance = new SpeechSynthesisUtterance();
//speech Api 생성
utterance.addEventListener("end", function () {
//발언이 완료. 글자 입력 허용
textDisplay.disabled = false;
});
utterance.addEventListener("boundary", function (e) {
//발언이 문장 경계에 도달하면 시행
currentChar = e.charIndex;
});
// readText Function
function readText(testText) {
//멈춤상태에서도 speaking은 값이 참이면 실행, 그러면 다시 음성 재개.
if (speechSynthesis.paused && speechSynthesis.speaking) {
return speechSynthesis.resume();
}
//멈추지 않은 상태에서 말한다 --- 음성이 진행중.
if (speechSynthesis.speaking) return;
utterance.text = testText;
utterance.rate = speedBtn.value || 1;
//입력 못하게 막기.
textDisplay.disabled = true;
speechSynthesis.speak(utterance);
}
// pauseText Function
function pauseText() {
if (speechSynthesis.speaking)
//말하는 중에 멈춤 누르면 멈추기.
speechSynthesis.pause();
}
// stopText Function
function stopText() {
speechSynthesis.resume();
speechSynthesis.cancel();
}
This Pen doesn't use any external CSS resources.
This Pen doesn't use any external JavaScript resources.