Fossil SCM

Experimentally added '?' help buttons in wikiedit. Experimentally emit all fossil.XYZ APIs, rather than selected ones, to test whether that reduces overall transmission together with caching. DOM init-time timing workarounds to get confirmer buttons to pin their sizes properly.

stephan 2020-08-24 20:49 UTC trunk
Commit 9edbb7eab1b0fe489d79cbdfbf8d9394203f7e2c553dca2bbcd43dceef73d564
+59 -5
--- src/default.css
+++ src/default.css
@@ -1100,15 +1100,16 @@
11001100
.font-size-200 {
11011101
font-size: 200%;
11021102
}
11031103
11041104
/**
1105
- .input-with-label is intended to be a wrapper element which
1106
- contain both a LABEL tag and an INPUT or SELECT control.
1107
- The wrapper is "necessary", as opposed to placing the INPUT
1108
- in the LABEL, so that we can include multiple INPUT
1109
- elements (e.g. a set of radio buttons).
1105
+ .input-with-label is intended to be a wrapper element which contain
1106
+ both a LABEL tag and an INPUT or SELECT control. The wrapper is
1107
+ "necessary", as opposed to placing the INPUT in the LABEL, so that
1108
+ we can include multiple INPUT elements (e.g. a set of radio
1109
+ buttons). Note that these elements must sometimes be BLOCK elements
1110
+ (e.g. DIV) so that certain nesting constructs are legal.
11101111
*/
11111112
.input-with-label {
11121113
border: 1px inset #808080;
11131114
border-radius: 0.25em;
11141115
padding: 0.25em 0.4em;
@@ -1293,5 +1294,58 @@
12931294
12941295
blockquote.file-content {
12951296
/* file content block in the /file page */
12961297
margin: 0 1em;
12971298
}
1299
+
1300
+
1301
+/**
1302
+ Circular "help" buttons intended to be placed to the right of
1303
+ another element and hold text text for it. These get initialized
1304
+ automatically at page startup via fossil.popupwidget.js. All child
1305
+ content gets moved out of the DOM and shown in a popup when they
1306
+ are clicked. They may be SPAN elements if their children are all
1307
+ inline elements, otherwise they must be DIVs (block elements)
1308
+ so that nesting of block elements is legal.
1309
+*/
1310
+.help-buttonlet {
1311
+ display: inline-block;
1312
+ min-width: 1rem;
1313
+ max-width: 1rem;
1314
+ min-height: 1rem;
1315
+ max-height: 1rem;
1316
+ font-size: 0.9em;
1317
+ border-radius: 0.5rem;
1318
+ background-color: rgba(54, 54, 255,0.4);
1319
+ color: rgb(255, 255, 255);
1320
+ cursor: pointer;
1321
+ font-family: monspace;
1322
+ text-align: center;
1323
+ margin: 0 0 0 0.35em;
1324
+ border-width: 1px;
1325
+ border-style: outset;
1326
+ font-weight: 700;
1327
+ overflow: hidden;
1328
+}
1329
+
1330
+.help-buttonlet::before {
1331
+ content: "?";
1332
+}
1333
+
1334
+/**
1335
+ We really want to hide all help text via CSS but CSS cannot select
1336
+ TEXT nodes. Thus we move them out of the way programmatically
1337
+ during initialization.
1338
+*/
1339
+.help-buttonlet > *{}
1340
+
1341
+/**
1342
+ CSS class for PopupWidget which wraps .help-buttonlet content.
1343
+ They also have class fossil-tooltip. We need an overly-exact
1344
+ selector here to be certain that this class's style overrides
1345
+ that of fossil-tooltip.
1346
+*/
1347
+.fossil-tooltip.help-buttonlet-content {
1348
+ cursor: default;
1349
+ text-align: left;
1350
+ border-style: outset;
1351
+}
12981352
--- src/default.css
+++ src/default.css
@@ -1100,15 +1100,16 @@
1100 .font-size-200 {
1101 font-size: 200%;
1102 }
1103
1104 /**
1105 .input-with-label is intended to be a wrapper element which
1106 contain both a LABEL tag and an INPUT or SELECT control.
1107 The wrapper is "necessary", as opposed to placing the INPUT
1108 in the LABEL, so that we can include multiple INPUT
1109 elements (e.g. a set of radio buttons).
 
1110 */
1111 .input-with-label {
1112 border: 1px inset #808080;
1113 border-radius: 0.25em;
1114 padding: 0.25em 0.4em;
@@ -1293,5 +1294,58 @@
1293
1294 blockquote.file-content {
1295 /* file content block in the /file page */
1296 margin: 0 1em;
1297 }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1298
--- src/default.css
+++ src/default.css
@@ -1100,15 +1100,16 @@
1100 .font-size-200 {
1101 font-size: 200%;
1102 }
1103
1104 /**
1105 .input-with-label is intended to be a wrapper element which contain
1106 both a LABEL tag and an INPUT or SELECT control. The wrapper is
1107 "necessary", as opposed to placing the INPUT in the LABEL, so that
1108 we can include multiple INPUT elements (e.g. a set of radio
1109 buttons). Note that these elements must sometimes be BLOCK elements
1110 (e.g. DIV) so that certain nesting constructs are legal.
1111 */
1112 .input-with-label {
1113 border: 1px inset #808080;
1114 border-radius: 0.25em;
1115 padding: 0.25em 0.4em;
@@ -1293,5 +1294,58 @@
1294
1295 blockquote.file-content {
1296 /* file content block in the /file page */
1297 margin: 0 1em;
1298 }
1299
1300
1301 /**
1302 Circular "help" buttons intended to be placed to the right of
1303 another element and hold text text for it. These get initialized
1304 automatically at page startup via fossil.popupwidget.js. All child
1305 content gets moved out of the DOM and shown in a popup when they
1306 are clicked. They may be SPAN elements if their children are all
1307 inline elements, otherwise they must be DIVs (block elements)
1308 so that nesting of block elements is legal.
1309 */
1310 .help-buttonlet {
1311 display: inline-block;
1312 min-width: 1rem;
1313 max-width: 1rem;
1314 min-height: 1rem;
1315 max-height: 1rem;
1316 font-size: 0.9em;
1317 border-radius: 0.5rem;
1318 background-color: rgba(54, 54, 255,0.4);
1319 color: rgb(255, 255, 255);
1320 cursor: pointer;
1321 font-family: monspace;
1322 text-align: center;
1323 margin: 0 0 0 0.35em;
1324 border-width: 1px;
1325 border-style: outset;
1326 font-weight: 700;
1327 overflow: hidden;
1328 }
1329
1330 .help-buttonlet::before {
1331 content: "?";
1332 }
1333
1334 /**
1335 We really want to hide all help text via CSS but CSS cannot select
1336 TEXT nodes. Thus we move them out of the way programmatically
1337 during initialization.
1338 */
1339 .help-buttonlet > *{}
1340
1341 /**
1342 CSS class for PopupWidget which wraps .help-buttonlet content.
1343 They also have class fossil-tooltip. We need an overly-exact
1344 selector here to be certain that this class's style overrides
1345 that of fossil-tooltip.
1346 */
1347 .fossil-tooltip.help-buttonlet-content {
1348 cursor: default;
1349 text-align: left;
1350 border-style: outset;
1351 }
1352
--- src/fileedit.c
+++ src/fileedit.c
@@ -1980,12 +1980,18 @@
19801980
CX("</ul>");
19811981
}
19821982
CX("</div>"/*#fileedit-tab-help*/);
19831983
19841984
builtin_request_js("sbsdiff.js");
1985
+#if 0
19851986
style_emit_fossil_js_apis(0, "fetch", "dom", "tabs", "confirmer",
19861987
"storage", 0);
1988
+#else
1989
+ style_emit_all_fossil_js_apis();
1990
+ builtin_fulfill_js_requests();
1991
+ builtin_request_js("fossil.page.fileedit.js");
1992
+#endif
19871993
builtin_fulfill_js_requests();
19881994
/*
19891995
** Set up a JS-side mapping of the AJAX_RENDER_xyz values. This is
19901996
** used for dynamically toggling certain UI components on and off.
19911997
** Must come after window.fossil has been intialized and before
19921998
--- src/fileedit.c
+++ src/fileedit.c
@@ -1980,12 +1980,18 @@
1980 CX("</ul>");
1981 }
1982 CX("</div>"/*#fileedit-tab-help*/);
1983
1984 builtin_request_js("sbsdiff.js");
 
1985 style_emit_fossil_js_apis(0, "fetch", "dom", "tabs", "confirmer",
1986 "storage", 0);
 
 
 
 
 
1987 builtin_fulfill_js_requests();
1988 /*
1989 ** Set up a JS-side mapping of the AJAX_RENDER_xyz values. This is
1990 ** used for dynamically toggling certain UI components on and off.
1991 ** Must come after window.fossil has been intialized and before
1992
--- src/fileedit.c
+++ src/fileedit.c
@@ -1980,12 +1980,18 @@
1980 CX("</ul>");
1981 }
1982 CX("</div>"/*#fileedit-tab-help*/);
1983
1984 builtin_request_js("sbsdiff.js");
1985 #if 0
1986 style_emit_fossil_js_apis(0, "fetch", "dom", "tabs", "confirmer",
1987 "storage", 0);
1988 #else
1989 style_emit_all_fossil_js_apis();
1990 builtin_fulfill_js_requests();
1991 builtin_request_js("fossil.page.fileedit.js");
1992 #endif
1993 builtin_fulfill_js_requests();
1994 /*
1995 ** Set up a JS-side mapping of the AJAX_RENDER_xyz values. This is
1996 ** used for dynamically toggling certain UI components on and off.
1997 ** Must come after window.fossil has been intialized and before
1998
--- src/fossil.bootstrap.js
+++ src/fossil.bootstrap.js
@@ -328,10 +328,18 @@
328328
*/
329329
F.onPageLoad = function(callback){
330330
window.addEventListener('load', callback, false);
331331
return this;
332332
};
333
+ /**
334
+ Convenience wrapper which adds a DOMContentLoadedevent listener
335
+ to the window object. Returns this.
336
+ */
337
+ F.onDOMContentLoaded = function(callback){
338
+ window.addEventListener('DOMContentLoaded', callback, false);
339
+ return this;
340
+ };
333341
334342
/**
335343
Assuming name is a repo-style filename, this function returns
336344
a shortened form of that name:
337345
338346
--- src/fossil.bootstrap.js
+++ src/fossil.bootstrap.js
@@ -328,10 +328,18 @@
328 */
329 F.onPageLoad = function(callback){
330 window.addEventListener('load', callback, false);
331 return this;
332 };
 
 
 
 
 
 
 
 
333
334 /**
335 Assuming name is a repo-style filename, this function returns
336 a shortened form of that name:
337
338
--- src/fossil.bootstrap.js
+++ src/fossil.bootstrap.js
@@ -328,10 +328,18 @@
328 */
329 F.onPageLoad = function(callback){
330 window.addEventListener('load', callback, false);
331 return this;
332 };
333 /**
334 Convenience wrapper which adds a DOMContentLoadedevent listener
335 to the window object. Returns this.
336 */
337 F.onDOMContentLoaded = function(callback){
338 window.addEventListener('DOMContentLoaded', callback, false);
339 return this;
340 };
341
342 /**
343 Assuming name is a repo-style filename, this function returns
344 a shortened form of that name:
345
346
--- src/fossil.numbered-lines.js
+++ src/fossil.numbered-lines.js
@@ -6,19 +6,19 @@
66
77
Requires: fossil.bootstrap, fossil.dom, fossil.popupwidget,
88
fossil.copybutton
99
*/
1010
var tbl = arg || document.querySelectorAll('table.numbered-lines');
11
- if(!tbl) return /* no matching elements */;
12
- else if(!arg){
11
+ if(tbl && !arg){
1312
if(tbl.length>1){ /* multiple query results: recurse */
1413
tbl.forEach( (t)=>callee(t) );
1514
return;
1615
}else{/* single query result */
1716
tbl = tbl[0];
1817
}
1918
}
19
+ if(!tbl) return /* no matching elements */;
2020
const F = window.fossil, D = F.dom;
2121
const tdLn = tbl.querySelector('td.line-numbers');
2222
const lineState = {
2323
urlArgs: (window.location.search||'?')
2424
.replace(/&?\budc=[^&]*/,'') /* "update display prefs cookie" */
2525
--- src/fossil.numbered-lines.js
+++ src/fossil.numbered-lines.js
@@ -6,19 +6,19 @@
6
7 Requires: fossil.bootstrap, fossil.dom, fossil.popupwidget,
8 fossil.copybutton
9 */
10 var tbl = arg || document.querySelectorAll('table.numbered-lines');
11 if(!tbl) return /* no matching elements */;
12 else if(!arg){
13 if(tbl.length>1){ /* multiple query results: recurse */
14 tbl.forEach( (t)=>callee(t) );
15 return;
16 }else{/* single query result */
17 tbl = tbl[0];
18 }
19 }
 
20 const F = window.fossil, D = F.dom;
21 const tdLn = tbl.querySelector('td.line-numbers');
22 const lineState = {
23 urlArgs: (window.location.search||'?')
24 .replace(/&?\budc=[^&]*/,'') /* "update display prefs cookie" */
25
--- src/fossil.numbered-lines.js
+++ src/fossil.numbered-lines.js
@@ -6,19 +6,19 @@
6
7 Requires: fossil.bootstrap, fossil.dom, fossil.popupwidget,
8 fossil.copybutton
9 */
10 var tbl = arg || document.querySelectorAll('table.numbered-lines');
11 if(tbl && !arg){
 
12 if(tbl.length>1){ /* multiple query results: recurse */
13 tbl.forEach( (t)=>callee(t) );
14 return;
15 }else{/* single query result */
16 tbl = tbl[0];
17 }
18 }
19 if(!tbl) return /* no matching elements */;
20 const F = window.fossil, D = F.dom;
21 const tdLn = tbl.querySelector('td.line-numbers');
22 const lineState = {
23 urlArgs: (window.location.search||'?')
24 .replace(/&?\budc=[^&]*/,'') /* "update display prefs cookie" */
25
--- src/fossil.page.fileedit.js
+++ src/fossil.page.fileedit.js
@@ -492,10 +492,11 @@
492492
"Warning: persistent storage is not available, "+
493493
"so uncomitted edits will not survive a page reload."
494494
));
495495
}
496496
domInsertPoint.parentNode.insertBefore(wrapper, domInsertPoint);
497
+ P.tabs.switchToTab(1/*DOM visibility workaround*/);
497498
F.confirmer(btnClear, {
498499
/* must come after insertion into the DOM for the pinSize option to work. */
499500
pinSize: true,
500501
confirmText: "DISCARD all local edits?",
501502
onconfirm: function(e){
@@ -509,10 +510,11 @@
509510
},
510511
ticks: F.config.confirmerButtonTicks
511512
});
512513
D.addClass(this.e.btnClear,'hidden' /* must not be set until after confirmer is set up!*/);
513514
$stash._fireStashEvent(/*read the page-load-time stash*/);
515
+ P.tabs.switchToTab(0/*DOM visibility workaround*/);
514516
delete this.init;
515517
},
516518
/**
517519
Regenerates the edit selection list.
518520
*/
@@ -737,10 +739,11 @@
737739
"click",(e)=>P.diff(false), false
738740
);
739741
P.e.btnCommit.addEventListener(
740742
"click",(e)=>P.commit(), false
741743
);
744
+ P.tabs.switchToTab(1/*DOM visibility workaround*/);
742745
F.confirmer(P.e.btnReload, {
743746
pinSize: true,
744747
confirmText: "Really reload, losing edits?",
745748
onconfirm: (e)=>P.unstashContent().loadFile(),
746749
ticks: F.config.confirmerButtonTicks
747750
--- src/fossil.page.fileedit.js
+++ src/fossil.page.fileedit.js
@@ -492,10 +492,11 @@
492 "Warning: persistent storage is not available, "+
493 "so uncomitted edits will not survive a page reload."
494 ));
495 }
496 domInsertPoint.parentNode.insertBefore(wrapper, domInsertPoint);
 
