Fossil SCM

wikiedit: now uses fossil.confirmer pinSize option on confirmer buttons. Save button is no longer re-labeled during save to avoid layout reflow. Save button is now always enabled and attempting to save when there are no edits triggers an error message.

stephan 2020-08-11 15:39 trunk
Commit f94a55385e097fa782fd4292b6bcf2a86f63ea9c4570e0fddb8ec06a3544f224
2 files changed +23 -25 +10 -7
--- src/fossil.page.wikiedit.js
+++ src/fossil.page.wikiedit.js
@@ -918,27 +918,15 @@
918918
const w = P.winfo;
919919
if(!w){
920920
F.error("No page loaded.");
921921
return;
922922
}
923
- setTimeout(
924
- function(){
925
- if(alsoClose){
926
- P.save(()=>window.location.href=F.repoUrl('wiki',{name: w.name}));
927
- }else{
928
- P.save();
929
- }
930
- }, 0
931
- /* timeout is a workaround to allow save() to update the
932
- button's text (per forum feedback). The idea is to force
933
- the call of save() to happen *after* the confirmer
934
- callback returns so that we can change the button label
935
- without the confirmer setting it back to its
936
- pre-confirmed state. This is, however, no guaranty that
937
- save() will actually be called *after* the confirmer
938
- re-sets the button label. */
939
- );
923
+ if(alsoClose){
924
+ P.save(()=>window.location.href=F.repoUrl('wiki',{name: w.name}));
925
+ }else{
926
+ P.save();
927
+ }
940928
};
941929
const doReload = function(e){
942930
const w = P.winfo;
943931
if(!w){
944932
F.error("No page loaded.");
@@ -961,27 +949,30 @@
961949
delete P.winfo;
962950
P.updatePageTitle();
963951
F.message("Discarded new page ["+w.name+"].");
964952
}
965953
};
966
-
954
+
967955
if(P.config.useConfirmerButtons.reload){
968956
F.confirmer(P.e.btnReload, {
957
+ pinSize: true,
969958
confirmText: "Really reload, losing edits?",
970959
onconfirm: doReload,
971960
ticks: F.config.confirmerButtonTicks
972961
});
973962
}else{
974963
P.e.btnReload.addEventListener('click', doReload, false);
975964
}
976965
if(P.config.useConfirmerButtons.save){
977966
F.confirmer(P.e.btnSave, {
967
+ pinSize: true,
978968
confirmText: "Really save changes?",
979969
onconfirm: ()=>doSave(),
980970
ticks: F.config.confirmerButtonTicks
981971
});
982972
F.confirmer(P.e.btnSaveClose, {
973
+ pinSize: true,
983974
confirmText: "Really save changes?",
984975
onconfirm: ()=>doSave(true),
985976
ticks: F.config.confirmerButtonTicks
986977
});
987978
}else{
@@ -988,11 +979,14 @@
988979
P.e.btnSave.addEventListener('click', ()=>doSave(), false);
989980
P.e.btnSaveClose.addEventListener('click', ()=>doSave(true), false);
990981
}
991982
992983
P.e.taEditor.addEventListener(
993
- 'change', ()=>P.stashContentChange(), false
984
+ 'change', function(){
985
+ P._isDirty = true;
986
+ P.stashContentChange();
987
+ }, false
994988
);
995989
996990
P.selectMimetype(false, true);
997991
P.e.selectMimetype.addEventListener(
998992
'change',
@@ -1052,10 +1046,11 @@
10521046
10531047
P.addEventListener(
10541048
// Update various state on wiki page load
10551049
'wiki-page-loaded',
10561050
function(ev){
1051
+ delete P._isDirty;
10571052
const winfo = ev.detail;
10581053
P.winfo = winfo;
10591054
P.previewNeedsUpdate = true;
10601055
P.e.selectMimetype.value = winfo.mimetype;
10611056
P.tabs.switchToTab(P.e.tabs.content);
@@ -1130,18 +1125,21 @@
11301125
/**
11311126
Change the save button depending on whether we have stuff to save
11321127
or not.
11331128
*/
11341129
P.updateSaveButton = function(){
1130
+ /**
1131
+ // Current disabled, per forum feedback and MSIE compatibility, but
1132
+ // might be revisited...
11351133
if(!this.winfo || !this.getStashedWinfo(this.winfo)){
11361134
D.disable(this.e.btnSave).innerText =
11371135
"No changes to save";
11381136
D.disable(this.e.btnSaveClose);
11391137
}else{
11401138
D.enable(this.e.btnSave).innerText = "Save";
11411139
D.enable(this.e.btnSaveClose);
1142
- }
1140
+ }*/
11431141
return this;
11441142
};
11451143
11461144
/**
11471145
Getter (if called with no args) or setter (if passed an arg) for
@@ -1249,10 +1247,11 @@
12491247
version: stashWinfo.version,
12501248
parent: stashWinfo.parent,
12511249
isEmpty: !!stashWinfo.isEmpty,
12521250
content: $stash.stashedContent(stashWinfo)
12531251
});
1252
+ this._isDirty = true/*b/c loading normally clears that flag*/;
12541253
return this;
12551254
}
12561255
F.message(
12571256
"Loading content..."
12581257
).fetch('wikiajax/fetch',{
@@ -1382,10 +1381,14 @@
13821381
expected to be a function, which is called only if
13831382
saving succeeds, after all other post-save processing.
13841383
*/
13851384
P.save = function callee(onSuccessCallback){
13861385
if(!affirmPageLoaded()) return this;
1386
+ else if(!this._isDirty){
1387
+ F.error("There are no changes to save.");
1388
+ return this;
1389
+ }
13871390
const content = this.wikiContent();
13881391
const self = this;
13891392
callee.onload = function(w){
13901393
const oldWinfo = self.winfo;
13911394
self.unstashContent(oldWinfo);
@@ -1403,15 +1406,10 @@
14031406
F.message(
14041407
"Saving page..."
14051408
).fetch('wikiajax/save',{
14061409
payload: fd,
14071410
responseType: 'json',
1408
- beforesend: function(){
1409
- D.disable(P.e.btnSave, P.e.btnSaveClose);
1410
- P.e.btnSave.innerText = "Saving...";
1411
- F.fetch.beforesend();
1412
- },
14131411
onload: callee.onload
14141412
});
14151413
return this;
14161414
};
14171415
14181416
--- src/fossil.page.wikiedit.js
+++ src/fossil.page.wikiedit.js
@@ -918,27 +918,15 @@
918 const w = P.winfo;
919 if(!w){
920 F.error("No page loaded.");
921 return;
922 }
923 setTimeout(
924 function(){
925 if(alsoClose){
926 P.save(()=>window.location.href=F.repoUrl('wiki',{name: w.name}));
927 }else{
928 P.save();
929 }
930 }, 0
931 /* timeout is a workaround to allow save() to update the
932 button's text (per forum feedback). The idea is to force
933 the call of save() to happen *after* the confirmer
934 callback returns so that we can change the button label
935 without the confirmer setting it back to its
936 pre-confirmed state. This is, however, no guaranty that
937 save() will actually be called *after* the confirmer
938 re-sets the button label. */
939 );
940 };
941 const doReload = function(e){
942 const w = P.winfo;
943 if(!w){
944 F.error("No page loaded.");
@@ -961,27 +949,30 @@
961 delete P.winfo;
962 P.updatePageTitle();
963 F.message("Discarded new page ["+w.name+"].");
964 }
965 };
966
967 if(P.config.useConfirmerButtons.reload){
968 F.confirmer(P.e.btnReload, {
 
969 confirmText: "Really reload, losing edits?",
970 onconfirm: doReload,
971 ticks: F.config.confirmerButtonTicks
972 });
973 }else{
974 P.e.btnReload.addEventListener('click', doReload, false);
975 }
976 if(P.config.useConfirmerButtons.save){
977 F.confirmer(P.e.btnSave, {
 
978 confirmText: "Really save changes?",
979 onconfirm: ()=>doSave(),
980 ticks: F.config.confirmerButtonTicks
981 });
982 F.confirmer(P.e.btnSaveClose, {
 
983 confirmText: "Really save changes?",
984 onconfirm: ()=>doSave(true),
985 ticks: F.config.confirmerButtonTicks
986 });
987 }else{
@@ -988,11 +979,14 @@
988 P.e.btnSave.addEventListener('click', ()=>doSave(), false);
989 P.e.btnSaveClose.addEventListener('click', ()=>doSave(true), false);
990 }
991
992 P.e.taEditor.addEventListener(
993 'change', ()=>P.stashContentChange(), false
 
 
 
994 );
995
996 P.selectMimetype(false, true);
997 P.e.selectMimetype.addEventListener(
998 'change',
@@ -1052,10 +1046,11 @@
1052
1053 P.addEventListener(
1054 // Update various state on wiki page load
1055 'wiki-page-loaded',
1056 function(ev){
 
1057 const winfo = ev.detail;
1058 P.winfo = winfo;
1059 P.previewNeedsUpdate = true;
1060 P.e.selectMimetype.value = winfo.mimetype;
1061 P.tabs.switchToTab(P.e.tabs.content);
@@ -1130,18 +1125,21 @@
1130 /**
1131 Change the save button depending on whether we have stuff to save
1132 or not.
1133 */
1134 P.updateSaveButton = function(){
 
 
 
1135 if(!this.winfo || !this.getStashedWinfo(this.winfo)){
1136 D.disable(this.e.btnSave).innerText =
1137 "No changes to save";
1138 D.disable(this.e.btnSaveClose);
1139 }else{
1140 D.enable(this.e.btnSave).innerText = "Save";
1141 D.enable(this.e.btnSaveClose);
1142 }
1143 return this;
1144 };
1145
1146 /**
1147 Getter (if called with no args) or setter (if passed an arg) for
@@ -1249,10 +1247,11 @@
1249 version: stashWinfo.version,
1250 parent: stashWinfo.parent,
1251 isEmpty: !!stashWinfo.isEmpty,
1252 content: $stash.stashedContent(stashWinfo)
1253 });
 
1254 return this;
1255 }
1256 F.message(
1257 "Loading content..."
1258 ).fetch('wikiajax/fetch',{
@@ -1382,10 +1381,14 @@
1382 expected to be a function, which is called only if
1383 saving succeeds, after all other post-save processing.
1384 */
1385 P.save = function callee(onSuccessCallback){
1386 if(!affirmPageLoaded()) return this;
 
 
 
 
1387 const content = this.wikiContent();
1388 const self = this;
1389 callee.onload = function(w){
1390 const oldWinfo = self.winfo;
1391 self.unstashContent(oldWinfo);
@@ -1403,15 +1406,10 @@
1403 F.message(
1404 "Saving page..."
1405 ).fetch('wikiajax/save',{
1406 payload: fd,
1407 responseType: 'json',
1408 beforesend: function(){
1409 D.disable(P.e.btnSave, P.e.btnSaveClose);
1410 P.e.btnSave.innerText = "Saving...";
1411 F.fetch.beforesend();
1412 },
1413 onload: callee.onload
1414 });
1415 return this;
1416 };
1417
1418
--- src/fossil.page.wikiedit.js
+++ src/fossil.page.wikiedit.js
@@ -918,27 +918,15 @@
918 const w = P.winfo;
919 if(!w){
920 F.error("No page loaded.");
921 return;
922 }
923 if(alsoClose){
924 P.save(()=>window.location.href=F.repoUrl('wiki',{name: w.name}));
925 }else{
926 P.save();
927 }
 
 
 
 
 
 
 
 
 
 
 
 
928 };
929 const doReload = function(e){
930 const w = P.winfo;
931 if(!w){
932 F.error("No page loaded.");
@@ -961,27 +949,30 @@
949 delete P.winfo;
950 P.updatePageTitle();
951 F.message("Discarded new page ["+w.name+"].");
952 }
953 };
954
955 if(P.config.useConfirmerButtons.reload){
956 F.confirmer(P.e.btnReload, {
957 pinSize: true,
958 confirmText: "Really reload, losing edits?",
959 onconfirm: doReload,
960 ticks: F.config.confirmerButtonTicks
961 });
962 }else{
963 P.e.btnReload.addEventListener('click', doReload, false);
964 }
965 if(P.config.useConfirmerButtons.save){
966 F.confirmer(P.e.btnSave, {
967 pinSize: true,
968 confirmText: "Really save changes?",
969 onconfirm: ()=>doSave(),
970 ticks: F.config.confirmerButtonTicks
971 });
972 F.confirmer(P.e.btnSaveClose, {
973 pinSize: true,
974 confirmText: "Really save changes?",
975 onconfirm: ()=>doSave(true),
976 ticks: F.config.confirmerButtonTicks
977 });
978 }else{
@@ -988,11 +979,14 @@
979 P.e.btnSave.addEventListener('click', ()=>doSave(), false);
980 P.e.btnSaveClose.addEventListener('click', ()=>doSave(true), false);
981 }
982
983 P.e.taEditor.addEventListener(
984 'change', function(){
985 P._isDirty = true;
986 P.stashContentChange();
987 }, false
988 );
989
990 P.selectMimetype(false, true);
991 P.e.selectMimetype.addEventListener(
992 'change',
@@ -1052,10 +1046,11 @@
1046
1047 P.addEventListener(
1048 // Update various state on wiki page load
1049 'wiki-page-loaded',
1050 function(ev){
1051 delete P._isDirty;
1052 const winfo = ev.detail;
1053 P.winfo = winfo;
1054 P.previewNeedsUpdate = true;
1055 P.e.selectMimetype.value = winfo.mimetype;
1056 P.tabs.switchToTab(P.e.tabs.content);
@@ -1130,18 +1125,21 @@
1125 /**
1126 Change the save button depending on whether we have stuff to save
1127 or not.
1128 */
1129 P.updateSaveButton = function(){
1130 /**
1131 // Current disabled, per forum feedback and MSIE compatibility, but
1132 // might be revisited...
1133 if(!this.winfo || !this.getStashedWinfo(this.winfo)){
1134 D.disable(this.e.btnSave).innerText =
1135 "No changes to save";
1136 D.disable(this.e.btnSaveClose);
1137 }else{
1138 D.enable(this.e.btnSave).innerText = "Save";
1139 D.enable(this.e.btnSaveClose);
1140 }*/
1141 return this;
1142 };
1143
1144 /**
1145 Getter (if called with no args) or setter (if passed an arg) for
@@ -1249,10 +1247,11 @@
1247 version: stashWinfo.version,
1248 parent: stashWinfo.parent,
1249 isEmpty: !!stashWinfo.isEmpty,
1250 content: $stash.stashedContent(stashWinfo)
1251 });
1252 this._isDirty = true/*b/c loading normally clears that flag*/;
1253 return this;
1254 }
1255 F.message(
1256 "Loading content..."
1257 ).fetch('wikiajax/fetch',{
@@ -1382,10 +1381,14 @@
1381 expected to be a function, which is called only if
1382 saving succeeds, after all other post-save processing.
1383 */
1384 P.save = function callee(onSuccessCallback){
1385 if(!affirmPageLoaded()) return this;
1386 else if(!this._isDirty){
1387 F.error("There are no changes to save.");
1388 return this;
1389 }
1390 const content = this.wikiContent();
1391 const self = this;
1392 callee.onload = function(w){
1393 const oldWinfo = self.winfo;
1394 self.unstashContent(oldWinfo);
@@ -1403,15 +1406,10 @@
1406 F.message(
1407 "Saving page..."
1408 ).fetch('wikiajax/save',{
1409 payload: fd,
1410 responseType: 'json',
 
 
 
 
 
1411 onload: callee.onload
1412 });
1413 return this;
1414 };
1415
1416
+10 -7
--- src/wiki.c
+++ src/wiki.c
@@ -1168,21 +1168,22 @@
11681168
NULL/*tooltip*/,
11691169
100,
11701170
"100%", 100, "125%", 125,
11711171
"150%", 150, "175%", 175,
11721172
"200%", 200, NULL);
1173
+ CX("<button class='wikiedit-save'>"
1174
+ "Save</button>"
1175
+ /*will get moved around dynamically*/);
1176
+ CX("<button class='wikiedit-save-close'>"
1177
+ "Save &amp; Close</button>"/*will get moved around dynamically*/);
1178
+ CX("<span class='save-button-slot'></span>");
11731179
CX("<button class='wikiedit-content-reload' "
11741180
"title='Reload the file from the server, discarding "
11751181
"any local edits. To help avoid accidental loss of "
11761182
"edits, it requires confirmation (a second click) within "
11771183
"a few seconds or it will not reload.'"
11781184
">Discard &amp; Reload</button>");
1179
- CX("<button class='wikiedit-save' disabled='disabled'>"
1180
- "Save</button>"/*will get moved around dynamically*/);
1181
- CX("<button class='wikiedit-save-close' disabled='disabled'>"
1182
- "Save &amp; Close</button>"/*will get moved around dynamically*/);
1183
- CX("<span class='save-button-slot'></span>");
11841185
CX("</div>");
11851186
CX("<div class='flex-container flex-column stretch'>");
11861187
CX("<textarea name='content' id='wikiedit-content-editor' "
11871188
"class='wikiedit' rows='25'>");
11881189
CX("</textarea>");
@@ -1194,11 +1195,12 @@
11941195
CX("<div id='wikiedit-tab-preview' "
11951196
"data-tab-parent='wikiedit-tabs' "
11961197
"data-tab-label='Preview' "
11971198
"class='hidden'"
11981199
">");
1199
- CX("<div class='wikiedit-options flex-container flex-row'>");
1200
+ CX("<div class='wikiedit-options flex-container "
1201
+ "flex-row child-gap-small'>");
12001202
CX("<button id='btn-preview-refresh' "
12011203
"data-f-preview-from='wikiContent' "
12021204
/* ^^^ fossil.page[methodName]() OR text source elem ID,
12031205
** but we need a method in order to support clients swapping out
12041206
** the text editor with their own. */
@@ -1226,11 +1228,12 @@
12261228
"data-tab-parent='wikiedit-tabs' "
12271229
"data-tab-label='Diff' "
12281230
"class='hidden'"
12291231
">");
12301232
1231
- CX("<div class='wikiedit-options flex-container flex-row' "
1233
+ CX("<div class='wikiedit-options flex-container "
1234
+ "flex-row child-gap-small' "
12321235
"id='wikiedit-tab-diff-buttons'>");
12331236
CX("<button class='sbs'>Side-by-side</button>"
12341237
"<button class='unified'>Unified</button>");
12351238
CX("<span class='save-button-slot'></span>");
12361239
CX("</div>");
12371240
--- src/wiki.c
+++ src/wiki.c
@@ -1168,21 +1168,22 @@
1168 NULL/*tooltip*/,
1169 100,
1170 "100%", 100, "125%", 125,
1171 "150%", 150, "175%", 175,
1172 "200%", 200, NULL);
 
 
 
 
 
 
1173 CX("<button class='wikiedit-content-reload' "
1174 "title='Reload the file from the server, discarding "
1175 "any local edits. To help avoid accidental loss of "
1176 "edits, it requires confirmation (a second click) within "
1177 "a few seconds or it will not reload.'"
1178 ">Discard &amp; Reload</button>");
1179 CX("<button class='wikiedit-save' disabled='disabled'>"
1180 "Save</button>"/*will get moved around dynamically*/);
1181 CX("<button class='wikiedit-save-close' disabled='disabled'>"
1182 "Save &amp; Close</button>"/*will get moved around dynamically*/);
1183 CX("<span class='save-button-slot'></span>");
1184 CX("</div>");
1185 CX("<div class='flex-container flex-column stretch'>");
1186 CX("<textarea name='content' id='wikiedit-content-editor' "
1187 "class='wikiedit' rows='25'>");
1188 CX("</textarea>");
@@ -1194,11 +1195,12 @@
1194 CX("<div id='wikiedit-tab-preview' "
1195 "data-tab-parent='wikiedit-tabs' "
1196 "data-tab-label='Preview' "
1197 "class='hidden'"
1198 ">");
1199 CX("<div class='wikiedit-options flex-container flex-row'>");
 
1200 CX("<button id='btn-preview-refresh' "
1201 "data-f-preview-from='wikiContent' "
1202 /* ^^^ fossil.page[methodName]() OR text source elem ID,
1203 ** but we need a method in order to support clients swapping out
1204 ** the text editor with their own. */
@@ -1226,11 +1228,12 @@
1226 "data-tab-parent='wikiedit-tabs' "
1227 "data-tab-label='Diff' "
1228 "class='hidden'"
1229 ">");
1230
1231 CX("<div class='wikiedit-options flex-container flex-row' "
 
1232 "id='wikiedit-tab-diff-buttons'>");
1233 CX("<button class='sbs'>Side-by-side</button>"
1234 "<button class='unified'>Unified</button>");
1235 CX("<span class='save-button-slot'></span>");
1236 CX("</div>");
1237
--- src/wiki.c
+++ src/wiki.c
@@ -1168,21 +1168,22 @@
1168 NULL/*tooltip*/,
1169 100,
1170 "100%", 100, "125%", 125,
1171 "150%", 150, "175%", 175,
1172 "200%", 200, NULL);
1173 CX("<button class='wikiedit-save'>"
1174 "Save</button>"
1175 /*will get moved around dynamically*/);
1176 CX("<button class='wikiedit-save-close'>"
1177 "Save &amp; Close</button>"/*will get moved around dynamically*/);
1178 CX("<span class='save-button-slot'></span>");
1179 CX("<button class='wikiedit-content-reload' "
1180 "title='Reload the file from the server, discarding "
1181 "any local edits. To help avoid accidental loss of "
1182 "edits, it requires confirmation (a second click) within "
1183 "a few seconds or it will not reload.'"
1184 ">Discard &amp; Reload</button>");
 
 
 
 
 
1185 CX("</div>");
1186 CX("<div class='flex-container flex-column stretch'>");
1187 CX("<textarea name='content' id='wikiedit-content-editor' "
1188 "class='wikiedit' rows='25'>");
1189 CX("</textarea>");
@@ -1194,11 +1195,12 @@
1195 CX("<div id='wikiedit-tab-preview' "
1196 "data-tab-parent='wikiedit-tabs' "
1197 "data-tab-label='Preview' "
1198 "class='hidden'"
1199 ">");
1200 CX("<div class='wikiedit-options flex-container "
1201 "flex-row child-gap-small'>");
1202 CX("<button id='btn-preview-refresh' "
1203 "data-f-preview-from='wikiContent' "
1204 /* ^^^ fossil.page[methodName]() OR text source elem ID,
1205 ** but we need a method in order to support clients swapping out
1206 ** the text editor with their own. */
@@ -1226,11 +1228,12 @@
1228 "data-tab-parent='wikiedit-tabs' "
1229 "data-tab-label='Diff' "
1230 "class='hidden'"
1231 ">");
1232
1233 CX("<div class='wikiedit-options flex-container "
1234 "flex-row child-gap-small' "
1235 "id='wikiedit-tab-diff-buttons'>");
1236 CX("<button class='sbs'>Side-by-side</button>"
1237 "<button class='unified'>Unified</button>");
1238 CX("<span class='save-button-slot'></span>");
1239 CX("</div>");
1240

Keyboard Shortcuts

Open search /
Next entry (timeline) j
Previous entry (timeline) k
Open focused entry Enter
Show this help ?
Toggle theme Top nav button