User:AlternateTorg/PersonalNotes/code.js

/* * This script adds a "Personal Notes" editor to the right rail on the page. * Anything written in this editor is stored locally in the user's browser, and * is only visible to that user. */ (function { 'use strict'; var NAMESPACE = '__com_walkertribe_rjw_fandom-personal-notes__'; var COMMUNITY_ID = NAMESPACE + mw.config.get('wgDBname'); var PAGE_NAME = mw.config.get('wgPageName'); var RIGHT_RAIL_SELECTOR = 'aside .right-rail-wrapper'; var TEXTAREA_ID = NAMESPACE + 'textarea'; var DIALOG_ID = NAMESPACE + 'dialog'; var MIN_TEXTAREA_HEIGHT = 100; var AUTO_SAVE_DELAY_MS = 1000;

var timer;

/** * Loads all the notes for this community. The return value is an object where * the notes for each page are keyed under that page's name. * * @returns {Object} - the notes */ function loadNotes { var data = localStorage.getItem(COMMUNITY_ID); return data ? JSON.parse(data) : {}; }

/** * Loads any stored data for this page into the editor. */ function load { document.getElementById(TEXTAREA_ID).value = loadNotes[PAGE_NAME] || ''; }

/** * Stores the contents of the editor into local storage. */ function save { var notes = loadNotes; var value = document.getElementById(TEXTAREA_ID).value;

if (value.length) { notes[PAGE_NAME] = value; } else { delete notes[PAGE_NAME]; }

localStorage.setItem(COMMUNITY_ID, JSON.stringify(notes)); }

/** * Fires when the editor gets focus. Adds the border to the field. */ function onFocus { document.getElementById(TEXTAREA_ID).style.borderColor = 'unset'; }

/** * Fires when the editor loses focus. Saves the contents and removes the border * from the field. */ function onBlur { clearTimeout(timer); save; document.getElementById(TEXTAREA_ID).style.borderColor = 'transparent'; }

/** * Fires when the editor contents change. Auto-adjusts the height of the field, * and sets a timer to save the contents if the user stops typing. */ function onInput { clearTimeout(timer); var editor = document.getElementById(TEXTAREA_ID); editor.style.height = 'auto'; editor.style.height = Math.max(editor.scrollHeight, MIN_TEXTAREA_HEIGHT) + 'px'; timer = setTimeout(save, AUTO_SAVE_DELAY_MS); }

/** * Builds the notes editor. */ function buildEditor(railEl) { var notesDiv = document.createElement('div'); notesDiv.style.marginTop = '24px'; notesDiv.style.borderBottom = '1px solid var(--theme-border-color)'; var h2 = document.createElement('h2'); h2.className = 'rail-module__header'; h2.textContent = 'Personal Notes'; notesDiv.appendChild(h2); var textarea = document.createElement('textarea'); textarea.id = TEXTAREA_ID; textarea.autocomplete = false; textarea.placeholder = 'Whatever you write here is visible only to you.'; textarea.style.display = 'block'; textarea.style.boxSizing = 'border-box'; textarea.style.width = '100%'; textarea.style.resize = 'none'; textarea.style.overflow = 'hidden'; textarea.style.fontFamily = 'inherit'; textarea.style.fontSize = '100%'; textarea.style.backgroundColor = 'transparent'; textarea.style.color = 'var(--theme-page-text-color)'; textarea.style.borderColor = 'transparent'; notesDiv.appendChild(textarea); var buttonDiv = document.createElement('div'); buttonDiv.style.textAlign = 'right'; buttonDiv.style.margin = '3px 0 24px 0'; var button = document.createElement('button'); button.style.border = 'none'; button.style.color = 'var(--theme-page-background-color)'; button.style.backgroundColor = 'var(--theme-accent-color)'; button.style.borderRadius = '6px'; button.style.padding = '3px 12px'; button.style.cursor = 'pointer'; button.textContent = 'View notes list'; button.addEventListener('click', showDialog); buttonDiv.appendChild(button); notesDiv.appendChild(buttonDiv); railEl.insertBefore(notesDiv, railEl.firstChild); load; onInput; textarea.addEventListener('input', onInput); textarea.addEventListener('focus', onFocus); textarea.addEventListener('blur', onBlur); }

function buildDialog { var dialog = document.createElement('dialog'); dialog.id = DIALOG_ID; dialog.style.boxSizing = 'border-box'; dialog.style.position = 'fixed'; dialog.style.height = '50%'; dialog.style.width = '30em'; dialog.style.backgroundColor = 'var(--theme-page-background-color)'; dialog.style.boxShadow = '0 0 3em #000'; dialog.style.border = 'solid var(--theme-accent-color) 3px'; dialog.style.borderRadius = '6px'; dialog.style.padding = '0'; dialog.style.overflow = 'hidden'; var closeButton = document.createElement('div'); closeButton.style.boxSizing = 'border-box'; closeButton.style.width = '2em'; closeButton.style.textAlign = 'center'; closeButton.style.position = 'absolute'; closeButton.style.top = '0'; closeButton.style.right = '0'; closeButton.style.fontSize = '2em'; closeButton.style.color = 'var(--theme-page-text-color)'; closeButton.style.cursor = 'pointer'; closeButton.textContent = '×'; closeButton.addEventListener('click', function { 	dialog.close;  }); dialog.appendChild(closeButton); var h2 = document.createElement('h2'); h2.className = 'mw-headline'; h2.style.height = '2.5em'; h2.style.margin = '0'; h2.style.padding = '12px 24px'; h2.style.color = 'var(--theme-page-text-color)'; h2.textContent = 'Notes List'; dialog.appendChild(h2); var scrollPane = document.createElement('div'); scrollPane.style.height = 'calc(100% - 2.5em)'; scrollPane.style.overflowX = 'hidden'; scrollPane.style.overflowY = 'auto'; scrollPane.style.padding = '12px 24px 48px 48px'; var ul = document.createElement('ul'); ul.style.color = 'var(--theme-page-text-color)'; ul.style.listStyle = 'circle'; scrollPane.appendChild(ul); dialog.appendChild(scrollPane); document.body.appendChild(dialog); }

function showDialog { var ul = document.querySelector('#' + DIALOG_ID + ' ul'); ul.innerHTML = ''; var keys = Array.from(Object.keys(loadNotes)).sort; var li;

for (var i = 0; i < keys.length; i++) { li = document.createElement('li'); var a = document.createElement('a'); var title = keys[i]; a.href = mw.util.getUrl(title); a.target = '_blank'; a.textContent = title.replaceAll('_', ' '); li.appendChild(a); ul.appendChild(li); }

if (!keys.length) { li = document.createElement('li'); var em = document.createElement('em'); em.textContent = 'No notes'; li.appendChild(em); ul.appendChild(li); }

document.getElementById(DIALOG_ID).showModal; }

function init { var railEl = document.querySelector(RIGHT_RAIL_SELECTOR);

if (!railEl) { return; }

buildEditor(railEl); buildDialog; }

init; });