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.
This commit is contained in:
OverSu 2026-09-30 23:13:03 +02:00
commit b38dea0597
25901 changed files with 9982925 additions and 369 deletions

View file

@ -0,0 +1,167 @@
/* 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));