Fossil

Changes On Branch shift-enter-preview
Login

Changes On Branch shift-enter-preview

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

Changes In Branch shift-enter-preview Excluding Merge-Ins

This is equivalent to a diff from 70cae0a9 to 895ecf9e

2023-12-22
14:32
Add option to disable the shift-enter preview hotkey in /wikiedit, /fileedit, and /chat as a workaround for software keyboards which report the shift key being pressed when auto-capitalizing text, per discussion in forum post dbd5b68366147ce8. (check-in: 4bb5515c user: stephan tags: trunk)
14:27
Remove the write-perms check from the /ajax/preview-text route so that folks without checkin permissions can use /chat. Problem reported in forum post ed4a762b3a557898. Some code-adjacent end-of-line whitespace cleanups. (check-in: 0c6e669a user: stephan tags: trunk)
2023-12-16
01:39
Add the shift-enter toggle config option to /chat, sharing the same persistent config key as /wikiedit and /fileedit. (Closed-Leaf check-in: 895ecf9e user: stephan tags: shift-enter-preview)
01:10
In /wikiedit and /fileedit, add a checkbox to disable shift-enter for toggling preview, as per discussion in forum post dbd5b68366147ce8. (check-in: 8c1c4fa9 user: stephan tags: shift-enter-preview)
2023-12-14
17:24
Update the built-in SQLite to the latest trunk version that is destined to become 3.45.0 someday. This is beta-testing for SQLite. (check-in: 70cae0a9 user: drh tags: trunk)
16:29
Improve "whatis" output when in "filename" mode and parse supported whatis options when using "fossil all whatis". (check-in: e1e9da26 user: mgagnon tags: trunk)

Changes to src/fileedit.c.

1696
1697
1698
1699
1700
1701
1702
1703
1704
1705
1706
1707
1708
1709
1710

1711
1712
1713
1714
1715
1716
1717
1718
1719
1720
1721
1722
1723
1724
1725
1726
1727
1728

