Fossil SCM

Several small style tweaks. Changed style_labeled_checkbox() parameter order for better readability. TabManager class now supports events alerting before/after a tab is switched to. Added auto-refresh of preview when the preview tab is activated, with a checkbox to disable it for slow connections and/or large documents (the refresh button still works as before).

stephan 2020-05-10 08:47 fileedit-ajaxify
Commit ee175636aa9a8862b2ae2e7d42c3365efe798a5f4e9bfb8bf4e194e0ce17fb41
--- src/default_css.txt
+++ src/default_css.txt
@@ -996,19 +996,27 @@
996996
#fileedit-comment {
997997
width: 100%;
998998
font-family: monospace;
999999
}
10001000
.tab-container > .tabs > .tab-panel > .fileedit-options {
1001
- margin-top: 0.25em 0;
1001
+ margin-top: 0;
10021002
border: none;
10031003
border-radius: 0;
10041004
border-bottom-width: 1px;
10051005
border-bottom-style: dotted;
10061006
}
10071007
.tab-container > .tabs > .tab-panel > .fileedit-options > button {
10081008
vertical-align: middle;
10091009
margin: 0.5em;
1010
+}
1011
+.tab-container > .tabs > .tab-panel > .fileedit-options > input {
1012
+ vertical-align: middle;
1013
+ margin: 0.5em;
1014
+}
1015
+.tab-container > .tabs > .tab-panel > .fileedit-options > .input-with-label {
1016
+ vertical-align: middle;
1017
+ margin: 0.5em;
10101018
}
10111019
////////////////////////////////////////////////////////////////////
10121020
// Styles developed for /fileedit but which have wider
10131021
// applicability:
10141022
.flex-container {
@@ -1020,10 +1028,13 @@
10201028
justify-content: center;
10211029
align-items: center;
10221030
}
10231031
.fileedit-options.flex-container.row {
10241032
align-items: first baseline;
1033
+}
1034
+.fileedit-options > div > * {
1035
+ margin: 0.25em;
10251036
}
10261037
.flex-container.row.stretch {
10271038
flex-direction: row;
10281039
flex-wrap: wrap;
10291040
align-items: stretch;
@@ -1036,10 +1047,13 @@
10361047
align-items: center;
10371048
}
10381049
.flex-container.column.stretch {
10391050
align-items: stretch;
10401051
margin: 0;
1052
+}
1053
+.flex-container.child-gap-small > * {
1054
+ margin: 0.25em;
10411055
}
10421056
.font-size-100 {
10431057
font-size: 100%;
10441058
}
10451059
.font-size-125 {
@@ -1061,11 +1075,11 @@
10611075
border: 1px inset #808080;
10621076
border-radius: 0.5em;
10631077
padding: 0.25em 0.4em;
10641078
margin: 0 0.5em;
10651079
display: inline-block;
1066
- cursor: pointer;
1080
+ cursor: default;
10671081
}
10681082
.input-with-label > * {
10691083
vertical-align: middle;
10701084
}
10711085
.input-with-label > input {
10721086
--- src/default_css.txt
+++ src/default_css.txt
@@ -996,19 +996,27 @@
996 #fileedit-comment {
997 width: 100%;
998 font-family: monospace;
999 }
1000 .tab-container > .tabs > .tab-panel > .fileedit-options {
1001 margin-top: 0.25em 0;
1002 border: none;
1003 border-radius: 0;
1004 border-bottom-width: 1px;
1005 border-bottom-style: dotted;
1006 }
1007 .tab-container > .tabs > .tab-panel > .fileedit-options > button {
1008 vertical-align: middle;
1009 margin: 0.5em;
 
 
 
 
 
 
 
 
1010 }
1011 ////////////////////////////////////////////////////////////////////
1012 // Styles developed for /fileedit but which have wider
1013 // applicability:
1014 .flex-container {
@@ -1020,10 +1028,13 @@
1020 justify-content: center;
1021 align-items: center;
1022 }
1023 .fileedit-options.flex-container.row {
1024 align-items: first baseline;
 
 
 
1025 }
1026 .flex-container.row.stretch {
1027 flex-direction: row;
1028 flex-wrap: wrap;
1029 align-items: stretch;
@@ -1036,10 +1047,13 @@
1036 align-items: center;
1037 }
1038 .flex-container.column.stretch {
1039 align-items: stretch;
1040 margin: 0;
 
 
 
1041 }
1042 .font-size-100 {
1043 font-size: 100%;
1044 }
1045 .font-size-125 {
@@ -1061,11 +1075,11 @@
1061 border: 1px inset #808080;
1062 border-radius: 0.5em;
1063 padding: 0.25em 0.4em;
1064 margin: 0 0.5em;
1065 display: inline-block;
1066 cursor: pointer;
1067 }
1068 .input-with-label > * {
1069 vertical-align: middle;
1070 }
1071 .input-with-label > input {
1072
--- src/default_css.txt
+++ src/default_css.txt
@@ -996,19 +996,27 @@
996 #fileedit-comment {
997 width: 100%;
998 font-family: monospace;
999 }
1000 .tab-container > .tabs > .tab-panel > .fileedit-options {
1001 margin-top: 0;
1002 border: none;
1003 border-radius: 0;
1004 border-bottom-width: 1px;
1005 border-bottom-style: dotted;
1006 }
1007 .tab-container > .tabs > .tab-panel > .fileedit-options > button {
1008 vertical-align: middle;
1009 margin: 0.5em;
1010 }
1011 .tab-container > .tabs > .tab-panel > .fileedit-options > input {
1012 vertical-align: middle;
1013 margin: 0.5em;
1014 }
1015 .tab-container > .tabs > .tab-panel > .fileedit-options > .input-with-label {
1016 vertical-align: middle;
1017 margin: 0.5em;
1018 }
1019 ////////////////////////////////////////////////////////////////////
1020 // Styles developed for /fileedit but which have wider
1021 // applicability:
1022 .flex-container {
@@ -1020,10 +1028,13 @@
1028 justify-content: center;
1029 align-items: center;
1030 }
1031 .fileedit-options.flex-container.row {
1032 align-items: first baseline;
1033 }
1034 .fileedit-options > div > * {
1035 margin: 0.25em;
1036 }
1037 .flex-container.row.stretch {
1038 flex-direction: row;
1039 flex-wrap: wrap;
1040 align-items: stretch;
@@ -1036,10 +1047,13 @@
1047 align-items: center;
1048 }
1049 .flex-container.column.stretch {
1050 align-items: stretch;
1051 margin: 0;
1052 }
1053 .flex-container.child-gap-small > * {
1054 margin: 0.25em;
1055 }
1056 .font-size-100 {
1057 font-size: 100%;
1058 }
1059 .font-size-125 {
@@ -1061,11 +1075,11 @@
1075 border: 1px inset #808080;
1076 border-radius: 0.5em;
1077 padding: 0.25em 0.4em;
1078 margin: 0 0.5em;
1079 display: inline-block;
1080 cursor: default;
1081 }
1082 .input-with-label > * {
1083 vertical-align: middle;
1084 }
1085 .input-with-label > input {
1086
+28 -19
--- src/fileedit.c
+++ src/fileedit.c
@@ -1606,11 +1606,12 @@
16061606
{
16071607
CX("<div id='fileedit-tab-content' "
16081608
"data-tab-parent='fileedit-tabs' "
16091609
"data-tab-label='File Content'"
16101610
">");
1611
- CX("<div class='fileedit-options flex-container row'>");
1611
+ CX("<div class='fileedit-options "
1612
+ "flex-container row child-gap-small'>");
16121613
if(1){
16131614
/* Discard/reload button. Leave this out until we have a
16141615
** nice way of offering confirmation, e.g. like the old
16151616
** jQuery.confirmer plugin which required a 2nd click of the
16161617
** button within X seconds to confirm. Right now it's simply
@@ -1654,10 +1655,20 @@
16541655
"data-f-preview-via='_postPreview' "
16551656
/* ^^^ fossil.page[methodName](content, callback) */
16561657
"data-f-preview-to='fileedit-tab-preview-wrapper' "
16571658
/* ^^^ dest elem ID */
16581659
">Refresh</button>");
1660
+ /* Toggle auto-update of preview when the Preview tab is selected. */
1661
+ style_labeled_checkbox("cb-preview-autoupdate",
1662
+ NULL,
1663
+ "Auto-refresh?",
1664
+ "1", 1,
1665
+ "If on, the preview will automatically "
1666
+ "refresh when this tab is selected. Not "
1667
+ "recommended for large files or slow "
1668
+ "connections.");
1669
+
16591670
/* Default preview rendering mode selection... */
16601671
previewRenderMode = fileedit_render_mode_for_mimetype(zFileMime);
16611672
style_select_list_int("select-preview-mode",
16621673
"preview_render_mode",
16631674
"Preview Mode",
@@ -1700,14 +1711,13 @@
17001711
"", 100, NULL);
17011712
/* Selection of line numbers for text preview */
17021713
style_labeled_checkbox("cb-line-numbers",
17031714
"preview_ln",
17041715
"Add line numbers to plain-text previews?",
1705
- "1",
1716
+ "1", P("preview_ln")!=0,
17061717
"If on, plain-text files (only) will get "
1707
- "line numbers added to the preview.",
1708
- P("preview_ln")!=0);
1718
+ "line numbers added to the preview.");
17091719
CX("</div>"/*.fileedit-options*/);
17101720
CX("<div id='fileedit-tab-preview-wrapper'></div>");
17111721
CX("</div>"/*#fileedit-tab-preview*/);
17121722
}
17131723
@@ -1738,43 +1748,42 @@
17381748
17391749
{
17401750
/******* Commit flags/options *******/
17411751
CX("<div class='fileedit-options flex-container row'>");
17421752
style_labeled_checkbox("cb-dry-run",
1743
- "dry_run", "Dry-run?", "1",
1753
+ "dry_run", "Dry-run?", "1", 1,
17441754
"In dry-run mode, the Save button performs "
17451755
"all work needed for saving but then rolls "
17461756
"back the transaction, and thus does not "
1747
- "really save.",
1748
- 1);
1757
+ "really save.");
17491758
style_labeled_checkbox("cb-allow-fork",
17501759
"allow_fork", "Allow fork?", "1",
1751
- "Allow saving to create a fork?",
1752
- cimi.flags & CIMINI_ALLOW_FORK);
1760
+ cimi.flags & CIMINI_ALLOW_FORK,
1761
+ "Allow saving to create a fork?");
17531762
style_labeled_checkbox("cb-allow-older",
17541763
"allow_older", "Allow older?", "1",
1764
+ cimi.flags & CIMINI_ALLOW_OLDER,
17551765
"Allow saving against a parent version "
1756
- "which has a newer timestamp?",
1757
- cimi.flags & CIMINI_ALLOW_OLDER);
1766
+ "which has a newer timestamp?");
17581767
style_labeled_checkbox("cb-exec-bit",
17591768
"exec_bit", "Executable?", "1",
1760
- "Set the executable bit?",
1761
- PERM_EXE==cimi.filePerm);
1769
+ PERM_EXE==cimi.filePerm,
1770
+ "Set the executable bit?");
17621771
style_labeled_checkbox("cb-allow-merge-conflict",
17631772
"allow_merge_conflict",
17641773
"Allow merge conflict markers?", "1",
1774
+ cimi.flags & CIMINI_ALLOW_MERGE_MARKER,
17651775
"Allow saving even if the content contains "
17661776
"what appear to be fossil merge conflict "
1767
- "markers?",
1768
- cimi.flags & CIMINI_ALLOW_MERGE_MARKER);
1777
+ "markers?");
17691778
style_labeled_checkbox("cb-prefer-delta",
17701779
"prefer_delta",
17711780
"Prefer delta manifest?", "1",
1781
+ cimi.flags & CIMINI_PREFER_DELTA,
17721782
"Will create a delta manifest, instead of "
17731783
"baseline, if conditions are favorable to "
1774
- "do so. This option is only a suggestion.",
1775
- cimi.flags & CIMINI_PREFER_DELTA);
1784
+ "do so. This option is only a suggestion.");
17761785
style_select_list_int("select-eol-style",
17771786
"eol", "EOL Style",
17781787
"EOL conversion policy, noting that "
17791788
"form-processing may implicitly change the "
17801789
"line endings of the input.",
@@ -1797,16 +1806,16 @@
17971806
CX("<input type='text' name='comment' "
17981807
"id='fileedit-comment'></input>");
17991808
CX("<textarea name='commentBig' class='hidden' "
18001809
"rows='5' id='fileedit-comment-big'></textarea>\n");
18011810
{ /* comment options... */
1802
- CX("<div class='fileedit-options flex-container column'>");
1811
+ CX("<div class='flex-container column child-gap-small'>");
18031812
CX("<button id='comment-toggle' "
18041813
"title='Toggle between single- and multi-line comment mode, "
18051814
"noting that switching from multi- to single-line will cause "
18061815
"newlines to get stripped.'"
1807
- ">toggle single-/multi-line</button> ");
1816
+ ">Toggle single-/multi-line</button> ");
18081817
if(0){
18091818
/* Manifests support an N-card (comment mime type) but it has
18101819
** yet to be honored where comments are rendered, so we don't
18111820
** currently offer it as an option here:
18121821
** https://fossil-scm.org/forum/forumpost/662da045a1
18131822
--- src/fileedit.c
+++ src/fileedit.c
@@ -1606,11 +1606,12 @@
1606 {
1607 CX("<div id='fileedit-tab-content' "
1608 "data-tab-parent='fileedit-tabs' "
1609 "data-tab-label='File Content'"
1610 ">");
1611 CX("<div class='fileedit-options flex-container row'>");
 
1612 if(1){
1613 /* Discard/reload button. Leave this out until we have a
1614 ** nice way of offering confirmation, e.g. like the old
1615 ** jQuery.confirmer plugin which required a 2nd click of the
1616 ** button within X seconds to confirm. Right now it's simply
@@ -1654,10 +1655,20 @@
1654 "data-f-preview-via='_postPreview' "
1655 /* ^^^ fossil.page[methodName](content, callback) */
1656 "data-f-preview-to='fileedit-tab-preview-wrapper' "
1657 /* ^^^ dest elem ID */
1658 ">Refresh</button>");
 
 
 
 
 
 
 
 
 
 
1659 /* Default preview rendering mode selection... */
1660 previewRenderMode = fileedit_render_mode_for_mimetype(zFileMime);
1661 style_select_list_int("select-preview-mode",
1662 "preview_render_mode",
1663 "Preview Mode",
@@ -1700,14 +1711,13 @@
1700 "", 100, NULL);
1701 /* Selection of line numbers for text preview */
1702 style_labeled_checkbox("cb-line-numbers",
1703 "preview_ln",
1704 "Add line numbers to plain-text previews?",
1705 "1",
1706 "If on, plain-text files (only) will get "
1707 "line numbers added to the preview.",
1708 P("preview_ln")!=0);
1709 CX("</div>"/*.fileedit-options*/);
1710 CX("<div id='fileedit-tab-preview-wrapper'></div>");
1711 CX("</div>"/*#fileedit-tab-preview*/);
1712 }
1713
@@ -1738,43 +1748,42 @@
1738
1739 {
1740 /******* Commit flags/options *******/
1741 CX("<div class='fileedit-options flex-container row'>");
1742 style_labeled_checkbox("cb-dry-run",
1743 "dry_run", "Dry-run?", "1",
1744 "In dry-run mode, the Save button performs "
1745 "all work needed for saving but then rolls "
1746 "back the transaction, and thus does not "
1747 "really save.",
1748 1);
1749 style_labeled_checkbox("cb-allow-fork",
1750 "allow_fork", "Allow fork?", "1",
1751 "Allow saving to create a fork?",
1752 cimi.flags & CIMINI_ALLOW_FORK);
1753 style_labeled_checkbox("cb-allow-older",
1754 "allow_older", "Allow older?", "1",
 
1755 "Allow saving against a parent version "
1756 "which has a newer timestamp?",
1757 cimi.flags & CIMINI_ALLOW_OLDER);
1758 style_labeled_checkbox("cb-exec-bit",
1759 "exec_bit", "Executable?", "1",
1760 "Set the executable bit?",
1761 PERM_EXE==cimi.filePerm);
1762 style_labeled_checkbox("cb-allow-merge-conflict",
1763 "allow_merge_conflict",
1764 "Allow merge conflict markers?", "1",
 
1765 "Allow saving even if the content contains "
1766 "what appear to be fossil merge conflict "
1767 "markers?",
1768 cimi.flags & CIMINI_ALLOW_MERGE_MARKER);
1769 style_labeled_checkbox("cb-prefer-delta",
1770 "prefer_delta",
1771 "Prefer delta manifest?", "1",
 
1772 "Will create a delta manifest, instead of "
1773 "baseline, if conditions are favorable to "
1774 "do so. This option is only a suggestion.",
1775 cimi.flags & CIMINI_PREFER_DELTA);
1776 style_select_list_int("select-eol-style",
1777 "eol", "EOL Style",
1778 "EOL conversion policy, noting that "
1779 "form-processing may implicitly change the "
1780 "line endings of the input.",
@@ -1797,16 +1806,16 @@
1797 CX("<input type='text' name='comment' "
1798 "id='fileedit-comment'></input>");
1799 CX("<textarea name='commentBig' class='hidden' "
1800 "rows='5' id='fileedit-comment-big'></textarea>\n");
1801 { /* comment options... */
1802 CX("<div class='fileedit-options flex-container column'>");
1803 CX("<button id='comment-toggle' "
1804 "title='Toggle between single- and multi-line comment mode, "
1805 "noting that switching from multi- to single-line will cause "
1806 "newlines to get stripped.'"
1807 ">toggle single-/multi-line</button> ");
1808 if(0){
1809 /* Manifests support an N-card (comment mime type) but it has
1810 ** yet to be honored where comments are rendered, so we don't
1811 ** currently offer it as an option here:
1812 ** https://fossil-scm.org/forum/forumpost/662da045a1
1813
--- src/fileedit.c
+++ src/fileedit.c
@@ -1606,11 +1606,12 @@
1606 {
1607 CX("<div id='fileedit-tab-content' "
1608 "data-tab-parent='fileedit-tabs' "
1609 "data-tab-label='File Content'"
1610 ">");
1611 CX("<div class='fileedit-options "
1612 "flex-container row child-gap-small'>");
1613 if(1){
1614 /* Discard/reload button. Leave this out until we have a
1615 ** nice way of offering confirmation, e.g. like the old
1616 ** jQuery.confirmer plugin which required a 2nd click of the
1617 ** button within X seconds to confirm. Right now it's simply
@@ -1654,10 +1655,20 @@
1655 "data-f-preview-via='_postPreview' "
1656 /* ^^^ fossil.page[methodName](content, callback) */
1657 "data-f-preview-to='fileedit-tab-preview-wrapper' "
1658 /* ^^^ dest elem ID */
1659 ">Refresh</button>");
1660 /* Toggle auto-update of preview when the Preview tab is selected. */
1661 style_labeled_checkbox("cb-preview-autoupdate",
1662 NULL,
1663 "Auto-refresh?",
1664 "1", 1,
1665 "If on, the preview will automatically "
1666 "refresh when this tab is selected. Not "
1667 "recommended for large files or slow "
1668 "connections.");
1669
1670 /* Default preview rendering mode selection... */
1671 previewRenderMode = fileedit_render_mode_for_mimetype(zFileMime);
1672 style_select_list_int("select-preview-mode",
1673 "preview_render_mode",
1674 "Preview Mode",
@@ -1700,14 +1711,13 @@
1711 "", 100, NULL);
1712 /* Selection of line numbers for text preview */
1713 style_labeled_checkbox("cb-line-numbers",
1714 "preview_ln",
1715 "Add line numbers to plain-text previews?",
1716 "1", P("preview_ln")!=0,
1717 "If on, plain-text files (only) will get "
1718 "line numbers added to the preview.");
 
1719 CX("</div>"/*.fileedit-options*/);
1720 CX("<div id='fileedit-tab-preview-wrapper'></div>");
1721 CX("</div>"/*#fileedit-tab-preview*/);
1722 }
1723
@@ -1738,43 +1748,42 @@
1748
1749 {
1750 /******* Commit flags/options *******/
1751 CX("<div class='fileedit-options flex-container row'>");
1752 style_labeled_checkbox("cb-dry-run",
1753 "dry_run", "Dry-run?", "1", 1,
1754 "In dry-run mode, the Save button performs "
1755 "all work needed for saving but then rolls "
1756 "back the transaction, and thus does not "
1757 "really save.");
 
1758 style_labeled_checkbox("cb-allow-fork",
1759 "allow_fork", "Allow fork?", "1",
1760 cimi.flags & CIMINI_ALLOW_FORK,
1761 "Allow saving to create a fork?");
1762 style_labeled_checkbox("cb-allow-older",
1763 "allow_older", "Allow older?", "1",
1764 cimi.flags & CIMINI_ALLOW_OLDER,
1765 "Allow saving against a parent version "
1766 "which has a newer timestamp?");
 
1767 style_labeled_checkbox("cb-exec-bit",
1768 "exec_bit", "Executable?", "1",
1769 PERM_EXE==cimi.filePerm,
1770 "Set the executable bit?");
1771 style_labeled_checkbox("cb-allow-merge-conflict",
1772 "allow_merge_conflict",
1773 "Allow merge conflict markers?", "1",
1774 cimi.flags & CIMINI_ALLOW_MERGE_MARKER,
1775 "Allow saving even if the content contains "
1776 "what appear to be fossil merge conflict "
1777 "markers?");
 
1778 style_labeled_checkbox("cb-prefer-delta",
1779 "prefer_delta",
1780 "Prefer delta manifest?", "1",
1781 cimi.flags & CIMINI_PREFER_DELTA,
1782 "Will create a delta manifest, instead of "
1783 "baseline, if conditions are favorable to "
1784 "do so. This option is only a suggestion.");
 
1785 style_select_list_int("select-eol-style",
1786 "eol", "EOL Style",
1787 "EOL conversion policy, noting that "
1788 "form-processing may implicitly change the "
1789 "line endings of the input.",
@@ -1797,16 +1806,16 @@
1806 CX("<input type='text' name='comment' "
1807 "id='fileedit-comment'></input>");
1808 CX("<textarea name='commentBig' class='hidden' "
1809 "rows='5' id='fileedit-comment-big'></textarea>\n");
1810 { /* comment options... */
1811 CX("<div class='flex-container column child-gap-small'>");
1812 CX("<button id='comment-toggle' "
1813 "title='Toggle between single- and multi-line comment mode, "
1814 "noting that switching from multi- to single-line will cause "
1815 "newlines to get stripped.'"
1816 ">Toggle single-/multi-line</button> ");
1817 if(0){
1818 /* Manifests support an N-card (comment mime type) but it has
1819 ** yet to be honored where comments are rendered, so we don't
1820 ** currently offer it as an option here:
1821 ** https://fossil-scm.org/forum/forumpost/662da045a1
1822
--- src/fossil.page.fileedit.js
+++ src/fossil.page.fileedit.js
@@ -19,10 +19,11 @@
1919
+"button.fileedit-content-reload"),
2020
selectPreviewModeWrap: E('#select-preview-mode'),
2121
selectHtmlEmsWrap: E('#select-preview-html-ems'),
2222
selectEolWrap: E('#select-preview-html-ems'),
2323
cbLineNumbersWrap: E('#cb-line-numbers'),
24
+ cbAutoPreview: E('#cb-preview-autoupdate > input[type=checkbox]'),
2425
tabs:{
2526
content: E('#fileedit-tab-content'),
2627
preview: E('#fileedit-tab-preview'),
2728
diff: E('#fileedit-tab-diff'),
2829
commit: E('#fileedit-tab-commit')
@@ -47,20 +48,23 @@
4748
tab panels. Seems to be the best fit in terms of
4849
functionality and visibility. */
4950
E('#fossil-status-bar'), P.tabs.e.tabs
5051
);
5152
52
- const stopEvent = function(e){
53
- //e.preventDefault();
54
- //e.stopPropagation();
55
- return P;
56
- };
57
-
58
- //P.tabs.getButtonForTab(P.e.tabs.preview)
53
+ P.tabs.addEventListener(
54
+ /* Set up auto-refresh of the preview tab... */
55
+ 'before-switch-to', function(ev){
56
+ if(ev.detail===P.e.tabs.preview
57
+ && P.e.cbAutoPreview.checked){
58
+ P.preview();
59
+ }
60
+ }
61
+ );
62
+
5963
F.connectPagePreviewers(
6064
P.e.tabs.preview.querySelector(
61
- 'button'
65
+ '#btn-preview-refresh'
6266
)
6367
);
6468
6569
const diffButtons = E('#fileedit-tab-diff-buttons');
6670
diffButtons.querySelector('button.sbs').addEventListener(
@@ -215,11 +219,10 @@
215219
urlParams: {filename:file,checkin:rev},
216220
onload:(r)=>{
217221
F.message('Loaded content.');
218222
self.e.taEditor.value = r;
219223
self.updateVersion(file,rev);
220
- self.preview();
221224
self.tabs.switchToTab(self.e.tabs.content);
222225
}
223226
});
224227
return this;
225228
};
@@ -229,48 +232,46 @@
229232
this page's input fields, and updates the UI with with the
230233
preview.
231234
232235
Returns this object, noting that the operation is async.
233236
*/
234
- P.preview = function(switchToTab){
237
+ P.preview = function f(switchToTab){
235238
if(!this.finfo){
236239
F.error("No content is loaded.");
237240
return this;
238241
}
239
- const target = this.e.tabs.preview.querySelector(
240
- '#fileedit-tab-preview-wrapper'
241
- );
242
+ if(!f.target){
243
+ f.target = this.e.tabs.preview.querySelector(
244
+ '#fileedit-tab-preview-wrapper'
245
+ );
246
+ }
242247
const self = this;
243248
const updateView = function(c){
244
- D.clearElement(target);
245
- if('string'===typeof c) target.innerHTML = c;
249
+ D.clearElement(f.target);
250
+ if('string'===typeof c) f.target.innerHTML = c;
246251
if(switchToTab) self.tabs.switchToTab(self.e.tabs.preview);
247252
};
248
- const content = this.e.taEditor.value;
249
- if(!content){
250
- updateView('');
251
- return this;
252
- }
253
- this._postPreview(content, updateView);
254
- return this;
253
+ return this._postPreview(this.e.taEditor.value, updateView);
255254
};
256255
257256
/**
258257
Callback for use with F.connectPagePreviewers()
259258
*/
260259
P._postPreview = function(content,callback){
261260
if(!content){
262261
callback(content);
263
- return;
262
+ return this;
264263
}
265264
const fd = new FormData();
266265
fd.append('render_mode',E('select[name=preview_render_mode]').value);
267266
fd.append('filename',this.finfo.filename);
268267
fd.append('ln',E('[name=preview_ln]').checked ? 1 : 0);
269268
fd.append('iframe_height', E('[name=preview_html_ems]').value);
270269
fd.append('content',content || '');
271
- fossil.fetch('fileedit_preview',{
270
+ F.message(
271
+ "Fetching preview..."
272
+ ).fetch('fileedit_preview',{
272273
payload: fd,
273274
onload: (r)=>{
274275
callback(r);
275276
F.message('Updated preview.');
276277
},
@@ -277,29 +278,32 @@
277278
onerror: (e)=>{
278279
fossil.fetch.onerror(e);
279280
callback("Error fetching preview: "+e);
280281
}
281282
});
283
+ return this;
282284
};
283285
284286
285287
/**
286288
Fetches the content diff based on the contents and settings of this
287289
page's input fields, and updates the UI with the diff view.
288290
289291
Returns this object, noting that the operation is async.
290292
*/
291
- P.diff = function(sbs){
293
+ P.diff = function f(sbs){
292294
if(!this.finfo){
293295
F.error("No content is loaded.");
294296
return this;
295297
}
296298
const content = this.e.taEditor.value,
297
- target = this.e.tabs.diff.querySelector(
298
- '#fileedit-tab-diff-wrapper'
299
- ),
300299
self = this;
300
+ if(!f.target){
301
+ f.target = this.e.tabs.diff.querySelector(
302
+ '#fileedit-tab-diff-wrapper'
303
+ );
304
+ }
301305
const fd = new FormData();
302306
fd.append('filename',this.finfo.filename);
303307
fd.append('checkin', this.finfo.checkin);
304308
fd.append('sbs', sbs ? 1 : 0);
305309
fd.append('content',content);
@@ -306,11 +310,11 @@
306310
F.message(
307311
"Fetching diff..."
308312
).fetch('fileedit_diff',{
309313
payload: fd,
310314
onload: function(c){
311
- target.innerHTML = [
315
+ f.target.innerHTML = [
312316
"<div>Diff <code>[",
313317
self.finfo.checkin,
314318
"]</code> &rarr; Local Edits</div>",
315319
c||'No changes.'
316320
].join('');
317321
--- src/fossil.page.fileedit.js
+++ src/fossil.page.fileedit.js
@@ -19,10 +19,11 @@
19 +"button.fileedit-content-reload"),
20 selectPreviewModeWrap: E('#select-preview-mode'),
21 selectHtmlEmsWrap: E('#select-preview-html-ems'),
22 selectEolWrap: E('#select-preview-html-ems'),
23 cbLineNumbersWrap: E('#cb-line-numbers'),
 
24 tabs:{
25 content: E('#fileedit-tab-content'),
26 preview: E('#fileedit-tab-preview'),
27 diff: E('#fileedit-tab-diff'),
28 commit: E('#fileedit-tab-commit')
@@ -47,20 +48,23 @@
47 tab panels. Seems to be the best fit in terms of
48 functionality and visibility. */
49 E('#fossil-status-bar'), P.tabs.e.tabs
50 );
51
52 const stopEvent = function(e){
53 //e.preventDefault();
54 //e.stopPropagation();
55 return P;
56 };
57
58 //P.tabs.getButtonForTab(P.e.tabs.preview)
 
 
 
59 F.connectPagePreviewers(
60 P.e.tabs.preview.querySelector(
61 'button'
62 )
63 );
64
65 const diffButtons = E('#fileedit-tab-diff-buttons');
66 diffButtons.querySelector('button.sbs').addEventListener(
@@ -215,11 +219,10 @@
215 urlParams: {filename:file,checkin:rev},
216 onload:(r)=>{
217 F.message('Loaded content.');
218 self.e.taEditor.value = r;
219 self.updateVersion(file,rev);
220 self.preview();
221 self.tabs.switchToTab(self.e.tabs.content);
222 }
223 });
224 return this;
225 };
@@ -229,48 +232,46 @@
229 this page's input fields, and updates the UI with with the
230 preview.
231
232 Returns this object, noting that the operation is async.
233 */
234 P.preview = function(switchToTab){
235 if(!this.finfo){
236 F.error("No content is loaded.");
237 return this;
238 }
239 const target = this.e.tabs.preview.querySelector(
240 '#fileedit-tab-preview-wrapper'
241 );
 
 
242 const self = this;
243 const updateView = function(c){
244 D.clearElement(target);
245 if('string'===typeof c) target.innerHTML = c;
246 if(switchToTab) self.tabs.switchToTab(self.e.tabs.preview);
247 };
248 const content = this.e.taEditor.value;
249 if(!content){
250 updateView('');
251 return this;
252 }
253 this._postPreview(content, updateView);
254 return this;
255 };
256
257 /**
258 Callback for use with F.connectPagePreviewers()
259 */
260 P._postPreview = function(content,callback){
261 if(!content){
262 callback(content);
263 return;
264 }
265 const fd = new FormData();
266 fd.append('render_mode',E('select[name=preview_render_mode]').value);
267 fd.append('filename',this.finfo.filename);
268 fd.append('ln',E('[name=preview_ln]').checked ? 1 : 0);
269 fd.append('iframe_height', E('[name=preview_html_ems]').value);
270 fd.append('content',content || '');
271 fossil.fetch('fileedit_preview',{
 
 
272 payload: fd,
273 onload: (r)=>{
274 callback(r);
275 F.message('Updated preview.');
276 },
@@ -277,29 +278,32 @@
277 onerror: (e)=>{
278 fossil.fetch.onerror(e);
279 callback("Error fetching preview: "+e);
280 }
281 });
 
282 };
283
284
285 /**
286 Fetches the content diff based on the contents and settings of this
287 page's input fields, and updates the UI with the diff view.
288
289 Returns this object, noting that the operation is async.
290 */
291 P.diff = function(sbs){
292 if(!this.finfo){
293 F.error("No content is loaded.");
294 return this;
295 }
296 const content = this.e.taEditor.value,
297 target = this.e.tabs.diff.querySelector(
298 '#fileedit-tab-diff-wrapper'
299 ),
300 self = this;
 
 
 
 
 
301 const fd = new FormData();
302 fd.append('filename',this.finfo.filename);
303 fd.append('checkin', this.finfo.checkin);
304 fd.append('sbs', sbs ? 1 : 0);
305 fd.append('content',content);
@@ -306,11 +310,11 @@
306 F.message(
307 "Fetching diff..."
308 ).fetch('fileedit_diff',{
309 payload: fd,
310 onload: function(c){
311 target.innerHTML = [
312 "<div>Diff <code>[",
313 self.finfo.checkin,
314 "]</code> &rarr; Local Edits</div>",
315 c||'No changes.'
316 ].join('');
317
--- src/fossil.page.fileedit.js
+++ src/fossil.page.fileedit.js
@@ -19,10 +19,11 @@
19 +"button.fileedit-content-reload"),
20 selectPreviewModeWrap: E('#select-preview-mode'),
21 selectHtmlEmsWrap: E('#select-preview-html-ems'),
22 selectEolWrap: E('#select-preview-html-ems'),
23 cbLineNumbersWrap: E('#cb-line-numbers'),
24 cbAutoPreview: E('#cb-preview-autoupdate > input[type=checkbox]'),
25 tabs:{
26 content: E('#fileedit-tab-content'),
27 preview: E('#fileedit-tab-preview'),
28 diff: E('#fileedit-tab-diff'),
29 commit: E('#fileedit-tab-commit')
@@ -47,20 +48,23 @@
48 tab panels. Seems to be the best fit in terms of
49 functionality and visibility. */
50 E('#fossil-status-bar'), P.tabs.e.tabs
51 );
52
53 P.tabs.addEventListener(
54 /* Set up auto-refresh of the preview tab... */
55 'before-switch-to', function(ev){
56 if(ev.detail===P.e.tabs.preview
57 && P.e.cbAutoPreview.checked){
58 P.preview();
59 }
60 }
61 );
62
63 F.connectPagePreviewers(
64 P.e.tabs.preview.querySelector(
65 '#btn-preview-refresh'
66 )
67 );
68
69 const diffButtons = E('#fileedit-tab-diff-buttons');
70 diffButtons.querySelector('button.sbs').addEventListener(
@@ -215,11 +219,10 @@
219 urlParams: {filename:file,checkin:rev},
220 onload:(r)=>{
221 F.message('Loaded content.');
222 self.e.taEditor.value = r;
223 self.updateVersion(file,rev);
 
224 self.tabs.switchToTab(self.e.tabs.content);
225 }
226 });
227 return this;
228 };
@@ -229,48 +232,46 @@
232 this page's input fields, and updates the UI with with the
233 preview.
234
235 Returns this object, noting that the operation is async.
236 */
237 P.preview = function f(switchToTab){
238 if(!this.finfo){
239 F.error("No content is loaded.");
240 return this;
241 }
242 if(!f.target){
243 f.target = this.e.tabs.preview.querySelector(
244 '#fileedit-tab-preview-wrapper'
245 );
246 }
247 const self = this;
248 const updateView = function(c){
249 D.clearElement(f.target);
250 if('string'===typeof c) f.target.innerHTML = c;
251 if(switchToTab) self.tabs.switchToTab(self.e.tabs.preview);
252 };
253 return this._postPreview(this.e.taEditor.value, updateView);
 
 
 
 
 
 
254 };
255
256 /**
257 Callback for use with F.connectPagePreviewers()
258 */
259 P._postPreview = function(content,callback){
260 if(!content){
261 callback(content);
262 return this;
263 }
264 const fd = new FormData();
265 fd.append('render_mode',E('select[name=preview_render_mode]').value);
266 fd.append('filename',this.finfo.filename);
267 fd.append('ln',E('[name=preview_ln]').checked ? 1 : 0);
268 fd.append('iframe_height', E('[name=preview_html_ems]').value);
269 fd.append('content',content || '');
270 F.message(
271 "Fetching preview..."
272 ).fetch('fileedit_preview',{
273 payload: fd,
274 onload: (r)=>{
275 callback(r);
276 F.message('Updated preview.');
277 },
@@ -277,29 +278,32 @@
278 onerror: (e)=>{
279 fossil.fetch.onerror(e);
280 callback("Error fetching preview: "+e);
281 }
282 });
283 return this;
284 };
285
286
287 /**
288 Fetches the content diff based on the contents and settings of this
289 page's input fields, and updates the UI with the diff view.
290
291 Returns this object, noting that the operation is async.
292 */
293 P.diff = function f(sbs){
294 if(!this.finfo){
295 F.error("No content is loaded.");
296 return this;
297 }
298 const content = this.e.taEditor.value,
 
 
 
299 self = this;
300 if(!f.target){
301 f.target = this.e.tabs.diff.querySelector(
302 '#fileedit-tab-diff-wrapper'
303 );
304 }
305 const fd = new FormData();
306 fd.append('filename',this.finfo.filename);
307 fd.append('checkin', this.finfo.checkin);
308 fd.append('sbs', sbs ? 1 : 0);
309 fd.append('content',content);
@@ -306,11 +310,11 @@
310 F.message(
311 "Fetching diff..."
312 ).fetch('fileedit_diff',{
313 payload: fd,
314 onload: function(c){
315 f.target.innerHTML = [
316 "<div>Diff <code>[",
317 self.finfo.checkin,
318 "]</code> &rarr; Local Edits</div>",
319 c||'No changes.'
320 ].join('');
321
--- src/fossil.tabs.js
+++ src/fossil.tabs.js
@@ -30,11 +30,14 @@
3030
};
3131
3232
TabManager.prototype = {
3333
/**
3434
Initializes the tabs associated with the given tab container
35
- (DOM element or selector for a single element).
35
+ (DOM element or selector for a single element). This must be
36
+ called once before using any other member functions of a given
37
+ instance, noting that the constructor will call this if it is
38
+ passed an argument.
3639
3740
The tab container must have an 'id' attribute. This function
3841
looks through the DOM for all elements which have
3942
data-tab-parent=thatId. For each one it creates a button to
4043
switch to that tab and moves the element into this.e.tabs.
@@ -45,11 +48,11 @@
4548
When it's done, it auto-selects the first tab unless a tab has
4649
a truthy numeric value in its data-tab-select attribute, in
4750
which case the last tab to have such a property is selected.
4851
4952
This method must only be called once per instance. TabManagers
50
- may be nested but may not share any tabs instances.
53
+ may be nested but must not share any tabs instances.
5154
5255
Returns this object.
5356
5457
DOM elements of potential interest to users:
5558
@@ -86,10 +89,11 @@
8689
if(+c.dataset.tabSelect) selectIndex=n;
8790
this.addTab(c);
8891
});
8992
return this.switchToTab(selectIndex);
9093
},
94
+
9195
/**
9296
For the given tab element, unique selector string, or integer
9397
(0-based tab number), returns the button associated with that
9498
tab, or undefined if the argument does not match any current
9599
tab.
@@ -122,10 +126,48 @@
122126
btn.$manager = this;
123127
btn.$tab = tab;
124128
btn.addEventListener('click', f.click, false);
125129
return this;
126130
},
131
+
132
+ /**
133
+ Internal. Fires a new CustomEvent to all listeners which have
134
+ registered via this.addEventListener().
135
+ */
136
+ _dispatchEvent: function(name, detail){
137
+ try{
138
+ this.e.container.dispatchEvent(
139
+ new CustomEvent(name, {detail: detail})
140
+ );
141
+ }catch(e){
142
+ /* ignore */
143
+ }
144
+ return this;
145
+ },
146
+
147
+ /**
148
+ Registers an event listener for this object's custom events.
149
+ The callback gets a CustomEvent object with a 'detail'
150
+ propertly holding any tab-related state for the event. The events
151
+ are:
152
+
153
+ - 'before-switch-to' is emitted immediately before a new tab is
154
+ switched to. detail = the tab element.
155
+
156
+ - 'after-switch-to' is emitted immediately after a new tab is
157
+ switched to. detail = the tab element.
158
+
159
+ Any exceptions thrown by listeners are caught and ignored, to
160
+ avoid that they knock the tab state out of sync.
161
+
162
+ Returns this object.
163
+ */
164
+ addEventListener: function(eventName, callback){
165
+ this.e.container.addEventListener(eventName, callback, false);
166
+ return this;
167
+ },
168
+
127169
/**
128170
If the given DOM element, unique selector, or integer (0-based
129171
tab number) is one of this object's tabs, the UI makes that tab
130172
the currently-visible one. Returns this object.
131173
*/
@@ -133,13 +175,21 @@
133175
tab = tabArg(tab,this);
134176
const self = this;
135177
this.e.tabs.childNodes.forEach((e,ndx)=>{
136178
const btn = this.e.tabBar.childNodes[ndx];
137179
if(e===tab){
180
+ if(D.hasClass(e,'selected')){
181
+ return;
182
+ }
183
+ self._dispatchEvent('before-switch-to',tab);
138184
setVisible(e, true);
139185
D.addClass(btn,'selected');
186
+ self._dispatchEvent('after-switch-to',tab);
140187
}else{
188
+ if(D.hasClass(e,'selected')){
189
+ return;
190
+ }
141191
setVisible(e, false);
142192
D.removeClass(btn,'selected');
143193
}
144194
});
145195
return this;
146196
--- src/fossil.tabs.js
+++ src/fossil.tabs.js
@@ -30,11 +30,14 @@
30 };
31
32 TabManager.prototype = {
33 /**
34 Initializes the tabs associated with the given tab container
35 (DOM element or selector for a single element).
 
 
 
36
37 The tab container must have an 'id' attribute. This function
38 looks through the DOM for all elements which have
39 data-tab-parent=thatId. For each one it creates a button to
40 switch to that tab and moves the element into this.e.tabs.
@@ -45,11 +48,11 @@
45 When it's done, it auto-selects the first tab unless a tab has
46 a truthy numeric value in its data-tab-select attribute, in
47 which case the last tab to have such a property is selected.
48
49 This method must only be called once per instance. TabManagers
50 may be nested but may not share any tabs instances.
51
52 Returns this object.
53
54 DOM elements of potential interest to users:
55
@@ -86,10 +89,11 @@
86 if(+c.dataset.tabSelect) selectIndex=n;
87 this.addTab(c);
88 });
89 return this.switchToTab(selectIndex);
90 },
 
91 /**
92 For the given tab element, unique selector string, or integer
93 (0-based tab number), returns the button associated with that
94 tab, or undefined if the argument does not match any current
95 tab.
@@ -122,10 +126,48 @@
122 btn.$manager = this;
123 btn.$tab = tab;
124 btn.addEventListener('click', f.click, false);
125 return this;
126 },
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
127 /**
128 If the given DOM element, unique selector, or integer (0-based
129 tab number) is one of this object's tabs, the UI makes that tab
130 the currently-visible one. Returns this object.
131 */
@@ -133,13 +175,21 @@
133 tab = tabArg(tab,this);
134 const self = this;
135 this.e.tabs.childNodes.forEach((e,ndx)=>{
136 const btn = this.e.tabBar.childNodes[ndx];
137 if(e===tab){
 
 
 
 
138 setVisible(e, true);
139 D.addClass(btn,'selected');
 
140 }else{
 
 
 
141 setVisible(e, false);
142 D.removeClass(btn,'selected');
143 }
144 });
145 return this;
146
--- src/fossil.tabs.js
+++ src/fossil.tabs.js
@@ -30,11 +30,14 @@
30 };
31
32 TabManager.prototype = {
33 /**
34 Initializes the tabs associated with the given tab container
35 (DOM element or selector for a single element). This must be
36 called once before using any other member functions of a given
37 instance, noting that the constructor will call this if it is
38 passed an argument.
39
40 The tab container must have an 'id' attribute. This function
41 looks through the DOM for all elements which have
42 data-tab-parent=thatId. For each one it creates a button to
43 switch to that tab and moves the element into this.e.tabs.
@@ -45,11 +48,11 @@
48 When it's done, it auto-selects the first tab unless a tab has
49 a truthy numeric value in its data-tab-select attribute, in
50 which case the last tab to have such a property is selected.
51
52 This method must only be called once per instance. TabManagers
53 may be nested but must not share any tabs instances.
54
55 Returns this object.
56
57 DOM elements of potential interest to users:
58
@@ -86,10 +89,11 @@
89 if(+c.dataset.tabSelect) selectIndex=n;
90 this.addTab(c);
91 });
92 return this.switchToTab(selectIndex);
93 },
94
95 /**
96 For the given tab element, unique selector string, or integer
97 (0-based tab number), returns the button associated with that
98 tab, or undefined if the argument does not match any current
99 tab.
@@ -122,10 +126,48 @@
126 btn.$manager = this;
127 btn.$tab = tab;
128 btn.addEventListener('click', f.click, false);
129 return this;
130 },
131
132 /**
133 Internal. Fires a new CustomEvent to all listeners which have
134 registered via this.addEventListener().
135 */
136 _dispatchEvent: function(name, detail){
137 try{
138 this.e.container.dispatchEvent(
139 new CustomEvent(name, {detail: detail})
140 );
141 }catch(e){
142 /* ignore */
143 }
144 return this;
145 },
146
147 /**
148 Registers an event listener for this object's custom events.
149 The callback gets a CustomEvent object with a 'detail'
150 propertly holding any tab-related state for the event. The events
151 are:
152
153 - 'before-switch-to' is emitted immediately before a new tab is
154 switched to. detail = the tab element.
155
156 - 'after-switch-to' is emitted immediately after a new tab is
157 switched to. detail = the tab element.
158
159 Any exceptions thrown by listeners are caught and ignored, to
160 avoid that they knock the tab state out of sync.
161
162 Returns this object.
163 */
164 addEventListener: function(eventName, callback){
165 this.e.container.addEventListener(eventName, callback, false);
166 return this;
167 },
168
169 /**
170 If the given DOM element, unique selector, or integer (0-based
171 tab number) is one of this object's tabs, the UI makes that tab
172 the currently-visible one. Returns this object.
173 */
@@ -133,13 +175,21 @@
175 tab = tabArg(tab,this);
176 const self = this;
177 this.e.tabs.childNodes.forEach((e,ndx)=>{
178 const btn = this.e.tabBar.childNodes[ndx];
179 if(e===tab){
180 if(D.hasClass(e,'selected')){
181 return;
182 }
183 self._dispatchEvent('before-switch-to',tab);
184 setVisible(e, true);
185 D.addClass(btn,'selected');
186 self._dispatchEvent('after-switch-to',tab);
187 }else{
188 if(D.hasClass(e,'selected')){
189 return;
190 }
191 setVisible(e, false);
192 D.removeClass(btn,'selected');
193 }
194 });
195 return this;
196
+9 -6
--- src/style.c
+++ src/style.c
@@ -1313,30 +1313,33 @@
13131313
** <input type='checkbox' name={{zFieldName}} value={{zValue}}
13141314
** {{isChecked ? " checked : ""}}/>
13151315
** <span>{{zLabel}}</span>
13161316
** </span>
13171317
**
1318
-** zFieldName, zLabel, and zValue are required. zWrapperId and zTip
1319
-** are optional.
1318
+** zLabel, and zValue are required. zFieldName, zWrapperId, and zTip
1319
+** are may be NULL or empty.
13201320
**
13211321
** Be sure that the input-with-label CSS class is defined sensibly, in
13221322
** particular, having its display:inline-block is useful for alignment
13231323
** purposes.
13241324
*/
13251325
void style_labeled_checkbox(const char * zWrapperId,
13261326
const char *zFieldName, const char * zLabel,
1327
- const char * zValue, const char * zTip,
1328
- int isChecked){
1327
+ const char * zValue, int isChecked,
1328
+ const char * zTip){
13291329
CX("<span class='input-with-label'");
13301330
if(zTip && *zTip){
13311331
CX(" title='%h'", zTip);
13321332
}
13331333
if(zWrapperId && *zWrapperId){
13341334
CX(" id='%s'",zWrapperId);
13351335
}
1336
- CX("><input type='checkbox' name='%s' value='%T'%s/>",
1337
- zFieldName,
1336
+ CX("><input type='checkbox' ");
1337
+ if(zFieldName && *zFieldName){
1338
+ CX("name='%s' ",zFieldName);
1339
+ }
1340
+ CX("value='%T'%s/>",
13381341
zValue ? zValue : "", isChecked ? " checked" : "");
13391342
CX("<span>%h</span></span>", zLabel);
13401343
}
13411344
13421345
/*
13431346
--- src/style.c
+++ src/style.c
@@ -1313,30 +1313,33 @@
1313 ** <input type='checkbox' name={{zFieldName}} value={{zValue}}
1314 ** {{isChecked ? " checked : ""}}/>
1315 ** <span>{{zLabel}}</span>
1316 ** </span>
1317 **
1318 ** zFieldName, zLabel, and zValue are required. zWrapperId and zTip
1319 ** are optional.
1320 **
1321 ** Be sure that the input-with-label CSS class is defined sensibly, in
1322 ** particular, having its display:inline-block is useful for alignment
1323 ** purposes.
1324 */
1325 void style_labeled_checkbox(const char * zWrapperId,
1326 const char *zFieldName, const char * zLabel,
1327 const char * zValue, const char * zTip,
1328 int isChecked){
1329 CX("<span class='input-with-label'");
1330 if(zTip && *zTip){
1331 CX(" title='%h'", zTip);
1332 }
1333 if(zWrapperId && *zWrapperId){
1334 CX(" id='%s'",zWrapperId);
1335 }
1336 CX("><input type='checkbox' name='%s' value='%T'%s/>",
1337 zFieldName,
 
 
 
1338 zValue ? zValue : "", isChecked ? " checked" : "");
1339 CX("<span>%h</span></span>", zLabel);
1340 }
1341
1342 /*
1343
--- src/style.c
+++ src/style.c
@@ -1313,30 +1313,33 @@
1313 ** <input type='checkbox' name={{zFieldName}} value={{zValue}}
1314 ** {{isChecked ? " checked : ""}}/>
1315 ** <span>{{zLabel}}</span>
1316 ** </span>
1317 **
1318 ** zLabel, and zValue are required. zFieldName, zWrapperId, and zTip
1319 ** are may be NULL or empty.
1320 **
1321 ** Be sure that the input-with-label CSS class is defined sensibly, in
1322 ** particular, having its display:inline-block is useful for alignment
1323 ** purposes.
1324 */
1325 void style_labeled_checkbox(const char * zWrapperId,
1326 const char *zFieldName, const char * zLabel,
1327 const char * zValue, int isChecked,
1328 const char * zTip){
1329 CX("<span class='input-with-label'");
1330 if(zTip && *zTip){
1331 CX(" title='%h'", zTip);
1332 }
1333 if(zWrapperId && *zWrapperId){
1334 CX(" id='%s'",zWrapperId);
1335 }
1336 CX("><input type='checkbox' ");
1337 if(zFieldName && *zFieldName){
1338 CX("name='%s' ",zFieldName);
1339 }
1340 CX("value='%T'%s/>",
1341 zValue ? zValue : "", isChecked ? " checked" : "");
1342 CX("<span>%h</span></span>", zLabel);
1343 }
1344
1345 /*
1346

Keyboard Shortcuts

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