How Fast Can You Type?

https://ngtrangtee.github.io/JavaScript%20DOM/jsdom-bai8/index-8.html

HTML Code

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <link rel="preconnect" href="https://fonts.gstatic.com">
    <link href="https://fonts.googleapis.com/css2?family=Open+Sans:ital,wght@0,400;0,600;0,700;0,800;1,400&display=swap"
        rel="stylesheet">
    <link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/font-awesome/4.7.0/css/font-awesome.min.css"
        integrity="sha384-wvfXpqpZZVQGK6TAh5PVlGOfQNHSoD2xbE+QkPxCAFlNEevoEH3Sl0sibVcOQVnN" crossorigin="anonymous">
    <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0/css/bootstrap.min.css"
        integrity="sha384-Gn5384xqQ1aoWXA+058RXPxPg6fy4IWvTNh0E263XmFcJlSAwiGgFAW/dAiS6JXm" crossorigin="anonymous">
    <link rel="stylesheet" href="./style.css">
    <title>Document</title>
</head>

<body>
    <!-- ======== QUÊN MẬT KHẨU ======== -->
    <div id="forgot-container">
        <div class="container bg-white p-4">
            <h3>Khôi phục Mật khẩu</h3>
            <p>Điền vào email mà bạn sử dụng để đăng kí. Chúng tôi sẽ gửi email khôi phục mật khẩu cho bạn.</p>

            <div class="input-group mb-3">
                <input type="text" class="form-control" placeholder="Username" aria-label="username"
                    aria-describedby="basic-addon2">
                <div class="input-group-append">
                    <button class="btn btn-info pl-4 pr-4">Gửi</button>
                </div>
            </div>
            <button class="btn-link-login">Quay lại đăng nhập</button>
        </div>
    </div>

    <!-- ======== ĐĂNG NHẬP - ĐĂNG KÝ ======== -->
    <div id="login-container">
        <div class="container bg-white p-4">
            <ul class="nav nav-tabs" role="tablist">
                <li class="nav-item">
                    <a class="nav-link active" id="login-tab" data-toggle="tab" href="#login" role="tab"
                        aria-controls="login" aria-selected="true">Đăng nhập</a>
                </li>
                <li class="nav-item">
                    <a class="nav-link" id="register-tab" data-toggle="tab" href="#register" role="tab"
                        aria-controls="register" aria-selected="false">Tạo tài khoản</a>
                </li>
            </ul>
            <div class="tab-content">
                <div class="tab-pane fade show active mt-4" id="login" role="tabpanel" aria-labelledby="login-tab">
                    <div class="row">
                        <div class="col-md-6">
                            <div class="form-group">
                                <label for="login-username" class="font-weight-bold">Tên đăng nhập</label>
                                <input type="email" class="form-control" id="login-username"
                                    aria-describedby="login-username">
                            </div>
                        </div>
                    </div>
                    <div class="row">
                        <div class="col-md-6">
                            <div class="form-group">
                                <label for="login-password" class="font-weight-bold">Mật khẩu</label>
                                <input type="password" class="form-control" id="login-password">
                            </div>
                        </div>
                    </div>

                    <button type="submit" class="btn btn-info pl-5 pr-5" id="btn-login">Đăng nhập</button>

                    <button class="btn-link-forgot-password">Bạn quên mật khẩu?</button>
                </div>
                <div class="tab-pane fade mt-4" id="register" role="tabpanel" aria-labelledby="register-tab">
                    <div class="row">
                        <div class="col-md-6">
                            <div class="form-group">
                                <label for="register-username" class="font-weight-bold">Tên đăng nhập</label>
                                <input type="email" class="form-control" id="register-username"
                                    aria-describedby="register-username">
                            </div>
                        </div>
                    </div>
                    <div class="row">
                        <div class="col-md-6">
                            <div class="form-group">
                                <label for="register-password" class="font-weight-bold">Mật khẩu</label>
                                <input type="password" class="form-control" id="register-password">
                            </div>
                        </div>
                    </div>
                    <div class="row">
                        <div class="col-md-6">
                            <div class="form-group">
                                <label for="register-confirm-password" class="font-weight-bold">Nhập lại mật
                                    khẩu</label>
                                <input type="password" class="form-control" id="register-confirm-password">
                            </div>
                        </div>
                    </div>
                    <div class="row">
                        <div class="col-md-6">
                            <div class="form-group">
                                <label for="register-password" class="font-weight-bold">Ảnh đại diện</label>
                                <input type="text" class="form-control" id="register-avatar">
                            </div>
                        </div>
                    </div>

                    <button type="submit" class="btn btn-success pl-5 pr-5" id="btn-register">Đăng ký</button>
                </div>
            </div>
        </div>
    </div>
    <!-- ======== CHƠI GAME ======== -->
    <div id="game-container">
        <div class="container mt-5">

            <!-- Đăng nhập + Chọn ngôn ngữ -->
            <div id="btn-container" class="mb-3">
                <button class="btn btn-login">Đăng nhập</button>
                <select id="chose-language" class="btn">
                    <option value="1">Vietnamese</option>
                    <option value="2">English</option>
                </select>
            </div>

            <!-- Nơi hiển thị từ để gõ -->
            <div id="words">
                <span class="correct">không</span>
                <span class="correct">tượng</span>
                <span class="wrong">nguyễn</span>
                <span class="wrong">zing</span>
                <span class="correct">lịch</span>
                <span class="correct">chủ</span>
                <span class="highlight">cũng</span>
                <span>mệt</span>
                <span>cái</span>
                <span>an</span>
                <span>về</span>
                <span>thứ</span>
                <span>thành</span>
                <span>cộng</span>
                <span>sa</span>
                <span>anh</span>
                <span>hài</span>
                <span>qua</span>
                <span>đến</span>
                <span>nạn</span>
                <span>mạng</span>
                <span>hơn</span>
                <span>an</span>
            </div>

            <!-- Gõ từ + Hiển thị thời gian + Reload -->
            <div id="control">
                <input type="text" id="input-word">
                <p id="time">1:00</p>
                <button class="btn btn-reload">
                    <i class="fa fa-refresh" aria-hidden="true"></i>
                </button>
            </div>

            <!-- Hiển thị kết quả của người chơi -->
            <div id="info" class="mt-5 mb-5">
                <div class="result">
                    <p class="result-title">Kết quả</p>
                    <div class="result-wpm">
                        <span class="wpm-count">0 WPM</span>
                        <span class="wpm-mess">(từ mỗi phút)</span>
                    </div>
                    <div class="result-item">
                        <div>Tổ hợp phím</div>
                        <div class="character-count-box">
                            <p>
                                (
                                <span class="character-correct-count text-success">0</span>
                                |
                                <span class="character-wrong-count text-danger">0</span>
                                )
                            </p>
                            <p class="character-count">0</p>
                        </div>
                    </div>
                    <div class="result-item">
                        <div>Độ chính xác</div>
                        <div class="words-accuracy font-weight-bold words-accuracy">00.00%</div>
                    </div>
                    <div class="result-item">
                        <div>Những từ đúng</div>
                        <div class="text-success words-correct font-weight-bold">0</div>
                    </div>
                    <div class="result-item">
                        <div>Những từ sai</div>
                        <div class="text-danger words-danger font-weight-bold">0</div>
                    </div>
                </div>
            </div>
        </div>

        <!-- Bảng xếp hạng người chơi -->
        <div class="container mb-5" id="ranking-container">
            <h4 class="mb-3 text-uppercase">Bảng xếp hạng (top 10)</h4>
            <table class="table bg-white">
                <thead>
                    <tr>
                        <th scope="col">#</th>
                        <th scope="col">Ảnh đại diện</th>
                        <th scope="col">Tên đăng nhập</th>
                        <th scope="col">WPM</th>
                        <th scope="col">Thời gian</th>
                    </tr>
                </thead>
                <tbody>
                    <tr>
                        <td>1.</td>
                        <td>
                            <img src="https://images.unsplash.com/photo-1504593811423-6dd665756598?ixid=MnwxMjA3fDB8MHxzZWFyY2h8MTR8fHBlcnNvbnxlbnwwfHwwfHw%3D&ixlib=rb-1.2.1&auto=format&fit=crop&w=500&q=60"
                                alt="">
                        </td>
                        <td>Bùi Văn Hiên</td>
                        <td class="font-weight-bold">151</td>
                        <td class="font-italic">11:20:25 - 23/04/2021</td>
                    </tr>
                    <tr>
                        <td>2.</td>
                        <td>
                            <img src="https://images.unsplash.com/photo-1569124589354-615739ae007b?ixid=MnwxMjA3fDB8MHxzZWFyY2h8MzN8fHBlcnNvbnxlbnwwfHwwfHw%3D&ixlib=rb-1.2.1&auto=format&fit=crop&w=500&q=60"
                                alt="">
                        </td>
                        <td>Nguyễn Thu Hằng</td>
                        <td class="font-weight-bold">148</td>
                        <td class="font-italic">15:41:32 - 22/04/2021</td>
                    </tr>
                    <tr>
                        <td>3.</td>
                        <td>
                            <img src="https://images.unsplash.com/photo-1595399874399-10f2444c4eb2?ixid=MnwxMjA3fDB8MHxzZWFyY2h8NTN8fHBlcnNvbnxlbnwwfHwwfHw%3D&ixlib=rb-1.2.1&auto=format&fit=crop&w=500&q=60"
                                alt="">
                        </td>
                        <td>Phạm Văn Minh</td>
                        <td class="font-weight-bold">147</td>
                        <td class="font-italic">19:11:54 - 23/04/2021</td>
                    </tr>
                </tbody>
            </table>
        </div>
    </div>

    <script src="https://code.jquery.com/jquery-3.2.1.slim.min.js"
        integrity="sha384-KJ3o2DKtIkvYIK3UENzmM7KCkRr/rE9/Qpg6aAZGJwFDMVNA/GpGFF93hXpG5KkN"
        crossorigin="anonymous"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.12.9/umd/popper.min.js"
        integrity="sha384-ApNbgh9B+Y1QKtv3Rn7W3mgPxhU9K/ScQsAP7hUibX39j7fakFPskvXusvfa0b4Q"
        crossorigin="anonymous"></script>
    <script src="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0/js/bootstrap.min.js"
        integrity="sha384-JZR6Spejh4U02d8jOt6vLEHfe/JQGiRRSQQxSfFWpi1MquVdAyjUar5+76PVCmYl"
        crossorigin="anonymous"></script>

    <!-- <script src="link.js"></script> -->
    <script src="./main.js"></script>