1729
1730
1731
1732
1733
1734
1735
       "data-tab-parent='fileedit-tabs' "
       "data-tab-label='File Selection' "
       "class='hidden'"
       ">");
    CX("<div id='fileedit-file-selector'></div>");
    CX("</div>"/*#fileedit-tab-fileselect*/);
  }
  
  /******* Content tab *******/
  {
    CX("<div id='fileedit-tab-content' "
       "data-tab-parent='fileedit-tabs' "
       "data-tab-label='File Content' "
       "class='hidden'"
       ">");

    CX("<div class='flex-container flex-row child-gap-small'>");
    CX("<div class='input-with-label'>"
       "<button class='fileedit-content-reload confirmer' "
       ">Discard &amp; Reload</button>"
       "<div class='help-buttonlet'>"
       "Reload the file from the server, discarding "
       "any local edits. To help avoid accidental loss of "
       "edits, it requires confirmation (a second click) within "
       "a few seconds or it will not reload."
       "</div>"
       "</div>");
    style_select_list_int("select-font-size",
                          "editor_font_size", "Editor font size",
                          NULL/*tooltip*/,
                          100,
                          "100%", 100, "125%", 125,
                          "150%", 150, "175%", 175,
                          "200%", 200, NULL);

    CX("</div>");
    CX("<div class='flex-container flex-column stretch'>");
    CX("<textarea name='content' id='fileedit-content-editor' "
       "class='fileedit' rows='25'>");
    CX("</textarea>");
    CX("</div>"/*textarea wrapper*/);
    CX("</div>"/*#tab-file-content*/);







|







>
|

















>







1696
1697
1698
1699
1700
1701
1702
1703
1704
1705
1706
1707
1708
1709
1710
1711
1712
1713
1714
1715
1716
1717
1718
1719
1720
1721
1722
1723
1724
1725
1726
1727
1728
1729
1730
1731
1732
1733
1734
1735
1736
1737
       "data-tab-parent='fileedit-tabs' "
       "data-tab-label='File Selection' "
       "class='hidden'"
       ">");
    CX("<div id='fileedit-file-selector'></div>");
    CX("</div>"/*#fileedit-tab-fileselect*/);
  }

  /******* Content tab *******/
  {
    CX("<div id='fileedit-tab-content' "
       "data-tab-parent='fileedit-tabs' "
       "data-tab-label='File Content' "
       "class='hidden'"
       ">");
    CX("<div class='fileedit-options flex-container "
       "flex-row child-gap-small'>");
    CX("<div class='input-with-label'>"
       "<button class='fileedit-content-reload confirmer' "
       ">Discard &amp; Reload</button>"
       "<div class='help-buttonlet'>"
       "Reload the file from the server, discarding "
       "any local edits. To help avoid accidental loss of "
       "edits, it requires confirmation (a second click) within "
       "a few seconds or it will not reload."
       "</div>"
       "</div>");
    style_select_list_int("select-font-size",
                          "editor_font_size", "Editor font size",
                          NULL/*tooltip*/,
                          100,
                          "100%", 100, "125%", 125,
                          "150%", 150, "175%", 175,
                          "200%", 200, NULL);
    wikiedit_emit_toggle_preview();
    CX("</div>");
    CX("<div class='flex-container flex-column stretch'>");
    CX("<textarea name='content' id='fileedit-content-editor' "
       "class='fileedit' rows='25'>");
    CX("</textarea>");
    CX("</div>"/*textarea wrapper*/);
    CX("</div>"/*#tab-file-content*/);

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

1
2
3
4
5
6
7
8
9
10
11

12
13
14
15
16
17
18
/**
   This file contains the client-side implementation of fossil's /chat
   application. 
*/
window.fossil.onPageLoad(function(){
  const F = window.fossil, D = F.dom;
  const E1 = function(selector){
    const e = document.querySelector(selector);
    if(!e) throw new Error("missing required DOM element: "+selector);
    return e;
  };

  /**
     Returns true if e is entirely within the bounds of the window's viewport.
  */
  const isEntirelyInViewport = function(e) {
    const rect = e.getBoundingClientRect();
    return (
      rect.top >= 0 &&


|








>







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
/**
   This file contains the client-side implementation of fossil's /chat
   application.
*/
window.fossil.onPageLoad(function(){
  const F = window.fossil, D = F.dom;
  const E1 = function(selector){
    const e = document.querySelector(selector);
    if(!e) throw new Error("missing required DOM element: "+selector);
    return e;
  };

  /**
     Returns true if e is entirely within the bounds of the window's viewport.
  */
  const isEntirelyInViewport = function(e) {
    const rect = e.getBoundingClientRect();
    return (
      rect.top >= 0 &&
394
395
396
397
398
399
400





401
402
403
404
405
406
407
             ctrl-enter both send them. */
          "edit-ctrl-send": false,
          /* When on, the edit field starts as a single line and
             expands as the user types, and the relevant buttons are
             laid out in a compact form. When off, the edit field and
             buttons are larger. */
          "edit-compact-mode": true,





          /* When on, sets the font-family on messages and the edit
             field to monospace. */
          "monospace-messages": false,
          /* When on, non-chat UI elements (page header/footer) are
             hidden */
          "chat-only-mode": false,
          /* When set to a URI, it is assumed to be an audio file,







>
>
>
>
>







395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
             ctrl-enter both send them. */
          "edit-ctrl-send": false,
          /* When on, the edit field starts as a single line and
             expands as the user types, and the relevant buttons are
             laid out in a compact form. When off, the edit field and
             buttons are larger. */
          "edit-compact-mode": true,
          /* See notes for this setting in fossil.page.wikiedit.js.
             Both /wikiedit and /fileedit share this persistent config
             option under the same storage key. */
          "edit-shift-enter-preview":
            F.storage.getBool('edit-shift-enter-preview', true),
          /* When on, sets the font-family on messages and the edit
             field to monospace. */
          "monospace-messages": false,
          /* When on, non-chat UI elements (page header/footer) are
             hidden */
          "chat-only-mode": false,
          /* When set to a URI, it is assumed to be an audio file,
1497
1498
1499
1500
1501
1502
1503
1504
1505
1506
1507
1508
1509
1510
1511
1512
1513
1514
1515
1516
1517
1518
1519
1520
1521
1522
1523
1524
1525
1526
1527
1528
1529
1530
1531
1532
1533
1534
1535
1536
1537
1538
1539
1540
1541
1542
1543
1544
1545
      /* Shift-enter will run preview mode UNLESS preview mode is
         active AND the input field is empty, in which case it will
         switch back to message view. */
      if(Chat.e.currentView===Chat.e.viewPreview && !text){
        Chat.setCurrentView(Chat.e.viewMessages);
      }else if(!text){
        f.$toggleCompact(compactMode);
      }else{
        Chat.e.btnPreview.click();
      }
      return false;
    }
    if(ev.ctrlKey && !text && !BlobXferState.blob){
      /* Ctrl-enter on empty input field(s) toggles Enter/Ctrl-enter mode */
      ev.preventDefault();
      ev.stopPropagation();
      f.$toggleCtrl(ctrlMode);
      return false;
    }
    if(!ctrlMode && ev.ctrlKey && text){
      //console.debug("!ctrlMode && ev.ctrlKey && text.");
      /* Ctrl-enter in Enter-sends mode SHOULD, with this logic add a
         newline, but that is not happening, for unknown reasons
         (possibly related to this element being a conteneditable DIV
         instead of a textarea). Forcibly appending a newline do the
         input area does not work, also for unknown reasons, and would
         only be suitable when we're at the end of the input.

         Strangely, this approach DOES work for shift-enter, but we
         need shift-enter as a hotkey for preview mode.
      */
      //return;
      // return here "should" cause newline to be added, but that doesn't work
    }
    if((!ctrlMode && !ev.ctrlKey) || (ev.ctrlKey/* && ctrlMode*/)){
      /* Ship it! */
      ev.preventDefault();
      ev.stopPropagation();
      Chat.submitMessage();
      return false;
    }
  };  
  Chat.e.inputFields.forEach(
    (e)=>e.addEventListener('keydown', inputWidgetKeydown, false)
  );
  Chat.e.btnSubmit.addEventListener('click',(e)=>{
    e.preventDefault();
    Chat.submitMessage();
    return false;







|















|

















|







1503
1504
1505
1506
1507
1508
1509
1510
1511
1512
1513
1514
1515
1516
1517
1518
1519
1520
1521
1522
1523
1524
1525
1526
1527
1528
1529
1530
1531
1532
1533
1534
1535
1536
1537
1538
1539
1540
1541
1542
1543
1544
1545
1546
1547
1548
1549
1550
1551
      /* Shift-enter will run preview mode UNLESS preview mode is
         active AND the input field is empty, in which case it will
         switch back to message view. */
      if(Chat.e.currentView===Chat.e.viewPreview && !text){
        Chat.setCurrentView(Chat.e.viewMessages);
      }else if(!text){
        f.$toggleCompact(compactMode);
      }else if(Chat.settings.getBool('edit-shift-enter-preview', true)){
        Chat.e.btnPreview.click();
      }
      return false;
    }
    if(ev.ctrlKey && !text && !BlobXferState.blob){
      /* Ctrl-enter on empty input field(s) toggles Enter/Ctrl-enter mode */
      ev.preventDefault();
      ev.stopPropagation();
      f.$toggleCtrl(ctrlMode);
      return false;
    }
    if(!ctrlMode && ev.ctrlKey && text){
      //console.debug("!ctrlMode && ev.ctrlKey && text.");
      /* Ctrl-enter in Enter-sends mode SHOULD, with this logic add a
         newline, but that is not happening, for unknown reasons
         (possibly related to this element being a contenteditable DIV
         instead of a textarea). Forcibly appending a newline do the
         input area does not work, also for unknown reasons, and would
         only be suitable when we're at the end of the input.

         Strangely, this approach DOES work for shift-enter, but we
         need shift-enter as a hotkey for preview mode.
      */
      //return;
      // return here "should" cause newline to be added, but that doesn't work
    }
    if((!ctrlMode && !ev.ctrlKey) || (ev.ctrlKey/* && ctrlMode*/)){
      /* Ship it! */
      ev.preventDefault();
      ev.stopPropagation();
      Chat.submitMessage();
      return false;
    }
  };
  Chat.e.inputFields.forEach(
    (e)=>e.addEventListener('keydown', inputWidgetKeydown, false)
  );
  Chat.e.btnSubmit.addEventListener('click',(e)=>{
    e.preventDefault();
    Chat.submitMessage();
    return false;
1665
1666
1667
1668
1669
1670
1671







1672
1673
1674
1675
1676
1677
1678
        boolValue: 'edit-widget-x',
        hint: [
          "When enabled, chat input uses a so-called 'contenteditable' ",
          "field. Though generally more comfortable and modern than ",
          "plain-text input fields, browser-specific quirks and bugs ",
          "may lead to frustration. Ideal for mobile devices."
        ].join('')







      }]
    },{
      label: "Appearance Options...",
      children:[{
        label: "Left-align my posts",
        hint: "Default alignment of your own messages is selected "
          + "based window width/height ratio.",







>
>
>
>
>
>
>







1671
1672
1673
1674
1675
1676
1677
1678
1679
1680
1681
1682
1683
1684
1685
1686
1687
1688
1689
1690
1691
        boolValue: 'edit-widget-x',
        hint: [
          "When enabled, chat input uses a so-called 'contenteditable' ",
          "field. Though generally more comfortable and modern than ",
          "plain-text input fields, browser-specific quirks and bugs ",
          "may lead to frustration. Ideal for mobile devices."
        ].join('')
      },{
        label: "Shift-enter to preview",
        hint: ["Use shift-enter to preview being-edited messages. ",
               "This is normally desirable but some software-mode ",
               "keyboards misinteract with this, in which cases it can be ",
               "disabled."],
        boolValue: 'edit-shift-enter-preview'
      }]
    },{
      label: "Appearance Options...",
      children:[{
        label: "Left-align my posts",
        hint: "Default alignment of your own messages is selected "
          + "based window width/height ratio.",

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

68
69
70
71
72
73
74
75






76
77
78
79
80
81
82
     );
  */
  const E = (s)=>document.querySelector(s),
        D = F.dom,
        P = F.page;

  P.config = {
    defaultMaxStashSize: 7






  };

  /**
     $stash is an internal-use-only object for managing "stashed"
     local edits, to help avoid that users accidentally lose content
     by switching tabs or following links or some such. The basic
     theory of operation is...







|
>
>
>
>
>
>







68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
     );
  */
  const E = (s)=>document.querySelector(s),
        D = F.dom,
        P = F.page;

  P.config = {
    defaultMaxStashSize: 7,
    /**
       See notes for this setting in fossil.page.wikiedit.js. Both
       /wikiedit and /fileedit share this persistent config option
       under the same storage key.
    */
    shiftEnterPreview: F.storage.getBool('edit-shift-enter-preview', true)
  };

  /**
     $stash is an internal-use-only object for managing "stashed"
     local edits, to help avoid that users accidentally lose content
     by switching tabs or following links or some such. The basic
     theory of operation is...
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
        }
      }
    );
    ////////////////////////////////////////////////////////////
    // Trigger preview on Ctrl-Enter. This only works on the built-in
    // editor widget, not a client-provided one.
    P.e.taEditor.addEventListener('keydown',function(ev){
      if(ev.shiftKey && 13 === ev.keyCode){
        ev.preventDefault();
        ev.stopPropagation();
        P.e.taEditor.blur(/*force change event, if needed*/);
        P.tabs.switchToTab(P.e.tabs.preview);
        if(!P.e.cbAutoPreview.checked){/* If NOT in auto-preview mode, trigger an update. */
          P.preview();
        }







|







728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
        }
      }
    );
    ////////////////////////////////////////////////////////////
    // Trigger preview on Ctrl-Enter. This only works on the built-in
    // editor widget, not a client-provided one.
    P.e.taEditor.addEventListener('keydown',function(ev){
      if(P.config.shiftEnterPreview && ev.shiftKey && 13===ev.keyCode){
        ev.preventDefault();
        ev.stopPropagation();
        P.e.taEditor.blur(/*force change event, if needed*/);
        P.tabs.switchToTab(P.e.tabs.preview);
        if(!P.e.cbAutoPreview.checked){/* If NOT in auto-preview mode, trigger an update. */
          P.preview();
        }
843
844
845
846
847
848
849







850
851
852
853
854
855
856
      }
    );

    P.fileSelectWidget.init();
    P.stashWidget.init(
      P.e.tabs.content.lastElementChild
    );







  }/*F.onPageLoad()*/);

  /**
     Getter (if called with no args) or setter (if passed an arg) for
     the current file content.

     The setter form sets the content, dispatches a







>
>
>
>
>
>
>







849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
      }
    );

    P.fileSelectWidget.init();
    P.stashWidget.init(
      P.e.tabs.content.lastElementChild
    );

    const cbEditPreview = E('#edit-shift-enter-preview');
    cbEditPreview.addEventListener('change', function(e){
      F.storage.set('edit-shift-enter-preview',
                    P.config.shiftEnterPreview = e.target.checked);
    }, false);
    cbEditPreview.checked = P.config.shiftEnterPreview;
  }/*F.onPageLoad()*/);

  /**
     Getter (if called with no args) or setter (if passed an arg) for
     the current file content.

     The setter form sets the content, dispatches a

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

73
74
75
76
77
78
79







80






81
82
83
84
85
86
87
    useConfirmerButtons:{
    /* If true during fossil.page setup, certain buttons will use a
       "confirmer" step, else they will not. The confirmer topic has
       been the source of much contention in the forum. */
      save: false,
      reload: true,
      discardStash: true







    }






  };

  /**
     $stash is an internal-use-only object for managing "stashed"
     local edits, to help avoid that users accidentally lose content
     by switching tabs or following links or some such. The basic
     theory of operation is...







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







73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
    useConfirmerButtons:{
    /* If true during fossil.page setup, certain buttons will use a
       "confirmer" step, else they will not. The confirmer topic has
       been the source of much contention in the forum. */
      save: false,
      reload: true,
      discardStash: true
    },
    /**
       If true, a keyboard combo of shift-enter (from the editor)
       toggles between preview and edit modes.  This is normally
       desired but at least one software keyboard is known to
       misinteract with this, treating an Enter after
       automatically-capitalized letters as a shift-enter:

       https://fossil-scm.org/forum/forumpost/dbd5b68366147ce8

       Maintenance note: /fileedit also uses this same key for the
       same purpose.
    */
    shiftEnterPreview: F.storage.getBool('edit-shift-enter-preview', true)
  };

  /**
     $stash is an internal-use-only object for managing "stashed"
     local edits, to help avoid that users accidentally lose content
     by switching tabs or following links or some such. The basic
     theory of operation is...
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
            opt.dataset.isDeleted = true;
          }
          self._refreshStashMarks(opt);
        });
      D.enable(sel);
      if(P.winfo) sel.value = P.winfo.name;
    },
    
    /** Loads the page list and populates the selection list. */
    loadList: function callee(){
      if(!callee.onload){
        const self = this;
        callee.onload = function(list){
          self.cache.pageList = list;
          self._rebuildList();







|







465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
            opt.dataset.isDeleted = true;
          }
          self._refreshStashMarks(opt);
        });
      D.enable(sel);
      if(P.winfo) sel.value = P.winfo.name;
    },

    /** Loads the page list and populates the selection list. */
    loadList: function callee(){
      if(!callee.onload){
        const self = this;
        callee.onload = function(list){
          self.cache.pageList = list;
          self._rebuildList();
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
      }, false);

      D.append(
        parentElem,
        D.append(D.addClass(D.div(), 'fieldset-wrapper'),
                 fsFilter, fsNewPage, fsLegend)
      );
      
      D.append(parentElem, btn);
      btn.addEventListener('click', ()=>this.loadList(), false);
      this.loadList();
      const onSelect = (e)=>P.loadPage(e.target.value);
      sel.addEventListener('change', onSelect, false);
      sel.addEventListener('dblclick', onSelect, false);
      F.page.addEventListener('wiki-stash-updated', ()=>{







|







662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
      }, false);

      D.append(
        parentElem,
        D.append(D.addClass(D.div(), 'fieldset-wrapper'),
                 fsFilter, fsNewPage, fsLegend)
      );

      D.append(parentElem, btn);
      btn.addEventListener('click', ()=>this.loadList(), false);
      this.loadList();
      const onSelect = (e)=>P.loadPage(e.target.value);
      sel.addEventListener('change', onSelect, false);
      sel.addEventListener('dblclick', onSelect, false);
      F.page.addEventListener('wiki-stash-updated', ()=>{
672
673
674
675
676
677
678







679
680
681
682
683
684
685
686
687
          if(page.isEmpty) opt.dataset.isDeleted = true;
          else delete opt.dataset.isDeleted;
          self._refreshStashMarks(opt);
        }else if('sandbox'!==page.type){
          F.error("BUG: internal mis-handling of page object: missing OPTION for page "+page.name);
        }
      });







      delete this.init;
    }
  };

  /**
     Widget for listing and selecting $stash entries.
  */
  P.stashWidget = {
    e:{/*DOM element(s)*/},







>
>
>
>
>
>
>

|







685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
          if(page.isEmpty) opt.dataset.isDeleted = true;
          else delete opt.dataset.isDeleted;
          self._refreshStashMarks(opt);
        }else if('sandbox'!==page.type){
          F.error("BUG: internal mis-handling of page object: missing OPTION for page "+page.name);
        }
      });

      const cbEditPreview = E('#edit-shift-enter-preview');
      cbEditPreview.addEventListener('change', function(e){
        F.storage.set('edit-shift-enter-preview',
                      P.config.shiftEnterPreview = e.target.checked);
      }, false);
      cbEditPreview.checked = P.config.shiftEnterPreview;
      delete this.init;
    }/*init()*/
  };

  /**
     Widget for listing and selecting $stash entries.
  */
  P.stashWidget = {
    e:{/*DOM element(s)*/},
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
        }
      }
    );
    ////////////////////////////////////////////////////////////
    // Trigger preview on Ctrl-Enter. This only works on the built-in
    // editor widget, not a client-provided one.
    P.e.taEditor.addEventListener('keydown',function(ev){
      if(ev.shiftKey && 13 === ev.keyCode){
        ev.preventDefault();
        ev.stopPropagation();
        P.e.taEditor.blur(/*force change event, if needed*/);
        P.tabs.switchToTab(P.e.tabs.preview);
        if(!P.e.cbAutoPreview.checked){/* If NOT in auto-preview mode, trigger an update. */
          P.preview();
        }







|







932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
        }
      }
    );
    ////////////////////////////////////////////////////////////
    // Trigger preview on Ctrl-Enter. This only works on the built-in
    // editor widget, not a client-provided one.
    P.e.taEditor.addEventListener('keydown',function(ev){
      if(P.config.shiftEnterPreview && ev.shiftKey && 13===ev.keyCode){
        ev.preventDefault();
        ev.stopPropagation();
        P.e.taEditor.blur(/*force change event, if needed*/);
        P.tabs.switchToTab(P.e.tabs.preview);
        if(!P.e.cbAutoPreview.checked){/* If NOT in auto-preview mode, trigger an update. */
          P.preview();
        }

Changes to src/style.fileedit.css.

74
75
76
77
78
79
80



81
82
83
84
85
86
87
  overflow: auto;
}
body.fileedit #fileedit-tab-preview-wrapper > pre {
  margin: 0;
}
body.fileedit #fileedit-tab-fileselect > h1 {
  margin: 0;



}
body.fileedit .fileedit-options.commit-message > div {
  display: flex;
  flex-direction: column;
  align-items: stretch;
  font-family: monospace;
}







