Merge branch 'master' into tsara-add-indonesian

This commit is contained in:
Jack 2020-06-27 00:35:17 +01:00 committed by GitHub
commit d40f3db5e6
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
22 changed files with 832 additions and 101 deletions

View file

@ -395,4 +395,32 @@ exports.removeTag = functions.https.onCall((request,response) => {
console.error(`error deleting tag for ${request.uid} - ${e}`);
return {resultCode:-999};
}
})
exports.updateResultTags = functions.https.onCall((request,response) => {
try{
let validTags = true;
request.tags.forEach(tag => {
if(!/^[0-9a-zA-Z]+$/.test(tag)) validTags = false;
})
if(validTags){
return admin.firestore().collection(`users/${request.uid}/results`).doc(request.resultid).update({
tags: request.tags
}).then(e => {
console.log(`user ${request.uid} updated tags for result ${request.resultid}`);
return {
resultCode:1
};
}).catch(e => {
console.error(`error while updating tags for result by user ${request.uid}: ${e.message}`);
return {resultCode:-999};
})
}else{
console.error(`invalid tags for user ${request.uid}: ${request.tags}`);
return {resultCode:-1};
}
}catch(e){
console.error(`error updating tags by ${request.uid} - ${e}`);
return {resultCode:-999};
}
})

View file

@ -2858,7 +2858,7 @@
}
},
"websocket-extensions": {
"version": "0.1.4",
"version": ">=0.1.4",
"resolved": "https://registry.npmjs.org/websocket-extensions/-/websocket-extensions-0.1.4.tgz",
"integrity": "sha512-OqedPIGOfsDlo31UNwYbCFMSaO9m9G/0faIHj5/dZFDMFqPTcx6UwqyOy3COEaEOg/9VsGIpdqn62W5KhoKSpg=="
},

2
package-lock.json generated
View file

@ -4232,7 +4232,7 @@
}
},
"websocket-extensions": {
"version": "0.1.3",
"version": ">=0.1.4",
"resolved": "https://registry.npmjs.org/websocket-extensions/-/websocket-extensions-0.1.3.tgz",
"integrity": "sha512-nqHUnMXmBzT0w570r2JpJxfiSD1IzoI+HGVdd3aZ0yNi3ngvQ4jv1dtHt5VGxfI2yj5yqImPhOK4vmIh2xMbGg=="
},

204
public/css/balloon.css Normal file
View file