</body>

</html>

JS Code

body {
  background: #f0f2f5;
}

.container {
  display: block;
  width: 980px;
  margin-left: auto;
  margin-right: auto;
  padding-top: 112px;
  padding-bottom: 72px;
}
.left {
  box-sizing: border-box;
  display: inline-block;
  width: 580px;
  padding-right: 32px;
  vertical-align: top;
}
.logo-facebook {
  width: 301.06px;
  margin: 0%;
}

.left h2 {
  font-family: Arial, Helvetica, sans-serif;
  font-size: 28px;
  font-weight: normal;
  width: 500px;
  margin-top: 0%;
  position: relative;
}

.right {
  display: inline-block;
  width: 396px;
  vertical-align: top;
}

.upper-right {
  align-items: center;
  background-color: #fff;
  border: none;
  border-radius: 8px;
  box-shadow: 0 2px 4px rgb(0 0 0 / 10%), 0 8px 16px rgb(0 0 0 / 10%);
  box-sizing: border-box;
  margin: 40px 0 0;
  padding: 20px 0 28px;
  width: 396px;
}

.login-form {
  box-sizing: border-box;
  width: 100%;
  padding-left: 20px;
  padding-right: 20px;
}
.email-sdt {
  box-sizing: border-box;
  width: 100%;
  display: block;
  padding: 6px;
}