>
>
>







74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
  overflow: auto;
}
body.fileedit #fileedit-tab-preview-wrapper > pre {
  margin: 0;
}
body.fileedit #fileedit-tab-fileselect > h1 {
  margin: 0;
}
body.fileedit .fileedit-options > div > * {
  margin: 0.25em;
}
body.fileedit .fileedit-options.commit-message > div {
  display: flex;
  flex-direction: column;
  align-items: stretch;
  font-family: monospace;
}
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
  margin: 0.5em;
}
body.fileedit .tab-container > .tabs > .tab-panel > .fileedit-options > input {
  vertical-align: middle;
  margin: 0.5em;
}
body.fileedit .tab-container > .tabs > .tab-panel > .fileedit-options > .input-with-label {
  vertical-align: middle;
  margin: 0.5em;
}
body.fileedit .fileedit-options > div > * {
  margin: 0.25em;
}
body.fileedit .fileedit-options.flex-container.flex-row {
  align-items: first baseline;
}







<
|







106
107
108
109
110
111
112

113
114
115
116
117
118
119
120
  margin: 0.5em;
}
body.fileedit .tab-container > .tabs > .tab-panel > .fileedit-options > input {
  vertical-align: middle;
  margin: 0.5em;
}
body.fileedit .tab-container > .tabs > .tab-panel > .fileedit-options > .input-with-label {

  margin: 0 0.5em 0.25em 0.5em;
}
body.fileedit .fileedit-options > div > * {
  margin: 0.25em;
}
body.fileedit .fileedit-options.flex-container.flex-row {
  align-items: first baseline;
}

