added localDbSvc
This commit is contained in:
parent
f06f872a04
commit
97172e28b3
@ -13,7 +13,9 @@
|
||||
"dependencies": {
|
||||
"bezier-easing": "^1.1.0",
|
||||
"clunderscore": "^1.0.3",
|
||||
"debug": "^2.6.8",
|
||||
"diff-match-patch": "^1.0.0",
|
||||
"indexeddbshim": "^3.0.4",
|
||||
"katex": "^0.7.1",
|
||||
"markdown-it": "^8.3.1",
|
||||
"markdown-it-abbr": "^1.0.4",
|
||||
@ -35,6 +37,7 @@
|
||||
"babel-eslint": "^7.1.1",
|
||||
"babel-loader": "^6.2.10",
|
||||
"babel-plugin-transform-runtime": "^6.22.0",
|
||||
"babel-polyfill": "^6.23.0",
|
||||
"babel-preset-env": "^1.3.2",
|
||||
"babel-preset-stage-2": "^6.22.0",
|
||||
"babel-register": "^6.22.0",
|
||||
|
@ -104,41 +104,4 @@ textarea {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$r: 9px;
|
||||
$d: $r * 2;
|
||||
$t: 1500ms;
|
||||
|
||||
.spinner {
|
||||
width: $d;
|
||||
height: $d;
|
||||
display: block;
|
||||
position: relative;
|
||||
border: $d/10 solid currentColor;
|
||||
border-radius: 50%;
|
||||
|
||||
&::before,
|
||||
&::after {
|
||||
content: "";
|
||||
position: absolute;
|
||||
display: block;
|
||||
width: $d/10;
|
||||
background-color: currentColor;
|
||||
border-radius: ($d/10)/2;
|
||||
transform-origin: 50% 0;
|
||||
}
|
||||
|
||||
&::before {
|
||||
height: $r - $d/5;
|
||||
left: $r - $d/10 - $d/20;
|
||||
top: 50%;
|
||||
animation: spin $t linear infinite;
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes spin {
|
||||
to {
|
||||
transform: rotate(360deg);
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
@ -206,4 +206,42 @@ export default {
|
||||
margin: 10px 5px 0;
|
||||
color: rgba(255, 255, 255, 0.33);
|
||||
}
|
||||
|
||||
$r: 9px;
|
||||
$d: $r * 2;
|
||||
$b: $d/10;
|
||||
$t: 1500ms;
|
||||
|
||||
.spinner {
|
||||
width: $d;
|
||||
height: $d;
|
||||
display: block;
|
||||
position: relative;
|
||||
border: $b solid currentColor;
|
||||
border-radius: 50%;
|
||||
|
||||
&::before,
|
||||
&::after {
|
||||
content: "";
|
||||
position: absolute;
|
||||
display: block;
|
||||
width: $b;
|
||||
background-color: currentColor;
|
||||
border-radius: $b * 0.5;
|
||||
transform-origin: 50% 0;
|
||||
}
|
||||
|
||||
&::before {
|
||||
height: $r * 0.5;
|
||||
left: $r - $b * 1.5;
|
||||
top: 50%;
|
||||
animation: spin $t linear infinite;
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes spin {
|
||||
to {
|
||||
transform: rotate(360deg);
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
@ -1,5 +1,5 @@
|
||||
<template>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" baseProfile="full" class="icon" width="100%" height="100%" viewBox="0 0 24.00 24.00" enable-background="new 0 0 24.00 24.00" xml:space="preserve">
|
||||
<path fill="#000000" fill-opacity="1" stroke-width="0.2" stroke-linejoin="round" d="M13.125,16.5l-3.5,0l0,-3l3.5,0c0.828,0 1.5,0.672 1.5,1.5c0,0.828 -0.672,1.5 -1.5,1.5Zm-3.5,-9l3,0c0.828,0 1.5,0.672 1.5,1.5c0,0.828 -0.672,1.5 -1.5,1.5l-3,0m5.6,1.288c0.966,-0.674 1.65,-1.767 1.65,-2.788c0,-2.255 -1.745,-4 -4,-4l-6.25,0l0,14l7.042,0c2.094,0 3.708,-1.698 3.708,-3.792c0,-1.516 -0.863,-2.814 -2.15,-3.42Z" />
|
||||
<path d="M13.35,17.401l-4.201,0l0,-3.601l4.201,0c0.997,0 1.801,0.805 1.801,1.801c0,0.996 -0.804,1.8 -1.801,1.8m-4.201,-10.802l3.601,0c0.996,0 1.801,0.804 1.801,1.8c0,0.996 -0.805,1.801 -1.801,1.801l-3.601,0m6.722,1.548c1.164,-0.816 1.98,-2.149 1.98,-3.349c0,-2.712 -2.1,-4.801 -4.801,-4.801l-7.502,0l0,16.804l8.45,0c2.521,0 4.454,-2.04 4.454,-4.549c0,-1.825 -1.033,-3.385 -2.581,-4.105Z" style="fill-rule:nonzero;"/>
|
||||
</svg>
|
||||
</template>
|
||||
|
@ -1,5 +1,5 @@
|
||||
<template>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" baseProfile="full" class="icon" width="100%" height="100%" viewBox="0 0 24.00 24.00" enable-background="new 0 0 24.00 24.00" xml:space="preserve">
|
||||
<path fill="#000000" fill-opacity="1" stroke-linejoin="round" d="M10,5l0,3l2.214,0l-3.428,8l-2.786,0l0,3l8,0l0,-3l-2.214,0l3.428,-8l2.786,0l0,-3l-8,0Z" />
|
||||
<path d="M8.617,3.658l0,3.575l2.633,0l-2.075,9.534l-3.325,0l0,3.575l9.533,0l0,-3.575l-2.633,0l2.075,-9.534l3.325,0l0,-3.575l-9.533,0Z" style="fill-rule:nonzero;"/>
|
||||
</svg>
|
||||
</template>
|
||||
|
@ -1,5 +1,5 @@
|
||||
<template>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" baseProfile="full" class="icon" width="100%" height="100%" viewBox="0 0 24.00 24.00" enable-background="new 0 0 24.00 24.00" xml:space="preserve">
|
||||
<path fill="#000000" fill-opacity="1" stroke-width="0.2" stroke-linejoin="round" d="M 7,5L 21,5L 21,7L 7,7L 7,5 Z M 7,13L 7,11L 21,11L 21,13L 7,13 Z M 4,4.50001C 4.83,4.50001 5.5,5.16993 5.5,6.00001C 5.5,6.83008 4.83,7.50001 4,7.50001C 3.17,7.50001 2.5,6.83008 2.5,6.00001C 2.5,5.16993 3.17,4.50001 4,4.50001 Z M 4,10.5C 4.83,10.5 5.5,11.17 5.5,12C 5.5,12.83 4.83,13.5 4,13.5C 3.17,13.5 2.5,12.83 2.5,12C 2.5,11.17 3.17,10.5 4,10.5 Z M 7,19L 7,17L 21,17L 21,19L 7,19 Z M 4,16.5C 4.83,16.5 5.5,17.17 5.5,18C 5.5,18.83 4.83,19.5 4,19.5C 3.17,19.5 2.5,18.83 2.5,18C 2.5,17.17 3.17,16.5 4,16.5 Z " />
|
||||
<path d="M7.043,4.695l14.61,0l0,2.087l-14.61,0l0,-2.087m0,8.349l0,-2.088l14.61,0l0,2.088l-14.61,0m-3.131,-8.871c0.866,0 1.566,0.699 1.566,1.565c0,0.867 -0.7,1.566 -1.566,1.566c-0.866,0 -1.565,-0.699 -1.565,-1.566c0,-0.866 0.699,-1.565 1.565,-1.565m0,6.262c0.866,0 1.566,0.699 1.566,1.565c0,0.866 -0.7,1.565 -1.566,1.565c-0.866,0 -1.565,-0.699 -1.565,-1.565c0,-0.866 0.699,-1.565 1.565,-1.565m3.131,8.87l0,-2.087l14.61,0l0,2.087l-14.61,0m-3.131,-2.609c0.866,0 1.566,0.699 1.566,1.566c0,0.866 -0.7,1.565 -1.566,1.565c-0.866,0 -1.565,-0.699 -1.565,-1.565c0,-0.867 0.699,-1.566 1.565,-1.566Z" style="fill-rule:nonzero;"/>
|
||||
</svg>
|
||||
</template>
|
||||
|
@ -1,5 +1,5 @@
|
||||
<template>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" baseProfile="full" class="icon" width="100%" height="100%" viewBox="0 0 24.00 24.00" enable-background="new 0 0 24.00 24.00" xml:space="preserve">
|
||||
<path fill="#000000" fill-opacity="1" stroke-width="0.2" stroke-linejoin="round" d="M 6.99938,12.998L 20.9994,12.998L 20.9994,10.998L 6.99938,10.998M 6.99938,18.998L 20.9994,18.998L 20.9994,16.998L 6.99938,16.998M 6.99938,6.99805L 20.9994,6.99805L 20.9994,4.99805L 6.99938,4.99805M 1.99938,10.998L 3.79939,10.998L 1.99938,13.0981L 1.99938,13.998L 4.99938,13.998L 4.99938,12.998L 3.19938,12.998L 4.99938,10.898L 4.99938,9.99805L 1.99938,9.99805M 2.99938,7.99805L 3.99938,7.99805L 3.99938,3.99805L 1.99938,3.99805L 1.99938,4.99805L 2.99938,4.99805M 1.99938,16.998L 3.99938,16.998L 3.99938,17.498L 2.99938,17.498L 2.99938,18.498L 3.99938,18.498L 3.99938,18.998L 1.99938,18.998L 1.99938,19.998L 4.99938,19.998L 4.99938,15.998L 1.99938,15.998L 1.99938,16.998 Z " />
|
||||
<path d="M7.235,13.059l14.825,0l0,-2.118l-14.825,0m0,8.471l14.825,0l0,-2.117l-14.825,0m0,-10.59l14.825,0l0,-2.117l-14.825,0m-5.295,6.353l1.906,0l-1.906,2.224l0,0.953l3.177,0l0,-1.059l-1.906,0l1.906,-2.224l0,-0.953l-3.177,0m1.059,-2.118l1.059,0l0,-4.235l-2.118,0l0,1.059l1.059,0m-1.059,12.707l2.118,0l0,0.529l-1.059,0l0,1.059l1.059,0l0,0.529l-2.118,0l0,1.059l3.177,0l0,-4.235l-3.177,0l0,1.059Z" style="fill-rule:nonzero;"/>
|
||||
</svg>
|
||||
</template>
|
||||
|
@ -1,5 +1,5 @@
|
||||
<template>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" baseProfile="full" class="icon" width="100%" height="100%" viewBox="0 0 24.00 24.00" enable-background="new 0 0 24.00 24.00" xml:space="preserve">
|
||||
<path fill="#000000" fill-opacity="1" stroke-linejoin="round" d="M 14,17L 17,17L 19,13L 19,7L 13,7L 13,13L 16,13M 6,17L 9,17L 11,13L 11,7L 5,7L 5,13L 8,13L 6,17 Z " />
|
||||
<path d="M14.446,18.235l2.92,0l1.946,-4.988l0,-7.482l-5.839,0l0,7.482l2.92,0m-10.732,4.988l2.919,0l1.947,-4.988l0,-7.482l-5.839,0l0,7.482l2.919,0l-1.946,4.988Z" style="fill-rule:nonzero;"/>
|
||||
</svg>
|
||||
</template>
|
||||
|
@ -1,5 +1,5 @@
|
||||
<template>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" baseProfile="full" class="icon" width="100%" height="100%" viewBox="0 0 24.00 24.00" enable-background="new 0 0 24.00 24.00" xml:space="preserve">
|
||||
<path fill="#000000" fill-opacity="1" stroke-linejoin="round" d="M 3,12L 6,12L 6,19L 9,19L 9,12L 12,12L 12,9L 3,9M 9,4L 9,7L 14,7L 14,19L 17,19L 17,7L 22,7L 22,4L 9,4 Z " />
|
||||
<path d="M2.007,12.526l3.156,0l0,7.363l3.155,0l0,-7.363l3.156,0l0,-3.156l-9.467,0m6.311,-5.259l0,3.155l5.26,0l0,12.623l3.156,0l0,-12.623l5.259,0l0,-3.155l-13.675,0Z" style="fill-rule:nonzero;"/>
|
||||
</svg>
|
||||
</template>
|
||||
|
@ -1,5 +1,5 @@
|
||||
<template>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" baseProfile="full" class="icon" width="100%" height="100%" viewBox="0 0 24.00 24.00" enable-background="new 0 0 24.00 24.00" xml:space="preserve">
|
||||
<path fill="#000000" fill-opacity="1" stroke-width="0.2" stroke-linejoin="miter" d="M20.275,12.05l0,1.505l-3.305,0c0.756,1.61 0.72,6.009 -4.682,6.03c-6.265,0.023 -6.03,-4.89 -6.03,-4.89l2.986,0.023c0.023,2.539 2.362,2.539 2.844,2.504c0.482,-0.035 2.28,-0.023 2.421,-1.787c0.066,-0.818 -0.761,-1.444 -1.665,-1.88l-9.119,0l0,-1.505l16.55,0Zm-2.698,-3.091l-2.997,-0.024c0,0 0.129,-2.08 -2.468,-2.092c-2.598,-0.012 -2.386,1.658 -2.363,1.869c0.024,0.212 0.247,1.246 2.257,1.74l-4.737,0c0,0 -2.624,-5.062 3.785,-5.936c6.547,-0.893 6.535,4.455 6.523,4.443Z" />
|
||||
<path d="M20.874,12.059l0,1.729l-3.541,0c0.806,1.851 0.766,6.918 -5.026,6.918c-6.721,0.043 -6.463,-5.621 -6.463,-5.621l3.203,0.044c0.024,2.914 2.55,2.914 3.05,2.879c0.516,-0.043 2.444,-0.034 2.598,-2.058c0.064,-0.942 -0.823,-1.66 -1.791,-2.162l-9.778,0l0,-1.729l17.748,0m-2.896,-3.554l-3.211,-0.026c0,0 0.137,-2.395 -2.646,-2.404c-2.783,-0.017 -2.541,1.902 -2.541,2.144c0.032,0.243 0.274,1.436 2.42,2.007l-5.074,0c0,0 -2.816,-5.82 4.057,-6.814c7.027,-1.038 7.011,5.11 6.995,5.093Z" style="fill-rule:nonzero;"/>
|
||||
</svg>
|
||||
</template>
|
||||
|
363
src/services/localDbSvc.js
Normal file
363
src/services/localDbSvc.js
Normal file
@ -0,0 +1,363 @@
|
||||
import 'babel-polyfill';
|
||||
import 'indexeddbshim';
|
||||
import utils from './utils';
|
||||
|
||||
let indexedDB = window.indexedDB;
|
||||
const localStorage = window.localStorage;
|
||||
const dbVersion = 1;
|
||||
|
||||
// Use the shim on Safari or if indexedDB is not available
|
||||
if (window.shimIndexedDB && (!indexedDB || (navigator.userAgent.indexOf('Chrome') === -1 && navigator.userAgent.indexOf('Safari') !== -1))) {
|
||||
indexedDB = window.shimIndexedDB;
|
||||
}
|
||||
|
||||
const deletedMarkerMaxAge = 1000;
|
||||
|
||||
function identity(value) {
|
||||
return value;
|
||||
}
|
||||
|
||||
function makeStore(storeName, schemaParameter) {
|
||||
const schema = {
|
||||
...schemaParameter,
|
||||
updated: 'int',
|
||||
};
|
||||
|
||||
const schemaKeys = Object.keys(schema);
|
||||
const schemaKeysLen = schemaKeys.length;
|
||||
const complexKeys = [];
|
||||
let complexKeysLen = 0;
|
||||
const attributeCheckers = {};
|
||||
const attributeReaders = {};
|
||||
const attributeWriters = {};
|
||||
|
||||
class Dao {
|
||||
constructor(id, skipInit) {
|
||||
this.id = id || utils.uid();
|
||||
if (!skipInit) {
|
||||
const fakeItem = {};
|
||||
for (let i = 0; i < schemaKeysLen; i += 1) {
|
||||
attributeReaders[schemaKeys[i]](fakeItem, this);
|
||||
}
|
||||
this.$dirty = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function createDao(id) {
|
||||
return new Dao(id);
|
||||
}
|
||||
|
||||
Object.keys(schema).forEach((key) => {
|
||||
const value = schema[key];
|
||||
const storedValueKey = `_${key}`;
|
||||
let defaultValue = value.default === undefined ? '' : value.default;
|
||||
let serializer = value.serializer || identity;
|
||||
let parser = value.parser || identity;
|
||||
if (value === 'int') {
|
||||
defaultValue = 0;
|
||||
} else if (value === 'object') {
|
||||
defaultValue = 'null';
|
||||
parser = JSON.parse;
|
||||
serializer = JSON.stringify;
|
||||
}
|
||||
|
||||
attributeReaders[key] = (dbItem, dao) => {
|
||||
dao[storedValueKey] = dbItem[key] || defaultValue;
|
||||
};
|
||||
attributeWriters[key] = (dbItem, dao) => {
|
||||
const storedValue = dao[storedValueKey];
|
||||
if (storedValue && storedValue !== defaultValue) {
|
||||
dbItem[key] = storedValue;
|
||||
}
|
||||
};
|
||||
|
||||
function getter() {
|
||||
return this[storedValueKey];
|
||||
}
|
||||
|
||||
function setter(param) {
|
||||
const val = param || defaultValue;
|
||||
if (this[storedValueKey] === val) {
|
||||
return false;
|
||||
}
|
||||
this[storedValueKey] = val;
|
||||
this.$dirty = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
if (key === 'updated') {
|
||||
Object.defineProperty(Dao.prototype, key, {
|
||||
get: getter,
|
||||
set: (value) => {
|
||||
if (setter.call(this, value)) {
|
||||
this.$dirtyUpdated = true;
|
||||
}
|
||||
}
|
||||
})
|
||||
} else if (value === 'string' || value === 'int') {
|
||||
Object.defineProperty(Dao.prototype, key, {
|
||||
get: getter,
|
||||
set: setter
|
||||
})
|
||||
} else if (![64, 128] // Handle string64 and string128
|
||||
.cl_some(function (length) {
|
||||
if (value === 'string' + length) {
|
||||
Object.defineProperty(Dao.prototype, key, {
|
||||
get: getter,
|
||||
set: function (value) {
|
||||
if (value && value.length > length) {
|
||||
value = value.slice(0, length)
|
||||
}
|
||||
setter.call(this, value)
|
||||
}
|
||||
})
|
||||
return true
|
||||
}
|
||||
})
|
||||
) {
|
||||
// Other types go to complexKeys list
|
||||
complexKeys.push(key)
|
||||
complexKeysLen++
|
||||
|
||||
// And have complex readers/writers
|
||||
attributeReaders[key] = function (dbItem, dao) {
|
||||
const storedValue = dbItem[key]
|
||||
if (!storedValue) {
|
||||
storedValue = defaultValue
|
||||
}
|
||||
dao[storedValueKey] = storedValue
|
||||
dao[key] = parser(storedValue)
|
||||
}
|
||||
attributeWriters[key] = function (dbItem, dao) {
|
||||
const storedValue = serializer(dao[key])
|
||||
dao[storedValueKey] = storedValue
|
||||
if (storedValue && storedValue !== defaultValue) {
|
||||
dbItem[key] = storedValue
|
||||
}
|
||||
}
|
||||
|
||||
// Checkers are only for complex types
|
||||
attributeCheckers[key] = function (dao) {
|
||||
return serializer(dao[key]) !== dao[storedValueKey]
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
const lastTx = 0
|
||||
const storedSeqs = Object.create(null)
|
||||
|
||||
function readDbItem(item, daoMap) {
|
||||
const dao = daoMap[item.id] || new Dao(item.id, true)
|
||||
if (!item.updated) {
|
||||
delete storedSeqs[item.id]
|
||||
if (dao.updated) {
|
||||
delete daoMap[item.id]
|
||||
return true
|
||||
}
|
||||
return
|
||||
}
|
||||
if (storedSeqs[item.id] === item.seq) {
|
||||
return
|
||||
}
|
||||
storedSeqs[item.id] = item.seq
|
||||
for (const i = 0; i < schemaKeysLen; i++) {
|
||||
attributeReaders[schemaKeys[i]](item, dao)
|
||||
}
|
||||
dao.$dirty = false
|
||||
dao.$dirtyUpdated = false
|
||||
daoMap[item.id] = dao
|
||||
return true
|
||||
}
|
||||
|
||||
function getPatch(tx, cb) {
|
||||
let resetMap;
|
||||
|
||||
// We may have missed some deleted markers
|
||||
if (lastTx && tx.txCounter - lastTx > deletedMarkerMaxAge) {
|
||||
// Delete all dirty daos, user was asleep anyway...
|
||||
resetMap = true
|
||||
// And retrieve everything from DB
|
||||
lastTx = 0
|
||||
}
|
||||
|
||||
const hasChanged = !lastTx
|
||||
const store = tx.objectStore(storeName)
|
||||
const index = store.index('seq')
|
||||
const range = $window.IDBKeyRange.lowerBound(lastTx, true)
|
||||
const items = []
|
||||
const itemsToDelete = []
|
||||
index.openCursor(range).onsuccess = function (event) {
|
||||
const cursor = event.target.result
|
||||
if (!cursor) {
|
||||
itemsToDelete.cl_each(function (item) {
|
||||
store.delete(item.id)
|
||||
})
|
||||
items.length && debug('Got ' + items.length + ' ' + storeName + ' items')
|
||||
// Return a patch, to apply changes later
|
||||
return cb(function (daoMap) {
|
||||
if (resetMap) {
|
||||
Object.keys(daoMap).cl_each(function (key) {
|
||||
delete daoMap[key]
|
||||
})
|
||||
storedSeqs = Object.create(null)
|
||||
}
|
||||
items.cl_each(function (item) {
|
||||
hasChanged |= readDbItem(item, daoMap)
|
||||
})
|
||||
return hasChanged
|
||||
})
|
||||
}
|
||||
const item = cursor.value
|
||||
items.push(item)
|
||||
// Remove old deleted markers
|
||||
if (!item.updated && tx.txCounter - item.seq > deletedMarkerMaxAge) {
|
||||
itemsToDelete.push(item)
|
||||
}
|
||||
cursor.continue()
|
||||
}
|
||||
}
|
||||
|
||||
function writeAll(daoMap, tx) {
|
||||
lastTx = tx.txCounter
|
||||
const store = tx.objectStore(storeName)
|
||||
|
||||
// Remove deleted daos
|
||||
const storedIds = Object.keys(storedSeqs)
|
||||
const storedIdsLen = storedIds.length
|
||||
for (const i = 0; i < storedIdsLen; i++) {
|
||||
const id = storedIds[i]
|
||||
if (!daoMap[id]) {
|
||||
// Put a deleted marker to notify other tabs
|
||||
store.put({
|
||||
id: id,
|
||||
seq: lastTx
|
||||
})
|
||||
delete storedSeqs[id]
|
||||
}
|
||||
}
|
||||
|
||||
// Put changes
|
||||
const daoIds = Object.keys(daoMap)
|
||||
const daoIdsLen = daoIds.length
|
||||
for (i = 0; i < daoIdsLen; i++) {
|
||||
const dao = daoMap[daoIds[i]]
|
||||
const dirty = dao.$dirty
|
||||
for (const j = 0; !dirty && j < complexKeysLen; j++) {
|
||||
dirty |= attributeCheckers[complexKeys[j]](dao)
|
||||
}
|
||||
if (dirty) {
|
||||
if (!dao.$dirtyUpdated) {
|
||||
// Force update the `updated` attribute
|
||||
dao.updated = Date.now()
|
||||
}
|
||||
const item = {
|
||||
id: daoIds[i],
|
||||
seq: lastTx
|
||||
}
|
||||
for (j = 0; j < schemaKeysLen; j++) {
|
||||
attributeWriters[schemaKeys[j]](item, dao)
|
||||
}
|
||||
debug('Put ' + storeName + ' item')
|
||||
store.put(item)
|
||||
storedSeqs[item.id] = item.seq
|
||||
dao.$dirty = false
|
||||
dao.$dirtyUpdated = false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
getPatch,
|
||||
writeAll,
|
||||
createDao,
|
||||
Dao,
|
||||
};
|
||||
}
|
||||
|
||||
class Connection {
|
||||
constructor() {
|
||||
this.getTxCbs = [];
|
||||
|
||||
// Init connexion
|
||||
const request = indexedDB.open('classeur-db', dbVersion);
|
||||
|
||||
request.onerror = () => {
|
||||
throw new Error("Can't connect to IndexedDB.");
|
||||
};
|
||||
|
||||
request.onsuccess = (event) => {
|
||||
this.db = event.target.result;
|
||||
localStorage.localDbVersion = this.db.version; // Safari does not support onversionchange
|
||||
this.db.onversionchange = () => window.location.reload();
|
||||
|
||||
this.getTxCbs.forEach(cb => this.createTx(cb));
|
||||
this.getTxCbs = null;
|
||||
};
|
||||
|
||||
request.onupgradeneeded = (event) => {
|
||||
const eventDb = event.target.result;
|
||||
const oldVersion = event.oldVersion || 0;
|
||||
function createStore(name) {
|
||||
const store = eventDb.createObjectStore(name, { keyPath: 'id' });
|
||||
store.createIndex('seq', 'seq', { unique: false });
|
||||
}
|
||||
|
||||
// We don't use 'break' in this switch statement,
|
||||
// the fall-through behaviour is what we want.
|
||||
/* eslint-disable no-fallthrough */
|
||||
switch (oldVersion) {
|
||||
case 0:
|
||||
[
|
||||
'contents',
|
||||
'files',
|
||||
'folders',
|
||||
'objects',
|
||||
'app',
|
||||
].forEach(createStore);
|
||||
default:
|
||||
}
|
||||
/* eslint-enable no-fallthrough */
|
||||
};
|
||||
}
|
||||
|
||||
createTx(cb) {
|
||||
if (!this.db) {
|
||||
this.getTxCbs.push(cb);
|
||||
return;
|
||||
}
|
||||
|
||||
// If DB version has changed (Safari support)
|
||||
if (parseInt(localStorage.localDbVersion, 10) !== this.db.version) {
|
||||
window.location.reload();
|
||||
return;
|
||||
}
|
||||
const tx = this.db.transaction(this.db.objectStoreNames, 'readwrite');
|
||||
// tx.onerror = (evt) => {
|
||||
// dbg('Rollback transaction', evt);
|
||||
// };
|
||||
const store = tx.objectStore('app');
|
||||
const request = store.get('txCounter');
|
||||
request.onsuccess = () => {
|
||||
tx.txCounter = request.result ? request.result.value : 0;
|
||||
tx.txCounter += 1;
|
||||
store.put({
|
||||
id: 'txCounter',
|
||||
value: tx.txCounter,
|
||||
});
|
||||
cb(tx);
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
class LocalDbStorage {
|
||||
init(store) {
|
||||
this.store = store;
|
||||
store.subscribe((mutation, state) => {
|
||||
console.log(mutation, state);
|
||||
});
|
||||
this.connection = new Connection();
|
||||
}
|
||||
}
|
||||
|
||||
export default LocalDbStorage;
|
@ -4,11 +4,14 @@ import Vuex from 'vuex';
|
||||
import files from './modules/files';
|
||||
import layout from './modules/layout';
|
||||
import editor from './modules/editor';
|
||||
import LocalDbStorage from '../services/localDbSvc';
|
||||
|
||||
Vue.use(Vuex);
|
||||
|
||||
const debug = process.env.NODE_ENV !== 'production';
|
||||
|
||||
const localDbStorage = new LocalDbStorage();
|
||||
|
||||
const store = new Vuex.Store({
|
||||
modules: {
|
||||
files,
|
||||
@ -16,7 +19,7 @@ const store = new Vuex.Store({
|
||||
editor,
|
||||
},
|
||||
strict: debug,
|
||||
plugins: debug ? [createLogger()] : [],
|
||||
plugins: [_store => localDbStorage.init(_store)].concat(debug ? [createLogger()] : []),
|
||||
});
|
||||
|
||||
export default store;
|
||||
|
65
yarn.lock
65
yarn.lock
@ -115,6 +115,10 @@ argparse@^1.0.7:
|
||||
dependencies:
|
||||
sprintf-js "~1.0.2"
|
||||
|
||||
argsarray@^0.0.1:
|
||||
version "0.0.1"
|
||||
resolved "https://registry.yarnpkg.com/argsarray/-/argsarray-0.0.1.tgz#6e7207b4ecdb39b0af88303fa5ae22bda8df61cb"
|
||||
|
||||
arr-diff@^2.0.0:
|
||||
version "2.0.0"
|
||||
resolved "https://registry.yarnpkg.com/arr-diff/-/arr-diff-2.0.0.tgz#8f3b827f955a8bd669697e4a4256ac3ceae356cf"
|
||||
@ -692,6 +696,14 @@ babel-plugin-transform-strict-mode@^6.24.1:
|
||||
babel-runtime "^6.22.0"
|
||||
babel-types "^6.24.1"
|
||||
|
||||
babel-polyfill@6.23.0, babel-polyfill@^6.23.0:
|
||||
version "6.23.0"
|
||||
resolved "https://registry.yarnpkg.com/babel-polyfill/-/babel-polyfill-6.23.0.tgz#8364ca62df8eafb830499f699177466c3b03499d"
|
||||
dependencies:
|
||||
babel-runtime "^6.22.0"
|
||||
core-js "^2.4.0"
|
||||
regenerator-runtime "^0.10.0"
|
||||
|
||||
babel-preset-env@^1.3.2:
|
||||
version "1.5.1"
|
||||
resolved "https://registry.yarnpkg.com/babel-preset-env/-/babel-preset-env-1.5.1.tgz#d2eca6af179edf27cdc305a84820f601b456dd0b"
|
||||
@ -1587,7 +1599,7 @@ debug@2.6.7:
|
||||
dependencies:
|
||||
ms "2.0.0"
|
||||
|
||||
debug@^2.1.1, debug@^2.2.0, debug@^2.6.0:
|
||||
debug@^2.1.1, debug@^2.2.0, debug@^2.6.0, debug@^2.6.8:
|
||||
version "2.6.8"
|
||||
resolved "https://registry.yarnpkg.com/debug/-/debug-2.6.8.tgz#e731531ca2ede27d188222427da17821d68ff4fc"
|
||||
dependencies:
|
||||
@ -2933,6 +2945,10 @@ ignore@^3.2.0:
|
||||
version "3.3.3"
|
||||
resolved "https://registry.yarnpkg.com/ignore/-/ignore-3.3.3.tgz#432352e57accd87ab3110e82d3fea0e47812156d"
|
||||
|
||||
immediate@^3.2.2:
|
||||
version "3.2.3"
|
||||
resolved "https://registry.yarnpkg.com/immediate/-/immediate-3.2.3.tgz#d140fa8f614659bd6541233097ddaac25cdd991c"
|
||||
|
||||
imurmurhash@^0.1.4:
|
||||
version "0.1.4"
|
||||
resolved "https://registry.yarnpkg.com/imurmurhash/-/imurmurhash-0.1.4.tgz#9218b9b2b928a238b13dc4fb6b6d576f231453ea"
|
||||
@ -2947,6 +2963,13 @@ indent-string@^2.1.0:
|
||||
dependencies:
|
||||
repeating "^2.0.0"
|
||||
|
||||
indexeddbshim@^3.0.4:
|
||||
version "3.0.4"
|
||||
resolved "https://registry.yarnpkg.com/indexeddbshim/-/indexeddbshim-3.0.4.tgz#b4d9a4fb3fce7532b66e19790a15692f9b2c7b56"
|
||||
dependencies:
|
||||
babel-polyfill "6.23.0"
|
||||
websql "https://github.com/brettz9/node-websql#configurable"
|
||||
|
||||
indexes-of@^1.0.1:
|
||||
version "1.0.1"
|
||||
resolved "https://registry.yarnpkg.com/indexes-of/-/indexes-of-1.0.1.tgz#f30f716c8e2bd346c7b67d3df3915566a7c05607"
|
||||
@ -3701,10 +3724,6 @@ markdown-it-footnote@^3.0.1:
|
||||
version "3.0.1"
|
||||
resolved "https://registry.yarnpkg.com/markdown-it-footnote/-/markdown-it-footnote-3.0.1.tgz#7f3730747cacc86e2fe0bf8a17a710f34791517a"
|
||||
|
||||
markdown-it-mathjax@^2.0.0:
|
||||
version "2.0.0"
|
||||
resolved "https://registry.yarnpkg.com/markdown-it-mathjax/-/markdown-it-mathjax-2.0.0.tgz#ae2b4f4c5c719a03f9e475c664f7b2685231d9e9"
|
||||
|
||||
markdown-it-pandoc-renderer@1.1.3:
|
||||
version "1.1.3"
|
||||
resolved "https://registry.yarnpkg.com/markdown-it-pandoc-renderer/-/markdown-it-pandoc-renderer-1.1.3.tgz#77f1a5b488c5460ab1e1dcbcfcc07d12674f7a3a"
|
||||
@ -3903,6 +3922,10 @@ nan@^2.3.0, nan@^2.3.2:
|
||||
version "2.6.2"
|
||||
resolved "https://registry.yarnpkg.com/nan/-/nan-2.6.2.tgz#e4ff34e6c95fdfb5aecc08de6596f43605a7db45"
|
||||
|
||||
nan@~2.4.0:
|
||||
version "2.4.0"
|
||||
resolved "https://registry.yarnpkg.com/nan/-/nan-2.4.0.tgz#fb3c59d45fe4effe215f0b890f8adf6eb32d2232"
|
||||
|
||||
natives@^1.1.0:
|
||||
version "1.1.0"
|
||||
resolved "https://registry.yarnpkg.com/natives/-/natives-1.1.0.tgz#e9ff841418a6b2ec7a495e939984f78f163e6e31"
|
||||
@ -4007,7 +4030,7 @@ node-libs-browser@^2.0.0:
|
||||
util "^0.10.3"
|
||||
vm-browserify "0.0.4"
|
||||
|
||||
node-pre-gyp@^0.6.29:
|
||||
node-pre-gyp@^0.6.29, node-pre-gyp@~0.6.31:
|
||||
version "0.6.36"
|
||||
resolved "https://registry.yarnpkg.com/node-pre-gyp/-/node-pre-gyp-0.6.36.tgz#db604112cb74e0d477554e9b505b17abddfab786"
|
||||
dependencies:
|
||||
@ -4044,6 +4067,10 @@ node-sass@^4.5.3:
|
||||
sass-graph "^2.1.1"
|
||||
stdout-stream "^1.4.0"
|
||||
|
||||
noop-fn@^1.0.0:
|
||||
version "1.0.0"
|
||||
resolved "https://registry.yarnpkg.com/noop-fn/-/noop-fn-1.0.0.tgz#5f33d47f13d2150df93e0cb036699e982f78ffbf"
|
||||
|
||||
"nopt@2 || 3", nopt@~3.0.1:
|
||||
version "3.0.6"
|
||||
resolved "https://registry.yarnpkg.com/nopt/-/nopt-3.0.6.tgz#c6465dbf08abcd4db359317f79ac68a646b28ff9"
|
||||
@ -4735,6 +4762,10 @@ postcss@^6.0.1:
|
||||
source-map "^0.5.6"
|
||||
supports-color "^3.2.3"
|
||||
|
||||
pouchdb-collections@^1.0.1:
|
||||
version "1.0.1"
|
||||
resolved "https://registry.yarnpkg.com/pouchdb-collections/-/pouchdb-collections-1.0.1.tgz#fe63a17da977611abef7cb8026cb1a9553fd8359"
|
||||
|
||||
prelude-ls@~1.1.2:
|
||||
version "1.1.2"
|
||||
resolved "https://registry.yarnpkg.com/prelude-ls/-/prelude-ls-1.1.2.tgz#21932a549f5e52ffd9a827f570e04be62a97da54"
|
||||
@ -5401,6 +5432,13 @@ sprintf-js@~1.0.2:
|
||||
version "1.0.3"
|
||||
resolved "https://registry.yarnpkg.com/sprintf-js/-/sprintf-js-1.0.3.tgz#04e6926f662895354f3dd015203633b857297e2c"
|
||||
|
||||
sqlite3@^3.1.3:
|
||||
version "3.1.8"
|
||||
resolved "https://registry.yarnpkg.com/sqlite3/-/sqlite3-3.1.8.tgz#4cbcf965d8b901d1b1015cbc7fc415aae157dfaa"
|
||||
dependencies:
|
||||
nan "~2.4.0"
|
||||
node-pre-gyp "~0.6.31"
|
||||
|
||||
sshpk@^1.7.0:
|
||||
version "1.13.0"
|
||||
resolved "https://registry.yarnpkg.com/sshpk/-/sshpk-1.13.0.tgz#ff2a3e4fd04497555fed97b39a0fd82fafb3a33c"
|
||||
@ -5756,6 +5794,10 @@ tiny-emitter@^2.0.0:
|
||||
version "2.0.0"
|
||||
resolved "https://registry.yarnpkg.com/tiny-emitter/-/tiny-emitter-2.0.0.tgz#bad327adb1804b42a231afa741532bd884cd09ad"
|
||||
|
||||
tiny-queue@^0.2.1:
|
||||
version "0.2.1"
|
||||
resolved "https://registry.yarnpkg.com/tiny-queue/-/tiny-queue-0.2.1.tgz#25a67f2c6e253b2ca941977b5ef7442ef97a6046"
|
||||
|
||||
to-arraybuffer@^1.0.0:
|
||||
version "1.0.1"
|
||||
resolved "https://registry.yarnpkg.com/to-arraybuffer/-/to-arraybuffer-1.0.1.tgz#7d229b1fcc637e466ca081180836a7aabff83f43"
|
||||
@ -6141,6 +6183,17 @@ webpack@^2.6.1:
|
||||
webpack-sources "^0.2.3"
|
||||
yargs "^6.0.0"
|
||||
|
||||
"websql@https://github.com/brettz9/node-websql#configurable":
|
||||
version "0.4.4"
|
||||
resolved "https://github.com/brettz9/node-websql#c9828a34c92eced64858fc19151ec099fd60e8dd"
|
||||
dependencies:
|
||||
argsarray "^0.0.1"
|
||||
immediate "^3.2.2"
|
||||
noop-fn "^1.0.0"
|
||||
pouchdb-collections "^1.0.1"
|
||||
sqlite3 "^3.1.3"
|
||||
tiny-queue "^0.2.1"
|
||||
|
||||
whet.extend@~0.9.9:
|
||||
version "0.9.9"
|
||||
resolved "https://registry.yarnpkg.com/whet.extend/-/whet.extend-0.9.9.tgz#f877d5bf648c97e5aa542fadc16d6a259b9c11a1"
|
||||
|
Loading…
Reference in New Issue
Block a user