1
0
Fork 0
mirror of https://github.com/Alamantus/Lexiconga.git synced 2025-05-03 08:43:19 +02:00

Start moving click handlers on document.body

Instead of adding listeners to individual elements, the body click routes for better efficiency
This commit is contained in:
Robbie Antenesse 2024-06-18 10:58:20 -06:00
parent 7ec29d1fbc
commit 04f2970ccf
8 changed files with 177 additions and 157 deletions

View file

@ -3,7 +3,6 @@ import { setCookie } from "../StackOverflow/cookie";
import { changeDictionary, createNewDictionary } from "./dictionaryManagement"; import { changeDictionary, createNewDictionary } from "./dictionaryManagement";
import { addMessage } from "../utilities"; import { addMessage } from "../utilities";
import { renderForgotPasswordForm } from "./passwordReset"; import { renderForgotPasswordForm } from "./passwordReset";
import { setupMaximizeButtons } from "../setupListeners/buttons";
export function setupLoginModal(modal) { export function setupLoginModal(modal) {
const closeElements = modal.querySelectorAll('.modal-background, .close-button'); const closeElements = modal.querySelectorAll('.modal-background, .close-button');
@ -74,5 +73,4 @@ export function setupMakePublic() {
document.execCommand('copy'); document.execCommand('copy');
addMessage('Copied public link to clipboard', 3000); addMessage('Copied public link to clipboard', 3000);
}); });
setupMaximizeButtons();
} }

View file