Changes to src/style.wikiedit.css.

41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
  margin: 0.5em;
}
body.wikiedit .tab-container > .tabs > .tab-panel > .wikiedit-options > input {
  vertical-align: middle;
  margin: 0.5em;
}
body.wikiedit .tab-container > .tabs > .tab-panel > .wikiedit-options > .input-with-label {
  vertical-align: middle;
  margin: 0 0.5em 0.25em 0.5em;
}
body.wikiedit label {
  display: inline; /* some skins set label display to block! */
}
body.wikiedit .wikiedit-options > div > * {
  margin: 0.25em;







<







41
42
43
44
45
46
47

48
49
50
51
52
53
54
  margin: 0.5em;
}
body.wikiedit .tab-container > .tabs > .tab-panel > .wikiedit-options > input {
  vertical-align: middle;
  margin: 0.5em;
}
body.wikiedit .tab-container > .tabs > .tab-panel > .wikiedit-options > .input-with-label {

  margin: 0 0.5em 0.25em 0.5em;
}
body.wikiedit label {
  display: inline; /* some skins set label display to block! */
}
body.wikiedit .wikiedit-options > div > * {
  margin: 0.25em;

Changes to src/wiki.c.

1245
1246
1247
1248
1249
1250
1251
















1252
1253
1254
1255
1256
1257
1258
                     "CSRF violation (make sure sending of HTTP "
                     "Referer headers is enabled for XHR "
                     "connections).");
    return;
  }
  pRoute->xCallback();
}

















