[READ-ONLY] Mirror of https://github.com/probablykasper/taskler. Simple text editor for your New Tab page taskler.kasper.space
browser-extension chrome chrome-extension editor extension firefox firefox-addon firefox-extension notes
0

Configure Feed

Select the types of activity you want to include in your feed.

Move to TypeScript

Kasper (Sep 26, 2022, 12:08 AM +0200) e10d1cb7 909bce3a

+85 -39
+84 -38
src/index.js src/index.ts
··· 1 + type InitLocalStorageOptions<T> = { 2 + key: string; 3 + defaultValue: T; 4 + onUpdate: (value: T) => void; 5 + } 6 + type LocalStorageHandle<T> = { 7 + get: () => T; 8 + set: (value: T) => LocalStorageHandle<T>; 9 + update: () => LocalStorageHandle<T>; 10 + } 1 11 // localStorage wrapper 2 - function initLocalStorage (options) { 12 + function initLocalStorage<T>(options: InitLocalStorageOptions<T>) { 13 + const handle: LocalStorageHandle<T> = { 14 + get() { 15 + const item = localStorage.getItem(options.key) 16 + if (item === null) { 17 + return JSON.parse(JSON.stringify(options.defaultValue)) 18 + } else { 19 + return JSON.parse(item) 20 + } 21 + }, 22 + set(value) { 23 + setItem(value) 24 + return handle 25 + }, 26 + update() { 27 + if (options.onUpdate) options.onUpdate(getItem()) 28 + return handle 29 + } 30 + } 3 31 function getItem () { 4 - return JSON.parse(localStorage.getItem(options.key)) 32 + const value = localStorage.getItem(options.key) 33 + return value === null ? null : JSON.parse(value) 5 34 } 6 - function setItem (value) { 35 + function setItem (value: any) { 7 36 localStorage.setItem(options.key, JSON.stringify(value)) 8 37 } 9 - if (localStorage.getItem(options.key) === null) { 10 - setItem(options.defaultValue) // set default 11 - } 12 - if (options.onUpdate) options.onUpdate(getItem()) // set value on pageload 13 - options.get = getItem 14 - options.set = (value) => { 15 - setItem(value) 16 - return options 17 - } 18 - options.update = () => { 19 - if (options.onUpdate) options.onUpdate(getItem()) 20 - return options 21 - } 38 + if (options.onUpdate) options.onUpdate(handle.get()) // set value on pageload 22 39 // detect updates from other tabs 23 40 window.addEventListener('storage', (event) => { 24 41 console.log('stor', event) 25 42 if (event.key === options.key && options.onUpdate) options.onUpdate(getItem()) 26 43 }, false) 27 - return options 44 + return handle 28 45 } 29 46 30 47 // migrate from quill-delta to quill-state ··· 34 51 localStorage.removeItem('quill-delta') 35 52 } 36 53 37 - let autoList 54 + let autoList: boolean 38 55 const autoListCheckbox = document.querySelector('#auto-list-checkbox') 39 - const autoListSetting = initLocalStorage({ 56 + if (!(autoListCheckbox instanceof HTMLInputElement)) throw alert('autoListCheckbox not found') 57 + const autoListSetting = initLocalStorage<boolean>({ 40 58 key: 'auto-list', 41 59 defaultValue: false, 42 60 onUpdate: (newAutoListSetting) => { ··· 59 77 Quill.register('modules/magicUrl', MagicUrl) 60 78 61 79 import Delta from 'quill-delta'; 62 - window.quill = new Quill(document.querySelector('#note'), { 80 + 81 + type HistoryModule = { 82 + clear: () => void; 83 + undo: () => void; 84 + redo: () => void; 85 + stack: { 86 + undo: Delta[], 87 + redo: Delta[], 88 + }; 89 + } 90 + /** Add missing quill module types */ 91 + interface QuillInstance extends Quill { 92 + history: HistoryModule; 93 + } 94 + 95 + const noteElement = document.querySelector('#note') 96 + if (!(noteElement instanceof HTMLElement)) throw alert('noteElement not found') 97 + const quill: QuillInstance = new Quill(noteElement, { 63 98 modules: { 64 99 toolbar: [ 65 100 [{header: [1, 2, false]}], ··· 130 165 // formats: ['header'], 131 166 theme: 'snow', 132 167 placeholder: 'Maybe I\'ll have a todo list here?' 133 - }) 168 + }) as QuillInstance 134 169 135 - const quillState = initLocalStorage({ 170 + type QuillState = { 171 + delta: Delta, 172 + historyStack: HistoryModule['stack'], 173 + } 174 + const quillState = initLocalStorage<QuillState>({ 136 175 key: 'quill-state', 137 176 defaultValue: { delta: {ops: []}, historyStack: { undo: [], redo: []} }, 138 177 onUpdate: (quillState) => { ··· 140 179 quill.history.clear() 141 180 const stack = quillState.historyStack 142 181 for (let i = 0; i < stack.undo.length; i++) { 143 - const ob = {} 144 - ob.redo = new Delta(stack.undo[i].redo.ops) 145 - ob.undo = new Delta(stack.undo[i].undo.ops) 182 + const ob = { 183 + redo: new Delta(stack.undo[i].redo.ops), 184 + undo: new Delta(stack.undo[i].undo.ops), 185 + } 146 186 quill.history.stack.undo.push(ob) 147 187 } 148 188 for (let i = 0; i < stack.redo.length; i++) { 149 - const ob = {} 150 - ob.redo = new Delta(stack.redo[i].redo.ops) 151 - ob.undo = new Delta(stack.redo[i].undo.ops) 189 + const ob = { 190 + redo: new Delta(stack.redo[i].redo.ops), 191 + undo: new Delta(stack.redo[i].undo.ops), 192 + } 152 193 quill.history.stack.redo.push(ob) 153 194 } 154 195 } ··· 162 203 }) 163 204 164 205 // extension icons 165 - const body = document.querySelector('body') 166 206 const isBrowser = location.protocol === 'https:' || location.protocol === 'http:' 167 207 if (isBrowser) { 168 208 // browser version check: 169 209 // https://stackoverflow.com/questions/9847580/how-to-detect-safari-chrome-ie-firefox-and-opera-browser/9851769 170 210 171 211 // Firefox 1+ 172 - const isFirefox = typeof InstallTrigger !== 'undefined' 212 + const isFirefox = typeof window['InstallTrigger'] !== 'undefined' 173 213 // Chrome 1+ and other Chromium-based browsers 174 - const isChromium = !!window.chrome 214 + const isChromium = !!window['chrome'] 175 215 176 216 if (isFirefox) { 177 - document.getElementById('firefox-extension-icon').classList.add('visible') 217 + document.getElementById('firefox-extension-icon')?.classList.add('visible') 178 218 } else if (isChromium) { 179 - document.getElementById('chrome-extension-icon').classList.add('visible') 219 + document.getElementById('chrome-extension-icon')?.classList.add('visible') 180 220 } 181 221 } 182 222 183 223 /** There's also initial theme setup in index.pug */ 184 224 function themeHandling() { 185 225 const darkModeCheckbox = document.querySelector('#dark-mode-checkbox') 226 + if (!(darkModeCheckbox instanceof HTMLInputElement)) throw alert('darkModeCheckbox not found') 186 227 // Get the systemTheme using window.matchMedia 187 228 const prefersDarkMQ = matchMedia('(prefers-color-scheme: dark)') 188 229 let systemTheme = prefersDarkMQ.matches ? 'dark' : 'light' ··· 191 232 systemTheme = e.matches ? 'dark' : 'light' 192 233 // Update the theme, as long as there's no theme override 193 234 if (localStorage.getItem('theme') === null) { 194 - window.setTheme(systemTheme) 235 + setTheme(systemTheme) 195 236 } 196 237 } 197 238 ··· 216 257 themeHandling() 217 258 218 259 const toolbarCheckbox = document.querySelector('#toolbar-checkbox') 219 - const toolbar = document.querySelector('.ql-toolbar') 260 + if (!(toolbarCheckbox instanceof HTMLInputElement)) throw alert('toolbarCheckbox not found') 220 261 const toolbarSetting = initLocalStorage({ 221 262 key: 'toolbar', 222 263 defaultValue: false, 223 264 onUpdate: (newToolbarSetting) => { 224 - if (newToolbarSetting === true) { 265 + const toolbar = document.querySelector('.ql-toolbar') 266 + if (!toolbar) { 267 + throw alert('Toolbar element not found') 268 + } else if (newToolbarSetting === true) { 225 269 toolbar.classList.add('visible') 226 270 if (toolbarCheckbox.checked === false) toolbarCheckbox.checked = true 227 271 } else { ··· 237 281 238 282 // settingsDialog 239 283 const settingsIcon = document.querySelector('.settings') 284 + if (!settingsIcon) throw alert('Settings icon not found') 240 285 const dialog = document.querySelector('.settings-dialog') 286 + if (!dialog) throw alert('Dialog not found') 241 287 settingsIcon.addEventListener('click', () => { 242 288 dialog.classList.add('visible') 243 289 }) 244 290 245 291 document.addEventListener('click', function (e) { 246 - if (e.target.classList.contains('dialog-container')) { 292 + if (e.target instanceof HTMLElement && e.target.classList.contains('dialog-container')) { 247 293 var dialog = e.target 248 294 dialog.classList.remove('visible') 249 295 } ··· 251 297 252 298 // enable transitions 253 299 window.addEventListener('load', () => { 254 - body.classList.remove('no-transition') 300 + document.body.classList.remove('no-transition') 255 301 })
+1 -1
src/index.pug
··· 59 59 <svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" d="M0 0h24v24H0V0z"/><path d="M9 16.17L4.83 12l-1.42 1.41L9 19 21 7l-1.41-1.41L9 16.17z"/></svg> 60 60 label(for='auto-list-checkbox') 61 61 p Automatically create lists 62 - script(type='module' src='index.js') 62 + script(type='module' src='index.ts') 63 63