mirror of
https://github.com/monkeytypegame/monkeytype.git
synced 2025-09-28 01:25:32 +08:00
Merge pull request #1145 from 0x8b/custom-test-duration-input-parser
custom test duration input parser
This commit is contained in:
commit
e2fa8cfa97
8 changed files with 273 additions and 128 deletions
|
@ -130,7 +130,8 @@ const refactoredSrc = [
|
|||
"./src/js/commandline-lists.js",
|
||||
"./src/js/commandline.js",
|
||||
"./src/js/challenge-controller.js",
|
||||
"./src/js/custom-mode2-popup.js",
|
||||
"./src/js/custom-word-amount-popup.js",
|
||||
"./src/js/custom-test-duration-popup.js",
|
||||
"./src/js/test/test-config.js",
|
||||
"./src/js/loader.js",
|
||||
"./src/js/mini-result-chart.js",
|
||||
|
|
|
@ -1,99 +0,0 @@
|
|||
import * as UpdateConfig from "./config";
|
||||
import * as ManualRestart from "./manual-restart-tracker";
|
||||
import * as Notifications from "./notification-center";
|
||||
import * as TestLogic from "./test-logic";
|
||||
|
||||
export function show(mode) {
|
||||
if ($("#customMode2PopupWrapper").hasClass("hidden")) {
|
||||
if (mode == "time") {
|
||||
$("#customMode2Popup .title").text("Test length");
|
||||
$("#customMode2Popup").attr("mode", "time");
|
||||
} else if (mode == "words") {
|
||||
$("#customMode2Popup .title").text("Word amount");
|
||||
$("#customMode2Popup").attr("mode", "words");
|
||||
}
|
||||
$("#customMode2PopupWrapper")
|
||||
.stop(true, true)
|
||||
.css("opacity", 0)
|
||||
.removeClass("hidden")
|
||||
.animate({ opacity: 1 }, 100, (e) => {
|
||||
$("#customMode2Popup input").focus().select();
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
function hide() {
|
||||
if (!$("#customMode2PopupWrapper").hasClass("hidden")) {
|
||||
$("#customMode2PopupWrapper")
|
||||
.stop(true, true)
|
||||
.css("opacity", 1)
|
||||
.animate(
|
||||
{
|
||||
opacity: 0,
|
||||
},
|
||||
100,
|
||||
(e) => {
|
||||
$("#customMode2PopupWrapper").addClass("hidden");
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
function apply() {
|
||||
let mode = $("#customMode2Popup").attr("mode");
|
||||
let val = parseInt($("#customMode2Popup input").val());
|
||||
|
||||
if (mode == "time") {
|
||||
if (val !== null && !isNaN(val) && val >= 0) {
|
||||
UpdateConfig.setTimeConfig(val);
|
||||
ManualRestart.set();
|
||||
TestLogic.restart();
|
||||
if (val >= 1800) {
|
||||
Notifications.add("Stay safe and take breaks!", 0);
|
||||
} else if (val == 0) {
|
||||
Notifications.add(
|
||||
"Infinite time! Make sure to use Bail Out from the command line to save your result.",
|
||||
0,
|
||||
7
|
||||
);
|
||||
}
|
||||
} else {
|
||||
Notifications.add("Custom time must be at least 1", 0);
|
||||
}
|
||||
} else if (mode == "words") {
|
||||
if (val !== null && !isNaN(val) && val >= 0) {
|
||||
UpdateConfig.setWordCount(val);
|
||||
ManualRestart.set();
|
||||
TestLogic.restart();
|
||||
if (val > 2000) {
|
||||
Notifications.add("Stay safe and take breaks!", 0);
|
||||
} else if (val == 0) {
|
||||
Notifications.add(
|
||||
"Infinite words! Make sure to use Bail Out from the command line to save your result.",
|
||||
0,
|
||||
7
|
||||
);
|
||||
}
|
||||
} else {
|
||||
Notifications.add("Custom word amount must be at least 1", 0);
|
||||
}
|
||||
}
|
||||
|
||||
hide();
|
||||
}
|
||||
|
||||
$("#customMode2PopupWrapper").click((e) => {
|
||||
if ($(e.target).attr("id") === "customMode2PopupWrapper") {
|
||||
hide();
|
||||
}
|
||||
});
|
||||
|
||||
$("#customMode2Popup input").keypress((e) => {
|
||||
if (e.keyCode == 13) {
|
||||
apply();
|
||||
}
|
||||
});
|
||||
|
||||
$("#customMode2Popup .button").click(() => {
|
||||
apply();
|
||||
});
|
140
src/js/custom-test-duration-popup.js
Normal file
140
src/js/custom-test-duration-popup.js
Normal file
|
@ -0,0 +1,140 @@
|
|||
import * as UpdateConfig from "./config";
|
||||
import * as ManualRestart from "./manual-restart-tracker";
|
||||
import * as Notifications from "./notification-center";
|
||||
import * as TestLogic from "./test-logic";
|
||||
|
||||
function parseInput(input) {
|
||||
const re = /((-\s*)?\d+(\.\d+)?\s*[hms]?)/g;
|
||||
const seconds = [...input.toLowerCase().matchAll(re)]
|
||||
.map((match) => {
|
||||
const part = match[0];
|
||||
const duration = parseFloat(part.replaceAll(/\s+/g, ""));
|
||||
|
||||
if (part.includes("h")) {
|
||||
return 3600 * duration;
|
||||
} else if (part.includes("m")) {
|
||||
return 60 * duration;
|
||||
} else {
|
||||
return duration;
|
||||
}
|
||||
})
|
||||
.reduce((total, dur) => total + dur, 0);
|
||||
|
||||
return Math.floor(seconds);
|
||||
}
|
||||
|
||||
function format(duration) {
|
||||
const hours = Math.floor(duration / 3600);
|
||||
const minutes = Math.floor((duration % 3600) / 60);
|
||||
const seconds = (duration % 3600) % 60;
|
||||
|
||||
const time = [];
|
||||
|
||||
if (hours > 0) {
|
||||
time.push(`${hours} hour${hours === 1 ? "" : "s"}`);
|
||||
}
|
||||
|
||||
if (minutes > 0) {
|
||||
time.push(`${minutes} minute${minutes === 1 ? "" : "s"}`);
|
||||
}
|
||||
|
||||
if (seconds > 0) {
|
||||
time.push(`${seconds} second${seconds === 1 ? "" : "s"}`);
|
||||
}
|
||||
|
||||
if (time.length === 3) {
|
||||
return `${time[0]}, ${time[1]} and ${time[2]}`;
|
||||
} else if (time.length === 2) {
|
||||
return `${time[0]} and ${time[1]}`;
|
||||
} else {
|
||||
return `${time[0]}`;
|
||||
}
|
||||
}
|
||||
|
||||
function previewDuration() {
|
||||
const input = $("#customTestDurationPopup input").val();
|
||||
const duration = parseInput(input);
|
||||
let formattedDuration = "";
|
||||
|
||||
if (duration < 0) {
|
||||
formattedDuration = "NEGATIVE TIME";
|
||||
} else if (duration == 0) {
|
||||
formattedDuration = "Infinite test";
|
||||
} else {
|
||||
formattedDuration = "Total time: " + format(duration);
|
||||
}
|
||||
|
||||
$("#customTestDurationPopup .preview").text(formattedDuration);
|
||||
}
|
||||
|
||||
export function show() {
|
||||
if ($("#customTestDurationPopupWrapper").hasClass("hidden")) {
|
||||
$("#customTestDurationPopupWrapper")
|
||||
.stop(true, true)
|
||||
.css("opacity", 0)
|
||||
.removeClass("hidden")
|
||||
.animate({ opacity: 1 }, 100, (e) => {
|
||||
$("#customTestDurationPopup input").focus().select();
|
||||
});
|
||||
}
|
||||
|
||||
previewDuration();
|
||||
}
|
||||
|
||||
function hide() {
|
||||
if (!$("#customTestDurationPopupWrapper").hasClass("hidden")) {
|
||||
$("#customTestDurationPopupWrapper")
|
||||
.stop(true, true)
|
||||
.css("opacity", 1)
|
||||
.animate(
|
||||
{
|
||||
opacity: 0,
|
||||
},
|
||||
100,
|
||||
(e) => {
|
||||
$("#customTestDurationPopupWrapper").addClass("hidden");
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
function apply() {
|
||||
let val = parseInput($("#customTestDurationPopup input").val());
|
||||
|
||||
if (val !== null && !isNaN(val) && val >= 0) {
|
||||
UpdateConfig.setTimeConfig(val);
|
||||
ManualRestart.set();
|
||||
TestLogic.restart();
|
||||
if (val >= 1800) {
|
||||
Notifications.add("Stay safe and take breaks!", 0);
|
||||
} else if (val == 0) {
|
||||
Notifications.add(
|
||||
"Infinite time! Make sure to use Bail Out from the command line to save your result.",
|
||||
0,
|
||||
7
|
||||
);
|
||||
}
|
||||
} else {
|
||||
Notifications.add("Custom time must be at least 1", 0);
|
||||
}
|
||||
|
||||
hide();
|
||||
}
|
||||
|
||||
$("#customTestDurationPopupWrapper").click((e) => {
|
||||
if ($(e.target).attr("id") === "customTestDurationPopupWrapper") {
|
||||
hide();
|
||||
}
|
||||
});
|
||||
|
||||
$("#customTestDurationPopup input").keyup((e) => {
|
||||
previewDuration();
|
||||
|
||||
if (e.keyCode == 13) {
|
||||
apply();
|
||||
}
|
||||
});
|
||||
|
||||
$("#customTestDurationPopup .button").click(() => {
|
||||
apply();
|
||||
});
|
72
src/js/custom-word-amount-popup.js
Normal file
72
src/js/custom-word-amount-popup.js
Normal file
|
@ -0,0 +1,72 @@
|
|||
import * as UpdateConfig from "./config";
|
||||
import * as ManualRestart from "./manual-restart-tracker";
|
||||
import * as Notifications from "./notification-center";
|
||||
import * as TestLogic from "./test-logic";
|
||||
|
||||
export function show() {
|
||||
if ($("#customWordAmountPopupWrapper").hasClass("hidden")) {
|
||||
$("#customWordAmountPopupWrapper")
|
||||
.stop(true, true)
|
||||
.css("opacity", 0)
|
||||
.removeClass("hidden")
|
||||
.animate({ opacity: 1 }, 100, (e) => {
|
||||
$("#customWordAmountPopup input").focus().select();
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
function hide() {
|
||||
if (!$("#customWordAmountPopupWrapper").hasClass("hidden")) {
|
||||
$("#customWordAmountPopupWrapper")
|
||||
.stop(true, true)
|
||||
.css("opacity", 1)
|
||||
.animate(
|
||||
{
|
||||
opacity: 0,
|
||||
},
|
||||
100,
|
||||
(e) => {
|
||||
$("#customWordAmountPopupWrapper").addClass("hidden");
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
function apply() {
|
||||
let val = parseInt($("#customWordAmountPopup input").val());
|
||||
|
||||
if (val !== null && !isNaN(val) && val >= 0) {
|
||||
UpdateConfig.setWordCount(val);
|
||||
ManualRestart.set();
|
||||
TestLogic.restart();
|
||||
if (val > 2000) {
|
||||
Notifications.add("Stay safe and take breaks!", 0);
|
||||
} else if (val == 0) {
|
||||
Notifications.add(
|
||||
"Infinite words! Make sure to use Bail Out from the command line to save your result.",
|
||||
0,
|
||||
7
|
||||
);
|
||||
}
|
||||
} else {
|
||||
Notifications.add("Custom word amount must be at least 1", 0);
|
||||
}
|
||||
|
||||
hide();
|
||||
}
|
||||
|
||||
$("#customWordAmountPopupWrapper").click((e) => {
|
||||
if ($(e.target).attr("id") === "customWordAmountPopupWrapper") {
|
||||
hide();
|
||||
}
|
||||
});
|
||||
|
||||
$("#customWordAmountPopup input").keypress((e) => {
|
||||
if (e.keyCode == 13) {
|
||||
apply();
|
||||
}
|
||||
});
|
||||
|
||||
$("#customWordAmountPopup .button").click(() => {
|
||||
apply();
|
||||
});
|
|
@ -645,7 +645,8 @@ $(document).keydown(function (event) {
|
|||
let wordsFocused = $("#wordsInput").is(":focus");
|
||||
let modePopupVisible =
|
||||
!$("#customTextPopupWrapper").hasClass("hidden") ||
|
||||
!$("#customMode2PopupWrapper").hasClass("hidden") ||
|
||||
!$("#customWordAmountPopupWrapper").hasClass("hidden") ||
|
||||
!$("#customTestDurationPopupWrapper").hasClass("hidden") ||
|
||||
!$("#quoteSearchPopupWrapper").hasClass("hidden");
|
||||
if (
|
||||
pageTestActive &&
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
import * as CustomMode2Popup from "./custom-mode2-popup";
|
||||
import * as CustomWordAmountPopup from "./custom-word-amount-popup";
|
||||
import * as CustomTestDurationPopup from "./custom-test-duration-popup";
|
||||
import * as UpdateConfig from "./config";
|
||||
import * as ManualRestart from "./manual-restart-tracker";
|
||||
import * as TestLogic from "./test-logic";
|
||||
|
@ -16,7 +17,7 @@ export function hide() {
|
|||
$(document).on("click", "#top .config .wordCount .text-button", (e) => {
|
||||
const wrd = $(e.currentTarget).attr("wordCount");
|
||||
if (wrd == "custom") {
|
||||
CustomMode2Popup.show("words");
|
||||
CustomWordAmountPopup.show();
|
||||
} else {
|
||||
UpdateConfig.setWordCount(wrd);
|
||||
ManualRestart.set();
|
||||
|
@ -27,7 +28,7 @@ $(document).on("click", "#top .config .wordCount .text-button", (e) => {
|
|||
$(document).on("click", "#top .config .time .text-button", (e) => {
|
||||
let mode = $(e.currentTarget).attr("timeConfig");
|
||||
if (mode == "custom") {
|
||||
CustomMode2Popup.show("time");
|
||||
CustomTestDurationPopup.show();
|
||||
} else {
|
||||
UpdateConfig.setTimeConfig(mode);
|
||||
ManualRestart.set();
|
||||
|
|
|
@ -134,12 +134,15 @@ html {
|
|||
outline: none;
|
||||
}
|
||||
|
||||
.select2-container--default .select2-selection--single .select2-selection__rendered {
|
||||
.select2-container--default
|
||||
.select2-selection--single
|
||||
.select2-selection__rendered {
|
||||
color: var(--text-color);
|
||||
outline: none;
|
||||
}
|
||||
|
||||
.select2-container--default .select2-results__option--highlighted.select2-results__option--selectable {
|
||||
.select2-container--default
|
||||
.select2-results__option--highlighted.select2-results__option--selectable {
|
||||
background-color: var(--sub-color);
|
||||
color: var(--text-color);
|
||||
}
|
||||
|
@ -156,16 +159,15 @@ html {
|
|||
border-radius: var(--roundness);
|
||||
}
|
||||
|
||||
.select2-container--default .select2-selection--single
|
||||
{
|
||||
.select2-container--default .select2-selection--single {
|
||||
color: var(--text-color);
|
||||
background: rgba(0, 0, 0, 0.1);
|
||||
outline: none;
|
||||
border: none;
|
||||
height:auto;
|
||||
height: auto;
|
||||
}
|
||||
|
||||
.select2-selection:focus{
|
||||
.select2-selection:focus {
|
||||
height: fit-content;
|
||||
padding: 5px;
|
||||
border-radius: var(--roundness);
|
||||
|
@ -174,7 +176,7 @@ html {
|
|||
border: none;
|
||||
outline: none;
|
||||
}
|
||||
.select2-selection:active{
|
||||
.select2-selection:active {
|
||||
height: fit-content;
|
||||
padding: 5px;
|
||||
border-radius: var(--roundness);
|
||||
|
@ -184,15 +186,23 @@ html {
|
|||
outline: none;
|
||||
}
|
||||
|
||||
.select2-container--default .select2-selection--single .select2-selection__arrow {
|
||||
.select2-container--default
|
||||
.select2-selection--single
|
||||
.select2-selection__arrow {
|
||||
height: 35px;
|
||||
}
|
||||
|
||||
.select2-container--default .select2-selection--single .select2-selection__arrow b {
|
||||
.select2-container--default
|
||||
.select2-selection--single
|
||||
.select2-selection__arrow
|
||||
b {
|
||||
border-color: var(--main-color) transparent transparent transparent;
|
||||
}
|
||||
|
||||
.select2-container--default.select2-container--open .select2-selection--single .select2-selection__arrow b {
|
||||
.select2-container--default.select2-container--open
|
||||
.select2-selection--single
|
||||
.select2-selection__arrow
|
||||
b {
|
||||
border-color: var(--main-color) transparent;
|
||||
}
|
||||
|
||||
|
@ -591,7 +601,7 @@ a:hover {
|
|||
}
|
||||
}
|
||||
|
||||
#wordFilterPopupWrapper{
|
||||
#wordFilterPopupWrapper {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
background: rgba(0, 0, 0, 0.75);
|
||||
|
@ -604,7 +614,7 @@ a:hover {
|
|||
align-items: center;
|
||||
padding: 5rem 0;
|
||||
|
||||
#wordFilterPopup{
|
||||
#wordFilterPopup {
|
||||
background: var(--bg-color);
|
||||
border-radius: var(--roundness);
|
||||
padding: 2rem;
|
||||
|
@ -612,25 +622,23 @@ a:hover {
|
|||
gap: 1rem;
|
||||
width: 400px;
|
||||
|
||||
|
||||
|
||||
.lengthgrid{
|
||||
display:grid;
|
||||
.lengthgrid {
|
||||
display: grid;
|
||||
grid-template-columns: 1fr 1fr;
|
||||
grid-template-rows: 1fr 1fr;
|
||||
gap: 0.2rem;
|
||||
}
|
||||
|
||||
.wordLength{
|
||||
.wordLength {
|
||||
width: 10rem;
|
||||
}
|
||||
|
||||
.wftip{
|
||||
.wftip {
|
||||
color: var(--sub-color);
|
||||
font-size: 0.8rem;
|
||||
}
|
||||
|
||||
.wfload{
|
||||
.wfload {
|
||||
justify-self: center;
|
||||
}
|
||||
}
|
||||
|
@ -674,7 +682,8 @@ a:hover {
|
|||
}
|
||||
}
|
||||
|
||||
#customMode2PopupWrapper {
|
||||
#customWordAmountPopupWrapper,
|
||||
#customTestDurationPopupWrapper {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
background: rgba(0, 0, 0, 0.75);
|
||||
|
@ -687,7 +696,8 @@ a:hover {
|
|||
align-items: center;
|
||||
padding: 5rem 0;
|
||||
|
||||
#customMode2Popup {
|
||||
#customWordAmountPopup,
|
||||
#customTestDurationPopup {
|
||||
background: var(--bg-color);
|
||||
border-radius: var(--roundness);
|
||||
padding: 2rem;
|
||||
|
@ -705,6 +715,13 @@ a:hover {
|
|||
color: var(--sub-color);
|
||||
}
|
||||
}
|
||||
|
||||
#customTestDurationPopup {
|
||||
.preview {
|
||||
font-size: 0.75rem;
|
||||
color: var(--sub-color);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#customThemeShareWrapper {
|
||||
|
|
|
@ -136,9 +136,9 @@
|
|||
<div class="button">ok</div>
|
||||
</div>
|
||||
</div>
|
||||
<div id="customMode2PopupWrapper" class="hidden">
|
||||
<div id="customMode2Popup" mode="">
|
||||
<div class="title">Test length</div>
|
||||
<div id="customWordAmountPopupWrapper" class="hidden">
|
||||
<div id="customWordAmountPopup">
|
||||
<div class="title">Word amount</div>
|
||||
<input type="number" value="1" min="1" max="10000" />
|
||||
<div class="tip">
|
||||
You can start an infinite test by inputting 0. Then, to stop the test,
|
||||
|
@ -147,6 +147,18 @@
|
|||
<div class="button">ok</div>
|
||||
</div>
|
||||
</div>
|
||||
<div id="customTestDurationPopupWrapper" class="hidden">
|
||||
<div id="customTestDurationPopup">
|
||||
<div class="title">Test duration</div>
|
||||
<div class="preview"></div>
|
||||
<input value="1" />
|
||||
<div class="tip">
|
||||
You can start an infinite test by inputting 0. Then, to stop the test,
|
||||
use the Bail Out feature (esc > Bail Out)
|
||||
</div>
|
||||
<div class="button">ok</div>
|
||||
</div>
|
||||
</div>
|
||||
<div id="quoteSearchPopupWrapper" class="hidden">
|
||||
<div id="quoteSearchPopup" mode="">
|
||||
<div class="title">Quote Search</div>
|
||||
|
|
Loading…
Add table
Reference in a new issue