add: new js files for simplicity

This commit is contained in:
2026-05-13 17:21:03 -04:00
parent 0a55500892
commit 788190328b
8 changed files with 1186 additions and 8 deletions
+439
View File
@@ -0,0 +1,439 @@
import * as note from './note.js';
import { state } from './state.js';
import * as ref from './reference.js';
// Get the link element
var tabs = [];
let controller;
// Function to change the CSS file based on checkbox state
/**
* Method to toggle dark/light mode
*
* @param {*} event
*/
export function toggleDarkMode(event) {
let mainCssLink = $('link[data-css="mode"');
if(mainCssLink.length > 0) {
mainCssLink[0].href = (event.target.checked ? mainCssLink.data('dark') : mainCssLink.data('light'));
}
}
/**
* Toggles the visibility of the fields container and updates the active state of the show/hide button.
*
* @param Event e
* @param boolean forceShow
* @return {void}
*/
export function toggleFields(e, forceShow = false) {
const fieldsContainer = document.querySelector('.fields-container');
let showHideBtn = document.getElementById('show-hide-btn');
let mobileShowHideBtn = document.getElementById('mobile-show-hide-btn');
if (forceShow || !fieldsContainer.classList.contains('show')) {
fieldsContainer.classList.add('show');
fieldsContainer.style.display = 'flex';
showHideBtn.classList.add('active');
mobileShowHideBtn.classList.add('active');
} else {
fieldsContainer.classList.remove('show');
fieldsContainer.style.display = 'none';
showHideBtn.classList.remove('active');
mobileShowHideBtn.classList.remove('active');
}
}
/**
* Increases the font size of the element with the id 'ref' by 1 point.
*
* @return {void} This function does not return a value.
*/
export function increaseFont() {
var currentSize = document.querySelector('#ref-text').style.fontSize;
const newSize = parseInt(currentSize) + 1;
document.querySelector('#ref-text').style.fontSize = newSize + 'pt';
document.querySelector('#notes').style.fontSize = newSize + 'pt';
document.querySelector('#notePreview').style.fontSize = newSize + 'pt';
}
/**
* Decreases the font size of the element with the id 'ref' by 1 point.
*
* @return {void} This function does not return a value.
*/
export function decreaseFont() {
var currentSize = document.querySelector('#ref-text').style.fontSize;
const newSize = parseInt(currentSize) - 1;
document.querySelector('#ref-text').style.fontSize = newSize + 'pt';
document.querySelector('#notes').style.fontSize = newSize + 'pt';
document.querySelector('#notePreview').style.fontSize = newSize + 'pt';
}
/**
* Previews a note by rendering the markdown content of the note in a preview section.
* Toggles between the note text and preview sections.
*
* @return {void} This function does not return anything.
*/
export function previewNote() {
var noteText = document.querySelector('#notes');
var notePreview = document.querySelector('#notePreview');
var previewButton = document.querySelector('#previewBtn');
const title = document.querySelector('#noteTitle');
const speaker = document.querySelector('#speaker');
const passage = document.querySelector('#passage');
const markdownPreview = "# " + title.value + " - " +
speaker.options[speaker.selectedIndex].text + " - " + passage.value + "\n\n" + noteText.value;
notePreview.innerHTML = state.md.render(markdownPreview);
if (previewButton.classList.contains('active')) {
document.querySelector('.note-text').style.display = 'block';
notePreview.style.display = 'none';
previewButton.classList.remove('active');
} else {
document.querySelector('.note-text').style.display = 'none';
notePreview.style.display = 'block';
previewButton.classList.add('active');
}
note.findLinks();
}
/**
* Sets event listeners for keyup events on the document and the '#notes' element.
*
* @return {void}
*/
export function setEventListeners() {
document.addEventListener('keyup', function (event) {
if (event.key == "F3") {
openRef(false);
}
});
document.querySelector('#notes').addEventListener('keyup', function (event) {
let key = event.keyCode;
if (key == 8 || key >= 48 && key <= 90 || key >= 96 && key <= 111 || key >= 186 && key <= 222) {
state.textDirty = true;
document.querySelector('.mobile-note-header h2').classList.add('dirty');
document.querySelector('.note-header h2').classList.add('dirty');
}
});
document.getElementById('dark-mode-checkbox').addEventListener('click', toggleDarkMode);
document.getElementById('mobile-dark-mode-checkbox').addEventListener('click', toggleDarkMode);
document.getElementById('show-hide-btn').addEventListener('click', toggleFields);
document.getElementById('mobile-show-hide-btn').addEventListener('click', toggleFields);
document.getElementById('increaseFont').addEventListener('click', increaseFont);
document.getElementById('decreaseFont').addEventListener('click', decreaseFont);
document.getElementById('open-ref').addEventListener('click', openRef, {closeSidebar: false});
document.getElementById('mobile-open-ref').addEventListener('click', openRef, {closeSidebar: false});
document.getElementById('previewBtn').addEventListener('click', previewNote);
document.getElementById('searchBtn').addEventListener('click', ref.queryRef);
document.getElementById('closeSearch').addEventListener('click', closeRef);
}
export function initHome() {
setBooks();
setEventListeners();
$('sidebar-link').on('click', function(event) {
event.preventDefault();
event.stopPropagation();
$('#sidebar').toggleClass('inactive');
});
$('sidebar').on('click', 'a', function(event) {
var $a = $(this), href = $a.attr('href'), target = $a.attr('target');
event.preventDefault();
event.stopPropagation();
$('sidebar').addClass('inactive');
setTimeout(function() {
if (target == '_blank')
window.open(href);
else
window.location.href = href;
}, 500);
});
$('#note-table').DataTable({
paging: false,
ajax: {
url: '/get-notes',
type: 'POST'
},
columns: [
{ data: 'link' },
{ data: 'speaker.name' },
{ data: 'passage' },
{
data: 'date.date',
render: DataTable.render.date("L")
},
]
});
$('#shareBtn').on('click', note.openShareNote);
$('#modal-backdrop').on('click', note.closeShareNote);
state.md = new markdownit({
html: true,
linkify: true,
breaks: true
});
if ($('#noteDate')) {
$('#noteDate').datepicker();
}
if ($('#query')) {
document.querySelector('#query').addEventListener('keyup', function (event) {
if (event.key == "Enter") {
search();
}
});
}
// Assuming 'to' and 'saveInterval' are declared globally elsewhere in your script
if (typeof state.to === 'undefined' || !state.to) {
state.to = setTimeout(note.saveNote, state.saveInterval);
}
}
/**
* Fetches data from '/js/data.json', assigns it to BOOKS, and handles errors.
*
* @return {void}
*/
export function setBooks() {
fetch('js/data.json')
.then((res) => {
if (!res.ok) {
throw new Error('HTTP Error: Status: ${res.status}');
}
return res.json();
})
.then((data) => {
state.BOOKS = data;
})
.catch((error) => {
console.log(error);
})
}
/**
* Opens the reference with the option to close the sidebar.
*
* @param {boolean} closeSidebar - Indicates whether to close the sidebar when opening the reference.
*/
export function openRef(e, closeSidebar = true) {
document.querySelector('#open-ref').classList.add('active');
document.querySelector('#mobile-open-ref').classList.add('active');
let refQuery = document.querySelector('#refQuery');
refQuery.style.display = 'block';
let ref = document.querySelector('#ref-text');
refQuery.style.left = ref.offsetLeft + 'px';
refQuery.style.top = ref.offsetTop + 'px';
if (closeSidebar) {
document.querySelector('.toggle').click();
}
}
/**
* Closes the reference query and resets the reference search form.
*
* @return {void} This function does not return anything.
*/
export function closeRef() {
document.querySelector('#referenceSearch').value = '';
document.querySelector('#referenceSearch').style.display = '';
document.querySelector('#referenceType').value = '';
document.querySelector('#referenceBook').value = '';
document.querySelector('#referenceBook').style.display = 'none';
document.querySelector('#chapter-range').innerText = '';
document.querySelector('#verse-range').innerText = '';
document.querySelector('#refQuery').style.display = 'none';
document.querySelector('#open-ref').classList.remove('active');
document.querySelector('#mobile-open-ref').classList.remove('active');
}
/**
* Retrieves a note from the server based on the provided ID.
*
* @param {string} id - The ID of the note to retrieve.
* @param {boolean} [runOpen=true] - Whether to open the note sidebar after retrieving the note.
* @return {Promise<void>} A promise that resolves when the note is successfully retrieved and the UI is updated.
*/
export function retrieveNote(id, runOpen = true) {
fetch('/get-note', {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({
'id': id
})
})
.then(response => response.json())
.then(result => {
var dt = new Date(result.date.date);
document.querySelector('#notes').value = result.text;
document.querySelector('#passage').value = result.passage;
document.querySelector('#series').value = result.series.id;
document.querySelector('#speaker').value = result.speaker.id;
document.querySelector('#noteTitle').value = result.title;
document.querySelector('#noteDate').value = '';
document.querySelector('#noteDate').value =
(dt.getMonth() < 9 ? '0' + (dt.getMonth() + 1) : (dt.getMonth() + 1)) + '/' +
(dt.getDate() < 10 ? '0' + dt.getDate() : dt.getDate()) + '/' +
dt.getFullYear();
document.querySelector('#noteId').value = result.id;
if (result.refs) {
references = result.refs;
}
const list = document.querySelector('#ref-list');
list.innerHTML = '';
var newList = null;
for (var x in references) {
var newList = document.createElement('li');
newList.className = 'tab';
var button = makeButton(x);
newList.appendChild(button);
list.appendChild(newList);
}
if (runOpen) {
note.openNote(false);
}
});
}
/**
* A function to create a button element with the specified title and event listeners for click and double click actions.
*
* @param {string} title - The title to be displayed on the button.
* @return {Element} The created button element.
*/
export function makeButton(title) {
var btn = document.createElement('button');
btn.innerText = title;
btn.class = 'button';
btn.style = 'line-height:normal;'
btn.addEventListener('click', function () {
removeActiveRef();
document.querySelector('#ref-text').innerHTML = state.md.render(state.references[title]);
this.classList.add('active');
note.findRefLinks();
});
btn.addEventListener('dblclick', function () {
document.querySelector('#ref-text').innerHTML = '';
delete state.references[title];
var list = this.parentElement;
list.remove();
state.saved = false;
state.textDirty = true;
note.saveNote();
});
removeActiveRef();
btn.classList.add('active');
return btn;
}
/**
* Removes the 'active' class from all elements with the class 'active'.
*
* @return {void} This function does not return a value.
*/
export function removeActiveRef() {
tabs = document.querySelectorAll('#ref-list .active');
for (var t in tabs) {
if (isFinite(parseInt(t))) {
tabs[t].classList.remove('active');
}
}
}
/**
* Generates a random UUIDv4 string.
*
* @return {string} The generated UUIDv4 string.
*/
export function uuidv4() {
return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'
.replace(/[xy]/g, function (c) {
const r = Math.random() * 16 | 0,
v = c == 'x' ? r : (r & 0x3 | 0x8);
return v.toString(16);
});
}
/**
* Searches for notes based on the query entered in the search field.
* Sends a POST request to the '/search' endpoint with the query as a JSON payload.
* Updates the '#old-notes' element with the search results.
*
* @return {Promise} A Promise that resolves with the search results.
*/
export function search() {
query = document.querySelector('#query').value;
fetch('/search', {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({
'query': query
})
})
.then(response => response.json())
.then(results => {
var oldNotes = document.querySelector('#old-notes');
oldNotes.innerHTML = '';
for (var n in results) {
var link = document.createElement('a');
link.href = '#';
link.setAttribute('onclick', "note.retrieveNote('" + results[n].id + "');note.openNote();");
link.innerHTML = results[n].title;
var p = document.createElement('p');
p.innerHTML = results[n].passage;
var article = document.createElement('article');
article.appendChild(link);
article.appendChild(p);
oldNotes.append(article);
}
});
}
/**
* Closes the passage popup by clearing its content and hiding it.
*
* @return {void} This function does not return anything.
*/
export function closePopup() {
const popup = document.querySelector('#passage-popup');
popup.innerHTML = '';
popup.style.display = 'none';
}
+412
View File
@@ -0,0 +1,412 @@
import { state } from './state.js';
import { toggleFields } from './home.js';
/**
* Toggles the visibility of the note list and reference elements.
*
* @param {boolean} [openSidebar=true] - Whether to open the sidebar after toggling the visibility.
* @return {void}
*/
export function openNote(openSidebar = true) {
const noteList = document.querySelector('#note-list');
const refs = document.querySelector('#ref');
if (noteList.style.display == 'block') {
noteList.style.display = 'none';
refs.style.display = 'block';
} else {
noteList.style.display = 'block';
refs.style.display = 'none';
}
if (openSidebar) {
document.querySelector('.toggle').click();
}
}
/**
* Starts the save process by updating the save-check element's classList, removing error, fa-times-circle, and fa-save classes,
* adding the 'saving' and 'fa-save' classes, and setting the opacity to 1.
*
* @return {void} This function does not return anything.
*/
export function startSave() {
document.querySelector('#save-check').classList.remove('error', 'fa-times-circle', 'fa-save');
document.querySelector('#save-check').classList.add('saving', 'fa-save');
document.querySelector('#save-check').style.opacity = 1;
}
/**
* Displays a checkmark animation on the screen.
*
* @param {none} - This function does not take any parameters.
* @return {none} - This function does not return any value.
*/
export function showSave() {
if (state.saved) { return; }
var checkmark = document.getElementById("save-check");
checkmark.classList.add('fa-save');
// Schedule the animation to run every 1 second (which is equivalent to a 1-second delay between each iteration)
var si = setInterval(function () {
// Increment the opacity of the checkmark by 0.01 each time
op = parseFloat(checkmark.style.opacity);
checkmark.style.opacity = op - 0.1;
// If the opacity is greater than or equal to 1, reset it back to 0 and stop the animation
if (checkmark.style.opacity == 0.1) {
checkmark.style.opacity = 0;
clearInterval(si);
state.saved = false;
}
}, 100);
}
/**
* function to discard the note by clearing all input fields and closing the menu.
*/
export function deleteNote(noteId, link) {
document.querySelector('#noteTitle').value = '';
document.querySelector('#speaker').value = 0;
document.querySelector('#series').value = 0;
document.querySelector('#template').value = 0;
document.querySelector('#passage').value = '';
document.querySelector('#notes').value = '';
document.querySelector('#recording').value = '';
document.querySelector('#noteDate').value = '';
document.querySelector('#noteId').value = '';
var row = link.parentElement.parentElement;
fetch('/delete-note', {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({
'id': noteId
})
})
.then(response => response.json())
.then(data => {
if (data.msg != 'deleted') {
return;
}
alert('Note deleted.');
row.remove();
});
}
/**
* Validates a note by checking if all required fields are filled.
*
* @return {boolean} Returns true if all required fields are filled, false otherwise.
*/
export function validateNote() {
const note = document.querySelector('#notes');
const date = document.querySelector('#noteDate');
const speaker = document.querySelector('#speaker');
const series = document.querySelector('#series');
const title = document.querySelector('#noteTitle');
const psg = document.querySelector('#passage');
let ret = true;
if (!title.value.length) { title.classList.add('input-error'); ret = false; }
if (!date.value) { date.classList.add('input-error'); ret = false; }
if (!parseInt(speaker.value)) { speaker.classList.add('input-error'); ret = false; }
if (!parseInt(series.value)) { series.classList.add('input-error'); ret = false; }
if (!psg.value) { psg.classList.add('input-error'); ret = false; }
if (!note.value.length) { note.classList.add('input-error'); ret = false; }
if (!ret) {
toggleFields(null, true);
}
return ret;
}
/**
* Resets the state of the note editor by clearing the text and form fields,
* resetting the references, and removing any dirty classes. It also sets the
* date to the current date, clears the speaker, series, template, passage,
* recording, and note ID fields. Finally, it clears the reference list and
* reference display.
*
* @return {void} This function does not return anything.
*/
export function newNote() {
notes = document.querySelector('#notes');
notes.text = '';
notes.value = '';
state.references = {};
state.saved = true;
state.textDirty = false;
document.querySelector('#note-header-left h2').classList.remove('dirty');
dt = new Date();
document.querySelector('#noteDate').value = dt.getFullYear() + '-' +
(dt.getMonth() < 9 ? '0' + (dt.getMonth() + 1) : (dt.getMonth() + 1)) + '-' +
(dt.getDate() < 10 ? '0' + dt.getDate() : dt.getDate());
document.querySelector('#noteTitle').value = '';
document.querySelector('#speaker').value = 0;
document.querySelector('#series').value = 0;
document.querySelector('#template').value = 0;
document.querySelector('#passage').value = '';
document.querySelector('#recording').value = '';
document.querySelector('#noteId').value = '';
document.querySelector('#ref-list').innerHTML = '';
document.querySelector('#ref').innerHTML = '';
document.querySelector('.toggle').click();
}
/**
* Save a note by sending it to the server for storage.
*
* @param {Event} event - The event object triggering the save action.
* @return {void} No explicit return value.
*/
export function saveNote(event) {
console.debug('called saveNote '+new Date());
if (event) {
event.preventDefault();
}
if (!state.textDirty) {
clearTimeout(state.to);
state.to = setTimeout(saveNote, state.saveInterval);
return;
}
document.querySelector('#noteTitle').classList.remove('input-error');
document.querySelector('#noteDate').classList.remove('input-error');
document.querySelector('#speaker').classList.remove('input-error');
document.querySelector('#series').classList.remove('input-error');
document.querySelector('#passage').classList.remove('input-error');
document.querySelector('#notes').classList.remove('input-error');
if (!validateNote()) {
clearTimeout(state.to);
state.to = setTimeout(saveNote, state.saveInterval);
return;
}
let saveCheck = document.querySelector('#save-check');
var noteText = document.querySelector('#notes').value;
startSave();
var note = {
id: document.querySelector("#noteId").value,
date: document.querySelector('#noteDate').value,
title: document.querySelector('#noteTitle').value,
speaker: document.querySelector('#speaker').value,
series: document.querySelector('#series').value,
passage: document.querySelector('#passage').value,
note: document.querySelector('#notes').value,
recording: document.querySelector('#recording').value,
refs: references
};
$.ajax({
url: '/save-note',
method: 'POST',
contentType: 'application/json',
data: JSON.stringify(note),
dataType: 'json',
timeout: state.saveTimeout
})
.done(function (data) {
if (data.msg == 'saved' && !state.saved) {
state.saveFailureCount = SAVE_FAILURE_LIMIT;
saveCheck.classList.remove('saving', 'error', 'fa-times-circle', 'fa-save');
showSave();
if (noteText == document.querySelector('#notes').value) {
state.saved = true;
state.textDirty = false;
document.querySelector('note-header h2').classList.remove('dirty');
document.querySelector('mobile-note-header h2').classList.remove('dirty');
}
if (data.new) {
document.querySelector('#noteId').value = data.id;
}
}
})
.fail(function (xhr, status, error) {
state.saveFailureCount--;
saveCheck.classList.remove('saving', 'fa-save');
saveCheck.classList.add('fa-times-circle', 'error');
console.error(error);
})
.always(function (xhr, status) {
if (status == 'timeout') {
saveCheck.classList.remove('saving', 'fa-save');
saveCheck.classList.add('error', 'fa-times-circle');
}
clearTimeout(to);
if (state.saveFailureCount > 0) {
state.to = setTimeout(saveNote, state.saveInterval);
} else {
state.saveFailureCount = SAVE_FAILURE_LIMIT;
}
});
}
/**
* Function that finds reference links and fetches passage data when clicked.
*/
export function findRefLinks() {
var links = document.querySelector('#ref-text').querySelectorAll('a');
for (var i = 0; i < links.length; i++) {
links[i].addEventListener('click', function (e) {
e.preventDefault();
if (!this.href.includes('get-passage')) {
return;
}
var passage = this.href.split('/');
passage = passage[passage.length - 1];
fetch(this.href, {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({
'passage': passage
})
})
.then(response => response.text())
.then(result => {
passage = passage.replace(/\+/g, ' ');
psg = passage.split(' ');
if (psg.length > 2) {
book = psg[0] + ' ' + psg[1];
cv = psg[2];
} else {
book = psg[0];
cv = psg[1];
}
showPassage(
e,
"<button onclick='closePopup()'>Close</button>&nbsp;&nbsp;" +
"<button onclick=\"queryRef('bible', '" + book + "', '" + cv + "')\">Open Ref</button><br/>" +
result);
});
});
}
}
/**
* Finds all links in the note preview and adds event listeners to them.
*
* @return {void}
*/
export function findLinks() {
var links = document.querySelector('#notePreview').querySelectorAll('a');
for (var i = 0; i < links.length; i++) {
links[i].addEventListener('click', function (e) {
e.preventDefault();
if (!this.href.includes('get-passage')) {
return;
}
var passage = this.href.split('/');
passage = passage[passage.length - 1];
fetch(this.href, {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({
'passage': passage
})
})
.then(response => response.text())
.then(result => {
passage = passage.replace(/\+/g, ' ');
psg = passage.split(' ');
if (psg.length > 2) {
book = psg[0] + ' ' + psg[1];
cv = psg[2];
} else {
book = psg[0];
cv = psg[1];
}
showPassage(
e,
"<button onclick='home.closePopup()'>Close</button>&nbsp;&nbsp;" +
"<button onclick=\"home.queryRef('bible', '" + book + "', '" + cv + "')\">Open Ref</button><br/>" +
result);
});
});
}
}
/**
* Opens the share note functionality.
*/
export function openShareNote() {
var id = document.querySelector('#noteId').value;
if (!id) {
alert('No Open Note Found');
return;
}
bd = document.querySelector('#modal-backdrop');
bd.style.display = 'block';
cont = document.querySelector('#modal-container');
cont.style.display = bd.style.display;
emailCont = document.querySelector('#modal-container');
emailCont.style.left = ((window.innerWidth / 2) - (emailCont.clientWidth / 2)) + 'px';
emailCont.style.top = ((window.innerHeight / 2) - (emailCont.clientHeight / 2)) + 'px';
}
/**
* Closes the share note modal by hiding the backdrop and container,
* and clears the email input value.
*/
export function closeShareNote() {
var bd = document.querySelector('#modal-backdrop');
var cont = document.querySelector('#modal-container');
bd.style.display = 'none';
cont.style.display = 'none';
document.querySelector('#shareEmail').value = '';
}
/**
* Function to share a note by sending the note ID and email to the server.
*/
export function shareNote(event) {
var id = document.querySelector('#noteId').value;
var email = document.querySelector('#shareEmail').value;
if (!id || !email) {
alert('Invalid Input');
return;
}
fetch('/share-note', {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({
'id': id,
'email': email
})
})
.then(response => response.json())
.then(result => {
if (result) {
alert(result.msg);
}
});
closeShareNote();
}
+212 -5
View File
@@ -1,3 +1,7 @@
import { state } from './state.js';
import { closeRef, makeButton } from './home.js';
import { saveNote, findRefLinks } from './note.js';
/**
* Retrieves the reference type from the server and populates the reference series dropdown.
*
@@ -7,7 +11,7 @@
export function retrieveReferenceType(el) {
fetch('/reference/' + el.value, {
method: 'GET',
header: {
headers: {
'Content-Type': 'application/json'
}
})
@@ -41,7 +45,7 @@ export function retrieveReference(el) {
}
fetch('/get-reference', {
method: "POST",
header: {
headers: {
"Content-Type": "application/json"
},
body: JSON.stringify({
@@ -66,7 +70,7 @@ export function saveReference() {
let cont = document.querySelector('#reference');
fetch('/save-reference', {
method: 'POST',
header: {
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({
@@ -76,10 +80,213 @@ export function saveReference() {
})
.then(response => response.json())
.then(results => {
//alert(results.msg);
document.querySelector('#reference').value = '';
document.querySelector('#referenceType').value = '';
document.querySelector('#referenceSeries').value = '';
});
}
/**
* Retrieves the list of books based on the selected reference type.
*
* @return {void}
*/
export function retrieveBooks() {
document.querySelector('#chapter-range').innerText = '';
document.querySelector('#verse-range').innerText = '';
document.querySelector('#referenceSearch').value = '';
document.querySelector('#referenceSearch').style.display = 'none';
const selectedType = document.querySelector('#referenceType').value;
if (!selectedType) { return; }
var bookList = document.querySelector('#referenceBook');
bookList.style.display = "block";
bookList.innerHTML = '';
if (selectedType == 'bible') {
document.querySelector('#referenceSearch').style.display = 'block';
var none = document.createElement("option");
none.value = '';
none.text = '-- Select --';
bookList.appendChild(none);
for (var x in state.BOOKS.bible) {
var newBook = document.createElement("option");
newBook.text = x;
bookList.appendChild(newBook);
}
} else if (selectedType == 'creed') {
var none = document.createElement('option');
none.value = '';
none.text = '-- Select --';
bookList.appendChild(none);
for (var x in state.BOOKS.creed) {
var newBook = document.createElement('option');
newBook.value = x;
newBook.text = state.BOOKS.creed[x];
bookList.appendChild(newBook);
}
} else if (selectedType == 'cd') {
var none = document.createElement("option");
none.value = '';
none.text = '-- Select --';
bookList.appendChild(none);
for (var x in state.BOOKS.cd) {
var newBook = document.createElement("option");
newBook.text = state.BOOKS.cd[x];
bookList.appendChild(newBook);
}
} else if (selectedType == 'hc') {
var none = document.createElement("option");
none.value = '';
none.text = '-- Select --';
bookList.appendChild(none);
for (var x in state.BOOKS[selectedType]) {
var newBook = document.createElement("optgroup");
newBook.label = "Lord's Day " + (parseInt(x) + 1)
var ld = document.createElement("option");
ld.value = 'ld' + (parseInt(x) + 1);
ld.text = "LD " + (parseInt(x) + 1) + " All";
newBook.appendChild(ld);
for (var y in state.BOOKS[selectedType][x]) {
var question = document.createElement("option");
question.value = 'hc' + state.BOOKS[selectedType][x][y];
question.text = "HC" + state.BOOKS[selectedType][x][y];
newBook.appendChild(question);
}
bookList.appendChild(newBook);
}
} else if (selectedType == 'note') {
var none = document.createElement("option");
none.value = '';
none.text = '-- Select --';
bookList.appendChild(none);
fetch('/retrieve-reference', {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({
'type': 'note'
})
})
.then(response => response.json())
.then(results => {
for (var x in results) {
var newBook = document.createElement("option");
newBook.value = results[x].id;
newBook.text = results[x].title;
bookList.appendChild(newBook);
}
});
} else {
var min = state.BOOKS[selectedType][0];
var max = state.BOOKS[selectedType][1];
var none = document.createElement("option");
none.value = '';
none.text = '-- Select --';
bookList.appendChild(none);
for (var x = min; x <= max; x++) {
var newBook = document.createElement("option");
newBook.value = x;
newBook.text = x;
bookList.appendChild(newBook);
}
}
}
/**
* Filters the books based on the selected reference type and updates the chapter range.
*
* @return {void} This function does not return anything.
*/
export function filterBooks() {
document.querySelector('#chapter-range').innerText = '';
document.querySelector('#verse-range').innerText = '';
if (document.querySelector('#referenceType').value != 'bible') {
return;
}
var bookList = document.querySelector('#referenceBook');
var book = state.BOOKS.bible[bookList.value];
var max = Object.keys(book).length;
var chapterRange = document.querySelector('#chapter-range');
chapterRange.innerText = 'Chapters: ' + max;
}
/**
* Filters the verse based on the selected book and chapter.
*
* @return {void} This function does not return anything.
*/
export function filterVerse() {
if (document.querySelector('#referenceType').value != 'bible') {
return;
}
var bookList = document.querySelector('#referenceBook').value;
var search = document.querySelector('#referenceSearch').value;
var chapter = search.split(':')[0];
var verseRange = document.querySelector('#verse-range');
if (!state.BOOKS.bible[bookList] || !state.BOOKS.bible[bookList][chapter]) {
verseRange.innerText = 'Unknown Chapter';
return;
}
var verse = state.BOOKS.bible[bookList][chapter];
verseRange.innerText = 'Verse: ' + verse;
}
/**
* Fetches a reference based on the provided type, book, and input.
*
* @param {string} type - The type of reference.
* @param {string} book - The book of the reference.
* @param {string} input - The input for the reference.
* @return {void} This function does not return anything directly, but processes the fetched reference data.
*/
export function queryRef(e, type = null, book = null, input = null) {
if (!input) {
var input = document.querySelector('#refQuery #referenceSearch').value;
}
if (!type) {
var type = document.querySelector('#referenceType').value;
}
if (!book) {
var book = document.querySelector('#referenceBook').value;
}
fetch('/retrieve-reference', {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({
'type': type,
'book': book,
'reference': input,
})
})
.then(response => response.json())
.then(results => {
const list = document.querySelector('#ref-list');
var newList = document.createElement('li');
newList.className = 'tab';
let button = makeButton(results.title);
newList.appendChild(button);
list.appendChild(newList);
const ref = document.querySelector('#ref-text');
ref.innerHTML = state.md.render(results.text);
state.references[results.title] = results.text;
closeRef();
state.saved = false;
state.textDirty = true;
saveNote();
findRefLinks();
});
}
+1 -3
View File
@@ -10,15 +10,13 @@ registerBtn.addEventListener("click", handleSubmit);
// Function to handle form submission
function handleSubmit(event) {
// Prevent default form submission behavior
event.preventDefault();
// Validate input
const name = nameInput.value;
const email = emailInput.value;
const password = passwordInput.value;
if (name === "" || email === "" || password === "") {
event.preventDefault();
alert("Please fill in all fields.");
return;
}
+54
View File
@@ -0,0 +1,54 @@
import { state } from './state.js';
/**
* A description of the entire function.
*/
export function newSeries() {
if (document.querySelector('#series').value == 'new') {
document.querySelector('#newSeries').style.display = 'inline-block';
document.querySelector('#series').style.display = 'none';
}
state.saved = false;
state.textDirty = true;
}
/**
* Saves a series by making a POST request to '/save-series' with the series name as the request body.
*
* @param {Event} event - The keydown event.
* @return {Promise} A Promise that resolves with the response from the server.
*/
export function saveSeries(event) {
if (event.keyCode == 27) {
document.querySelector('#newSeries').style.display = 'none';
document.querySelector('#series').style.display = 'inline-block';
document.querySelector('#series').value = 0;
}
if (event.keyCode == 13 && document.querySelector('#newSeries').value != '') {
fetch('/save-series', {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({
'seriesName': document.querySelector('#newSeries').value
})
})
.then(response => response.json())
.then(results => {
var newSeries = document.createElement('option');
newSeries.text = document.querySelector('#newSeries').value;
newSeries.value = results.id;
document.querySelector('#series').add(newSeries);
alert(results.msg);
document.querySelector('#newSeries').style.display = 'none';
document.querySelector('#series').style.display = 'inline-block';
document.querySelector('#newSeries').value = '';
document.querySelector('#series').value = results.id;
});
}
}
+54
View File
@@ -0,0 +1,54 @@
import { state } from './state.js';
/**
* Toggles the display of the new speaker input field and hides the speaker select field.
*
* @return {void} This function does not return anything.
*/
export function newSpeaker() {
if (document.querySelector('#speaker').value == 'new') {
document.querySelector('#newSpeaker').style.display = 'inline-block';
document.querySelector('#speaker').style.display = 'none';
}
state.saved = false;
state.textDirty = true;
}
/**
* Saves a new speaker to the database and updates the UI with the new speaker option.
*
* @param {Event} event - The keydown event triggered by the user.
* @return {Promise} A Promise that resolves with the results of the fetch request.
*/
export function saveSpeaker(event) {
if (event.keyCode == 27) {
document.querySelector('#newSpeaker').style.display = 'none';
document.querySelector('#speaker').style.display = 'inline-block';
document.querySelector('#speaker').value = 0;
}
if (event.keyCode == 13 && document.querySelector('#newSpeaker').value != '') {
fetch('/save-speaker', {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({
'speakerName': document.querySelector('#newSpeaker').value
})
})
.then(response => response.json())
.then(results => {
var newSpeaker = document.createElement('option');
newSpeaker.text = document.querySelector('#newSpeaker').value;
newSpeaker.value = results.id;
document.querySelector('#speaker').add(newSpeaker);
alert(results.msg);
document.querySelector('#newSpeaker').style.display = 'none';
document.querySelector('#speaker').style.display = 'inline-block';
document.querySelector('#newSpeaker').value = '';
document.querySelector('#speaker').value = results.id;
});
}
}
+11
View File
@@ -0,0 +1,11 @@
export let state = {
textDirty: false,
saved: true,
references: {},
saveTimeout: null,
saveInterval: 5000,
saveFailureCount: 0,
to: null,
BOOKS: {},
md: null,
}
+3
View File
@@ -1,3 +1,5 @@
import { state } from "./state.js";
/**
* Retrieves a template from the server and sets it as the value of a specified destination element.
*
@@ -24,6 +26,7 @@ export function retrieveTemplate(orig, dest) {
.then(results => {
const div = document.querySelector('#' + dest);
div.value = results;
state.textDirty = true;
});
}