@ -0,0 +1,204 @@
:root {
--balloon-border-radius: 2px;
--balloon-color: rgba(16, 16, 16, 0.95);
--balloon-text-color: #fff;
--balloon-font-size: 1rem;
--balloon-move: 4px; }
button[aria-label][data-balloon-pos] {
overflow: visible; }
[aria-label][data-balloon-pos] {
position: relative;
cursor: pointer; }
[aria-label][data-balloon-pos]:after {
opacity: 0;
pointer-events: none;
transition: all 0.18s ease-out 0s;
text-indent: 0;
/* font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Oxygen, Ubuntu, Cantarell, "Open Sans", "Helvetica Neue", sans-serif; */
font-weight: normal;
font-style: normal;
text-shadow: none;
font-size: var(--balloon-font-size);
background: var(--balloon-color);
border-radius: 2px;
color: var(--balloon-text-color);
border-radius: var(--balloon-border-radius);
content: attr(aria-label);
padding: .5em 1em;
position: absolute;
white-space: nowrap;
z-index: 10; }
[aria-label][data-balloon-pos]:before {
width: 0;
height: 0;
border: 5px solid transparent;
border-top-color: var(--balloon-color);
opacity: 0;
pointer-events: none;
transition: all 0.18s ease-out 0s;
content: "";
position: absolute;
z-index: 10; }
[aria-label][data-balloon-pos]:hover:before, [aria-label][data-balloon-pos]:hover:after, [aria-label][data-balloon-pos][data-balloon-visible]:before, [aria-label][data-balloon-pos][data-balloon-visible]:after, [aria-label][data-balloon-pos]:not([data-balloon-nofocus]):focus:before, [aria-label][data-balloon-pos]:not([data-balloon-nofocus]):focus:after {
opacity: 1;
pointer-events: none; }
[aria-label][data-balloon-pos].font-awesome:after {
font-family: FontAwesome, -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, 'Open Sans', 'Helvetica Neue', sans-serif; }
[aria-label][data-balloon-pos][data-balloon-break]:after {
white-space: pre; }
[aria-label][data-balloon-pos][data-balloon-break][data-balloon-length]:after {
white-space: pre-line;
word-break: break-word; }
[aria-label][data-balloon-pos][data-balloon-blunt]:before, [aria-label][data-balloon-pos][data-balloon-blunt]:after {
transition: none; }
[aria-label][data-balloon-pos][data-balloon-pos="up"]:after {
bottom: 100%;
left: 50%;
margin-bottom: 10px;
transform: translate(-50%, var(--balloon-move));
transform-origin: top; }
[aria-label][data-balloon-pos][data-balloon-pos="up"]:before {
bottom: 100%;
left: 50%;
transform: translate(-50%, var(--balloon-move));
transform-origin: top; }
[aria-label][data-balloon-pos][data-balloon-pos="up"]:hover:after, [aria-label][data-balloon-pos][data-balloon-pos="up"][data-balloon-visible]:after {
transform: translate(-50%, 0); }
[aria-label][data-balloon-pos][data-balloon-pos="up"]:hover:before, [aria-label][data-balloon-pos][data-balloon-pos="up"][data-balloon-visible]:before {
transform: translate(-50%, 0); }
[aria-label][data-balloon-pos][data-balloon-pos="up-left"]:after {
bottom: 100%;
left: 0;
margin-bottom: 10px;
transform: translate(0, var(--balloon-move));
transform-origin: top; }
[aria-label][data-balloon-pos][data-balloon-pos="up-left"]:before {
bottom: 100%;
left: 5px;
transform: translate(0, var(--balloon-move));
transform-origin: top; }
[aria-label][data-balloon-pos][data-balloon-pos="up-left"]:hover:after, [aria-label][data-balloon-pos][data-balloon-pos="up-left"][data-balloon-visible]:after {
transform: translate(0, 0); }
[aria-label][data-balloon-pos][data-balloon-pos="up-left"]:hover:before, [aria-label][data-balloon-pos][data-balloon-pos="up-left"][data-balloon-visible]:before {
transform: translate(0, 0); }
[aria-label][data-balloon-pos][data-balloon-pos="up-right"]:after {
bottom: 100%;
right: 0;
margin-bottom: 10px;
transform: translate(0, var(--balloon-move));
transform-origin: top; }
[aria-label][data-balloon-pos][data-balloon-pos="up-right"]:before {
bottom: 100%;
right: 5px;
transform: translate(0, var(--balloon-move));
transform-origin: top; }
[aria-label][data-balloon-pos][data-balloon-pos="up-right"]:hover:after, [aria-label][data-balloon-pos][data-balloon-pos="up-right"][data-balloon-visible]:after {
transform: translate(0, 0); }
[aria-label][data-balloon-pos][data-balloon-pos="up-right"]:hover:before, [aria-label][data-balloon-pos][data-balloon-pos="up-right"][data-balloon-visible]:before {
transform: translate(0, 0); }
[aria-label][data-balloon-pos][data-balloon-pos="down"]:after {
left: 50%;
margin-top: 10px;
top: 100%;
transform: translate(-50%, calc(var(--balloon-move) * -1)); }
[aria-label][data-balloon-pos][data-balloon-pos="down"]:before {
width: 0;
height: 0;
border: 5px solid transparent;
border-bottom-color: var(--balloon-color);
left: 50%;
top: 100%;
transform: translate(-50%, calc(var(--balloon-move) * -1)); }
[aria-label][data-balloon-pos][data-balloon-pos="down"]:hover:after, [aria-label][data-balloon-pos][data-balloon-pos="down"][data-balloon-visible]:after {
transform: translate(-50%, 0); }
[aria-label][data-balloon-pos][data-balloon-pos="down"]:hover:before, [aria-label][data-balloon-pos][data-balloon-pos="down"][data-balloon-visible]:before {
transform: translate(-50%, 0); }
[aria-label][data-balloon-pos][data-balloon-pos="down-left"]:after {
left: 0;
margin-top: 10px;
top: 100%;
transform: translate(0, calc(var(--balloon-move) * -1)); }
[aria-label][data-balloon-pos][data-balloon-pos="down-left"]:before {
width: 0;
height: 0;
border: 5px solid transparent;
border-bottom-color: var(--balloon-color);
left: 5px;
top: 100%;
transform: translate(0, calc(var(--balloon-move) * -1)); }
[aria-label][data-balloon-pos][data-balloon-pos="down-left"]:hover:after, [aria-label][data-balloon-pos][data-balloon-pos="down-left"][data-balloon-visible]:after {
transform: translate(0, 0); }
[aria-label][data-balloon-pos][data-balloon-pos="down-left"]:hover:before, [aria-label][data-balloon-pos][data-balloon-pos="down-left"][data-balloon-visible]:before {
transform: translate(0, 0); }
[aria-label][data-balloon-pos][data-balloon-pos="down-right"]:after {
right: 0;
margin-top: 10px;
top: 100%;
transform: translate(0, calc(var(--balloon-move) * -1)); }
[aria-label][data-balloon-pos][data-balloon-pos="down-right"]:before {
width: 0;
height: 0;
border: 5px solid transparent;
border-bottom-color: var(--balloon-color);
right: 5px;
top: 100%;
transform: translate(0, calc(var(--balloon-move) * -1)); }
[aria-label][data-balloon-pos][data-balloon-pos="down-right"]:hover:after, [aria-label][data-balloon-pos][data-balloon-pos="down-right"][data-balloon-visible]:after {
transform: translate(0, 0); }
[aria-label][data-balloon-pos][data-balloon-pos="down-right"]:hover:before, [aria-label][data-balloon-pos][data-balloon-pos="down-right"][data-balloon-visible]:before {
transform: translate(0, 0); }
[aria-label][data-balloon-pos][data-balloon-pos="left"]:after {
margin-right: 10px;
right: 100%;
top: 50%;
transform: translate(var(--balloon-move), -50%); }
[aria-label][data-balloon-pos][data-balloon-pos="left"]:before {
width: 0;
height: 0;
border: 5px solid transparent;
border-left-color: var(--balloon-color);
right: 100%;
top: 50%;
transform: translate(var(--balloon-move), -50%); }
[aria-label][data-balloon-pos][data-balloon-pos="left"]:hover:after, [aria-label][data-balloon-pos][data-balloon-pos="left"][data-balloon-visible]:after {
transform: translate(0, -50%); }
[aria-label][data-balloon-pos][data-balloon-pos="left"]:hover:before, [aria-label][data-balloon-pos][data-balloon-pos="left"][data-balloon-visible]:before {
transform: translate(0, -50%); }
[aria-label][data-balloon-pos][data-balloon-pos="right"]:after {
left: 100%;
margin-left: 10px;
top: 50%;
transform: translate(calc(var(--balloon-move) * -1), -50%); }
[aria-label][data-balloon-pos][data-balloon-pos="right"]:before {
width: 0;
height: 0;
border: 5px solid transparent;
border-right-color: var(--balloon-color);
left: 100%;
top: 50%;
transform: translate(calc(var(--balloon-move) * -1), -50%); }
[aria-label][data-balloon-pos][data-balloon-pos="right"]:hover:after, [aria-label][data-balloon-pos][data-balloon-pos="right"][data-balloon-visible]:after {
transform: translate(0, -50%); }
[aria-label][data-balloon-pos][data-balloon-pos="right"]:hover:before, [aria-label][data-balloon-pos][data-balloon-pos="right"][data-balloon-visible]:before {
transform: translate(0, -50%); }
[aria-label][data-balloon-pos][data-balloon-length="small"]:after {
white-space: normal;
width: 80px; }
[aria-label][data-balloon-pos][data-balloon-length="medium"]:after {
white-space: normal;
width: 150px; }
[aria-label][data-balloon-pos][data-balloon-length="large"]:after {
white-space: normal;
width: 260px; }
[aria-label][data-balloon-pos][data-balloon-length="xlarge"]:after {
white-space: normal;
width: 380px; }
@media screen and (max-width: 768px) {
[aria-label][data-balloon-pos][data-balloon-length="xlarge"]:after {
white-space: normal;
width: 90vw; } }
[aria-label][data-balloon-pos][data-balloon-length="fit"]:after {
white-space: normal;
width: 100%; }

