From 1711f92e674b0d079832a66b6849e4dac862bece Mon Sep 17 00:00:00 2001 From: Alex Pankratov Date: Wed, 31 Mar 2021 18:27:33 +0200 Subject: [PATCH] Make use of Storage api --- nullboard.html | 2767 ++++++++++++++++++++++++------------------------ 1 file changed, 1379 insertions(+), 1388 deletions(-) diff --git a/nullboard.html b/nullboard.html index f062cfe..307fbe2 100644 --- a/nullboard.html +++ b/nullboard.html @@ -89,8 +89,15 @@ -moz-user-select: none; } + @keyframes shake { + 33% { margin-left: -5px; } + 66% { margin-left: 5px; } + 100% { margin-left: 0px; } + } + body.ding { - padding-top: 2px; + animation-name: shake; + animation-duration: 200ms; } a { @@ -803,55 +810,55 @@ /* * Dark mode */ - body.dark { + body.theme-dark { background-color: #15171A; color: #d6d6d6; } - .dark .board .head { + .theme-dark .board .head { background: #202224; } /***/ - .dark .board .menu { + .theme-dark .board .menu { background: linear-gradient(to right, #20222400, #202224 10px); } - .dark .board .menu a { + .theme-dark .board .menu a { color: #aaa; } - .dark .board .menu a:hover { + .theme-dark .board .menu a:hover { color: #fc4; } - .dark .board .menu a.warn:hover, - .dark .board .ops a.warn:hover { + .theme-dark .board .menu a.warn:hover, + .theme-dark .board .ops a.warn:hover { color: #fc5555 !important; } - .dark .board .head { + .theme-dark .board .head { color: #eee; } - .dark .board .head .edit::placeholder { + .theme-dark .board .head .edit::placeholder { color: #bf9d21; } /***/ - .dark .board .list { + .theme-dark .board .list { background: #202224; } - .dark .board .note { + .theme-dark .board .note { background: #2B2C2F; background: linear-gradient(#2B2C2F, #27282B); box-shadow: 0 1px 3px #0005; text-shadow: 0 0 4px #0008; } - .dark.reveal .board .head .text a, - .dark.reveal .board .note .text a { + .theme-dark.reveal .board .head .text a, + .theme-dark.reveal .board .note .text a { color: #fc0; } @@ -861,46 +868,46 @@ 100% { color: inherit; } } - .dark .board .head .text a:hover, - .dark .board .note .text a:hover { + .theme-dark .board .head .text a:hover, + .theme-dark .board .note .text a:hover { animation-name: whoomp-dark; } - .dark .board .note.raw { + .theme-dark .board .note.raw { background: transparent; box-shadow: none; } - .dark .board .note.raw .text { + .theme-dark .board .note.raw .text { color: #eee; text-shadow: 0 0 4px #0008; } - .dark .board .note .ops .teaser { + .theme-dark .board .note .ops .teaser { color: #ccc; } - .dark .board .note .ops .bulk { + .theme-dark .board .note .ops .bulk { background: #202224; border-left: 1px solid #111; border-bottom: 1px solid #111; } - .dark .board .note.raw .ops .bulk { + .theme-dark .board .note.raw .ops .bulk { border: none; } - .dark .board .note .ops .bulk a { + .theme-dark .board .note .ops .bulk a { color: #ccc; } - .dark .board .note .ops .bulk a:hover { + .theme-dark .board .note .ops .bulk a:hover { color: #fc2; } - .dark .board .note.dragging, - .dark .board .note.dragging.raw { + .theme-dark .board .note.dragging, + .theme-dark .board .note.dragging.raw { background: #15171A; box-shadow: 0 +1px 0 #000 inset, 0 -1px 0 #000 inset, @@ -908,195 +915,195 @@ -1px 0 0 #000 inset; } - .dark .dragster { + .theme-dark .dragster { box-shadow: 0px 1px 4px #000000; background: #2e3032; } - .dark .dragster a { + .theme-dark .dragster a { color: #d6d6d6; } /***/ - .dark textarea, - .dark input { + .theme-dark textarea, + .theme-dark input { background: #111315; color: #eee; } - .dark .board .head.editing .edit { + .theme-dark .board .head.editing .edit { outline: 1px solid #bc9908; } - .dark .board .note.editing { + .theme-dark .board .note.editing { background: #111315; outline: 1px solid #bc9908; } /***/ - .dark .config, .dark.crowded .config:hover { + .theme-dark .config, .theme-dark.crowded .config:hover { background-color: #15171A; } - .dark .config a { + .theme-dark .config a { color: #ddd; } - .dark .config a:hover { + .theme-dark .config a:hover { color: #fc2; } - .dark .config .bulk div { + .theme-dark .config .bulk div { border-top: 1px solid #fff2; border-bottom: 1px solid #fff2; } - .dark .config .bulk div a.active { + .theme-dark .config .bulk div a.active { color: #fc2; } - .dark .config .bulk a.switch-theme { + .theme-dark .config .bulk a.switch-theme { border-top: 1px solid #fff2; } - .dark .config a.switch-theme i { + .theme-dark .config a.switch-theme i { display: inline; } - .dark .config a.switch-theme b { + .theme-dark .config a.switch-theme b { display: none; } /***/ - .dark .logo a { + .theme-dark .logo a { color: #ccc; } - .dark .logo, .dark.crowded .logo:hover { + .theme-dark .logo, .theme-dark.crowded .logo:hover { background: #15171A; } - .dark .logo a:hover { + .theme-dark .logo a:hover { color: #fc2; } - .dark .logo > a:hover { + .theme-dark .logo > a:hover { color: #fff; } /* * Larger font */ - body.z1, - body.z1 input, - body.z1 textarea { + body.fsize-z1, + body.fsize-z1 input, + body.fsize-z1 textarea { font-size: 15px; } - .z1 .board { + .fsize-z1 .board { min-width: 290px; } - .z1 .board u:before { + .fsize-z1 .board u:before { font-size: 19px; line-height: 12px; } - .z1 .board .head .text { + .fsize-z1 .board .head .text { min-height: 22px; } - .z1 .board .head .text, - .z1 .board .head .edit { + .fsize-z1 .board .head .text, + .fsize-z1 .board .head .edit { font-size: 15px; line-height: 22px; } - .z1 .board .head .edit::placeholder { + .fsize-z1 .board .head .edit::placeholder { font-size: 10px; line-height: 23px; } - .z1 .board .menu { + .fsize-z1 .board .menu { height: 22px; font-size: 13px; line-height: 22px; } - .z1 .board .list { + .fsize-z1 .board .list { width: 290px; } - .z1 .board .note .text, - .z1 .board .note .edit, - .z1 .dragster { + .fsize-z1 .board .note .text, + .fsize-z1 .board .note .edit, + .fsize-z1 .dragster { font-size: 13px; } - .z1 .board .note .text { + .fsize-z1 .board .note .text { min-height: 16px; } - .z1 .board .note.collapsed { + .fsize-z1 .board .note.collapsed { height: 26px; } - .z1 .board .note.collapsed .text { + .fsize-z1 .board .note.collapsed .text { height: 17px; line-height: 25px; } - .z1 .dragster.collapsed { + .fsize-z1 .dragster.collapsed { line-height: 24px; } - .z1 .board .note .ops { + .fsize-z1 .board .note .ops { font-size: 10px; } /***/ - .z1 .logo { + .fsize-z1 .logo { font-size: 13px; line-height: 21px; } - .z1 .logo .bulk a:before { + .fsize-z1 .logo .bulk a:before { width: 13px; } /***/ - .z1 .config { + .fsize-z1 .config { font-size: 13px; line-height: 21px; } - .z1 .config .bulk div a.active:before { + .fsize-z1 .config .bulk div a.active:before { width: 15px; } - .z1 .config a.switch-fsize i { + .fsize-z1 .config a.switch-fsize i { display: inline; } - .z1 .config a.switch-fsize b { + .fsize-z1 .config a.switch-fsize b { display: none; } /***/ - .z1 .overlay .license { + .fsize-z1 .overlay .license { font-size: 14px; line-height: 18px; width: 443px; } - .z1 .overlay .about { + .fsize-z1 .overlay .about { font-size: 12px; line-height: 18px; width: 277px; } - .z1 .overlay .about h1 { + .fsize-z1 .overlay .about h1 { font-size: 17px; width: 277px; } @@ -1210,36 +1217,443 @@ + + + -// function htmlDecode(enc) -// { -// return $('tt .encoder').html(enc).text(); -// } - - function setText($note, text) - { - $note.attr('_text', text); - - text = htmlEncode(text); - hmmm = /\b(https?:\/\/[^\s]+)/mg; - - text = text.replace(hmmm, function(url){ - return '' + url + ''; - }); - - $note.html(text); - } - - function getText($note) - { - return $note.attr('_text'); - } - - /* - * board ops - save/load/parse/peek/nuke/import - */ - function saveBoard() - { - var $board = $('.wrap .board'); - var board = new Board( getText($board.find('> .head .text')) ); - - $board.find('.list').each(function(){ - var $list = $(this); - var l = board.addList( getText($list.find('.head .text')) ); - - $list.find('.note').each(function(){ - var $note = $(this) - var n = l.addNote( getText($note.find('.text')) ); - n.raw = $note.hasClass('raw'); - n.min = $note.hasClass('collapsed'); - }); - }); - - // - var rev_new = document.nb.board.history[0] + 1; - var rev_old = document.nb.board.revision; - - document.nb.board.revision = rev_new; - - board.id = document.nb.board.id; - board.revision = document.nb.board.revision; - - var blob_id = board.id + '.' + board.revision; - - localStorage.setItem('nullboard.board.' + blob_id, JSON.stringify(board)); - localStorage.setItem('nullboard.board.' + board.id, board.revision); - console.log('Saved nullboard.board.' + blob_id + ' of ' + board.title); - - // - trimBoardHistory(rev_old, rev_new, 50); - - updateUndoRedo(); - updateBoardIndex(); - } - - function parseBoard(blob) - { - var board; - - try - { - board = JSON.parse(blob); - } - catch(x) - { - console.log('Malformed JSON'); - return false; - } - - if (typeof board.format === 'undefined') - { - console.log('Board.format is missing'); - return false; - } - - if (board.format != document.nb.dataVersion) - { - console.log('Board.format is wrong', board.format, document.nb.dataVersion); - return false; - } - - if (! board.revision) - { - console.log("Board.revision is missing"); - return false; - } - - return $.extend(new Board, board); - } - - function loadCurrentBoardBlob(board_id) - { - var revision; - - revision = localStorage.getItem('nullboard.board.' + board_id); - if (! revision) - return false; - - return localStorage.getItem('nullboard.board.' + board_id + '.' + revision); - } - - function loadBoard(board_id) - { - var blob; - var board; - - blob = loadCurrentBoardBlob(board_id); - if (! blob) - return false; - - board = parseBoard(blob); - if (! board) - { - alert('Whoops. Error parsing board data.'); - console.log('Whoops, there it is:', blob); - return false; - } - - if (board.id != board_id) - { - alert('Whoops. Malformed board.'); - console.log('Whoops, there it is:', board.id, board_id); - return false; - } - - board.history = loadBoardHistory(board.id); - - return board; - } - - // - function loadBoardHistory(board_id) - { - var re = new RegExp('^nullboard\.board\.' + board_id + '\.(\\d+)$'); - var r = []; - - for (var i=0; i .head .menu .bulk'); - var $menu_b = $b.find('> .head .menu .bulk'); - - var pos_a = $a.offset().left; - var pos_b = $b.offset().left; - - $a.css({ position: 'relative' }); - $b.css({ position: 'relative' }); - - $menu_a.hide(); - $menu_b.hide(); - - $a.animate({ left: (pos_b - pos_a) + 'px' }, 'fast'); - $b.animate({ left: (pos_a - pos_b) + 'px' }, 'fast', function(){ - - if (left) $list.prev().before($list); - else $list.before($list.next()); - - $a.css({ position: '', left: '' }); - $b.css({ position: '', left: '' }); - - $menu_a.css({ display: '' }); - $menu_b.css({ display: '' }); - - saveBoard(); - }); - } - - // - function openBoard(board_id) - { - closeBoard(true); - - document.nb.board = loadBoard(board_id); - - localStorage.setItem('nullboard.last_board', board_id); - - showBoard(true); - } - - function reopenBoard(revision) - { - var board_id = document.nb.board.id; - - var via_menu = $('.wrap .board > .head .menu .bulk').is(':visible'); - - localStorage.setItem('nullboard.board.' + board_id, revision); - openBoard(board_id); - - if (via_menu) - { - var $menu = $('.wrap .board > .head .menu'); - var $teaser = $menu.find('.teaser'); - var $bulk = $menu.find('.bulk'); - - $teaser.hide().delay(100).queue(function(){ $(this).css('display', '').dequeue(); }); - $bulk.show().delay(100).queue(function(){ $(this).css('display', '').dequeue(); }); - } - } - - function closeBoard(quick) - { - var $board = $('.wrap .board'); - - if (quick) - $board.remove(); - else - $board - .animate({ opacity: 0 }, 'fast') - .queue(function(){ $board.remove(); }); - - document.nb.board = null; - localStorage.setItem('nullboard.last_board', null); - - updateUndoRedo(); - updateBoardIndex(); - } - - // - function addBoard() - { - document.nb.board = new Board(''); - document.nb.board.history = [ 0 ]; - - localStorage.setItem('nullboard.last_board', document.nb.board_id); - - showBoard(false); - - $('.wrap .board .head').addClass('brand-new'); - $('.wrap .board .head .text').click(); - } - - function deleteBoard() - { - var $list = $('.wrap .board .list'); - - if ($list.length && ! confirm("PERMANENTLY delete this board, all its lists and their notes?")) - return; - - nukeBoard(); - closeBoard(); - } - - // - function undoBoard() - { - if (! document.nb.board) - return false; - - var hist = document.nb.board.history; - var have = document.nb.board.revision; - var want = 0; - - for (var i=0; i ' + want); - - reopenBoard(want); - return true; - } - - function redoBoard() - { - if (! document.nb.board) - return false; - - var hist = document.nb.board.history; - var have = document.nb.board.revision; - var want = 0; - - for (var i=1; i ' + want); - - reopenBoard(want); - return true; - } - - // - function showBoard(quick) - { - var board = document.nb.board; - - var $wrap = $('.wrap'); - var $bdiv = $('tt .board'); - var $ldiv = $('tt .list'); - var $ndiv = $('tt .note'); - - var $b = $bdiv.clone(); - var $b_lists = $b.find('.lists'); - - $b[0].board_id = board.id; - setText( $b.find('.head .text'), board.title ); - - board.lists.forEach(function(list){ - - var $l = $ldiv.clone(); - var $l_notes = $l.find('.notes'); - - setText( $l.find('.head .text'), list.title ); - - list.notes.forEach(function(n){ - var $n = $ndiv.clone(); - setText( $n.find('.text'), n.text ); - if (n.raw) $n.addClass('raw'); - if (n.min) $n.addClass('collapsed'); - $l_notes.append($n); - }); - - $b_lists.append($l); - }); - - if (quick) - $wrap.html('').append($b); - else - $wrap.html('') - .css({ opacity: 0 }) - .append($b) - .animate({ opacity: 1 }); - - updatePageTitle(); - updateUndoRedo(); - updateBoardIndex(); - setupListScrolling(); - } - - /* - * - */ - function updatePageTitle() - { - if (! document.nb.board) - { - document.title = 'Nullboard'; - return; - } - - var $text = $('.wrap .board > .head .text'); - var title = getText( $text ); - - document.nb.board.title = title; - document.title = 'NB - ' + (title || '(unnamed board)'); - } - - function updateUndoRedo() - { - var $undo = $('.board .menu .undo-board'); - var $redo = $('.board .menu .redo-board'); - - var undo = false; - var redo = false; - - if (document.nb.board) - { - var history = document.nb.board.history; - var rev = document.nb.board.revision; - - undo = (rev != history[history.length-1]); - redo = (rev != history[0]); - } - - if (undo) $undo.show(); else $undo.hide(); - if (redo) $redo.show(); else $redo.hide(); - } - - function updateBoardIndex() - { - var $index = $('.config .boards'); - var $export = $('.config .exp-board'); - var $entry = $('tt .load-board'); - - var $board = $('.wrap .board'); - var id_now = document.nb.board && document.nb.board.id; - var empty = true; - - $index.html(''); - $index.hide(); - - for (var i=0; i$1'); - - // - var c1 = []; - var c2 = []; - - text.substr(qos).trim().split('\n').forEach(function(line){ - line = line.split(':'); - c1.push( line[0].trim() + ':' ); - c2.push( line[1].trim() ); - }); - - bulk += '' + c1.join('
') + '
'; - bulk += '' + c2.join('
') + '
'; - - // - var links = - [ - { text: '2-clause BSD license', href: 'https://opensource.org/licenses/BSD-2-Clause/' }, - { text: 'Commons Clause', href: 'https://commonsclause.com/' } - ]; - - links.forEach(function(l){ - bulk = bulk.replace(l.text, '' + l.text + ''); - }); - - return bulk.trim(); - } - - // - function setRevealState(ev) - { - var raw = ev.originalEvent; - var caps = raw.getModifierState && raw.getModifierState( 'CapsLock' ); - - if (caps) $('body').addClass('reveal'); - else $('body').removeClass('reveal'); - } - - function handleTab(ev) - { - var $this = $(this); - var $note = $this.closest('.note'); - var $sibl = ev.shiftKey ? $note.prev() : $note.next(); - - if ($sibl.length) - { - stopEditing($this, false); - $sibl.find('.text').click(); - } - } - - // - function adjustLayout() - { - var $body = $('body'); - var $board = $('.board'); - - if (! $board.length) - return; - - var lists = $board.find('.list').length; - var lists_w = (lists < 2) ? 250 : 260 * lists - 10; - var body_w = $body.width(); - - if (lists_w + 190 <= body_w) - { - $board.css('max-width', ''); - $body.removeClass('crowded'); - } - else - { - var max = Math.floor( (body_w - 40) / 260 ); - max = (max < 2) ? 250 : 260 * max - 10; - $board.css('max-width', max + 'px'); - $body.addClass('crowded'); - } - } - - // - function adjustListScroller() - { - var $board = $('.board'); - if (! $board.length) - return; - - var $lists = $('.board .lists'); - var $scroller = $('.board .lists-scroller'); - var $inner = $scroller.find('div'); - - var max = $board.width(); - var want = $lists[0].scrollWidth; - var have = $inner.width(); - - if (want <= max) - { - $scroller.hide(); - return; - } - - $scroller.show(); - if (want == have) - return; - - $inner.width(want); - cloneScrollPos($lists, $scroller); - } - - // - function cloneScrollPos($src, $dst) - { - var src = $src[0]; - var dst = $dst[0]; - - if (src._busyScrolling) - { - src._busyScrolling--; - return; - } - - dst._busyScrolling++; - dst.scrollLeft = src.scrollLeft; - } - - function setupListScrolling() - { - var $lists = $('.board .lists'); - var $scroller = $('.board .lists-scroller'); - - adjustListScroller(); - - $lists[0]._busyScrolling = 0; - $scroller[0]._busyScrolling = 0; - - $scroller.on('scroll', function(){ cloneScrollPos($scroller, $lists); }); - $lists .on('scroll', function(){ cloneScrollPos($lists, $scroller); }); - - adjustLayout(); - } - - /* - * this should *really* be in a separate file - */ - function noteLocation($item) - { - var loc = 0; - for (var $p = $item.closest('.note'); $p.length; $p = $p.prev(), loc += 1); - for (var $p = $item.closest('.list'); $p.length; $p = $p.prev(), loc += 10000); - return loc; - } + + + -