VulpesOS/gaia/shared/js/smart-screen/card_store.js
OverSu b38dea0597 Publish Vulpes Preview 15 sources for desktop, Android and Tundra
Share Gaia assets and adapters, keep private profiles and development documents local, and update both public READMEs.
2026-09-30 23:13:03 +02:00

167 lines
4.4 KiB
JavaScript
Executable file

/* global evt, PipedPromise, SharedUtils */
(function(exports) {
'use strict';
var CardStore = function(name, mode, manifestURL) {
var that = this;
this._mode = mode || 'readwrite';
this._name = name;
if (manifestURL) {
this._manifestURL = manifestURL;
this._getStore();
} else {
this._isOwner = true;
navigator.mozApps.getSelf().onsuccess = function(evt) {
var app = evt.target.result;
that._manifestURL = app.manifestURL;
that._getStore();
};
}
};
CardStore.prototype = evt({
_dataStore: undefined,
_appRevisionId: undefined,
_manifestURL: undefined,
// Only two modes available: readonly and readwrite (default)
// 'readwrite' mode is for Smart-Home app only
_mode: 'readwrite',
isStarted: function cs_isStarted() {
return !!this._manifestURL && !!this._dataStore;
},
canWrite: function cs_canWrite() {
return this._mode === 'readwrite';
},
_onChange: function(evt) {
this.fire('change', evt);
},
_getStore: function cs_getStore() {
var that = this;
return this._getPipedPromise('_getStore', function(resolve, reject) {
if (that.isStarted()) {
resolve(that._dataStore);
return;
}
navigator.getDataStores(that._name).then(
function(stores) {
stores.forEach(function(store) {
if (store.owner === that._manifestURL) {
that._dataStore = store;
that._dataStore.addEventListener('change',
that._onChange.bind(that));
}
});
if (that._dataStore) {
resolve(that._dataStore);
} else {
reject();
}
});
});
},
getData: function cs_getData(id) {
var that = this;
return new Promise(function(resolve, reject) {
that._getStore().then(function onFulfill(store) {
if (store) {
store.get(id).then(resolve);
} else {
reject('no store available');
}
}, function onReject(reason) {
reject(reason);
});
});
},
saveData: function cs_saveData(id, data) {
var that = this;
return new Promise(function(resolve, reject) {
if (that.canWrite()) {
that._getStore().then(function onFulfill(store) {
if (store) {
store.put(data, id).then(resolve, function(error) {
reject(error);
});
} else {
reject('no store available');
}
}, function onReject(reason) {
reject(reason);
});
} else {
// resolve directly without actually writing anything,
// because we are in readonly mode
resolve();
}
});
},
iterateData: function cs_listData(cb) {
return new Promise((resolve, reject) => {
this._getStore().then(store => {
return store.sync();
// For a brand-new cursor, when calling next() continuously, the task
// sequence looks like:
// 1st call: operation 'clear'
// 2st call: operation 'add' with 1st entry
// 3rd call: operation 'add' with 2nd
// ...
// n+1st call: operation 'add' with nth data entry
// n+2nd call: operation 'done'
}).then(function iterateTask(cursor) {
cursor.next().then(task => {
if (task.operation == 'add') {
cb(task.data, task.id);
iterateTask(cursor);
} else if (task.operation == 'clear') {
iterateTask(cursor);
} else if (task.operation == 'done') {
cursor.close();
resolve();
} else {
iterateTask(cursor);
}
});
});
});
},
addData: function cs_addData(data, id) {
return this._getStore().then(store => {
return store.add(data, id);
});
},
removeData: function cs_removeData(id) {
return this._getStore().then(store => {
return store.remove(id);
});
},
getLength: function cs_getLength() {
return this._getStore().then(store => {
return store.getLength();
});
},
get isOwner() {
return this._isOwner;
}
});
SharedUtils.addMixin(CardStore, PipedPromise);
exports.CardStore = CardStore;
}(window));