.upper-right .login-form input {
  box-sizing: border-box;
  border-radius: 6px;
  font-size: 17px;
  padding: 14px 16px;
  width: 100%;
  border: 1px solid #dddfe2;
  list-style: 16px;
  vertical-align: middle;
}

.password {
  padding: 14px 6px;
  box-sizing: border-box;
  width: 100%;
}

.dang-nhap {
  box-sizing: border-box;
  padding-top: 6px;
  width: 100%;
  margin-left: auto;
  margin-right: auto;
  cursor: pointer;
  position: relative;
  border-radius: 6px;
  border: none;
  font-size: 20px;
  line-height: 48px;
  padding: 0 16px;
  width: 100%;
  background-color: #1877f2;
  color: white;
  font-size: 20px;
  font-weight: bolder;
}

.quen-mat-khau {
  display: block;
  color: #1877f2;
  font-size: 14px;
  font-weight: 500;
  cursor: pointer;
  text-decoration: none;
  font-family: Arial, Helvetica, sans-serif;
  text-align: center;
  margin-top: 16px;
}

.line {
  align-items: center;
  border-bottom: 1px solid #dadde1;
  display: flex;
  margin: 20px 16px;
  text-align: center;
}

.tao-tai-khoan-moi {
  text-align: center;
}

#tao-tai-khoan-moi {
  font-family: Arial, Helvetica, sans-serif;
  padding-top: 6px;
  border: none;
  border-radius: 6px;
  font-size: 17px;
  line-height: 48px;
  padding: 0 16px;
  cursor: pointer;
  display: inline-block;
  text-decoration: none;
  background-color: #42b72a;
  color: #fff;
  position: relative;
  text-align: center;
}

#popup {
  display: none;
}

#popup:not(:checked) + .popup {
  visibility: hidden;
}

#popup:checked + .popup {
  visibility: visible;
  background-color: rgb(255 255 255 / 50%);
}

.popup {
  box-sizing: border-box;
  position: fixed;
  /* Để căn giữa với position */
  top: 0;
  left: 0;
  right: 0;
  bottom: 0;
}

.popup-content {
  position: fixed;
  box-sizing: border-box;
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%);
  background-color: #fff;
  border-radius: 8px;
  overflow: hidden;
  width: 432px;
  padding: 10px;
  box-shadow: 0 2px 4px rgb(0 0 0 / 10%), 0 8px 16px rgb(0 0 0 / 10%);
}

#close{
    position: absolute;
    right: 11px;
    top: 11px;
    cursor: pointer;
}
.tao-tai-khoan-moi > h2{
    font-family: Helvetica, Arial, sans-serif;
    text-align: left;
    padding-left: 11px;
    font-size: 30px;
    margin-bottom: 0%;
    margin-top: 0%;
}

h2 + p{
    text-align: left;
    font-family: Helvetica, Arial, sans-serif;
    padding-left: 13px;
    margin-top: 0%;

}
.ho {
  display: inline-block;
  border-color: #ccd0d5;
  margin-left: 0%;
  position:relative;
}

.ten {
  display: inline-block;
  border-color: #ccd0d5;
  position:relative;
}