497 F.confirmer(btnClear, {
498 /* must come after insertion into the DOM for the pinSize option to work. */
499 pinSize: true,
500 confirmText: "DISCARD all local edits?",
501 onconfirm: function(e){
@@ -509,10 +510,11 @@
509 },
510 ticks: F.config.confirmerButtonTicks
511 });
512 D.addClass(this.e.btnClear,'hidden' /* must not be set until after confirmer is set up!*/);
513 $stash._fireStashEvent(/*read the page-load-time stash*/);
 
514 delete this.init;
515 },
516 /**
517 Regenerates the edit selection list.
518 */
@@ -737,10 +739,11 @@
737 "click",(e)=>P.diff(false), false
738 );
739 P.e.btnCommit.addEventListener(
740 "click",(e)=>P.commit(), false
741 );
 
742 F.confirmer(P.e.btnReload, {
743 pinSize: true,
744 confirmText: "Really reload, losing edits?",
745 onconfirm: (e)=>P.unstashContent().loadFile(),
746 ticks: F.config.confirmerButtonTicks
747
--- src/fossil.page.fileedit.js
+++ src/fossil.page.fileedit.js
@@ -492,10 +492,11 @@
492 "Warning: persistent storage is not available, "+
493 "so uncomitted edits will not survive a page reload."
494 ));
495 }
496 domInsertPoint.parentNode.insertBefore(wrapper, domInsertPoint);
497 P.tabs.switchToTab(1/*DOM visibility workaround*/);
498 F.confirmer(btnClear, {
499 /* must come after insertion into the DOM for the pinSize option to work. */
500 pinSize: true,
501 confirmText: "DISCARD all local edits?",
502 onconfirm: function(e){
@@ -509,10 +510,11 @@
510 },
511 ticks: F.config.confirmerButtonTicks
512 });
513 D.addClass(this.e.btnClear,'hidden' /* must not be set until after confirmer is set up!*/);
514 $stash._fireStashEvent(/*read the page-load-time stash*/);
515 P.tabs.switchToTab(0/*DOM visibility workaround*/);
516 delete this.init;
517 },
518 /**
519 Regenerates the edit selection list.
520 */
@@ -737,10 +739,11 @@
739 "click",(e)=>P.diff(false), false
740 );
741 P.e.btnCommit.addEventListener(
742 "click",(e)=>P.commit(), false
743 );
744 P.tabs.switchToTab(1/*DOM visibility workaround*/);
745 F.confirmer(P.e.btnReload, {
746 pinSize: true,
747 confirmText: "Really reload, losing edits?",
748 onconfirm: (e)=>P.unstashContent().loadFile(),
749 ticks: F.config.confirmerButtonTicks
750
--- src/fossil.page.wikiedit.js
+++ src/fossil.page.wikiedit.js
@@ -2,11 +2,11 @@
22
"use strict";
33
/**
44
Client-side implementation of the /wikiedit app. Requires that
55
the fossil JS bootstrapping is complete and that several fossil
66
JS APIs have been installed: fossil.fetch, fossil.dom,
7
- fossil.tabs, fossil.storage, fossil.confirmer.
7
+ fossil.tabs, fossil.storage, fossil.confirmer, fossil.popupwidget.
88
99
Custom events which can be listened for via
1010
fossil.page.addEventListener():
1111
1212
- Event 'wiki-page-loaded': passes on information when it
@@ -557,11 +557,11 @@
557557
D.attr(sel, 'size', 12);
558558
D.option(D.disable(D.clearElement(sel)), "Loading...");
559559
560560
/** Set up filter checkboxes for the various types
561561
of wiki pages... */
562
- const fsFilter = D.fieldset("Page types"),
562
+ const fsFilter = D.addClass(D.fieldset("Page types"),"page-types-list"),
563563
fsFilterBody = D.div(),
564564
filters = ['normal', 'branch/...', 'tag/...', 'checkin/...']
565565
;
566566
D.append(fsFilter, fsFilterBody);
567567
D.addClass(fsFilterBody, 'flex-container', 'flex-column', 'stretch');
@@ -597,13 +597,18 @@
597597
'deleted'),
598598
'for', cbId),
599599
cb = D.attr(D.input('checkbox'), 'id', cbId);
600600
cb.checked = false;
601601
D.addClass(parentElem,'hide-deleted');
602
- D.attr(lbl, 'title',
603
- 'Fossil considers empty pages to be "deleted" in some contexts.');
604
- D.append(fsFilterBody, D.append(D.span(), cb, lbl));
602
+ D.attr(lbl);
603
+ const deletedTip = F.helpButtonlets.create(
604
+ D.span(),
605
+ 'Fossil considers empty pages to be "deleted" in some contexts.'
606
+ );
607
+ D.append(fsFilterBody, D.append(
608
+ D.span(), cb, lbl, deletedTip
609
+ ));
605610
cb.addEventListener(
606611
'change',
607612
function(ev){
608613
if(ev.target.checked) D.removeClass(parentElem,'hide-deleted');
609614
else D.addClass(parentElem,'hide-deleted');
@@ -682,22 +687,26 @@
682687
init: function(domInsertPoint/*insert widget BEFORE this element*/){
683688
const wrapper = D.addClass(
684689
D.attr(D.div(),'id','wikiedit-stash-selector'),
685690
'input-with-label'
686691
);
687
- const sel = this.e.select = D.select();
688
- const btnClear = this.e.btnClear = D.button("Discard Edits");
692
+ const sel = this.e.select = D.select(),
693
+ btnClear = this.e.btnClear = D.button("Discard Edits"),
694
+ btnHelp = D.append(
695
+ D.addClass(D.div(), "help-buttonlet"),
696
+ 'Locally-edited wiki pages. Timestamps are the last local edit time. ',
697
+ 'Only the ',P.config.defaultMaxStashSize,' most recent pages ',
698
+ 'are retained. Saving or reloading a file removes it from this list. ',
699
+ D.append(D.code(),'localStorage'),' uses browser-local persistent storage. ',
700
+ D.append(D.code(),'sessionStorage'),' uses storage local to this browser tab.'
701
+ );
689702
D.append(wrapper, "Local edits (",
690703
D.append(D.code(),
691704
F.storage.storageImplName()),
692705
"):",
693
- sel, btnClear);
694
- D.attr(wrapper, "title", [
695
- 'Locally-edited wiki pages. Timestamps are the last local edit time.',
696
- 'Only the',P.config.defaultMaxStashSize,'most recent pages',
697
- 'are retained. Saving or reloading a file removes it from this list.'
698
- ].join(' '));
706
+ btnHelp, sel, btnClear);
707
+ F.helpButtonlets.setup(btnHelp);
699708
D.option(D.disable(sel), "(empty)");
700709
P.addEventListener('wiki-stash-updated',(e)=>this.updateList(e.detail));
701710
P.addEventListener('wiki-page-loaded',(e)=>this.updateList($stash, e.detail));
702711
sel.addEventListener('change',function(e){
703712
const opt = this.selectedOptions[0];
@@ -835,13 +844,11 @@
835844
P.base.originalHref = P.base.tag.href;
836845
P.e = { /* various DOM elements we work with... */
837846
taEditor: E('#wikiedit-content-editor'),
838847
btnReload: E("#wikiedit-tab-content button.wikiedit-content-reload"),
839848
btnSave: E("button.wikiedit-save"),
840
- btnSaveClose: D.attr(E("button.wikiedit-save-close"),
841
- 'title',
842
- 'Save changes and return to the wiki reader.'),
849
+ btnSaveClose: E("button.wikiedit-save-close"),
843850
selectMimetype: E('select[name=mimetype]'),
844851
selectFontSizeWrap: E('#select-font-size'),
845852
// selectDiffWS: E('select[name=diff_ws]'),
846853
cbAutoPreview: E('#cb-preview-autoupdate > input[type=checkbox]'),
847854
previewTarget: E('#wikiedit-tab-preview-wrapper'),
@@ -870,12 +877,12 @@
870877
'before-switch-to', function(ev){
871878
const theTab = ev.detail, btnSlot = theTab.querySelector('.save-button-slot');
872879
if(btnSlot){
873880
/* Several places make sense for a save button, so we'll
874881
move that button around to those tabs where it makes sense. */
875
- btnSlot.parentNode.insertBefore( P.e.btnSave, btnSlot );
876
- btnSlot.parentNode.insertBefore( P.e.btnSaveClose, btnSlot );
882
+ btnSlot.parentNode.insertBefore( P.e.btnSave.parentNode, btnSlot );
883
+ btnSlot.parentNode.insertBefore( P.e.btnSaveClose.parentNode, btnSlot );
877884
P.updateSaveButton();
878885
}
879886
if(theTab===P.e.tabs.preview){
880887
P.baseHrefForWiki();
881888
if(P.previewNeedsUpdate && P.e.cbAutoPreview.checked) P.preview();
@@ -958,10 +965,11 @@
958965
F.message("Discarded new page ["+w.name+"].");
959966
}
960967
};
961968
962969
if(P.config.useConfirmerButtons.reload){
970
+ P.tabs.switchToTab(1/*DOM visibility workaround*/);
963971
F.confirmer(P.e.btnReload, {
964972
pinSize: true,
965973
confirmText: "Really reload, losing edits?",
966974
onconfirm: doReload,
967975
ticks: F.config.confirmerButtonTicks
@@ -968,10 +976,11 @@
968976
});
969977
}else{
970978
P.e.btnReload.addEventListener('click', doReload, false);
971979
}
972980
if(P.config.useConfirmerButtons.save){
981
+ P.tabs.switchToTab(1/*DOM visibility workaround*/);
973982
F.confirmer(P.e.btnSave, {
974983
pinSize: true,
975984
confirmText: "Really save changes?",
976985
onconfirm: ()=>doSave(),
977986
ticks: F.config.confirmerButtonTicks
@@ -1069,13 +1078,19 @@
10691078
}
10701079
P.updatePageTitle().updateSaveButton(/* b/c save() routes through here */);
10711080
},
10721081
false
10731082
);
1074
- /* These init()s need to come after P's event handlers are registered */
1083
+ /* These init()s need to come after P's event handlers are registered.
1084
+ The tab-switching is a workaround for the pinSize option of the confirmer widgets:
1085
+ it does not work if the confirmer button being initialized is in a hidden
1086
+ part of the DOM :/. */
1087
+ P.tabs.switchToTab(0);
10751088
WikiList.init( P.e.tabs.pageList.firstElementChild );
1089
+ P.tabs.switchToTab(1);
10761090
P.stashWidget.init(P.e.tabs.content.lastElementChild);
1091
+ P.tabs.switchToTab(0);
10771092
//P.$wikiList = WikiList/*only for testing/debugging*/;
10781093
}/*F.onPageLoad()*/);
10791094
10801095
/**
10811096
Returns true if fossil.page.winfo is set, indicating that a page
10821097
--- src/fossil.page.wikiedit.js
+++ src/fossil.page.wikiedit.js
@@ -2,11 +2,11 @@
2 "use strict";
3 /**
4 Client-side implementation of the /wikiedit app. Requires that
5 the fossil JS bootstrapping is complete and that several fossil
6 JS APIs have been installed: fossil.fetch, fossil.dom,
7 fossil.tabs, fossil.storage, fossil.confirmer.
8
9 Custom events which can be listened for via
10 fossil.page.addEventListener():
11
12 - Event 'wiki-page-loaded': passes on information when it
@@ -557,11 +557,11 @@
557 D.attr(sel, 'size', 12);
558 D.option(D.disable(D.clearElement(sel)), "Loading...");
559
560 /** Set up filter checkboxes for the various types
561 of wiki pages... */
562 const fsFilter = D.fieldset("Page types"),
563 fsFilterBody = D.div(),
564 filters = ['normal', 'branch/...', 'tag/...', 'checkin/...']
565 ;
566 D.append(fsFilter, fsFilterBody);
567 D.addClass(fsFilterBody, 'flex-container', 'flex-column', 'stretch');
@@ -597,13 +597,18 @@
597 'deleted'),
598 'for', cbId),
599 cb = D.attr(D.input('checkbox'), 'id', cbId);
600 cb.checked = false;
601 D.addClass(parentElem,'hide-deleted');
602 D.attr(lbl, 'title',
603 'Fossil considers empty pages to be "deleted" in some contexts.');
604 D.append(fsFilterBody, D.append(D.span(), cb, lbl));
 
 
 
 
 
605 cb.addEventListener(
606 'change',
607 function(ev){
608 if(ev.target.checked) D.removeClass(parentElem,'hide-deleted');
609 else D.addClass(parentElem,'hide-deleted');
@@ -682,22 +687,26 @@
682 init: function(domInsertPoint/*insert widget BEFORE this element*/){
683 const wrapper = D.addClass(
684 D.attr(D.div(),'id','wikiedit-stash-selector'),
685 'input-with-label'
686 );
687 const sel = this.e.select = D.select();
688 const btnClear = this.e.btnClear = D.button("Discard Edits");
 
 
 
 
 
 
 
 
689 D.append(wrapper, "Local edits (",
690 D.append(D.code(),
691 F.storage.storageImplName()),
692 "):",
693 sel, btnClear);
694 D.attr(wrapper, "title", [
695 'Locally-edited wiki pages. Timestamps are the last local edit time.',
696 'Only the',P.config.defaultMaxStashSize,'most recent pages',
697 'are retained. Saving or reloading a file removes it from this list.'
698 ].join(' '));
699 D.option(D.disable(sel), "(empty)");
700 P.addEventListener('wiki-stash-updated',(e)=>this.updateList(e.detail));
701 P.addEventListener('wiki-page-loaded',(e)=>this.updateList($stash, e.detail));
702 sel.addEventListener('change',function(e){
703 const opt = this.selectedOptions[0];
@@ -835,13 +844,11 @@
835 P.base.originalHref = P.base.tag.href;
836 P.e = { /* various DOM elements we work with... */
837 taEditor: E('#wikiedit-content-editor'),
838 btnReload: E("#wikiedit-tab-content button.wikiedit-content-reload"),
839 btnSave: E("button.wikiedit-save"),
840 btnSaveClose: D.attr(E("button.wikiedit-save-close"),
841 'title',
842 'Save changes and return to the wiki reader.'),
843 selectMimetype: E('select[name=mimetype]'),
844 selectFontSizeWrap: E('#select-font-size'),
845 // selectDiffWS: E('select[name=diff_ws]'),
846 cbAutoPreview: E('#cb-preview-autoupdate > input[type=checkbox]'),
847 previewTarget: E('#wikiedit-tab-preview-wrapper'),
@@ -870,12 +877,12 @@
870 'before-switch-to', function(ev){
871 const theTab = ev.detail, btnSlot = theTab.querySelector('.save-button-slot');
872 if(btnSlot){
873 /* Several places make sense for a save button, so we'll
874 move that button around to those tabs where it makes sense. */
875 btnSlot.parentNode.insertBefore( P.e.btnSave, btnSlot );
876 btnSlot.parentNode.insertBefore( P.e.btnSaveClose, btnSlot );
877 P.updateSaveButton();
878 }
879 if(theTab===P.e.tabs.preview){
880 P.baseHrefForWiki();
881 if(P.previewNeedsUpdate && P.e.cbAutoPreview.checked) P.preview();
@@ -958,10 +965,11 @@
958 F.message("Discarded new page ["+w.name+"].");
959 }
960 };
961
962 if(P.config.useConfirmerButtons.reload){
 
963 F.confirmer(P.e.btnReload, {
964 pinSize: true,
965 confirmText: "Really reload, losing edits?",
966 onconfirm: doReload,
967 ticks: F.config.confirmerButtonTicks
@@ -968,10 +976,11 @@
968 });
969 }else{
970 P.e.btnReload.addEventListener('click', doReload, false);
971 }
972 if(P.config.useConfirmerButtons.save){
 
973 F.confirmer(P.e.btnSave, {
974 pinSize: true,
975 confirmText: "Really save changes?",
976 onconfirm: ()=>doSave(),
977 ticks: F.config.confirmerButtonTicks
@@ -1069,13 +1078,19 @@
1069 }
1070 P.updatePageTitle().updateSaveButton(/* b/c save() routes through here */);
1071 },
1072 false
1073 );
1074 /* These init()s need to come after P's event handlers are registered */
 
 
 
 
1075 WikiList.init( P.e.tabs.pageList.firstElementChild );
 
1076 P.stashWidget.init(P.e.tabs.content.lastElementChild);
 
1077 //P.$wikiList = WikiList/*only for testing/debugging*/;
1078 }/*F.onPageLoad()*/);
1079
1080 /**
1081 Returns true if fossil.page.winfo is set, indicating that a page
1082
--- src/fossil.page.wikiedit.js
+++ src/fossil.page.wikiedit.js
@@ -2,11 +2,11 @@
2 "use strict";
3 /**
4 Client-side implementation of the /wikiedit app. Requires that
5 the fossil JS bootstrapping is complete and that several fossil
6 JS APIs have been installed: fossil.fetch, fossil.dom,
7 fossil.tabs, fossil.storage, fossil.confirmer, fossil.popupwidget.
8
9 Custom events which can be listened for via
10 fossil.page.addEventListener():
11
12 - Event 'wiki-page-loaded': passes on information when it
@@ -557,11 +557,11 @@
557 D.attr(sel, 'size', 12);
558 D.option(D.disable(D.clearElement(sel)), "Loading...");
559
560 /** Set up filter checkboxes for the various types
561 of wiki pages... */
562 const fsFilter = D.addClass(D.fieldset("Page types"),"page-types-list"),
563 fsFilterBody = D.div(),
564 filters = ['normal', 'branch/...', 'tag/...', 'checkin/...']
565 ;
566 D.append(fsFilter, fsFilterBody);
567 D.addClass(fsFilterBody, 'flex-container', 'flex-column', 'stretch');
@@ -597,13 +597,18 @@
597 'deleted'),
598 'for', cbId),
599 cb = D.attr(D.input('checkbox'), 'id', cbId);
600 cb.checked = false;
601 D.addClass(parentElem,'hide-deleted');
602 D.attr(lbl);
603 const deletedTip = F.helpButtonlets.create(
604 D.span(),
605 'Fossil considers empty pages to be "deleted" in some contexts.'
606 );
607 D.append(fsFilterBody, D.append(
608 D.span(), cb, lbl, deletedTip
609 ));
610 cb.addEventListener(
611 'change',
612 function(ev){
613 if(ev.target.checked) D.removeClass(parentElem,'hide-deleted');
614 else D.addClass(parentElem,'hide-deleted');
@@ -682,22 +687,26 @@
687 init: function(domInsertPoint/*insert widget BEFORE this element*/){
688 const wrapper = D.addClass(
689 D.attr(D.div(),'id','wikiedit-stash-selector'),
690 'input-with-label'
691 );
692 const sel = this.e.select = D.select(),
693 btnClear = this.e.btnClear = D.button("Discard Edits"),
694 btnHelp = D.append(
695 D.addClass(D.div(), "help-buttonlet"),
696 'Locally-edited wiki pages. Timestamps are the last local edit time. ',
697 'Only the ',P.config.defaultMaxStashSize,' most recent pages ',
698 'are retained. Saving or reloading a file removes it from this list. ',
699 D.append(D.code(),'localStorage'),' uses browser-local persistent storage. ',
700 D.append(D.code(),'sessionStorage'),' uses storage local to this browser tab.'
701 );
702 D.append(wrapper, "Local edits (",
703 D.append(D.code(),
704 F.storage.storageImplName()),
705 "):",
706 btnHelp, sel, btnClear);
707 F.helpButtonlets.setup(btnHelp);
 
 
 
 
708 D.option(D.disable(sel), "(empty)");
709 P.addEventListener('wiki-stash-updated',(e)=>this.updateList(e.detail));
710 P.addEventListener('wiki-page-loaded',(e)=>this.updateList($stash, e.detail));
711 sel.addEventListener('change',function(e){
712 const opt = this.selectedOptions[0];
@@ -835,13 +844,11 @@
844 P.base.originalHref = P.base.tag.href;
845 P.e = { /* various DOM elements we work with... */
846 taEditor: E('#wikiedit-content-editor'),
847 btnReload: E("#wikiedit-tab-content button.wikiedit-content-reload"),
848 btnSave: E("button.wikiedit-save"),
849 btnSaveClose: E("button.wikiedit-save-close"),
 
 
850 selectMimetype: E('select[name=mimetype]'),
851 selectFontSizeWrap: E('#select-font-size'),
852 // selectDiffWS: E('select[name=diff_ws]'),
853 cbAutoPreview: E('#cb-preview-autoupdate > input[type=checkbox]'),
854 previewTarget: E('#wikiedit-tab-preview-wrapper'),
@@ -870,12 +877,12 @@
877 'before-switch-to', function(ev){
878 const theTab = ev.detail, btnSlot = theTab.querySelector('.save-button-slot');
879 if(btnSlot){
880 /* Several places make sense for a save button, so we'll
881 move that button around to those tabs where it makes sense. */
882 btnSlot.parentNode.insertBefore( P.e.btnSave.parentNode, btnSlot );
883 btnSlot.parentNode.insertBefore( P.e.btnSaveClose.parentNode, btnSlot );
884 P.updateSaveButton();
885 }
886 if(theTab===P.e.tabs.preview){
887 P.baseHrefForWiki();
888 if(P.previewNeedsUpdate && P.e.cbAutoPreview.checked) P.preview();
@@ -958,10 +965,11 @@
965 F.message("Discarded new page ["+w.name+"].");
966 }
967 };
968
969 if(P.config.useConfirmerButtons.reload){
970 P.tabs.switchToTab(1/*DOM visibility workaround*/);
971 F.confirmer(P.e.btnReload, {
972 pinSize: true,
973 confirmText: "Really reload, losing edits?",
974 onconfirm: doReload,
975 ticks: F.config.confirmerButtonTicks
@@ -968,10 +976,11 @@
976 });
977 }else{
978 P.e.btnReload.addEventListener('click', doReload, false);
979 }
980 if(P.config.useConfirmerButtons.save){
981 P.tabs.switchToTab(1/*DOM visibility workaround*/);
982 F.confirmer(P.e.btnSave, {
983 pinSize: true,
984 confirmText: "Really save changes?",
985 onconfirm: ()=>doSave(),
986 ticks: F.config.confirmerButtonTicks
@@ -1069,13 +1078,19 @@
1078 }
1079 P.updatePageTitle().updateSaveButton(/* b/c save() routes through here */);
1080 },
1081 false
1082 );
1083 /* These init()s need to come after P's event handlers are registered.
1084 The tab-switching is a workaround for the pinSize option of the confirmer widgets:
1085 it does not work if the confirmer button being initialized is in a hidden
1086 part of the DOM :/. */
1087 P.tabs.switchToTab(0);
1088 WikiList.init( P.e.tabs.pageList.firstElementChild );
1089 P.tabs.switchToTab(1);
1090 P.stashWidget.init(P.e.tabs.content.lastElementChild);
1091 P.tabs.switchToTab(0);
1092 //P.$wikiList = WikiList/*only for testing/debugging*/;
1093 }/*F.onPageLoad()*/);
1094
1095 /**
1096 Returns true if fossil.page.winfo is set, indicating that a page
1097
--- src/fossil.popupwidget.js
+++ src/fossil.popupwidget.js
@@ -264,6 +264,113 @@
264264
error: function(/*...*/){
265265
return toastImpl('error',2,arguments);
266266
}
267267
}/*F.toast*/;
268268
269
+
270
+ F.helpButtonlets = {
271
+ /**
272
+ Initializes one or more "help buttonlets". It may be passed any of:
273
+
274
+ - A string: CSS selector (multiple matches are legal)
275
+
276
+ - A single DOM element.
277
+
278
+ - A forEach-compatible container of DOM elements.
279
+
280
+ - No arguments, which is equivalent to passing the string
281
+ ".help-buttonlet:not(.processed)".
282
+
283
+ Passing the same element(s) more than once is a no-op: during
284
+ initialization, each elements get the class'processed' added to
285
+ it, and any elements with that class are skipped.
286
+
287
+ All child nodes of a help buttonlet are removed from the button
288
+ during initialization and stashed away for use in a PopupWidget
289
+ when the botton is clicked.
290
+
291
+ */
292
+ setup: function f(){
293
+ if(!f.clickHandler){
294
+ f.clickHandler = function fch(ev){
295
+ if(!fch.popup){
296
+ fch.popup = new F.PopupWidget({
297
+ cssClass: ['fossil-tooltip', 'help-buttonlet-content'],
298
+ refresh: function(){
299
+ }
300
+ });
301
+ const hide = ()=>fch.popup.hide();
302
+ fch.popup.e.addEventListener('click', hide, false);
303
+ document.body.addEventListener('click', hide, true);
304
+ document.body.addEventListener('keydown', function(ev){
305
+ if(fch.popup.isShown() && 27===ev.which){
306
+ fch.popup.hide();
307
+ }
308
+ }, true);
309
+ }
310
+ D.append(D.clearElement(fch.popup.e), ev.target.$helpContent);
311
+ const rect1 = ev.target.getClientRects()[0];
312
+ var x = rect1.left, y = rect1.top;
313
+ if(x<0) x = 0;
314
+ if(y<0) y = 0;
315
+ /* shift help to the left 1/2 the width of fch.popup.e. However,
316
+ fch.popup.e.getClientRects() is empty until the popup is shown,
317
+ so we have to show it, calculate that size, then move it. */
318
+ fch.popup.show(x, y);
319
+ const rect2 = fch.popup.e.getClientRects()[0];
320
+ x -= rect2.width/2;
321
+ if(x<0) x = 0;
322
+ fch.popup.show(x, y);
323
+ };
324
+ }
325
+ var elems;
326
+ if(!arguments.length){
327
+ arguments[0] = '.help-buttonlet:not(.processed)';
328
+ arguments.length = 1;
329
+ }
330
+ if(arguments.length){
331
+ if('string'===typeof arguments[0]){
332
+ elems = document.querySelectorAll(arguments[0]);
333
+ }else if(arguments[0] instanceof HTMLElement){
334
+ elems = [arguments[0]];
335
+ }else{/* assume DOM element list or array */
336
+ elems = arguments[0];
337
+ }
338
+ }
339
+ if(!elems) return;
340
+ elems.forEach(function(e){
341
+ if(e.classList.contains('processed')) return;
342
+ e.classList.add('processed');
343
+ e.$helpContent = [];
344
+ /* We have to move all child nodes out of the way because we
345
+ cannot hide TEXT nodes via CSS (which cannot select TEXT
346
+ nodes). We have to do it in two steps to avoid invaliding
347
+ the list during traversal. */
348
+ e.childNodes.forEach((ch)=>e.$helpContent.push(ch));
349
+ e.$helpContent.forEach((ch)=>ch.remove());
350
+ e.addEventListener('click', f.clickHandler, false);
351
+ });
352
+ },
353
+
354
+ /**
355
+ Sets up the given element as a "help buttonlet", adding the CSS
356
+ class help-buttonlet to it. Any (optional) arguments after the
357
+ first are appended to the element using fossil.dom.append(), so
358
+ that they become the content for the buttonlet's popup help.
359
+
360
+ The element is then passed to this.setup() before it
361
+ is returned from this function.
362
+ */
363
+ create: function(elem/*...body*/){
364
+ D.addClass(elem, 'help-buttonlet');
365
+ if(arguments.length>1){
366
+ const args = Array.prototype.slice.call(arguments,1);
367
+ D.append(elem, args);
368
+ }
369
+ this.setup(elem);
370
+ return elem;
371
+ }
372
+ }/*helpButtonlets*/;
373
+
374
+ F.onDOMContentLoaded( ()=>F.helpButtonlets.setup() );
375
+
269376
})(window.fossil);
270377
--- src/fossil.popupwidget.js
+++ src/fossil.popupwidget.js
@@ -264,6 +264,113 @@
264 error: function(/*...*/){
265 return toastImpl('error',2,arguments);
266 }
267 }/*F.toast*/;
268
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
269 })(window.fossil);
270
--- src/fossil.popupwidget.js
+++ src/fossil.popupwidget.js
@@ -264,6 +264,113 @@
264 error: function(/*...*/){
265 return toastImpl('error',2,arguments);
266 }
267 }/*F.toast*/;
268
269
270 F.helpButtonlets = {
271 /**
272 Initializes one or more "help buttonlets". It may be passed any of:
273
274 - A string: CSS selector (multiple matches are legal)
275
276 - A single DOM element.
277
278 - A forEach-compatible container of DOM elements.
279
280 - No arguments, which is equivalent to passing the string
281 ".help-buttonlet:not(.processed)".
282
283 Passing the same element(s) more than once is a no-op: during
284 initialization, each elements get the class'processed' added to
285 it, and any elements with that class are skipped.
286
287 All child nodes of a help buttonlet are removed from the button
288 during initialization and stashed away for use in a PopupWidget
289 when the botton is clicked.
290
291 */
292 setup: function f(){
293 if(!f.clickHandler){
294 f.clickHandler = function fch(ev){
295 if(!fch.popup){
296 fch.popup = new F.PopupWidget({
297 cssClass: ['fossil-tooltip', 'help-buttonlet-content'],
298 refresh: function(){
299 }
300 });
301 const hide = ()=>fch.popup.hide();
302 fch.popup.e.addEventListener('click', hide, false);
303 document.body.addEventListener('click', hide, true);
304 document.body.addEventListener('keydown', function(ev){
305 if(fch.popup.isShown() && 27===ev.which){
306 fch.popup.hide();
307 }
308 }, true);
309 }
310 D.append(D.clearElement(fch.popup.e), ev.target.$helpContent);
311 const rect1 = ev.target.getClientRects()[0];
312 var x = rect1.left, y = rect1.top;
313 if(x<0) x = 0;
314 if(y<0) y = 0;
315 /* shift help to the left 1/2 the width of fch.popup.e. However,
316 fch.popup.e.getClientRects() is empty until the popup is shown,
317 so we have to show it, calculate that size, then move it. */
318 fch.popup.show(x, y);
319 const rect2 = fch.popup.e.getClientRects()[0];
320 x -= rect2.width/2;
321 if(x<0) x = 0;
322 fch.popup.show(x, y);
323 };
324 }
325 var elems;
326 if(!arguments.length){
327 arguments[0] = '.help-buttonlet:not(.processed)';
328 arguments.length = 1;
329 }
330 if(arguments.length){
331 if('string'===typeof arguments[0]){
332 elems = document.querySelectorAll(arguments[0]);
333 }else if(arguments[0] instanceof HTMLElement){
334 elems = [arguments[0]];
335 }else{/* assume DOM element list or array */
336 elems = arguments[0];
337 }
338 }
339 if(!elems) return;
340 elems.forEach(function(e){
341 if(e.classList.contains('processed')) return;
342 e.classList.add('processed');
343 e.$helpContent = [];
344 /* We have to move all child nodes out of the way because we
345 cannot hide TEXT nodes via CSS (which cannot select TEXT
346 nodes). We have to do it in two steps to avoid invaliding
347 the list during traversal. */
348 e.childNodes.forEach((ch)=>e.$helpContent.push(ch));
349 e.$helpContent.forEach((ch)=>ch.remove());
350 e.addEventListener('click', f.clickHandler, false);
351 });
352 },
353
354 /**
355 Sets up the given element as a "help buttonlet", adding the CSS
356 class help-buttonlet to it. Any (optional) arguments after the
357 first are appended to the element using fossil.dom.append(), so
358 that they become the content for the buttonlet's popup help.
359
360 The element is then passed to this.setup() before it
361 is returned from this function.
362 */
363 create: function(elem/*...body*/){
364 D.addClass(elem, 'help-buttonlet');
365 if(arguments.length>1){
366 const args = Array.prototype.slice.call(arguments,1);
367 D.append(elem, args);
368 }
369 this.setup(elem);
370 return elem;
371 }
372 }/*helpButtonlets*/;
373
374 F.onDOMContentLoaded( ()=>F.helpButtonlets.setup() );
375
376 })(window.fossil);
377
+4
--- src/info.c
+++ src/info.c
@@ -2118,12 +2118,16 @@
21182118
cgi_printf("%z", htmlize(z, nZ));
21192119
CX("</code></pre></td></tr></tbody></table>\n");
21202120
if( db_int(0, "SELECT EXISTS(SELECT 1 FROM lnos)") ){
21212121
builtin_request_js("scroll.js");
21222122
}
2123
+#if 0
21232124
style_emit_fossil_js_apis(0, "dom", "copybutton", "popupwidget",
21242125
"numbered-lines", 0);
2126
+#else
2127
+ style_emit_all_fossil_js_apis();
2128
+#endif
21252129
}
21262130
21272131
/*
21282132
** COMMAND: test-line-numbers
21292133
**
21302134
--- src/info.c
+++ src/info.c
@@ -2118,12 +2118,16 @@
2118 cgi_printf("%z", htmlize(z, nZ));
2119 CX("</code></pre></td></tr></tbody></table>\n");
2120 if( db_int(0, "SELECT EXISTS(SELECT 1 FROM lnos)") ){
2121 builtin_request_js("scroll.js");
2122 }
 
2123 style_emit_fossil_js_apis(0, "dom", "copybutton", "popupwidget",
2124 "numbered-lines", 0);
 
 
 
2125 }
2126
2127 /*
2128 ** COMMAND: test-line-numbers
2129 **
2130
--- src/info.c
+++ src/info.c
@@ -2118,12 +2118,16 @@
2118 cgi_printf("%z", htmlize(z, nZ));
2119 CX("</code></pre></td></tr></tbody></table>\n");
2120 if( db_int(0, "SELECT EXISTS(SELECT 1 FROM lnos)") ){
2121 builtin_request_js("scroll.js");
2122 }
2123 #if 0
2124 style_emit_fossil_js_apis(0, "dom", "copybutton", "popupwidget",
2125 "numbered-lines", 0);
2126 #else
2127 style_emit_all_fossil_js_apis();
2128 #endif
2129 }
2130
2131 /*
2132 ** COMMAND: test-line-numbers
2133 **
2134
+25 -10
--- src/style.c
+++ src/style.c
@@ -1230,16 +1230,16 @@
12301230
** element. If isChecked is true, the checkbox gets the "checked"
12311231
** attribute set, else it is not.
12321232
**
12331233
** Resulting structure:
12341234
**
1235
-** <span class='input-with-label' title={{zTip}} id={{zWrapperId}}>
1235
+** <div class='input-with-label' title={{zTip}} id={{zWrapperId}}>
12361236
** <input type='checkbox' name={{zFieldName}} value={{zValue}}
12371237
** id='A RANDOM VALUE'
12381238
** {{isChecked ? " checked : ""}}/>
12391239
** <label for='ID OF THE INPUT FIELD'>{{zLabel}}</label>
1240
-** </span>
1240
+** </div>
12411241
**
12421242
** zLabel, and zValue are required. zFieldName, zWrapperId, and zTip
12431243
** are may be NULL or empty.
12441244
**
12451245
** Be sure that the input-with-label CSS class is defined sensibly, in
@@ -1249,11 +1249,11 @@
12491249
void style_labeled_checkbox(const char * zWrapperId,
12501250
const char *zFieldName, const char * zLabel,
12511251
const char * zValue, int isChecked,
12521252
const char * zTip){
12531253
char * zLabelID = style_next_input_id();
1254
- CX("<span class='input-with-label'");
1254
+ CX("<div class='input-with-label'");
12551255
if(zTip && *zTip){
12561256
CX(" title='%h'", zTip);
12571257
}
12581258
if(zWrapperId && *zWrapperId){
12591259
CX(" id='%s'",zWrapperId);
@@ -1262,11 +1262,11 @@
12621262
if(zFieldName && *zFieldName){
12631263
CX("name='%s' ",zFieldName);
12641264
}
12651265
CX("value='%T'%s/>",
12661266
zValue ? zValue : "", isChecked ? " checked" : "");
1267
- CX("<label for='%s'>%h</label></span>", zLabelID, zLabel);
1267
+ CX("<label for='%s'>%h</label></div>", zLabelID, zLabel);
12681268
fossil_free(zLabelID);
12691269
}
12701270
12711271
/*
12721272
** Outputs a SELECT list from a compile-time list of integers.
@@ -1296,14 +1296,14 @@
12961296
**
12971297
** zTooltip is an optional value for the SELECT's title attribute.
12981298
**
12991299
** The structure of the emitted HTML is:
13001300
**
1301
-** <span class='input-with-label' title={{zToolTip}} id={{zWrapperId}}>
1301
+** <div class='input-with-label' title={{zToolTip}} id={{zWrapperId}}>
13021302
** <label for='SELECT ELEMENT ID'>{{zLabel}}</label>
13031303
** <select id='RANDOM ID' name={{zFieldName}}>...</select>
1304
-** </span>
1304
+** </div>
13051305
**
13061306
** Example:
13071307
**
13081308
** style_select_list_int("my-grapes", "my_grapes", "Grapes",
13091309
** "Select the number of grapes",
@@ -1318,11 +1318,11 @@
13181318
... ){
13191319
char * zLabelID = style_next_input_id();
13201320
va_list vargs;
13211321
13221322
va_start(vargs,selectedVal);
1323
- CX("<span class='input-with-label'");
1323
+ CX("<div class='input-with-label'");
13241324
if(zToolTip && *zToolTip){
13251325
CX(" title='%h'",zToolTip);
13261326
}
13271327
if(zWrapperId && *zWrapperId){
13281328
CX(" id='%s'",zWrapperId);
@@ -1347,11 +1347,11 @@
13471347
CX("%d",v);
13481348
}
13491349
CX("</option>\n");
13501350
}
13511351
CX("</select>\n");
1352
- CX("</span>\n");
1352
+ CX("</div>\n");
13531353
va_end(vargs);
13541354
fossil_free(zLabelID);
13551355
}
13561356
13571357
/*
@@ -1382,11 +1382,11 @@
13821382
13831383
va_start(vargs,zSelectedVal);
13841384
if(!zSelectedVal){
13851385
zSelectedVal = __FILE__/*some string we'll never match*/;
13861386
}
1387
- CX("<span class='input-with-label'");
1387
+ CX("<div class='input-with-label'");
13881388
if(zToolTip && *zToolTip){
13891389
CX(" title='%h'",zToolTip);
13901390
}
13911391
if(zWrapperId && *zWrapperId){
13921392
CX(" id='%s'",zWrapperId);
@@ -1411,11 +1411,11 @@
14111411
CX("%h",zVal);
14121412
}
14131413
CX("</option>\n");
14141414
}
14151415
CX("</select>\n");
1416
- CX("</span>\n");
1416
+ CX("</div>\n");
14171417
va_end(vargs);
14181418
fossil_free(zLabelID);
14191419
}
14201420
14211421
@@ -1560,5 +1560,20 @@
15601560
builtin_request_js(zName);
15611561
fossil_free(zName);
15621562
}
15631563
va_end(vargs);
15641564
}
1565
+
1566
+/*
1567
+** Emits, via builtin_request_js(), all JS fossil.XYZ APIs which are
1568
+** not strictly specific to a single page. The idea is that we can get
1569
+** better bundle caching and reduced HTTP requests by including all
1570
+** JS, rather than creating separate bundles on a per-page basis.
1571
+*/
1572
+void style_emit_all_fossil_js_apis(void){
1573
+ style_emit_fossil_js_apis(0,
1574
+ "dom", "fetch",
1575
+ "storage", "tabs",
1576
+ "confirmer", "popupwidget",
1577
+ "copybutton", "numbered-lines",
1578
+ 0);
1579
+}
15651580
--- src/style.c
+++ src/style.c
@@ -1230,16 +1230,16 @@
1230 ** element. If isChecked is true, the checkbox gets the "checked"
1231 ** attribute set, else it is not.
1232 **
1233 ** Resulting structure:
1234 **
1235 ** <span class='input-with-label' title={{zTip}} id={{zWrapperId}}>
1236 ** <input type='checkbox' name={{zFieldName}} value={{zValue}}
1237 ** id='A RANDOM VALUE'
1238 ** {{isChecked ? " checked : ""}}/>
1239 ** <label for='ID OF THE INPUT FIELD'>{{zLabel}}</label>
1240 ** </span>
1241 **
1242 ** zLabel, and zValue are required. zFieldName, zWrapperId, and zTip
1243 ** are may be NULL or empty.
1244 **
1245 ** Be sure that the input-with-label CSS class is defined sensibly, in
@@ -1249,11 +1249,11 @@
1249 void style_labeled_checkbox(const char * zWrapperId,
1250 const char *zFieldName, const char * zLabel,
1251 const char * zValue, int isChecked,
1252 const char * zTip){
1253 char * zLabelID = style_next_input_id();
1254 CX("<span class='input-with-label'");
1255 if(zTip && *zTip){
1256 CX(" title='%h'", zTip);
1257 }
1258 if(zWrapperId && *zWrapperId){
1259 CX(" id='%s'",zWrapperId);
@@ -1262,11 +1262,11 @@
1262 if(zFieldName && *zFieldName){
1263 CX("name='%s' ",zFieldName);
1264 }
1265 CX("value='%T'%s/>",
1266 zValue ? zValue : "", isChecked ? " checked" : "");
1267 CX("<label for='%s'>%h</label></span>", zLabelID, zLabel);
1268 fossil_free(zLabelID);
1269 }
1270
1271 /*
1272 ** Outputs a SELECT list from a compile-time list of integers.
@@ -1296,14 +1296,14 @@
1296 **
1297 ** zTooltip is an optional value for the SELECT's title attribute.
1298 **
1299 ** The structure of the emitted HTML is:
1300 **
1301 ** <span class='input-with-label' title={{zToolTip}} id={{zWrapperId}}>
1302 ** <label for='SELECT ELEMENT ID'>{{zLabel}}</label>
1303 ** <select id='RANDOM ID' name={{zFieldName}}>...</select>
1304 ** </span>
1305 **
1306 ** Example:
1307 **
1308 ** style_select_list_int("my-grapes", "my_grapes", "Grapes",
1309 ** "Select the number of grapes",
@@ -1318,11 +1318,11 @@
1318 ... ){
1319 char * zLabelID = style_next_input_id();
1320 va_list vargs;
1321
1322 va_start(vargs,selectedVal);
1323 CX("<span class='input-with-label'");
1324 if(zToolTip && *zToolTip){
1325 CX(" title='%h'",zToolTip);
1326 }
1327 if(zWrapperId && *zWrapperId){
1328 CX(" id='%s'",zWrapperId);
@@ -1347,11 +1347,11 @@
1347 CX("%d",v);
1348 }
1349 CX("</option>\n");
1350 }
1351 CX("</select>\n");
1352 CX("</span>\n");
1353 va_end(vargs);
1354 fossil_free(zLabelID);
1355 }
1356
1357 /*
@@ -1382,11 +1382,11 @@
1382
1383 va_start(vargs,zSelectedVal);
1384 if(!zSelectedVal){
1385 zSelectedVal = __FILE__/*some string we'll never match*/;
1386 }
1387 CX("<span class='input-with-label'");
1388 if(zToolTip && *zToolTip){
1389 CX(" title='%h'",zToolTip);
1390 }
1391 if(zWrapperId && *zWrapperId){
1392 CX(" id='%s'",zWrapperId);
@@ -1411,11 +1411,11 @@
1411 CX("%h",zVal);
1412 }
1413 CX("</option>\n");
1414 }
1415 CX("</select>\n");
1416 CX("</span>\n");
1417 va_end(vargs);
1418 fossil_free(zLabelID);
1419 }
1420
1421
@@ -1560,5 +1560,20 @@
1560 builtin_request_js(zName);
1561 fossil_free(zName);
1562 }
1563 va_end(vargs);
1564 }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1565
--- src/style.c
+++ src/style.c
@@ -1230,16 +1230,16 @@
1230 ** element. If isChecked is true, the checkbox gets the "checked"
1231 ** attribute set, else it is not.
1232 **
1233 ** Resulting structure:
1234 **
1235 ** <div class='input-with-label' title={{zTip}} id={{zWrapperId}}>
1236 ** <input type='checkbox' name={{zFieldName}} value={{zValue}}
1237 ** id='A RANDOM VALUE'
1238 ** {{isChecked ? " checked : ""}}/>
1239 ** <label for='ID OF THE INPUT FIELD'>{{zLabel}}</label>
1240 ** </div>
1241 **
1242 ** zLabel, and zValue are required. zFieldName, zWrapperId, and zTip
1243 ** are may be NULL or empty.
1244 **
1245 ** Be sure that the input-with-label CSS class is defined sensibly, in
@@ -1249,11 +1249,11 @@
1249 void style_labeled_checkbox(const char * zWrapperId,
1250 const char *zFieldName, const char * zLabel,
1251 const char * zValue, int isChecked,
1252 const char * zTip){
1253 char * zLabelID = style_next_input_id();
1254 CX("<div class='input-with-label'");
1255 if(zTip && *zTip){
1256 CX(" title='%h'", zTip);
1257 }
1258 if(zWrapperId && *zWrapperId){
1259 CX(" id='%s'",zWrapperId);
@@ -1262,11 +1262,11 @@
1262 if(zFieldName && *zFieldName){
1263 CX("name='%s' ",zFieldName);
1264 }
1265 CX("value='%T'%s/>",
1266 zValue ? zValue : "", isChecked ? " checked" : "");
1267 CX("<label for='%s'>%h</label></div>", zLabelID, zLabel);
1268 fossil_free(zLabelID);
1269 }
1270
1271 /*
1272 ** Outputs a SELECT list from a compile-time list of integers.
@@ -1296,14 +1296,14 @@
1296 **
1297 ** zTooltip is an optional value for the SELECT's title attribute.
1298 **
1299 ** The structure of the emitted HTML is:
1300 **
1301 ** <div class='input-with-label' title={{zToolTip}} id={{zWrapperId}}>
1302 ** <label for='SELECT ELEMENT ID'>{{zLabel}}</label>
1303 ** <select id='RANDOM ID' name={{zFieldName}}>...</select>
1304 ** </div>
1305 **
1306 ** Example:
1307 **
1308 ** style_select_list_int("my-grapes", "my_grapes", "Grapes",
1309 ** "Select the number of grapes",
@@ -1318,11 +1318,11 @@
1318 ... ){
1319 char * zLabelID = style_next_input_id();
1320 va_list vargs;
1321
1322 va_start(vargs,selectedVal);
1323 CX("<div class='input-with-label'");
1324 if(zToolTip && *zToolTip){
1325 CX(" title='%h'",zToolTip);
1326 }
1327 if(zWrapperId && *zWrapperId){
1328 CX(" id='%s'",zWrapperId);
@@ -1347,11 +1347,11 @@
1347 CX("%d",v);
1348 }
1349 CX("</option>\n");
1350 }
1351 CX("</select>\n");
1352 CX("</div>\n");
1353 va_end(vargs);
1354 fossil_free(zLabelID);
1355 }
1356
1357 /*
@@ -1382,11 +1382,11 @@
1382
1383 va_start(vargs,zSelectedVal);
1384 if(!zSelectedVal){
1385 zSelectedVal = __FILE__/*some string we'll never match*/;
1386 }
1387 CX("<div class='input-with-label'");
1388 if(zToolTip && *zToolTip){
1389 CX(" title='%h'",zToolTip);
1390 }
1391 if(zWrapperId && *zWrapperId){
1392 CX(" id='%s'",zWrapperId);
@@ -1411,11 +1411,11 @@
1411 CX("%h",zVal);
1412 }
1413 CX("</option>\n");
1414 }
1415 CX("</select>\n");
1416 CX("</div>\n");
1417 va_end(vargs);
1418 fossil_free(zLabelID);
1419 }
1420
1421
@@ -1560,5 +1560,20 @@
1560 builtin_request_js(zName);
1561 fossil_free(zName);
1562 }
1563 va_end(vargs);
1564 }
1565
1566 /*
1567 ** Emits, via builtin_request_js(), all JS fossil.XYZ APIs which are
1568 ** not strictly specific to a single page. The idea is that we can get
1569 ** better bundle caching and reduced HTTP requests by including all
1570 ** JS, rather than creating separate bundles on a per-page basis.
1571 */
1572 void style_emit_all_fossil_js_apis(void){
1573 style_emit_fossil_js_apis(0,
1574 "dom", "fetch",
1575 "storage", "tabs",
1576 "confirmer", "popupwidget",
1577 "copybutton", "numbered-lines",
1578 0);
1579 }
1580
--- src/style.wikiedit.css
+++ src/style.wikiedit.css
@@ -184,11 +184,18 @@
184184
flex-direction: row;
185185
flex-wrap: wrap;
186186
align-items: baseline;
187187
}
188188
body.wikiedit #wikiedit-stash-selector select {
189
- margin: 0 1em;
189
+ margin: 0 1em 0 0.5em;
190190
height: initial;
191191
font-family: monospace;
192192
flex: 10 1 auto;
193193
}
194194
195
+
196
+body.wikiedit fieldset.page-types-list > div > span {
197
+ display: flex;
198
+ flex-direction: row;
199
+ flex-wrap: nowrap;
200
+ align-items: center;
201
+}
195202
--- src/style.wikiedit.css
+++ src/style.wikiedit.css
@@ -184,11 +184,18 @@
184 flex-direction: row;
185 flex-wrap: wrap;
186 align-items: baseline;
187 }
188 body.wikiedit #wikiedit-stash-selector select {
189 margin: 0 1em;
190 height: initial;
191 font-family: monospace;
192 flex: 10 1 auto;
193 }
194
 
 
 
 
 
 
 