@ -2,41 +2,49 @@ import { renderMaximizedTextbox, renderInfoModal, renderIPATable, renderIPAHelp
import helpFile from '../../markdown/help.md'; import helpFile from '../../markdown/help.md';
import termsFile from '../../markdown/terms.md'; import termsFile from '../../markdown/terms.md';
import privacyFile from '../../markdown/privacy.md'; import privacyFile from '../../markdown/privacy.md';
import { setupSearchBar } from './search'; import { handleSearchClickEvents } from './search';
import { setupSettingsModal } from './modals'; import { handleSettingsModalClicks } from './settings';
export function setupHeaderButtons() { /**
setupSearchBar(); * Identify selector strings and handlers
setupSettingsModal(); * @param {Function} when Passed from setupListeners, which listens to clicks on document.body
*/
document.getElementById('loginCreateAccountButton').addEventListener('click', () => { export function handleHeaderButtonClicks(when) {
import('../account/index.js').then(account => { handleSearchClickEvents(when);
account.showLoginForm(); handleSettingsModalClicks(when);
}); when('#loginCreateAccountButton', () => loadAccountScript('showLoginForm'));
});
} }
export function setupIPAButtons() { // TODO: Set this up correctly
const ipaTableButtons = document.getElementsByClassName('ipa-table-button'), function loadAccountScript(accountScriptMethod) {
ipaFieldHelpButtons = document.getElementsByClassName('ipa-field-help-button'); let script = document.getElementById('accountScript');
if (script) {
Array.from(ipaTableButtons).forEach(button => { Account[accountScriptMethod]();
button.removeEventListener('click', renderIPATable); } else {
button.addEventListener('click', renderIPATable); script = document.createElement('script');
}); document.body.appendChild(script);
script.onload = () => {
Array.from(ipaFieldHelpButtons).forEach(button => { Account[accountScriptMethod]();
button.removeEventListener('click', renderIPAHelp); }
button.addEventListener('click', renderIPAHelp); script.src = './account.js';
}); }
} }
export function setupMaximizeButtons() { /**
const maximizeButtons = document.getElementsByClassName('maximize-button'); * Identify selector strings and handlers
Array.from(maximizeButtons).forEach(button => { * @param {Function} when Passed from setupListeners, which listens to clicks on document.body
button.removeEventListener('click', renderMaximizedTextbox); */
button.addEventListener('click', renderMaximizedTextbox); export function handleIPAButtonClicks(when) {
}); when('.ipa-table-button', renderIPATable);
when('.ipa-field-help-button', renderIPAHelp);
}
/**
* Identify selector strings and handlers
* @param {Function} when Passed from setupListeners, which listens to clicks on document.body
*/
export function handleMaximizeButtonClicks(when) {
when('.maximize-button', renderMaximizedTextbox);
} }
export function setupInfoButtons() { export function setupInfoButtons() {

View file

@ -1,68 +1,65 @@
import { showSection, hideDetailsPanel } from '../displayToggles'; import { showSection, hideDetailsPanel } from '../displayToggles';
import { openEditModal, saveEditModal, saveAndCloseEditModal, exportDictionary, exportWords, importDictionary, importWords, confirmDeleteDictionary } from '../dictionaryManagement'; import { openEditModal, saveEditModal, saveAndCloseEditModal, exportDictionary, exportWords, importDictionary, importWords, confirmDeleteDictionary } from '../dictionaryManagement';
import { setupMaximizeButtons } from './buttons';
export function setupDetailsTabs() { /**
const tabs = document.querySelectorAll('#detailsSection nav li'); * Identify selector strings and handlers
tabs.forEach(tab => { * @param {Function} when Passed from setupListeners, which listens to clicks on document.body
tab.addEventListener('click', () => { */
const section = tab.innerText.toLowerCase(); export function handleDetailClicks(when) {
// Details Tabs
when('#detailsSection nav li', handleClickTab);
// Edit Form Tabs
when('#editModal nav li', handleClickEditFormTab);
// Edit Form Buttons
when('#editSave', saveEditModal);
when('#editSaveAndClose', saveAndCloseEditModal);
when('#importDictionaryFile', importDictionary);
when('#importWordsCSV', importWords);
when('#exportDictionaryButton', exportDictionary);
when('#exportWordsButton', exportWords);
when('#deleteDictionaryButton', confirmDeleteDictionary);
}
function handleClickTab(tabElement) {
const section = tabElement.innerText.toLowerCase();
if (section === 'edit') { if (section === 'edit') {
openEditModal(); openEditModal();
} else { } else {
const isActive = tab.classList.contains('active'); const isActive = tabElement.classList.contains('active');
tabs.forEach(t => t.classList.remove('active')); document.querySelectorAll('#detailsSection nav li')
.forEach(t => t.classList.remove('active'));
if (isActive) { if (isActive) {
hideDetailsPanel(); hideDetailsPanel();
} else { } else {
tab.classList.add('active'); tabElement.classList.add('active');
showSection(section); showSection(section);
} }
} }
});
});
setupEditFormTabs();
setupEditFormInteractions();
setupEditFormButtons();
} }
function setupEditFormTabs() { function handleClickEditFormTab(tabElement) {
const tabs = document.querySelectorAll('#editModal nav li'); document.querySelectorAll('#editModal nav li').forEach(t => {
tabs.forEach(tab => {
tab.addEventListener('click', () => {
tabs.forEach(t => {
t.classList.remove('active'); t.classList.remove('active');
document.getElementById('edit' + t.innerText + 'Tab').style.display = 'none'; document.getElementById('edit' + t.innerText + 'Tab').style.display = 'none';
}); });
tab.classList.add('active'); tabElement.classList.add('active');
const tabSection = document.getElementById('edit' + tab.innerText + 'Tab'); const tabSection = document.getElementById('edit' + tabElement.innerText + 'Tab');
tabSection.style.display = ''; tabSection.style.display = '';
tabSection.scrollTop = 0; tabSection.scrollTop = 0;
});
});
} }
function setupEditFormInteractions() { export function setupEditFormInteractions() {
const preventDuplicatesBox = document.getElementById('editPreventDuplicates'); const preventDuplicatesBox = document.getElementById('editPreventDuplicates');
preventDuplicatesBox.addEventListener('change', () => { preventDuplicatesBox.removeEventListener('change', handlePreventDuplicatesBoxChange);
preventDuplicatesBox.addEventListener('change', handlePreventDuplicatesBoxChange);
}
function handlePreventDuplicatesBoxChange(event) {
const caseSensitiveBox = document.getElementById('editCaseSensitive'); const caseSensitiveBox = document.getElementById('editCaseSensitive');
if (preventDuplicatesBox.checked) { if (event.target.checked) {
caseSensitiveBox.disabled = false; caseSensitiveBox.disabled = false;
} else { } else {
caseSensitiveBox.disabled = true; caseSensitiveBox.disabled = true;
caseSensitiveBox.checked = false; caseSensitiveBox.checked = false;
} }
});
}
function setupEditFormButtons() {
document.getElementById('editSave').addEventListener('click', saveEditModal);
document.getElementById('editSaveAndClose').addEventListener('click', saveAndCloseEditModal);
document.getElementById('importDictionaryFile').addEventListener('change', importDictionary);
document.getElementById('importWordsCSV').addEventListener('change', importWords);
document.getElementById('exportDictionaryButton').addEventListener('click', exportDictionary);
document.getElementById('exportWordsButton').addEventListener('click', exportWords);
document.getElementById('deleteDictionaryButton').addEventListener('click', confirmDeleteDictionary);
setupMaximizeButtons();
} }

