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,46 @@
/* global Card */
(function(exports) {
'use strict';
function AppBookmark(options) {
this.url = options.url;
this.name = options.name;
this.group = options.group;
this.thumbnail = options.thumbnail;
Card.prototype.constructor.call(this);
}
AppBookmark.deserialize = function ab_deserialize(cardEntry) {
var cardInstance;
if (cardEntry && cardEntry.type === 'AppBookmark') {
cardInstance = new AppBookmark({
name: cardEntry.name,
url: cardEntry.url,
group: cardEntry.group,
thumbnail: cardEntry.thumbnail
});
}
return cardInstance;
};
AppBookmark.prototype = Object.create(Card.prototype);
AppBookmark.prototype.constructor = AppBookmark;
AppBookmark.prototype.launch = function ab_launch(args) {
window.open(this.url, '_blank', 'remote=true,applike=true');
};
AppBookmark.prototype.serialize = function ab_serialize() {
return {
type: 'AppBookmark',
name: this.name,
url: this.url,
group: this.group,
thumbnail: this.thumbnail
};
};
exports.AppBookmark = AppBookmark;
}(window));

View file

@ -0,0 +1,86 @@
/* global Card */
(function(exports) {
'use strict';
var Application = function Application(options) {
this.nativeApp = options.nativeApp;
this.name = options.name;
this.cachedIconBlob = undefined;
this.thumbnail = options.thumbnail;
this.launchURL = options.launchURL;
this.group = options.group;
Card.prototype.constructor.call(this);
};
Application.deserialize = function app_deserialize(cardEntry, installedApps) {
var cardInstance;
if (cardEntry && installedApps && cardEntry.type === 'Application') {
cardInstance = new Application({
nativeApp: installedApps[cardEntry.manifestURL],
name: cardEntry.name,
thumbnail: cardEntry.thumbnail,
launchURL: cardEntry.launchURL,
group: cardEntry.group
});
}
return cardInstance;
};
Application.prototype = Object.create(Card.prototype);
Application.prototype.constructor = Application;
// expose getter of property of nativeApp
var exposedPropertyNames = ['manifest', 'updateManifest'];
exposedPropertyNames.forEach(function(propertyName) {
Object.defineProperty(Application.prototype, propertyName, {
get: function() {
return this.nativeApp && this.nativeApp[propertyName];
}
});
});
Application.prototype.serialize = function app_serialize() {
return {
manifestURL: this.nativeApp.manifestURL,
name: this.name,
type: 'Application',
thumbnail: this.thumbnail,
launchURL: this.launchURL,
group: this.group
};
};
Application.prototype.launch = function app_launch(args) {
if (this.nativeApp && this.nativeApp.launch && !this.launchURL) {
this.nativeApp.launch(args);
} else {
if (!Application._iacPort) {
console.error('no iacPort found, we cannot launch Application');
return;
}
Application._iacPort.postMessage({
'manifestURL': this.nativeApp.manifestURL,
'timestamp': (new Date()).getTime(),
'url': this.launchURL
});
}
};
window.addEventListener('load', function _retrieveIACPort() {
window.removeEventListener('load', _retrieveIACPort);
navigator.mozApps.getSelf().onsuccess = function(evt) {
var app = evt.target.result;
if (app) {
app.connect('customlaunchpath').then(function onAccepted(ports) {
Application._iacPort = ports[0];
});
}
};
});
exports.Application = Application;
}(window));

View file

@ -0,0 +1,40 @@
/* global evt */
(function(exports) {
'use strict';
var _counter = 0;
// Card is the base class for Application, Deck, and Folder
var Card = function Card() {
this.generateCardId();
};
Card.deserialize = function c_deserialize(cardEntry) {
// just to prevent undefined error
};
Card.prototype = evt({
get cardId() {
return this._id;
},
generateCardId: function c_generateCardId() {
// XXX: use constructor.name + name + incremental counter
// as cardId for now. Notice that cardId is only meaningful for
// Smart-Home app. Because only Smart-Home app has 'write' privilege.
var name = (this.nativeApp && this.nativeApp.manifest) ?
this.nativeApp.manifest.name : 'card';
this._id = this.constructor.name + '-' + name + '-' + (_counter);
_counter += 1;
return this._id;
},
serialize: function c_serialize() {
// just to prevent undefined error
},
constructor: Card
});
exports.Card = Card;
}(window));