View file

@ -148,6 +148,60 @@ a:hover {
}
#resultEditTagsPanelWrapper{
width: 100%;
height: 100%;
background: rgba(0, 0, 0, 0.75);
position: fixed;
left: 0;
top: 0;
z-index: 1000;
display: grid;
justify-content: center;
align-items: center;
padding: 5rem 0;
#resultEditTagsPanel{
background: var(--bg-color);
border-radius: var(--roundness);
padding: 2rem;
display: grid;
gap: 1rem;
overflow-y: scroll;
width: 500px;
.buttons{
display: grid;
gap: 1rem;
grid-template-columns: 1fr 1fr 1fr;
}
.button{
display: block;
color: var(--text-color);
cursor: pointer;
transition: .25s;
padding: .2rem .5rem;
border-radius: var(--roundness);
background: rgba(0,0,0,.1);
text-align: center;
-webkit-user-select: none;
display: grid;
align-content: center;
height: min-content;
height: -moz-min-content;
&.active{
background: var(--main-color);
color: var(--bg-color);
}
&:hover,&:focus{
color: var(--bg-color);
background: var(--main-color);
outline: none;
}
}
}
}
#versionHistoryWrapper{
width: 100%;
height: 100%;
@ -274,6 +328,9 @@ a:hover {
font-size: 0.75rem;
line-height: 0.75rem;
color: var(--sub-color);
.fas{
margin-right: .5rem;
}
&:last-child{
border-radius: 0 0 var(--roundness) var(--roundness);
}
@ -575,6 +632,7 @@ a:hover {
margin-left: -0.15rem;
color: var(--main-color);
transition: .25s;
cursor: pointer;
}
@ -1489,6 +1547,17 @@ key {
tbody tr:nth-child(odd) td{
background: rgba(0, 0, 0, 0.1);
}
td.infoIcons span{
margin: 0 .1rem;
}
}
#resultEditTags{
transition: .25s;
}
#resultEditTags:hover{
cursor: pointer;
color: var(--main-color);
opacity: 1 !important;
}
}

View file

@ -6,14 +6,15 @@
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Monkey Type</title>
<link rel="stylesheet" href="css/fa.css">
<link rel="stylesheet" href="css/style.css?v=14">
<link rel="stylesheet" href="css/balloon.css">
<link rel="stylesheet" href="css/style.css?v=18">
<link rel="stylesheet" href="themes/serika_dark.css" id="currentTheme">
<link id="favicon" rel="shortcut icon" href="fav.png">
<link rel="shortcut icon" href="fav.png">
<meta name="name" content="Monkey Type">
<meta name="image" content="https://monkey-type.com/mtsocial_large.png">
<meta name="description" content="A super customisable, minimalistic typing test.">
<meta name="keywords" content="typing, test, typing-test, typing test, monkey-type, monkeytype, monkey, type, miodec, wpm">
<meta name="keywords" content="typing, test, typing-test, typing test, monkey-type, monkeytype, monkey type, monkey-types, monkey types, types, monkey, type, miodec, wpm, words per minute, typing website, minimalistic, custom typing test, customizable, customisable, themes, random words, smooth caret, smooth, new, new typing site, new typing website">
<meta name="author" content="Miodec">
<meta property="og:title" content="Monkey Type">
<meta property="og:url" content="https://monkey-type.com/">
@ -40,6 +41,14 @@
<div class="button"><i class="fas fa-plus"></i></div>
</div>
</div>
<div id="resultEditTagsPanelWrapper" class="hidden">
<div id="resultEditTagsPanel" resultid="">
<div class="buttons">
</div>
<div class="button confirmButton"><i class="fas fa-check"></i></div>
</div>
</div>
<div id="versionHistoryWrapper" class="hidden">
<div id="versionHistory">
<div class="tip">Click anywhere to dismiss</div>
@ -73,26 +82,6 @@
<div id="timerWrapper">
<div id="timer"></div>
</div>
<div id="resultScreenshot" class="">
<div class="stats">
<div class="group">
<div class="top">wpm</div>
<div class="bottom">100</div>
</div>
<div class="group">
<div class="top">key</div>
<div class="bottom">100/2</div>
</div>
<div class="group">
<div class="top">acc</div>
<div class="bottom">100%</div>
</div>
</div>
<div class="logo">
<!-- <div class="top">monkey-see</div> -->
<div class="bottom">monkey-type.com</div>
</div>
</div>
<div id="centerContent" class="hidden">
<div id="top">
<div class="logo">
@ -671,8 +660,8 @@
<td>incorrect<br>chars</td>
<td>mode</td>
<!-- <td>punctuation</td> -->
<td>difficulty</td>
<td>language</td>
<td>info</td>
<td>tags</td>
<td>date</td>
</tr>
</thead>
@ -724,17 +713,17 @@
<script src="https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.22.2/moment.min.js"></script>
<!-- <script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/2.7.3/Chart.min.js"></script> -->
<script src="js/chart.js"></script>
<script src="js/chartjs-plugin-trendline.js?v=17"></script>
<script src="js/chartjs-plugin-trendline.js?v=20"></script>
<script src="js/chartjs-plugin-annotation.js"></script>
<script src="js/html2canvas.js"></script>
<script src="js/words.js?v=17"></script>
<script src="js/layouts.js?v=17"></script>
<script src="js/db.js?v=17"></script>
<script src="js/userconfig.js?v=17"></script>
<script src="js/commandline.js?v=17"></script>
<script src="js/settings.js?v=17"></script>
<script src="js/account.js?v=17"></script>
<script src="js/script.js?v=17"></script>
<script src="js/words.js?v=20"></script>
<script src="js/layouts.js?v=20"></script>
<script src="js/db.js?v=20"></script>
<script src="js/userconfig.js?v=20"></script>
<script src="js/commandline.js?v=20"></script>
<script src="js/settings.js?v=20"></script>
<script src="js/account.js?v=20"></script>
<script src="js/script.js?v=20"></script>
</html>

