diff --git a/public/javascripts/context_menu.js b/public/javascripts/context_menu.js index 66bb37d86..18d596c3d 100644 --- a/public/javascripts/context_menu.js +++ b/public/javascripts/context_menu.js @@ -3,24 +3,51 @@ const contextMenu = (function() { const treeEl = $("#tree"); + let clipboardId = null; + let clipboardMode = null; + function pasteAfter(node) { - const subjectNode = treeUtils.getNodeByNoteTreeId(noteTree.getClipboardNoteTreeId()); + if (clipboardMode === 'cut') { + const subjectNode = treeUtils.getNodeByNoteTreeId(clipboardId); - treeChanges.moveAfterNode(subjectNode, node); + treeChanges.moveAfterNode(subjectNode, node); + } + else if (clipboardMode === 'copy') { + treeChanges.cloneNoteAfter(clipboardId, node.data.note_tree_id); + } + else { + throw new Error("Unrecognized clipboard mode=" + mode); + } - noteTree.setClipboardNoteTreeId(null); + clipboardId = null; + clipboardMode = null; } function pasteInto(node) { - const subjectNode = treeUtils.getNodeByNoteTreeId(noteTree.getClipboardNoteTreeId()); + if (clipboardMode === 'cut') { + const subjectNode = treeUtils.getNodeByNoteTreeId(clipboardId); - treeChanges.moveToNode(subjectNode, node); + treeChanges.moveToNode(subjectNode, node); + } + else if (clipboardMode === 'copy') { + treeChanges.cloneNoteTo(clipboardId, node.data.note_id); + } + else { + throw new Error("Unrecognized clipboard mode=" + mode); + } - noteTree.setClipboardNoteTreeId(null); + clipboardId = null; + clipboardMode = null; + } + + function copy(node) { + clipboardId = node.data.note_id; + clipboardMode = 'copy'; } function cut(node) { - noteTree.setClipboardNoteTreeId(node.note_tree_id); + clipboardId = node.data.note_tree_id; + clipboardMode = 'cut'; } const contextMenuSettings = { @@ -42,8 +69,8 @@ const contextMenu = (function() { beforeOpen: (event, ui) => { const node = $.ui.fancytree.getNode(ui.target); // Modify menu entries depending on node status - treeEl.contextmenu("enableEntry", "pasteAfter", noteTree.getClipboardNoteTreeId() !== null); - treeEl.contextmenu("enableEntry", "pasteInto", noteTree.getClipboardNoteTreeId() !== null); + treeEl.contextmenu("enableEntry", "pasteAfter", clipboardId !== null); + treeEl.contextmenu("enableEntry", "pasteInto", clipboardId !== null); // Activate node on right-click node.setActive(); @@ -56,13 +83,13 @@ const contextMenu = (function() { const node = $.ui.fancytree.getNode(ui.target); if (ui.cmd === "insertNoteHere") { - const parentNoteTreeId = treeUtils.getParentNoteTreeId(node); + const parentNoteId = node.data.note_pid; const isProtected = treeUtils.getParentProtectedStatus(node); - noteEditor.createNote(node, parentNoteTreeId, 'after', isProtected); + noteTree.createNote(node, parentNoteId, 'after', isProtected); } else if (ui.cmd === "insertChildNote") { - noteEditor.createNote(node, node.data.note_id, 'into'); + noteTree.createNote(node, node.data.note_id, 'into'); } else if (ui.cmd === "protectSubTree") { protected_session.protectSubTree(node.data.note_id, true); @@ -70,6 +97,9 @@ const contextMenu = (function() { else if (ui.cmd === "unprotectSubTree") { protected_session.protectSubTree(node.data.note_id, false); } + else if (ui.cmd === "copy") { + copy(node); + } else if (ui.cmd === "cut") { cut(node); } diff --git a/public/javascripts/dialogs/jump_to_note.js b/public/javascripts/dialogs/jump_to_note.js index 0792d5229..ccdb36839 100644 --- a/public/javascripts/dialogs/jump_to_note.js +++ b/public/javascripts/dialogs/jump_to_note.js @@ -29,6 +29,11 @@ const jumpToNote = (function() { return link.getNodePathFromLabel(val); } + function getSelectedNoteId() { + const notePath = getSelectedNotePath(); + return treeUtils.getNoteIdFromNotePath(notePath); + } + function goToNote() { const notePath = getSelectedNotePath(); @@ -63,12 +68,12 @@ const jumpToNote = (function() { } } else if (action === 'add-current-as-child') { - treeUtils.addAsChild(getSelectedNotePath(), noteTree.getCurrentNotePath()); + treeChanges.cloneNoteTo(noteTree.getCurrentNoteId(), getSelectedNoteId()); dialogEl.dialog("close"); } else if (action === 'add-selected-as-child') { - treeUtils.addAsChild(noteTree.getCurrentNotePath(), getSelectedNotePath()); + treeChanges.cloneNoteTo(getSelectedNoteId(), noteTree.getCurrentNoteId()); dialogEl.dialog("close"); } diff --git a/public/javascripts/dialogs/recent_notes.js b/public/javascripts/dialogs/recent_notes.js index 8a14dea8a..bf91328eb 100644 --- a/public/javascripts/dialogs/recent_notes.js +++ b/public/javascripts/dialogs/recent_notes.js @@ -79,6 +79,11 @@ const recentNotes = (function() { return selectBoxEl.find("option:selected").val(); } + function getSelectedNoteId() { + const notePath = getSelectedNotePath(); + return treeUtils.getNoteIdFromNotePath(notePath); + } + function setActiveNoteBasedOnRecentNotes() { const notePath = getSelectedNotePath(); @@ -104,13 +109,13 @@ const recentNotes = (function() { } async function addCurrentAsChild() { - await treeUtils.addAsChild(getSelectedNotePath(), noteTree.getCurrentNotePath()); + await treeChanges.cloneNoteTo(noteTree.getCurrentNoteId(), getSelectedNoteId()); dialogEl.dialog("close"); } async function addRecentAsChild() { - await treeUtils.addAsChild(noteTree.getCurrentNotePath(), getSelectedNotePath()); + await treeChanges.cloneNoteTo(getSelectedNoteId(), noteTree.getCurrentNoteId()); dialogEl.dialog("close"); } diff --git a/public/javascripts/note_editor.js b/public/javascripts/note_editor.js index 7834cdf84..47e44b4b7 100644 --- a/public/javascripts/note_editor.js +++ b/public/javascripts/note_editor.js @@ -1,7 +1,6 @@ "use strict"; const noteEditor = (function() { - const treeEl = $("#tree"); const noteTitleEl = $("#note-title"); const noteDetailEl = $('#note-detail'); const protectButton = $("#protect-button"); @@ -113,59 +112,6 @@ const noteEditor = (function() { showMessage("Saved!"); } - function createNewTopLevelNote() { - let rootNode = treeEl.fancytree("getRootNode"); - - createNote(rootNode, "root", "into"); - } - - let newNoteCreated = false; - - async function createNote(node, parentTreeId, target, isProtected) { - // if isProtected isn't available (user didn't enter password yet), then note is created as unencrypted - // but this is quite weird since user doesn't see WHERE the note is being created so it shouldn't occur often - if (!isProtected || !protected_session.isProtectedSessionAvailable()) { - isProtected = false; - } - - const newNoteName = "new note"; - - const result = await $.ajax({ - url: baseApiUrl + 'notes/' + parentTreeId + '/children' , - type: 'POST', - data: JSON.stringify({ - note_title: newNoteName, - target: target, - target_note_id: node.note_tree_id, - is_protected: isProtected - }), - contentType: "application/json" - }); - - const newNode = { - title: newNoteName, - key: counter++, - note_id: result.note_id, - note_tree_id: result.note_tree_id, - is_protected: isProtected, - extraClasses: isProtected ? "protected" : "" - }; - - newNoteCreated = true; - - if (target === 'after') { - node.appendSibling(newNode).setActive(true); - } - else { - node.addChildren(newNode).setActive(true); - - node.folder = true; - node.renderTitle(); - } - - showMessage("Created!"); - } - function setNoteBackgroundIfProtected(note) { if (note.detail.is_protected) { $(".note-editable").addClass("protected"); @@ -184,8 +130,8 @@ const noteEditor = (function() { async function loadNoteToEditor(noteId) { currentNote = await $.get(baseApiUrl + 'notes/' + noteId); - if (newNoteCreated) { - newNoteCreated = false; + if (noteTree.isNewNoteCreated()) { + noteTree.switchOffNewNoteCreated(); noteTitleEl.focus().select(); } @@ -249,8 +195,6 @@ const noteEditor = (function() { saveNoteIfChanged, updateNoteFromInputs, saveNoteToServer, - createNewTopLevelNote, - createNote, setNoteBackgroundIfProtected, loadNote, getCurrentNote, diff --git a/public/javascripts/note_tree.js b/public/javascripts/note_tree.js index 55c50f276..f27730baf 100644 --- a/public/javascripts/note_tree.js +++ b/public/javascripts/note_tree.js @@ -7,7 +7,6 @@ const noteTree = (function() { let startNoteTreeId = null; let treeLoadTime = null; - let clipboardNoteTreeId = null; let notesMap = {}; let parentToChildren = {}; let childToParents = {}; @@ -30,14 +29,6 @@ const noteTree = (function() { return treeLoadTime; } - function getClipboardNoteTreeId() { - return clipboardNoteTreeId; - } - - function setClipboardNoteTreeId(cbNoteId) { - clipboardNoteTreeId = cbNoteId; - } - function getNoteTreeId(parentNoteId, childNoteId) { const key = parentNoteId + "-" + childNoteId; @@ -107,41 +98,46 @@ const noteTree = (function() { for (const childNoteId of childNoteIds) { const noteTreeId = getNoteTreeId(parentNoteId, childNoteId); const note = notesMap[noteTreeId]; + const node = {}; - note.title = noteIdToTitle[note.note_id]; + node.note_id = note.note_id; + node.note_pid = note.note_pid; + node.note_tree_id = note.note_tree_id; + node.is_protected = note.is_protected; + node.title = noteIdToTitle[note.note_id]; - note.extraClasses = ""; + node.extraClasses = ""; - if (note.is_protected) { - note.extraClasses += ",protected"; + if (node.is_protected) { + node.extraClasses += ",protected"; } if (childToParents[childNoteId].length > 1) { - note.extraClasses += ",multiple-parents"; + node.extraClasses += ",multiple-parents"; } - if (note.extraClasses.startsWith(",")) { - note.extraClasses = note.extraClasses.substr(1); + if (node.extraClasses.startsWith(",")) { + node.extraClasses = node.extraClasses.substr(1); } - note.key = counter++ + ""; // key needs to be string - note.refKey = note.note_id; - note.expanded = note.is_expanded; + node.key = counter++ + ""; // key needs to be string + node.refKey = note.note_id; + node.expanded = note.is_expanded; - noteTreeIdToKey[noteTreeId] = note.key; + noteTreeIdToKey[noteTreeId] = node.key; if (parentToChildren[note.note_id] && parentToChildren[note.note_id].length > 0) { - note.folder = true; + node.folder = true; - if (note.expanded) { - note.children = prepareNoteTreeInner(note.note_id); + if (node.expanded) { + node.children = prepareNoteTreeInner(note.note_id); } else { - note.lazy = true; + node.lazy = true; } } - noteList.push(note); + noteList.push(node); } return noteList; @@ -211,6 +207,10 @@ const noteTree = (function() { function showParentList(noteId, node) { const parents = childToParents[noteId]; + if (!parents) { + throw new Error("Can't find parents for noteId=" + noteId); + } + if (parents.length <= 1) { parentListEl.hide(); } @@ -284,15 +284,17 @@ const noteTree = (function() { } function initFancyTree(noteTree) { + console.log(noteTree); + const keybindings = { "insert": node => { - const parentNoteTreeId = treeUtils.getParentNoteTreeId(node); + const parentNoteId = node.data.note_pid; const isProtected = treeUtils.getParentProtectedStatus(node); - noteEditor.createNote(node, parentNoteTreeId, 'after', isProtected); + createNote(node, parentNoteId, 'after', isProtected); }, "ctrl+insert": node => { - noteEditor.createNote(node, node.note_id, 'into', node.data.is_protected); + createNote(node, node.data.note_id, 'into', node.data.is_protected); }, "del": node => { treeChanges.deleteNode(node); @@ -498,10 +500,6 @@ const noteTree = (function() { tree.clearFilter(); } - function getByNoteTreeId(noteTreeId) { - return notesMap[noteTreeId]; - } - // note that if you want to access data like note_id or is_protected, you need to go into "data" property function getCurrentNode() { return treeEl.fancytree("getActiveNode"); @@ -587,6 +585,74 @@ const noteTree = (function() { } } + function createNewTopLevelNote() { + let rootNode = treeEl.fancytree("getRootNode"); + + createNote(rootNode, "root", "into"); + } + + let newNoteCreated = false; + + function isNewNoteCreated() { + return newNoteCreated; + } + + function switchOffNewNoteCreated() { + newNoteCreated = false; + } + + async function createNote(node, parentNoteId, target, isProtected) { + // if isProtected isn't available (user didn't enter password yet), then note is created as unencrypted + // but this is quite weird since user doesn't see WHERE the note is being created so it shouldn't occur often + if (!isProtected || !protected_session.isProtectedSessionAvailable()) { + isProtected = false; + } + + const newNoteName = "new note"; + + const result = await $.ajax({ + url: baseApiUrl + 'notes/' + parentNoteId + '/children' , + type: 'POST', + data: JSON.stringify({ + note_title: newNoteName, + target: target, + target_note_tree_id: node.data.note_tree_id, + is_protected: isProtected + }), + contentType: "application/json" + }); + + const newNode = { + title: newNoteName, + note_id: result.note_id, + note_pid: parentNoteId, + refKey: result.note_id, + note_tree_id: result.note_tree_id, + is_protected: isProtected, + extraClasses: isProtected ? "protected" : "" + }; + + parentToChildren[parentNoteId].push(result.note_id); + parentToChildren[result.note_id] = []; + childToParents[result.note_id] = [ parentNoteId ]; + + noteIdToTitle[result.note_id] = newNoteName; + + newNoteCreated = true; + + if (target === 'after') { + node.appendSibling(newNode).setActive(true); + } + else { + node.addChildren(newNode).setActive(true); + + node.folder = true; + node.renderTitle(); + } + + showMessage("Created!"); + } + $("button#reset-search-button").click(resetSearch); $("input[name=search]").keyup(e => { @@ -613,13 +679,10 @@ const noteTree = (function() { return { getTreeLoadTime, - getClipboardNoteTreeId, - setClipboardNoteTreeId, reload, collapseTree, scrollToCurrentNote, toggleSearch, - getByNoteTreeId, getKeyFromNoteTreeId, getNoteTreeIdFromKey, setCurrentNoteTreeBasedOnProtectedStatus, @@ -630,6 +693,10 @@ const noteTree = (function() { getNoteTitle, setCurrentNotePathToHash, getAutocompleteItems, - setCurrentNoteTitle + setCurrentNoteTitle, + createNewTopLevelNote, + createNote, + isNewNoteCreated, + switchOffNewNoteCreated }; })(); \ No newline at end of file diff --git a/public/javascripts/tree_changes.js b/public/javascripts/tree_changes.js index 84f310841..7cbb1952e 100644 --- a/public/javascripts/tree_changes.js +++ b/public/javascripts/tree_changes.js @@ -25,6 +25,17 @@ const treeChanges = (function() { noteTree.setCurrentNotePathToHash(node); } + // beware that first arg is noteId and second is noteTreeId! + async function cloneNoteAfter(noteId, afterNoteTreeId) { + await $.ajax({ + url: baseApiUrl + 'notes/' + noteId + '/cloneAfter/' + afterNoteTreeId, + type: 'PUT', + error: () => showError("Error cloning note.") + }); + + await noteTree.reload(); + } + async function moveToNode(node, toNode) { await $.ajax({ url: baseApiUrl + 'notes/' + node.data.note_tree_id + '/moveTo/' + toNode.data.note_id, @@ -42,6 +53,16 @@ const treeChanges = (function() { noteTree.setCurrentNotePathToHash(node); } + async function cloneNoteTo(childNoteId, parentNoteId) { + await $.ajax({ + url: baseApiUrl + 'notes/' + childNoteId + '/cloneTo/' + parentNoteId, + type: 'PUT', + error: () => showError("Error cloning note.") + }); + + await noteTree.reload(); + } + async function deleteNode(node) { if (!confirm('Are you sure you want to delete note "' + node.title + '"?')) { return; @@ -97,6 +118,8 @@ const treeChanges = (function() { moveAfterNode, moveToNode, deleteNode, - moveNodeUp + moveNodeUp, + cloneNoteAfter, + cloneNoteTo }; })(); \ No newline at end of file diff --git a/public/javascripts/tree_utils.js b/public/javascripts/tree_utils.js index be29ca346..144e0b260 100644 --- a/public/javascripts/tree_utils.js +++ b/public/javascripts/tree_utils.js @@ -3,10 +3,6 @@ const treeUtils = (function() { const treeEl = $("#tree"); - function getParentNoteTreeId(node) { - return node.note_pid; - } - function getParentProtectedStatus(node) { return node.getParent() === null ? 0 : node.getParent().data.is_protected; } @@ -34,24 +30,6 @@ const treeUtils = (function() { return titlePath.join(" > "); } - function getFullName(noteTreeId) { - let note = noteTree.getByNoteTreeId(noteTreeId); - - if (note === null) { - return "[unknown]"; - } - - const path = []; - - while (note) { - path.push(note.note_title); - - note = noteTree.getByNoteTreeId(note.note_pid); - } - - return path.reverse().join(" > "); - } - function getNotePath(node) { const path = []; @@ -66,28 +44,12 @@ const treeUtils = (function() { return path.reverse().join("/"); } - async function addAsChild(parentNotePath, childNotePath) { - const parentNoteId = treeUtils.getNoteIdFromNotePath(parentNotePath); - const childNoteId = treeUtils.getNoteIdFromNotePath(childNotePath); - - await $.ajax({ - url: baseApiUrl + 'tree/' + parentNoteId + '/addChild/' + childNoteId, - type: 'PUT', - error: () => showError("Error adding child.") - }); - - await noteTree.reload(); - } - return { - getParentNoteTreeId, getParentProtectedStatus, getNodeByKey, getNodeByNoteTreeId, - getFullName, getFullNameForPath, getNotePath, - getNoteIdFromNotePath, - addAsChild + getNoteIdFromNotePath }; })(); \ No newline at end of file diff --git a/routes/api/notes.js b/routes/api/notes.js index cbc437463..a08c564b8 100644 --- a/routes/api/notes.js +++ b/routes/api/notes.js @@ -29,12 +29,12 @@ router.get('/:noteId', auth.checkApiAuth, async (req, res, next) => { }); }); -router.post('/:parentNoteTreeId/children', async (req, res, next) => { - const parentNoteTreeId = req.params.parentNoteTreeId; +router.post('/:parentNoteId/children', async (req, res, next) => { + const parentNoteId = req.params.parentNoteId; const browserId = utils.browserId(req); const note = req.body; - const { noteId, noteTreeId } = await notes.createNewNote(parentNoteTreeId, note, browserId); + const { noteId, noteTreeId } = await notes.createNewNote(parentNoteId, note, browserId); res.send({ 'note_id': noteId, diff --git a/routes/api/notes_move.js b/routes/api/notes_move.js index 7496d1adb..0cffbc8c5 100644 --- a/routes/api/notes_move.js +++ b/routes/api/notes_move.js @@ -86,6 +86,75 @@ router.put('/:noteTreeId/moveAfter/:afterNoteTreeId', async (req, res, next) => } }); +router.put('/:childNoteId/cloneTo/:parentNoteId', auth.checkApiAuth, async (req, res, next) => { + const parentNoteId = req.params.parentNoteId; + const childNoteId = req.params.childNoteId; + + const existing = await sql.getSingleValue('SELECT * FROM notes_tree WHERE note_id = ? AND note_pid = ?', [childNoteId, parentNoteId]); + + if (!existing) { + const maxNotePos = await sql.getSingleValue('SELECT MAX(note_pos) FROM notes_tree WHERE note_pid = ? AND is_deleted = 0', [parentNoteId]); + const newNotePos = maxNotePos === null ? 0 : maxNotePos + 1; + + const noteTreeId = utils.newNoteTreeId(); + + await sql.doInTransaction(async () => { + await sync_table.addNoteTreeSync(noteTreeId); + + await sql.insert("notes_tree", { + 'note_tree_id': noteTreeId, + 'note_id': childNoteId, + 'note_pid': parentNoteId, + 'note_pos': newNotePos, + 'is_expanded': 0, + 'date_modified': utils.nowTimestamp(), + 'is_deleted': 0 + }); + }); + } + else if (existing && existing.is_deleted) { + await sql.execute("UPDATE notes_tree SET is_deleted = 0 WHERE note_tree_id = ?", [existing.note_tree_id]); + } + + res.send({}); +}); + +router.put('/:noteId/cloneAfter/:afterNoteTreeId', async (req, res, next) => { + const noteId = req.params.noteId; + const afterNoteTreeId = req.params.afterNoteTreeId; + + const afterNote = await sql.getSingleResult("SELECT * FROM notes_tree WHERE note_tree_id = ?", [afterNoteTreeId]); + + if (afterNote) { + await sql.doInTransaction(async () => { + // we don't change date_modified so other changes are prioritized in case of conflict + await sql.execute("UPDATE notes_tree SET note_pos = note_pos + 1 WHERE note_pid = ? AND note_pos > ? AND is_deleted = 0", + [afterNote.note_pid, afterNote.note_pos]); + + const noteTreeId = utils.newNoteTreeId(); + + await sql.insert("notes_tree", { + 'note_tree_id': noteTreeId, + 'note_id': noteId, + 'note_pid': afterNote.note_pid, + 'note_pos': afterNote.note_pos + 1, + 'is_expanded': 0, + 'date_modified': utils.nowTimestamp(), + 'is_deleted': 0 + }); + + await sync_table.addNoteTreeSync(noteTreeId); + await sync_table.addNoteReorderingSync(afterNote.note_pid); + await sql.addAudit(audit_category.CHANGE_POSITION, utils.browserId(req), afterNote.note_pid); + }); + + res.send({}); + } + else { + res.status(500).send("After note " + afterNoteTreeId + " doesn't exist."); + } +}); + router.put('/:noteTreeId/expanded/:expanded', async (req, res, next) => { const noteTreeId = req.params.noteTreeId; const expanded = req.params.expanded; diff --git a/routes/api/tree.js b/routes/api/tree.js index bf67962eb..2ab7cabeb 100644 --- a/routes/api/tree.js +++ b/routes/api/tree.js @@ -48,37 +48,4 @@ router.put('/:noteId/protectSubTree/:isProtected', auth.checkApiAuth, async (req res.send({}); }); -router.put('/:parentNoteId/addChild/:childNoteId', auth.checkApiAuth, async (req, res, next) => { - const parentNoteId = req.params.parentNoteId; - const childNoteId = req.params.childNoteId; - - const existing = await sql.getSingleValue('SELECT * FROM notes_tree WHERE note_id = ? AND note_pid = ?', [childNoteId, parentNoteId]); - - if (!existing) { - const maxNotePos = await sql.getSingleValue('SELECT MAX(note_pos) FROM notes_tree WHERE note_pid = ? AND is_deleted = 0', [parentNoteId]); - const newNotePos = maxNotePos === null ? 0 : maxNotePos + 1; - - const noteTreeId = utils.newNoteTreeId(); - - await sql.doInTransaction(async () => { - await sync_table.addNoteTreeSync(noteTreeId); - - await sql.insert("notes_tree", { - 'note_tree_id': noteTreeId, - 'note_id': childNoteId, - 'note_pid': parentNoteId, - 'note_pos': newNotePos, - 'is_expanded': 0, - 'date_modified': utils.nowTimestamp(), - 'is_deleted': 0 - }); - }); - } - else if (existing && existing.is_deleted) { - await sql.execute("UPDATE notes_tree SET is_deleted = 0 WHERE note_tree_id = ?", [existing.note_tree_id]); - } - - res.send({}); -}); - module.exports = router; diff --git a/services/notes.js b/services/notes.js index d5e9a5085..30c193b2e 100644 --- a/services/notes.js +++ b/services/notes.js @@ -18,7 +18,7 @@ async function createNewNote(parentNoteId, note, browserId) { newNotePos = maxNotePos === null ? 0 : maxNotePos + 1; } else if (note.target === 'after') { - const afterNote = await sql.getSingleResult('SELECT note_pos FROM notes_tree WHERE note_id = ?', [note.target_note_id]); + const afterNote = await sql.getSingleResult('SELECT note_pos FROM notes_tree WHERE note_tree_id = ?', [note.target_note_tree_id]); newNotePos = afterNote.note_pos + 1; diff --git a/views/index.ejs b/views/index.ejs index a4af1392a..747b81083 100644 --- a/views/index.ejs +++ b/views/index.ejs @@ -37,7 +37,7 @@