View file

@ -1,17 +1,19 @@
import { usePhondueDigraphs } from '../KeyboardFire/phondue/ipaField'; import { usePhondueDigraphs } from '../KeyboardFire/phondue/ipaField';
import { enableHotKeys } from '../hotkeys'; import { enableHotKeys } from '../hotkeys';
import { dismiss, isDismissed } from '../announcements'; import { dismiss } from '../announcements';
import { fadeOutElement } from '../utilities'; import { handleDetailClicks, setupEditFormInteractions } from './details';
import { setupDetailsTabs } from './details';
import { setupWordForm, setupMobileWordFormButton } from './words'; import { setupWordForm, setupMobileWordFormButton } from './words';
import { setupIPAButtons, setupHeaderButtons, setupInfoButtons } from './buttons'; import { setupInfoButtons, handleIPAButtonClicks, handleMaximizeButtonClicks } from './buttons';
import { setupTemplateForm, setupTemplateSelectOptions } from './settings'; import { handleTemplateFormClicks, setupTemplateChangeEvents, setupTemplateSelectOptions } from './settings';
import { setupSearchBarEvents } from './search';
export default function setupListeners() { export default function setupListeners() {
setupAnnouncements(); document.body.addEventListener('click', handleClickEvents);
setupDetailsTabs();
setupTemplateForm(); setupEditFormInteractions();
setupHeaderButtons(); setupTemplateChangeEvents();
setupSearchBarEvents();
setupWordForm(); setupWordForm();
setupMobileWordFormButton(); setupMobileWordFormButton();
setupInfoButtons(); setupInfoButtons();
@ -21,25 +23,36 @@ export default function setupListeners() {
} }
} }
function setupAnnouncements() { function handleClickEvents(event) {
const announcements = document.querySelectorAll('.announcement'); const when = (selector, cb) => {
Array.from(announcements).forEach(announcement => { if (event.target.matches(selector)) {
if (announcement.id && isDismissed(announcement.id)) { cb(event.target);
fadeOutElement(announcement);
} else {
announcement.querySelector('.close-button').addEventListener('click', () => dismiss(announcement));
} }
};
handleClickAccouncementClose(when);
handleDetailClicks(when);
handleTemplateFormClicks(when);
handleIPAButtonClicks(when);
handleMaximizeButtonClicks(when);
}
/**
* Identify selector strings and handlers
* @param {Function} when Passed from setupListeners, which listens to clicks on document.body
*/
function handleClickAccouncementClose(when) {
when('.announcement .close-button', closeElement => {
dismiss(closeElement.parentElement);
}); });
} }
export function setupIPAFields() { export function setupIPAFields(parent) {
if (window.settings.useIPAPronunciationField) { if (window.settings.useIPAPronunciationField) {
const ipaFields = document.getElementsByClassName('ipa-field'); const ipaFields = (parent ?? document).querySelectorAll('.ipa-field');
Array.from(ipaFields).forEach(field => { Array.from(ipaFields).forEach(field => {
field.removeEventListener('keypress', usePhondueDigraphs); field.removeEventListener('keypress', usePhondueDigraphs);
field.addEventListener('keypress', usePhondueDigraphs); field.addEventListener('keypress', usePhondueDigraphs);
}); });
} }
setupIPAButtons();
} }