View file

@ -163,6 +163,14 @@ firebase.auth().onAuthStateChanged(function(user) {
console.log('DB snapshot ready');
accountIconLoading(false);
updateFilterTags();
updateCommandsTagsList();
loadActiveTagsFromCookie();
updateResultEditTagsPanelButtons();
config.resultFilters.forEach(filter => {
if(filter.substring(0,4) === "tag_" && filter !== "tag_notag"){
toggleFilterButton(filter);
}
})
});
var displayName = user.displayName;
var email = user.email;
@ -197,7 +205,7 @@ var resultHistoryChart = new Chart($(".pageAccount #resultHistoryChart"), {
trendlineLinear: {
style: "rgba(255,105,180, .8)",
lineStyle: "dotted",
width: 2
width: 4
}
},
],
@ -466,12 +474,12 @@ function loadMoreLines(){
result = filteredResults[i];
if(result == undefined) continue;
let withpunc = '';
if (result.punctuation) {
withpunc = '<br>punctuation';
}
if (result.blindMode) {
withpunc = '<br>blind';
}
// if (result.punctuation) {
// withpunc = '<br>punctuation';
// }
// if (result.blindMode) {
// withpunc = '<br>blind';
// }
let diff = result.difficulty;
if (diff == undefined){
diff = 'normal';
@ -481,6 +489,53 @@ function loadMoreLines(){
if (raw == undefined){
raw = '-';
}
let icons = `<span aria-label="${result.language.replace('_',' ')}" data-balloon-pos="up"><i class="fas fa-fw fa-globe-americas"></i></span>`;
if(diff === 'normal'){
icons += `<span aria-label="${result.difficulty}" data-balloon-pos="up"><i class="far fa-fw fa-star"></i></span>`;
}else if(diff === "expert"){
icons += `<span aria-label="${result.difficulty}" data-balloon-pos="up"><i class="fas fa-fw fa-star-half-alt"></i></span>`;
}else if(diff === "master"){
icons += `<span aria-label="${result.difficulty}" data-balloon-pos="up"><i class="fas fa-fw fa-star"></i></span>`;
}
if(result.punctuation){
icons += `<span aria-label="punctuation" data-balloon-pos="up"><i class="fas fa-fw fa-quote-right"></i></span>`;
}
if(result.blindMode){
icons += `<span aria-label="blind mode" data-balloon-pos="up"><i class="fas fa-fw fa-eye-slash"></i></span>`;
}
let tagNames = "";
if(result.tags !== undefined && result.tags.length > 0){
result.tags.forEach(tag => {
dbSnapshot.tags.forEach(snaptag => {
if(tag === snaptag.id){
tagNames += snaptag.name + ", ";
}
})
})
tagNames = tagNames.substring(0, tagNames.length - 2);
}
// if(tagNames !== ""){
// icons += `<span aria-label="${tagNames}" data-balloon-pos="up"><i class="fas fa-fw fa-tag"></i></span>`;
// }
let tagIcons = `<span id="resultEditTags" resultId="${result.id}" tags='${JSON.stringify(result.tags)}' style="opacity: .25"><i class="fas fa-fw fa-tag"></i></span>`;
if(tagNames !== ""){
if(result.tags !== undefined && result.tags.length > 1){
tagIcons = `<span id="resultEditTags" resultId="${result.id}" tags='${JSON.stringify(result.tags)}' aria-label="${tagNames}" data-balloon-pos="up"><i class="fas fa-fw fa-tags"></i></span>`;
}else{
tagIcons = `<span id="resultEditTags" resultId="${result.id}" tags='${JSON.stringify(result.tags)}' aria-label="${tagNames}" data-balloon-pos="up"><i class="fas fa-fw fa-tag"></i></span>`;
}
}
$(".pageAccount .history table tbody").append(`
<tr>
@ -490,8 +545,8 @@ function loadMoreLines(){
<td>${result.correctChars}</td>
<td>${result.incorrectChars}</td>
<td>${result.mode} ${result.mode2}${withpunc}</td>
<td>${diff}</td>
<td>${result.language.replace('_','<br>')}</td>
<td class="infoIcons">${icons}</td>
<td>${tagIcons}</td>
<td>${moment(result.timestamp).format('DD MMM YYYY<br>HH:mm')}</td>
</tr>`);
}
@ -804,3 +859,104 @@ function refreshAccountPage() {
cont();
}
}
function showResultEditTagsPanel(){
if ($("#resultEditTagsPanelWrapper").hasClass("hidden")) {
$("#resultEditTagsPanelWrapper")
.stop(true, true)
.css("opacity", 0)
.removeClass("hidden")
.animate({opacity: 1},125);
}
}
function hideResultEditTagsPanel(){
if (!$("#resultEditTagsPanelWrapper").hasClass("hidden")) {
$("#resultEditTagsPanelWrapper")
.stop(true, true)
.css("opacity", 1)
.animate(
{
opacity: 0
},100,e => {
$("#resultEditTagsPanelWrapper").addClass('hidden');
});
}
}
$(document).on('click','.pageAccount .group.history #resultEditTags',f => {
if(dbSnapshot.tags.length > 0){
let resultid = $(f.target).parents('span').attr('resultid');
let tags = $(f.target).parents('span').attr('tags');
$("#resultEditTagsPanel").attr('resultid',resultid);
$("#resultEditTagsPanel").attr('tags',tags);
updateActiveResultEditTagsPanelButtons(JSON.parse(tags));
showResultEditTagsPanel();
}
})
$(document).on('click','#resultEditTagsPanelWrapper .button.tag',f => {
$(f.target).toggleClass('active');
})
$("#resultEditTagsPanelWrapper").click(e => {
if($(e.target).attr('id') === "resultEditTagsPanelWrapper"){
hideResultEditTagsPanel();
}
})
function updateResultEditTagsPanelButtons(){
$("#resultEditTagsPanel .buttons").empty();
dbSnapshot.tags.forEach(tag => {
$("#resultEditTagsPanel .buttons").append(`<div class="button tag" tagid="${tag.id}">${tag.name}</div>`);
})
}
function updateActiveResultEditTagsPanelButtons(active){
if(active === []) return;
$.each($("#resultEditTagsPanel .buttons .button"), (index,obj) => {
let tagid = $(obj).attr('tagid');
if(active.includes(tagid)){
$(obj).addClass('active');
}else{
$(obj).removeClass('active');
}
// active.forEach(activetagid => {
// if(activetagid === tagid){
// $(obj).addClass('active');
// }else{
// $(obj).removeClass('active');
// }
// })
});
}
$("#resultEditTagsPanel .confirmButton").click(f => {
let resultid = $("#resultEditTagsPanel").attr('resultid');
let oldtags = JSON.parse($("#resultEditTagsPanel").attr('tags'));
let newtags = [];
$.each($("#resultEditTagsPanel .buttons .button"), (index,obj) => {
let tagid = $(obj).attr('tagid');
if($(obj).hasClass('active')){
newtags.push(tagid);
}
});
showBackgroundLoader();
hideResultEditTagsPanel();
updateResultTags({uid:firebase.auth().currentUser.uid,tags:newtags,resultid:resultid}).then(r=>{
hideBackgroundLoader();
if(r.data.resultCode === 1){
showNotification('Tags updated',1000);
dbSnapshot.results.forEach(result => {
if(result.id === resultid){
result.tags = newtags;
}
})
refreshAccountPage();
}else{
showNotification('Error updating tags',3000);
}
});
})

View file

@ -9,7 +9,7 @@
* Mod by: vesal: accept also xy-data so works with scatter
*/
var pluginTrendlineLinear = {
afterDraw: function(chartInstance) {
afterDatasetsDraw: function(chartInstance) {
var yScale;
var xScale;
for (var axis in chartInstance.scales) {
@ -84,7 +84,7 @@ function addFitter(datasetMeta, ctx, dataset, xScale, yScale) {
}
ctx.lineWidth = lineWidth;
if (lineStyle === "dotted") { ctx.setLineDash([2, 3]); }
if (lineStyle === "dotted") { ctx.setLineDash([6, 6]); }
ctx.beginPath();
ctx.moveTo(x1, y1);
ctx.lineTo(x2, y2);

View file

@ -13,6 +13,17 @@ let commands = {
restartTest();
}
},
{
visible: false,
id: "changeTags",
display: "Change tags...",
subgroup: true,
exec: () => {
updateCommandsTagsList();
currentCommands.push(commandsTags);
showCommandLine();
}
},
{
id: "toggleSmoothCaret",
display: "Toggle smooth caret",
@ -426,6 +437,51 @@ let commandsFontSize = {
]
};
let commandsTags = {
title: "Change tags...",
list: [
]
};
function updateCommandsTagsList(){
if(dbSnapshot.tags.length > 0){
commandsTags.list = [];
dbSnapshot.tags.forEach(tag => {
let dis = tag.name;
if(tag.active === true){
dis = '<i class="fas fa-check-square"></i>' + dis;
}else{
dis = '<i class="fas fa-square"></i>' + dis;
}
commandsTags.list.push({
id: "toggleTag" + tag.id,
display: dis,
sticky: true,
exec: () => {
toggleTag(tag.id);
updateTestModesNotice();
let txt = tag.name;
if(tag.active === true){
txt = '<i class="fas fa-check-square"></i>' + txt;
}else{
txt = '<i class="fas fa-square"></i>' + txt;
}
$(`#commandLine .suggestions .entry[command='toggleTag${tag.id}']`).html(txt);
}
})
})
commands.list[1].visible = true;
}
}
let themesList;
$.getJSON("themes/list.json", function(data) {
@ -644,6 +700,7 @@ function triggerCommand(command){
let subgroup = false;
let input = false;
let list = currentCommands[currentCommands.length-1];
let sticky = false;
$.each(list.list, (i, obj) => {
if (obj.id == command) {
if (obj.input) {
@ -654,10 +711,13 @@ function triggerCommand(command){
if (obj.subgroup !== null && obj.subgroup !== undefined) {
subgroup = obj.subgroup;
}
if(obj.sticky === true){
sticky = true;
}
}
}
});
if (!subgroup && !input) {
if (!subgroup && !input && !sticky) {
try{
firebase.analytics().logEvent('usedCommandLine', {
command: command
@ -721,7 +781,7 @@ function hideCommandLine() {
let list = currentCommands[currentCommands.length-1];
if (inputVal[0] == "") {
$.each(list.list, (index, obj) => {
obj.found = true;
if(obj.visible !== false) obj.found = true;
});
} else {
$.each(list.list, (index, obj) => {
@ -737,7 +797,7 @@ function hideCommandLine() {
}
});
if (foundcount > 0) {
obj.found = true;
if(obj.visible !== false) obj.found = true;
} else {
obj.found = false;
}

View file

@ -27,5 +27,12 @@ const layouts = {
"aA","sS","hH","tT","gG","yY","nN","eE","oO","iI","'\"",
"zZ","xX","mM","cC","vV","kK","lL",",<",".>","/?",
" "
],
turkishf: [
"*+","1!","2\"","3^","4$","5%","6&","7'","8(","9)","0=","/?","-_",
"fF","gG","ğĞ","ıI","oO","dD","rR","nN","hH","pP","qQ","wW","xX",
"uU","iİ","eE","aA","üÜ","tT","kK","mM","lL","yY","şŞ",
"jJ","öÖ","vV","cC","çÇ","zZ","sS","bB",".:",",;",
" "
]
}
}

View file

@ -22,7 +22,6 @@ let activeWordTopBeforeJump = 0;
let activeWordTop = 0;
let activeWordJumped = false;
let sameWordset = false;
let activeTags = [];
let accuracyStats = {
correct: 0,
@ -35,7 +34,29 @@ const testCompleted = firebase.functions().httpsCallable('testCompleted');
const addTag = firebase.functions().httpsCallable('addTag');
const editTag = firebase.functions().httpsCallable('editTag');
const removeTag = firebase.functions().httpsCallable('removeTag');
const updateResultTags = firebase.functions().httpsCallable('updateResultTags');
function smooth(arr, windowSize, getter = (value) => value, setter) {
const get = getter
const result = []
for (let i = 0; i < arr.length; i += 1) {
const leftOffeset = i - windowSize
const from = leftOffeset >= 0 ? leftOffeset : 0
const to = i + windowSize + 1
let count = 0
let sum = 0
for (let j = from; j < to && j < arr.length; j += 1) {
sum += get(arr[j])
count += 1
}
result[i] = setter ? setter(arr[i], sum / count) : sum / count
}
return result
}
function showNotification(text, time) {
let noti = $(".notification");
@ -631,8 +652,8 @@ function calculateStats() {
let wpmraw = roundTo2(((chars.allCorrectChars + chars.spaces + chars.incorrectChars + chars.extraChars) * (60/testSeconds))/5);
let acc = roundTo2((accuracyStats.correct / (accuracyStats.correct + accuracyStats.incorrect)) * 100);
return {
wpm: wpm,
wpmRaw: wpmraw,
wpm: isNaN(wpm) ? 0 : wpm,
wpmRaw: isNaN(wpmraw) ? 0 : wpmraw,
acc: acc,
correctChars: chars.correctWordChars,
incorrectChars: chars.incorrectChars + chars.extraChars + chars.missedChars,
@ -676,7 +697,7 @@ function showResult(difficultyFailed = false) {
let testtime = roundedToFixed(stats.time,1);
$("#result .stats .wpm .bottom").text(Math.round(stats.wpm));
$("#result .stats .raw .bottom").text(Math.round(stats.wpmRaw));
$("#result .stats .acc .bottom").text(Math.round(stats.acc) + "%");
$("#result .stats .acc .bottom").text(Math.floor(stats.acc) + "%");
$("#result .stats .key .bottom").text(stats.correctChars + stats.spaces + "/" + stats.incorrectChars);
$("#result .stats .time .bottom").text(testtime+'s');
@ -701,8 +722,7 @@ function showResult(difficultyFailed = false) {
// $("#result .stats .time").removeClass('hidden');
// $("#result .stats .time .bottom").text(roundedToFixed(stats.time,1)+'s');
}
let pbVal = 0;
if (firebase.auth().currentUser != null) {
$("#result .loginTip").addClass('hidden');
@ -717,6 +737,18 @@ function showResult(difficultyFailed = false) {
}else if(sameWordset){
showNotification("Test invalid - repeated",2000);
}else{
let activeTags = [];
try{
dbSnapshot.tags.forEach(tag => {
if(tag.active === true){
activeTags.push(tag.id);
}
})
}catch(e){
}
let completedEvent = {
wpm: stats.wpm,
rawWpm: stats.wpmRaw,
@ -762,6 +794,9 @@ function showResult(difficultyFailed = false) {
}
localPb = true;
}
wpmOverTimeChart.options.annotation.annotations[0].value = d2;
wpmOverTimeChart.options.annotation.annotations[0].label.content = "PB: "+ d2;
wpmOverTimeChart.update();
})
})
@ -780,7 +815,7 @@ function showResult(difficultyFailed = false) {
if(e.data === 2){
//new pb
if(!localPb){
showNotification('Local PB data is out of sync! Refresh the page to resync it or contact Miodec on Discord.',15000);
showNotification('Local PB data is out of sync! Resyncing.',5000);
}
db_saveLocalPB(config.mode,mode2,config.punctuation,config.language,config.difficulty,stats.wpm);
}else{
@ -863,13 +898,15 @@ function showResult(difficultyFailed = false) {
}
let tagsText = "";
activeTags.forEach(tagid => {
dbSnapshot.tags.forEach(snaptag => {
if(tagid === snaptag.id){
tagsText += "<br>"+snaptag.name;
}
try{
dbSnapshot.tags.forEach(tag => {
if(tag.active === true){
tagsText += "<br>"+tag.name;
}
})
})
}catch(e){
}
if(tagsText == ""){
$("#result .stats .tags").addClass('hidden');
@ -898,10 +935,15 @@ function showResult(difficultyFailed = false) {
wpmOverTimeChart.data.labels = labels;
let rawWpmPerSecond = keypressPerSecond.map(f => Math.round((f/5)*60));
rawWpmPerSecond = smooth(rawWpmPerSecond,1);
wpmOverTimeChart.data.datasets[0].borderColor = mainColor;
wpmOverTimeChart.data.datasets[0].data = wpmHistory;
wpmOverTimeChart.data.datasets[1].borderColor = subColor;
wpmOverTimeChart.data.datasets[1].data = rawHistory;
wpmOverTimeChart.data.datasets[1].data = rawWpmPerSecond;
wpmOverTimeChart.options.annotation.annotations[0].borderColor = subColor;
wpmOverTimeChart.options.annotation.annotations[0].label.backgroundColor = subColor;
@ -909,12 +951,15 @@ function showResult(difficultyFailed = false) {
let maxVal = 0;
rawHistory.forEach(raw =>{
if(raw >= maxVal){
maxVal = raw;
}
})
// let maxVal = 0;
// rawWpmPerSecond.forEach(raw =>{
// if(raw >= maxVal){
// maxVal = raw;
// }
// })
let maxVal = Math.max(...[Math.max(...rawWpmPerSecond),Math.max(...wpmHistory)]);
wpmOverTimeChart.options.scales.yAxes[0].ticks.max = maxVal;
wpmOverTimeChart.options.scales.yAxes[1].ticks.max = maxVal;
@ -1039,7 +1084,7 @@ function restartTest(withSameWordset = false) {
clearIntervals();
$("#restartTestButton").css('opacity', 1);
if ($("#commandLineWrapper").hasClass('hidden')) focusWords();
wpmOverTimeChart.options.annotation.annotations[0].value = "-20";
wpmOverTimeChart.options.annotation.annotations[0].value = "-30";
wpmOverTimeChart.update();
@ -1394,6 +1439,9 @@ function hideBackgroundLoader(){
function updateTestModesNotice(){
let anim = false;
if($(".pageTest #testModesNotice").text() === "") anim = true;
$(".pageTest #testModesNotice").empty();
if(config.difficulty === "expert"){
@ -1408,14 +1456,31 @@ function updateTestModesNotice(){
}
tagsString = "";
$.each($('.pageSettings .section.tags .tagsList .tag'), (index, tag) => {
if($(tag).children('.active').attr('active') === 'true'){
tagsString += $(tag).children('.title').text() + ', ';
// $.each($('.pageSettings .section.tags .tagsList .tag'), (index, tag) => {
// if($(tag).children('.active').attr('active') === 'true'){
// tagsString += $(tag).children('.title').text() + ', ';
// }
// })
try{
dbSnapshot.tags.forEach(tag => {
if(tag.active === true){
tagsString += tag.name + ', ';
}
})
})
if(tagsString !== ""){
$(".pageTest #testModesNotice").append(`<div><i class="fas fa-tag"></i>${tagsString.substring(0, tagsString.length - 2)}</div>`);
if(tagsString !== ""){
$(".pageTest #testModesNotice").append(`<div><i class="fas fa-tag"></i>${tagsString.substring(0, tagsString.length - 2)}</div>`);
}
}catch(e){
}
if(anim){
$(".pageTest #testModesNotice").css('transition','none').css('opacity',0).animate({
opacity: 1
},125, (e) => {
$(".pageTest #testModesNotice").css('transition','.125s');
});
}
}
@ -1453,6 +1518,7 @@ function tagsEdit(){
name: inputVal,
id: e.data.id
})
updateResultEditTagsPanelButtons();
updateSettingsPage();
updateFilterTags();
}else if(status === -1){
@ -1473,6 +1539,7 @@ function tagsEdit(){
tag.name = inputVal;
}
})
updateResultEditTagsPanelButtons();
updateSettingsPage();
updateFilterTags();
}else if(status === -1){
@ -1493,6 +1560,7 @@ function tagsEdit(){
dbSnapshot.tags.splice(index, 1);
}
})
updateResultEditTagsPanelButtons();
updateSettingsPage();
updateFilterTags();
updateActiveTags();
@ -1790,7 +1858,7 @@ $(document).keydown((event) => {
}
compareInput(currentWordIndex,currentInput,!config.blindMode);
}
currentKeypressCount++;
// currentKeypressCount++;
updateCaretPosition();
}
//space
@ -1834,6 +1902,7 @@ $(document).keydown((event) => {
currentWordIndex++;
updateActiveElement();
updateCaretPosition();
currentKeypressCount++;
} else {
inputHistory.push(currentInput);
highlightBadWord(currentWordIndex,!config.blindMode)
@ -1854,6 +1923,7 @@ $(document).keydown((event) => {
}
updateActiveElement();
updateCaretPosition();
currentKeypressCount++;
}
if (config.mode === "words" || config.mode === "custom") {
updateTimer();
@ -1901,6 +1971,12 @@ $(document).ready(() => {
$("#restartTestButton").addClass('hidden');
}
$("#centerContent").css("opacity", "0").removeClass("hidden").stop(true, true).animate({ opacity: 1 }, 250);
if(window.location.pathname === '/account'){
history.replaceState('/',null,'/');
}else if(window.location.pathname !== '/'){
let page = window.location.pathname.replace('/','');
changePage(page);
}
});
let ctx = $("#wpmChart");
@ -2052,7 +2128,7 @@ let wpmOverTimeChart = new Chart(ctx, {
type: 'line',
mode: 'horizontal',
scaleID: 'wpm',
value: '-20',
value: '-30',
borderColor: 'red',
borderWidth: 1,
borderDash: [2,2],
@ -2088,7 +2164,7 @@ let wpmOverTimeChart = new Chart(ctx, {
// Text to display in label - default is null. Provide an array to display values on a new line
content: "PB",
},
}
}]
}
}

View file

@ -18,7 +18,7 @@ function updateSettingsPage(){
if(firebase.auth().currentUser !== null && dbSnapshot !== null){
let tagsEl = $(".pageSettings .section.tags .tagsList").empty();
dbSnapshot.tags.forEach(tag => {
if(activeTags.includes(tag.id)){
if(tag.active === true){
tagsEl.append(`
<div class="tag" id="${tag.id}">
@ -129,16 +129,54 @@ function setSettingsButton(buttonSection,tf) {
}
}
function updateActiveTags(){
activeTags = [];
tagsString = "";
$.each($('.pageSettings .section.tags .tagsList .tag'), (index, tag) => {
if($(tag).children('.active').attr('active') === 'true'){
activeTags.push($(tag).attr('id'));
tagsString += $(tag).children('.title').text() + ', ';
function showActiveTags(){
// activeTags = [];
// tagsString = "";
// $.each($('.pageSettings .section.tags .tagsList .tag'), (index, tag) => {
// if($(tag).children('.active').attr('active') === 'true'){
// activeTags.push($(tag).attr('id'));
// tagsString += $(tag).children('.title').text() + ', ';
// }
// })
// updateTestModesNotice();
// if($(target).attr('active') === 'true'){
// $(target).attr('active','false');
// $(target).html('<i class="fas fa-square"></i>')
// }else{
// $(target).attr('active','true');
// $(target).html('<i class="fas fa-check-square"></i>')
// }
// $.each($('.pageSettings .section.tags .tagsList .tag'), (index, tag) => {
// let tagid = $(tag).attr('')
// })
dbSnapshot.tags.forEach(tag => {
if(tag.active === true){
$(`.pageSettings .section.tags .tagsList .tag[id='${tag.id}'] .active`).html('<i class="fas fa-check-square"></i>');
}else{
$(`.pageSettings .section.tags .tagsList .tag[id='${tag.id}'] .active`).html('<i class="fas fa-square"></i>');
}
})
}
function toggleTag(tagid, nosave = false){
dbSnapshot.tags.forEach(tag => {
if(tag.id === tagid){
if(tag.active === undefined){
tag.active = true;
}else{
tag.active = !tag.active;
}
}
})
updateTestModesNotice();
if(!nosave) saveActiveTagsToCookie();
}
//smooth caret
@ -377,14 +415,15 @@ $(".pageSettings .section.extraTestColor .buttons .button.off").click(e => {
$(document).on("click",".pageSettings .section.tags .tagsList .tag .active",e => {
let target = e.currentTarget;
let tagid = $(target).parent('.tag').attr('id');
if($(target).attr('active') === 'true'){
$(target).attr('active','false');
$(target).html('<i class="fas fa-square"></i>')
}else{
$(target).attr('active','true');
$(target).html('<i class="fas fa-check-square"></i>')
}
updateActiveTags();
// if($(target).attr('active') === 'true'){
// $(target).attr('active','false');
// $(target).html('<i class="fas fa-square"></i>')
// }else{
// $(target).attr('active','true');
// $(target).html('<i class="fas fa-check-square"></i>')
// }
toggleTag(tagid);
showActiveTags();
})
$(document).on("click",".pageSettings .section.tags .addTagButton",e => {

View file

@ -38,6 +38,28 @@ function saveConfigToCookie() {
restartCount = 0;
}
function saveActiveTagsToCookie(){
let tags = [];
try{
dbSnapshot.tags.forEach(tag => {
if(tag.active === true){
tags.push(tag.id);
}
})
let d = new Date();
d.setFullYear(d.getFullYear() + 1);
$.cookie("activeTags", null);
$.cookie("activeTags", JSON.stringify(tags), {
expires: d,
path: '/'
});
}catch(e){
}
}
function loadConfigFromCookie() {
let newConfig = $.cookie('config');
if (newConfig && newConfig != null && newConfig != "null") {
@ -75,6 +97,15 @@ function loadConfigFromCookie() {
saveConfigToCookie();
}
function loadActiveTagsFromCookie(){
let newTags = $.cookie('activeTags');
newTags = JSON.parse(newTags);
newTags.forEach(ntag => {
toggleTag(ntag, true);
})
saveActiveTagsToCookie();
}
function showTestConfig() {
$("#top .config").removeClass('hidden').css("opacity",1);
}

File diff suppressed because one or more lines are too long

2
public/robots.txt Normal file
View file

@ -0,0 +1,2 @@
User-agent: *
Disallow:

View file

@ -51,8 +51,8 @@
},
{
"name": "rgb",
"bgColor": "#111",
"textColor": "#eee"
"bgColor": "linear-gradient(to left, indigo, blue, green, yellow, orange, red);",
"textColor": "#fff"
},
{
"name": "oblivion",
@ -188,5 +188,25 @@
"name": "vaporwave",
"bgColor": "#a4a7ea",
"textColor": "#e368da"
},
{
"name": "pulse",
"bgColor": "#181818",
"textColor": "#17b8bd"
},
{
"name": "matrix",
"bgColor": "#000000",
"textColor": "#15ff00"
},
{
"name": "olive",
"bgColor": "#e9e5cc",
"textColor": "#92946f"
},
{
"name": "strawberry",
"bgColor": "#e53c58",
"textColor": "#fcfcf8"
}
]

15
public/themes/matrix.css Normal file
View file

@ -0,0 +1,15 @@
:root {
--bg-color: #000000;
--main-color: #15ff00;
--caret-color: #15ff00;
--sub-color: #032700;
--text-color: #adffa7;
--error-color: #da3333;
--error-extra-color: #791717;
--extra-error-color: #da3333;
--extra-error-extra-color: #791717;
}
#liveWpm, #timerNumber{
color: white;
}

View file

@ -2,7 +2,7 @@
--bg-color: #2d2e30;
--main-color: #65d2cd;
--caret-color: #65d2cd;
--sub-color: #7e8389;
--sub-color: #54585c;
--text-color: #e3e6eb;
--error-color: #d36a7b;
--error-extra-color: #994154;

11
public/themes/olive.css Normal file
View file

@ -0,0 +1,11 @@
:root {
--bg-color: #e9e5cc;
--caret-color: #92946f;
--main-color: #92946f;
--sub-color: #b7b39e;
--text-color: #373731;
--error-color: #cf2f2f;
--error-extra-color: #a22929;
--extra-error-color: #cf2f2f;
--extra-error-extra-color: #a22929;
}

11
public/themes/pulse.css Normal file
View file

@ -0,0 +1,11 @@
:root {
--bg-color: #181818;
--main-color: #17b8bd;
--caret-color: #17b8bd;
--sub-color: #53565a;
--text-color: #e5f4f4;
--error-color: #da3333;
--error-extra-color: #791717;
--extra-error-color: #da3333;
--extra-error-extra-color: #791717;
}

View file

@ -25,7 +25,7 @@
}
}
#liveWpm{
#liveWpm, #timerNumber{
color: white;
}

View file

@ -0,0 +1,11 @@
:root {
--bg-color: #f37f83;
--main-color: #fcfcf8;
--caret-color: #fcfcf8;
--sub-color: #e53c58;
--text-color: #fcfcf8;
--error-color: #fcd23f;
--error-extra-color: #d7ae1e;
--extra-error-color: #fcd23f;
--extra-error-extra-color: #d7ae1e;
}