Refactor bookmarks
This commit is contained in:
parent
cb87988e8f
commit
f33abf16c5
@ -246,7 +246,7 @@ Fictioneer customizes WordPress by using as many standard action and filter hook
|
||||
| `template_redirect` | `fictioneer_disable_date_archives`, `fictioneer_generate_epub`, `fictioneer_handle_oauth`, `fictioneer_logout`, `fictioneer_disable_attachment_pages`, `fictioneer_gate_unpublished_content`
|
||||
| `trashed_post` | `fictioneer_refresh_post_caches`, `fictioneer_track_chapter_and_story_updates`, `fictioneer_update_modified_date_on_story_for_chapter`, `fictioneer_purge_transients`, `fictioneer_flush_object_cache`
|
||||
| `untrash_post` | `fictioneer_refresh_post_caches`, `fictioneer_track_chapter_and_story_updates`, `fictioneer_update_modified_date_on_story_for_chapter`, `fictioneer_purge_transients`, `fictioneer_flush_object_cache`
|
||||
| `wp_ajax_*` | `fictioneer_ajax_clear_my_checkmarks`, `fictioneer_ajax_clear_my_comments`, `fictioneer_ajax_clear_my_comment_subscriptions`, `fictioneer_ajax_clear_my_follows`, `fictioneer_ajax_clear_my_reminders`, `fictioneer_ajax_delete_epub`, `fictioneer_ajax_delete_my_account`, `fictioneer_ajax_delete_my_comment`, `fictioneer_ajax_edit_comment`, `fictioneer_ajax_get_avatar`, `fictioneer_ajax_get_bookmarks`, `fictioneer_ajax_get_comment_form`, `fictioneer_ajax_get_comment_section`, `fictioneer_ajax_get_finished_checkmarks_list`, `fictioneer_ajax_get_follows_list`, `fictioneer_ajax_get_follows_notifications`, `fictioneer_ajax_get_nonce`, `fictioneer_ajax_get_reminders_list`, `fictioneer_ajax_is_user_logged_in`, `fictioneer_ajax_mark_follows_read`, `fictioneer_ajax_moderate_comment`, `fictioneer_ajax_purge_schema`, `fictioneer_ajax_report_comment`, `fictioneer_ajax_save_bookmarks`, `fictioneer_ajax_set_checkmark`, `fictioneer_ajax_submit_comment`, `fictioneer_ajax_toggle_follow`, `fictioneer_ajax_toggle_reminder`, `fictioneer_ajax_unset_my_oauth`, `fictioneer_ajax_get_user_data`
|
||||
| `wp_ajax_*` | `fictioneer_ajax_clear_my_checkmarks`, `fictioneer_ajax_clear_my_comments`, `fictioneer_ajax_clear_my_comment_subscriptions`, `fictioneer_ajax_clear_my_follows`, `fictioneer_ajax_clear_my_reminders`, `fictioneer_ajax_delete_epub`, `fictioneer_ajax_delete_my_account`, `fictioneer_ajax_delete_my_comment`, `fictioneer_ajax_edit_comment`, `fictioneer_ajax_get_avatar`, `fictioneer_ajax_get_comment_form`, `fictioneer_ajax_get_comment_section`, `fictioneer_ajax_get_finished_checkmarks_list`, `fictioneer_ajax_get_follows_list`, `fictioneer_ajax_get_follows_notifications`, `fictioneer_ajax_get_nonce`, `fictioneer_ajax_get_reminders_list`, `fictioneer_ajax_is_user_logged_in`, `fictioneer_ajax_mark_follows_read`, `fictioneer_ajax_moderate_comment`, `fictioneer_ajax_purge_schema`, `fictioneer_ajax_report_comment`, `fictioneer_ajax_save_bookmarks`, `fictioneer_ajax_set_checkmark`, `fictioneer_ajax_submit_comment`, `fictioneer_ajax_toggle_follow`, `fictioneer_ajax_toggle_reminder`, `fictioneer_ajax_unset_my_oauth`, `fictioneer_ajax_get_user_data`
|
||||
| `wp_ajax_nopriv_*` | `fictioneer_ajax_get_comment_form`, `fictioneer_ajax_get_comment_section`, `fictioneer_ajax_get_nonce`, `fictioneer_ajax_is_user_logged_in`, `fictioneer_ajax_submit_comment`
|
||||
| `wp_before_admin_bar_render` | `fictioneer_remove_admin_bar_links`, `fictioneer_remove_dashboard_from_admin_bar`
|
||||
| `wp_dashboard_setup` | `fictioneer_remove_dashboard_widgets`
|
||||
|
@ -13,7 +13,6 @@ if ( ! defined( 'FICTIONEER_FAST_AJAX_FUNCTIONS' ) ) {
|
||||
'fictioneer_ajax_get_nonce',
|
||||
// Bookmarks
|
||||
'fictioneer_ajax_save_bookmarks',
|
||||
'fictioneer_ajax_get_bookmarks',
|
||||
// Follows
|
||||
'fictioneer_ajax_toggle_follow',
|
||||
'fictioneer_ajax_clear_my_follows',
|
||||
|
@ -1,48 +1,5 @@
|
||||
<?php
|
||||
|
||||
// =============================================================================
|
||||
// GET BOOKMARKS FOR USERS - AJAX
|
||||
// =============================================================================
|
||||
|
||||
/**
|
||||
* Get an user's bookmarks via AJAX
|
||||
*
|
||||
* @since Fictioneer 4.0
|
||||
* @link https://developer.wordpress.org/reference/functions/wp_send_json_success/
|
||||
* @link https://developer.wordpress.org/reference/functions/wp_send_json_error/
|
||||
* @see fictioneer_get_validated_ajax_user()
|
||||
*/
|
||||
|
||||
function fictioneer_ajax_get_bookmarks() {
|
||||
// Enabled?
|
||||
if ( ! get_option( 'fictioneer_enable_bookmarks' ) ) {
|
||||
wp_send_json_error(
|
||||
array( 'error' => __( 'Not allowed.', 'fictioneer' ) ),
|
||||
403
|
||||
);
|
||||
}
|
||||
|
||||
// Setup and validations
|
||||
$user = fictioneer_get_validated_ajax_user();
|
||||
|
||||
if ( ! $user ) {
|
||||
wp_send_json_error( array( 'error' => __( 'Request did not pass validation.', 'fictioneer' ) ) );
|
||||
}
|
||||
|
||||
// Look for saved bookmarks on user...
|
||||
$bookmarks = get_user_meta( $user->ID, 'fictioneer_bookmarks', true );
|
||||
$bookmarks = $bookmarks ? $bookmarks : '{}';
|
||||
|
||||
// Response
|
||||
if ( $bookmarks ) {
|
||||
wp_send_json_success( array( 'bookmarks' => $bookmarks ) );
|
||||
}
|
||||
}
|
||||
|
||||
if ( get_option( 'fictioneer_enable_bookmarks' ) ) {
|
||||
add_action( 'wp_ajax_fictioneer_ajax_get_bookmarks', 'fictioneer_ajax_get_bookmarks' );
|
||||
}
|
||||
|
||||
// =============================================================================
|
||||
// SAVE BOOKMARKS FOR USERS - AJAX
|
||||
// =============================================================================
|
||||
|
2
js/application.min.js
vendored
2
js/application.min.js
vendored
File diff suppressed because one or more lines are too long
2
js/bookmarks.min.js
vendored
2
js/bookmarks.min.js
vendored
File diff suppressed because one or more lines are too long
2
js/user-profile.min.js
vendored
2
js/user-profile.min.js
vendored
@ -1 +1 @@
|
||||
function fcn_unsetOauth(t,e,n){const a=prompt(sprintf(_x("Are you sure? Note that if you disconnect all accounts, you may no longer be able to log back in once you log out. Enter %s to confirm.","Unset OAuth prompt.","fictioneer"),_x("delete","Prompt deletion confirmation string.","fictioneer").toUpperCase()));if(!a||a.toLowerCase()!=_x("delete","Prompt deletion confirmation string.","fictioneer").toLowerCase())return;const r=_$$$(`oauth-${e}`);r.classList.add("ajax-in-progress"),fcn_ajaxPost(payload={action:"fictioneer_ajax_unset_my_oauth",nonce:t,channel:e,id:n}).then((t=>{t.success?(r.classList.remove("_connected"),r.classList.add("_disconnected"),r.querySelector("button").remove(),fcn_showNotification(r.dataset.unset)):(r.style.background="var(--warning)",fcn_showNotification(t.data.error,5,"warning"))})).catch((t=>{t.status&&t.statusText&&(r.style.background="var(--warning)",fcn_showNotification(`${t.status}: ${t.statusText}`,5,"warning"))})).then((()=>{r.classList.remove("ajax-in-progress")}))}function fcn_deleteMyAccount(t){if(_$$$("button-delete-my-account").hasAttribute("disabled"))return;const e=prompt(sprintf(t.dataset.warning,_x("delete","Prompt deletion confirmation string.","fictioneer").toUpperCase()));e&&e.toLowerCase()==_x("delete","Prompt deletion confirmation string.","fictioneer").toLowerCase()&&(_$$$("button-delete-my-account").setAttribute("disabled",!0),fcn_ajaxPost({action:"fictioneer_ajax_delete_my_account",nonce:t.dataset.nonce,id:t.dataset.id}).then((t=>{t.success?location.reload():(fcn_showNotification(t.data.error,5,"warning"),_$$$("button-delete-my-account").innerHTML=t.data.button)})).catch((t=>{t.status&&t.statusText&&(fcn_showNotification(`${t.status}: ${t.statusText}`,5,"warning"),_$$$("button-delete-my-account").innerHTML=response.data.button)})))}_$$(".button-unset-oauth").forEach((t=>{t.addEventListener("click",(t=>{fcn_unsetOauth(t.currentTarget.dataset.nonce,t.currentTarget.dataset.channel,t.currentTarget.dataset.id)}))})),_$$$("button-delete-my-account")?.addEventListener("click",(t=>{fcn_deleteMyAccount(t.currentTarget)}));const fcn_profileDataTranslations=_$$$("profile-data-translations")?.dataset;function fcn_dataDeletionPrompt(t){const e=prompt(sprintf(t.dataset.warning,_x("delete","Prompt deletion confirmation string.","fictioneer").toUpperCase()));return!(!e||e.toLowerCase()!=_x("delete","Prompt deletion confirmation string.","fictioneer").toLowerCase())}function fcn_clearData(t,e){const n=t.closest(".card");localStorage.removeItem("fcnBookshelfContent"),n.classList.add("ajax-in-progress"),t.remove(),fcn_ajaxPost({action:e,fcn_fast_ajax:1,nonce:t.dataset.nonce}).then((t=>{t.success?n.querySelector(".card__content").innerHTML=t.data.success:fcn_showNotification(t.data.error,10,"warning")})).catch((t=>{t.status&&t.statusText&&fcn_showNotification(`${t.status}: ${t.statusText}`,10,"warning")})).then((()=>{n.classList.remove("ajax-in-progress")}))}_$(".button-clear-comments")?.addEventListener("click",(t=>{fcn_dataDeletionPrompt(t.currentTarget)&&fcn_clearData(t.currentTarget,"fictioneer_ajax_clear_my_comments")})),_$(".button-clear-comment-subscriptions")?.addEventListener("click",(t=>{fcn_dataDeletionPrompt(t.currentTarget)&&fcn_clearData(t.currentTarget,"fictioneer_ajax_clear_my_comment_subscriptions")})),_$(".button-clear-checkmarks")?.addEventListener("click",(t=>{if(!fcn_dataDeletionPrompt(t.currentTarget))return;const e=fcn_getUserData();e.checkmarks={data:{},updated:Date.now()},fcn_setUserData(e),fcn_updateCheckmarksView(),fcn_clearData(t.currentTarget,"fictioneer_ajax_clear_my_checkmarks",!0)})),_$(".button-clear-reminders")?.addEventListener("click",(t=>{if(!fcn_dataDeletionPrompt(t.currentTarget))return;const e=fcn_getUserData();e.reminders={data:{}},fcn_setUserData(e),fcn_updateRemindersView(),fcn_clearData(t.currentTarget,"fictioneer_ajax_clear_my_reminders",!0)})),_$(".button-clear-follows")?.addEventListener("click",(t=>{if(!fcn_dataDeletionPrompt(t.currentTarget))return;const e=fcn_getUserData();e.follows={data:{}},fcn_setUserData(e),fcn_updateFollowsView(),fcn_clearData(t.currentTarget,"fictioneer_ajax_clear_my_follows",!0)})),_$(".button-clear-bookmarks")?.addEventListener("click",(t=>{fcn_dataDeletionPrompt(t.currentTarget)&&(fcn_bookmarks.data&&Object.keys(fcn_bookmarks.data).forEach((t=>fcn_removeBookmark(t))),t.currentTarget.closest(".card").querySelector(".card__content").innerHTML=fcn_profileDataTranslations.clearedSuccess,fcn_setBookmarks(fcn_bookmarks))}));
|
||||
function fcn_unsetOauth(t,e,n){const a=prompt(sprintf(_x("Are you sure? Note that if you disconnect all accounts, you may no longer be able to log back in once you log out. Enter %s to confirm.","Unset OAuth prompt.","fictioneer"),_x("delete","Prompt deletion confirmation string.","fictioneer").toUpperCase()));if(!a||a.toLowerCase()!=_x("delete","Prompt deletion confirmation string.","fictioneer").toLowerCase())return;const r=_$$$(`oauth-${e}`);r.classList.add("ajax-in-progress"),fcn_ajaxPost(payload={action:"fictioneer_ajax_unset_my_oauth",nonce:t,channel:e,id:n}).then((t=>{t.success?(r.classList.remove("_connected"),r.classList.add("_disconnected"),r.querySelector("button").remove(),fcn_showNotification(r.dataset.unset)):(r.style.background="var(--warning)",fcn_showNotification(t.data.error,5,"warning"))})).catch((t=>{t.status&&t.statusText&&(r.style.background="var(--warning)",fcn_showNotification(`${t.status}: ${t.statusText}`,5,"warning"))})).then((()=>{r.classList.remove("ajax-in-progress")}))}function fcn_deleteMyAccount(t){if(_$$$("button-delete-my-account").hasAttribute("disabled"))return;const e=prompt(sprintf(t.dataset.warning,_x("delete","Prompt deletion confirmation string.","fictioneer").toUpperCase()));e&&e.toLowerCase()==_x("delete","Prompt deletion confirmation string.","fictioneer").toLowerCase()&&(_$$$("button-delete-my-account").setAttribute("disabled",!0),fcn_ajaxPost({action:"fictioneer_ajax_delete_my_account",nonce:t.dataset.nonce,id:t.dataset.id}).then((t=>{t.success?location.reload():(fcn_showNotification(t.data.error,5,"warning"),_$$$("button-delete-my-account").innerHTML=t.data.button)})).catch((t=>{t.status&&t.statusText&&(fcn_showNotification(`${t.status}: ${t.statusText}`,5,"warning"),_$$$("button-delete-my-account").innerHTML=response.data.button)})))}_$$(".button-unset-oauth").forEach((t=>{t.addEventListener("click",(t=>{fcn_unsetOauth(t.currentTarget.dataset.nonce,t.currentTarget.dataset.channel,t.currentTarget.dataset.id)}))})),_$$$("button-delete-my-account")?.addEventListener("click",(t=>{fcn_deleteMyAccount(t.currentTarget)}));const fcn_profileDataTranslations=_$$$("profile-data-translations")?.dataset;function fcn_dataDeletionPrompt(t){const e=prompt(sprintf(t.dataset.warning,_x("delete","Prompt deletion confirmation string.","fictioneer").toUpperCase()));return!(!e||e.toLowerCase()!=_x("delete","Prompt deletion confirmation string.","fictioneer").toLowerCase())}function fcn_clearData(t,e){const n=t.closest(".card");localStorage.removeItem("fcnBookshelfContent"),n.classList.add("ajax-in-progress"),t.remove(),fcn_ajaxPost({action:e,fcn_fast_ajax:1,nonce:t.dataset.nonce}).then((t=>{t.success?n.querySelector(".card__content").innerHTML=t.data.success:fcn_showNotification(t.data.error,10,"warning")})).catch((t=>{t.status&&t.statusText&&fcn_showNotification(`${t.status}: ${t.statusText}`,10,"warning")})).then((()=>{n.classList.remove("ajax-in-progress")}))}_$(".button-clear-comments")?.addEventListener("click",(t=>{fcn_dataDeletionPrompt(t.currentTarget)&&fcn_clearData(t.currentTarget,"fictioneer_ajax_clear_my_comments")})),_$(".button-clear-comment-subscriptions")?.addEventListener("click",(t=>{fcn_dataDeletionPrompt(t.currentTarget)&&fcn_clearData(t.currentTarget,"fictioneer_ajax_clear_my_comment_subscriptions")})),_$(".button-clear-checkmarks")?.addEventListener("click",(t=>{if(!fcn_dataDeletionPrompt(t.currentTarget))return;const e=fcn_getUserData();e.checkmarks={data:{},updated:Date.now()},fcn_setUserData(e),fcn_updateCheckmarksView(),fcn_clearData(t.currentTarget,"fictioneer_ajax_clear_my_checkmarks",!0)})),_$(".button-clear-reminders")?.addEventListener("click",(t=>{if(!fcn_dataDeletionPrompt(t.currentTarget))return;const e=fcn_getUserData();e.reminders={data:{}},fcn_setUserData(e),fcn_updateRemindersView(),fcn_clearData(t.currentTarget,"fictioneer_ajax_clear_my_reminders",!0)})),_$(".button-clear-follows")?.addEventListener("click",(t=>{if(!fcn_dataDeletionPrompt(t.currentTarget))return;const e=fcn_getUserData();e.follows={data:{}},fcn_setUserData(e),fcn_updateFollowsView(),fcn_clearData(t.currentTarget,"fictioneer_ajax_clear_my_follows",!0)})),_$(".button-clear-bookmarks")?.addEventListener("click",(t=>{if(!fcn_dataDeletionPrompt(t.currentTarget))return;const e=fcn_getUserData();e.bookmarks="{}",fcn_setUserData(e),fcn_bookmarks.data={},t.currentTarget.closest(".card").querySelector(".card__content").innerHTML=fcn_profileDataTranslations.clearedSuccess,fcn_setBookmarks(fcn_bookmarks)}));
|
@ -604,4 +604,48 @@ function fictioneer_ajax_get_fingerprint() {
|
||||
}
|
||||
add_action( 'wp_ajax_fictioneer_ajax_get_fingerprint', 'fictioneer_ajax_get_fingerprint' );
|
||||
|
||||
// =============================================================================
|
||||
// GET BOOKMARKS FOR USERS - AJAX
|
||||
// =============================================================================
|
||||
|
||||
/**
|
||||
* Get an user's bookmarks via AJAX
|
||||
*
|
||||
* @since Fictioneer 4.0
|
||||
* @link https://developer.wordpress.org/reference/functions/wp_send_json_success/
|
||||
* @link https://developer.wordpress.org/reference/functions/wp_send_json_error/
|
||||
* @see fictioneer_get_validated_ajax_user()
|
||||
*/
|
||||
|
||||
function fictioneer_ajax_get_bookmarks() {
|
||||
// Enabled?
|
||||
if ( ! get_option( 'fictioneer_enable_bookmarks' ) ) {
|
||||
wp_send_json_error(
|
||||
array( 'error' => __( 'Not allowed.', 'fictioneer' ) ),
|
||||
403
|
||||
);
|
||||
}
|
||||
|
||||
// Setup and validations
|
||||
$user = fictioneer_get_validated_ajax_user();
|
||||
|
||||
if ( ! $user ) {
|
||||
wp_send_json_error( array( 'error' => __( 'Request did not pass validation.', 'fictioneer' ) ) );
|
||||
}
|
||||
|
||||
// Look for saved bookmarks on user...
|
||||
$bookmarks = get_user_meta( $user->ID, 'fictioneer_bookmarks', true );
|
||||
$bookmarks = $bookmarks ? $bookmarks : '{}';
|
||||
|
||||
// Response
|
||||
if ( $bookmarks ) {
|
||||
wp_send_json_success( array( 'bookmarks' => $bookmarks ) );
|
||||
}
|
||||
}
|
||||
|
||||
if ( get_option( 'fictioneer_enable_bookmarks' ) ) {
|
||||
add_action( 'wp_ajax_fictioneer_ajax_get_bookmarks', 'fictioneer_ajax_get_bookmarks' );
|
||||
}
|
||||
|
||||
|
||||
?>
|
||||
|
@ -297,8 +297,6 @@ function fcn_setLoggedInState(state, initialize = true) {
|
||||
// Setup local user data, but only if the login state has not been added
|
||||
// synchronous from local storage (avoid double initialize).
|
||||
if (initialize) {
|
||||
if (typeof fcn_getBookmarksForUser === 'function') fcn_getBookmarksForUser();
|
||||
if (typeof fcn_showChapterBookmark === 'function') fcn_showChapterBookmark();
|
||||
fcn_getProfileImage();
|
||||
}
|
||||
}
|
||||
|
@ -9,126 +9,54 @@ const /** @const {HTMLElement[]} */ fcn_jumpToBookmarkButtons = _$$('.button--bo
|
||||
/** @const {HTMLElement} */ fcn_bookmarksSmallCardBlock = _$('.bookmarks-block'),
|
||||
/** @const {HTMLElement} */ fcn_bookmarksSmallCardTemplate = _$('.bookmark-small-card-template');
|
||||
|
||||
var /** @type {Object} */ fcn_bookmarks = fcn_getBookmarks(),
|
||||
var /** @type {Object} */ fcn_bookmarks,
|
||||
/** @type {Number} */ fcn_userBookmarksTimeout;
|
||||
|
||||
// Initialize
|
||||
fcn_getBookmarksForUser();
|
||||
fcn_showChapterBookmark();
|
||||
fcn_initializeLocalBookmarks();
|
||||
|
||||
document.addEventListener('fcnUserDataReady', event => {
|
||||
fcn_initializeUserBookmarks(event);
|
||||
});
|
||||
|
||||
// =============================================================================
|
||||
// SAVE BOOKMARKS FOR USER
|
||||
// INITIALIZE
|
||||
// =============================================================================
|
||||
|
||||
/**
|
||||
* Save bookmarks JSON to the database via AJAX.
|
||||
* Initialize local bookmarks.
|
||||
*
|
||||
* @description Saves the bookmarks JSON to the database if an user is logged in,
|
||||
* otherwise the function aborts to avoid unnecessary requests. This can only
|
||||
* happen once every n seconds, as set by the timeout interval, to avoid further
|
||||
* unnecessary requests in case someone triggers multiple updates.
|
||||
* @description Looks for bookmarks in local storage, both for guests and logged-in
|
||||
* users. If none are found, an empty bookmarks JSON is created and set.
|
||||
*
|
||||
* @since 4.0
|
||||
* @param {String} value - The stringified bookmarks JSON to be saved.
|
||||
* @see fcn_isValidJSONString()
|
||||
*/
|
||||
|
||||
function fcn_saveBookmarksForUser(value) {
|
||||
// Do not proceed if not logged in
|
||||
if (!fcn_isLoggedIn) return;
|
||||
function fcn_initializeLocalBookmarks() {
|
||||
// Look for bookmarks in local storage
|
||||
fcn_bookmarks = fcn_getBookmarks();
|
||||
|
||||
// Reset AJAX threshold
|
||||
fcn_bookmarks['lastLoaded'] = 0;
|
||||
// Always update bookmarks in storage
|
||||
fcn_setBookmarks(fcn_bookmarks, true);
|
||||
|
||||
// Save to local storage
|
||||
localStorage.setItem('fcnChapterBookmarks', JSON.stringify(fcn_bookmarks));
|
||||
|
||||
// Payload
|
||||
const payload = {
|
||||
'action': 'fictioneer_ajax_save_bookmarks',
|
||||
'fcn_fast_ajax': 1,
|
||||
'bookmarks': value
|
||||
}
|
||||
|
||||
// Clear previous timeout (if still pending)
|
||||
clearTimeout(fcn_userBookmarksTimeout);
|
||||
|
||||
// Only one save request every n seconds
|
||||
fcn_userBookmarksTimeout = setTimeout(() => {
|
||||
fcn_ajaxPost(payload)
|
||||
.then((response) => {
|
||||
// Check for failure
|
||||
if (response.data.error) {
|
||||
fcn_showNotification(response.data.error, 3, 'warning');
|
||||
}
|
||||
})
|
||||
.catch((error) => {
|
||||
if (error.status && error.statusText) {
|
||||
fcn_showNotification(`${error.status}: ${error.statusText}`, 3, 'warning');
|
||||
}
|
||||
});
|
||||
}, fictioneer_ajax.post_debounce_rate); // Debounce synchronization
|
||||
// Update view
|
||||
fcn_updateBookmarksView();
|
||||
}
|
||||
|
||||
// =============================================================================
|
||||
// GET BOOKMARKS FOR USER
|
||||
// =============================================================================
|
||||
|
||||
/**
|
||||
* Fetch bookmarks JSON from database via AJAX and set it.
|
||||
* Initialize Bookmarks for logged-in users.
|
||||
*
|
||||
* @description Check whether to pull bookmarks for a logged-in user from the
|
||||
* database. This can only happen once every n seconds, as set by the difference
|
||||
* between the fcn_ajaxLimitThreshold and 'lastLoaded' node, in order to reduce
|
||||
* the number of requests if someone is just browsing.
|
||||
*
|
||||
* @since 4.0
|
||||
* @see fcn_setBookmarks()
|
||||
* @see fcn_showChapterBookmark()
|
||||
* @see fcn_updateBookmarkCards()
|
||||
* @since 5.7.0
|
||||
* @param {Event} event - The fcnUserDataReady event.
|
||||
*/
|
||||
|
||||
function fcn_getBookmarksForUser() {
|
||||
// Do not proceed if not logged in
|
||||
if (!fcn_isLoggedIn) {
|
||||
return;
|
||||
}
|
||||
function fcn_initializeUserBookmarks(event) {
|
||||
// Always update bookmarks in storage
|
||||
fcn_setBookmarks(JSON.parse(event.detail.data.bookmarks), true);
|
||||
|
||||
// Only update from server after some time has passed (e.g. 60 seconds)
|
||||
if (fcn_ajaxLimitThreshold < fcn_bookmarks['lastLoaded']) {
|
||||
if (Object.keys(fcn_bookmarks.data).length > 0) fcn_updateBookmarkCards();
|
||||
return;
|
||||
}
|
||||
|
||||
// Request
|
||||
fcn_ajaxGet({
|
||||
'action': 'fictioneer_ajax_get_bookmarks',
|
||||
'fcn_fast_ajax': 1
|
||||
})
|
||||
.then((response) => {
|
||||
// Check for success
|
||||
if (response.success) {
|
||||
// Unpack
|
||||
let bookmarks = response.data.bookmarks;
|
||||
|
||||
// Validate
|
||||
bookmarks = fcn_isValidJSONString(bookmarks) ? bookmarks : '{}';
|
||||
bookmarks = JSON.parse(bookmarks);
|
||||
|
||||
if (Object.keys(bookmarks).length > 2) {
|
||||
bookmarks = {};
|
||||
}
|
||||
|
||||
// Setup
|
||||
if (typeof bookmarks === 'object' && bookmarks.data) {
|
||||
bookmarks['lastLoaded'] = Date.now();
|
||||
fcn_setBookmarks(bookmarks, true);
|
||||
fcn_showChapterBookmark();
|
||||
}
|
||||
}
|
||||
|
||||
// Regardless of success
|
||||
fcn_updateBookmarkCards();
|
||||
});
|
||||
// Update view
|
||||
fcn_updateBookmarksView();
|
||||
}
|
||||
|
||||
// =============================================================================
|
||||
@ -136,46 +64,20 @@ function fcn_getBookmarksForUser() {
|
||||
// =============================================================================
|
||||
|
||||
/**
|
||||
* Get bookmarks JSON from local storage or create new one.
|
||||
* Initialize bookmarks from local storage.
|
||||
*
|
||||
* @description Looks for bookmarks in local storage, both for guests and logged-in
|
||||
* users. If none are found, an empty bookmarks JSON is created, set, and returned.
|
||||
*
|
||||
* @since 4.0
|
||||
* @since 5.7.0
|
||||
* @see fcn_isValidJSONString()
|
||||
* @return {Object} The bookmarks JSON.
|
||||
*/
|
||||
|
||||
function fcn_getBookmarks() {
|
||||
// Look for bookmarks in local storage
|
||||
let b = localStorage.getItem('fcnChapterBookmarks');
|
||||
fcn_bookmarks = localStorage.getItem('fcnChapterBookmarks');
|
||||
|
||||
// Check for valid JSON and create new one if not found
|
||||
b = (b && fcn_isValidJSONString(b)) ? JSON.parse(b) : { 'lastLoaded': 0, 'data': {} };
|
||||
|
||||
// Always update bookmarks in storage
|
||||
fcn_setBookmarks(b, true);
|
||||
|
||||
// Render bookmark cards if no AJAX request following
|
||||
if (!fcn_isLoggedIn) {
|
||||
fcn_updateBookmarkCards();
|
||||
}
|
||||
|
||||
// Insert bookmarks count on user profile page
|
||||
const stats = _$('.profile-bookmarks-stats');
|
||||
|
||||
if (stats) {
|
||||
stats.innerHTML = stats.innerHTML.replace('%s', Object.keys(b.data).length);
|
||||
}
|
||||
|
||||
if (Object.keys(b.data).length > 0) {
|
||||
_$$('.icon-menu-bookmarks').forEach(element => {
|
||||
element.classList.remove('hidden');
|
||||
});
|
||||
}
|
||||
|
||||
// Return bookmarks JSON
|
||||
return b;
|
||||
return (fcn_bookmarks && fcn_isValidJSONString(fcn_bookmarks)) ?
|
||||
JSON.parse(fcn_bookmarks) : { 'data': {} };
|
||||
}
|
||||
|
||||
// =============================================================================
|
||||
@ -192,7 +94,7 @@ function fcn_getBookmarks() {
|
||||
* unfinished requests can be cancelled without loss of data.
|
||||
*
|
||||
* @since 4.0
|
||||
* @see fcn_saveBookmarksForUser()
|
||||
* @see fcn_saveUserBookmarks()
|
||||
* @param {Object} value - The bookmarks JSON to be set.
|
||||
* @param {Boolean} [silent=false] - Whether or not to update the database.
|
||||
*/
|
||||
@ -205,16 +107,110 @@ function fcn_setBookmarks(value, silent = false) {
|
||||
|
||||
// Keep global updated
|
||||
fcn_bookmarks = value;
|
||||
|
||||
// Save to local storage
|
||||
localStorage.setItem('fcnChapterBookmarks', JSON.stringify(value));
|
||||
|
||||
// Do not save to database if silent update
|
||||
if (silent) return;
|
||||
// Keep user data updated as well
|
||||
if (fcn_isLoggedIn) {
|
||||
const currentUserData = fcn_getUserData();
|
||||
|
||||
// Update database for user; cancel any enqueued update via the timeout
|
||||
window.clearTimeout(fcn_userBookmarksTimeout);
|
||||
fcn_saveBookmarksForUser(JSON.stringify(value));
|
||||
if (currentUserData) {
|
||||
currentUserData.bookmarks = JSON.stringify(value);
|
||||
fcn_setUserData(currentUserData);
|
||||
}
|
||||
}
|
||||
|
||||
// Do not save to database if silent update
|
||||
if (silent) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Update database for user
|
||||
fcn_saveUserBookmarks(JSON.stringify(value));
|
||||
}
|
||||
|
||||
// =============================================================================
|
||||
// UPDATE BOOKMARKS VIEW
|
||||
// =============================================================================
|
||||
|
||||
/**
|
||||
* Updates the view with the current Bookmarks state.
|
||||
*
|
||||
* @since 5.7.0
|
||||
*/
|
||||
|
||||
function fcn_updateBookmarksView() {
|
||||
// Abort if bookmarks are not set
|
||||
if (!fcn_bookmarks) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Setup
|
||||
const stats = _$('.profile-bookmarks-stats'),
|
||||
count = Object.keys(fcn_bookmarks.data).length;
|
||||
|
||||
// Insert bookmarks count on user profile page
|
||||
if (stats) {
|
||||
stats.innerHTML = stats.innerHTML.replace('%s', count);
|
||||
}
|
||||
|
||||
// Bookmark icons
|
||||
if (count > 0) {
|
||||
_$$('.icon-menu-bookmarks').forEach(element => {
|
||||
element.classList.remove('hidden');
|
||||
});
|
||||
}
|
||||
|
||||
// Render bookmark cards if already logged-in
|
||||
fcn_showBookmarkCards();
|
||||
|
||||
// Chapter bookmark
|
||||
fcn_showChapterBookmark();
|
||||
}
|
||||
|
||||
// =============================================================================
|
||||
// SAVE USER BOOKMARKS
|
||||
// =============================================================================
|
||||
|
||||
/**
|
||||
* Save bookmarks JSON to the database via AJAX.
|
||||
*
|
||||
* @description Saves the bookmarks JSON to the database if an user is logged in,
|
||||
* otherwise the function aborts to avoid unnecessary requests. This can only
|
||||
* happen once every n seconds, as set by the timeout interval, to avoid further
|
||||
* unnecessary requests in case someone triggers multiple updates.
|
||||
*
|
||||
* @since 4.0
|
||||
* @param {String} value - The stringified bookmarks JSON to be saved.
|
||||
*/
|
||||
|
||||
function fcn_saveUserBookmarks(value) {
|
||||
// Do not proceed if not logged in
|
||||
if (!fcn_isLoggedIn) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Clear previous timeout (if still pending)
|
||||
clearTimeout(fcn_userBookmarksTimeout);
|
||||
|
||||
// Only one save request every n seconds
|
||||
fcn_userBookmarksTimeout = setTimeout(() => {
|
||||
fcn_ajaxPost({
|
||||
'action': 'fictioneer_ajax_save_bookmarks',
|
||||
'fcn_fast_ajax': 1,
|
||||
'bookmarks': value
|
||||
})
|
||||
.then(response => {
|
||||
// Check for failure
|
||||
if (response.data.error) {
|
||||
fcn_showNotification(response.data.error, 3, 'warning');
|
||||
}
|
||||
})
|
||||
.catch(error => {
|
||||
if (error.status && error.statusText) {
|
||||
fcn_showNotification(`${error.status}: ${error.statusText}`, 3, 'warning');
|
||||
}
|
||||
});
|
||||
}, fictioneer_ajax.post_debounce_rate); // Debounce synchronization
|
||||
}
|
||||
|
||||
// =============================================================================
|
||||
@ -428,14 +424,17 @@ function fcn_setMobileMenuBookmarks() {
|
||||
* @see fcn_bookmarkDeleteHandler()
|
||||
*/
|
||||
|
||||
function fcn_updateBookmarkCards() {
|
||||
// Check whether there are bookmark cards to render
|
||||
function fcn_showBookmarkCards() {
|
||||
// Check whether bookmark cards need to be rendered
|
||||
if (
|
||||
!fcn_bookmarks ||
|
||||
!fcn_bookmarksSmallCardBlock ||
|
||||
!fcn_bookmarksSmallCardTemplate ||
|
||||
Object.keys(fcn_bookmarks.data).length < 1
|
||||
) return;
|
||||
Object.keys(fcn_bookmarks.data).length < 1 ||
|
||||
_$('.bookmark-card')
|
||||
) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Make block visible
|
||||
fcn_bookmarksSmallCardBlock.classList.remove('hidden');
|
||||
|
@ -122,8 +122,7 @@ function fcn_toggleFollow(storyId) {
|
||||
// =============================================================================
|
||||
|
||||
/**
|
||||
* Updates the view to reflect the current Follows state and saves the JSON
|
||||
* to local storage.
|
||||
* Updates the view with the current Follows state.
|
||||
*
|
||||
* @since 4.3
|
||||
*/
|
||||
|
@ -118,8 +118,7 @@ function fcn_toggleReminder(storyId) {
|
||||
// =============================================================================
|
||||
|
||||
/**
|
||||
* Updates the view to reflect the current Reminders state and saves the JSON
|
||||
* to local storage.
|
||||
* Updates the view with the current Reminders state.
|
||||
*
|
||||
* @since 5.0
|
||||
*/
|
||||
|
@ -274,6 +274,8 @@ _$('.button-clear-checkmarks')?.addEventListener(
|
||||
const currentUserData = fcn_getUserData();
|
||||
currentUserData.checkmarks = { 'data': {}, 'updated': Date.now() };
|
||||
fcn_setUserData(currentUserData);
|
||||
|
||||
// Update views
|
||||
fcn_updateCheckmarksView();
|
||||
|
||||
// Clear data
|
||||
@ -298,6 +300,8 @@ _$('.button-clear-reminders')?.addEventListener(
|
||||
const currentUserData = fcn_getUserData();
|
||||
currentUserData.reminders = { 'data': {} };
|
||||
fcn_setUserData(currentUserData);
|
||||
|
||||
// Update view
|
||||
fcn_updateRemindersView();
|
||||
|
||||
// Clear data
|
||||
@ -322,6 +326,8 @@ _$('.button-clear-follows')?.addEventListener(
|
||||
const currentUserData = fcn_getUserData();
|
||||
currentUserData.follows = { 'data': {} };
|
||||
fcn_setUserData(currentUserData);
|
||||
|
||||
// Update view
|
||||
fcn_updateFollowsView();
|
||||
|
||||
// Clear data
|
||||
@ -338,15 +344,20 @@ _$('.button-clear-bookmarks')?.addEventListener(
|
||||
'click',
|
||||
e => {
|
||||
// Confirm clear request using localized string
|
||||
if (!fcn_dataDeletionPrompt(e.currentTarget)) return;
|
||||
|
||||
// Remove bookmarks
|
||||
if (fcn_bookmarks.data) {
|
||||
Object.keys(fcn_bookmarks.data).forEach(id => fcn_removeBookmark(id));
|
||||
if (!fcn_dataDeletionPrompt(e.currentTarget)) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Update database and view
|
||||
// Remove bookmarks
|
||||
const currentUserData = fcn_getUserData();
|
||||
currentUserData.bookmarks = '{}';
|
||||
fcn_setUserData(currentUserData);
|
||||
fcn_bookmarks.data = {};
|
||||
|
||||
// Update view
|
||||
e.currentTarget.closest('.card').querySelector('.card__content').innerHTML = fcn_profileDataTranslations.clearedSuccess;
|
||||
|
||||
// Update local storage and database
|
||||
fcn_setBookmarks(fcn_bookmarks);
|
||||
}
|
||||
);
|
||||
|
Loading…
x
Reference in New Issue
Block a user