Fossil

Diff
Login

Diff

Differences From Artifact [c8ff6ab276]:

To Artifact [28a28b20d1]:


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
39
40
41
42
43
44

45


46
47
48
49
50
51
52
(function(F/*the fossil object*/){
  "use strict";
  /**
     Client-side implementation of the /pikchrshow app. Requires that
     the fossil JS bootstrapping is complete and that these fossil
     JS APIs have been installed: fossil.fetch, fossil.dom

  */
  const E = (s)=>document.querySelector(s),
        D = F.dom,
        P = F.page;








  F.onPageLoad(function() {
    document.body.classList.add('pikchrshow');
    P.e = { /* various DOM elements we work with... */
      previewTarget: E('#pikchrshow-output'),


      btnSubmit: E('#pikchr-submit-preview'),
      cbDarkMode: E('#flipcolors-wrapper > input[type=checkbox]'),
      taContent: E('#content')





    };
















    P.e.cbDarkMode.addEventListener('change', function(ev){
      if(ev.target.checked) D.addClass(P.e.previewTarget, 'dark-mode');
      else D.removeClass(P.e.previewTarget, 'dark-mode');
    }, false);
    if(P.e.cbDarkMode.checked) D.addClass(P.e.previewTarget, 'dark-mode');


    P.e.btnSubmit.addEventListener('click', function(){


      P.preview();

    }, false);














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























































  P.preview = function fp(){
    if(!fp.hasOwnProperty('toDisable')){
      fp.toDisable = [
        P.e.btnSubmit, P.e.taContent

      ];
      fp.target = P.e.previewTarget;
      fp.updateView = function(c,isError){



        D.enable(fp.toDisable);
        fp.target.innerHTML = c || '';
        if(isError) D.addClass(fp.target, 'error');
        else D.removeClass(fp.target, 'error');
      };
    }
    D.disable(fp.toDisable);

    const content = this.e.taContent.value;


    if(!content){
      fp.updateView("No pikchr content!",true);
      return this;
    }
    const self = this;
    const fd = new FormData();
    fd.append('ajax', true);




|
|
>




>
>
>
>
>
>
>
>




>
>


|
>
>
>
>
>

>

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






>
|
>
>
|
>

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


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


|
|
>

|

>
>
>

<
<
|



>
|
>
>







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
39
40
41
42
43
44
45
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
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
101
102
103
104
105
106
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
152
153
154
155
156
157
158
159
160
(function(F/*the fossil object*/){
  "use strict";
  /**
     Client-side implementation of the /pikchrshow app. Requires that
     the fossil JS bootstrapping is complete and that these fossil JS
     APIs have been installed: fossil.fetch, fossil.dom,
     fossil.copybutton
  */
  const E = (s)=>document.querySelector(s),
        D = F.dom,
        P = F.page;

  P.previewMode = 0 /*0==rendered SVG, 1==pikchr text markdown,
                      2==pikchr text fossil, 3==raw SVG. */
  P.response = {/*stashed state for the server's preview response*/
    isError: false,
    inputText: undefined /* value of the editor field at render-time */,
    raw: undefined /* raw response text/HTML from server */
  };
  F.onPageLoad(function() {
    document.body.classList.add('pikchrshow');
    P.e = { /* various DOM elements we work with... */
      previewTarget: E('#pikchrshow-output'),
      previewModeLabel: E('#pikchrshow-output-wrapper > legend'),
      btnCopy: E('#pikchrshow-output-wrapper > legend > .copy-button'),
      btnSubmit: E('#pikchr-submit-preview'),
      cbDarkMode: E('#flipcolors-wrapper > input[type=checkbox]'),
      taContent: E('#content'),
      taPreviewText: D.attr(D.textarea(), 'rows', 20, 'cols', 60,
                            'readonly', true),
      divControls: E('#pikchrshow-controls'),
      btnTogglePreviewMode: D.button("Preview mode"),
      selectMarkupAlignment: D.select()
    };
    D.append(P.e.divControls, P.e.btnTogglePreviewMode);

    // Setup markup alignment selection...
    D.append(P.e.divControls, P.e.selectMarkupAlignment);
    D.disable(D.option(P.e.selectMarkupAlignment, '', 'Markup Alignment'));
    ['left', 'center'].forEach(function(val,ndx){
      D.option(P.e.selectMarkupAlignment, ndx ? val : '', val);
    });

    // Setup clipboard-copy of markup/SVG...
    F.copyButton(P.e.btnCopy, {copyFromElement: P.e.taPreviewText});
    P.e.btnCopy.addEventListener('text-copied',function(ev){
       D.flashOnce(ev.target);
    },false);

    // Set up dark mode simulator...
    P.e.cbDarkMode.addEventListener('change', function(ev){
      if(ev.target.checked) D.addClass(P.e.previewTarget, 'dark-mode');
      else D.removeClass(P.e.previewTarget, 'dark-mode');
    }, false);
    if(P.e.cbDarkMode.checked) D.addClass(P.e.previewTarget, 'dark-mode');

    // Set up preview update and preview mode toggle...
    P.e.btnSubmit.addEventListener('click', ()=>P.preview(), false);
    P.e.btnTogglePreviewMode.addEventListener('click', function(){
      /* Rotate through the 4 available preview modes */
      P.previewMode = ++P.previewMode % 4;
      P.renderPreview();
    }, false);
    P.e.selectMarkupAlignment.addEventListener('change', function(ev){
      /* Update markdown/fossil wiki preview if it's active */
      if(P.previewMode==1 || P.previewMode==2){
        P.renderPreview();
      }
    }, false);

    if(P.e.taContent.value/*was pre-filled server-side*/){
      /* Fill our "response" state so that renderPreview() can work */
      P.response.inputText = P.e.taContent.value;
      P.response.raw = P.e.previewTarget.innerHTML;
      P.renderPreview()/*not strictly necessary, but gets all
                         labels/headers in alignment.*/;
    }    
  }/*F.onPageLoad()*/);

  /**
     Updates the preview view based on the current preview mode and
     error state.
  */
  P.renderPreview = function f(){
    if(!f.hasOwnProperty('rxNonce')){
      f.rxNonce = /<!--.+-->\r?\n?/g /*nonce comments*/;
    }
    const preTgt = this.e.previewTarget;
    if(this.response.isError){
      preTgt.innerHTML = this.response.raw;
      D.addClass(preTgt, 'error');
      this.e.previewModeLabel.innerText = "Error";
      return;
    }
    D.removeClass(preTgt, 'error');
    D.removeClass(this.e.btnTogglePreviewMode, 'hidden');
    let label;
    switch(this.previewMode){
    case 0:
      label = "Rendered SVG";
      preTgt.innerHTML = this.response.raw;
      this.e.taPreviewText.value = this.response.raw.replace(f.rxNonce, '')/*for copy button*/;
      break;
    case 1:
      label = "Markdown";
      this.e.taPreviewText.value = [
        '```pikchr'+(this.e.selectMarkupAlignment.value
                     ? ' '+this.e.selectMarkupAlignment.value : ''),
        this.response.inputText, '```'
      ].join('\n');
      D.append(D.clearElement(preTgt), this.e.taPreviewText);
      break;
    case 2:
      label = "Fossil wiki";
      this.e.taPreviewText.value = [
        '<verbatim type="pikchr',
        this.e.selectMarkupAlignment.value ? ' '+this.e.selectMarkupAlignment.value : '',
        '">', this.response.inputText, '</verbatim>'
      ].join('');
      D.append(D.clearElement(preTgt), this.e.taPreviewText);
      break;
    case 3:
      label = "Raw SVG";
      this.e.taPreviewText.value = this.response.raw.replace(f.rxNonce, '');
      D.append(D.clearElement(preTgt), this.e.taPreviewText);
      break;
    }
    D.append(D.clearElement(this.e.previewModeLabel),
             label, this.e.btnCopy);
  };

  /** Fetches the preview from the server and updates the preview to
      the rendered SVG content or error report. */
  P.preview = function fp(){
    if(!fp.hasOwnProperty('toDisable')){
      fp.toDisable = [ /* elements to disable during ajax operations */
        this.e.btnSubmit, this.e.taContent,
        this.e.btnTogglePreviewMode, this.e.selectMarkupAlignment,
      ];
      fp.target = this.e.previewTarget;
      fp.updateView = function(c,isError){
        P.previewMode = 0;
        P.response.raw = c;
        P.response.isError = isError;
        D.enable(fp.toDisable);


        P.renderPreview();
      };
    }
    D.disable(fp.toDisable);
    D.addClass(this.e.btnTogglePreviewMode, 'hidden');
    const content = this.e.taContent.value.trim();
    this.response.raw = undefined;
    this.response.inputText = content;
    if(!content){
      fp.updateView("No pikchr content!",true);
      return this;
    }
    const self = this;
    const fd = new FormData();
    fd.append('ajax', true);