1
+
2
+ import MarkdownIt from 'markdown-it'
3
+ import Renderer from 'markdown-it/lib/renderer'
4
+ import Token from 'markdown-it/lib/token'
5
+ import _ from 'underscore'
6
+ import htmlTemplate from './template.html'
7
+
8
+ let stateObj : any = { }
9
+ let templatesObj : any = { }
10
+ let allVariables : any = [ ]
11
+ let codeBlocks : any = [ ]
12
+
13
+ const generateInputHTML = ( data : any ) => {
14
+ let htmlInput = ``
15
+
16
+ if ( data . type !== 'button' ) {
17
+ stateObj [ data . variableName ] = data . defaultValue
18
+ allVariables . push ( data . variableName )
19
+ }
20
+
21
+ const onChangeText = `updateState(this); ${ data . onChange + ';' } `
22
+
23
+ if ( data . type === 'text' ) {
24
+ htmlInput = `<input id="rd-${ data . variableName } " class="rd-text-input rd-input" type="text" oninput="${ onChangeText } " value="${ data . defaultValue } " />`
25
+ } else if ( data . type === 'multiline-text' ) {
26
+ htmlInput = `<textarea id="rd-${ data . variableName } " class="rd-ml-text-input rd-input" type="text" oninput="${ onChangeText } ">${ data . defaultValue } </textarea>`
27
+ } else if ( data . type === 'number' ) {
28
+ htmlInput = `<input id="rd-${ data . variableName } " class="rd-text-input rd-input" type="number" oninput="${ onChangeText } " value="${ data . defaultValue } " />`
29
+ } else if ( data . type === 'password' ) {
30
+ htmlInput = `<input id="rd-${ data . variableName } " class="rd-text-input rd-input" type="password" oninput="${ onChangeText } " />`
31
+ } else if ( data . type === 'list' ) {
32
+ htmlInput = `<select id="rd-${ data . variableName } " class="rd-text-input rd-input" onchange="${ onChangeText } " value="${ data . defaultValue } " >
33
+ ${ data . values . map ( ( v : any ) => '<option value="' + v + '" ' + ( data . defaultValue === v ? 'selected' : '' ) + '>' + v + '</option>' ) . join ( '\n' ) }
34
+ </select>`
35
+ } else if ( data . type === 'color' ) {
36
+ htmlInput = `<input id="rd-${ data . variableName } " class="rd-color-input rd-input" type="color" oninput="${ onChangeText } " value="${ data . defaultValue } " />`
37
+ } else if ( data . type === 'date' ) {
38
+ htmlInput = `<input id="rd-${ data . variableName } " class="rd-text-input rd-input" type="date" oninput="${ onChangeText } " value="${ data . defaultValue } " />`
39
+ } else if ( data . type === 'button' ) {
40
+ htmlInput = `<button id="rd-${ data . variableName } " class="rd-button rd-input" onclick="${ data . trigger } ">${ data . label } </button>`
41
+ }
42
+
43
+ let html = `
44
+ <div class="rd-input-block">
45
+ <div class="rd-input-block-label">
46
+ ${ data . label }
47
+ </div>
48
+ <div class="rd-input-block-row">
49
+ ${ htmlInput }
50
+ <button class="copy-button" onclick="copyInput('rd-${ data . variableName } ')">
51
+ <svg width="16px" height="16px" version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" viewBox="0 0 100.56 122.88" style="enable-background:new 0 0 100.56 122.88" xml:space="preserve"><g><path d="M72.15,112.2L90.4,93H72.15V112.2L72.15,112.2z M81.75,9.2c0,1.69-1.37,3.05-3.05,3.05c-1.69,0-3.05-1.37-3.05-3.05V6.11 H6.11v92.24h3.01c1.69,0,3.05,1.37,3.05,3.05c0,1.69-1.37,3.05-3.05,3.05H5.48c-1.51,0-2.88-0.61-3.87-1.61l0.01-0.01 c-1-1-1.61-2.37-1.61-3.87V5.48C0,3.97,0.61,2.6,1.61,1.61C2.6,0.61,3.97,0,5.48,0h70.79c1.5,0,2.87,0.62,3.86,1.61l0,0l0.01,0.01 c0.99,0.99,1.61,2.36,1.61,3.86V9.2L81.75,9.2z M100.56,90.55c0,1.4-0.94,2.58-2.22,2.94l-26.88,28.27 c-0.56,0.68-1.41,1.11-2.36,1.11c-0.06,0-0.12,0-0.19-0.01c-0.06,0-0.12,0.01-0.18,0.01H24.29c-1.51,0-2.88-0.61-3.87-1.61 l0.01-0.01l-0.01-0.01c-0.99-0.99-1.61-2.36-1.61-3.86v-93.5c0-1.51,0.62-2.88,1.61-3.87l0.01,0.01c1-0.99,2.37-1.61,3.86-1.61 h70.79c1.5,0,2.87,0.62,3.86,1.61l0,0l0.01,0.01c0.99,0.99,1.61,2.36,1.61,3.86V90.55L100.56,90.55z M94.45,86.9V24.54H24.92v92.24 h41.13V89.95c0-1.69,1.37-3.05,3.05-3.05H94.45L94.45,86.9z"/></g></svg>
52
+ </button>
53
+ </div>
54
+ </div>
55
+ `
56
+ if ( data . type === 'button' ) {
57
+ html = `
58
+ <div class="rd-input-block">
59
+ <div class="rd-input-block-row">
60
+ ${ htmlInput }
61
+ </div>
62
+ </div>
63
+ `
64
+ }
65
+ return html
66
+ }
67
+
68
+ const generateTemplateHTML = ( data : any , type = '' ) => {
69
+ const id = `template-${ Math . floor ( Math . random ( ) * 1000000000 ) } `
70
+ let html = `
71
+ <div class="rd-template">
72
+ <pre id="${ id } " class="rd-template-content ${ type . length > 0 ? 'rd-' + type : '' } ">${ data } </pre>
73
+ <div class="rd-template-menu"><button class="copy-button" onclick="copyTemplate('${ id } ')">
74
+ <svg width="16px" height="16px" version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" viewBox="0 0 100.56 122.88" style="enable-background:new 0 0 100.56 122.88" xml:space="preserve"><g><path d="M72.15,112.2L90.4,93H72.15V112.2L72.15,112.2z M81.75,9.2c0,1.69-1.37,3.05-3.05,3.05c-1.69,0-3.05-1.37-3.05-3.05V6.11 H6.11v92.24h3.01c1.69,0,3.05,1.37,3.05,3.05c0,1.69-1.37,3.05-3.05,3.05H5.48c-1.51,0-2.88-0.61-3.87-1.61l0.01-0.01 c-1-1-1.61-2.37-1.61-3.87V5.48C0,3.97,0.61,2.6,1.61,1.61C2.6,0.61,3.97,0,5.48,0h70.79c1.5,0,2.87,0.62,3.86,1.61l0,0l0.01,0.01 c0.99,0.99,1.61,2.36,1.61,3.86V9.2L81.75,9.2z M100.56,90.55c0,1.4-0.94,2.58-2.22,2.94l-26.88,28.27 c-0.56,0.68-1.41,1.11-2.36,1.11c-0.06,0-0.12,0-0.19-0.01c-0.06,0-0.12,0.01-0.18,0.01H24.29c-1.51,0-2.88-0.61-3.87-1.61 l0.01-0.01l-0.01-0.01c-0.99-0.99-1.61-2.36-1.61-3.86v-93.5c0-1.51,0.62-2.88,1.61-3.87l0.01,0.01c1-0.99,2.37-1.61,3.86-1.61 h70.79c1.5,0,2.87,0.62,3.86,1.61l0,0l0.01,0.01c0.99,0.99,1.61,2.36,1.61,3.86V90.55L100.56,90.55z M94.45,86.9V24.54H24.92v92.24 h41.13V89.95c0-1.69,1.37-3.05,3.05-3.05H94.45L94.45,86.9z"/></g></svg>
75
+ </button></div>
76
+ </div>
77
+ `
78
+ templatesObj [ id ] = data
79
+
80
+ return html
81
+ }
82
+
83
+ const generateInlineTemplateHTML = ( data : any ) => {
84
+ const id = `template-${ Math . floor ( Math . random ( ) * 1000000000 ) } `
85
+
86
+ let html = `
87
+ <span class="rd-inline-template">
88
+ <span id="${ id } " class="rd-inline-template-content">${ data } </span>
89
+ </span>
90
+ `
91
+ templatesObj [ id ] = data
92
+
93
+ return html
94
+ }
95
+
96
+ const createGenericBlock = ( content : string , type = '' ) => {
97
+ return `
98
+ <pre class="rd-generic-block ${ type . length > 0 ? 'rd-' + type : '' } ">${ content } </pre>
99
+ `
100
+ }
101
+
102
+ /////
103
+ /////
104
+ /////
105
+ /////
106
+
107
+ const RDConvertor = ( mdContent : string ) => {
108
+
109
+
110
+ stateObj = { }
111
+ templatesObj = { }
112
+ allVariables = [ ]
113
+ codeBlocks = [ ]
114
+
115
+ // const md = new MDIT({
116
+ // html: true, // Enable HTML tags in source
117
+ // xhtmlOut: false, // Use '/' to close single tags (<br />).
118
+ // // This is only for full CommonMark compatibility.
119
+ // breaks: true, // Convert '\n' in paragraphs into <br>
120
+ // langPrefix: 'language-', // CSS language prefix for fenced blocks. Can be
121
+ // // useful for external highlighters.
122
+ // linkify: true, // Autoconvert URL-like text to links
123
+ // typographer: false,
124
+ // })
125
+
126
+ const md = MarkdownIt ( ) . set ( { html : true , breaks : true , xhtmlOut : false , typographer : false , linkify : true } )
127
+
128
+
129
+ md . renderer . rules . code_inline = ( tokens : Token [ ] ,
130
+ idx : number ,
131
+ options : MarkdownIt . Options ,
132
+ env : any ,
133
+ self : Renderer , ) => {
134
+
135
+ const token = tokens [ idx ]
136
+ const content = token . content . trim ( )
137
+ return generateInlineTemplateHTML ( content )
138
+ }
139
+
140
+
141
+ md . renderer . rules . fence = ( tokens : Token [ ] ,
142
+ idx : number ,
143
+ options : MarkdownIt . Options ,
144
+ env : any ,
145
+ self : Renderer , ) => {
146
+ // a code block
147
+ const token = tokens [ idx ]
148
+
149
+ if ( token . tag === 'code' ) {
150
+ const parts = token . info . split ( / \s + / )
151
+ let tokenName = token . info
152
+ if ( parts . length > 1 ) {
153
+ tokenName = parts [ 0 ]
154
+ }
155
+
156
+ if ( tokenName === '@input' ) {
157
+ const content = token . content . trim ( )
158
+ try {
159
+ const jsonContent = JSON . parse ( content )
160
+ const html = generateInputHTML ( jsonContent )
161
+ return html
162
+ } catch ( error ) {
163
+ return content
164
+ }
165
+ } else if ( tokenName === '@template' ) {
166
+ const content = token . content . trim ( )
167
+ try {
168
+ const html = generateTemplateHTML ( content , parts [ 1 ] )
169
+ return html
170
+ } catch ( error ) {
171
+ return content
172
+ }
173
+ } else if ( tokenName === '@code' ) {
174
+ const content = token . content . trim ( )
175
+ codeBlocks . push ( content )
176
+ return ''
177
+ } else {
178
+ const content = token . content . trim ( )
179
+ return createGenericBlock ( content , tokenName )
180
+ }
181
+ }
182
+
183
+ return token . content
184
+ }
185
+
186
+
187
+ const html = md . render ( mdContent )
188
+ let templateFileContent = htmlTemplate . replace ( 'REPLACE_HTML' , html )
189
+
190
+ const stateStr = `var state = ${ JSON . stringify ( stateObj ) } `
191
+ templateFileContent = templateFileContent . replace ( 'REPLACE_STATE' , stateStr )
192
+
193
+ const templatesStr = `var templates = ${ JSON . stringify ( templatesObj ) } `
194
+ templateFileContent = templateFileContent . replace ( 'REPLACE_TEMPLATES' , templatesStr )
195
+
196
+ const codeBlocksStr = codeBlocks . join ( '\n\n' )
197
+ templateFileContent = templateFileContent . replace ( 'REPLACE_CODE' , codeBlocksStr )
198
+
199
+ const mdLines = mdContent . split ( '\n' )
200
+ const mdHtmlLines = mdLines . map ( e => `<!--${ _ . escape ( e ) } -->` )
201
+ const mdLinesStr = mdHtmlLines . join ( '\n' )
202
+ templateFileContent = templateFileContent . replace ( 'REPLACE_MD' , mdLinesStr )
203
+
204
+ return { templateFileContent, allVariables}
205
+ }
206
+
207
+ export default RDConvertor
0 commit comments