Fossil SCM

fossil-scm / src / fossil.wikiedit-wysiwyg.js
Blame History Raw 491 lines
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

Keyboard Shortcuts

Open search /
Next entry (timeline) j
Previous entry (timeline) k
Open focused entry Enter
Show this help ?
Toggle theme Top nav button