Fortify follows and reminders data structure

This commit is contained in:
Tetrakern 2024-12-30 07:09:30 +01:00
parent 6b907f5079
commit b7fbfdc899
6 changed files with 23 additions and 4 deletions

4
js/complete.min.js vendored

File diff suppressed because one or more lines are too long

2
js/follows.min.js vendored
View File

@ -1 +1 @@
function fcn_toggleFollow(t,e=null){const s=window.FictioneerApp.Controllers.fictioneerFollows;if(!s)return void fcn_showNotification("Error: Follows Controller not connected.",3,"warning");const a=FcnUtils.userData();(e=e??!a.follows.data[t])?a.follows.data[t]={story_id:parseInt(t),timestamp:Date.now()}:delete a.follows.data[t],a.lastLoaded=0,FcnUtils.setUserData(a),s.refreshView(),clearTimeout(s.timeout),s.timeout=setTimeout((()=>{FcnUtils.remoteAction("fictioneer_ajax_toggle_follow",{payload:{set:e,story_id:t}})}),FcnGlobals.debounceRate)}application.register("fictioneer-follows",class extends Stimulus.Controller{static get targets(){return["toggleButton","newDisplay","scrollList","mobileScrollList","mobileMarkRead"]}followsLoaded=!1;markedRead=!1;timeout=0;initialize(){fcn()?.userReady?this.#t=!0:document.addEventListener("fcnUserDataReady",(()=>{this.refreshView(),this.#t=!0,this.#e()}))}connect(){window.FictioneerApp.Controllers.fictioneerFollows=this,this.#t&&(this.refreshView(),this.#e())}data(){return this.followsCachedData=FcnUtils.userData().follows?.data,Array.isArray(this.followsCachedData)&&0===this.followsCachedData.length&&(this.followsCachedData={}),this.followsCachedData}isFollowed(t){return!(!FcnUtils.loggedIn()||!this.data()?.[t])}unreadCount(){return parseInt(FcnUtils.userData()?.follows?.new??0)}toggleFollow({params:{id:t}}){this.#s()&&(fcn_toggleFollow(t,!this.isFollowed(t)),this.refreshView())}clear(){const t=FcnUtils.userData();t.follows={data:{}},fcn().setUserData(t),this.refreshView()}refreshView(){this.toggleButtonTargets.forEach((t=>{const e=t.dataset.storyId;t.classList.toggle("_followed",this.isFollowed(e))}));const t=this.unreadCount();this.newDisplayTargets.forEach((e=>{e.classList.toggle("_new",t>0),t>0&&(e.dataset.newCount=t,this.hasMobileMarkReadTarget&&this.mobileMarkReadTarget.classList.remove("hidden"))}))}loadFollowsHtml(){this.followsLoaded||FcnUtils.aGet({action:"fictioneer_ajax_get_follows_notifications",fcn_fast_ajax:1}).then((t=>{t.data.html&&(this.hasScrollListTarget&&(this.scrollListTarget.innerHTML=t.data.html),this.hasMobileScrollListTarget&&(this.mobileScrollListTarget.innerHTML=t.data.html),!1===FcnUtils.userData().loggedIn&&(fcn().removeUserData(),fcn().fetchUserData()))})).catch((t=>{429===t.status?fcn_showNotification(fictioneer_tl.notification.slowDown,3,"warning"):t.status&&t.statusText&&fcn_showNotification(`${t.status}: ${t.statusText}`,5,"warning"),this.hasScrollListTarget&&this.scrollListTarget.remove(),this.hasMobileScrollListTarget&&this.mobileScrollListTarget.remove()})).then((()=>{this.followsLoaded=!0,this.hasNewDisplayTarget&&this.newDisplayTargets.forEach((t=>{t.classList.add("_loaded")}))}))}markRead(){if(!this.followsLoaded&&this.unreadCount()>0||this.markedRead)return;this.markedRead=!0,this.newDisplayTargets.forEach((t=>{t.classList.remove("_new")})),this.hasMobileMarkReadTarget&&this.mobileMarkReadTarget.classList.add("hidden");const t=FcnUtils.userData();t.new=0,t.lastLoaded=0,FcnUtils.setUserData(t),FcnUtils.aPost({action:"fictioneer_ajax_mark_follows_read",fcn_fast_ajax:1}).catch((t=>{t.status&&t.statusText&&fcn_showNotification(`${t.status}: ${t.statusText}`,5,"warning")}))}#t=!1;#a=!1;#s(){const t=FcnUtils.loggedIn();return t||(this.#i(),this.#a=!0),t}#o(){return this.#s()&&JSON.stringify(this.followsCachedData??0)!==JSON.stringify(this.data())}#l(){this.refreshInterval||(this.refreshInterval=setInterval((()=>{!this.#a&&this.#o()&&this.refreshView()}),3e4+1e3*Math.random()))}#e(){this.#l(),this.visibilityStateCheck=()=>{this.#s()&&("visible"===document.visibilityState?(this.#a=!1,this.refreshView(),this.#l()):(this.#a=!0,clearInterval(this.refreshInterval),this.refreshInterval=null))},document.addEventListener("visibilitychange",this.visibilityStateCheck)}#i(){clearInterval(this.refreshInterval),document.removeEventListener("visibilitychange",this.visibilityStateCheck)}}); function fcn_toggleFollow(t,e=null){const s=window.FictioneerApp.Controllers.fictioneerFollows;if(!s)return void fcn_showNotification("Error: Follows Controller not connected.",3,"warning");const a=FcnUtils.userData();("object"!=typeof a.follows.data||null===a.follows.data||Array.isArray(a.follows.data))&&(a.follows.data={}),(e=e??!a.follows.data[t])?a.follows.data[t]={story_id:parseInt(t),timestamp:Date.now()}:delete a.follows.data[t],a.lastLoaded=0,FcnUtils.setUserData(a),s.refreshView(),clearTimeout(s.timeout),s.timeout=setTimeout((()=>{FcnUtils.remoteAction("fictioneer_ajax_toggle_follow",{payload:{set:e,story_id:t}})}),FcnGlobals.debounceRate)}application.register("fictioneer-follows",class extends Stimulus.Controller{static get targets(){return["toggleButton","newDisplay","scrollList","mobileScrollList","mobileMarkRead"]}followsLoaded=!1;markedRead=!1;timeout=0;initialize(){fcn()?.userReady?this.#t=!0:document.addEventListener("fcnUserDataReady",(()=>{this.refreshView(),this.#t=!0,this.#e()}))}connect(){window.FictioneerApp.Controllers.fictioneerFollows=this,this.#t&&(this.refreshView(),this.#e())}data(){return this.followsCachedData=FcnUtils.userData().follows?.data,Array.isArray(this.followsCachedData)&&0===this.followsCachedData.length&&(this.followsCachedData={}),this.followsCachedData}isFollowed(t){return!(!FcnUtils.loggedIn()||!this.data()?.[t])}unreadCount(){return parseInt(FcnUtils.userData()?.follows?.new??0)}toggleFollow({params:{id:t}}){this.#s()&&(fcn_toggleFollow(t,!this.isFollowed(t)),this.refreshView())}clear(){const t=FcnUtils.userData();t.follows={data:{}},fcn().setUserData(t),this.refreshView()}refreshView(){this.toggleButtonTargets.forEach((t=>{const e=t.dataset.storyId;t.classList.toggle("_followed",this.isFollowed(e))}));const t=this.unreadCount();this.newDisplayTargets.forEach((e=>{e.classList.toggle("_new",t>0),t>0&&(e.dataset.newCount=t,this.hasMobileMarkReadTarget&&this.mobileMarkReadTarget.classList.remove("hidden"))}))}loadFollowsHtml(){this.followsLoaded||FcnUtils.aGet({action:"fictioneer_ajax_get_follows_notifications",fcn_fast_ajax:1}).then((t=>{t.data.html&&(this.hasScrollListTarget&&(this.scrollListTarget.innerHTML=t.data.html),this.hasMobileScrollListTarget&&(this.mobileScrollListTarget.innerHTML=t.data.html),!1===FcnUtils.userData().loggedIn&&(fcn().removeUserData(),fcn().fetchUserData()))})).catch((t=>{429===t.status?fcn_showNotification(fictioneer_tl.notification.slowDown,3,"warning"):t.status&&t.statusText&&fcn_showNotification(`${t.status}: ${t.statusText}`,5,"warning"),this.hasScrollListTarget&&this.scrollListTarget.remove(),this.hasMobileScrollListTarget&&this.mobileScrollListTarget.remove()})).then((()=>{this.followsLoaded=!0,this.hasNewDisplayTarget&&this.newDisplayTargets.forEach((t=>{t.classList.add("_loaded")}))}))}markRead(){if(!this.followsLoaded&&this.unreadCount()>0||this.markedRead)return;this.markedRead=!0,this.newDisplayTargets.forEach((t=>{t.classList.remove("_new")})),this.hasMobileMarkReadTarget&&this.mobileMarkReadTarget.classList.add("hidden");const t=FcnUtils.userData();t.new=0,t.lastLoaded=0,FcnUtils.setUserData(t),FcnUtils.aPost({action:"fictioneer_ajax_mark_follows_read",fcn_fast_ajax:1}).catch((t=>{t.status&&t.statusText&&fcn_showNotification(`${t.status}: ${t.statusText}`,5,"warning")}))}#t=!1;#a=!1;#s(){const t=FcnUtils.loggedIn();return t||(this.#i(),this.#a=!0),t}#o(){return this.#s()&&JSON.stringify(this.followsCachedData??0)!==JSON.stringify(this.data())}#l(){this.refreshInterval||(this.refreshInterval=setInterval((()=>{!this.#a&&this.#o()&&this.refreshView()}),3e4+1e3*Math.random()))}#e(){this.#l(),this.visibilityStateCheck=()=>{this.#s()&&("visible"===document.visibilityState?(this.#a=!1,this.refreshView(),this.#l()):(this.#a=!0,clearInterval(this.refreshInterval),this.refreshInterval=null))},document.addEventListener("visibilitychange",this.visibilityStateCheck)}#i(){clearInterval(this.refreshInterval),document.removeEventListener("visibilitychange",this.visibilityStateCheck)}});

2
js/reminders.min.js vendored
View File

@ -1 +1 @@
function fcn_toggleReminder(e,t=null){const i=window.FictioneerApp.Controllers.fictioneerReminders;if(!i)return void fcn_showNotification("Error: Reminders Controller not connected.",3,"warning");const r=FcnUtils.userData();(t=t??!r.reminders.data[e])?r.reminders.data[e]={story_id:parseInt(e),timestamp:Date.now()}:delete r.reminders.data[e],r.lastLoaded=0,FcnUtils.setUserData(r),i.refreshView(),clearTimeout(i.timeout),i.timeout=setTimeout((()=>{FcnUtils.remoteAction("fictioneer_ajax_toggle_reminder",{payload:{set:t,story_id:e}})}),FcnGlobals.debounceRate)}application.register("fictioneer-reminders",class extends Stimulus.Controller{static get targets(){return["toggleButton"]}remindersLoaded=!1;timeout=0;initialize(){fcn()?.userReady?this.#e=!0:document.addEventListener("fcnUserDataReady",(()=>{this.refreshView(),this.#e=!0,this.#t()}))}connect(){window.FictioneerApp.Controllers.fictioneerReminders=this,this.#e&&(this.refreshView(),this.#t())}data(){return this.remindersCachedData=FcnUtils.userData().reminders?.data,Array.isArray(this.remindersCachedData)&&0===this.remindersCachedData.length&&(this.remindersCachedData={}),this.remindersCachedData}isRemembered(e){return!(!FcnUtils.loggedIn()||!this.data()?.[e])}toggleReminder({params:{id:e}}){this.#i()&&(fcn_toggleReminder(e,!this.isRemembered(e)),this.refreshView())}clear(){const e=FcnUtils.userData();e.reminders={data:{}},fcn().setUserData(e),this.refreshView()}refreshView(){this.toggleButtonTargets.forEach((e=>{const t=e.dataset.storyId;e.classList.toggle("_remembered",this.isRemembered(t))}))}#e=!1;#r=!1;#i(){const e=FcnUtils.loggedIn();return e||(this.#s(),this.#r=!0),e}#a(){return this.#i()&&JSON.stringify(this.remindersCachedData??0)!==JSON.stringify(this.data())}#n(){this.refreshInterval||(this.refreshInterval=setInterval((()=>{!this.#r&&this.#a()&&this.refreshView()}),3e4+1e3*Math.random()))}#t(){this.#n(),this.visibilityStateCheck=()=>{this.#i()&&("visible"===document.visibilityState?(this.#r=!1,this.refreshView(),this.#n()):(this.#r=!0,clearInterval(this.refreshInterval),this.refreshInterval=null))},document.addEventListener("visibilitychange",this.visibilityStateCheck)}#s(){clearInterval(this.refreshInterval),document.removeEventListener("visibilitychange",this.visibilityStateCheck)}}); function fcn_toggleReminder(e,t=null){const r=window.FictioneerApp.Controllers.fictioneerReminders;if(!r)return void fcn_showNotification("Error: Reminders Controller not connected.",3,"warning");const i=FcnUtils.userData();("object"!=typeof i.reminders.data||null===i.reminders.data||Array.isArray(i.reminders.data))&&(i.reminders.data={}),(t=t??!i.reminders.data[e])?i.reminders.data[e]={story_id:parseInt(e),timestamp:Date.now()}:delete i.reminders.data[e],i.lastLoaded=0,FcnUtils.setUserData(i),r.refreshView(),clearTimeout(r.timeout),r.timeout=setTimeout((()=>{FcnUtils.remoteAction("fictioneer_ajax_toggle_reminder",{payload:{set:t,story_id:e}})}),FcnGlobals.debounceRate)}application.register("fictioneer-reminders",class extends Stimulus.Controller{static get targets(){return["toggleButton"]}remindersLoaded=!1;timeout=0;initialize(){fcn()?.userReady?this.#e=!0:document.addEventListener("fcnUserDataReady",(()=>{this.refreshView(),this.#e=!0,this.#t()}))}connect(){window.FictioneerApp.Controllers.fictioneerReminders=this,this.#e&&(this.refreshView(),this.#t())}data(){return this.remindersCachedData=FcnUtils.userData().reminders?.data,Array.isArray(this.remindersCachedData)&&0===this.remindersCachedData.length&&(this.remindersCachedData={}),this.remindersCachedData}isRemembered(e){return!(!FcnUtils.loggedIn()||!this.data()?.[e])}toggleReminder({params:{id:e}}){this.#r()&&(fcn_toggleReminder(e,!this.isRemembered(e)),this.refreshView())}clear(){const e=FcnUtils.userData();e.reminders={data:{}},fcn().setUserData(e),this.refreshView()}refreshView(){this.toggleButtonTargets.forEach((e=>{const t=e.dataset.storyId;e.classList.toggle("_remembered",this.isRemembered(t))}))}#e=!1;#i=!1;#r(){const e=FcnUtils.loggedIn();return e||(this.#s(),this.#i=!0),e}#a(){return this.#r()&&JSON.stringify(this.remindersCachedData??0)!==JSON.stringify(this.data())}#n(){this.refreshInterval||(this.refreshInterval=setInterval((()=>{!this.#i&&this.#a()&&this.refreshView()}),3e4+1e3*Math.random()))}#t(){this.#n(),this.visibilityStateCheck=()=>{this.#r()&&("visible"===document.visibilityState?(this.#i=!1,this.refreshView(),this.#n()):(this.#i=!0,clearInterval(this.refreshInterval),this.refreshInterval=null))},document.addEventListener("visibilitychange",this.visibilityStateCheck)}#s(){clearInterval(this.refreshInterval),document.removeEventListener("visibilitychange",this.visibilityStateCheck)}});

View File

@ -222,6 +222,7 @@ function fcn_toggleCheckmark(storyId, chapterId = null, set = null) {
type = 'chapter'; type = 'chapter';
} }
// Ensure data object is properly initialized
if ( if (
typeof userData.checkmarks.data !== 'object' || typeof userData.checkmarks.data !== 'object' ||
userData.checkmarks.data === null || userData.checkmarks.data === null ||

View File

@ -258,6 +258,15 @@ function fcn_toggleFollow(storyId, set = null) {
const userData = FcnUtils.userData(); const userData = FcnUtils.userData();
// Ensure data object is properly initialized
if (
typeof userData.follows.data !== 'object' ||
userData.follows.data === null ||
Array.isArray(userData.follows.data)
) {
userData.follows.data = {};
}
// Decide force if not given // Decide force if not given
set = set ?? !userData.follows.data[storyId]; set = set ?? !userData.follows.data[storyId];

View File

@ -153,6 +153,15 @@ function fcn_toggleReminder(storyId, set = null) {
const userData = FcnUtils.userData(); const userData = FcnUtils.userData();
// Ensure data object is properly initialized
if (
typeof userData.reminders.data !== 'object' ||
userData.reminders.data === null ||
Array.isArray(userData.reminders.data)
) {
userData.reminders.data = {};
}
// Decide force if not given // Decide force if not given
set = set ?? !userData.reminders.data[storyId]; set = set ?? !userData.reminders.data[storyId];