VulpesOS/gaia/shared/js/smart-screen/cards/folder.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

231 lines
7.3 KiB
JavaScript
Executable file

/* 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));