#ho,
#ten {
  position: relative;
  font-family: Helvetica, Arial, sans-serif;
  font-size: 15px;
  line-height: 16px;
  padding: 12px;
  border-radius: 5px;
  width: 80%;
  border: 1px solid #ccd0d5;
  width: 160px;
  margin-bottom: 11px;
}

#sdt-hoac-email:invalid {
  border: 1px solid red;
}

#ho:invalid {
   border: 1px solid red;
}

#ten:invalid{
   border: 1px solid red;
}

#mat-khau-moi:invalid {
  border-color: red;
}

.sdt-hoac-email {
    width: 383px;
    margin-left: auto;
    margin-right: auto;
    margin-bottom: 11px;
}
#sdt-hoac-email {
  box-sizing: border-box;
  border: 1px solid #ccd0d5;
  border-radius: 5px;
  border-color: #ccd0d5;
  width: 100%;
  font-family: Arial, Helvetica, sans-serif;
  font-size: 15px;
  line-height: 16px;
  padding: 11px;
}

.mat-khau-moi {
    width: 383px;
    margin-left: auto;
    margin-right: auto;
    margin-bottom: 11px;
}
#mat-khau-moi {
  box-sizing: border-box;
  border: 1px solid #ccd0d5;
  border-radius: 5px;
  border-color: #ccd0d5;
  width: 100%;
  font-family: Arial, Helvetica, sans-serif;
  font-size: 15px;
  line-height: 16px;
  padding: 11px;
}

.line-dang-ki {
  align-items: center;
  border-bottom: 1px solid #dadde1;
  display: flex;
  margin-top: 16px;
  margin-bottom: 16px;
  text-align: center;
  width: 100%;
}

.ngay-sinh > p {
  color: #606770;
  font-family: Helvetica, Arial, sans-serif;
  font-size: 12px;
  font-weight: normal;
  line-height: 20px;
  margin-bottom: 0;
  margin-top: 2px;
  text-align: left;
  padding-left: 11px;
}
.ngay-sinh{
  display: block;
  margin-left: 4px;
  margin-right: 4px;
}

#ngay, #thang, #nam{
  display: inline-block;
  width: 30%;
    border-radius: 4px;
    color: #1c1e21;
    font-family: Helvetica, Arial, sans-serif;
    font-size: 15px;
    font-weight: normal;
    height: 36px;
    line-height: 20px;
    border: 1px solid #ccd0d5;
}

#thang {
  height: 40px;
}

.ngay-sinh ~ p{
  color: #777;
  font-size: 11px;
  font-family: Arial, Helvetica, sans-serif;
  margin-left:14px ;
  margin-right: 14px;
  text-align: justify;
}

#submit {
  background-color: #00a400;
  border: none;
  border-radius: 6px;
  box-shadow: none;
  color: #fff;
  font-size: 18px;
  font-weight: 600;
  height: 36px;
  overflow: hidden;
  padding: 0 32px;
  text-shadow: none;
}

#submit:hover{
  background: linear-gradient(#79bc64, #578843);
}

.material-icons{
  position: absolute ;
}

.below-right{
  display: block;
  font-family: Arial, Helvetica, sans-serif;
  text-align: justify;
  width: 100%;
  margin-left: auto;
  margin-right: auto;
  font-size: 12px;
}

CSS Code

*,
*::after,
*::before {
    padding: 0;
    margin: 0;
    box-sizing: border-box;
}

body {
    background: #add5ff;
    overflow-x: hidden;

    font-family: 'Open Sans', sans-serif;
    line-height: 1.428571429;
    color: #333;

    display: flex;
    flex-direction: column;
    justify-content: center;
}

.container {
    width: 1000px;
}

#chose-language option {
    display: inline-block;
    padding: 0.5rem 0;
}

.btn-login {
    color: #fff;
    background-color: #428bca;
    border-color: #357ebd;
    margin-right: 1rem;
}

.btn-chose-language {
    color: #fff;
    background-color: #5cb85c;
    border-color: #4cae4c;
}

#words {
    padding: 1rem;
    background: #ffffff;
    border: 1px solid #8eb6d8;
}

#words span {
    display: inline-block;
    font-size: 2.2em;
    line-height: 1.6em;
    padding: 3px 5px 3px 5px;
}

#words span.highlight {
    background: #dddddd;
    color: #000;
    -webkit-border-radius: 3px;
    -moz-border-radius: 3px;
    border-radius: 3px;
}

#words span.highlight-wrong {
    background: red;
    color: #000;
    -webkit-border-radius: 3px;
    -moz-border-radius: 3px;
    border-radius: 3px;
}

#words span.wrong {
    color: red;
}

#words span.correct {
    color: green;
}

#control {
    padding: 1rem;
    background: #a7c8e7;
    -webkit-border-radius: 4px;
    border-radius: 4px;

    display: flex;
    justify-content: center;
    align-items: center;
}

#input-word {
    height: 50px;
    font-size: 2em;
    line-height: 1em;
    color: #333;

    padding: 6px 12px;
    border: 1px solid #ccc;
    border-radius: 4px;
    outline: none;
    transition: border-color ease-in-out 0.15s, box-shadow ease-in-out 0.15s;
}

