Skip to content

Instantly share code, notes, and snippets.

@encap
Last active August 13, 2021 13:14
Show Gist options
  • Save encap/b163e94a4962520c33cf04ac46850e28 to your computer and use it in GitHub Desktop.
Save encap/b163e94a4962520c33cf04ac46850e28 to your computer and use it in GitHub Desktop.
The Logic behind virtual keyboard component on CodeRush
computed: {
mistakesHistory() {
return this.history.filter((change) => change.type === 'mistake');
},
mistakes() {
return this.mistakesHistory.reduce((acc, mistake) => {
if (mistake.shift && mistake.expectedText !== ' ') {
if (mistake.text.toLowerCase() === mistake.expectedText
|| (mistake.text.match(/[~!@#$%^&*()_+{}:"|<>?]/)
&& mistake.expectedText.match(/[`1234567890-=[\];'\\,./]/)
)) {
// console.log(`Shift Wasn't needed: '${mistake.text}' '${mistake.expectedText}'`);
acc.push({
keyCode: 16,
key: 'Shift',
expectedText: mistake.expectedText,
text: mistake.text,
});
} else if (mistake.text === mistake.expectedText.toLowerCase()
|| (mistake.text.match(/[`1234567890-=[\];'\\,./]/)
&& mistake.expectedText.match(/[~!@#$%^&*()_+{}:"|<>?]/)
)) {
// console.log(`Shift Expected: '${mistake.text}' '${mistake.expectedText}'`);
acc.push({
...mistake,
expectedText: 'Shift',
});
} else {
acc.push(mistake);
}
} else {
acc.push(mistake);
}
return acc;
}, []);
},
},
mounted() {
this.keyStats = this.generatekeyStats();
this.markWrongKeys();
this.$store.commit('ADD_TRACKED_CONTAINER', this.$refs.keyboard);
},
beforeDestroy() {
this.$store.commit('REMOVE_TRACKED_CONTAINER', this.$refs.keyboard.className);
},
methods: {
markWrongKeys() {
Object.keys(this.keyStats).forEach((keyCode) => {
const keyEl = document.getElementById(keyCode);
const { count } = this.keyStats[keyCode];
keyEl.style.setProperty('--wrong-count', count);
keyEl.setAttribute('wrong-count', count);
});
},
showExpectedKeys(ev) {
if (ev.target && ev.target.getAttribute('wrong-count') && !this.showExpected) {
// debounce
if (this.timeout) window.clearTimeout(this.timeout);
this.timeout = window.setTimeout(() => {
if (ev.target.matches(':hover')) {
const originKeyCode = ev.target.id;
// console.green(!this.stayOnLeave[originKeyCode]);
if (!this.stayOnLeave[originKeyCode]) {
const expectedKeysCodes = this.keyStats[originKeyCode].expected;
// console.log(`Hovered "${originKeyCode}" expected "${expectedKeysCodes}"`);
expectedKeysCodes.forEach((keyCode) => {
const keyEl = document.getElementById(keyCode);
let currentValue = Number(keyEl.getAttribute('expected-count'));
currentValue += 1;
// console.log(`incrementing "${keyCode}", value: ${currentValue}`);
keyEl.setAttribute('expected-count', currentValue);
});
}
this.timeout = undefined;
}
}, 50);
}
},
hideExpectedKeys(ev) {
if (ev.target.getAttribute('wrong-count') && !this.timeout && !this.showExpected) {
const originKeyCode = ev.target.id;
if (!this.stayOnLeave[originKeyCode]) {
const expectedKeysCodes = this.keyStats[originKeyCode].expected;
expectedKeysCodes.forEach((keyCode) => {
const keyEl = document.getElementById(keyCode);
let currentValue = Number(keyEl.getAttribute('expected-count'));
// console.log(`decrementing "${keyCode}", value: ${currentValue}`);
currentValue -= 1;
if (currentValue === 0) {
keyEl.removeAttribute('expected-count');
} else {
keyEl.setAttribute('expected-count', currentValue);
}
});
} else {
// console.log(`StayOnLeave ${originKeyCode}`);
}
}
},
changeLeaveAction(ev) {
const keyCode = ev.target.id;
if (this.keyStats[keyCode]) {
if (this.stayOnLeave[keyCode] !== undefined) {
this.stayOnLeave[keyCode] = !this.stayOnLeave[keyCode];
} else {
this.stayOnLeave[keyCode] = true;
}
if (this.stayOnLeave[keyCode]) {
ev.target.classList.add('locked');
} else {
ev.target.classList.remove('locked');
}
}
},
reset() {
this.$refs.keyboard.querySelectorAll('[expected-count]').forEach((el) => {
el.removeAttribute('expected-count');
});
this.$refs.keyboard.querySelectorAll('.locked').forEach((el) => {
el.classList.remove('locked');
this.stayOnLeave[el.id] = false;
});
this.showExpected = false;
},
toggleExpected() {
// if (this.showExpected) {
// this.$refs.keyboard.querySelectorAll('[expected-count]').forEach((el) => {
// console.log('reset', el);
// el.removeAttribute('expected-count');
// });
// } else {
Object.keys(this.keyStats).forEach((wrongKeyCode) => {
if (!this.stayOnLeave[wrongKeyCode]) {
const expectedKeysCodes = this.keyStats[wrongKeyCode].expected;
expectedKeysCodes.forEach((keyCode) => {
const keyEl = document.getElementById(keyCode);
let currentValue = Number(keyEl.getAttribute('expected-count'));
if (this.showExpected) {
currentValue -= 1;
} else {
currentValue += 1;
}
// console.log(`incrementing "${keyCode}", value: ${currentValue}`);
if (currentValue < 1) {
keyEl.removeAttribute('expected-count');
} else {
keyEl.setAttribute('expected-count', currentValue);
}
});
}
});
// }
this.showExpected = !this.showExpected;
},
generatekeyStats() {
const keys = {};
this.keyboard.forEach((row) => {
row.forEach((key) => {
if (key.keyCode) {
const stats = this.mistakes.reduce((acc, mistake) => {
if (mistake.keyCode === key.keyCode) {
const text = mistake.expectedText;
acc.count += 1;
const keyEl = this.$refs.keyboard
.querySelector(`[id][content*="${CSS.escape(text)}" i]`);
if (keyEl) {
acc.expected.push(keyEl.id);
}
}
return acc;
}, { expected: [], count: 0 });
if (stats.expected.length) {
keys[key.keyCode] = stats;
}
}
});
});
return keys;
},
},
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment