Skip to content

Commit

Permalink
Refactor js code organization
Browse files Browse the repository at this point in the history
Now we centralize the initialization of most elements through an init function that can be called when first loading a page and also when loading modals
  • Loading branch information
ffont committed Nov 3, 2023
1 parent 020258b commit d8bf647
Show file tree
Hide file tree
Showing 44 changed files with 333 additions and 548 deletions.
17 changes: 3 additions & 14 deletions freesound/static/bw-frontend/src/components/addSoundsModal.js
Original file line number Diff line number Diff line change
@@ -1,17 +1,9 @@
import {dismissModal, handleGenericModal} from "../components/modal"
import {stopAllPlayers} from '../components/player/utils'
import {createPlayer} from '../components/player/player-ui'
import {initializeObjectSelector, updateObjectSelectorDataProperties} from '../components/objectSelector'
import addCheckboxVisibleElements from "../components/checkbox"
import {serializedIdListToIntList, combineIdsLists} from "../utils/data"

const handleAddSoundsModal = (modalId, modalUrl, selectedSoundsDestinationElement, onSoundsSelectedCallback) => {
handleGenericModal(modalUrl, (modalContainer) => {
const players = [...modalContainer.getElementsByClassName('bw-player')]
players.forEach(createPlayer)

addCheckboxVisibleElements()

const inputElement = modalContainer.getElementsByTagName('input')[0];
inputElement.addEventListener("keypress", function(event) {
if (event.key === "Enter") {
Expand Down Expand Up @@ -45,14 +37,11 @@ const handleAddSoundsModal = (modalId, modalUrl, selectedSoundsDestinationElemen
onSoundsSelectedCallback(objectSelectorElement.dataset.selectedIds);
dismissModal(modalId);
});
}, (modalContainer) => {
// Stop all players that could be being played inside the modal
stopAllPlayers();
}, true, true);
}, undefined, true, true);
}

const prepareAddSoundsModalAndFields = () => {
const addSoundsButtons = [...document.querySelectorAll(`[data-toggle^="add-sounds-modal"]`)];
const prepareAddSoundsModalAndFields = (container) => {
const addSoundsButtons = [...container.querySelectorAll(`[data-toggle^="add-sounds-modal"]`)];
addSoundsButtons.forEach(addSoundsButton => {
const removeSoundsButton = addSoundsButton.nextElementSibling;
removeSoundsButton.disabled = true;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
import {handleGenericModal} from './modal';


const bindDownloadSoundButtons = () => {
const prepareAfterDownloadSoundModals = () => {
const downloadButtonElements = document.getElementsByClassName('sound-download-button');
downloadButtonElements.forEach(element => {
const showModalUrl = element.dataset.showAfterDownloadModalUrl;
element.addEventListener('click', () => {
handleGenericModal(showModalUrl, () => {}, () => {}, false, true);
handleGenericModal(showModalUrl, undefined, undefined, false, true);
});
});
}

bindDownloadSoundButtons();
export { prepareAfterDownloadSoundModals };
63 changes: 27 additions & 36 deletions freesound/static/bw-frontend/src/components/asyncSection.js
Original file line number Diff line number Diff line change
@@ -1,39 +1,30 @@
import {showToast} from "./toast";
import {initPlayersInModal} from './modal';
import {bindSimilarSoundModals} from './similarSoundsModal';
import {bindBookmarkSoundButtons} from './bookmarkSound';
import {bindRemixGroupModals} from './remixGroupModal';
import { showToast } from "./toast";
import { initializeStuffInContainer } from "../utils/initHelper";

const asyncSectionPlaceholders = document.getElementsByClassName('async-section');

const initPlayersAndPlayerModalsInElement = (element) => {
initPlayersInModal(element);
bindSimilarSoundModals();
bindBookmarkSoundButtons();
bindRemixGroupModals();
}

asyncSectionPlaceholders.forEach(element => {
const contentUrl = element.dataset.asyncSectionContentUrl;

const req = new XMLHttpRequest();
req.open('GET', contentUrl);
req.onload = () => {
if (req.status >= 200 && req.status < 300) {
element.innerHTML = req.responseText;

// Make sure we initialize sound/pack players inside the async section
initPlayersAndPlayerModalsInElement(element);
} else {
const prepareAsyncSections = (container) => {
const asyncSectionPlaceholders = container.getElementsByClassName('async-section');
asyncSectionPlaceholders.forEach(element => {
const contentUrl = element.dataset.asyncSectionContentUrl;
const req = new XMLHttpRequest();
req.open('GET', contentUrl);
req.onload = () => {
if (req.status >= 200 && req.status < 300) {
element.innerHTML = req.responseText;
// Make sure we initialize sound/pack players inside the async section
initializeStuffInContainer(element, true, false);
} else {
// Unexpected errors happened while processing request: show toast
showToast('Unexpected errors occurred while loading some of the content of this page. Please try again later...')
}
};
req.onerror = () => {
// Unexpected errors happened while processing request: show toast
showToast('Unexpected errors occurred while loading some of the content of this page. Please try again later...')
}
};
req.onerror = () => {
// Unexpected errors happened while processing request: show toast
showToast('Unexpected errors occurred while loading some of the content of this page. Please try again later...')
};

// Send the form
req.send();
});
};

// Send the form
req.send();
});
}

export {prepareAsyncSections};
14 changes: 5 additions & 9 deletions freesound/static/bw-frontend/src/components/bookmarkSound.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import {dismissModal, handleGenericModal} from "./modal";
import {createSelect} from "./select";
import {showToast} from "./toast";
import {makePostRequest} from "../utils/postRequest";

Expand Down Expand Up @@ -47,18 +46,17 @@ const initBookmarkFormModal = (soundId, addBookmarkUrl) => {
const modalContainer = document.getElementById(`bookmarkSoundModal`);
const selectElement = modalContainer.getElementsByTagName('select')[0];
const wrapper = document.createElement('div');
wrapper.style = 'display:inline-block;';
if (selectElement === undefined){
// If no select element, the modal has probably loaded for an unauthenticated user
return;
}
selectElement.parentNode.insertBefore(wrapper, selectElement.parentNode.firstChild);
const label = document.createElement('div');
label.innerHTML = "Select a bookmark category:"
label.style = 'display:inline-block;';
label.classList.add('text-grey');
wrapper.appendChild(label)
wrapper.appendChild(selectElement)
createSelect(); // We need to trigger create select elements because bookmark form has one

const formElement = modalContainer.getElementsByTagName('form')[0];
const buttonsInModalForm = formElement.getElementsByTagName('button');
Expand All @@ -80,8 +78,8 @@ const initBookmarkFormModal = (soundId, addBookmarkUrl) => {
});
};

const bindBookmarkSoundButtons = () => {
const bookmarkSoundButtons = [...document.querySelectorAll('[data-toggle="bookmark-modal"]')];
const bindBookmarkSoundModals = (container) => {
const bookmarkSoundButtons = [...container.querySelectorAll('[data-toggle="bookmark-modal"]')];
bookmarkSoundButtons.forEach(element => {
if (element.dataset.alreadyBinded !== undefined){
return;
Expand All @@ -94,14 +92,12 @@ const bindBookmarkSoundButtons = () => {
if (!evt.altKey) {
handleGenericModal(element.dataset.modalUrl, () => {
initBookmarkFormModal(soundId, element.dataset.addBookmarkUrl);
}, () => {}, true, true);
}, undefined, true, true);
} else {
saveBookmark(element.dataset.addBookmarkUrl);
}
});
});
}

bindBookmarkSoundButtons();

export {bindBookmarkSoundButtons};
export { bindBookmarkSoundModals };
14 changes: 3 additions & 11 deletions freesound/static/bw-frontend/src/components/carousel.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,14 +8,8 @@ const autoprefixedTransformProperties = [
'transform',
]

const initializeCarousels = (parentContainer) => {
let carouselContainers;
if (parentContainer === undefined){
carouselContainers = [...document.getElementsByClassName('bw-carousel-container')]
} else {
carouselContainers = [...parentContainer.getElementsByClassName('bw-carousel-container')]
}

const makeCarousels = (container) => {
const carouselContainers = [...container.getElementsByClassName('bw-carousel-container')]
carouselContainers.forEach(carouselContainer => {
const carousel = [
...carouselContainer.getElementsByClassName('bw-carousel'),
Expand Down Expand Up @@ -150,6 +144,4 @@ const initializeCarousels = (parentContainer) => {
})
}

initializeCarousels();

export {initializeCarousels};
export {makeCarousels};
8 changes: 3 additions & 5 deletions freesound/static/bw-frontend/src/components/checkbox.js
Original file line number Diff line number Diff line change
Expand Up @@ -35,11 +35,9 @@ const addVisibleCheckbox = (checkboxEl) => {
}
};

const addCheckboxVisibleElements = () => {
const checkboxes = [...document.querySelectorAll('input.bw-checkbox')];
const makeCheckboxes = (container) => {
const checkboxes = [...container.querySelectorAll('input.bw-checkbox')];
checkboxes.forEach(addVisibleCheckbox);
};

addCheckboxVisibleElements();

export default addCheckboxVisibleElements;
export { makeCheckboxes };
59 changes: 29 additions & 30 deletions freesound/static/bw-frontend/src/components/collapsableBlock.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
const collapsableToggles = document.getElementsByClassName('collapsable-toggle');

const toggleCollapse = (toggleElement) => {
const collapsableContainer = document.getElementById(toggleElement.dataset.target);
let closeClass = 'collapsable-block-close';
Expand All @@ -24,36 +22,37 @@ const handleCollapsable = (e) => {
toggleCollapse(e.target);
};

collapsableToggles.forEach(element => {
if (element.dataset.initialized !== undefined) { return;}
element.dataset.initialized = 'true';
const collapsableContainer = document.getElementById(element.dataset.target);
if (element.dataset.maxHeightWhenClosed !== undefined) {
// If a max height is set, then the element will be partially visible when closed,
// but if the element's height is actually less than the max height, then no "colappsable"
// actions will take place and we hide the toggle element
if (element.dataset.maxHeightWhenClosed >= collapsableContainer.clientHeight) {
element.classList.add('display-none'); // Hide controls
return; // continue to next toggle element as this will not implement collapsable behaviour
const makeCollapsableBlocks = (container) => {
const collapsableToggles = container.getElementsByClassName('collapsable-toggle');
collapsableToggles.forEach(element => {
if (element.dataset.initialized !== undefined) { return;}
element.dataset.initialized = 'true';
const collapsableContainer = document.getElementById(element.dataset.target);
if (element.dataset.maxHeightWhenClosed !== undefined) {
// If a max height is set, then the element will be partially visible when closed,
// but if the element's height is actually less than the max height, then no "colappsable"
// actions will take place and we hide the toggle element
if (element.dataset.maxHeightWhenClosed >= collapsableContainer.clientHeight) {
element.classList.add('display-none'); // Hide controls
return; // continue to next toggle element as this will not implement collapsable behaviour
}
}
}

if (collapsableContainer.classList.contains('collapsable-block-close') || collapsableContainer.classList.contains('collapsable-block-close-gradient')){
// The collapsable block is already hidden
element.ariaExpanded = "false";
element.textContent = element.dataset.showText;
} else {
// The collapsable block is not hidden, but if hideOnLoad is set, it should be hidden
element.ariaExpanded = "true";
if (element.dataset.hideOnLoad !== undefined){
toggleCollapse(element); // this will set the ariaExpanded to false
if (collapsableContainer.classList.contains('collapsable-block-close') || collapsableContainer.classList.contains('collapsable-block-close-gradient')){
// The collapsable block is already hidden
element.ariaExpanded = "false";
element.textContent = element.dataset.showText;
} else {
element.textContent = element.dataset.hideText;
// The collapsable block is not hidden, but if hideOnLoad is set, it should be hidden
element.ariaExpanded = "true";
if (element.dataset.hideOnLoad !== undefined){
toggleCollapse(element); // this will set the ariaExpanded to false
} else {
element.textContent = element.dataset.hideText;
}
}
}
element.addEventListener('click', handleCollapsable);
});

export {toggleCollapse};

element.addEventListener('click', handleCollapsable);
});
}

export {toggleCollapse, makeCollapsableBlocks};
19 changes: 7 additions & 12 deletions freesound/static/bw-frontend/src/components/commentsModal.js
Original file line number Diff line number Diff line change
@@ -1,24 +1,19 @@
import {handleGenericModal, bindModalActivationElements, activateModalsIfParameters, initPlayersInModal, stopPlayersInModal, bindConfirmationModalElements} from './modal';
import {bindFlagUserElements} from './flagging';
import {handleGenericModal, bindModalActivationElements, activateModalsIfParameters} from './modal';


const handleCommentsModal = (modalUrl, modalActivationParam, atPage) => {
if ((atPage !== undefined) && modalUrl.indexOf('&page') == -1){
modalUrl += '&page=' + atPage;
}
handleGenericModal(modalUrl, (modalContainer) => {
initPlayersInModal(modalContainer);
bindConfirmationModalElements(modalContainer); // For the "delete comment" buttons which need confirmation
bindFlagUserElements(modalContainer); // For the "flag comment" buttons
}, (modalContainer) => {
stopPlayersInModal(modalContainer);
}, true, true, modalActivationParam);
handleGenericModal(modalUrl, undefined, undefined, true, true, modalActivationParam);
}

const bindCommentsModals = (container) => {
bindModalActivationElements('[data-toggle="comments-modal"]', handleCommentsModal, container);
}

bindCommentsModals();
activateModalsIfParameters('[data-toggle="comments-modal"]', handleCommentsModal);
const activateCommentsModalsIfParameters = () => {
activateModalsIfParameters('[data-toggle="comments-modal"]', handleCommentsModal);
}

export {bindCommentsModals};
export {bindCommentsModals, activateCommentsModalsIfParameters};
20 changes: 7 additions & 13 deletions freesound/static/bw-frontend/src/components/downloadersModals.js
Original file line number Diff line number Diff line change
@@ -1,25 +1,19 @@
import {handleGenericModal, bindModalActivationElements, activateModalsIfParameters, initPlayersInModal, stopPlayersInModal} from './modal';
import {handleGenericModal, bindModalActivationElements, activateModalsIfParameters} from './modal';

const handleDownloadersModal = (modalUrl, modalActivationParam, atPage) => {
if ((atPage !== undefined) && modalUrl.indexOf('&page') == -1){
modalUrl += '&page=' + atPage;
}
handleGenericModal(modalUrl, (modalContainer) => {
// This method is used both for the "users that downloaded sound/pack" and the "sounds/packs downloaded by user" modals
// The second type displays sounds players in the modal so we need to initialize them when modal is loaded
initPlayersInModal(modalContainer);
}, (modalContainer) => {
// This method is used both for the "users that downloaded sound/pack" and the "sounds/packs downloaded by user" modals
// The second type displays sounds players in the modal so we need to stop them when modal is closed
stopPlayersInModal(modalContainer);
}, true, true, modalActivationParam);
handleGenericModal(modalUrl, undefined, undefined, true, true, modalActivationParam);
}

const bindDownloadersModals = (container) => {
bindModalActivationElements('[data-toggle="downloaders-modal"]', handleDownloadersModal, container);
}

bindDownloadersModals();
activateModalsIfParameters('[data-toggle="downloaders-modal"]', handleDownloadersModal);
const activateDownloadersModalsIfParameters = () => {
activateModalsIfParameters('[data-toggle="downloaders-modal"]', handleDownloadersModal);
}


export {bindDownloadersModals};
export {bindDownloadersModals, activateDownloadersModalsIfParameters};
27 changes: 15 additions & 12 deletions freesound/static/bw-frontend/src/components/dropdown.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
const dropdownToggles = [...document.querySelectorAll('[data-toggle="dropdown"]')];

const lastOpenedDropdown = { toggle: undefined, dropdownOptions: undefined };

const closeOnClickAway = () => {
Expand Down Expand Up @@ -39,14 +37,19 @@ const toggleExpandDropdown = toggle => {
}
};

dropdownToggles.forEach(toggle => {
toggle.ariaExpanded = 'false';
toggle.ariaHasPopup = 'menu';
const dropdownContainer = toggle.closest('.dropdown');
const dropdownOptions = dropdownContainer.getElementsByClassName('dropdown-menu')[0];
dropdownOptions.setAttribute('role', 'menu');
dropdownOptions.getElementsByClassName('dropdown-item').forEach(item => {
item.setAttribute('role', 'menuitem');
const makeDropdowns = (container) => {
const dropdownToggles = [...container.querySelectorAll('[data-toggle="dropdown"]')];
dropdownToggles.forEach(toggle => {
toggle.ariaExpanded = 'false';
toggle.ariaHasPopup = 'menu';
const dropdownContainer = toggle.closest('.dropdown');
const dropdownOptions = dropdownContainer.getElementsByClassName('dropdown-menu')[0];
dropdownOptions.setAttribute('role', 'menu');
dropdownOptions.getElementsByClassName('dropdown-item').forEach(item => {
item.setAttribute('role', 'menuitem');
});
toggle.addEventListener('click', () => toggleExpandDropdown(toggle));
});
toggle.addEventListener('click', () => toggleExpandDropdown(toggle));
});
}

export {makeDropdowns};
Loading

0 comments on commit d8bf647

Please sign in to comment.