#input-word:focus {
    outline: none;
    border: 1px solid #000;
}

#time {
    line-height: 50px;
    height: 50px;
    text-align: center;
    font-size: 1.6em;
    -webkit-border-radius: 3px;
    -moz-border-radius: 3px;
    border-radius: 3px;
    color: white;
    background: #3c4d5c;
    margin: 0 1rem;
    padding: 0 0.5rem;
}

.btn-reload {
    height: 50px;
    padding: 10px 16px;
    font-size: 18px;
    line-height: 1.33;
    border-radius: 6px;

    color: #fff;
    background-color: #428bca;
    border-color: #357ebd;
}
/* ============ Result ============== */
#info {
    width: 300px;
    background-color: #fff;
}
.result-title {
    color: #fff;
    background: #4d7f9f;
    font-size: 16px;
    padding: 8px 15px;
    margin: 0px;
    font-weight: bold;
    text-shadow: 1px 1px 1px #333333;
    border-radius: 3px 3px 0px 0px;
}

.result-wpm {
    border-bottom: 1px solid #ccc;
    padding-top: 0.5rem;
    padding-bottom: 1rem;
}

.wpm-count {
    font-size: 46px;
    color: #527a1e;
    display: block;
    text-align: center;
    font-weight: 600;
}

.wpm-mess {
    color: #81888c;
    font-size: 12px;
    display: block;
    text-align: center;
}

.result-item {
    display: flex;
    justify-content: space-between;
    border-bottom: 1px solid #ccc;
    padding: 1rem;
}

.character-count-box {
    display: flex;
}

.character-count-box p {
    margin-bottom: 0;
}

.character-count {
    margin-left: 0.5rem;
}

/* ============ RANKING ============== */
#ranking-container img {
    width: 50px;
    height: 50px;
    border-radius: 50%;
    object-fit: cover;
}

#ranking-container td {
    line-height: 50px;
}

/* ============ LOGIN ============== */
#login-container {
    height: 100vh;
    overflow: hidden;

    display: flex;
    justify-content: center;
    align-items: center;

    display: none;
}

.btn-link-forgot-password,
.btn-link-login {
    display: block;
    border: none;
    background-color: transparent;
    color: #428bca;
    margin-top: 1.5rem;
}

/* ============ FORGOT ============== */
#forgot-container {
    height: 100vh;
    overflow: hidden;

    display: flex;
    justify-content: center;
    align-items: center;

    display: none;
}

#forgot-container h3 {
    color: #F06102;
    font-size: 18px;
    line-height: 32px;
    margin-top: 20px;
    border-bottom: 1px solid #eee;
    margin-bottom: 30px;
}

JS Code

// Truy cập vào các thành phần
const wordsEl = document.querySelector("#words");
const inputWordEl = document.querySelector("#input-word");
const timeEl = document.querySelector("#time");
const btnReload = document.querySelector(".btn-reload");
const languageEl = document.querySelector("#chose-language");

const wordsCorrectEl = document.querySelector('.words-correct')
const wordsWrongEl = document.querySelector('.words-danger')
const wordsAccuracyEl = document.querySelector('.words-accuracy')
const wpmEl = document.querySelector(".wpm-count");
const characterCorrectEl = document.querySelector(".character-correct-count");
const characterWrongEl = document.querySelector('.character-wrong-count')
const characterCountEl = document.querySelector(".character-count");

const tableEl = document.querySelector("tbody")

// Đặt biến global cho loginUser
let loginUser = []

// Khai báo biến
let string_vietnamese =
	"Tôi trả tiền làm tượng nhưng cũng không hài lòng Anh Tú Thứ năm Chủ khu du lịch An sapa Sa Pa Lào Cai nghĩ cộng đồng mạng nên có cái nhìn chính xác hơn về sự cố liên quan đến tượng Nữ thần Tự do vừa qua Chia sẻ với Zing ông Nguyễn Ngọc Đông chủ khu An sapa thừa nhận rất mệt mỏi trong những ngày qua khi trở thành nạn nhân của cộng đồng mạng";

let string_english =
	"This shows us that the global nature needs our lives in the planet It involved all of us even if in many ways different and unequivocal And in this way it teaches us even more on what we have to do to create a just planet fair and safe from an environmental point of view In brief the Covid pandemic has taught us this interdependence this sharing together";

let language = {
	1: string_vietnamese,
	2: string_english,
};

let time;
let words;
let interval; //xét đếm ngược
let index; //Thứ tự của từ trong mảng; dựa vào đây để highlight lên
let isPlaying; //khi gõ, mặc định là false, khi gõ là true

languageEl.addEventListener("change", function () {
	init();
});

btnReload.addEventListener("click", function () {
	init();
});

function randomWords(arr) {
	return arr.sort(function () {
		return Math.random() - 0.5;
	});
}

