Commit a80293af authored by Duhoux Pierre-Louis's avatar Duhoux Pierre-Louis

[PR] Add bookmarks table and propagate bookmarks to store and to popup

parent 17efdce3
......@@ -422,6 +422,10 @@
"message": "Bookmarks",
"description": "Title of bookmarks list in manga detail"
},
"list_details_no_bookmarks": {
"message": "No bookmarks",
"description": "In manga detail, information to tell that there is no bookmarks for this manga / group of mangas"
},
"list_details_act_search": {
"message": "Search this manga elsewhere",
"description": "Seacrh elsewhere action button in manga details"
......
import * as utils from './utils'
/**
* Class helping to store data in IndexedDb
* In AMR V1, objects were stored in WebDB. WebDB is deprecated and Mozilla never implemented WebDB in FireFox
......@@ -6,6 +8,7 @@
* - mirrors definition,
* - mirrors full list of mangas
* - mangas reading list
* - bookmarked chapters and scans
*/
class StoreDB {
constructor() {
......@@ -17,7 +20,7 @@ class StoreDB {
*/
initDB() {
this.status = 3;
this.dbversion = 1;
this.dbversion = 2;
this.db = undefined;
let store = this;
return new Promise((resolve, reject) => {
......@@ -45,6 +48,7 @@ class StoreDB {
db.createObjectStore("mirrors", { keyPath: "mirrorName" });
db.createObjectStore("mangalists", { keyPath: "mirrorName" });
db.createObjectStore("mangas", { keyPath: "key" });
db.createObjectStore("bookmarks", { keyPath: "key" });
};
request.onsuccess = function (event) {
store.db = event.target.result;
......@@ -292,5 +296,79 @@ class StoreDB {
});
});
}
/**
* Store a bookmark entry
* @param {*} bm {url, type (0: chapter, 1: scan), mgkey, title}
*/
storeBookmark(bm) {
let store = this;
return this.checkInit()
.then(() => {
return new Promise((resolve, result) => {
let transaction = store.db.transaction(["bookmarks"], "readwrite");
transaction.onerror = function (event) {
reject("Impossible to store bookmarks " + bm.url + ". Error code : " + event.target.errorCode);
};
let objectStore = transaction.objectStore("bookmarks");
if (!bm.key) {
bm.key = utils.mangaKey(bm.url);
}
let request = objectStore.put(bm);
request.onsuccess = function (event) {
resolve(event.target.result);
};
});
});
}
/**
* Get all bookmarks
* @param {*} bm
*/
getBookmarks() {
let store = this;
return this.checkInit()
.then(() => {
return new Promise((resolve, result) => {
let transaction = store.db.transaction(["bookmarks"]);
let objectStore = transaction.objectStore("bookmarks");
let bms = []
objectStore.openCursor().onsuccess = function (event) {
let cursor = event.target.result;
if (cursor) {
bms.push(cursor.value);
cursor.continue();
}
else {
resolve(bms);
}
};
});
});
}
/**
* Delete a bookmark
* @param {*} bm
*/
deleteBookmark(key) {
let store = this;
return this.checkInit()
.then(() => {
return new Promise((resolve, result) => {
let transaction = store.db.transaction(["bookmarks"], "readwrite");
transaction.onerror = function (event) {
reject("Impossible to delete bookmarks " + key + ". Error code : " + event.target.errorCode);
};
let objectStore = transaction.objectStore("bookmarks");
let request = objectStore.delete(key);
request.onsuccess = function (event) {
resolve(event.target.result);
};
});
});
}
}
export default new StoreDB();
......@@ -28,6 +28,12 @@ IconHelper.setBlueIcon();
utils.debug("Initialize mangas");
await store.dispatch('initMangasFromDB');
/**
* Initialize bookmarks list in store from DB
*/
utils.debug("Initialize bookmarks");
await store.dispatch('initBookmarksFromDB');
/**
* Initiliaze extension versioning
*/
......
......@@ -153,7 +153,7 @@ class Reading {
$(img).data("finish", "1");
$(img).css("display", "none");
//Bookmark DIV MOD ??? TODO
//Bookmark DIV MOD ??? MODE CANVAS NOT USED ANYMORE
} else {
$("#" + $(img).data("divLoad")).css("display", "none");
$(img).data("finish", "1");
......
......@@ -32,7 +32,7 @@
<div class="det-sel-wrapper">
<select dark v-model="newCat" @change="addCategory()" :class="color(2)">
<option value="">{{i18n("list_details_cats_select")}}</option>
<option v-for="(cat, key) of this.options.categoriesStates"
<option v-for="(cat, key) of options.categoriesStates"
v-if="cat.type !== 'native'"
:key="key"
:value="cat.name">
......@@ -44,6 +44,14 @@
<!-- Manage manga bookmarks -->
<v-flex xs6 class="amr-bookmarks">
<span>{{i18n("list_details_books")}} : </span>
<select v-if="bookmarks.length" dark v-model="curBm" @change="openBookmark()" :class="color(2)">
<option v-for="(bm, key) of bookmarks"
:key="key"
:value="bm.key">
{{bm.title}}
</option>
</select>
<span v-if="!bookmarks.length">{{i18n("list_details_no_bookmarks")}}</span>
</v-flex>
</v-layout>
<!-- Actions buttons -->
......@@ -109,6 +117,12 @@ export default {
);
}, []);
},
// bookmarks for this group
bookmarks: function() {
return this.$store.state.bookmarks.all.filter(
bm => this.mangas.findIndex(mg => mg.key === bm.mgkey) !== -1
)
},
/**
* return true if at least one manga of the group is still updating (update top is 1)
*/
......
......@@ -245,6 +245,12 @@ export default {
key: "all",
mutation: "setMangas"
});
// initialize state for store in popup from background
await this.$store.dispatch("getStateFromReference", {
module: "bookmarks",
key: "all",
mutation: "setBookmarks"
});
this.loaded = true;
this.$emit("manga-loaded")
}
......
import storedb from '../../amr/storedb'
import * as utils from '../../amr/utils'
/**
* initial state of the bookmarks module
*/
const state = {
/**
* List of bookmarks
*/
all: []
}
// getters
const getters = {
/**
* Return the whole list of bookmarks
*/
allBookmarks: state => state.all,
}
// actions
const actions = {
/**
* Get bookmarks from local database
* @param {*} param0
*/
async initBookmarksFromDB({ commit, dispatch }) {
let bookmarks = await storedb.getBookmarks(); // Get bookmarks from local database
// set bookmarks list in store
commit('setBookmarks', bookmarks);
},
/**
* Create a bookmark in the store
* @param {*} param0
* @param {*} bm
*/
async createBookmark({ commit }, bm) {
utils.debug("create description of bookmark " + bm.key + " in db");
commit('createBookmark', bm);
await storedb.storeBookmark(bm);
},
/**
* Delete a bookmark in the store
* @param {*} param0
* @param {*} key
*/
async deleteBookmark({ commit }, key) {
let bm = state.all.find(bookmark => bookmark.key === key);
if (bm !== undefined) {
commit('deleteBookmark', key);
await storedb.deleteBookmark(key);
}
},
}
/**
* All possible mutations on bookmarks objects
* It is very important to write a mutation each time we need to update or create fields on a bookmark object.
* This way, mutations are propagated in the different instances of the store.
* If not, some modifications can be not reflected and not saved to the database.
* A mutation MUST be a synchrone function
*/
const mutations = {
/**
* Set the list of bookmarks in the store
* @param {*} state
* @param {*} bookmarks
*/
setBookmarks(state, bookmarks) {
state.all = []
state.all.push(...bookmarks)
},
/**
* Create a new bookmark
* @param {*} state
* @param {*} bm object containing bookmark info
*/
createBookmark(state, bm) {
if (!bm.key) {
bm.key = utils.mangaKey(bm.url)
}
state.all.push(bm)
},
/**
* Delete a bookmark
* @param {*} state
* @param {*} key key of the bookmark to delete
*/
deleteBookmark(state, key) {
let bmindex = state.all.findIndex(bookmark => bookmark.key === key)
if (bmindex >= 0) {
state.all.splice(bmindex, 1);
}
},
}
export default {
state,
getters,
actions,
mutations
}
\ No newline at end of file
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment