Fossil

Check-in [4d5004ef]
Login

Check-in [4d5004ef]

Many hyperlinks are disabled.
Use anonymous login to enable hyperlinks.

Overview
Comment: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.
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | fileedit-ajaxify
Files: files | file ages | folders
SHA3-256: 4d5004ef2d8cdf02bd106910d18f76eeb7b8b979bfd9d3f88fbb73c13e275449
User & Date: stephan 2020-05-09 12:36:51
Context
2020-05-09
12:54
Determine which comment editing mode to enable based on which of the editor fields is hidden by default, so that we stay in sync if the C side changes. ... (check-in: a4314603 user: stephan tags: fileedit-ajaxify)
12:36
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. ... (check-in: 4d5004ef user: stephan tags: fileedit-ajaxify)
2020-05-08
14:15
Swapped the style_emit_script_builtin() parameters for consistency with style_emit_script_tag(). ... (check-in: 02240eec user: stephan tags: fileedit-ajaxify)
Changes
Hide Diffs Unified Diffs Ignore Whitespace Patch

Changes to src/default_css.txt.

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
  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;
}
////////////////////////////////////////////////////////////////////
// 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;



}
.flex-container.row.stretch {
  flex-direction: row;
  flex-wrap: wrap;
  align-items: stretch;
  margin: 0;
}







|




















>
>
>







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
  padding: 0;
}
#fileedit-comment {
  width: 100%;
  font-family: monospace;
}
.tab-container > .tabs > .tab-panel > .fileedit-options {
  margin-top: 0.25em 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;
}
////////////////////////////////////////////////////////////////////
// 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;
}
.flex-container.row.stretch {
  flex-direction: row;
  flex-wrap: wrap;
  align-items: stretch;
  margin: 0;
}

Changes to src/fileedit.c.

1786
1787
1788
1789
1790
1791
1792
1793




1794
1795
1796
1797


1798




1799


1800

1801
1802





1803
1804

1805

1806
1807
1808
1809
1810
1811
1812
                          "Windows", 2,
                          NULL);
    CX("</div>"/*checkboxes*/);
  }

  { /******* Commit comment, button, and result manifest *******/
    CX("<fieldset class='fileedit-options'>"
       "<legend>Message (required)</legend><div>");




    CX("<input type='text' name='comment' "
       "id='fileedit-comment'>");
    /* ^^^ adding the 'required' attribute means we cannot even
       submit for PREVIEW mode if it's empty :/. */


    if(blob_size(&cimi.comment)){




      blob_appendf(&endScript,


                   "document.querySelector('#fileedit-comment').value="

                   "\"%h\";\n", blob_str(&cimi.comment));
    }





    CX("</input>\n");
    CX("<div class='fileedit-hint'>Comments use the Fossil wiki markup "

       "syntax.</div>\n"/*TODO: select for fossil/md/plain text*/);

    CX("</div></fieldset>\n"/*commit comment*/);
    CX("<div class='flex-container row'>"
       "<button id='fileedit-btn-commit'>Commit</button>"
       "</div>\n");
    CX("<div id='fileedit-manifest'></div>\n");
  }








|
>
>
>
>

|
<
<
>
>
|
>
>
>
>
|
>
>
|
>
|
<
>
>
>
>
>
|
|
>
|
>







1786
1787
1788
1789
1790
1791
1792
1793
1794
1795
1796
1797
1798
1799


1800
1801
1802
1803
1804
1805
1806
1807
1808
1809
1810
1811
1812

1813
1814
1815
1816
1817
1818
1819
1820
1821
1822
1823
1824
1825
1826
1827
1828
1829
                          "Windows", 2,
                          NULL);
    CX("</div>"/*checkboxes*/);
  }

  { /******* Commit comment, button, and result manifest *******/
    CX("<fieldset class='fileedit-options'>"
       "<legend>Message (required) "
       "</legend><div>");
    /* We have two comment input fields, defaulting to single-line
    ** 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>\n");


   CX("<textarea name='commentBig' class='hidden' "
       "rows='5' id='fileedit-comment-big'></textarea>");
    { /* comment options... */
      CX("<div class='fileedit-options flex-container row'>");
      CX("<button id='comment-toggle' "
         "title='Toggle between single- and multi-line comment mode, "
         "noting that switching from multi- to single-line may cause "
         "newlines to get stripped.'"
         ">toggle single-/multi-line</button> ");
      style_select_list_str("comment-mimetype", "comment_mimetype",
                            "Comment style:",
                            "Specify how fossil will interpret the "
                            "comment string.",

                            NULL,
                            "Fossil", "text/x-fossil-wiki",
                            "Markdown", "text/x-markdown", 
                            "Plain text", "text/plain",
                            NULL);
      CX("</div>\n");
      CX("<div class='fileedit-hint flex-container row'>"
         "(Warning: switching from multi- to single-line mode will "
         "strip out all newlines!)</div>");
    }
    CX("</div></fieldset>\n"/*commit comment*/);
    CX("<div class='flex-container row'>"
       "<button id='fileedit-btn-commit'>Commit</button>"
       "</div>\n");
    CX("<div id='fileedit-manifest'></div>\n");
  }

Changes to src/fossil.page.fileedit.js.

1
2
3
4
5
6
7
8
9
10
11
12
13
14

15
16
17
18
19
20
21
22
23
24
25
26
27
28
29

30
31
32
33
34
35
36
(function(F/*the fossil object*/){
  "use strict";
  /**
     Code for the /filepage app. Requires that the fossil JS
     bootstrapping is complete and fossil.fetch() has been installed.
  */
  const E = (s)=>document.querySelector(s),
        D = F.dom,
        P = F.page;
  window.addEventListener("load", function() {
    P.tabs = new fossil.TabManager('#fileedit-tabs');
    P.e = {
      taEditor: E('#fileedit-content-editor'),
      taComment: E('#fileedit-comment'),

      ajaxContentTarget: E('#ajax-target'),
      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')
      }
    };


    P.tabs.e.container.insertBefore(
      E('#fossil-status-bar'), P.tabs.e.tabs
    );

    const stopEvent = function(e){
      //e.preventDefault();













|
>















>







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
(function(F/*the fossil object*/){
  "use strict";
  /**
     Code for the /filepage app. Requires that the fossil JS
     bootstrapping is complete and fossil.fetch() has been installed.
  */
  const E = (s)=>document.querySelector(s),
        D = F.dom,
        P = F.page;
  window.addEventListener("load", function() {
    P.tabs = new fossil.TabManager('#fileedit-tabs');
    P.e = {
      taEditor: E('#fileedit-content-editor'),
      taCommentSmall: E('#fileedit-comment'),
      taCommentBig: E('#fileedit-comment-big'),
      ajaxContentTarget: E('#ajax-target'),
      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')
      }
    };
    P.e.taComment = P.e.taCommentSmall;

    P.tabs.e.container.insertBefore(
      E('#fossil-status-bar'), P.tabs.e.tabs
    );

    const stopEvent = function(e){
      //e.preventDefault();
56
57
58
59
60
61
62




63
64
65
66
67
68
69
      "click",(e)=>P.commit(), false
    );
    F.confirmer(P.e.btnReload, {
      confirmText: "Really reload, losing edits?",
      onconfirm: (e)=>P.loadFile(),
      ticks: 3
    });




    /**
       Cosmetic: jump through some hoops to enable/disable
       certain preview options depending on the current
       preview mode...
    */
    const selectPreviewMode =
          P.e.selectPreviewModeWrap.querySelector('select');







>
>
>
>







58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
      "click",(e)=>P.commit(), false
    );
    F.confirmer(P.e.btnReload, {
      confirmText: "Really reload, losing edits?",
      onconfirm: (e)=>P.loadFile(),
      ticks: 3
    });
    E('#comment-toggle').addEventListener(
      "click",(e)=>P.toggleCommentMode(), false
    );

    /**
       Cosmetic: jump through some hoops to enable/disable
       certain preview options depending on the current
       preview mode...
    */
    const selectPreviewMode =
          P.e.selectPreviewModeWrap.querySelector('select');
101
102
103
104
105
106
107































108
109
110
111
112
113
114
      );
      selectFontSize.dispatchEvent(
        // Force UI update
        new Event('change',{target:selectFontSize})
      );
    }
  }, false)/*onload event handler*/;































  
  /**
     updateVersion() updates the filename and version in various UI
     elements...

     Returns this object.
  */







>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>







107
108
109
110
111
112
113
114
115
116
117
118
119
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
151
      );
      selectFontSize.dispatchEvent(
        // Force UI update
        new Event('change',{target:selectFontSize})
      );
    }
  }, false)/*onload event handler*/;

  /**
     Toggles between single- and multi-line comment
     mode.
  */
  P.toggleCommentMode = function(){
    var s, h, c = this.e.taComment.value;
    if(this.e.taComment === this.e.taCommentSmall){
      s = this.e.taCommentBig;
      h = this.e.taCommentSmall;
    }else{
      s = this.e.taCommentSmall;
      h = this.e.taCommentBig;
      /*
        Doing (input[type=text].value = textarea.value) unfortunately
        strips all newlines. To compensate we'll replace each EOL with
        a space. Not ideal. If we were to instead escape them as \n,
        and do the reverse when toggling again, then they would get
        committed as escaped newlines if the user did not first switch
        back to multi-line mode. We cannot blindly unescape the
        newlines, in the off chance that the user actually enters \n
        in the comment.
      */
      c = c.replace(/\r?\n/g,' ');
    }
    s.value = c;
    this.e.taComment = s;
    D.addClass(h, 'hidden');
    D.removeClass(s, 'hidden');
    console.debug(s,h);
  };
  
  /**
     updateVersion() updates the filename and version in various UI
     elements...

     Returns this object.
  */

Changes to src/style.c.

1414
1415
1416
1417
1418
1419
1420









































1421

















1422
1423


1424
1425

1426
1427
1428
1429
1430
1431
1432
      CX("%s", zOption);
    }else{
      CX("%d",v);
    }
    CX("</option>\n");
  }
  CX("</select>\n");









































  if(zLabel && *zLabel){

















    CX("</span>\n");
  }


  va_end(vargs);
}


/*
** The first time this is called, it emits code to install and
** bootstrap the window.fossil object, using the built-in file
** fossil.bootstrap.js (not to be confused with bootstrap.js).
**
** Subsequent calls are no-ops.







>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>

>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
|

>
>


>







1414
1415
1416
1417
1418
1419
1420
1421
1422
1423
1424
1425
1426
1427
1428
1429
1430
1431
1432
1433
1434
1435
1436
1437
1438
1439
1440
1441
1442
1443
1444
1445
1446
1447
1448
1449
1450
1451
1452
1453
1454
1455
1456
1457
1458
1459
1460
1461
1462
1463
1464
1465
1466
1467
1468
1469
1470
1471
1472
1473
1474
1475
1476
1477
1478
1479
1480
1481
1482
1483
1484
1485
1486
1487
1488
1489
1490
1491
1492
1493
      CX("%s", zOption);
    }else{
      CX("%d",v);
    }
    CX("</option>\n");
  }
  CX("</select>\n");
  CX("</span>\n");
  va_end(vargs);
}

/*
** The C-string counterpart of style_select_list_int(), this variant
** differs only in that its variadic arguments are C-strings in pairs
** of (optionLabel, optionValue). If a given optionLabel is an empty
** string, the corresponding optionValue is used as its label. If any
** given value matches zSelectedVal, that option gets preselected. If
** no options match zSelectedVal then the first entry is selected by
** default.
**
** Any of (zWrapperId, zTooltip, zSelectedVal) may be NULL or empty.
**
** Example:
**
** style_select_list_str("my-grapes", "my_grapes", "Grapes",
**                      "Select the number of grapes",
**                       P("my_field"),
**                       "1", "One", "2", "Two", "", "3",
**                       NULL);
*/
void style_select_list_str(const char * zWrapperId,
                           const char *zFieldName, const char * zLabel,
                           const char * zToolTip, char const * zSelectedVal,
                           ... ){
  va_list vargs;

  va_start(vargs,zSelectedVal);
  if(!zSelectedVal){
    zSelectedVal = __FILE__/*some string we'll never match*/;
  }
  CX("<span class='input-with-label'");
  if(zToolTip && *zToolTip){
    CX(" title='%h'",zToolTip);
  }
  if(zWrapperId && *zWrapperId){
    CX(" id='%s'",zWrapperId);
  }
  CX(">");
  if(zLabel && *zLabel){
    CX("<span>%h</span>", zLabel);
  }
  CX("<select name='%s'>",zFieldName);
  while(1){
    const char * zLabel = va_arg(vargs,char *);
    const char * zVal;
    if(NULL==zLabel){
      break;
    }
    zVal = va_arg(vargs,char *);
    CX("<option value='%T'%s>",
       zVal, 0==fossil_strcmp(zVal, zSelectedVal) ? " selected" : "");
    if(*zLabel){
      CX("%s", zLabel);
    }else{
      CX("%h",zVal);
    }
    CX("</option>\n");
  }
  CX("</select>\n");
  CX("</span>\n");
  va_end(vargs);
}


/*
** The first time this is called, it emits code to install and
** bootstrap the window.fossil object, using the built-in file
** fossil.bootstrap.js (not to be confused with bootstrap.js).
**
** Subsequent calls are no-ops.