// Render từ
function renderWords(arr) {
	// Render thời gian
	// xóa nội dung bảng
	wordsEl.innerHTML = "";
	for (let i = 0; i < arr.length; i++) {
		const w = arr[i];
		wordsEl.innerHTML += `<span>${w}</span>`;
	}
}

// Convert thời gian từ giây sang phút và giây
function convertTime(num) {
	let minute = `0${Math.floor(num / 60)}`.slice(-2); //Nếu có số nhỏ hơn 10 thì có số 0 đằng trước; thay vì phải kiểm tra lớn
	let second = `0${num % 60}`.slice(-2);
	return `${minute}:${second}`; // trả về chuỗi
}

// Truy cập vào spans
function highlightWord(index) {
	let spans = document.querySelectorAll("#words span");
	//xóa hết các phần đã highlight đi
	// Array.from(spans).map(span => span.classList.remove ('highlight')) //convert span sang mảng; muốn dùng Map thì phải đổi sang mảng mới dùng được; duyệt qua các phần tử của span và làm gì đó với các phần tử mà không thay đổi độ dài của mảng
	for (let i = 0; i < spans.length; i++) {
		spans[i].classList.remove("highlight");
	}
	spans[index].classList.add("highlight"); //lấy phần tử có chỉ số alf index và highlight vào
}

// Khi ấn dấu cách thì chuyển sang từ tiếp theo
inputWordEl.addEventListener("keyup", function (e) {
	if (!isPlaying) {
		interval = setInterval(countdownTime, 1000);
		isPlaying = true;
	}
	// Kiểm tra tại thời điểm gõ
	checkCurrentWord(e.target.value.trim(), words[index]); //tham số 1 = ô input, tham số 2- từ của mình

	// Chuyển sang từ tiếp theo
	if (e.keyCode == 32) {
		compareWord(e.target.value.trim(), words[index]); // Kiểm tra tại thời điểm next
		index++; // Tăng lại index lên 1, Chuyển sang từ tiếp theo
		highlightWord(index); //chuyển sang từ tiếp theo
		e.target.value = ""; //hoặc this.value = '' hoặc inputWordEl.value = ''
	}
});

function checkCurrentWord(inputValue, word) {
	let spans = document.querySelectorAll("#words span");

	if (!word.startsWith(inputValue)) {
		spans[index].classList.add("highlight-wrong");
	} else {
		spans[index].classList.remove("highlight-wrong");
	}
}

function compareWord(inputValue, word) {
	let spans = document.querySelectorAll("#words span");
	Array.from(spans).map((span) => span.classList.remove("highlight-wrong"));

	if (!word.startsWith(inputValue)) {
		spans[index].classList.add("wrong");
	} else if (word.startsWith(inputValue) && inputValue.length < word.length) {
		spans[index].classList.add("wrong");
	} else {
		spans[index].classList.add("correct");
	}
}

function countdownTime() {
	time--;
	timeEl.innerText = convertTime(time);

	if (time == 0) {
		clearInterval(interval);
		inputWordEl.disabled = true;
		inputWordEl.value = "";

		UpdateInfoPlayer();

		// B2 - chèn vào khi hết thời gian
		insertInfoPlayerToRanking()
	}
}

// Khai báo biến global
let wpmRanking = 0

function UpdateInfoPlayer() {
	let spans = document.querySelectorAll('#words span')
	let totalCorrectWords = 0
	let totalWrongWords = 0

	let totalCorrectCharacters = 0;
	let totalWrongCharacters = 0;

	for (let i = 0; i < spans.length; i++) {//Duyệt qua mảng span
		if (spans[i].classList.contains('correct')) {
			totalCorrectWords++
			totalCorrectCharacters += spans[i].innerText.length;
		}
		if (spans[i].classList.contains("wrong")) {
			totalWrongWords++;
			totalWrongCharacters += spans[i].innerText.length;
		}

	} 
	wpmRanking = totalWrongWords + totalCorrectWords
	wpmEl.innerText = Math.floor(((totalWrongCharacters + totalCorrectCharacters) / 5) / (10 / 60)) + " WPM"
	wordsAccuracyEl.innerText = ((totalCorrectWords / (totalCorrectWords + totalWrongWords) * 100).toFixed(2)) + '%';
	wordsCorrectEl.innerText = totalCorrectWords
	wordsWrongEl.innerText = totalWrongWords
	characterCorrectEl.innerText = totalCorrectCharacters
	characterWrongEl.innerText = totalWrongCharacters;
	characterCountEl.innerText = totalCorrectCharacters + totalWrongCharacters
}


