Add hotkeys

This commit is contained in:
Robbie Antenesse 2019-05-10 13:08:03 -06:00
parent ad3141ef6e
commit 15bba03e1d
8 changed files with 187 additions and 41 deletions

View File

@ -168,8 +168,7 @@
<footer>
<a class="button" id="settingsSave">Save</a>
<a class="button" id="settingsSaveAndClose">Save &amp; Close</a>
<a class="red button" onclick="this.parentElement.parentElement.parentElement.style.display='none';">Close Without
Saving</a>
<a class="red button" onclick="this.parentElement.parentElement.parentElement.style.display='none';">Close Without Saving</a>
</footer>
</div>
</section>

View File

@ -56,6 +56,7 @@ export const DEFAULT_DICTIONARY = {
export const DEFAULT_SETTINGS = {
useIPAPronunciationField: true,
useHotkeys: true,
};
export const DEFAULT_PAGE_SIZE = 50;

View File

@ -8,6 +8,14 @@ export function showSection(sectionName) {
}
}
export function hideDetailsPanel() {
document.getElementById('detailsPanel').style.display = 'none';
}
export function getIsDetailsPanelDisplayed() {
return document.getElementById('detailsPanel').style.display !== 'none';
}
function showDescription() {
const detailsPanel = document.getElementById('detailsPanel');
detailsPanel.style.display = 'block';

126
src/js/hotkeys.js Normal file
View File

@ -0,0 +1,126 @@
import { confirmEditWord, submitWordForm } from "./wordManagement";
import { showSection, getIsDetailsPanelDisplayed, hideDetailsPanel } from "./displayToggles";
import { renderInfoModal, renderMaximizedTextbox } from "./render";
import { showSearchModal, clearSearchText } from "./search";
import { saveAndCloseSettingsModal, openSettingsModal } from "./settings";
import { saveAndCloseEditModal, openEditModal } from "./dictionaryManagement";
export function enableHotKeys() {
document.addEventListener('keydown', hotKeyActions);
}
export function disableHotKeys() {
document.removeEventListener('keydown', hotKeyActions);
}
export function hotKeyActions(event) {
console.log(event);
if (typeof event.key === 'undefined' || typeof event.ctrlKey === 'undefined' || typeof event.altKey === 'undefined') {
console.warn('Browser does not have required event properties for hotkeys.');
disableHotKeys();
return false;
}
switch (event.key) {
case 'Escape': hideAllModals(); break;
case 'Return':
case 'Enter': {
if (event.ctrlKey) {
if (document.getElementById('settingsModal').style.display !== 'none') {
saveAndCloseSettingsModal();
} else if (document.getElementById('editModal').style.display !== 'none') {
saveAndCloseEditModal();
} else {
submitWord();
}
} break;
}
case 'd': if (event.ctrlKey) {event.preventDefault(); toggleDetailsDisplay()} break;
case 'e': if (event.ctrlKey) {event.preventDefault(); openEditModal()} break;
case 'h': if (event.ctrlKey) {event.preventDefault(); showHelpModal();} break;
case 'm': if (event.ctrlKey) {event.preventDefault(); maximizeTextarea();} break;
case 's': {
if (event.ctrlKey) {
event.preventDefault();
hideAllModals();
if (event.shiftKey) { // This is a failsafe in case the 'S' case below doesn't work for certain browsers
openSettingsModal();
} else {
showSearchModal();
}
}
break;
}
case 'S': if (event.ctrlKey) { event.preventDefault(); hideAllModals(); openSettingsModal(); } break;
case 'x': if (event.ctrlKey) {event.preventDefault(); clearSearchText();} break;
}
}
function hideAllModals() {
const permanentModals = ['#searchModal', '#settingsModal', '#editModal'];
const hideModals = document.querySelectorAll(permanentModals.join(',')),
removeModals = document.querySelectorAll('.modal:not(' + permanentModals.join('):not(') + ')');
Array.from(hideModals).forEach(modal => modal.style.display = 'none');
Array.from(removeModals).forEach(modal => modal.parentElement.removeChild(modal));
}
function toggleDetailsDisplay() {
const activeTab = document.querySelector('#detailsSection nav li.active');
console.log(activeTab);
Array.from(document.querySelectorAll('#detailsSection nav li')).forEach(li => li.classList.remove('active'));
if (activeTab) {
switch(activeTab.innerText.trim().toLowerCase()) {
case 'description': {
document.querySelector('#detailsSection nav li:nth-child(2)').classList.add('active');
showSection('details');
break;
}
case 'details': {
document.querySelector('#detailsSection nav li:nth-child(3)').classList.add('active');
showSection('stats');
break;
}
case 'stats': {
hideDetailsPanel();
break;
}
}
} else {
document.querySelector('#detailsSection nav li:nth-child(1)').classList.add('active');
showSection('description');
}
}
function submitWord() {
const focused = document.activeElement;
if (focused && focused.id) {
const isSubmittableField = focused.id.includes('wordName') || focused.id.includes('wordDefinition') || focused.id.includes('wordDetails');
if (isSubmittableField) {
if (focused.parentElement.parentElement.classList.contains('edit-form')) {
const wordId = parseInt(focused.parentElement.parentElement.id.replace('editForm_', ''));
confirmEditWord(wordId);
} else {
submitWordForm();
}
}
}
}
function showHelpModal() {
import('../markdown/help.md').then(html => {
renderInfoModal(html);
});
}
function maximizeTextarea() {
const focused = document.activeElement;
if (focused) {
const maximizeButton = focused.parentElement.querySelector('.maximize-button');
console.log(maximizeButton);
console.log(maximizeButton.parentElement);
if (maximizeButton) {
renderMaximizedTextbox(maximizeButton);
}
}
}

View File

@ -277,7 +277,7 @@ export function renderEditForm(wordId = false) {
}
export function renderIPATable(ipaTableButton) {
ipaTableButton = typeof ipaTableButton.target === 'undefined' ? ipaTableButton : ipaTableButton.target;
ipaTableButton = typeof ipaTableButton.target === 'undefined' || ipaTableButton.target === '' ? ipaTableButton : ipaTableButton.target;
const label = ipaTableButton.parentElement.innerText.replace(/(Field Help|IPA Chart)/g, '').trim();
const textBox = ipaTableButton.parentElement.querySelector('input');
import('./KeyboardFire/phondue/ipa-table.html').then(html => {
@ -301,7 +301,8 @@ export function renderIPATable(ipaTableButton) {
}
export function renderMaximizedTextbox(maximizeButton) {
maximizeButton = typeof maximizeButton.target === 'undefined' ? maximizeButton : maximizeButton.target;
maximizeButton = typeof maximizeButton.target === 'undefined' || maximizeButton.target === '' ? maximizeButton : maximizeButton.target;
console.log(maximizeButton.parentElement);
const label = maximizeButton.parentElement.innerText.replace(/(\*|Maximize)/g, '').trim();
const textBox = maximizeButton.parentElement.querySelector('textarea');
const modalElement = document.createElement('section');

View File

@ -1,5 +1,17 @@
import { cloneObject, getIndicesOf } from "../helpers";
import removeDiacritics from "./StackOverflow/removeDiacritics";
import { renderWords } from "./render";
export function showSearchModal() {
document.getElementById('searchModal').style.display = 'block';
document.getElementById('searchBox').focus();
}
export function clearSearchText() {
document.getElementById('searchBox').value = '';
document.getElementById('openSearchModal').value = '';
renderWords();
}
export function getSearchTerm() {
return document.getElementById('searchBox').value;

View File

@ -1,13 +1,13 @@
import {showSection} from './displayToggles';
import {showSection, hideDetailsPanel} from './displayToggles';
import { renderWords, renderEditForm, renderMaximizedTextbox, renderInfoModal, renderIPATable } from './render';
import { validateWord, addWord, confirmEditWord, cancelEditWord, confirmDeleteWord } from './wordManagement';
import { removeTags } from '../helpers';
import { getNextId } from './utilities';
import { confirmEditWord, cancelEditWord, confirmDeleteWord, submitWordForm } from './wordManagement';
import { openEditModal, saveEditModal, saveAndCloseEditModal } from './dictionaryManagement';
import { goToNextPage, goToPreviousPage, goToPage } from './pagination';
import { insertAtCursor, getInputSelection, setSelectionRange } from './StackOverflow/inputCursorManagement';
import { usePhondueDigraphs } from './KeyboardFire/phondue/ipaField';
import { openSettingsModal, saveSettingsModal, saveAndCloseSettingsModal } from './settings';
import { enableHotKeys } from './hotkeys';
import { showSearchModal, clearSearchText } from './search';
export default function setupListeners() {
setupDetailsTabs();
@ -16,6 +16,9 @@ export default function setupListeners() {
setupWordForm();
setupMobileWordFormButton();
setupInfoButtons();
if (window.settings.useHotkeys) {
enableHotKeys();
}
}
function setupDetailsTabs() {
@ -33,7 +36,7 @@ function setupDetailsTabs() {
const isActive = tab.classList.contains('active');
tabs.forEach(t => t.classList.remove('active'));
if (isActive) {
document.getElementById('detailsPanel').style.display = 'none';
hideDetailsPanel();
} else {
tab.classList.add('active');
showSection(section);
@ -96,15 +99,8 @@ function setupSearchBar() {
searchBox.addEventListener('input', event => {
openSearchModal.value = event.target.value;
});
clearSearchButton.addEventListener('click', event => {
searchBox.value = '';
openSearchModal.value = '';
renderWords();
});
openSearchModal.addEventListener('click', () => {
document.getElementById('searchModal').style.display = 'block';
searchBox.focus();
});
clearSearchButton.addEventListener('click', clearSearchText);
openSearchModal.addEventListener('click', showSearchModal);
const toggleDetailsCheck = function() {
if (searchExactWords.checked) {
@ -145,26 +141,7 @@ function setupWordForm() {
event.preventDefault();
return false;
});
addWordButton.addEventListener('click', () => {
const name = document.getElementById('wordName').value,
pronunciation = document.getElementById('wordPronunciation').value,
partOfSpeech = document.getElementById('wordPartOfSpeech').value,
definition = document.getElementById('wordDefinition').value,
details = document.getElementById('wordDetails').value;
const word = {
name: removeTags(name).trim(),
pronunciation: removeTags(pronunciation).trim(),
partOfSpeech: removeTags(partOfSpeech).trim(),
definition: removeTags(definition).trim(),
details: removeTags(details).trim(),
wordId: getNextId(),
};
if (validateWord(word)) {
addWord(word);
}
});
addWordButton.addEventListener('click', submitWordForm);
setupIPAFields();
setupMaximizeButtons();

View File

@ -1,5 +1,5 @@
import { renderWords } from "./render";
import { wordExists, addMessage } from "./utilities";
import { wordExists, addMessage, getNextId } from "./utilities";
import removeDiacritics from "./StackOverflow/removeDiacritics";
import { removeTags } from "../helpers";
import { saveDictionary } from "./dictionaryManagement";
@ -46,6 +46,27 @@ export function sortWords(render) {
}
}
export function submitWordForm() {
const name = document.getElementById('wordName').value,
pronunciation = document.getElementById('wordPronunciation').value,
partOfSpeech = document.getElementById('wordPartOfSpeech').value,
definition = document.getElementById('wordDefinition').value,
details = document.getElementById('wordDetails').value;
const word = {
name: removeTags(name).trim(),
pronunciation: removeTags(pronunciation).trim(),
partOfSpeech: removeTags(partOfSpeech).trim(),
definition: removeTags(definition).trim(),
details: removeTags(details).trim(),
wordId: getNextId(),
};
if (validateWord(word)) {
addWord(word);
}
}
export function addWord(word, render = true) {
window.currentDictionary.words.push(word);
addMessage('Word Created Successfully');
@ -75,8 +96,9 @@ export function updateWord(word, wordId) {
}
}
export function confirmEditWord() {
const wordId = parseInt(this.id.replace('editWordButton_', ''));
export function confirmEditWord(id) {
const wordId = typeof id.target !== 'undefined' ? parseInt(this.id.replace('editWordButton_', '')) : id;
console.log(wordId);
const name = document.getElementById('wordName_' + wordId).value,
pronunciation = document.getElementById('wordPronunciation_' + wordId).value,
partOfSpeech = document.getElementById('wordPartOfSpeech_' + wordId).value,