View file

@ -0,0 +1,61 @@
/* global Card */
(function(exports) {
'use strict';
var Deck = function Deck(options) {
this.nativeApp = options.nativeApp;
this.name = options.name;
this.deckClass = options.deckClass;
this.group = options.group;
Card.prototype.constructor.call(this);
};
Deck.deserialize = function deck_deserialize(cardEntry, installedApps) {
var cardInstance;
if (cardEntry && installedApps && cardEntry.type === 'Deck') {
cardInstance = new Deck({
name: cardEntry.name,
nativeApp: cardEntry.manifestURL &&
installedApps[cardEntry.manifestURL],
deckClass: cardEntry.deckClass,
group: cardEntry.group
});
}
return cardInstance;
};
Deck.prototype = Object.create(Card.prototype);
Deck.prototype.constructor = Deck;
// expose getter of property of nativeApp
var exposedPropertyNames = ['manifest', 'updateManifest'];
exposedPropertyNames.forEach(function(propertyName) {
Object.defineProperty(Deck.prototype, propertyName, {
get: function() {
return this.nativeApp && this.nativeApp[propertyName];
}
});
});
Deck.prototype.launch = function deck_launch(args) {
if (this.nativeApp && this.nativeApp.launch) {
this.nativeApp.launch(args);
}
};
Deck.prototype.serialize = function deck_serialize() {
// A deck doesn't need background color because it is always full-sized
// icon. If not, it is an issue from visual's image.
return {
name: this.name,
deckClass: this.deckClass,
manifestURL: this.nativeApp && this.nativeApp.manifestURL,
type: 'Deck',
group: this.group
};
};
exports.Deck = Deck;
}(window));

View file