// Lấy nội dung của thẻ span 
// tính độ dài của thẻ span 
// Khởi tạo, vừa vào trang sẽ gọi function này ra luôn
function init() {
	// 
	inputUsername.value = '';
	inputPassword.value = '',
	inputRegisterUsername.value = '';
	inputRegisterPassword.value = '',
	inputRegisterAvatar.value = '';
	// Lấy thông tin user từ trong login ra
	getDataFromLocalStorage()

	time = 10;
	index = 0; //truyền thẻ span có index = 0 - mặc định
	// Chọn ngôn ngữ
	isPlaying = false;
	inputWordEl.disabled = false;
	// Lấy ra giá trị 1 và 2
	// Mỗi lần chọn ngon ngữ mới sẽ thay dỏi intit một làần
	// Dựa vào giá trị 1 và 2, tạo ra objet

	if (interval) {
		clearInterval(interval); //khi đổi ngôn ngữ, load lại trang
	}
	inputWordEl.value = "";

	// Chuyển sang ngôn ngữ
	let languageValue = languageEl.value;
	words = language[languageValue].toLowerCase().split(" ");

	// Đổi vị trí các từ
	words = randomWords(words);

	// Gọi function renderWords
	renderWords(words);

	// Hiển thị thời gian
	timeEl.innerText = convertTime(time);

	// Hiển thị highlight
	highlightWord(index);
}

// Function lấy thông tin user từ phần login 
	// Khi mới vào trang, lấy thông tin user ra, lưu vào một biến global user để dùng vào các chỗ khác
function getDataFromLocalStorage() {
	let dataLocal = localStorage.getItem('user');
	if (JSON.parse(dataLocal)) {
		loginUser = JSON.parse(dataLocal)
	} else {
		loginUser = []
	}
	console.log(loginUser)

}

// Mock up mảng rank
let ranking = [
	{
		avatar: "https://images.unsplash.com/photo-1507525428034-b723cf961d3e?ixid=MnwxMjA3fDB8MHxzZWFyY2h8MXx8bmhhJTIwdHJhbmclMjBiZWFjaHxlbnwwfHwwfHw%3D&ixlib=rb-1.2.1&w=1000&q=80",
		username: "Nguyen Van A",
		wpm: 10,
		time: formatDate(new Date (2021,03,27,11,26,30)), //tháng tính từ 0 đến 11
	},
	{
		avatar: "https://ec.europa.eu/jrc/sites/jrcsh/files/styles/normal-responsive/public/fotolia-92027264european-day-forest-green-forest.jpg?itok=biCWJPQQ",
		username: "Tran Van B",
		wpm: 500,
		time: formatDate(new Date (2021,03,26,16,35,00)),
	},
	{
		avatar: "https://ychef.files.bbci.co.uk/624x351/p0973lkk.jpg",
		username: "Phan Thi C",
		wpm: 151,
		time: formatDate(new Date (2028,03,27,16,33,00)),
	},
]

// render ranking
	// trước khi hiển thị, phải sắp xếp theo thứ tự giảm dần
	// truy cập vào tbody
	// làm trống nội dung
	// vòng lặp qua mảng mock up qua cấu trúc tr
function renderRanking(arr) {
	let arrSort = arr.sort(function (a, b) {
		return b.wpm - a.wpm;
	});

	tableEl.innerHTML = "";

	for (let i = 0; i < arrSort.length; i++) {
	tableEl.innerHTML += `
		<tr>
			<td>${i+1}</td>
			<td>
				<img src=${arrSort[i].avatar}
					alt="">
			</td>
			<td>${arrSort[i].username}</td>
			<td class="font-weight-bold">${arrSort[i].wpm}</td>
			<td class="font-italic">${arrSort[i].time}</td>
		</tr>
    `
	}
}

// Function format Date
function formatDate(date){
	let year = date.getFullYear();
	let month = `0${date.getMonth()+1}`.slice(-2);
	let day = `0${date.getDate()}`.slice(-2);

	let hour = `0${date.getHours()}`.slice(-2);
	let minute = `0${date.getMinutes()}`.slice(-2);
	let second = `0${date.getSeconds()}`.slice(-2);

	return `${hour}:${minute}:${second} - ${day}/${month}/${year}`
}

function insertInfoPlayerToRanking() {
	let record = {
		avatar: loginUser.avatar,
		username: loginUser.username,
		wpm: wpmRanking,
		time: formatDate(new Date()), //tháng tính từ 0 đến 11
	}

	// Thêm người mới vào mảng ranking đã tạo > render
	ranking.push(record);
	renderRanking(ranking);

}

	// Gọi function, truyền vào mảng mock up
renderRanking(ranking)

// Run CSS, HTML, then call init rightout
window.onload = init;





// -------------------------------------------//-------------------------------------------//-----------
// LINK.JS//
const gameContainerEl = document.getElementById("game-container");
const loginContainerEl = document.getElementById("login-container");
const forgotContainerEl = document.getElementById("forgot-container");

const btnLinkLoginFromGame = document.querySelector(".btn-login");
const btnLinkForgot = document.querySelector(".btn-link-forgot-password");
const btnLinkLoginFromForgot = document.querySelector(".btn-link-login");

const btnLogin = document.querySelector("#btn-login");
const inputUsername = document.querySelector("#login-username");
const inputPassword = document.querySelector("#login-password");

const inputUsernameForgot = document.querySelector(".input-group input");
const btnSend = document.querySelector(".input-group-append button");

const btnRegister = document.querySelector("#btn-register");
const inputRegisterUsername = document.querySelector("#register-username");
const inputRegisterPassword = document.querySelector("#register-password");
const inputRegisterConfirmPassword = document.querySelector(
  "#register-confirm-password"
);
const inputRegisterAvatar = document.querySelector("#register-avatar");