195
--- src/style.wikiedit.css
+++ src/style.wikiedit.css
@@ -184,11 +184,18 @@
184 flex-direction: row;
185 flex-wrap: wrap;
186 align-items: baseline;
187 }
188 body.wikiedit #wikiedit-stash-selector select {
189 margin: 0 1em 0 0.5em;
190 height: initial;
191 font-family: monospace;
192 flex: 10 1 auto;
193 }
194
195
196 body.wikiedit fieldset.page-types-list > div > span {
197 display: flex;
198 flex-direction: row;
199 flex-wrap: nowrap;
200 align-items: center;
201 }
202
+37 -16
--- src/wiki.c
+++ src/wiki.c
@@ -1162,33 +1162,45 @@
11621162
"data-tab-parent='wikiedit-tabs' "
11631163
"data-tab-label='Editor' "
11641164
"class='hidden'"
11651165
">");
11661166
CX("<div class='flex-container flex-row child-gap-small'>");
1167
- CX("<span class='input-with-label'>"
1167
+ CX("<div class='input-with-label'>"
11681168
"<label>Mime type</label>");
11691169
mimetype_option_menu(0);
1170
- CX("</span>");
1170
+ CX("</div>");
11711171
style_select_list_int("select-font-size",
11721172
"editor_font_size", "Editor font size",
11731173
NULL/*tooltip*/,
11741174
100,
11751175
"100%", 100, "125%", 125,
11761176
"150%", 150, "175%", 175,
11771177
"200%", 200, NULL);
1178
- CX("<button class='wikiedit-save'>"
1178
+ CX("<div class='input-with-label'>"
1179
+ "<button class='wikiedit-save'>"
11791180
"Save</button>"
1180
- /*will get moved around dynamically*/);
1181
- CX("<button class='wikiedit-save-close'>"
1182
- "Save &amp; Close</button>"/*will get moved around dynamically*/);
1181
+ "</div>" /*will get moved around dynamically*/);
1182
+ CX("<div class='input-with-label'>"
1183
+ "<button class='wikiedit-save-close'>"
1184
+ "Save &amp; Close</button>"
1185
+ "<div class='help-buttonlet'>"
1186
+ "Saves edits to this page and returns to the wiki page viewer."
1187
+ "</div>"
1188
+ "</div>" /*will get moved around dynamically*/);
11831189
CX("<span class='save-button-slot'></span>");
1184
- CX("<button class='wikiedit-content-reload' "
1185
- "title='Reload the file from the server, discarding "
1190
+
1191
+ CX("<div class='input-with-label'>"
1192
+ "<button class='wikiedit-content-reload' "
1193
+ ">Discard &amp; Reload</button>"
1194
+ "<div class='help-buttonlet'>"
1195
+ "Reload the file from the server, discarding "
11861196
"any local edits. To help avoid accidental loss of "
11871197
"edits, it requires confirmation (a second click) within "
1188
- "a few seconds or it will not reload.'"
1189
- ">Discard &amp; Reload</button>");
1198
+ "a few seconds or it will not reload."
1199
+ "</div>"
1200
+ "</div>");
1201
+
11901202
CX("</div>");
11911203
CX("<div class='flex-container flex-column stretch'>");
11921204
CX("<textarea name='content' id='wikiedit-content-editor' "
11931205
"class='wikiedit' rows='25'>");
11941206
CX("</textarea>");
@@ -1213,16 +1225,19 @@
12131225
/* ^^^ fossil.page[methodName](content, callback) */
12141226
"data-f-preview-to='#wikiedit-tab-preview-wrapper' "
12151227
/* ^^^ dest elem ID */
12161228
">Refresh</button>");
12171229
/* Toggle auto-update of preview when the Preview tab is selected. */
1218
- style_labeled_checkbox("cb-preview-autoupdate",
1219
- NULL,
1220
- "Auto-refresh?",
1221
- "1", 1,
1222
- "If on, the preview will automatically "
1223
- "refresh when this tab is selected.");
1230
+ CX("<div class='input-with-label'>"
1231
+ "<input type='checkbox' value='1' "
1232
+ "id='cb-preview-autorefresh' checked=''>"
1233
+ "<label for='cb-preview-autorefresh'>Auto-refresh?</label>"
1234
+ "<div class='help-buttonlet'>"
1235
+ "If on, the preview will automatically "
1236
+ "refresh when this tab is selected."
1237
+ "</div>"
1238
+ "</div>");
12241239
CX("<span class='save-button-slot'></span>");
12251240
CX("</div>"/*.wikiedit-options*/);
12261241
CX("<div id='wikiedit-tab-preview-wrapper'></div>");
12271242
CX("</div>"/*#wikiedit-tab-preview*/);
12281243
}
@@ -1271,12 +1286,18 @@
12711286
well_formed_wiki_name_rules();
12721287
CX("</div>"/*#wikiedit-tab-save*/);
12731288
}
12741289
12751290
builtin_request_js("sbsdiff.js");
1291
+#if 0
12761292
style_emit_fossil_js_apis(0, "fetch", "dom", "tabs", "confirmer",
12771293
"storage", "page.wikiedit", 0);
1294
+#else
1295
+ style_emit_all_fossil_js_apis();
1296
+ builtin_fulfill_js_requests();
1297
+ builtin_request_js("fossil.page.wikiedit.js");
1298
+#endif
12781299
builtin_fulfill_js_requests();
12791300
/* Dynamically populate the editor... */
12801301
style_emit_script_tag(0,0);
12811302
{
12821303
/* Render the current page list to save us an XHR request
12831304
--- src/wiki.c
+++ src/wiki.c
@@ -1162,33 +1162,45 @@
1162 "data-tab-parent='wikiedit-tabs' "
1163 "data-tab-label='Editor' "
1164 "class='hidden'"
1165 ">");
1166 CX("<div class='flex-container flex-row child-gap-small'>");
1167 CX("<span class='input-with-label'>"
1168 "<label>Mime type</label>");
1169 mimetype_option_menu(0);
1170 CX("</span>");
1171 style_select_list_int("select-font-size",
1172 "editor_font_size", "Editor font size",
1173 NULL/*tooltip*/,
1174 100,
1175 "100%", 100, "125%", 125,
1176 "150%", 150, "175%", 175,
1177 "200%", 200, NULL);
1178 CX("<button class='wikiedit-save'>"
 
1179 "Save</button>"
1180 /*will get moved around dynamically*/);
1181 CX("<button class='wikiedit-save-close'>"
1182 "Save &amp; Close</button>"/*will get moved around dynamically*/);
 
 
 
 
 
