mirror of
https://github.com/apankrat/nullboard.git
synced 2025-01-17 20:58:33 +01:00
+ first revision of Storage
This commit is contained in:
parent
b864bee134
commit
b06f970b53
327
nullboard.html
327
nullboard.html
@ -1235,10 +1235,10 @@
|
|||||||
var cb2;
|
var cb2;
|
||||||
alert("Error occurred: " + e.error.message);
|
alert("Error occurred: " + e.error.message);
|
||||||
return false;
|
return false;
|
||||||
})
|
});
|
||||||
|
|
||||||
/*
|
/*
|
||||||
*
|
* data
|
||||||
*/
|
*/
|
||||||
function Note(text)
|
function Note(text)
|
||||||
{
|
{
|
||||||
@ -1284,12 +1284,11 @@
|
|||||||
return $('tt .encoder').text(raw).html();
|
return $('tt .encoder').text(raw).html();
|
||||||
}
|
}
|
||||||
|
|
||||||
function htmlDecode(enc)
|
// function htmlDecode(enc)
|
||||||
{
|
// {
|
||||||
return $('tt .encoder').html(enc).text();
|
// return $('tt .encoder').html(enc).text();
|
||||||
}
|
// }
|
||||||
|
|
||||||
//
|
|
||||||
function setText($note, text)
|
function setText($note, text)
|
||||||
{
|
{
|
||||||
$note.attr('_text', text);
|
$note.attr('_text', text);
|
||||||
@ -2866,6 +2865,320 @@
|
|||||||
|
|
||||||
setupListScrolling();
|
setupListScrolling();
|
||||||
|
|
||||||
|
</script>
|
||||||
|
<script>
|
||||||
|
|
||||||
|
function AppConfig()
|
||||||
|
{
|
||||||
|
this.format = null; // dataVersion
|
||||||
|
this.max_undo = 50; // board revisions to keep
|
||||||
|
this.theme = null; // default or 'dark'
|
||||||
|
this.fsize = null; // default or 'z1'
|
||||||
|
this.board = null; // active board
|
||||||
|
}
|
||||||
|
|
||||||
|
function BoardMeta()
|
||||||
|
{
|
||||||
|
this.title = '';
|
||||||
|
this.current = 1; // revision
|
||||||
|
this.history = []; // revision IDs
|
||||||
|
}
|
||||||
|
|
||||||
|
class Storage
|
||||||
|
{
|
||||||
|
type = '?';
|
||||||
|
|
||||||
|
open()
|
||||||
|
{
|
||||||
|
return this.openInner();
|
||||||
|
}
|
||||||
|
|
||||||
|
wipe()
|
||||||
|
{
|
||||||
|
return this.wipeInner();
|
||||||
|
}
|
||||||
|
|
||||||
|
getConfig()
|
||||||
|
{
|
||||||
|
return this.conf;
|
||||||
|
}
|
||||||
|
|
||||||
|
setConfig(c)
|
||||||
|
{
|
||||||
|
this.conf = c;
|
||||||
|
return this.setJson('config', this.conf);
|
||||||
|
}
|
||||||
|
|
||||||
|
getBoardIndex()
|
||||||
|
{
|
||||||
|
return this.boardIndex;
|
||||||
|
}
|
||||||
|
|
||||||
|
saveBoard(board)
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
* 1. assign new revision (next unused)
|
||||||
|
* 2. trim all in-between revisions bypassed by undos if any
|
||||||
|
* 3. cap history as per config
|
||||||
|
*/
|
||||||
|
var meta = this.boardIndex.get(board.id);
|
||||||
|
var ok = true;
|
||||||
|
|
||||||
|
if (! meta)
|
||||||
|
{
|
||||||
|
meta = new BoardMeta();
|
||||||
|
meta.title = board.title || '(untitled board)';
|
||||||
|
meta.history = [ board.revision ];
|
||||||
|
meta.current = board.revision;
|
||||||
|
|
||||||
|
boardIndex.set(board.id, meta);
|
||||||
|
}
|
||||||
|
|
||||||
|
var rev_old = board.revision;
|
||||||
|
var rev_new = meta.history[0] + 1;
|
||||||
|
|
||||||
|
board.revision = rev_new;
|
||||||
|
ok &= this.setJson('board.' + board.id + '.' + board.revision, board);
|
||||||
|
|
||||||
|
// adjust history
|
||||||
|
|
||||||
|
var keep = [ rev_new ];
|
||||||
|
|
||||||
|
for (rev of meta.history)
|
||||||
|
{
|
||||||
|
if ( (rev_new < rev && rev < rev_old) || (keep.length >= this.conf.max_undo) )
|
||||||
|
this.delItem('board.' + board.id + '.' + rev);
|
||||||
|
else
|
||||||
|
keep.push(rev);
|
||||||
|
}
|
||||||
|
|
||||||
|
meta.current = board.revision;
|
||||||
|
meta.history = keep;
|
||||||
|
|
||||||
|
ok &= this.setJson('board.' + board.id + '.meta', meta);
|
||||||
|
return ok;
|
||||||
|
}
|
||||||
|
|
||||||
|
loadBoard(board_id, revision)
|
||||||
|
{
|
||||||
|
var meta = this.boardIndex.get(board_id);
|
||||||
|
|
||||||
|
if (! meta)
|
||||||
|
throw 'Invalid board_id in loadBoard(' + board.id + ', ' + revision + ')';
|
||||||
|
|
||||||
|
if (! meta.history.includes(revision))
|
||||||
|
throw 'Invalid revision in loadBoard(' + board.id + ', ' + revision + ')';
|
||||||
|
|
||||||
|
return this.getJson('board.' + board_id + '.' + revision);
|
||||||
|
}
|
||||||
|
|
||||||
|
nukeBoard(board_id, revision)
|
||||||
|
{
|
||||||
|
var meta = this.boardIndex.get(board_id);
|
||||||
|
|
||||||
|
if (! meta)
|
||||||
|
throw 'Invalid board_id in nukeBoard(' + board.id + ')';
|
||||||
|
|
||||||
|
if (revision != null)
|
||||||
|
{
|
||||||
|
var i = meta.history.indexOf(revision);
|
||||||
|
if (i == -1)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
meta.history.splice(i, 1);
|
||||||
|
this.setJson('board.' + board_id + '.meta', meta);
|
||||||
|
|
||||||
|
this.delItem('board.' + board_id + '.' + revision);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
for (rev of meta.history)
|
||||||
|
this.delItem('board.' + board_id + '.' + rev);
|
||||||
|
|
||||||
|
this.delItem('board.' + board_id + '.meta');
|
||||||
|
this.boardIndex.delete(board_id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* private
|
||||||
|
*/
|
||||||
|
|
||||||
|
conf = null;
|
||||||
|
boardIndex = new Map();
|
||||||
|
|
||||||
|
getItem(name) { throw 'implement-me'; }
|
||||||
|
setItem(name) { throw 'implement-me'; }
|
||||||
|
delItem(name) { throw 'implement-me'; }
|
||||||
|
|
||||||
|
openInner() { throw 'implement-me'; }
|
||||||
|
wipeInner() { throw 'implement-me'; }
|
||||||
|
|
||||||
|
getJson(name)
|
||||||
|
{
|
||||||
|
var foo = this.getItem(name);
|
||||||
|
if (! foo) return false;
|
||||||
|
|
||||||
|
try { foo = JSON.parse(foo); } catch (x) { return false; }
|
||||||
|
return foo;
|
||||||
|
}
|
||||||
|
|
||||||
|
setJson(name, val)
|
||||||
|
{
|
||||||
|
return this.setItem(name, JSON.stringify(val));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
class Storage_Local extends Storage
|
||||||
|
{
|
||||||
|
getItem(name)
|
||||||
|
{
|
||||||
|
return localStorage.getItem('nullboard.' + name);
|
||||||
|
}
|
||||||
|
|
||||||
|
setItem(name, val)
|
||||||
|
{
|
||||||
|
localStorage.setItem('nullboard.' + name, val);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
delItem(name)
|
||||||
|
{
|
||||||
|
localStorage.removeItem('nullboard.' + name);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
openInner()
|
||||||
|
{
|
||||||
|
var conf = this.getJson('config');
|
||||||
|
|
||||||
|
if (conf)
|
||||||
|
{
|
||||||
|
if (conf.format != document.nb.dataVersion)
|
||||||
|
{
|
||||||
|
alert('Saved data is from a different version of NB');
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.conf = new AppConfig();
|
||||||
|
this.conf = Object.assign(this.conf, conf);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
conf = new AppConfig();
|
||||||
|
|
||||||
|
conf.format = document.nb.dataVersion;
|
||||||
|
conf.theme = this.getItem('theme');
|
||||||
|
conf.fsize = this.getItem('fsize');
|
||||||
|
conf.board = this.getItem('last_board');
|
||||||
|
|
||||||
|
this.setConfig(conf); // set & save it
|
||||||
|
}
|
||||||
|
|
||||||
|
this.boardIndex = new Map();
|
||||||
|
|
||||||
|
for (var i=0; i<localStorage.length; i++)
|
||||||
|
{
|
||||||
|
var k = localStorage.key(i);
|
||||||
|
var m = k.match(/^nullboard\.board\.(\d+)$/);
|
||||||
|
if (! m)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
var board_id = m[1];
|
||||||
|
var meta = this.getJson('board.' + board_id + '.meta');
|
||||||
|
|
||||||
|
meta = meta || this.rebuildMeta(board_id);
|
||||||
|
|
||||||
|
if (! meta)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
meta = Object.assign(new BoardMeta(), meta);
|
||||||
|
this.boardIndex.set(board_id, meta);
|
||||||
|
}
|
||||||
|
|
||||||
|
this.type = 'LocalStorage';
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
wipeInner()
|
||||||
|
{
|
||||||
|
for (var i=0; i<localStorage.length; )
|
||||||
|
{
|
||||||
|
var k = localStorage.key(i);
|
||||||
|
var m = k.match(/^nullboard\./);
|
||||||
|
|
||||||
|
if (m) localStorage.removeItem(k);
|
||||||
|
else i++;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.conf = new AppConfig();
|
||||||
|
this.conf.format = document.nb.dataVersion;
|
||||||
|
|
||||||
|
this.boardIndex = new Map();
|
||||||
|
|
||||||
|
this.type = 'LocalStorage';
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* private
|
||||||
|
*/
|
||||||
|
rebuildMeta(board_id)
|
||||||
|
{
|
||||||
|
var meta = new BoardMeta();
|
||||||
|
|
||||||
|
// get current revision
|
||||||
|
|
||||||
|
meta.current = this.getItem('board.' + board_id);
|
||||||
|
|
||||||
|
// load history
|
||||||
|
|
||||||
|
var re = new RegExp('^nullboard\.board\.' + board_id + '\.(\\d+)$');
|
||||||
|
var revs = new Array();
|
||||||
|
|
||||||
|
for (var i=0; i<localStorage.length; i++)
|
||||||
|
{
|
||||||
|
var m = localStorage.key(i).match(re);
|
||||||
|
if (m) revs.push( parseInt(m[1]) );
|
||||||
|
}
|
||||||
|
|
||||||
|
if (! revs.length)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
revs.sort(function(a,b){ return b-a; });
|
||||||
|
meta.history = revs;
|
||||||
|
|
||||||
|
// validate current revision
|
||||||
|
|
||||||
|
if (! meta.history.includes(meta.current))
|
||||||
|
meta.current = meta.history[meta.history.length-1];
|
||||||
|
|
||||||
|
// get board title
|
||||||
|
|
||||||
|
var board = this.getJson('board.' + board_id + '.' + meta.current)
|
||||||
|
meta.title = (board.title || '(untitled board)');
|
||||||
|
|
||||||
|
this.setJson('board.' + board_id + '.meta', meta);
|
||||||
|
|
||||||
|
return meta;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function _rollback()
|
||||||
|
{
|
||||||
|
localStorage.removeItem('nullboard.config');
|
||||||
|
|
||||||
|
var metas = [];
|
||||||
|
|
||||||
|
for (var i=0; i<localStorage.length; i++)
|
||||||
|
{
|
||||||
|
var m = localStorage.key(i).match(/^nullboard\.board\.(\d+)\.meta$/);
|
||||||
|
if (m) metas.push(m[0]);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (k of metas) localStorage.removeItem(k);
|
||||||
|
}
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
</html>
|
</html>
|
||||||
|
Loading…
x
Reference in New Issue
Block a user