// Chuyển từ màn chơi game => login
btnLinkLoginFromGame.addEventListener("click", function () {
  gameContainerEl.style.display = "none";
  loginContainerEl.style.display = "flex";
});

// Chuyển từ màn login => forgot
btnLinkForgot.addEventListener("click", function () {
  loginContainerEl.style.display = "none";
  forgotContainerEl.style.display = "flex";
});

// Chuyển từ màn forgot => login
btnLinkLoginFromForgot.addEventListener("click", function () {
  loginContainerEl.style.display = "flex";
  forgotContainerEl.style.display = "none";
});

// mock up một danh sách user để so sánh
let users = [
  // {
  //     username: 'user1',
  //     password: '11111',
  //     avatar: "https://i.pinimg.com/236x/4f/e1/d0/4fe1d0c4ee72ad6152789d6e2c84e4fc.jpg"
  // },
  // {
  //     username: 'user2',
  //     password: '22222',
  //     avatar: "https://www.clipartkey.com/mpngs/m/52-524202_class-dojo-monsters-avatar-clipart-png-download-class.png"
  // },
  // {
  //     username: 'user3',
  //     password: '33333',
  //     avatar: "https://www.jing.fm/clipimg/detail/82-827636_28-collection-of-class-dojo-avatar-clipart-class.png"
  // }
];

// truy cập vào nút login
// Lắng nghe sự kiện
// Lấy dữ liệu của 2 ô input, gán vào 2 biến
// Nếu
// duyệt qua mảng user, nếu nó bằng vói user trong mock up thì return true
// Khi mới vào trang, lấy thông tin user ra, lưu vào một biến global user để dùng vào các chỗ khá

btnLogin.addEventListener("click", function () {
  let usernameValue = inputUsername.value;
  let passwordValue = inputPassword.value;
  let dataLocal = localStorage.getItem("users");
  if (JSON.parse(dataLocal)) {
    users = JSON.parse(dataLocal);
  } else {
    users = [];
  }

  console.log(users);
  let isValid = false;
  if (usernameValue == "" || passwordValue == "") {
    alert("Cannot leave username or password blank");
    return;
  } else {
    for (let i = 0; i < users.length; i++) {
      if (
        users[i].username == usernameValue &&
        users[i].password == passwordValue
      ) {
        isValid = true;
        // Lưu data vào
        localStorage.setItem("user", JSON.stringify(users[i]));
        break;
      }
    }
    if (isValid) {
      alert("Login Successfully");
      loginContainerEl.style.display = "none";
		gameContainerEl.style.display = "block";
		init();
    } else {
      alert("username or password is incorrect");
    }
  }
});

// Khi hết thời gian thì lưu thông tin của user vào mảng ranking

// Quên mật khaaur
// truy cập vào nút gửi, lắng nghe sự kiện
// Nếu tìm được username giống, hiển thị password ra
btnSend.addEventListener("click", function () {
  let usernameForgotValue = inputUsernameForgot.value;

  let isValid = false;
  let userForgot;
  for (let i = 0; i < users.length; i++) {
    if (usernameForgotValue === users[i].username) {
      isValid = true;
      userForgot = users[i];
      break;
    }
  }
  if (isValid) {
    alert(`Your password is ${userForgot.password}`);
  } else {
    alert("No username found");
  }
});

// Tạo tài khoản mới
// Truy cập vào nút đăng kí, lắng nghe sự kiện
// Lấy dữ liệu của ô mật khẩu và tên đăng nhập
// Nếu dữ liệu trống -> Thông báo
// Nếu có dữ liệu
// -> So sánh dữ liệu với local storage
// Nếu có thì thông báo trùng
// Nếu không có thì Push dữ liệu vừa lấy vào storage

btnRegister.addEventListener("click", function () {
  let registerUsernameValue = inputRegisterUsername.value;
  let registerPasswordValue = inputRegisterPassword.value;
  let registerConfirmPasswordValue = inputRegisterConfirmPassword.value;
  let registerAvatarValue = inputRegisterAvatar.value;

  let isValid = false;
  if (registerUsernameValue == "" || registerPasswordValue == "") {
    alert("Cannot leave Username and/or Password blank");
    return;
  } else if (registerPasswordValue !== registerConfirmPasswordValue) {
    alert("Password and Confirm Password are not the same");
    registerPasswordValue = "";
    registerConfirmPasswordValue = "";
    return;
  } else {
    for (let i = 0; i < users.length; i++) {
      if (users[i].username == registerUsernameValue) {
        isValid = true;
        break;
      }
    }
    if (isValid) {
      alert("Username already existed");
    } else {
      let newUser = {
        username: registerUsernameValue,
        password: registerPasswordValue,
        avatar: registerAvatarValue,
      };
      users.push(newUser);
      console.log(users);
      localStorage.setItem("users", JSON.stringify(users));
    }
  }
});

I’m always open for great conversations.


Trang (Tee) Thao Nguyen