1183 CX("<span class='save-button-slot'></span>");
1184 CX("<button class='wikiedit-content-reload' "
1185 "title='Reload the file from the server, discarding "
 
 
 
 
1186 "any local edits. To help avoid accidental loss of "
1187 "edits, it requires confirmation (a second click) within "
1188 "a few seconds or it will not reload.'"
1189 ">Discard &amp; Reload</button>");
 
 
1190 CX("</div>");
1191 CX("<div class='flex-container flex-column stretch'>");
1192 CX("<textarea name='content' id='wikiedit-content-editor' "
1193 "class='wikiedit' rows='25'>");
1194 CX("</textarea>");
@@ -1213,16 +1225,19 @@
1213 /* ^^^ fossil.page[methodName](content, callback) */
1214 "data-f-preview-to='#wikiedit-tab-preview-wrapper' "
1215 /* ^^^ dest elem ID */
1216 ">Refresh</button>");
1217 /* Toggle auto-update of preview when the Preview tab is selected. */
1218 style_labeled_checkbox("cb-preview-autoupdate",
1219 NULL,
1220 "Auto-refresh?",
1221 "1", 1,
1222 "If on, the preview will automatically "
1223 "refresh when this tab is selected.");
 
 
 
1224 CX("<span class='save-button-slot'></span>");
1225 CX("</div>"/*.wikiedit-options*/);
1226 CX("<div id='wikiedit-tab-preview-wrapper'></div>");
1227 CX("</div>"/*#wikiedit-tab-preview*/);
1228 }
@@ -1271,12 +1286,18 @@
1271 well_formed_wiki_name_rules();
1272 CX("</div>"/*#wikiedit-tab-save*/);
1273 }
1274
1275 builtin_request_js("sbsdiff.js");
 