@ -0,0 +1,231 @@
/* global Card, uuid */
(function(exports) {
'use strict';
var Folder = function Folder(options) {
this._cardsInFolder = options._cardsInFolder || [];
this.name = options.name;
// folderId is used in cardStore as key
this.folderId = options.folderId || uuid.v4();
this._state = options.state || Folder.STATES.NORMAL;
Card.prototype.constructor.call(this);
};
Folder.STATES = Object.freeze({
// when folder is in DESERIALIZING state, it means we are still in the
// process of loading its content from datastore
'DESERIALIZING': 'DESERIALIZING',
'NORMAL': 'NORMAL',
// DIRTY state means the folder is out of sync with data store
'DIRTY': 'DIRTY',
// DETACHED state means the folder itself is not saved (detached)
// in card list
'DETACHED': 'DETACHED'
});
Folder.deserialize = function folder_deserialize(cardEntry) {
var cardInstance;
if (cardEntry && cardEntry.type === 'Folder') {
cardInstance = new Folder({
name: cardEntry.name,
folderId: cardEntry.folderId,
// The content of folder is saved in datastore under key of folderId
// thus we are not complete deserialize it yet, mark its state
// as 'DESERIALIZING'. Caller needs to put content of the folder
// back to its structure. Please refer to CardManager#_reloadCardList().
state: Folder.STATES.DESERIALIZING
});
}
return cardInstance;
};
Folder.prototype = Object.create(Card.prototype);
Folder.prototype.constructor = Folder;
Object.defineProperty(Folder.prototype, 'state', {
get: function() {
return this._state;
},
set: function(state) {
this._state = state;
this.fire('state-changed', this._state);
}
});
Folder.prototype.getCardList = function folder_getCardList() {
return this._cardsInFolder;
};
Folder.prototype.getFilteredCardList =
function folder_getFilteredCardList(filterName) {
if (typeof this._cardsInFolder !== 'object') {
return;
}
if (filterName === 'all') {
return this._cardsInFolder;
} else if (filterName) {
return this._cardsInFolder.filter(
elem => (elem.group === filterName));
}
};
Folder.prototype.isEmpty = function folder_isEmpty() {
return this._cardsInFolder.length === 0;
};
Folder.prototype.isNotEmpty = function folder_isNotEmpty() {
return this._cardsInFolder.length > 0;
};
Folder.prototype.isDeserializing = function folder_isDeserializing() {
return this._state === Folder.STATES.DESERIALIZING;
};
Folder.prototype.isDetached = function folder_isDetached() {
return this._state === Folder.STATES.DETACHED;
};
Folder.prototype.loadCardsInFolder = function folder_loadCardsInFolder(opts) {
var that = this;
if (opts.from === 'config') {
// load content of folder from config file (e.g. in 'cardEntry' form)
this._cardsInFolder =
opts.cardEntry._cardsInFolder.map(opts.deserializer);
this.state = Folder.STATES.NORMAL;
} else if (opts.from === 'datastore') {
// load content of folder from data store
opts.datastore.getData(this.folderId).then(function(innerCardList) {
innerCardList.forEach(function(innerCardEntry) {
that._cardsInFolder.push(opts.deserializer(innerCardEntry));
});
that.state = Folder.STATES.NORMAL;
});
}
};
// get index of card in folder
Folder.prototype._indexOfCard = function folder_indexOfCard(query) {
return this._cardsInFolder.indexOf(this.findCard(query));
};
// XXX: this method shares almost the same logic as
// findCardFromCardList in CardManager. We should consolidate them. See
// http://bugzil.la/1156726
// There are three types of query:
// 1. query by cardId
// 2. query by manifestURL and optionally launchURL
// 3. query by bookmark url
// 4. query by cardEntry (i.e. serialized card)
Folder.prototype.findCard = function folder_findCard(query) {
var found;
this._cardsInFolder.some(function(card, index) {
if (card.cardId === query.cardId) {
found = card;
return true;
} else if (query.manifestURL && card.nativeApp &&
card.nativeApp.manifestURL === query.manifestURL) {
// if we specify launchURL in query, then we must compare
// launchURL first
if (query.launchURL) {
if (card.launchURL === query.launchURL) {
found = card;
return true;
}
} else {
found = card;
return true;
}
} else if (query.url) {
if (query.url === card.url) {
found = card;
}
return true;
} else if (query.cardEntry) {
// XXX: this could be bad at performance because we serialize card
// in every loop. We might need improvement on this query.
if (JSON.stringify(card.serialize()) ===
JSON.stringify(query.cardEntry)) {
found = card;
return true;
}
}
});
return found;
};
Folder.prototype._isInFolder = function folder_isInFolder(card) {
if (card) {
return this._indexOfCard(card) > -1;
} else {
return false;
}
};
Folder.prototype._setDirty = function folder_setDirty() {
if (this._state !== Folder.STATES.DETACHED) {
this._state = Folder.STATES.DIRTY;
this.fire('state-changed', this._state);
}
this.fire('folder-changed', this);
};
Folder.prototype.addCard = function folder_addCard(card, index) {
// We don't support folder in folder
if (!this._isInFolder(card) && !(card instanceof Folder)) {
if (typeof index !== 'number') {
index = this._cardsInFolder.length;
}
this._cardsInFolder.splice(index, 0, card);
this._setDirty();
this.fire('card-inserted', card, index);
}
};
Folder.prototype.removeCard = function folder_removeCard(card) {
var index = this._indexOfCard(card);
if (index > -1) {
this._cardsInFolder.splice(index, 1);
this._setDirty();
this.fire('card-removed', [index]);
}
};
Folder.prototype.updateCard = function folder_updateCard(card, index) {
// The card instance is directly reference to card in '_cardsInFolder'
// So don't bother to update it again. But we DID need 'folder-changed'
// event to notify CardManager to write changes to data store.
this._setDirty();
this.fire('card-updated', card, index);
};
Folder.prototype.swapCard = function folder_swapCard(card1, card2) {
var index1 = (typeof card1 === 'number') ?
index1 = card1 : this._indexOfCard(card1);
var index2 = (typeof card2 === 'number') ?
index2 = card2 : this._indexOfCard(card2);
var temp = this._cardsInFolder[index1];
this._cardsInFolder[index1] = this._cardsInFolder[index2];
this._cardsInFolder[index2] = temp;
this._setDirty();
this.fire('card-swapped',
this._cardsInFolder[index1], this._cardsInFolder[index2],
index1, index2);
};
Folder.prototype.launch = function folder_launch() {
// fire launch event to inform exterior module
this.fire('launch', this);
};
Folder.prototype.serialize = function folder_serialize() {
return {
name: this.name,
folderId: this.folderId,
type: 'Folder'
};
};
exports.Folder = Folder;
}(window));