|
1
|
/** |
|
2
|
A slight adaptation of fossil's legacy wysiwyg wiki editor which |
|
3
|
makes it usable with the newer editor's edit widget replacement |
|
4
|
API. |
|
5
|
|
|
6
|
Requires: window.fossil, fossil.dom, and that the current page is |
|
7
|
/wikiedit. If called from another page it returns without effect. |
|
8
|
|
|
9
|
Caveat: this is an all-or-nothing solution. That is, once plugged |
|
10
|
in to /wikiedit, it cannot be removed without reloading the page. |
|
11
|
That is a limitation of the current editor-widget-swapping API. |
|
12
|
*/ |
|
13
|
(function(F/*fossil object*/){ |
|
14
|
'use strict'; |
|
15
|
if(!F || !F.page || F.page.name!=='wikiedit') return; |
|
16
|
|
|
17
|
const D = F.dom; |
|
18
|
|
|
19
|
//////////////////////////////////////////////////////////////////////// |
|
20
|
// Install an app-specific stylesheet... |
|
21
|
(function(){ |
|
22
|
const head = document.head || document.querySelector('head'), |
|
23
|
styleTag = document.createElement('style'), |
|
24
|
styleCSS = ` |
|
25
|
.intLink { cursor: pointer; } |
|
26
|
img.intLink { border: 0; } |
|
27
|
#wysiwyg-container { |
|
28
|
display: flex; |
|
29
|
flex-direction: column; |
|
30
|
max-width: 100% /* w/o this, toolbars don't wrap properly! */ |
|
31
|
} |
|
32
|
#wysiwygBox { |
|
33
|
border: 1px solid rgba(127,127,127,0.3); |
|
34
|
border-radius: 0.25em; |
|
35
|
padding: 0.25em 1em; |
|
36
|
margin: 0; |
|
37
|
overflow: auto; |
|
38
|
min-height: 20em; |
|
39
|
resize: vertical; |
|
40
|
} |
|
41
|
#wysiwygEditMode { /* wrapper for radio buttons */ |
|
42
|
border: 1px solid rgba(127,127,127,0.3); |
|
43
|
border-radius: 0.25em; |
|
44
|
padding: 0 0.35em 0 0.35em |
|
45
|
} |
|
46
|
#wysiwygEditMode > * { |
|
47
|
vertical-align: text-top; |
|
48
|
} |
|
49
|
#wysiwygEditMode label { cursor: pointer; } |
|
50
|
#wysiwyg-toolbars { |
|
51
|
margin: 0 0 0.25em 0; |
|
52
|
display: flex; |
|
53
|
flex-wrap: wrap; |
|
54
|
flex-direction: column; |
|
55
|
align-items: flex-start; |
|
56
|
} |
|
57
|
#wysiwyg-toolbars > * { |
|
58
|
margin: 0 0.5em 0.25em 0; |
|
59
|
} |
|
60
|
#wysiwyg-toolBar1, #wysiwyg-toolBar2 { |
|
61
|
margin: 0 0.2em 0.2em 0; |
|
62
|
display: flex; |
|
63
|
flex-flow: row wrap; |
|
64
|
} |
|
65
|
#wysiwyg-toolBar1 > * { /* formatting buttons */ |
|
66
|
vertical-align: middle; |
|
67
|
margin: 0 0.25em 0.25em 0; |
|
68
|
} |
|
69
|
#wysiwyg-toolBar2 > * { /* icons */ |
|
70
|
border: 1px solid rgba(127,127,127,0.3); |
|
71
|
vertical-align: baseline; |
|
72
|
margin: 0.1em; |
|
73
|
} |
|
74
|
`; |
|
75
|
head.appendChild(styleTag); |
|
76
|
styleTag.type = 'text/css'; |
|
77
|
D.append(styleTag, styleCSS); |
|
78
|
})(); |
|
79
|
|
|
80
|
const outerContainer = D.attr(D.div(), 'id', 'wysiwyg-container'), |
|
81
|
toolbars = D.attr(D.div(), 'id', 'wysiwyg-toolbars'), |
|
82
|
toolbar1 = D.attr(D.div(), 'id', 'wysiwyg-toolBar1'), |
|
83
|
// ^^^ formatting options |
|
84
|
toolbar2 = D.attr(D.div(), 'id', 'wysiwyg-toolBar2') |
|
85
|
// ^^^^ action icon buttons |
|
86
|
; |
|
87
|
D.append(outerContainer, D.append(toolbars, toolbar1, toolbar2)); |
|
88
|
|
|
89
|
/** Returns a function which simplifies adding a list of options |
|
90
|
to the given select element. See below for example usage. */ |
|
91
|
const addOptions = function(select){ |
|
92
|
return function ff(value, label){ |
|
93
|
D.option(select, value, label || value); |
|
94
|
return ff; |
|
95
|
}; |
|
96
|
}; |
|
97
|
|
|
98
|
//////////////////////////////////////////////////////////////////////// |
|
99
|
// Edit mode selection (radio buttons). |
|
100
|
const radio0 = |
|
101
|
D.attr( |
|
102
|
D.input('radio'), |
|
103
|
'name','wysiwyg-mode', |
|
104
|
'id', 'wysiwyg-mode-0', |
|
105
|
'value',0, |
|
106
|
'checked',true), |
|
107
|
radio1 = D.attr( |
|
108
|
D.input('radio'), |
|
109
|
'id','wysiwyg-mode-1', |
|
110
|
'name','wysiwyg-mode', |
|
111
|
'value',1), |
|
112
|
radios = D.append( |
|
113
|
D.attr(D.span(), 'id', 'wysiwygEditMode'), |
|
114
|
radio0, D.append( |
|
115
|
D.attr(D.label(), 'for', 'wysiwyg-mode-0'), |
|
116
|
"WYSIWYG" |
|
117
|
), |
|
118
|
radio1, D.append( |
|
119
|
D.attr(D.label(), 'for', 'wysiwyg-mode-1'), |
|
120
|
"Raw HTML" |
|
121
|
) |
|
122
|
); |
|
123
|
D.append(toolbar1, radios); |
|
124
|
const radioHandler = function(){setDocMode(+this.value)}; |
|
125
|
radio0.addEventListener('change',radioHandler, false); |
|
126
|
radio1.addEventListener('change',radioHandler, false); |
|
127
|
|
|
128
|
|
|
129
|
//////////////////////////////////////////////////////////////////////// |
|
130
|
// Text formatting options... |
|
131
|
var select; |
|
132
|
select = D.addClass(D.select(), 'format'); |
|
133
|
select.dataset.format = "formatblock"; |
|
134
|
D.append(toolbar1, select); |
|
135
|
addOptions(select)( |
|
136
|
'', '- formatting -')( |
|
137
|
"h1", "Title 1 <h1>")( |
|
138
|
"h2", "Title 2 <h2>")( |
|
139
|
"h3", "Title 3 <h3>")( |
|
140
|
"h4", "Title 4 <h4>")( |
|
141
|
"h5", "Title 5 <h5>")( |
|
142
|
"h6", "Subtitle <h6>")( |
|
143
|
"p", "Paragraph <p>")( |
|
144
|
"pre", "Preformatted <pre>"); |
|
145
|
|
|
146
|
select = D.addClass(D.select(), 'format'); |
|
147
|
select.dataset.format = "fontname"; |
|
148
|
D.append(toolbar1, select); |
|
149
|
D.addClass( |
|
150
|
D.option(select, '', '- font -'), |
|
151
|
"heading" |
|
152
|
); |
|
153
|
addOptions(select)( |
|
154
|
'Arial')( |
|
155
|
'Arial Black')( |
|
156
|
'Courier New')( |
|
157
|
'Times New Roman'); |
|
158
|
|
|
159
|
select = D.addClass(D.select(), 'format'); |
|
160
|
D.append(toolbar1, select); |
|
161
|
select.dataset.format = "fontsize"; |
|
162
|
D.addClass( |
|
163
|
D.option(select, '', '- size -'), |
|
164
|
"heading" |
|
165
|
); |
|
166
|
addOptions(select)( |
|
167
|
"1", "Very small")( |
|
168
|
"2", "A bit small")( |
|
169
|
"3", "Normal")( |
|
170
|
"4", "Medium-large")( |
|
171
|
"5", "Big")( |
|
172
|
"6", "Very big")( |
|
173
|
"7", "Maximum"); |
|
174
|
|
|
175
|
select = D.addClass(D.select(), 'format'); |
|
176
|
D.append(toolbar1, select); |
|
177
|
select.dataset.format = 'forecolor'; |
|
178
|
D.addClass( |
|
179
|
D.option(select, '', '- color -'), |
|
180
|
"heading" |
|
181
|
); |
|
182
|
addOptions(select)( |
|
183
|
"red", "Red")( |
|
184
|
"blue", "Blue")( |
|
185
|
"green", "Green")( |
|
186
|
"black", "Black")( |
|
187
|
"grey", "Grey")( |
|
188
|
"yellow", "Yellow")( |
|
189
|
"cyan", "Cyan")( |
|
190
|
"magenta", "Magenta"); |
|
191
|
|
|
192
|
|
|
193
|
//////////////////////////////////////////////////////////////////////// |
|
194
|
// Icon-based toolbar... |
|
195
|
/** |
|
196
|
Inject the icons... |
|
197
|
|
|
198
|
mkbuiltins strips anything which looks like a C++-style comment, |
|
199
|
even if it's in a string literal, and thus the runs of "/" |
|
200
|
characters in the DOM element data attributes have been mangled |
|
201
|
to work around that: we simply use \x2f for every 2nd slash. |
|
202
|
*/ |
|
203
|
(function f(title,format,src){ |
|
204
|
const img = D.img(); |
|
205
|
D.append(toolbar2, img); |
|
206
|
D.addClass(img, 'intLink'); |
|
207
|
D.attr(img, 'title', title); |
|
208
|
img.dataset.format = format; |
|
209
|
D.attr(img, 'src', 'string'===typeof src ? src : src.join('')); |
|
210
|
return f; |
|
211
|
})( |
|
212
|
'Undo', 'undo', |
|
213
|
["data:image/gif;base64,R0lGODlhFgAWAOMKADljwliE33mOrpGjuYKl8aezxqPD+7", |
|
214
|
"/I19DV3NHa7P/\x2f/\x2f/\x2f/\x2f/\x2f/\x2f/\x2f/\x2f", |
|
215
|
"/\x2f/\x2f/\x2f/yH5BAEKAA8ALAAAAAAWABYAAARR8MlJq704680", |
|
216
|
"7TkaYeJJBnES4EeUJvIGapWYAC0CsocQ7SDlWJkAkCA6ToMYWIARGQF3mRQVIEjkkSVLIbSfE", |
|
217
|
"whdRIH4fh/DZMICe3/C4nBQBADs="] |
|
218
|
)( |
|
219
|
'Redo','redo', |
|
220
|
["data:image/gif;base64,R0lGODlhFgAWAMIHAB1ChDljwl9vj1iE34Kl8aPD+7/I1/", |
|
221
|
"/\x2f/yH5BAEKAAcALAAAAAAWABYAAANKeLrc/jDKSesyphi7SiEgsVXZEATDICqBVJjpqWZt9Na", |
|
222
|
"EDNbQK1wCQsxlYnxMAImhyDoFAElJasRRvAZVRqqQXUy7Cgx4TC6bswkAOw=="] |
|
223
|
)( |
|
224
|
"Remove formatting", |
|
225
|
"removeFormat", |
|
226
|
["data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABYAAAAWCAYAAADEtGw7AA", |
|
227
|
"AABGdBTUEAALGPC/xhBQAAAAZiS0dEAP8A/wD/oL2nkwAAAAlwSFlzAAAOxAAADsQBlSsOGwA", |
|
228
|
"AAAd0SU1FB9oECQMCKPI8CIIAAAAIdEVYdENvbW1lbnQA9syWvwAAAuhJREFUOMtjYBgFxAB5", |
|
229
|
"01ZWBvVaL2nHnlmk6mXCJbF69zU+Hz/9fB5O1lx+bg45qhl8/fYr5it3XrP/YWTUvvvk3VeqG", |
|
230
|
"Xz70TvbJy8+Wv39+2/Hz19/mGwjZzuTYjALuoBv9jImaXHeyD3H7kU8fPj2ICML8z92dlbtMz", |
|
231
|
"deiG3fco7J08foH1kurkm3E9iw54YvKwuTuom+LPt/BgbWf3/\x2fsf37/1/c02cCG1lB8f/\x2ff95", |
|
232
|
"DZx74MTMzshhoSm6szrQ/a6Ir/Z2RkfEjBxuLYFpDiDi6Af/\x2f/2ckaHBp7+7wmavP5n76+P2C", |
|
233
|
"lrLIYl8H9W36auJCbCxM4szMTJac7Kza/\x2f/\x2fR3H1w2cfWAgafPbqs5g7D95++/P1B4+ECK8tA", |
|
234
|
"wMDw/1H7159+/7r7ZcvPz4fOHbzEwMDwx8GBgaGnNatfHZx8zqrJ+4VJBh5CQEGOySEua/v3n", |
|
235
|
"7hXmqI8WUGBgYGL3vVG7fuPK3i5GD9/fja7ZsMDAzMG/Ze52mZeSj4yu1XEq/ff7W5dvfVAS1", |
|
236
|
"lsXc4Db7z8C3r8p7Qjf/\x2f/2dnZGxlqJuyr3rPqQd/Hhyu7oSpYWScylDQsd3kzvnH738wMDzj", |
|
237
|
"5GBN1VIWW4c3KDon7VOvm7S3paB9u5qsU5/x5KUnlY+eexQbkLNsErK61+++VnAJcfkyMTIwf", |
|
238
|
"fj0QwZbJDKjcETs1Y8evyd48toz8y/ffzv/\x2fvPP4veffxpX77z6l5JewHPu8MqTDAwMDLzyrj", |
|
239
|
"b/mZm0JcT5Lj+89+Ybm6zz95oMh7s4XbygN3Sluq4Mj5K8iKMgP4f0/\x2f/\x2ffv77/\x2f8nLy+7MCc", |
|
240
|
"XmyYDAwODS9jM9tcvPypd35pne3ljdjvj26+H2dhYpuENikgfvQeXNmSl3tqepxXsqhXPyc66", |
|
241
|
"6s+fv1fMdKR3TK72zpix8nTc7bdfhfkEeVbC9KhbK/9iYWHiErbu6MWbY/7/\x2f8/4/\x2f9/pgOnH", |
|
242
|
"6jGVazvFDRtq2VgiBIZrUTIBgCk+ivHvuEKwAAAAABJRU5ErkJggg=="] |
|
243
|
)( |
|
244
|
"Bold", |
|
245
|
"bold", |
|
246
|
["data:image/gif;base64,R0lGODlhFgAWAID/AMDAwAAAACH5BAEAAAAALAAAAAAWAB", |
|
247
|
"YAQAInhI+pa+H9mJy0LhdgtrxzDG5WGFVk6aXqyk6Y9kXvKKNuLbb6zgMFADs="] |
|
248
|
)( |
|
249
|
"Italic", |
|
250
|
"italic", |
|
251
|
["data:image/gif;base64,R0lGODlhFgAWAKEDAAAAAF9vj5WIbf/\x2f/yH5BAEAAAMALA", |
|
252
|
"AAAAAWABYAAAIjnI+py+0Po5x0gXvruEKHrF2BB1YiCWgbMFIYpsbyTNd2UwAAOw=="] |
|
253
|
)( |
|
254
|
"Underline", |
|
255
|
"underline", |
|
256
|
["data:image/gif;base64,R0lGODlhFgAWAKECAAAAAF9vj/\x2f/\x2f/\x2f/\x2fyH5BAEAAAIALA", |
|
257
|
"AAAAAWABYAAAIrlI+py+0Po5zUgAsEzvEeL4Ea15EiJJ5PSqJmuwKBEKgxVuXWtun+DwxCCgA", |
|
258
|
"7"] |
|
259
|
)( |
|
260
|
"Left align", |
|
261
|
"justifyleft", |
|
262
|
["data:image/gif;base64,R0lGODlhFgAWAID/AMDAwAAAACH5BAEAAAAALAAAAAAWAB", |
|
263
|
"YAQAIghI+py+0Po5y02ouz3jL4D4JMGELkGYxo+qzl4nKyXAAAOw=="] |
|
264
|
)( |
|
265
|
"Center align", |
|
266
|
"justifycenter", |
|
267
|
["data:image/gif;base64,R0lGODlhFgAWAID/AMDAwAAAACH5BAEAAAAALAAAAAAWAB", |
|
268
|
"YAQAIfhI+py+0Po5y02ouz3jL4D4JOGI7kaZ5Bqn4sycVbAQA7"] |
|
269
|
)( |
|
270
|
"Right align", |
|
271
|
"justifyright", |
|
272
|
["data:image/gif;base64,R0lGODlhFgAWAID/AMDAwAAAACH5BAEAAAAALAAAAAAWAB", |
|
273
|
"YAQAIghI+py+0Po5y02ouz3jL4D4JQGDLkGYxouqzl43JyVgAAOw=="] |
|
274
|
)( |
|
275
|
"Numbered list", |
|
276
|
"insertorderedlist", |
|
277
|
["data:image/gif;base64,R0lGODlhFgAWAMIGAAAAADljwliE35GjuaezxtHa7P/\x2f/\x2f", |
|
278
|
"/\x2f/yH5BAEAAAcALAAAAAAWABYAAAM2eLrc/jDKSespwjoRFvggCBUBoTFBeq6QIAysQnRHaEO", |
|
279
|
"zyaZ07Lu9lUBnC0UGQU1K52s6n5oEADs="] |
|
280
|
)( |
|
281
|
"Dotted list", |
|
282
|
"insertunorderedlist", |
|
283
|
["data:image/gif;base64,R0lGODlhFgAWAMIGAAAAAB1ChF9vj1iE33mOrqezxv/\x2f/\x2f", |
|
284
|
"/\x2f/yH5BAEAAAcALAAAAAAWABYAAAMyeLrc/jDKSesppNhGRlBAKIZRERBbqm6YtnbfMY7lud6", |
|
285
|
"4UwiuKnigGQliQuWOyKQykgAAOw=="] |
|
286
|
)( |
|
287
|
"Quote", |
|
288
|
"formatblock", |
|
289
|
["data:image/gif;base64,R0lGODlhFgAWAIQXAC1NqjFRjkBgmT9nqUJnsk9xrFJ7u2", |
|
290
|
"R9qmKBt1iGzHmOrm6Sz4OXw3Odz4Cl2ZSnw6KxyqO306K63bG70bTB0rDI3bvI4P", |
|
291
|
"/\x2f/\x2f/\x2f/\x2f/", |
|
292
|
"/\x2f/\x2f/\x2f/\x2f/\x2f/\x2f/\x2f/\x2f/\x2f/\x2f", |
|
293
|
"/\x2f/\x2f/\x2fyH5BAEKAB8ALAAAAAAWABYAAAVP4CeOZGmeaKqubEs2Cekk", |
|
294
|
"ErvEI1zZuOgYFlakECEZFi0GgTGKEBATFmJAVXweVOoKEQgABB9IQDCmrLpjETrQQlhHjINrT", |
|
295
|
"q/b7/i8fp8PAQA7"] |
|
296
|
)( |
|
297
|
"Delete indentation", |
|
298
|
"outdent", |
|
299
|
["data:image/gif;base64,R0lGODlhFgAWAMIHAAAAADljwliE35GjuaezxtDV3NHa7P", |
|
300
|
"/\x2f/yH5BAEAAAcALAAAAAAWABYAAAM2eLrc/jDKCQG9F2i7u8agQgyK1z2EIBil+TWqEMxhMcz", |
|
301
|
"sYVJ3e4ahk+sFnAgtxSQDqWw6n5cEADs="] |
|
302
|
)( |
|
303
|
"Add indentation", |
|
304
|
"indent", |
|
305
|
["data:image/gif;base64,R0lGODlhFgAWAOMIAAAAADljwl9vj1iE35GjuaezxtDV3N", |
|
306
|
"Ha7P/\x2f/\x2f/\x2f/\x2f/\x2f/\x2f/\x2f/\x2f/\x2f/\x2f/\x2f/\x2f/\x2f", |
|
307
|
"/\x2f/\x2f/yH5BAEAAAgALAAAAAAWABYAAAQ7EMlJq704650", |
|
308
|
"B/x8gemMpgugwHJNZXodKsO5oqUOgo5KhBwWESyMQsCRDHu9VOyk5TM9zSpFSr9gsJwIAOw==" |
|
309
|
] |
|
310
|
)( |
|
311
|
"Hyperlink", |
|
312
|
"createlink", |
|
313
|
["data:image/gif;base64,R0lGODlhFgAWAOMKAB1ChDRLY19vj3mOrpGjuaezxrCztb", |
|
314
|
"/I19Ha7Pv8/f/\x2f/\x2f/\x2f/\x2f/\x2f/\x2f/\x2f/\x2f/\x2f/\x2f/\x2f", |
|
315
|
"/yH5BAEKAA8ALAAAAAAWABYAAARY8MlJq704682", |
|
316
|
"7/2BYIQVhHg9pEgVGIklyDEUBy/RlE4FQF4dCj2AQXAiJQDCWQCAEBwIioEMQBgSAFhDAGghG", |
|
317
|
"i9XgHAhMNoSZgJkJei33UESv2+/4vD4TAQA7"] |
|
318
|
)( |
|
319
|
"Cut", |
|
320
|
"cut", |
|
321
|
["data:image/gif;base64,R0lGODlhFgAWAIQSAB1ChBFNsRJTySJYwjljwkxwl19vj1", |
|
322
|
"dusYODhl6MnHmOrpqbmpGjuaezxrCztcDCxL/I18rL1P/\x2f/\x2f/\x2f/\x2f/\x2f/\x2f", |
|
323
|
"/\x2f/\x2f/\x2f/\x2f/\x2f/\x2f/\x2f/\x2f/", |
|
324
|
"/\x2f/\x2f/\x2f/\x2f/\x2f/\x2f/\x2f/\x2f/\x2f/\x2f/\x2f/\x2f/\x2f", |
|
325
|
"yH5BAEAAB8ALAAAAAAWABYAAAVu4CeOZGmeaKqubDs6TNnE", |
|
326
|
"bGNApNG0kbGMi5trwcA9GArXh+FAfBAw5UexUDAQESkRsfhJPwaH4YsEGAAJGisRGAQY7UCC9", |
|
327
|
"ZAXBB+74LGCRxIEHwAHdWooDgGJcwpxDisQBQRjIgkDCVlfmZqbmiEAOw=="] |
|
328
|
)( |
|
329
|
"Copy", |
|
330
|
"copy", |
|
331
|
["data:image/gif;base64,R0lGODlhFgAWAIQcAB1ChBFNsTRLYyJYwjljwl9vj1iE31", |
|
332
|
"iGzF6MnHWX9HOdz5GjuYCl2YKl8ZOt4qezxqK63aK/9KPD+7DI3b/I17LM/MrL1MLY9NHa7OP", |
|
333
|
"s++bx/Pv8/f/\x2f/\x2f/\x2f/\x2f/\x2f/\x2f/\x2f", |
|
334
|
"/yH5BAEAAB8ALAAAAAAWABYAAAWG4CeOZGmeaKqubOum1SQ/", |
|
335
|
"kPVOW749BeVSus2CgrCxHptLBbOQxCSNCCaF1GUqwQbBd0JGJAyGJJiobE+LnCaDcXAaEoxhQ", |
|
336
|
"ACgNw0FQx9kP+wmaRgYFBQNeAoGihCAJQsCkJAKOhgXEw8BLQYciooHf5o7EA+kC40qBKkAAA", |
|
337
|
"Grpy+wsbKzIiEAOw=="] |
|
338
|
)( |
|
339
|
/* Paste, when activated via JS, has no effect in some (maybe all) |
|
340
|
environments. Activated externally, e.g. keyboard, it works. */ |
|
341
|
"Paste (does not work in all environments)", |
|
342
|
"paste", |
|
343
|
["data:image/gif;base64,R0lGODlhFgAWAIQUAD04KTRLY2tXQF9vj414WZWIbXmOrp", |
|
344
|
"qbmpGjudClFaezxsa0cb/I1+3YitHa7PrkIPHvbuPs+/fvrvv8/f/\x2f/\x2f/\x2f", |
|
345
|
"/\x2f/\x2f/\x2f/\x2f/\x2f/\x2f/\x2f/", |
|
346
|
"/\x2f/\x2f/\x2f/\x2f/\x2f/\x2f/\x2f/\x2f/\x2f/\x2f/\x2f/\x2f/\x2f", |
|
347
|
"yH5BAEAAB8ALAAAAAAWABYAAAWN4CeOZGmeaKqubGsusPvB", |
|
348
|
"SyFJjVDs6nJLB0khR4AkBCmfsCGBQAoCwjF5gwquVykSFbwZE+AwIBV0GhFog2EwIDchjwRiQ", |
|
349
|
"o9E2Fx4XD5R+B0DDAEnBXBhBhN2DgwDAQFjJYVhCQYRfgoIDGiQJAWTCQMRiwwMfgicnVcAAA", |
|
350
|
"MOaK+bLAOrtLUyt7i5uiUhADs="] |
|
351
|
); |
|
352
|
|
|
353
|
//////////////////////////////////////////////////////////////////////// |
|
354
|
// The main editor area... |
|
355
|
const oDoc = D.attr(D.div(), 'id', "wysiwygBox"); |
|
356
|
D.attr(oDoc, 'contenteditable', 'true'); |
|
357
|
D.append(outerContainer, oDoc); |
|
358
|
|
|
359
|
/* Initialize the document editor */ |
|
360
|
function initDoc() { |
|
361
|
initEventHandlers(); |
|
362
|
if (!isWysiwyg()) { setDocMode(true); } |
|
363
|
} |
|
364
|
|
|
365
|
function initEventHandlers() { |
|
366
|
//console.debug("initEventHandlers()"); |
|
367
|
const handleDropDown = function() { |
|
368
|
formatDoc(this.dataset.format,this[this.selectedIndex].value); |
|
369
|
this.selectedIndex = 0; |
|
370
|
}; |
|
371
|
|
|
372
|
const handleFormatButton = function() { |
|
373
|
var extra; |
|
374
|
switch (this.dataset.format) { |
|
375
|
case 'createlink': |
|
376
|
const sLnk = prompt('Target URL:',''); |
|
377
|
if(sLnk) extra = sLnk; |
|
378
|
break; |
|
379
|
case 'formatblock': |
|
380
|
extra = 'blockquote'; |
|
381
|
break; |
|
382
|
} |
|
383
|
formatDoc(this.dataset.format, extra); |
|
384
|
}; |
|
385
|
|
|
386
|
var i, controls = outerContainer.querySelectorAll('select.format'); |
|
387
|
for(i = 0; i < controls.length; i++) { |
|
388
|
controls[i].addEventListener('change', handleDropDown, false);; |
|
389
|
} |
|
390
|
controls = outerContainer.querySelectorAll('.intLink'); |
|
391
|
for(i = 0; i < controls.length; i++) { |
|
392
|
controls[i].addEventListener('click', handleFormatButton, false); |
|
393
|
} |
|
394
|
} |
|
395
|
|
|
396
|
/* Return true if the document editor is in WYSIWYG mode. Return |
|
397
|
** false if it is in Markup mode */ |
|
398
|
function isWysiwyg() { |
|
399
|
return radio0.checked; |
|
400
|
} |
|
401
|
|
|
402
|
/* Run the editing command if in WYSIWYG mode */ |
|
403
|
function formatDoc(sCmd, sValue) { |
|
404
|
if (isWysiwyg()){ |
|
405
|
try { |
|
406
|
// First, try the W3C draft standard way, which has |
|
407
|
// been working on all non-IE browsers for a while. |
|
408
|
// It is also supported by IE11 and higher. |
|
409
|
document.execCommand("styleWithCSS", false, false); |
|
410
|
} catch (e) { |
|
411
|
try { |
|
412
|
// For IE9 or IE10, this should work. |
|
413
|
document.execCommand("useCSS", 0, true); |
|
414
|
} catch (e) { |
|
415
|
// OK, that apparently did not work, do nothing. |
|
416
|
} |
|
417
|
} |
|
418
|
document.execCommand(sCmd, false, sValue); |
|
419
|
oDoc.focus(); |
|
420
|
} |
|
421
|
} |
|
422
|
|
|
423
|
/* Change the editing mode. Convert to markup if the argument |
|
424
|
** is true and wysiwyg if the argument is false. */ |
|
425
|
function setDocMode(bToMarkup, content) { |
|
426
|
if(undefined===content){ |
|
427
|
content = bToMarkup ? oDoc.innerHTML : oDoc.innerText; |
|
428
|
} |
|
429
|
if(!setDocMode.linebreak){ |
|
430
|
setDocMode.linebreak = new RegExp("</p><p>","ig"); |
|
431
|
} |
|
432
|
if(!setDocMode.toHide){ |
|
433
|
setDocMode.toHide = toolbars.querySelectorAll( |
|
434
|
'#wysiwyg-toolBar1 > *:not(#wysiwygEditMode), ' |
|
435
|
+'#wysiwyg-toolBar2'); |
|
436
|
} |
|
437
|
if (bToMarkup) { |
|
438
|
/* WYSIWYG -> Markup */ |
|
439
|
// Legacy did this: content=content.replace(setDocMode.linebreak,"</p>\n\n<p>") |
|
440
|
D.append(D.clearElement(oDoc), content) |
|
441
|
oDoc.style.whiteSpace = "pre-wrap"; |
|
442
|
D.addClass(setDocMode.toHide, 'hidden'); |
|
443
|
} else { |
|
444
|
/* Markup -> WYSIWYG */ |
|
445
|
D.parseHtml(D.clearElement(oDoc), content); |
|
446
|
oDoc.style.whiteSpace = "normal"; |
|
447
|
D.removeClass(setDocMode.toHide, 'hidden'); |
|
448
|
} |
|
449
|
oDoc.focus(); |
|
450
|
} |
|
451
|
|
|
452
|
//////////////////////////////////////////////////////////////////////// |
|
453
|
// A hook which can be activated via a site skin to plug this editor |
|
454
|
// into the wikiedit page. |
|
455
|
F.page.wysiwyg = { |
|
456
|
// only for debugging: oDoc: oDoc, |
|
457
|
/* |
|
458
|
Replaces wikiedit's default editor widget with this wysiwyg |
|
459
|
editor. |
|
460
|
|
|
461
|
Must either be called via an onPageLoad handler via the site |
|
462
|
skin's footer or else it can be called manually from the dev |
|
463
|
tools console. Calling it too early (e.g. in the page footer |
|
464
|
outside of an onPageLoad handler) will crash because wikiedit |
|
465
|
has not been initialized. |
|
466
|
*/ |
|
467
|
init: function(){ |
|
468
|
initDoc(); |
|
469
|
const content = F.page.wikiContent() || ''; |
|
470
|
var isDirty = false /* keep from stashing too often */; |
|
471
|
F.page.setContentMethods( |
|
472
|
function(){ |
|
473
|
const rc = isWysiwyg() ? oDoc.innerHTML : oDoc.innerText; |
|
474
|
return rc; |
|
475
|
}, |
|
476
|
function(content){ |
|
477
|
isDirty = false; |
|
478
|
setDocMode(radio0.checked ? 0 : 1, content); |
|
479
|
} |
|
480
|
); |
|
481
|
oDoc.addEventListener('blur', function(){ |
|
482
|
if(isDirty) F.page.notifyOfChange(); |
|
483
|
}, false); |
|
484
|
oDoc.addEventListener('input', function(){isDirty = true}, false); |
|
485
|
F.page.wikiContent(content)/*feed it back in to our widget*/; |
|
486
|
F.page.replaceEditorElement(outerContainer); |
|
487
|
F.message("Replaced wiki editor widget with legacy wysiwyg editor."); |
|
488
|
} |
|
489
|
}; |
|
490
|
})(window.fossil); |
|
491
|
|