View file

@ -1,20 +1,4 @@
import { insertAtCursor, getInputSelection, setSelectionRange } from '../StackOverflow/inputCursorManagement'; import { insertAtCursor, getInputSelection, setSelectionRange } from '../StackOverflow/inputCursorManagement';
import {
openSettingsModal,
saveSettingsModal,
saveAndCloseSettingsModal,
createTemplate,
saveTemplate
} from '../settings';
export function setupSettingsModal() {
document.getElementById('createTemplateButton').addEventListener('click', createTemplate);
document.getElementById('saveTemplateButton').addEventListener('click', saveTemplate);
document.getElementById('settingsButton').addEventListener('click', openSettingsModal);
document.getElementById('settingsSave').addEventListener('click', saveSettingsModal);
document.getElementById('settingsSaveAndClose').addEventListener('click', saveAndCloseSettingsModal);
}
export function setupIPATable(modal, textBox) { export function setupIPATable(modal, textBox) {
const closeElements = modal.querySelectorAll('.modal-background, .close-button, .done-button'), const closeElements = modal.querySelectorAll('.modal-background, .close-button, .done-button'),

View file

@ -1,9 +1,20 @@
import { renderWords } from '../render/words'; import { renderWords } from '../render/words';
import { showSearchModal, clearSearchText, checkAllPartsOfSpeechFilters, uncheckAllPartsOfSpeechFilters } from '../search'; import { showSearchModal, clearSearchText, checkAllPartsOfSpeechFilters, uncheckAllPartsOfSpeechFilters } from '../search';
export function setupSearchBar() { /**
* Identify selector strings and handlers
* @param {Function} when Passed from setupListeners, which listens to clicks on document.body
*/
export function handleSearchClickEvents(when) {
when('#clearSearchButton', clearSearchText);
when('#openSearchModal', showSearchModal);
when('#checkAllFilters', checkAllPartsOfSpeechFilters);
when('#uncheckAllFilters', uncheckAllPartsOfSpeechFilters);
}
export function setupSearchBarEvents() {
const searchBox = document.getElementById('searchBox'), const searchBox = document.getElementById('searchBox'),
clearSearchButton = document.getElementById('clearSearchButton'),
openSearchModal = document.getElementById('openSearchModal'), openSearchModal = document.getElementById('openSearchModal'),
searchIgnoreDiacritics = document.getElementById('searchIgnoreDiacritics'), searchIgnoreDiacritics = document.getElementById('searchIgnoreDiacritics'),
searchExactWords = document.getElementById('searchExactWords'), searchExactWords = document.getElementById('searchExactWords'),
@ -14,8 +25,6 @@ export function setupSearchBar() {
searchBox.addEventListener('input', event => { searchBox.addEventListener('input', event => {
openSearchModal.value = event.target.value; openSearchModal.value = event.target.value;
}); });
clearSearchButton.addEventListener('click', clearSearchText);
openSearchModal.addEventListener('click', showSearchModal);
const toggleDetailsCheck = function() { const toggleDetailsCheck = function() {
if (searchExactWords.checked) { if (searchExactWords.checked) {
@ -47,8 +56,4 @@ export function setupSearchFilters() {
filter.removeEventListener('change', renderWords); filter.removeEventListener('change', renderWords);
filter.addEventListener('change', renderWords); filter.addEventListener('change', renderWords);
}); });
document.getElementById('checkAllFilters').removeEventListener('click', checkAllPartsOfSpeechFilters);
document.getElementById('checkAllFilters').addEventListener('click', checkAllPartsOfSpeechFilters);
document.getElementById('uncheckAllFilters').removeEventListener('click', uncheckAllPartsOfSpeechFilters);
document.getElementById('uncheckAllFilters').addEventListener('click', uncheckAllPartsOfSpeechFilters);
} }

View file

@ -1,27 +1,36 @@
import { createTemplate, saveTemplate, editSavedTemplate, deleteSelectedTemplate } from "../settings"; import {
createTemplate,
saveTemplate,
editSavedTemplate,
deleteSelectedTemplate,
openSettingsModal,
saveSettingsModal,
saveAndCloseSettingsModal
} from "../settings";
export function setupTemplateForm() { /**
document.getElementById('createTemplateButton').addEventListener('click', createTemplate); * Identify selector strings and handlers
document.getElementById('saveTemplateButton').addEventListener('click', saveTemplate); * @param {Function} when Passed from setupListeners, which listens to clicks on document.body
document.getElementById('deleteTemplateButton').addEventListener('click', deleteSelectedTemplate); */
setupSavedTemplatesSelect(); export function handleSettingsModalClicks(when) {
when('#createTemplateButton', createTemplate);
when('#saveTemplateButton', saveTemplate);
when('#deleteTemplateButton', deleteSelectedTemplate);
when('#settingsButton', openSettingsModal);
when('#settingsSave', saveSettingsModal);
when('#settingsSaveAndClose', saveAndCloseSettingsModal);
} }
export function setupSavedTemplatesSelect() { export function setupTemplateChangeEvents() {
const savedTemplatesSelect = document.getElementById('savedDetailsTemplates'); const savedTemplatesSelect = document.getElementById('savedDetailsTemplates');
savedTemplatesSelect.removeEventListener('change', editSavedTemplate); savedTemplatesSelect.removeEventListener('change', editSavedTemplate);
savedTemplatesSelect.addEventListener('change', editSavedTemplate); savedTemplatesSelect.addEventListener('change', editSavedTemplate);
setupTemplateSelectOptions();
} }
export function setupTemplateSelectOptions() { export function setupTemplateSelectOptions() {
const fillDetailsWithTemplate = function (e) {
if (e.target.value !== '') {
const template = window.settings.templates[parseInt(e.target.value)];
let detailsId = 'wordDetails' + e.target.id.replace('templateSelect', '');
document.getElementById(detailsId).value = template.template;
}
}
Array.from(document.getElementsByClassName('template-select')).forEach(select => { Array.from(document.getElementsByClassName('template-select')).forEach(select => {
if (select.id !== 'savedDetailsTemplates') { if (select.id !== 'savedDetailsTemplates') {
select.removeEventListener('change', fillDetailsWithTemplate); select.removeEventListener('change', fillDetailsWithTemplate);
@ -29,3 +38,12 @@ export function setupTemplateSelectOptions() {
} }
}); });
} }
function fillDetailsWithTemplate (event) {
const { target } = event;
if (target.value !== '') {
const template = window.settings.templates[parseInt(target.value)];
let detailsId = 'wordDetails' + target.id.replace('templateSelect', '');
document.getElementById(detailsId).value = template.template;
}
}

View file

@ -1,7 +1,6 @@
import { renderEditForm } from '../render/words'; import { renderEditForm } from '../render/words';
import { confirmEditWord, cancelEditWord, confirmDeleteWord, expandAdvancedForm, submitWordForm } from '../wordManagement'; import { confirmEditWord, cancelEditWord, confirmDeleteWord, expandAdvancedForm, submitWordForm } from '../wordManagement';
// import { goToNextPage, goToPreviousPage, goToPage } from '../pagination'; // import { goToNextPage, goToPreviousPage, goToPage } from '../pagination';
import { setupMaximizeButtons } from './buttons';
import { setupIPAFields } from '.'; import { setupIPAFields } from '.';
export function setupWordForm() { export function setupWordForm() {
@ -17,7 +16,6 @@ export function setupWordForm() {
addWordButton.addEventListener('click', submitWordForm); addWordButton.addEventListener('click', submitWordForm);
setupIPAFields(); setupIPAFields();
setupMaximizeButtons();
} }
export function setupWordOptionButtons() { export function setupWordOptionButtons() {
@ -80,7 +78,6 @@ export function setupWordEditFormButtons() {
}); });
setupIPAFields(); setupIPAFields();
setupMaximizeButtons();
} }
export function setupMobileWordFormButton() { export function setupMobileWordFormButton() {