Many hyperlinks are disabled.
Use anonymous login
to enable hyperlinks.
Overview
| Comment: | 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). |
|---|---|
| Downloads: | Tarball | ZIP archive |
| Timelines: | family | ancestors | descendants | both | fileedit-ajaxify |
| Files: | files | file ages | folders |
| SHA3-256: |
ee175636aa9a8862b2ae2e7d42c3365e |
| User & Date: | stephan 2020-05-10 08:47:53.144 |
Context
|
2020-05-10
| ||
| 09:16 | Minor efficiency hack in style_emit_script_builtin() and swapped a potentially problematic ordering of two JS includes. ... (check-in: c60ad868b4 user: stephan tags: fileedit-ajaxify) | |
| 08:47 | 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). ... (check-in: ee175636aa user: stephan tags: fileedit-ajaxify) | |
|
2020-05-09
| ||
| 13:56 | Disable rendering of the comment mime type selection list, as it's not honored/implemented where comments are rendered. ... (check-in: 875b60bccd user: stephan tags: fileedit-ajaxify) | |
Changes
Changes to src/default_css.txt.
| ︙ | ︙ | |||
994 995 996 997 998 999 1000 |
padding: 0;
}
#fileedit-comment {
width: 100%;
font-family: monospace;
}
.tab-container > .tabs > .tab-panel > .fileedit-options {
| | > > > > > > > > > > > > > > | 994 995 996 997 998 999 1000 1001 1002 1003 1004 1005 1006 1007 1008 1009 1010 1011 1012 1013 1014 1015 1016 1017 1018 1019 1020 1021 1022 1023 1024 1025 1026 1027 1028 1029 1030 1031 1032 1033 1034 1035 1036 1037 1038 1039 1040 1041 1042 1043 1044 1045 1046 1047 1048 1049 1050 1051 1052 1053 1054 1055 1056 1057 1058 1059 1060 1061 |
padding: 0;
}
#fileedit-comment {
width: 100%;
font-family: monospace;
}
.tab-container > .tabs > .tab-panel > .fileedit-options {
margin-top: 0;
border: none;
border-radius: 0;
border-bottom-width: 1px;
border-bottom-style: dotted;
}
.tab-container > .tabs > .tab-panel > .fileedit-options > button {
vertical-align: middle;
margin: 0.5em;
}
.tab-container > .tabs > .tab-panel > .fileedit-options > input {
vertical-align: middle;
margin: 0.5em;
}
.tab-container > .tabs > .tab-panel > .fileedit-options > .input-with-label {
vertical-align: middle;
margin: 0.5em;
}
////////////////////////////////////////////////////////////////////
// Styles developed for /fileedit but which have wider
// applicability:
.flex-container {
display: flex;
}
.flex-container.row {
flex-direction: row;
flex-wrap: wrap;
justify-content: center;
align-items: center;
}
.fileedit-options.flex-container.row {
align-items: first baseline;
}
.fileedit-options > div > * {
margin: 0.25em;
}
.flex-container.row.stretch {
flex-direction: row;
flex-wrap: wrap;
align-items: stretch;
margin: 0;
}
.flex-container.column {
flex-direction: column;
flex-wrap: wrap;
justify-content: center;
align-items: center;
}
.flex-container.column.stretch {
align-items: stretch;
margin: 0;
}
.flex-container.child-gap-small > * {
margin: 0.25em;
}
.font-size-100 {
font-size: 100%;
}
.font-size-125 {
font-size: 125%;
}
|
| ︙ | ︙ | |||
1059 1060 1061 1062 1063 1064 1065 |
// contains a SPAN label and an INPUT control.
.input-with-label {
border: 1px inset #808080;
border-radius: 0.5em;
padding: 0.25em 0.4em;
margin: 0 0.5em;
display: inline-block;
| | | 1073 1074 1075 1076 1077 1078 1079 1080 1081 1082 1083 1084 1085 1086 1087 |
// contains a SPAN label and an INPUT control.
.input-with-label {
border: 1px inset #808080;
border-radius: 0.5em;
padding: 0.25em 0.4em;
margin: 0 0.5em;
display: inline-block;
cursor: default;
}
.input-with-label > * {
vertical-align: middle;
}
.input-with-label > input {
margin: 0;
}
|
| ︙ | ︙ |
Changes to src/fileedit.c.
| ︙ | ︙ | |||
1604 1605 1606 1607 1608 1609 1610 |
/******* Content tab *******/
{
CX("<div id='fileedit-tab-content' "
"data-tab-parent='fileedit-tabs' "
"data-tab-label='File Content'"
">");
| | > | 1604 1605 1606 1607 1608 1609 1610 1611 1612 1613 1614 1615 1616 1617 1618 1619 |
/******* Content tab *******/
{
CX("<div id='fileedit-tab-content' "
"data-tab-parent='fileedit-tabs' "
"data-tab-label='File Content'"
">");
CX("<div class='fileedit-options "
"flex-container row child-gap-small'>");
if(1){
/* Discard/reload button. Leave this out until we have a
** nice way of offering confirmation, e.g. like the old
** jQuery.confirmer plugin which required a 2nd click of the
** button within X seconds to confirm. Right now it's simply
** to easy to tap by accident. */
CX("<button class='fileedit-content-reload confirmer' "
|
| ︙ | ︙ | |||
1652 1653 1654 1655 1656 1657 1658 1659 1660 1661 1662 1663 1664 1665 |
"data-f-preview-from='fileedit-content-editor' "
/* ^^^ text source elem ID*/
"data-f-preview-via='_postPreview' "
/* ^^^ fossil.page[methodName](content, callback) */
"data-f-preview-to='fileedit-tab-preview-wrapper' "
/* ^^^ dest elem ID */
">Refresh</button>");
/* Default preview rendering mode selection... */
previewRenderMode = fileedit_render_mode_for_mimetype(zFileMime);
style_select_list_int("select-preview-mode",
"preview_render_mode",
"Preview Mode",
"Preview mode format.",
previewRenderMode,
| > > > > > > > > > > | 1653 1654 1655 1656 1657 1658 1659 1660 1661 1662 1663 1664 1665 1666 1667 1668 1669 1670 1671 1672 1673 1674 1675 1676 |
"data-f-preview-from='fileedit-content-editor' "
/* ^^^ text source elem ID*/
"data-f-preview-via='_postPreview' "
/* ^^^ fossil.page[methodName](content, callback) */
"data-f-preview-to='fileedit-tab-preview-wrapper' "
/* ^^^ dest elem ID */
">Refresh</button>");
/* Toggle auto-update of preview when the Preview tab is selected. */
style_labeled_checkbox("cb-preview-autoupdate",
NULL,
"Auto-refresh?",
"1", 1,
"If on, the preview will automatically "
"refresh when this tab is selected. Not "
"recommended for large files or slow "
"connections.");
/* Default preview rendering mode selection... */
previewRenderMode = fileedit_render_mode_for_mimetype(zFileMime);
style_select_list_int("select-preview-mode",
"preview_render_mode",
"Preview Mode",
"Preview mode format.",
previewRenderMode,
|
| ︙ | ︙ | |||
1698 1699 1700 1701 1702 1703 1704 |
"", 20, "", 40,
"", 60, "", 80,
"", 100, NULL);
/* Selection of line numbers for text preview */
style_labeled_checkbox("cb-line-numbers",
"preview_ln",
"Add line numbers to plain-text previews?",
| | | < | 1709 1710 1711 1712 1713 1714 1715 1716 1717 1718 1719 1720 1721 1722 1723 1724 1725 |
"", 20, "", 40,
"", 60, "", 80,
"", 100, NULL);
/* Selection of line numbers for text preview */
style_labeled_checkbox("cb-line-numbers",
"preview_ln",
"Add line numbers to plain-text previews?",
"1", P("preview_ln")!=0,
"If on, plain-text files (only) will get "
"line numbers added to the preview.");
CX("</div>"/*.fileedit-options*/);
CX("<div id='fileedit-tab-preview-wrapper'></div>");
CX("</div>"/*#fileedit-tab-preview*/);
}
/****** Diff tab ******/
{
|
| ︙ | ︙ | |||
1736 1737 1738 1739 1740 1741 1742 |
"data-tab-label='Commit'"
">");
{
/******* Commit flags/options *******/
CX("<div class='fileedit-options flex-container row'>");
style_labeled_checkbox("cb-dry-run",
| | | < > | < > | < < | > > | < > | < | 1746 1747 1748 1749 1750 1751 1752 1753 1754 1755 1756 1757 1758 1759 1760 1761 1762 1763 1764 1765 1766 1767 1768 1769 1770 1771 1772 1773 1774 1775 1776 1777 1778 1779 1780 1781 1782 1783 1784 1785 1786 1787 1788 1789 1790 1791 |
"data-tab-label='Commit'"
">");
{
/******* Commit flags/options *******/
CX("<div class='fileedit-options flex-container row'>");
style_labeled_checkbox("cb-dry-run",
"dry_run", "Dry-run?", "1", 1,
"In dry-run mode, the Save button performs "
"all work needed for saving but then rolls "
"back the transaction, and thus does not "
"really save.");
style_labeled_checkbox("cb-allow-fork",
"allow_fork", "Allow fork?", "1",
cimi.flags & CIMINI_ALLOW_FORK,
"Allow saving to create a fork?");
style_labeled_checkbox("cb-allow-older",
"allow_older", "Allow older?", "1",
cimi.flags & CIMINI_ALLOW_OLDER,
"Allow saving against a parent version "
"which has a newer timestamp?");
style_labeled_checkbox("cb-exec-bit",
"exec_bit", "Executable?", "1",
PERM_EXE==cimi.filePerm,
"Set the executable bit?");
style_labeled_checkbox("cb-allow-merge-conflict",
"allow_merge_conflict",
"Allow merge conflict markers?", "1",
cimi.flags & CIMINI_ALLOW_MERGE_MARKER,
"Allow saving even if the content contains "
"what appear to be fossil merge conflict "
"markers?");
style_labeled_checkbox("cb-prefer-delta",
"prefer_delta",
"Prefer delta manifest?", "1",
cimi.flags & CIMINI_PREFER_DELTA,
"Will create a delta manifest, instead of "
"baseline, if conditions are favorable to "
"do so. This option is only a suggestion.");
style_select_list_int("select-eol-style",
"eol", "EOL Style",
"EOL conversion policy, noting that "
"form-processing may implicitly change the "
"line endings of the input.",
(cimi.flags & CIMINI_CONVERT_EOL_UNIX)
? 1 : (cimi.flags & CIMINI_CONVERT_EOL_WINDOWS
|
| ︙ | ︙ | |||
1795 1796 1797 1798 1799 1800 1801 |
** mode. JS code sets up the ability to toggle between single-
** and multi-line modes. */
CX("<input type='text' name='comment' "
"id='fileedit-comment'></input>");
CX("<textarea name='commentBig' class='hidden' "
"rows='5' id='fileedit-comment-big'></textarea>\n");
{ /* comment options... */
| | | | 1804 1805 1806 1807 1808 1809 1810 1811 1812 1813 1814 1815 1816 1817 1818 1819 1820 1821 1822 1823 |
** mode. JS code sets up the ability to toggle between single-
** and multi-line modes. */
CX("<input type='text' name='comment' "
"id='fileedit-comment'></input>");
CX("<textarea name='commentBig' class='hidden' "
"rows='5' id='fileedit-comment-big'></textarea>\n");
{ /* comment options... */
CX("<div class='flex-container column child-gap-small'>");
CX("<button id='comment-toggle' "
"title='Toggle between single- and multi-line comment mode, "
"noting that switching from multi- to single-line will cause "
"newlines to get stripped.'"
">Toggle single-/multi-line</button> ");
if(0){
/* Manifests support an N-card (comment mime type) but it has
** yet to be honored where comments are rendered, so we don't
** currently offer it as an option here:
** https://fossil-scm.org/forum/forumpost/662da045a1
**
** If/when it's ever implemented, simply enable this block and
|
| ︙ | ︙ |
Changes to src/fossil.page.fileedit.js.
| ︙ | ︙ | |||
17 18 19 20 21 22 23 24 25 26 27 28 29 30 |
btnCommit: E("#fileedit-btn-commit"),
btnReload: E("#fileedit-tab-content > .fileedit-options > "
+"button.fileedit-content-reload"),
selectPreviewModeWrap: E('#select-preview-mode'),
selectHtmlEmsWrap: E('#select-preview-html-ems'),
selectEolWrap: E('#select-preview-html-ems'),
cbLineNumbersWrap: E('#cb-line-numbers'),
tabs:{
content: E('#fileedit-tab-content'),
preview: E('#fileedit-tab-preview'),
diff: E('#fileedit-tab-diff'),
commit: E('#fileedit-tab-commit')
}
};
| > | 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 |
btnCommit: E("#fileedit-btn-commit"),
btnReload: E("#fileedit-tab-content > .fileedit-options > "
+"button.fileedit-content-reload"),
selectPreviewModeWrap: E('#select-preview-mode'),
selectHtmlEmsWrap: E('#select-preview-html-ems'),
selectEolWrap: E('#select-preview-html-ems'),
cbLineNumbersWrap: E('#cb-line-numbers'),
cbAutoPreview: E('#cb-preview-autoupdate > input[type=checkbox]'),
tabs:{
content: E('#fileedit-tab-content'),
preview: E('#fileedit-tab-preview'),
diff: E('#fileedit-tab-diff'),
commit: E('#fileedit-tab-commit')
}
};
|
| ︙ | ︙ | |||
45 46 47 48 49 50 51 |
P.tabs.e.container.insertBefore(
/* Move the status bar between the tab buttons and
tab panels. Seems to be the best fit in terms of
functionality and visibility. */
E('#fossil-status-bar'), P.tabs.e.tabs
);
| > > | | < > | < | > > | < > | 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 |
P.tabs.e.container.insertBefore(
/* Move the status bar between the tab buttons and
tab panels. Seems to be the best fit in terms of
functionality and visibility. */
E('#fossil-status-bar'), P.tabs.e.tabs
);
P.tabs.addEventListener(
/* Set up auto-refresh of the preview tab... */
'before-switch-to', function(ev){
if(ev.detail===P.e.tabs.preview
&& P.e.cbAutoPreview.checked){
P.preview();
}
}
);
F.connectPagePreviewers(
P.e.tabs.preview.querySelector(
'#btn-preview-refresh'
)
);
const diffButtons = E('#fileedit-tab-diff-buttons');
diffButtons.querySelector('button.sbs').addEventListener(
"click",(e)=>P.diff(true), false
);
|
| ︙ | ︙ | |||
213 214 215 216 217 218 219 |
F.message("Loading content...");
F.fetch('fileedit_content',{
urlParams: {filename:file,checkin:rev},
onload:(r)=>{
F.message('Loaded content.');
self.e.taEditor.value = r;
self.updateVersion(file,rev);
| < | > | | | > | | < < < | < < < | > > | > | > > | | | < > | | 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 |
F.message("Loading content...");
F.fetch('fileedit_content',{
urlParams: {filename:file,checkin:rev},
onload:(r)=>{
F.message('Loaded content.');
self.e.taEditor.value = r;
self.updateVersion(file,rev);
self.tabs.switchToTab(self.e.tabs.content);
}
});
return this;
};
/**
Fetches the page preview based on the contents and settings of
this page's input fields, and updates the UI with with the
preview.
Returns this object, noting that the operation is async.
*/
P.preview = function f(switchToTab){
if(!this.finfo){
F.error("No content is loaded.");
return this;
}
if(!f.target){
f.target = this.e.tabs.preview.querySelector(
'#fileedit-tab-preview-wrapper'
);
}
const self = this;
const updateView = function(c){
D.clearElement(f.target);
if('string'===typeof c) f.target.innerHTML = c;
if(switchToTab) self.tabs.switchToTab(self.e.tabs.preview);
};
return this._postPreview(this.e.taEditor.value, updateView);
};
/**
Callback for use with F.connectPagePreviewers()
*/
P._postPreview = function(content,callback){
if(!content){
callback(content);
return this;
}
const fd = new FormData();
fd.append('render_mode',E('select[name=preview_render_mode]').value);
fd.append('filename',this.finfo.filename);
fd.append('ln',E('[name=preview_ln]').checked ? 1 : 0);
fd.append('iframe_height', E('[name=preview_html_ems]').value);
fd.append('content',content || '');
F.message(
"Fetching preview..."
).fetch('fileedit_preview',{
payload: fd,
onload: (r)=>{
callback(r);
F.message('Updated preview.');
},
onerror: (e)=>{
fossil.fetch.onerror(e);
callback("Error fetching preview: "+e);
}
});
return this;
};
/**
Fetches the content diff based on the contents and settings of this
page's input fields, and updates the UI with the diff view.
Returns this object, noting that the operation is async.
*/
P.diff = function f(sbs){
if(!this.finfo){
F.error("No content is loaded.");
return this;
}
const content = this.e.taEditor.value,
self = this;
if(!f.target){
f.target = this.e.tabs.diff.querySelector(
'#fileedit-tab-diff-wrapper'
);
}
const fd = new FormData();
fd.append('filename',this.finfo.filename);
fd.append('checkin', this.finfo.checkin);
fd.append('sbs', sbs ? 1 : 0);
fd.append('content',content);
F.message(
"Fetching diff..."
).fetch('fileedit_diff',{
payload: fd,
onload: function(c){
f.target.innerHTML = [
"<div>Diff <code>[",
self.finfo.checkin,
"]</code> → Local Edits</div>",
c||'No changes.'
].join('');
F.message('Updated diff.');
self.tabs.switchToTab(self.e.tabs.diff);
|
| ︙ | ︙ |
Changes to src/fossil.tabs.js.
| ︙ | ︙ | |||
28 29 30 31 32 33 34 |
const setVisible = function(e,yes){
D[yes ? 'removeClass' : 'addClass'](e, 'hidden');
};
TabManager.prototype = {
/**
Initializes the tabs associated with the given tab container
| | > > > | | 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 |
const setVisible = function(e,yes){
D[yes ? 'removeClass' : 'addClass'](e, 'hidden');
};
TabManager.prototype = {
/**
Initializes the tabs associated with the given tab container
(DOM element or selector for a single element). This must be
called once before using any other member functions of a given
instance, noting that the constructor will call this if it is
passed an argument.
The tab container must have an 'id' attribute. This function
looks through the DOM for all elements which have
data-tab-parent=thatId. For each one it creates a button to
switch to that tab and moves the element into this.e.tabs.
The label for each tab is set by the data-tab-label attribute
of each element, defaulting to something not terribly useful.
When it's done, it auto-selects the first tab unless a tab has
a truthy numeric value in its data-tab-select attribute, in
which case the last tab to have such a property is selected.
This method must only be called once per instance. TabManagers
may be nested but must not share any tabs instances.
Returns this object.
DOM elements of potential interest to users:
this.e.container = the outermost container element.
|
| ︙ | ︙ | |||
84 85 86 87 88 89 90 91 92 93 94 95 96 97 |
let selectIndex = 0;
EA('[data-tab-parent='+cID+']').forEach((c,n)=>{
if(+c.dataset.tabSelect) selectIndex=n;
this.addTab(c);
});
return this.switchToTab(selectIndex);
},
/**
For the given tab element, unique selector string, or integer
(0-based tab number), returns the button associated with that
tab, or undefined if the argument does not match any current
tab.
*/
getButtonForTab: function(tab){
| > | 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 |
let selectIndex = 0;
EA('[data-tab-parent='+cID+']').forEach((c,n)=>{
if(+c.dataset.tabSelect) selectIndex=n;
this.addTab(c);
});
return this.switchToTab(selectIndex);
},
/**
For the given tab element, unique selector string, or integer
(0-based tab number), returns the button associated with that
tab, or undefined if the argument does not match any current
tab.
*/
getButtonForTab: function(tab){
|
| ︙ | ︙ | |||
120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 |
const btn = D.addClass(D.append(D.span(), lbl), 'tab-button');
D.append(this.e.tabBar,btn);
btn.$manager = this;
btn.$tab = tab;
btn.addEventListener('click', f.click, false);
return this;
},
/**
If the given DOM element, unique selector, or integer (0-based
tab number) is one of this object's tabs, the UI makes that tab
the currently-visible one. Returns this object.
*/
switchToTab: function(tab){
tab = tabArg(tab,this);
const self = this;
this.e.tabs.childNodes.forEach((e,ndx)=>{
const btn = this.e.tabBar.childNodes[ndx];
if(e===tab){
setVisible(e, true);
D.addClass(btn,'selected');
}else{
setVisible(e, false);
D.removeClass(btn,'selected');
}
});
return this;
}
};
F.TabManager = TabManager;
})(window.fossil);
| > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 |
const btn = D.addClass(D.append(D.span(), lbl), 'tab-button');
D.append(this.e.tabBar,btn);
btn.$manager = this;
btn.$tab = tab;
btn.addEventListener('click', f.click, false);
return this;
},
/**
Internal. Fires a new CustomEvent to all listeners which have
registered via this.addEventListener().
*/
_dispatchEvent: function(name, detail){
try{
this.e.container.dispatchEvent(
new CustomEvent(name, {detail: detail})
);
}catch(e){
/* ignore */
}
return this;
},
/**
Registers an event listener for this object's custom events.
The callback gets a CustomEvent object with a 'detail'
propertly holding any tab-related state for the event. The events
are:
- 'before-switch-to' is emitted immediately before a new tab is
switched to. detail = the tab element.
- 'after-switch-to' is emitted immediately after a new tab is
switched to. detail = the tab element.
Any exceptions thrown by listeners are caught and ignored, to
avoid that they knock the tab state out of sync.
Returns this object.
*/
addEventListener: function(eventName, callback){
this.e.container.addEventListener(eventName, callback, false);
return this;
},
/**
If the given DOM element, unique selector, or integer (0-based
tab number) is one of this object's tabs, the UI makes that tab
the currently-visible one. Returns this object.
*/
switchToTab: function(tab){
tab = tabArg(tab,this);
const self = this;
this.e.tabs.childNodes.forEach((e,ndx)=>{
const btn = this.e.tabBar.childNodes[ndx];
if(e===tab){
if(D.hasClass(e,'selected')){
return;
}
self._dispatchEvent('before-switch-to',tab);
setVisible(e, true);
D.addClass(btn,'selected');
self._dispatchEvent('after-switch-to',tab);
}else{
if(D.hasClass(e,'selected')){
return;
}
setVisible(e, false);
D.removeClass(btn,'selected');
}
});
return this;
}
};
F.TabManager = TabManager;
})(window.fossil);
|
Changes to src/style.c.
| ︙ | ︙ | |||
1311 1312 1313 1314 1315 1316 1317 |
**
** <span class='input-with-label' title={{zTip}} id={{zWrapperId}}>
** <input type='checkbox' name={{zFieldName}} value={{zValue}}
** {{isChecked ? " checked : ""}}/>
** <span>{{zLabel}}</span>
** </span>
**
| | | | | | > | > > | 1311 1312 1313 1314 1315 1316 1317 1318 1319 1320 1321 1322 1323 1324 1325 1326 1327 1328 1329 1330 1331 1332 1333 1334 1335 1336 1337 1338 1339 1340 1341 1342 1343 1344 1345 1346 1347 |
**
** <span class='input-with-label' title={{zTip}} id={{zWrapperId}}>
** <input type='checkbox' name={{zFieldName}} value={{zValue}}
** {{isChecked ? " checked : ""}}/>
** <span>{{zLabel}}</span>
** </span>
**
** zLabel, and zValue are required. zFieldName, zWrapperId, and zTip
** are may be NULL or empty.
**
** Be sure that the input-with-label CSS class is defined sensibly, in
** particular, having its display:inline-block is useful for alignment
** purposes.
*/
void style_labeled_checkbox(const char * zWrapperId,
const char *zFieldName, const char * zLabel,
const char * zValue, int isChecked,
const char * zTip){
CX("<span class='input-with-label'");
if(zTip && *zTip){
CX(" title='%h'", zTip);
}
if(zWrapperId && *zWrapperId){
CX(" id='%s'",zWrapperId);
}
CX("><input type='checkbox' ");
if(zFieldName && *zFieldName){
CX("name='%s' ",zFieldName);
}
CX("value='%T'%s/>",
zValue ? zValue : "", isChecked ? " checked" : "");
CX("<span>%h</span></span>", zLabel);
}
/*
** Outputs a SELECT list from a compile-time list of integers.
** The vargs must be a list of (const char *, int) pairs, terminated
|
| ︙ | ︙ |