1276 style_emit_fossil_js_apis(0, "fetch", "dom", "tabs", "confirmer",
1277 "storage", "page.wikiedit", 0);
 
 
 
 
 
1278 builtin_fulfill_js_requests();
1279 /* Dynamically populate the editor... */
1280 style_emit_script_tag(0,0);
1281 {
1282 /* Render the current page list to save us an XHR request
1283
--- src/wiki.c
+++ src/wiki.c
@@ -1162,33 +1162,45 @@
1162 "data-tab-parent='wikiedit-tabs' "
1163 "data-tab-label='Editor' "
1164 "class='hidden'"
1165 ">");
1166 CX("<div class='flex-container flex-row child-gap-small'>");
1167 CX("<div class='input-with-label'>"
1168 "<label>Mime type</label>");
1169 mimetype_option_menu(0);
1170 CX("</div>");
1171 style_select_list_int("select-font-size",
1172 "editor_font_size", "Editor font size",
1173 NULL/*tooltip*/,
1174 100,
1175 "100%", 100, "125%", 125,
1176 "150%", 150, "175%", 175,
1177 "200%", 200, NULL);
1178 CX("<div class='input-with-label'>"
1179 "<button class='wikiedit-save'>"
1180 "Save</button>"
1181 "</div>" /*will get moved around dynamically*/);
1182 CX("<div class='input-with-label'>"
1183 "<button class='wikiedit-save-close'>"
1184 "Save &amp; Close</button>"
1185 "<div class='help-buttonlet'>"
1186 "Saves edits to this page and returns to the wiki page viewer."
1187 "</div>"
1188 "</div>" /*will get moved around dynamically*/);
1189 CX("<span class='save-button-slot'></span>");
1190
1191 CX("<div class='input-with-label'>"
1192 "<button class='wikiedit-content-reload' "
1193 ">Discard &amp; Reload</button>"
1194 "<div class='help-buttonlet'>"
1195 "Reload the file from the server, discarding "
1196 "any local edits. To help avoid accidental loss of "
1197 "edits, it requires confirmation (a second click) within "
1198 "a few seconds or it will not reload."
1199 "</div>"
1200 "</div>");
1201
1202 CX("</div>");
1203 CX("<div class='flex-container flex-column stretch'>");
1204 CX("<textarea name='content' id='wikiedit-content-editor' "
1205 "class='wikiedit' rows='25'>");
1206 CX("</textarea>");
@@ -1213,16 +1225,19 @@
1225 /* ^^^ fossil.page[methodName](content, callback) */
1226 "data-f-preview-to='#wikiedit-tab-preview-wrapper' "
1227 /* ^^^ dest elem ID */
1228 ">Refresh</button>");
1229 /* Toggle auto-update of preview when the Preview tab is selected. */
1230 CX("<div class='input-with-label'>"
1231 "<input type='checkbox' value='1' "
1232 "id='cb-preview-autorefresh' checked=''>"
1233 "<label for='cb-preview-autorefresh'>Auto-refresh?</label>"
1234 "<div class='help-buttonlet'>"
1235 "If on, the preview will automatically "
1236 "refresh when this tab is selected."
1237 "</div>"
1238 "</div>");
1239 CX("<span class='save-button-slot'></span>");
1240 CX("</div>"/*.wikiedit-options*/);
1241 CX("<div id='wikiedit-tab-preview-wrapper'></div>");
1242 CX("</div>"/*#wikiedit-tab-preview*/);
1243 }
@@ -1271,12 +1286,18 @@
1286 well_formed_wiki_name_rules();
1287 CX("</div>"/*#wikiedit-tab-save*/);
1288 }
1289
1290 builtin_request_js("sbsdiff.js");
1291 #if 0
1292 style_emit_fossil_js_apis(0, "fetch", "dom", "tabs", "confirmer",
1293 "storage", "page.wikiedit", 0);
1294 #else
1295 style_emit_all_fossil_js_apis();
1296 builtin_fulfill_js_requests();
1297 builtin_request_js("fossil.page.wikiedit.js");
1298 #endif
1299 builtin_fulfill_js_requests();
1300 /* Dynamically populate the editor... */
1301 style_emit_script_tag(0,0);
1302 {
1303 /* Render the current page list to save us an XHR request
1304

Keyboard Shortcuts

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