Fossil SCM
Add pieces which, when loading a forum thread, visibly tag Reply and Edit buttons for posts which have local draft replies/edits, but do not yet enable them. Still to solve is how to update those tags dynamically as drafts are added and removed within the current page context. They're currently useful, but the lack of dynamic updates to them is confusing.
Commit
bee75fb8b22ff892857e4762ea35274fc427e92cd60a3917a457cc96fc876f98
Parent
0f539c6c29f090d…
2 files changed
+38
-9
+4
+38
-9
| --- src/fossil.page.forumpost.js | ||
| +++ src/fossil.page.forumpost.js | ||
| @@ -43,11 +43,11 @@ | ||
| 43 | 43 | submit. |
| 44 | 44 | |
| 45 | 45 | opt.ondiscard[=function]: if set, a Discard button is added |
| 46 | 46 | which, when activated, clears the current draft and removes |
| 47 | 47 | this object's widget from the DOM. After doing so, |
| 48 | - opt.ondiscard() is called and passed no arguments. Exceptions | |
| 48 | + opt.ondiscard() is called and passed this object. Exceptions | |
| 49 | 49 | thrown by ondiscard() are ignored but may be logged. |
| 50 | 50 | |
| 51 | 51 | opt.onsubmit[=function]: if set, this function is called |
| 52 | 52 | immediately after the post has been successfully saved, and |
| 53 | 53 | passed this object and a JSON-format response object from the |
| @@ -401,11 +401,11 @@ | ||
| 401 | 401 | ** before the drafts are cleared and any exceptions it throws are |
| 402 | 402 | ** ignored (but may be logged). |
| 403 | 403 | */ |
| 404 | 404 | discard(){ |
| 405 | 405 | if( this.#opt.ondiscard instanceof Function ){ |
| 406 | - try{this.#opt.ondiscard();} | |
| 406 | + try{this.#opt.ondiscard(this);} | |
| 407 | 407 | catch(e){ |
| 408 | 408 | console.error("ForumPostEditor.ondiscard() threw:",e); |
| 409 | 409 | } |
| 410 | 410 | } |
| 411 | 411 | this.#clearDraft(); |
| @@ -981,10 +981,14 @@ | ||
| 981 | 981 | j = F.nu(j); |
| 982 | 982 | if( j.error ) throw new Error(j.error); |
| 983 | 983 | return j; |
| 984 | 984 | }); |
| 985 | 985 | }; |
| 986 | + | |
| 987 | + const makeDraftKey = (prefix,uuid)=>{ | |
| 988 | + return prefix+'-'+uuid.substr(0,12); | |
| 989 | + }; | |
| 986 | 990 | |
| 987 | 991 | const setupEditReplyElement = (ePost, eButton, eToDisable)=>{ |
| 988 | 992 | const fpid = ePost.dataset.fpid; |
| 989 | 993 | ePost.dataset.originalMarginLeft = ePost.style.marginLeft; |
| 990 | 994 | ePost.style.marginLeft = 'initial'; |
| @@ -1011,13 +1015,15 @@ | ||
| 1011 | 1015 | eBtnReply.innerText = "Replying..."; |
| 1012 | 1016 | const ondone = (fpe, response)=>{ |
| 1013 | 1017 | /* onsubmit() and ondiscard() callback */ |
| 1014 | 1018 | restoreEditReplyElement(ePost, eBtnReply, eToDisable); |
| 1015 | 1019 | //console.debug("ondiscard/onsubmit", fpe, artifact); |
| 1016 | - if( response/*onsubmit*/ ){ | |
| 1020 | + if( response/*onsubmit()*/ ){ | |
| 1017 | 1021 | window.location = F.repoUrl('forumpost/'+response.uuid); |
| 1018 | 1022 | fpe.close(); |
| 1023 | + }else{/*ondiscard()*/ | |
| 1024 | + eBtnReply.classList.remove('draft'); | |
| 1019 | 1025 | } |
| 1020 | 1026 | }; |
| 1021 | 1027 | const fpe = new F.ForumPostEditor({ |
| 1022 | 1028 | hiddenFields: form.querySelectorAll( |
| 1023 | 1029 | 'input[type=hidden][name=csrf]' |
| @@ -1025,19 +1031,18 @@ | ||
| 1025 | 1031 | an edit to that post rather than a response. */ |
| 1026 | 1032 | ), |
| 1027 | 1033 | ondiscard: ondone, |
| 1028 | 1034 | onsubmit: ondone, |
| 1029 | 1035 | inReplyTo: fpid, |
| 1030 | - draftKey: 'draft-reply-'+( | |
| 1031 | - fEditHead | |
| 1036 | + draftKey: makeDraftKey('draft-reply', fEditHead | |
| 1032 | 1037 | /* The problem with firt as a key is that firt is not |
| 1033 | 1038 | necessarily the root edit of that post, which is |
| 1034 | 1039 | what we really want as a draft key so that the |
| 1035 | 1040 | draft does not disapper if firt is later edited |
| 1036 | 1041 | (giving us a new firt value here). */ |
| 1037 | 1042 | || fpid |
| 1038 | - ).substr(0,12) | |
| 1043 | + ) | |
| 1039 | 1044 | }); |
| 1040 | 1045 | initFPEWidget(ePost, fpe); |
| 1041 | 1046 | }/*replyClicked()*/; |
| 1042 | 1047 | |
| 1043 | 1048 | const editClicked = (form, ePost, eBtnEdit, eToDisable)=>{ |
| @@ -1048,20 +1053,22 @@ | ||
| 1048 | 1053 | fetchPost(fpid) |
| 1049 | 1054 | .then(artifact=>{ |
| 1050 | 1055 | const ondone = (fpe, response)=>{ |
| 1051 | 1056 | /* onsubmit() and ondiscard() callback */ |
| 1052 | 1057 | //console.debug("ondiscard/onsubmit", fpe, eToDisable); |
| 1053 | - if( fpe/*onsubmit*/ ){ | |
| 1058 | + if( response/*onsubmit()*/ ){ | |
| 1054 | 1059 | if( fpid === response.uuid |
| 1055 | 1060 | && !response.statusModified |
| 1056 | 1061 | && 0===response.attachedCount ){ |
| 1057 | 1062 | fpe.reportError("No changes made."); |
| 1058 | 1063 | }else{ |
| 1059 | 1064 | restoreEditReplyElement(ePost, eBtnEdit, eToDisable); |
| 1060 | 1065 | window.location = F.repoUrl('forumpost/'+response.uuid); |
| 1061 | 1066 | } |
| 1062 | 1067 | }else{ |
| 1068 | + /*ondiscard()*/ | |
| 1069 | + eBtnEdit.classList.remove('draft'); | |
| 1063 | 1070 | restoreEditReplyElement(ePost, eBtnEdit, eToDisable); |
| 1064 | 1071 | } |
| 1065 | 1072 | }; |
| 1066 | 1073 | const eStatusSelect = ePost.querySelector( |
| 1067 | 1074 | ':scope > fieldset.forum-status-selection select[name=status]' |
| @@ -1069,11 +1076,11 @@ | ||
| 1069 | 1076 | |
| 1070 | 1077 | const fpe = new F.ForumPostEditor({ |
| 1071 | 1078 | hiddenFields: form.querySelectorAll('input[type=hidden]'), |
| 1072 | 1079 | ondiscard: ondone, |
| 1073 | 1080 | onsubmit: ondone, |
| 1074 | - draftKey: 'draft-forumedit-'+(fEditHead || fpid).substr(0,12), | |
| 1081 | + draftKey: makeDraftKey('draft-forumedit', fEditHead || fpid), | |
| 1075 | 1082 | edit: artifact, |
| 1076 | 1083 | status: eStatusSelect?.value, |
| 1077 | 1084 | inReplyTo: firt |
| 1078 | 1085 | }); |
| 1079 | 1086 | initFPEWidget(ePost, fpe); |
| @@ -1092,26 +1099,48 @@ | ||
| 1092 | 1099 | if( !eThePost?.dataset?.fpid ){ |
| 1093 | 1100 | /* The server injects these. */ |
| 1094 | 1101 | console.warn("Unexpected missing fpid", eThePost); |
| 1095 | 1102 | return; |
| 1096 | 1103 | } |
| 1104 | + | |
| 1105 | + const checkButtonForDraft = (draftKeyPrefix, eBtn)=>{ | |
| 1106 | + if( 1 ){ | |
| 1107 | + /* 2026-06-09: this is currently disabled because it's | |
| 1108 | + much of the solution but not all of it. Still to solve | |
| 1109 | + is how to tag/untag these elements as local drafts are | |
| 1110 | + added/removed during this page's lifetime. | |
| 1111 | + ForumPostEditor does not have access to these buttons | |
| 1112 | + so can't flag them. We may need to add events to | |
| 1113 | + F.storage and monitor those. | |
| 1114 | + */ | |
| 1115 | + return; | |
| 1116 | + } | |
| 1117 | + const fpid = eThePost.dataset.fpid; | |
| 1118 | + const fEditHead = eThePost.dataset.fedithead; | |
| 1119 | + const draftKey = makeDraftKey(draftKeyPrefix, fEditHead || fpid); | |
| 1120 | + if( F.storage.contains(draftKey) ){ | |
| 1121 | + eBtn.classList.add('draft'); | |
| 1122 | + } | |
| 1123 | + }; | |
| 1097 | 1124 | /* Replace the Reply and Edit buttons with ones which will activate |
| 1098 | 1125 | a ForumPostEditor. */ |
| 1099 | 1126 | const btnReply = form.querySelector('input[type=submit][name=reply]'); |
| 1100 | 1127 | if( btnReply ){ |
| 1101 | 1128 | const b = D.button("Reply", ()=>replyClicked(form, eThePost, b, eToDisable)); |
| 1102 | 1129 | b.type = 'button'/*keep container form from submitting*/; |
| 1103 | 1130 | eToDisable.push(b); |
| 1131 | + checkButtonForDraft('draft-reply',b); | |
| 1104 | 1132 | btnReply.parentElement.insertBefore(b, btnReply); |
| 1105 | 1133 | btnReply.remove(); |
| 1106 | 1134 | } |
| 1107 | 1135 | const btnEdit = form.querySelector('input[type=submit][name=edit]'); |
| 1108 | 1136 | if( btnEdit ){ |
| 1109 | 1137 | //console.debug("hacking Edit button", btnEdit); |
| 1110 | 1138 | const b = D.button("Edit", ()=>editClicked(form, eThePost, b, eToDisable)); |
| 1111 | 1139 | b.type = 'button'; |
| 1112 | 1140 | eToDisable.push(b); |
| 1141 | + checkButtonForDraft('draft-forumedit',b); | |
| 1113 | 1142 | btnEdit.parentElement.insertBefore(b, btnEdit); |
| 1114 | 1143 | btnEdit.remove(); |
| 1115 | 1144 | } |
| 1116 | 1145 | /* Problem: we really need to disable the status-selection |
| 1117 | 1146 | button because it would redirect mid-edit. We wouldn't lose |
| @@ -1134,9 +1163,9 @@ | ||
| 1134 | 1163 | e.classList.remove('initially-hidden'); |
| 1135 | 1164 | }); |
| 1136 | 1165 | |
| 1137 | 1166 | if( Date.now() % 17 === 0 ){ |
| 1138 | 1167 | /* Purge old drafts only every now and then. */ |
| 1139 | - F.ForumPostEditor.purgeOldDrafts(/^draft-forum.*/); | |
| 1168 | + F.ForumPostEditor.purgeOldDrafts(/^draft-(reply|forumedit)-.*/)/*not purging forumnew*/; | |
| 1140 | 1169 | } |
| 1141 | 1170 | })/*F.onPageLoad callback*/; |
| 1142 | 1171 | })(window.fossil); |
| 1143 | 1172 |
| --- src/fossil.page.forumpost.js | |
| +++ src/fossil.page.forumpost.js | |
| @@ -43,11 +43,11 @@ | |
| 43 | submit. |
| 44 | |
| 45 | opt.ondiscard[=function]: if set, a Discard button is added |
| 46 | which, when activated, clears the current draft and removes |
| 47 | this object's widget from the DOM. After doing so, |
| 48 | opt.ondiscard() is called and passed no arguments. Exceptions |
| 49 | thrown by ondiscard() are ignored but may be logged. |
| 50 | |
| 51 | opt.onsubmit[=function]: if set, this function is called |
| 52 | immediately after the post has been successfully saved, and |
| 53 | passed this object and a JSON-format response object from the |
| @@ -401,11 +401,11 @@ | |
| 401 | ** before the drafts are cleared and any exceptions it throws are |
| 402 | ** ignored (but may be logged). |
| 403 | */ |
| 404 | discard(){ |
| 405 | if( this.#opt.ondiscard instanceof Function ){ |
| 406 | try{this.#opt.ondiscard();} |
| 407 | catch(e){ |
| 408 | console.error("ForumPostEditor.ondiscard() threw:",e); |
| 409 | } |
| 410 | } |
| 411 | this.#clearDraft(); |
| @@ -981,10 +981,14 @@ | |
| 981 | j = F.nu(j); |
| 982 | if( j.error ) throw new Error(j.error); |
| 983 | return j; |
| 984 | }); |
| 985 | }; |
| 986 | |
| 987 | const setupEditReplyElement = (ePost, eButton, eToDisable)=>{ |
| 988 | const fpid = ePost.dataset.fpid; |
| 989 | ePost.dataset.originalMarginLeft = ePost.style.marginLeft; |
| 990 | ePost.style.marginLeft = 'initial'; |
| @@ -1011,13 +1015,15 @@ | |
| 1011 | eBtnReply.innerText = "Replying..."; |
| 1012 | const ondone = (fpe, response)=>{ |
| 1013 | /* onsubmit() and ondiscard() callback */ |
| 1014 | restoreEditReplyElement(ePost, eBtnReply, eToDisable); |
| 1015 | //console.debug("ondiscard/onsubmit", fpe, artifact); |
| 1016 | if( response/*onsubmit*/ ){ |
| 1017 | window.location = F.repoUrl('forumpost/'+response.uuid); |
| 1018 | fpe.close(); |
| 1019 | } |
| 1020 | }; |
| 1021 | const fpe = new F.ForumPostEditor({ |
| 1022 | hiddenFields: form.querySelectorAll( |
| 1023 | 'input[type=hidden][name=csrf]' |
| @@ -1025,19 +1031,18 @@ | |
| 1025 | an edit to that post rather than a response. */ |
| 1026 | ), |
| 1027 | ondiscard: ondone, |
| 1028 | onsubmit: ondone, |
| 1029 | inReplyTo: fpid, |
| 1030 | draftKey: 'draft-reply-'+( |
| 1031 | fEditHead |
| 1032 | /* The problem with firt as a key is that firt is not |
| 1033 | necessarily the root edit of that post, which is |
| 1034 | what we really want as a draft key so that the |
| 1035 | draft does not disapper if firt is later edited |
| 1036 | (giving us a new firt value here). */ |
| 1037 | || fpid |
| 1038 | ).substr(0,12) |
| 1039 | }); |
| 1040 | initFPEWidget(ePost, fpe); |
| 1041 | }/*replyClicked()*/; |
| 1042 | |
| 1043 | const editClicked = (form, ePost, eBtnEdit, eToDisable)=>{ |
| @@ -1048,20 +1053,22 @@ | |
| 1048 | fetchPost(fpid) |
| 1049 | .then(artifact=>{ |
| 1050 | const ondone = (fpe, response)=>{ |
| 1051 | /* onsubmit() and ondiscard() callback */ |
| 1052 | //console.debug("ondiscard/onsubmit", fpe, eToDisable); |
| 1053 | if( fpe/*onsubmit*/ ){ |
| 1054 | if( fpid === response.uuid |
| 1055 | && !response.statusModified |
| 1056 | && 0===response.attachedCount ){ |
| 1057 | fpe.reportError("No changes made."); |
| 1058 | }else{ |
| 1059 | restoreEditReplyElement(ePost, eBtnEdit, eToDisable); |
| 1060 | window.location = F.repoUrl('forumpost/'+response.uuid); |
| 1061 | } |
| 1062 | }else{ |
| 1063 | restoreEditReplyElement(ePost, eBtnEdit, eToDisable); |
| 1064 | } |
| 1065 | }; |
| 1066 | const eStatusSelect = ePost.querySelector( |
| 1067 | ':scope > fieldset.forum-status-selection select[name=status]' |
| @@ -1069,11 +1076,11 @@ | |
| 1069 | |
| 1070 | const fpe = new F.ForumPostEditor({ |
| 1071 | hiddenFields: form.querySelectorAll('input[type=hidden]'), |
| 1072 | ondiscard: ondone, |
| 1073 | onsubmit: ondone, |
| 1074 | draftKey: 'draft-forumedit-'+(fEditHead || fpid).substr(0,12), |
| 1075 | edit: artifact, |
| 1076 | status: eStatusSelect?.value, |
| 1077 | inReplyTo: firt |
| 1078 | }); |
| 1079 | initFPEWidget(ePost, fpe); |
| @@ -1092,26 +1099,48 @@ | |
| 1092 | if( !eThePost?.dataset?.fpid ){ |
| 1093 | /* The server injects these. */ |
| 1094 | console.warn("Unexpected missing fpid", eThePost); |
| 1095 | return; |
| 1096 | } |
| 1097 | /* Replace the Reply and Edit buttons with ones which will activate |
| 1098 | a ForumPostEditor. */ |
| 1099 | const btnReply = form.querySelector('input[type=submit][name=reply]'); |
| 1100 | if( btnReply ){ |
| 1101 | const b = D.button("Reply", ()=>replyClicked(form, eThePost, b, eToDisable)); |
| 1102 | b.type = 'button'/*keep container form from submitting*/; |
| 1103 | eToDisable.push(b); |
| 1104 | btnReply.parentElement.insertBefore(b, btnReply); |
| 1105 | btnReply.remove(); |
| 1106 | } |
| 1107 | const btnEdit = form.querySelector('input[type=submit][name=edit]'); |
| 1108 | if( btnEdit ){ |
| 1109 | //console.debug("hacking Edit button", btnEdit); |
| 1110 | const b = D.button("Edit", ()=>editClicked(form, eThePost, b, eToDisable)); |
| 1111 | b.type = 'button'; |
| 1112 | eToDisable.push(b); |
| 1113 | btnEdit.parentElement.insertBefore(b, btnEdit); |
| 1114 | btnEdit.remove(); |
| 1115 | } |
| 1116 | /* Problem: we really need to disable the status-selection |
| 1117 | button because it would redirect mid-edit. We wouldn't lose |
| @@ -1134,9 +1163,9 @@ | |
| 1134 | e.classList.remove('initially-hidden'); |
| 1135 | }); |
| 1136 | |
| 1137 | if( Date.now() % 17 === 0 ){ |
| 1138 | /* Purge old drafts only every now and then. */ |
| 1139 | F.ForumPostEditor.purgeOldDrafts(/^draft-forum.*/); |
| 1140 | } |
| 1141 | })/*F.onPageLoad callback*/; |
| 1142 | })(window.fossil); |
| 1143 |
| --- src/fossil.page.forumpost.js | |
| +++ src/fossil.page.forumpost.js | |
| @@ -43,11 +43,11 @@ | |
| 43 | submit. |
| 44 | |
| 45 | opt.ondiscard[=function]: if set, a Discard button is added |
| 46 | which, when activated, clears the current draft and removes |
| 47 | this object's widget from the DOM. After doing so, |
| 48 | opt.ondiscard() is called and passed this object. Exceptions |
| 49 | thrown by ondiscard() are ignored but may be logged. |
| 50 | |
| 51 | opt.onsubmit[=function]: if set, this function is called |
| 52 | immediately after the post has been successfully saved, and |
| 53 | passed this object and a JSON-format response object from the |
| @@ -401,11 +401,11 @@ | |
| 401 | ** before the drafts are cleared and any exceptions it throws are |
| 402 | ** ignored (but may be logged). |
| 403 | */ |
| 404 | discard(){ |
| 405 | if( this.#opt.ondiscard instanceof Function ){ |
| 406 | try{this.#opt.ondiscard(this);} |
| 407 | catch(e){ |
| 408 | console.error("ForumPostEditor.ondiscard() threw:",e); |
| 409 | } |
| 410 | } |
| 411 | this.#clearDraft(); |
| @@ -981,10 +981,14 @@ | |
| 981 | j = F.nu(j); |
| 982 | if( j.error ) throw new Error(j.error); |
| 983 | return j; |
| 984 | }); |
| 985 | }; |
| 986 | |
| 987 | const makeDraftKey = (prefix,uuid)=>{ |
| 988 | return prefix+'-'+uuid.substr(0,12); |
| 989 | }; |
| 990 | |
| 991 | const setupEditReplyElement = (ePost, eButton, eToDisable)=>{ |
| 992 | const fpid = ePost.dataset.fpid; |
| 993 | ePost.dataset.originalMarginLeft = ePost.style.marginLeft; |
| 994 | ePost.style.marginLeft = 'initial'; |
| @@ -1011,13 +1015,15 @@ | |
| 1015 | eBtnReply.innerText = "Replying..."; |
| 1016 | const ondone = (fpe, response)=>{ |
| 1017 | /* onsubmit() and ondiscard() callback */ |
| 1018 | restoreEditReplyElement(ePost, eBtnReply, eToDisable); |
| 1019 | //console.debug("ondiscard/onsubmit", fpe, artifact); |
| 1020 | if( response/*onsubmit()*/ ){ |
| 1021 | window.location = F.repoUrl('forumpost/'+response.uuid); |
| 1022 | fpe.close(); |
| 1023 | }else{/*ondiscard()*/ |
| 1024 | eBtnReply.classList.remove('draft'); |
| 1025 | } |
| 1026 | }; |
| 1027 | const fpe = new F.ForumPostEditor({ |
| 1028 | hiddenFields: form.querySelectorAll( |
| 1029 | 'input[type=hidden][name=csrf]' |
| @@ -1025,19 +1031,18 @@ | |
| 1031 | an edit to that post rather than a response. */ |
| 1032 | ), |
| 1033 | ondiscard: ondone, |
| 1034 | onsubmit: ondone, |
| 1035 | inReplyTo: fpid, |
| 1036 | draftKey: makeDraftKey('draft-reply', fEditHead |
| 1037 | /* The problem with firt as a key is that firt is not |
| 1038 | necessarily the root edit of that post, which is |
| 1039 | what we really want as a draft key so that the |
| 1040 | draft does not disapper if firt is later edited |
| 1041 | (giving us a new firt value here). */ |
| 1042 | || fpid |
| 1043 | ) |
| 1044 | }); |
| 1045 | initFPEWidget(ePost, fpe); |
| 1046 | }/*replyClicked()*/; |
| 1047 | |
| 1048 | const editClicked = (form, ePost, eBtnEdit, eToDisable)=>{ |
| @@ -1048,20 +1053,22 @@ | |
| 1053 | fetchPost(fpid) |
| 1054 | .then(artifact=>{ |
| 1055 | const ondone = (fpe, response)=>{ |
| 1056 | /* onsubmit() and ondiscard() callback */ |
| 1057 | //console.debug("ondiscard/onsubmit", fpe, eToDisable); |
| 1058 | if( response/*onsubmit()*/ ){ |
| 1059 | if( fpid === response.uuid |
| 1060 | && !response.statusModified |
| 1061 | && 0===response.attachedCount ){ |
| 1062 | fpe.reportError("No changes made."); |
| 1063 | }else{ |
| 1064 | restoreEditReplyElement(ePost, eBtnEdit, eToDisable); |
| 1065 | window.location = F.repoUrl('forumpost/'+response.uuid); |
| 1066 | } |
| 1067 | }else{ |
| 1068 | /*ondiscard()*/ |
| 1069 | eBtnEdit.classList.remove('draft'); |
| 1070 | restoreEditReplyElement(ePost, eBtnEdit, eToDisable); |
| 1071 | } |
| 1072 | }; |
| 1073 | const eStatusSelect = ePost.querySelector( |
| 1074 | ':scope > fieldset.forum-status-selection select[name=status]' |
| @@ -1069,11 +1076,11 @@ | |
| 1076 | |
| 1077 | const fpe = new F.ForumPostEditor({ |
| 1078 | hiddenFields: form.querySelectorAll('input[type=hidden]'), |
| 1079 | ondiscard: ondone, |
| 1080 | onsubmit: ondone, |
| 1081 | draftKey: makeDraftKey('draft-forumedit', fEditHead || fpid), |
| 1082 | edit: artifact, |
| 1083 | status: eStatusSelect?.value, |
| 1084 | inReplyTo: firt |
| 1085 | }); |
| 1086 | initFPEWidget(ePost, fpe); |
| @@ -1092,26 +1099,48 @@ | |
| 1099 | if( !eThePost?.dataset?.fpid ){ |
| 1100 | /* The server injects these. */ |
| 1101 | console.warn("Unexpected missing fpid", eThePost); |
| 1102 | return; |
| 1103 | } |
| 1104 | |
| 1105 | const checkButtonForDraft = (draftKeyPrefix, eBtn)=>{ |
| 1106 | if( 1 ){ |
| 1107 | /* 2026-06-09: this is currently disabled because it's |
| 1108 | much of the solution but not all of it. Still to solve |
| 1109 | is how to tag/untag these elements as local drafts are |
| 1110 | added/removed during this page's lifetime. |
| 1111 | ForumPostEditor does not have access to these buttons |
| 1112 | so can't flag them. We may need to add events to |
| 1113 | F.storage and monitor those. |
| 1114 | */ |
| 1115 | return; |
| 1116 | } |
| 1117 | const fpid = eThePost.dataset.fpid; |
| 1118 | const fEditHead = eThePost.dataset.fedithead; |
| 1119 | const draftKey = makeDraftKey(draftKeyPrefix, fEditHead || fpid); |
| 1120 | if( F.storage.contains(draftKey) ){ |
| 1121 | eBtn.classList.add('draft'); |
| 1122 | } |
| 1123 | }; |
| 1124 | /* Replace the Reply and Edit buttons with ones which will activate |
| 1125 | a ForumPostEditor. */ |
| 1126 | const btnReply = form.querySelector('input[type=submit][name=reply]'); |
| 1127 | if( btnReply ){ |
| 1128 | const b = D.button("Reply", ()=>replyClicked(form, eThePost, b, eToDisable)); |
| 1129 | b.type = 'button'/*keep container form from submitting*/; |
| 1130 | eToDisable.push(b); |
| 1131 | checkButtonForDraft('draft-reply',b); |
| 1132 | btnReply.parentElement.insertBefore(b, btnReply); |
| 1133 | btnReply.remove(); |
| 1134 | } |
| 1135 | const btnEdit = form.querySelector('input[type=submit][name=edit]'); |
| 1136 | if( btnEdit ){ |
| 1137 | //console.debug("hacking Edit button", btnEdit); |
| 1138 | const b = D.button("Edit", ()=>editClicked(form, eThePost, b, eToDisable)); |
| 1139 | b.type = 'button'; |
| 1140 | eToDisable.push(b); |
| 1141 | checkButtonForDraft('draft-forumedit',b); |
| 1142 | btnEdit.parentElement.insertBefore(b, btnEdit); |
| 1143 | btnEdit.remove(); |
| 1144 | } |
| 1145 | /* Problem: we really need to disable the status-selection |
| 1146 | button because it would redirect mid-edit. We wouldn't lose |
| @@ -1134,9 +1163,9 @@ | |
| 1163 | e.classList.remove('initially-hidden'); |
| 1164 | }); |
| 1165 | |
| 1166 | if( Date.now() % 17 === 0 ){ |
| 1167 | /* Purge old drafts only every now and then. */ |
| 1168 | F.ForumPostEditor.purgeOldDrafts(/^draft-(reply|forumedit)-.*/)/*not purging forumnew*/; |
| 1169 | } |
| 1170 | })/*F.onPageLoad callback*/; |
| 1171 | })(window.fossil); |
| 1172 |
+4
| --- src/style.forum.css | ||
| +++ src/style.forum.css | ||
| @@ -4,10 +4,14 @@ | ||
| 4 | 4 | max-width: max-content; |
| 5 | 5 | border-radius: 0.5em; |
| 6 | 6 | padding: 0 0.5em; |
| 7 | 7 | margin-bottom: 0.35em; |
| 8 | 8 | } |
| 9 | + | |
| 10 | +body.forum .forumpost-single-controls button.draft:after { | |
| 11 | + content: " [draft]"; | |
| 12 | +} | |
| 9 | 13 | |
| 10 | 14 | .ForumPostEditor { |
| 11 | 15 | display: flex; |
| 12 | 16 | flex-direction: column; |
| 13 | 17 | gap: 1em; |
| 14 | 18 |
| --- src/style.forum.css | |
| +++ src/style.forum.css | |
| @@ -4,10 +4,14 @@ | |
| 4 | max-width: max-content; |
| 5 | border-radius: 0.5em; |
| 6 | padding: 0 0.5em; |
| 7 | margin-bottom: 0.35em; |
| 8 | } |
| 9 | |
| 10 | .ForumPostEditor { |
| 11 | display: flex; |
| 12 | flex-direction: column; |
| 13 | gap: 1em; |
| 14 |
| --- src/style.forum.css | |
| +++ src/style.forum.css | |
| @@ -4,10 +4,14 @@ | |
| 4 | max-width: max-content; |
| 5 | border-radius: 0.5em; |
| 6 | padding: 0 0.5em; |
| 7 | margin-bottom: 0.35em; |
| 8 | } |
| 9 | |
| 10 | body.forum .forumpost-single-controls button.draft:after { |
| 11 | content: " [draft]"; |
| 12 | } |
| 13 | |
| 14 | .ForumPostEditor { |
| 15 | display: flex; |
| 16 | flex-direction: column; |
| 17 | gap: 1em; |
| 18 |