@@ -177,6 +177,67 @@ function setIconAndLabelElement(parentElement, iconName, labelText) {
177177 }
178178}
179179
180+ /**
181+ * Set the button to a loading state and return a clone of the original button element.
182+ *
183+ * @param {Element } buttonElement - The button element to set to loading state.
184+ * @return {Element } The original button element cloned before modification.
185+ */
186+ function setButtonToLoadingState ( buttonElement ) {
187+ const originalButtonElement = buttonElement . cloneNode ( true ) ;
188+
189+ buttonElement . textContent = "" ;
190+ buttonElement . appendChild ( createIconLabelElement ( buttonElement . dataset . labelLoading ) ) ;
191+
192+ return originalButtonElement ;
193+ }
194+
195+ /**
196+ * Restore the button to its original state.
197+ *
198+ * @param {Element } buttonElement The button element to restore.
199+ * @param {Element } originalButtonElement The original button element to restore from.
200+ * @returns {void }
201+ */
202+ function restoreButtonState ( buttonElement , originalButtonElement ) {
203+ buttonElement . textContent = "" ;
204+ buttonElement . appendChild ( originalButtonElement ) ;
205+ }
206+
207+ /**
208+ * Set the button to a saved state.
209+ *
210+ * @param {Element } buttonElement The button element to set to saved state.
211+ */
212+ function setButtonToSavedState ( buttonElement ) {
213+ buttonElement . dataset . completed = "true" ;
214+ setIconAndLabelElement ( buttonElement , "save" , buttonElement . dataset . labelDone ) ;
215+ }
216+
217+ /**
218+ * Set the bookmark button state.
219+ *
220+ * @param {Element } buttonElement - The button element to update.
221+ * @param {string } newState - The new state to set ("star" or "unstar").
222+ */
223+ function setBookmarkButtonState ( buttonElement , newState ) {
224+ buttonElement . dataset . value = newState ;
225+ const iconType = newState === "star" ? "unstar" : "star" ;
226+ setIconAndLabelElement ( buttonElement , iconType , buttonElement . dataset [ newState === "star" ? "labelUnstar" : "labelStar" ] ) ;
227+ }
228+
229+ /**
230+ * Set the read status button state.
231+ *
232+ * @param {Element } buttonElement - The button element to update.
233+ * @param {string } newState - The new state to set ("read" or "unread").
234+ */
235+ function setReadStatusButtonState ( buttonElement , newState ) {
236+ buttonElement . dataset . value = newState ;
237+ const iconType = newState === "read" ? "unread" : "read" ;
238+ setIconAndLabelElement ( buttonElement , iconType , buttonElement . dataset [ newState === "read" ? "labelUnread" : "labelRead" ] ) ;
239+ }
240+
180241/**
181242 * Show a toast notification.
182243 *
@@ -202,29 +263,7 @@ function showToastNotification(iconType, notificationMessage) {
202263
203264 document . body . appendChild ( toastElementWrapper ) ;
204265
205- setTimeout ( ( ) => {
206- toastElementWrapper . classList . add ( "toast-animate" ) ;
207-
208- } , 100 ) ;
209- }
210-
211- /**
212- * Insert an icon label element into the parent element.
213- *
214- * @param {Element } parentElement The parent element to insert the icon label into.
215- * @param {string } iconLabelText The text to display in the icon label.
216- * @param {boolean } clearParentTextcontent If true, clear the parent's text content before appending the icon label.
217- * @returns {void }
218- */
219- function insertIconLabelElement ( parentElement , iconLabelText , clearParentTextcontent = true ) {
220- const span = document . createElement ( 'span' ) ;
221- span . classList . add ( 'icon-label' ) ;
222- span . textContent = iconLabelText ;
223-
224- if ( clearParentTextcontent ) {
225- parentElement . textContent = '' ;
226- }
227- parentElement . appendChild ( span ) ;
266+ setTimeout ( ( ) => toastElementWrapper . classList . add ( "toast-animate" ) , 100 ) ;
228267}
229268
230269/**
@@ -584,36 +623,21 @@ function handleEntryStatus(navigationDirection, element, setToRead) {
584623 */
585624function toggleEntryStatus ( element , toasting ) {
586625 const entryID = parseInt ( element . dataset . id , 10 ) ;
587- const link = element . querySelector ( ":is(a, button)[data-toggle-status]" ) ;
588- if ( ! link ) {
589- return ;
590- }
626+ const buttonElement = element . querySelector ( ":is(a, button)[data-toggle-status]" ) ;
627+ if ( ! buttonElement ) return ;
591628
592- const currentStatus = link . dataset . value ;
629+ const currentStatus = buttonElement . dataset . value ;
593630 const newStatus = currentStatus === "read" ? "unread" : "read" ;
594631
595- link . querySelector ( "span" ) . textContent = link . dataset . labelLoading ;
632+ setButtonToLoadingState ( buttonElement ) ;
633+
596634 updateEntriesStatus ( [ entryID ] , newStatus , ( ) => {
597- let iconElement , label ;
635+ setReadStatusButtonState ( buttonElement , newStatus ) ;
598636
599- if ( currentStatus === "read" ) {
600- iconElement = document . querySelector ( "template#icon-read" ) ;
601- label = link . dataset . labelRead ;
602- if ( toasting ) {
603- showToastNotification ( "read" , link . dataset . toastUnread ) ;
604- }
605- } else {
606- iconElement = document . querySelector ( "template#icon-unread" ) ;
607- label = link . dataset . labelUnread ;
608- if ( toasting ) {
609- showToastNotification ( "unread" , link . dataset . toastUnread ) ;
610- }
637+ if ( toasting ) {
638+ showToastNotification ( currentStatus , currentStatus === "read" ? buttonElement . dataset . toastUnread : buttonElement . dataset . toastRead ) ;
611639 }
612640
613- link . replaceChildren ( iconElement . content . cloneNode ( true ) ) ;
614- insertIconLabelElement ( link , label , false ) ;
615- link . dataset . value = newStatus ;
616-
617641 if ( element . classList . contains ( "item-status-" + currentStatus ) ) {
618642 element . classList . remove ( "item-status-" + currentStatus ) ;
619643 element . classList . add ( "item-status-" + newStatus ) ;
@@ -667,11 +691,10 @@ function handleSaveEntryAction(element = null) {
667691 const buttonElement = currentEntry . querySelector ( ":is(a, button)[data-save-entry]" ) ;
668692 if ( ! buttonElement || buttonElement . dataset . completed ) return ;
669693
670- insertIconLabelElement ( buttonElement , buttonElement . dataset . labelLoading ) ;
694+ setButtonToLoadingState ( buttonElement ) ;
671695
672696 sendPOSTRequest ( buttonElement . dataset . saveUrl ) . then ( ( ) => {
673- insertIconLabelElement ( buttonElement , buttonElement . dataset . labelDone ) ;
674- buttonElement . dataset . completed = "true" ;
697+ setButtonToSavedState ( buttonElement ) ;
675698 if ( isEntryView ( ) ) {
676699 showToastNotification ( "save" , buttonElement . dataset . toastDone ) ;
677700 }
@@ -690,19 +713,13 @@ function handleBookmarkAction(element) {
690713 const buttonElement = currentEntry . querySelector ( ":is(a, button)[data-toggle-bookmark]" ) ;
691714 if ( ! buttonElement ) return ;
692715
693- insertIconLabelElement ( buttonElement , buttonElement . dataset . labelLoading ) ;
716+ setButtonToLoadingState ( buttonElement ) ;
694717
695718 sendPOSTRequest ( buttonElement . dataset . bookmarkUrl ) . then ( ( ) => {
696- const currentStarStatus = buttonElement . dataset . value ;
697- const newStarStatus = currentStarStatus === "star" ? "unstar" : "star" ;
698- const isStarred = currentStarStatus === "star" ;
719+ const isStarred = buttonElement . dataset . value === "star" ;
720+ const newStarStatus = isStarred ? "unstar" : "star" ;
699721
700- const iconElement = document . querySelector ( isStarred ? "template#icon-star" : "template#icon-unstar" ) ;
701- const label = isStarred ? buttonElement . dataset . labelStar : buttonElement . dataset . labelUnstar ;
702-
703- buttonElement . replaceChildren ( iconElement . content . cloneNode ( true ) ) ;
704- insertIconLabelElement ( buttonElement , label , false ) ;
705- buttonElement . dataset . value = newStarStatus ;
722+ setBookmarkButtonState ( buttonElement , newStarStatus ) ;
706723
707724 if ( isEntryView ( ) ) {
708725 showToastNotification ( newStarStatus , buttonElement . dataset [ isStarred ? "toastUnstar" : "toastStar" ] ) ;
@@ -721,13 +738,10 @@ function handleFetchOriginalContentAction() {
721738 const buttonElement = document . querySelector ( ":is(a, button)[data-fetch-content-entry]" ) ;
722739 if ( ! buttonElement ) return ;
723740
724- const previousElement = buttonElement . cloneNode ( true ) ;
725-
726- insertIconLabelElement ( buttonElement , buttonElement . dataset . labelLoading ) ;
741+ const originalButtonElement = setButtonToLoadingState ( buttonElement ) ;
727742
728743 sendPOSTRequest ( buttonElement . dataset . fetchContentUrl ) . then ( ( response ) => {
729- buttonElement . textContent = '' ;
730- buttonElement . appendChild ( previousElement ) ;
744+ restoreButtonState ( buttonElement , originalButtonElement ) ;
731745
732746 response . json ( ) . then ( ( data ) => {
733747 if ( data . content && data . reading_time ) {
0 commit comments