/*
** WEBPAGE: wikiedit
** URL: /wikedit?name=PAGENAME
**
** The main front-end for the Ajax-based wiki editor app. Passing
** in the name of an unknown page will trigger the creation







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







1245
1246
1247
1248
1249
1250
1251
1252
1253
1254
1255
1256
1257
1258
1259
1260
1261
1262
1263
1264
1265
1266
1267
1268
1269
1270
1271
1272
1273
1274
                     "CSRF violation (make sure sending of HTTP "
                     "Referer headers is enabled for XHR "
                     "connections).");
    return;
  }
  pRoute->xCallback();
}

/*
** Emits a preview-toggle option widget for /wikiedit and /fileedit.
*/
void wikiedit_emit_toggle_preview(void){
  CX("<div class='input-with-label'>"
     "<input type='checkbox' id='edit-shift-enter-preview' "
     "></input><label for='edit-shift-enter-preview'>"
     "Shift-enter previews</label>"
     "<div class='help-buttonlet'>"
     "When enabled, shift-enter switches between preview and edit modes. "
     "Some software-based keyboards misinteract with this, so it can be "
     "disabled when needed."
     "</div>"
     "</div>");
}

/*
** WEBPAGE: wikiedit
** URL: /wikedit?name=PAGENAME
**
** The main front-end for the Ajax-based wiki editor app. Passing
** in the name of an unknown page will trigger the creation
1309
1310
1311
1312
1313
1314
1315
1316
1317
1318
1319
1320
1321
1322
1323
     "Status messages will go here.</div>\n"
     /* will be moved into the tab container via JS */);

  CX("<div id='wikiedit-edit-status''>"
     "<span class='name'></span>"
     "<span class='links'></span>"
     "</div>");
  
  /* Main tab container... */
  CX("<div id='wikiedit-tabs' class='tab-container'>Loading...</div>");
  /* The .hidden class on the following tab elements is to help lessen
     the FOUC effect of the tabs before JS re-assembles them. */

  /******* Page list *******/
  {







|







1325
1326
1327
1328
1329
1330
1331
1332
1333
1334
1335
1336
1337
1338
1339
     "Status messages will go here.</div>\n"
     /* will be moved into the tab container via JS */);

  CX("<div id='wikiedit-edit-status''>"
     "<span class='name'></span>"
     "<span class='links'></span>"
     "</div>");

  /* Main tab container... */
  CX("<div id='wikiedit-tabs' class='tab-container'>Loading...</div>");
  /* The .hidden class on the following tab elements is to help lessen
     the FOUC effect of the tabs before JS re-assembles them. */

  /******* Page list *******/
  {
1369
1370
1371
1372
1373
1374
1375
1376
1377
1378
1379
1380
1381
1382
1383
       "<div class='help-buttonlet'>"
       "Reload the file from the server, discarding "
       "any local edits. To help avoid accidental loss of "
       "edits, it requires confirmation (a second click) within "
       "a few seconds or it will not reload."
       "</div>"
       "</div>");

    CX("</div>");
    CX("<div class='flex-container flex-column stretch'>");
    CX("<textarea name='content' id='wikiedit-content-editor' "
       "class='wikiedit' rows='25'>");
    CX("</textarea>");
    CX("</div>"/*textarea wrapper*/);
    CX("</div>"/*#tab-file-content*/);







|







1385
1386
1387
1388
1389
1390
1391
1392
1393
1394
1395
1396
1397
1398
1399
       "<div class='help-buttonlet'>"
       "Reload the file from the server, discarding "
       "any local edits. To help avoid accidental loss of "
       "edits, it requires confirmation (a second click) within "
       "a few seconds or it will not reload."
       "</div>"
       "</div>");
    wikiedit_emit_toggle_preview();
    CX("</div>");
    CX("<div class='flex-container flex-column stretch'>");
    CX("<textarea name='content' id='wikiedit-content-editor' "
       "class='wikiedit' rows='25'>");
    CX("</textarea>");
    CX("</div>"/*textarea wrapper*/);
    CX("</div>"/*#tab-file-content*/);