Merge remote-tracking branch 'refs/remotes/origin/3.0'
[GitHub/WoltLab/WCF.git] / com.woltlab.wcf / templates / wysiwyg.tpl
1 {event name='beforeEditorJavaScript'}
2
3 <script data-relocate="true">
4 head.load([
5 {if ENABLE_DEBUG_MODE}
6 {* Imperavi *}
7 '{@$__wcf->getPath()}js/3rdParty/redactor2/redactor.js?v={@LAST_UPDATE_TIME}',
8 '{@$__wcf->getPath()}js/3rdParty/redactor2/plugins/alignment.js?v={@LAST_UPDATE_TIME}',
9 '{@$__wcf->getPath()}js/3rdParty/redactor2/plugins/source.js?v={@LAST_UPDATE_TIME}',
10 '{@$__wcf->getPath()}js/3rdParty/redactor2/plugins/table.js?v={@LAST_UPDATE_TIME}',
11
12 {* WoltLab *}
13 '{@$__wcf->getPath()}js/3rdParty/redactor2/plugins/WoltLabAttachment.js?v={@LAST_UPDATE_TIME}',
14 '{@$__wcf->getPath()}js/3rdParty/redactor2/plugins/WoltLabAutosave.js?v={@LAST_UPDATE_TIME}',
15 '{@$__wcf->getPath()}js/3rdParty/redactor2/plugins/WoltLabBlock.js?v={@LAST_UPDATE_TIME}',
16 '{@$__wcf->getPath()}js/3rdParty/redactor2/plugins/WoltLabButton.js?v={@LAST_UPDATE_TIME}',
17 '{@$__wcf->getPath()}js/3rdParty/redactor2/plugins/WoltLabCaret.js?v={@LAST_UPDATE_TIME}',
18 '{@$__wcf->getPath()}js/3rdParty/redactor2/plugins/WoltLabClean.js?v={@LAST_UPDATE_TIME}',
19 '{@$__wcf->getPath()}js/3rdParty/redactor2/plugins/WoltLabCode.js?v={@LAST_UPDATE_TIME}',
20 '{@$__wcf->getPath()}js/3rdParty/redactor2/plugins/WoltLabColor.js?v={@LAST_UPDATE_TIME}',
21 '{@$__wcf->getPath()}js/3rdParty/redactor2/plugins/WoltLabDragAndDrop.js?v={@LAST_UPDATE_TIME}',
22 '{@$__wcf->getPath()}js/3rdParty/redactor2/plugins/WoltLabDropdown.js?v={@LAST_UPDATE_TIME}',
23 '{@$__wcf->getPath()}js/3rdParty/redactor2/plugins/WoltLabEvent.js?v={@LAST_UPDATE_TIME}',
24 '{@$__wcf->getPath()}js/3rdParty/redactor2/plugins/WoltLabFont.js?v={@LAST_UPDATE_TIME}',
25 '{@$__wcf->getPath()}js/3rdParty/redactor2/plugins/WoltLabFullscreen.js?v={@LAST_UPDATE_TIME}',
26 '{@$__wcf->getPath()}js/3rdParty/redactor2/plugins/WoltLabHtml.js?v={@LAST_UPDATE_TIME}',
27 '{@$__wcf->getPath()}js/3rdParty/redactor2/plugins/WoltLabImage.js?v={@LAST_UPDATE_TIME}',
28 '{@$__wcf->getPath()}js/3rdParty/redactor2/plugins/WoltLabIndent.js?v={@LAST_UPDATE_TIME}',
29 '{@$__wcf->getPath()}js/3rdParty/redactor2/plugins/WoltLabInlineCode.js?v={@LAST_UPDATE_TIME}',
30 '{@$__wcf->getPath()}js/3rdParty/redactor2/plugins/WoltLabInsert.js?v={@LAST_UPDATE_TIME}',
31 '{@$__wcf->getPath()}js/3rdParty/redactor2/plugins/WoltLabKeydown.js?v={@LAST_UPDATE_TIME}',
32 '{@$__wcf->getPath()}js/3rdParty/redactor2/plugins/WoltLabLine.js?v={@LAST_UPDATE_TIME}',
33 '{@$__wcf->getPath()}js/3rdParty/redactor2/plugins/WoltLabLink.js?v={@LAST_UPDATE_TIME}',
34 '{@$__wcf->getPath()}js/3rdParty/redactor2/plugins/WoltLabList.js?v={@LAST_UPDATE_TIME}',
35 '{@$__wcf->getPath()}js/3rdParty/redactor2/plugins/WoltLabMedia.js?v={@LAST_UPDATE_TIME}',
36 '{@$__wcf->getPath()}js/3rdParty/redactor2/plugins/WoltLabMention.js?v={@LAST_UPDATE_TIME}',
37 '{@$__wcf->getPath()}js/3rdParty/redactor2/plugins/WoltLabModal.js?v={@LAST_UPDATE_TIME}',
38 '{@$__wcf->getPath()}js/3rdParty/redactor2/plugins/WoltLabObserve.js?v={@LAST_UPDATE_TIME}',
39 '{@$__wcf->getPath()}js/3rdParty/redactor2/plugins/WoltLabPaste.js?v={@LAST_UPDATE_TIME}',
40 '{@$__wcf->getPath()}js/3rdParty/redactor2/plugins/WoltLabQuote.js?v={@LAST_UPDATE_TIME}',
41 '{@$__wcf->getPath()}js/3rdParty/redactor2/plugins/WoltLabReply.js?v={@LAST_UPDATE_TIME}',
42 '{@$__wcf->getPath()}js/3rdParty/redactor2/plugins/WoltLabSize.js?v={@LAST_UPDATE_TIME}',
43 '{@$__wcf->getPath()}js/3rdParty/redactor2/plugins/WoltLabSmiley.js?v={@LAST_UPDATE_TIME}',
44 '{@$__wcf->getPath()}js/3rdParty/redactor2/plugins/WoltLabSource.js?v={@LAST_UPDATE_TIME}',
45 '{@$__wcf->getPath()}js/3rdParty/redactor2/plugins/WoltLabSpoiler.js?v={@LAST_UPDATE_TIME}',
46 '{@$__wcf->getPath()}js/3rdParty/redactor2/plugins/WoltLabTable.js?v={@LAST_UPDATE_TIME}',
47 '{@$__wcf->getPath()}js/3rdParty/redactor2/plugins/WoltLabUtils.js?v={@LAST_UPDATE_TIME}'
48 {else}
49 '{@$__wcf->getPath()}js/3rdParty/redactor2/redactor.combined.min.js?v={@LAST_UPDATE_TIME}'
50 {/if}
51
52 {if $__redactorJavaScript|isset}{@$__redactorJavaScript}{/if}
53 {assign var=__redactorJavaScript value=''}
54
55 {event name='redactorJavaScript'}
56 ], function () {
57 require(['Environment', 'Language', 'WoltLabSuite/Core/Ui/Redactor/Autosave', 'WoltLabSuite/Core/Ui/Redactor/Metacode'], function(Environment, Language, UiRedactorAutosave, UiRedactorMetacode) {
58 Language.addObject({
59 'wcf.attachment.dragAndDrop.dropHere': '{lang}wcf.attachment.dragAndDrop.dropHere{/lang}',
60 'wcf.attachment.dragAndDrop.dropNow': '{lang}wcf.attachment.dragAndDrop.dropNow{/lang}',
61
62 'wcf.editor.autosave.discard': '{lang}wcf.editor.autosave.discard{/lang}',
63 'wcf.editor.autosave.keep': '{lang}wcf.editor.autosave.keep{/lang}',
64 'wcf.editor.autosave.restored': '{lang}wcf.editor.autosave.restored{/lang}',
65
66 'wcf.editor.code.edit': '{lang}wcf.editor.code.edit{/lang}',
67 'wcf.editor.code.file': '{lang}wcf.editor.code.file{/lang}',
68 'wcf.editor.code.file.description': '{lang}wcf.editor.code.file.description{/lang}',
69 'wcf.editor.code.highlighter': '{lang}wcf.editor.code.highlighter{/lang}',
70 'wcf.editor.code.highlighter.description': '{lang}wcf.editor.code.highlighter.description{/lang}',
71 'wcf.editor.code.highlighter.detect': '{lang}wcf.editor.code.highlighter.detect{/lang}',
72 'wcf.editor.code.line': '{lang}wcf.editor.code.line{/lang}',
73 'wcf.editor.code.line.description': '{lang}wcf.editor.code.line.description{/lang}',
74 'wcf.editor.code.title': '{lang __literal=true}wcf.editor.code.title{/lang}',
75
76 'wcf.editor.html.description': '{lang}wcf.editor.html.description{/lang}',
77 'wcf.editor.html.title': '{lang}wcf.editor.html.title{/lang}',
78
79 'wcf.editor.image.edit': '{lang}wcf.editor.image.edit{/lang}',
80 'wcf.editor.image.insert': '{lang}wcf.editor.image.insert{/lang}',
81 'wcf.editor.image.link': '{lang}wcf.editor.image.link{/lang}',
82 'wcf.editor.image.link.error.invalid': '{lang}wcf.editor.image.link.error.invalid{/lang}',
83 'wcf.editor.image.float': '{lang}wcf.editor.image.float{/lang}',
84 'wcf.editor.image.float.left': '{lang}wcf.editor.image.float.left{/lang}',
85 'wcf.editor.image.float.right': '{lang}wcf.editor.image.float.right{/lang}',
86 'wcf.editor.image.source': '{lang}wcf.editor.image.source{/lang}',
87 'wcf.editor.image.source.error.insecure': '{lang}wcf.editor.image.source.error.insecure{/lang}',
88 'wcf.editor.image.source.error.invalid': '{lang}wcf.editor.image.source.error.invalid{/lang}',
89
90 'wcf.editor.link.add': '{lang}wcf.editor.link.add{/lang}',
91 'wcf.editor.link.edit': '{lang}wcf.editor.link.edit{/lang}',
92 'wcf.editor.link.error.invalid': '{lang}wcf.editor.link.error.invalid{/lang}',
93 'wcf.editor.link.url': '{lang}wcf.editor.link.url{/lang}',
94 'wcf.editor.link.text': '{lang}wcf.editor.link.text{/lang}',
95
96 'wcf.editor.list.indent': '{lang}wcf.editor.list.indent{/lang}',
97 'wcf.editor.list.outdent': '{lang}wcf.editor.list.outdent{/lang}',
98
99 'wcf.editor.quote.author': '{lang}wcf.editor.quote.author{/lang}',
100 'wcf.editor.quote.edit': '{lang}wcf.editor.quote.edit{/lang}',
101 'wcf.editor.quote.title': '{lang __literal=true}wcf.editor.quote.title{/lang}',
102 'wcf.editor.quote.url': '{lang}wcf.editor.quote.url{/lang}',
103 'wcf.editor.quote.url.description': '{lang}wcf.editor.quote.url.description{/lang}',
104 'wcf.editor.quote.url.error.invalid': '{lang}wcf.editor.quote.url.error.invalid{/lang}',
105
106 'wcf.editor.source.error.active': '{lang}wcf.editor.source.error.active{/lang}',
107
108 'wcf.editor.spoiler.label': '{lang}wcf.editor.spoiler.label{/lang}',
109 'wcf.editor.spoiler.label.description': '{lang}wcf.editor.spoiler.label.description{/lang}',
110 'wcf.editor.spoiler.edit': '{lang}wcf.editor.spoiler.edit{/lang}',
111 'wcf.editor.spoiler.title': '{lang __literal=true}wcf.editor.spoiler.title{/lang}'
112 });
113
114 var allowedInlineStyles = [], buttons = [], buttonMobile = [], buttonOptions = [], customButtons = [];
115 {include file='wysiwygToolbar'}
116
117 var highlighters = { {implode from=$__wcf->getBBCodeHandler()->getHighlighters() item=__highlighter}'{$__highlighter}': '{lang}wcf.bbcode.code.{@$__highlighter}.title{/lang}'{/implode} };
118
119 {include file='mediaJavaScript'}
120
121 var element = elById('{if $wysiwygSelector|isset}{$wysiwygSelector|encodeJS}{else}text{/if}');
122
123 var autosave = elData(element, 'autosave') || null;
124 if (autosave) {
125 autosave = new UiRedactorAutosave(element);
126 element.value = autosave.getInitialValue();
127 }
128
129 var disableMedia = elDataBool(element, 'disable-media');
130
131 var config = {
132 buttons: buttons,
133 clipboardImageUpload: {if $__wcf->getBBCodeHandler()->isAvailableBBCode('img')}true{else}false{/if},
134 direction: '{lang}wcf.global.pageDirection{/lang}',
135 formatting: ['p', 'h2', 'h3', 'h4'],
136 imageCaption: false,
137 imageUpload: {if $__wcf->getBBCodeHandler()->isAvailableBBCode('img')}true{else}false{/if},
138 lang: 'wsc', // fake language to offload phrases
139 langs: {
140 wsc: {
141 // general
142 edit: '{lang}wcf.global.button.edit{/lang}',
143
144 // formatting dropdown
145 heading2: '{lang}wcf.editor.format.heading2{/lang}',
146 heading3: '{lang}wcf.editor.format.heading3{/lang}',
147 heading4: '{lang}wcf.editor.format.heading4{/lang}',
148 paragraph: '{lang}wcf.editor.format.paragraph{/lang}',
149
150 // links
151 'link-edit': '{lang}wcf.editor.link.edit{/lang}',
152 'link-insert': '{lang}wcf.editor.link.add{/lang}',
153 unlink: '{lang}wcf.editor.link.unlink{/lang}',
154
155 // text alignment
156 'align-center': '{lang}wcf.editor.alignment.center{/lang}',
157 'align-justify': '{lang}wcf.editor.alignment.justify{/lang}',
158 'align-left': '{lang}wcf.editor.alignment.left{/lang}',
159 'align-right': '{lang}wcf.editor.alignment.right{/lang}',
160
161 // table plugin
162 'add-head': '{lang}wcf.editor.table.addHead{/lang}',
163 'delete-column': '{lang}wcf.editor.table.deleteColumn{/lang}',
164 'delete-head': '{lang}wcf.editor.table.deleteHead{/lang}',
165 'delete-row': '{lang}wcf.editor.table.deleteRow{/lang}',
166 'delete-table': '{lang}wcf.editor.table.deleteTable{/lang}',
167 'insert-table': '{lang}wcf.editor.table.insertTable{/lang}',
168 'insert-column-left': '{lang}wcf.editor.table.insertColumnLeft{/lang}',
169 'insert-column-right': '{lang}wcf.editor.table.insertColumnRight{/lang}',
170 'insert-row-above': '{lang}wcf.editor.table.insertRowAbove{/lang}',
171 'insert-row-below': '{lang}wcf.editor.table.insertRowBelow{/lang}',
172
173 // size
174 'remove-size': '{lang}wcf.editor.button.size.removeSize{/lang}',
175
176 // color
177 'remove-color': '{lang}wcf.editor.button.color.removeColor{/lang}',
178
179 // font
180 'remove-font': '{lang}wcf.editor.button.font.removeFont{/lang}'
181 }
182 },
183 linkify: false,
184 linkSize: 0xBADC0DED, // some random value to disable truncating
185 minHeight: 200,
186 pasteImages: {if $__wcf->getBBCodeHandler()->isAvailableBBCode('img')}true{else}false{/if},
187 pastePlainText: {if !$__wcf->user->userID || $__wcf->user->editorPastePreserveFormatting}false{else}true{/if},
188 plugins: [
189 // Imperavi
190 'alignment',
191 'source',
192 'table',
193
194 // WoltLab specials
195 'WoltLabBlock',
196 'WoltLabEvent',
197 'WoltLabKeydown',
198
199 // WoltLab core
200 'WoltLabAttachment',
201 'WoltLabAutosave',
202 'WoltLabCaret',
203 'WoltLabClean',
204 'WoltLabCode',
205 {if $__wcf->getBBCodeHandler()->isAvailableBBCode('color')}'WoltLabColor',{/if}
206 'WoltLabDragAndDrop',
207 'WoltLabDropdown',
208 {if $__wcf->getBBCodeHandler()->isAvailableBBCode('font')}'WoltLabFont',{/if}
209 'WoltLabFullscreen',
210 {if $__wcf->getBBCodeHandler()->isAvailableBBCode('html')}'WoltLabHtml',{/if}
211 'WoltLabImage',
212 'WoltLabIndent',
213 'WoltLabInlineCode',
214 'WoltLabInsert',
215 'WoltLabLine',
216 {if $__wcf->getBBCodeHandler()->isAvailableBBCode('url')}'WoltLabLink',{/if}
217 'WoltLabList',
218 'WoltLabModal',
219 'WoltLabObserve',
220 'WoltLabPaste',
221 'WoltLabQuote',
222 'WoltLabReply',
223 {if $__wcf->getBBCodeHandler()->isAvailableBBCode('size')}'WoltLabSize',{/if}
224 'WoltLabSmiley',
225 'WoltLabSource',
226 'WoltLabSpoiler',
227 'WoltLabTable',
228 'WoltLabUtils'
229 ],
230 toolbarFixed: false,
231 woltlab: {
232 allowImages: {if $__wcf->getBBCodeHandler()->isAvailableBBCode('img')}true{else}false{/if},
233 attachments: (elDataBool(element, 'disable-attachments') === false),
234 autosave: autosave,
235 allowedInlineStyles: allowedInlineStyles,
236 buttons: buttonOptions,
237 buttonMobile: buttonMobile,
238 customButtons: customButtons,
239 forceSecureImages: {if MESSAGE_FORCE_SECURE_IMAGES}true{else}false{/if},
240 highlighters: highlighters,
241 media: {if $__wcf->session->getPermission('admin.content.cms.canUseMedia')}true{else}false{/if},
242 mediaUrl: '{link controller='Media' id=-123456789 thumbnail='void' forceFrontend=true}{/link}'
243 }
244 };
245
246 // user mentions
247 if (elDataBool(element, 'support-mention')) {
248 config.plugins.push('WoltLabMention');
249 }
250
251 // media
252 {if $__wcf->session->getPermission('admin.content.cms.canUseMedia')}
253 if (disableMedia) {
254 var index = config.buttons.indexOf('woltlabMedia');
255 if (index !== -1) {
256 config.buttons.splice(index, 1);
257 }
258 }
259 else {
260 config.plugins.push('WoltLabMedia');
261 }
262 {/if}
263
264 {if $__redactorConfig|isset}{@$__redactorConfig}{/if}
265 {assign var=__redactorConfig value=''}
266
267 {event name='redactorConfig'}
268
269 // load the button plugin last to ensure all buttons have been initialized
270 // already and we can safely add all icons
271 config.plugins.push('WoltLabButton');
272
273 var content = element.value;
274 element.value = '';
275
276 config.callbacks = config.callbacks || { };
277 config.callbacks.init = function() {
278 // slight delay to allow Redactor to initialize itself
279 window.setTimeout(function() {
280 if (content === '' && Environment.platform() === 'ios') {
281 content = '<p><br></p>';
282 }
283
284 content = UiRedactorMetacode.convertFromHtml(element.id, content);
285
286 var redactor = $(element).data('redactor');
287
288 // set code
289 redactor.code.start(content);
290
291 // set value
292 redactor.core.textarea().val(redactor.clean.onSync(redactor.$editor.html()));
293
294 // work-around for autosave notice being stuck
295 window.setTimeout(function() {
296 var autosaveNotice = elBySel('.redactorAutosaveRestored.active', element.parentNode);
297 if (autosaveNotice) {
298 autosaveNotice.style.setProperty('position', 'static', '');
299
300 // force layout
301 //noinspection BadExpressionStatementJS
302 autosaveNotice.offsetTop;
303
304 autosaveNotice.style.removeProperty('position');
305 }
306 }, 10);
307 }, 10);
308 };
309
310 $(function () {
311 $(element).redactor(config);
312 });
313 });
314 });
315 </script>