Fossil SCM
Added style_select_list_str(), selection list for commit comment mime type, and a toggle to switch between single- and multi-line comment editing modes.
Commit
4d5004ef2d8cdf02bd106910d18f76eeb7b8b979bfd9d3f88fbb73c13e275449
Parent
02240eec90dee97…
4 files changed
+4
-1
+29
-12
+38
-1
+62
-1
+4
-1
| --- src/default_css.txt | ||
| +++ src/default_css.txt | ||
| @@ -996,11 +996,11 @@ | ||
| 996 | 996 | #fileedit-comment { |
| 997 | 997 | width: 100%; |
| 998 | 998 | font-family: monospace; |
| 999 | 999 | } |
| 1000 | 1000 | .tab-container > .tabs > .tab-panel > .fileedit-options { |
| 1001 | - margin-top: 0; | |
| 1001 | + margin-top: 0.25em 0; | |
| 1002 | 1002 | border: none; |
| 1003 | 1003 | border-radius: 0; |
| 1004 | 1004 | border-bottom-width: 1px; |
| 1005 | 1005 | border-bottom-style: dotted; |
| 1006 | 1006 | } |
| @@ -1017,10 +1017,13 @@ | ||
| 1017 | 1017 | .flex-container.row { |
| 1018 | 1018 | flex-direction: row; |
| 1019 | 1019 | flex-wrap: wrap; |
| 1020 | 1020 | justify-content: center; |
| 1021 | 1021 | align-items: center; |
| 1022 | +} | |
| 1023 | +.fileedit-options.flex-container.row { | |
| 1024 | + align-items: first baseline; | |
| 1022 | 1025 | } |
| 1023 | 1026 | .flex-container.row.stretch { |
| 1024 | 1027 | flex-direction: row; |
| 1025 | 1028 | flex-wrap: wrap; |
| 1026 | 1029 | align-items: stretch; |
| 1027 | 1030 |
| --- src/default_css.txt | |
| +++ src/default_css.txt | |
| @@ -996,11 +996,11 @@ | |
| 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 | } |
| @@ -1017,10 +1017,13 @@ | |
| 1017 | .flex-container.row { |
| 1018 | flex-direction: row; |
| 1019 | flex-wrap: wrap; |
| 1020 | justify-content: center; |
| 1021 | align-items: center; |
| 1022 | } |
| 1023 | .flex-container.row.stretch { |
| 1024 | flex-direction: row; |
| 1025 | flex-wrap: wrap; |
| 1026 | align-items: stretch; |
| 1027 |
| --- src/default_css.txt | |
| +++ src/default_css.txt | |
| @@ -996,11 +996,11 @@ | |
| 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 | } |
| @@ -1017,10 +1017,13 @@ | |
| 1017 | .flex-container.row { |
| 1018 | flex-direction: row; |
| 1019 | flex-wrap: wrap; |
| 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; |
| 1030 |
+29
-12
| --- src/fileedit.c | ||
| +++ src/fileedit.c | ||
| @@ -1788,23 +1788,40 @@ | ||
| 1788 | 1788 | CX("</div>"/*checkboxes*/); |
| 1789 | 1789 | } |
| 1790 | 1790 | |
| 1791 | 1791 | { /******* Commit comment, button, and result manifest *******/ |
| 1792 | 1792 | CX("<fieldset class='fileedit-options'>" |
| 1793 | - "<legend>Message (required)</legend><div>"); | |
| 1793 | + "<legend>Message (required) " | |
| 1794 | + "</legend><div>"); | |
| 1795 | + /* We have two comment input fields, defaulting to single-line | |
| 1796 | + ** mode. JS code sets up the ability to toggle between single- | |
| 1797 | + ** and multi-line modes. */ | |
| 1794 | 1798 | CX("<input type='text' name='comment' " |
| 1795 | - "id='fileedit-comment'>"); | |
| 1796 | - /* ^^^ adding the 'required' attribute means we cannot even | |
| 1797 | - submit for PREVIEW mode if it's empty :/. */ | |
| 1798 | - if(blob_size(&cimi.comment)){ | |
| 1799 | - blob_appendf(&endScript, | |
| 1800 | - "document.querySelector('#fileedit-comment').value=" | |
| 1801 | - "\"%h\";\n", blob_str(&cimi.comment)); | |
| 1802 | - } | |
| 1803 | - CX("</input>\n"); | |
| 1804 | - CX("<div class='fileedit-hint'>Comments use the Fossil wiki markup " | |
| 1805 | - "syntax.</div>\n"/*TODO: select for fossil/md/plain text*/); | |
| 1799 | + "id='fileedit-comment'></input>\n"); | |
| 1800 | + CX("<textarea name='commentBig' class='hidden' " | |
| 1801 | + "rows='5' id='fileedit-comment-big'></textarea>"); | |
| 1802 | + { /* comment options... */ | |
| 1803 | + CX("<div class='fileedit-options flex-container row'>"); | |
| 1804 | + CX("<button id='comment-toggle' " | |
| 1805 | + "title='Toggle between single- and multi-line comment mode, " | |
| 1806 | + "noting that switching from multi- to single-line may cause " | |
| 1807 | + "newlines to get stripped.'" | |
| 1808 | + ">toggle single-/multi-line</button> "); | |
| 1809 | + style_select_list_str("comment-mimetype", "comment_mimetype", | |
| 1810 | + "Comment style:", | |
| 1811 | + "Specify how fossil will interpret the " | |
| 1812 | + "comment string.", | |
| 1813 | + NULL, | |
| 1814 | + "Fossil", "text/x-fossil-wiki", | |
| 1815 | + "Markdown", "text/x-markdown", | |
| 1816 | + "Plain text", "text/plain", | |
| 1817 | + NULL); | |
| 1818 | + CX("</div>\n"); | |
| 1819 | + CX("<div class='fileedit-hint flex-container row'>" | |
| 1820 | + "(Warning: switching from multi- to single-line mode will " | |
| 1821 | + "strip out all newlines!)</div>"); | |
| 1822 | + } | |
| 1806 | 1823 | CX("</div></fieldset>\n"/*commit comment*/); |
| 1807 | 1824 | CX("<div class='flex-container row'>" |
| 1808 | 1825 | "<button id='fileedit-btn-commit'>Commit</button>" |
| 1809 | 1826 | "</div>\n"); |
| 1810 | 1827 | CX("<div id='fileedit-manifest'></div>\n"); |
| 1811 | 1828 |
| --- src/fileedit.c | |
| +++ src/fileedit.c | |
| @@ -1788,23 +1788,40 @@ | |
| 1788 | CX("</div>"/*checkboxes*/); |
| 1789 | } |
| 1790 | |
| 1791 | { /******* Commit comment, button, and result manifest *******/ |
| 1792 | CX("<fieldset class='fileedit-options'>" |
| 1793 | "<legend>Message (required)</legend><div>"); |
| 1794 | CX("<input type='text' name='comment' " |
| 1795 | "id='fileedit-comment'>"); |
| 1796 | /* ^^^ adding the 'required' attribute means we cannot even |
| 1797 | submit for PREVIEW mode if it's empty :/. */ |
| 1798 | if(blob_size(&cimi.comment)){ |
| 1799 | blob_appendf(&endScript, |
| 1800 | "document.querySelector('#fileedit-comment').value=" |
| 1801 | "\"%h\";\n", blob_str(&cimi.comment)); |
| 1802 | } |
| 1803 | CX("</input>\n"); |
| 1804 | CX("<div class='fileedit-hint'>Comments use the Fossil wiki markup " |
| 1805 | "syntax.</div>\n"/*TODO: select for fossil/md/plain text*/); |
| 1806 | CX("</div></fieldset>\n"/*commit comment*/); |
| 1807 | CX("<div class='flex-container row'>" |
| 1808 | "<button id='fileedit-btn-commit'>Commit</button>" |
| 1809 | "</div>\n"); |
| 1810 | CX("<div id='fileedit-manifest'></div>\n"); |
| 1811 |
| --- src/fileedit.c | |
| +++ src/fileedit.c | |
| @@ -1788,23 +1788,40 @@ | |
| 1788 | CX("</div>"/*checkboxes*/); |
| 1789 | } |
| 1790 | |
| 1791 | { /******* Commit comment, button, and result manifest *******/ |
| 1792 | CX("<fieldset class='fileedit-options'>" |
| 1793 | "<legend>Message (required) " |
| 1794 | "</legend><div>"); |
| 1795 | /* We have two comment input fields, defaulting to single-line |
| 1796 | ** mode. JS code sets up the ability to toggle between single- |
| 1797 | ** and multi-line modes. */ |
| 1798 | CX("<input type='text' name='comment' " |
| 1799 | "id='fileedit-comment'></input>\n"); |
| 1800 | CX("<textarea name='commentBig' class='hidden' " |
| 1801 | "rows='5' id='fileedit-comment-big'></textarea>"); |
| 1802 | { /* comment options... */ |
| 1803 | CX("<div class='fileedit-options flex-container row'>"); |
| 1804 | CX("<button id='comment-toggle' " |
| 1805 | "title='Toggle between single- and multi-line comment mode, " |
| 1806 | "noting that switching from multi- to single-line may cause " |
| 1807 | "newlines to get stripped.'" |
| 1808 | ">toggle single-/multi-line</button> "); |
| 1809 | style_select_list_str("comment-mimetype", "comment_mimetype", |
| 1810 | "Comment style:", |
| 1811 | "Specify how fossil will interpret the " |
| 1812 | "comment string.", |
| 1813 | NULL, |
| 1814 | "Fossil", "text/x-fossil-wiki", |
| 1815 | "Markdown", "text/x-markdown", |
| 1816 | "Plain text", "text/plain", |
| 1817 | NULL); |
| 1818 | CX("</div>\n"); |
| 1819 | CX("<div class='fileedit-hint flex-container row'>" |
| 1820 | "(Warning: switching from multi- to single-line mode will " |
| 1821 | "strip out all newlines!)</div>"); |
| 1822 | } |
| 1823 | CX("</div></fieldset>\n"/*commit comment*/); |
| 1824 | CX("<div class='flex-container row'>" |
| 1825 | "<button id='fileedit-btn-commit'>Commit</button>" |
| 1826 | "</div>\n"); |
| 1827 | CX("<div id='fileedit-manifest'></div>\n"); |
| 1828 |
+38
-1
| --- src/fossil.page.fileedit.js | ||
| +++ src/fossil.page.fileedit.js | ||
| @@ -9,11 +9,12 @@ | ||
| 9 | 9 | P = F.page; |
| 10 | 10 | window.addEventListener("load", function() { |
| 11 | 11 | P.tabs = new fossil.TabManager('#fileedit-tabs'); |
| 12 | 12 | P.e = { |
| 13 | 13 | taEditor: E('#fileedit-content-editor'), |
| 14 | - taComment: E('#fileedit-comment'), | |
| 14 | + taCommentSmall: E('#fileedit-comment'), | |
| 15 | + taCommentBig: E('#fileedit-comment-big'), | |
| 15 | 16 | ajaxContentTarget: E('#ajax-target'), |
| 16 | 17 | btnCommit: E("#fileedit-btn-commit"), |
| 17 | 18 | btnReload: E("#fileedit-tab-content > .fileedit-options > " |
| 18 | 19 | +"button.fileedit-content-reload"), |
| 19 | 20 | selectPreviewModeWrap: E('#select-preview-mode'), |
| @@ -25,10 +26,11 @@ | ||
| 25 | 26 | preview: E('#fileedit-tab-preview'), |
| 26 | 27 | diff: E('#fileedit-tab-diff'), |
| 27 | 28 | commit: E('#fileedit-tab-commit') |
| 28 | 29 | } |
| 29 | 30 | }; |
| 31 | + P.e.taComment = P.e.taCommentSmall; | |
| 30 | 32 | |
| 31 | 33 | P.tabs.e.container.insertBefore( |
| 32 | 34 | E('#fossil-status-bar'), P.tabs.e.tabs |
| 33 | 35 | ); |
| 34 | 36 | |
| @@ -58,10 +60,14 @@ | ||
| 58 | 60 | F.confirmer(P.e.btnReload, { |
| 59 | 61 | confirmText: "Really reload, losing edits?", |
| 60 | 62 | onconfirm: (e)=>P.loadFile(), |
| 61 | 63 | ticks: 3 |
| 62 | 64 | }); |
| 65 | + E('#comment-toggle').addEventListener( | |
| 66 | + "click",(e)=>P.toggleCommentMode(), false | |
| 67 | + ); | |
| 68 | + | |
| 63 | 69 | /** |
| 64 | 70 | Cosmetic: jump through some hoops to enable/disable |
| 65 | 71 | certain preview options depending on the current |
| 66 | 72 | preview mode... |
| 67 | 73 | */ |
| @@ -103,10 +109,41 @@ | ||
| 103 | 109 | // Force UI update |
| 104 | 110 | new Event('change',{target:selectFontSize}) |
| 105 | 111 | ); |
| 106 | 112 | } |
| 107 | 113 | }, false)/*onload event handler*/; |
| 114 | + | |
| 115 | + /** | |
| 116 | + Toggles between single- and multi-line comment | |
| 117 | + mode. | |
| 118 | + */ | |
| 119 | + P.toggleCommentMode = function(){ | |
| 120 | + var s, h, c = this.e.taComment.value; | |
| 121 | + if(this.e.taComment === this.e.taCommentSmall){ | |
| 122 | + s = this.e.taCommentBig; | |
| 123 | + h = this.e.taCommentSmall; | |
| 124 | + }else{ | |
| 125 | + s = this.e.taCommentSmall; | |
| 126 | + h = this.e.taCommentBig; | |
| 127 | + /* | |
| 128 | + Doing (input[type=text].value = textarea.value) unfortunately | |
| 129 | + strips all newlines. To compensate we'll replace each EOL with | |
| 130 | + a space. Not ideal. If we were to instead escape them as \n, | |
| 131 | + and do the reverse when toggling again, then they would get | |
| 132 | + committed as escaped newlines if the user did not first switch | |
| 133 | + back to multi-line mode. We cannot blindly unescape the | |
| 134 | + newlines, in the off chance that the user actually enters \n | |
| 135 | + in the comment. | |
| 136 | + */ | |
| 137 | + c = c.replace(/\r?\n/g,' '); | |
| 138 | + } | |
| 139 | + s.value = c; | |
| 140 | + this.e.taComment = s; | |
| 141 | + D.addClass(h, 'hidden'); | |
| 142 | + D.removeClass(s, 'hidden'); | |
| 143 | + console.debug(s,h); | |
| 144 | + }; | |
| 108 | 145 | |
| 109 | 146 | /** |
| 110 | 147 | updateVersion() updates the filename and version in various UI |
| 111 | 148 | elements... |
| 112 | 149 | |
| 113 | 150 |
| --- src/fossil.page.fileedit.js | |
| +++ src/fossil.page.fileedit.js | |
| @@ -9,11 +9,12 @@ | |
| 9 | P = F.page; |
| 10 | window.addEventListener("load", function() { |
| 11 | P.tabs = new fossil.TabManager('#fileedit-tabs'); |
| 12 | P.e = { |
| 13 | taEditor: E('#fileedit-content-editor'), |
| 14 | taComment: E('#fileedit-comment'), |
| 15 | ajaxContentTarget: E('#ajax-target'), |
| 16 | btnCommit: E("#fileedit-btn-commit"), |
| 17 | btnReload: E("#fileedit-tab-content > .fileedit-options > " |
| 18 | +"button.fileedit-content-reload"), |
| 19 | selectPreviewModeWrap: E('#select-preview-mode'), |
| @@ -25,10 +26,11 @@ | |
| 25 | preview: E('#fileedit-tab-preview'), |
| 26 | diff: E('#fileedit-tab-diff'), |
| 27 | commit: E('#fileedit-tab-commit') |
| 28 | } |
| 29 | }; |
| 30 | |
| 31 | P.tabs.e.container.insertBefore( |
| 32 | E('#fossil-status-bar'), P.tabs.e.tabs |
| 33 | ); |
| 34 | |
| @@ -58,10 +60,14 @@ | |
| 58 | F.confirmer(P.e.btnReload, { |
| 59 | confirmText: "Really reload, losing edits?", |
| 60 | onconfirm: (e)=>P.loadFile(), |
| 61 | ticks: 3 |
| 62 | }); |
| 63 | /** |
| 64 | Cosmetic: jump through some hoops to enable/disable |
| 65 | certain preview options depending on the current |
| 66 | preview mode... |
| 67 | */ |
| @@ -103,10 +109,41 @@ | |
| 103 | // Force UI update |
| 104 | new Event('change',{target:selectFontSize}) |
| 105 | ); |
| 106 | } |
| 107 | }, false)/*onload event handler*/; |
| 108 | |
| 109 | /** |
| 110 | updateVersion() updates the filename and version in various UI |
| 111 | elements... |
| 112 | |
| 113 |
| --- src/fossil.page.fileedit.js | |
| +++ src/fossil.page.fileedit.js | |
| @@ -9,11 +9,12 @@ | |
| 9 | P = F.page; |
| 10 | window.addEventListener("load", function() { |
| 11 | P.tabs = new fossil.TabManager('#fileedit-tabs'); |
| 12 | P.e = { |
| 13 | taEditor: E('#fileedit-content-editor'), |
| 14 | taCommentSmall: E('#fileedit-comment'), |
| 15 | taCommentBig: E('#fileedit-comment-big'), |
| 16 | ajaxContentTarget: E('#ajax-target'), |
| 17 | btnCommit: E("#fileedit-btn-commit"), |
| 18 | btnReload: E("#fileedit-tab-content > .fileedit-options > " |
| 19 | +"button.fileedit-content-reload"), |
| 20 | selectPreviewModeWrap: E('#select-preview-mode'), |
| @@ -25,10 +26,11 @@ | |
| 26 | preview: E('#fileedit-tab-preview'), |
| 27 | diff: E('#fileedit-tab-diff'), |
| 28 | commit: E('#fileedit-tab-commit') |
| 29 | } |
| 30 | }; |
| 31 | P.e.taComment = P.e.taCommentSmall; |
| 32 | |
| 33 | P.tabs.e.container.insertBefore( |
| 34 | E('#fossil-status-bar'), P.tabs.e.tabs |
| 35 | ); |
| 36 | |
| @@ -58,10 +60,14 @@ | |
| 60 | F.confirmer(P.e.btnReload, { |
| 61 | confirmText: "Really reload, losing edits?", |
| 62 | onconfirm: (e)=>P.loadFile(), |
| 63 | ticks: 3 |
| 64 | }); |
| 65 | E('#comment-toggle').addEventListener( |
| 66 | "click",(e)=>P.toggleCommentMode(), false |
| 67 | ); |
| 68 | |
| 69 | /** |
| 70 | Cosmetic: jump through some hoops to enable/disable |
| 71 | certain preview options depending on the current |
| 72 | preview mode... |
| 73 | */ |
| @@ -103,10 +109,41 @@ | |
| 109 | // Force UI update |
| 110 | new Event('change',{target:selectFontSize}) |
| 111 | ); |
| 112 | } |
| 113 | }, false)/*onload event handler*/; |
| 114 | |
| 115 | /** |
| 116 | Toggles between single- and multi-line comment |
| 117 | mode. |
| 118 | */ |
| 119 | P.toggleCommentMode = function(){ |
| 120 | var s, h, c = this.e.taComment.value; |
| 121 | if(this.e.taComment === this.e.taCommentSmall){ |
| 122 | s = this.e.taCommentBig; |
| 123 | h = this.e.taCommentSmall; |
| 124 | }else{ |
| 125 | s = this.e.taCommentSmall; |
| 126 | h = this.e.taCommentBig; |
| 127 | /* |
| 128 | Doing (input[type=text].value = textarea.value) unfortunately |
| 129 | strips all newlines. To compensate we'll replace each EOL with |
| 130 | a space. Not ideal. If we were to instead escape them as \n, |
| 131 | and do the reverse when toggling again, then they would get |
| 132 | committed as escaped newlines if the user did not first switch |
| 133 | back to multi-line mode. We cannot blindly unescape the |
| 134 | newlines, in the off chance that the user actually enters \n |
| 135 | in the comment. |
| 136 | */ |
| 137 | c = c.replace(/\r?\n/g,' '); |
| 138 | } |
| 139 | s.value = c; |
| 140 | this.e.taComment = s; |
| 141 | D.addClass(h, 'hidden'); |
| 142 | D.removeClass(s, 'hidden'); |
| 143 | console.debug(s,h); |
| 144 | }; |
| 145 | |
| 146 | /** |
| 147 | updateVersion() updates the filename and version in various UI |
| 148 | elements... |
| 149 | |
| 150 |
+62
-1
| --- src/style.c | ||
| +++ src/style.c | ||
| @@ -1416,15 +1416,76 @@ | ||
| 1416 | 1416 | CX("%d",v); |
| 1417 | 1417 | } |
| 1418 | 1418 | CX("</option>\n"); |
| 1419 | 1419 | } |
| 1420 | 1420 | CX("</select>\n"); |
| 1421 | + CX("</span>\n"); | |
| 1422 | + va_end(vargs); | |
| 1423 | +} | |
| 1424 | + | |
| 1425 | +/* | |
| 1426 | +** The C-string counterpart of style_select_list_int(), this variant | |
| 1427 | +** differs only in that its variadic arguments are C-strings in pairs | |
| 1428 | +** of (optionLabel, optionValue). If a given optionLabel is an empty | |
| 1429 | +** string, the corresponding optionValue is used as its label. If any | |
| 1430 | +** given value matches zSelectedVal, that option gets preselected. If | |
| 1431 | +** no options match zSelectedVal then the first entry is selected by | |
| 1432 | +** default. | |
| 1433 | +** | |
| 1434 | +** Any of (zWrapperId, zTooltip, zSelectedVal) may be NULL or empty. | |
| 1435 | +** | |
| 1436 | +** Example: | |
| 1437 | +** | |
| 1438 | +** style_select_list_str("my-grapes", "my_grapes", "Grapes", | |
| 1439 | +** "Select the number of grapes", | |
| 1440 | +** P("my_field"), | |
| 1441 | +** "1", "One", "2", "Two", "", "3", | |
| 1442 | +** NULL); | |
| 1443 | +*/ | |
| 1444 | +void style_select_list_str(const char * zWrapperId, | |
| 1445 | + const char *zFieldName, const char * zLabel, | |
| 1446 | + const char * zToolTip, char const * zSelectedVal, | |
| 1447 | + ... ){ | |
| 1448 | + va_list vargs; | |
| 1449 | + | |
| 1450 | + va_start(vargs,zSelectedVal); | |
| 1451 | + if(!zSelectedVal){ | |
| 1452 | + zSelectedVal = __FILE__/*some string we'll never match*/; | |
| 1453 | + } | |
| 1454 | + CX("<span class='input-with-label'"); | |
| 1455 | + if(zToolTip && *zToolTip){ | |
| 1456 | + CX(" title='%h'",zToolTip); | |
| 1457 | + } | |
| 1458 | + if(zWrapperId && *zWrapperId){ | |
| 1459 | + CX(" id='%s'",zWrapperId); | |
| 1460 | + } | |
| 1461 | + CX(">"); | |
| 1421 | 1462 | if(zLabel && *zLabel){ |
| 1422 | - CX("</span>\n"); | |
| 1463 | + CX("<span>%h</span>", zLabel); | |
| 1464 | + } | |
| 1465 | + CX("<select name='%s'>",zFieldName); | |
| 1466 | + while(1){ | |
| 1467 | + const char * zLabel = va_arg(vargs,char *); | |
| 1468 | + const char * zVal; | |
| 1469 | + if(NULL==zLabel){ | |
| 1470 | + break; | |
| 1471 | + } | |
| 1472 | + zVal = va_arg(vargs,char *); | |
| 1473 | + CX("<option value='%T'%s>", | |
| 1474 | + zVal, 0==fossil_strcmp(zVal, zSelectedVal) ? " selected" : ""); | |
| 1475 | + if(*zLabel){ | |
| 1476 | + CX("%s", zLabel); | |
| 1477 | + }else{ | |
| 1478 | + CX("%h",zVal); | |
| 1479 | + } | |
| 1480 | + CX("</option>\n"); | |
| 1423 | 1481 | } |
| 1482 | + CX("</select>\n"); | |
| 1483 | + CX("</span>\n"); | |
| 1424 | 1484 | va_end(vargs); |
| 1425 | 1485 | } |
| 1486 | + | |
| 1426 | 1487 | |
| 1427 | 1488 | /* |
| 1428 | 1489 | ** The first time this is called, it emits code to install and |
| 1429 | 1490 | ** bootstrap the window.fossil object, using the built-in file |
| 1430 | 1491 | ** fossil.bootstrap.js (not to be confused with bootstrap.js). |
| 1431 | 1492 |
| --- src/style.c | |
| +++ src/style.c | |
| @@ -1416,15 +1416,76 @@ | |
| 1416 | CX("%d",v); |
| 1417 | } |
| 1418 | CX("</option>\n"); |
| 1419 | } |
| 1420 | CX("</select>\n"); |
| 1421 | if(zLabel && *zLabel){ |
| 1422 | CX("</span>\n"); |
| 1423 | } |
| 1424 | va_end(vargs); |
| 1425 | } |
| 1426 | |
| 1427 | /* |
| 1428 | ** The first time this is called, it emits code to install and |
| 1429 | ** bootstrap the window.fossil object, using the built-in file |
| 1430 | ** fossil.bootstrap.js (not to be confused with bootstrap.js). |
| 1431 |
| --- src/style.c | |
| +++ src/style.c | |
| @@ -1416,15 +1416,76 @@ | |
| 1416 | CX("%d",v); |
| 1417 | } |
| 1418 | CX("</option>\n"); |
| 1419 | } |
| 1420 | CX("</select>\n"); |
| 1421 | CX("</span>\n"); |
| 1422 | va_end(vargs); |
| 1423 | } |
| 1424 | |
| 1425 | /* |
| 1426 | ** The C-string counterpart of style_select_list_int(), this variant |
| 1427 | ** differs only in that its variadic arguments are C-strings in pairs |
| 1428 | ** of (optionLabel, optionValue). If a given optionLabel is an empty |
| 1429 | ** string, the corresponding optionValue is used as its label. If any |
| 1430 | ** given value matches zSelectedVal, that option gets preselected. If |
| 1431 | ** no options match zSelectedVal then the first entry is selected by |
| 1432 | ** default. |
| 1433 | ** |
| 1434 | ** Any of (zWrapperId, zTooltip, zSelectedVal) may be NULL or empty. |
| 1435 | ** |
| 1436 | ** Example: |
| 1437 | ** |
| 1438 | ** style_select_list_str("my-grapes", "my_grapes", "Grapes", |
| 1439 | ** "Select the number of grapes", |
| 1440 | ** P("my_field"), |
| 1441 | ** "1", "One", "2", "Two", "", "3", |
| 1442 | ** NULL); |
| 1443 | */ |
| 1444 | void style_select_list_str(const char * zWrapperId, |
| 1445 | const char *zFieldName, const char * zLabel, |
| 1446 | const char * zToolTip, char const * zSelectedVal, |
| 1447 | ... ){ |
| 1448 | va_list vargs; |
| 1449 | |
| 1450 | va_start(vargs,zSelectedVal); |
| 1451 | if(!zSelectedVal){ |
| 1452 | zSelectedVal = __FILE__/*some string we'll never match*/; |
| 1453 | } |
| 1454 | CX("<span class='input-with-label'"); |
| 1455 | if(zToolTip && *zToolTip){ |
| 1456 | CX(" title='%h'",zToolTip); |
| 1457 | } |
| 1458 | if(zWrapperId && *zWrapperId){ |
| 1459 | CX(" id='%s'",zWrapperId); |
| 1460 | } |
| 1461 | CX(">"); |
| 1462 | if(zLabel && *zLabel){ |
| 1463 | CX("<span>%h</span>", zLabel); |
| 1464 | } |
| 1465 | CX("<select name='%s'>",zFieldName); |
| 1466 | while(1){ |
| 1467 | const char * zLabel = va_arg(vargs,char *); |
| 1468 | const char * zVal; |
| 1469 | if(NULL==zLabel){ |
| 1470 | break; |
| 1471 | } |
| 1472 | zVal = va_arg(vargs,char *); |
| 1473 | CX("<option value='%T'%s>", |
| 1474 | zVal, 0==fossil_strcmp(zVal, zSelectedVal) ? " selected" : ""); |
| 1475 | if(*zLabel){ |
| 1476 | CX("%s", zLabel); |
| 1477 | }else{ |
| 1478 | CX("%h",zVal); |
| 1479 | } |
| 1480 | CX("</option>\n"); |
| 1481 | } |
| 1482 | CX("</select>\n"); |
| 1483 | CX("</span>\n"); |
| 1484 | va_end(vargs); |
| 1485 | } |
| 1486 | |
| 1487 | |
| 1488 | /* |
| 1489 | ** The first time this is called, it emits code to install and |
| 1490 | ** bootstrap the window.fossil object, using the built-in file |
| 1491 | ** fossil.bootstrap.js (not to be confused with bootstrap.js). |
| 1492 |