Hide last authors
Marius Dumitru Florea 3.1 1 {{warning}}
2 The GWT WYSIWYG editor is no longer available starting with XWiki 9.7. It has been replaced by [[CKEditor>>extensions:Extension.CKEditor Integration.WebHome]].
3 {{/warning}}
4
Marius Dumitru Florea 1.1 5 This page will show you how to integrate the WYSIWYG editor in your wiki pages and how to interact with it.
6
Marius Dumitru Florea 2.1 7 {{toc start="2"/}}
8
Marius Dumitru Florea 1.1 9 == Integration ==
10
11 First, include the JavaScript code of the editor in your page like this:
12
13 {{code}}
14 {{velocity}}
15 $xwiki.jsfx.use("js/xwiki/wysiwyg/xwe/XWikiWysiwyg.js", true)
16 {{/velocity}}
17 {{/code}}
18
19 This way the editor code is loaded when your page is loaded. If you want to use the WYSIWYG editor in an AJAX fashion i.e. load its code on demand, asynchronously, then write this instead:
20
21 {{code}}
22 {{velocity}}
23 $xwiki.jsfx.use("js/xwiki/wysiwyg/xwe/XWikiWysiwyg.js", {'forceSkinAction': true, 'lazy': true})
24 {{/velocity}}
25 {{/code}}
26
27 This way the editor code is loaded after your first call to ##Wysiwyg.onModuleLoad##. Note that some WYSIWYG editor plugins might require external JavaScript libraries which you have to include also. Alternatively use the ##wysiwyg_import## velocity macro which takes care of this for you:
28
29 {{code}}
30 {{velocity}}
31 #set($lazy = false)
32 #wysiwyg_import($lazy)
33 {{/velocity}}
34 {{/code}}
35
36 At this point the ##Wysiwyg## object and the ##WysiwygEditor## class should be ready to use.
37
38 {{code}}
39 {{html}}
40 ...
41 <textarea id="demo"></textarea>
42 ...
43 <script type="text/javascript">
44 Wysiwyg.onModuleLoad(function() {
45 new WysiwygEditor({hookId:'demo'});
46 });
47 </script>
48 ...
49 {{/html}}
50 {{/code}}
51
52 The editor can replace a plain HTML text area specified by its id. See the [[configuration>>Extension.GWT WYSIWYG Editor.Configuration.WebHome]] page for a list of parameters that you can pass when creating a new editor instance.
53
54 == JavaScript API ==
55
56 === Wysiwyg ===
57
58 {{code}}
59 Wysiwyg.onModuleLoad(function() {
60 alert('WYSIWYG code is loaded!');
61 });
62 {{/code}}
63
64 **Methods**
65
66 * (% style="background-color:#D9E6F8" %)load() : void(%%)
67 Loads the WYSIWYG code on demand.
68 * (% style="background-color:#D9E6F8" %)onModuleLoad(fCode : function, lazy : boolean) : void(%%)
69 Schedules a function to be executed after the WYSIWYG module is loaded. A call to this method forces the WYSIWYG module to be loaded, unless the second parameter, ##lazy##, is set to ##true##.
70 * (% style="background-color:#D9E6F8" %)getInstance(hookId : String) : WysiwygEditor(%%)
71 Returns the WysiwygEditor instance associated with the given hook identifier, i.e. the editor instance that replaced the element with the specified identifier.
72
73 === WysiwygEditor ===
74
75 {{code}}
76 Wysiwyg.onModuleLoad(function() {
77 editor = new WysiwygEditor({hookId: 'content'});
78 });
79 {{/code}}
80
81 **Methods**
82
83 * (% style="background-color:#D9E6F8" %)WysiwygEditor(config : Object) : WysiwygEditor(%%)
84 Creates a new editor based on the given configuration object.
85 * (% style="background-color:#D9E6F8" %)addActionHandler(actionName : String, handler : function) : function(%%)
86 Registers the given handler for the specified action. The handler function will be called each time the specified action occurs. The returned function can be used to unregister the handler. The handler function receives the action name as parameter.
87 * (% style="background-color:#D9E6F8" %)getCommandManager() : CommandManager(%%)
88 Use the returned object to execute commands on the editor and query their value.
89 * (% style="background-color:#D9E6F8" %)getParameter(parameterName : String) : String(%%)
90 Returns the value of the specified configuration parameter. See the [[WYSIWYG editor configuration page>>Extension.GWT WYSIWYG Editor.Configuration.WebHome]] for a list of available parameters.
91 * (% style="background-color:#D9E6F8" %)getParameterNames() : String[](%%)
92 Returns the list of configuration parameters.
93 * (% style="background-color:#D9E6F8" %)getPlainTextArea() : Object(%%)
94 Returns the plain HTML text area element used by the editor.
95 * (% style="background-color:#D9E6F8" %)getRichTextArea() : Object(%%)
96 Returns the rich text area element used by the editor.
97 * (% style="background-color:#D9E6F8" %)getSelectionRange() : Object(%%)
98 Returns the rich text area's selection range. See ##setSelectionRange(Object)## for details about the returned object.
99 * (% style="background-color:#D9E6F8" %)getSourceText(onSuccess : function, onFailure : function) : void(%%)
100 Sends a request to the server to convert the HTML output of the rich text editor to source text and calls one of the given functions when the response is received.
101 * (% style="background-color:#D9E6F8" %)release() : void(%%)
102 Releases the editor so that it can be garbage collected before the page is unloaded. Call this method before the editor is physically detached from the DOM document.
103 * (% style="background-color:#D9E6F8" %)setFocus(focused : boolean) : void(%%)
104 Focuses or blurs the WYSIWYG editor.
105 * (% style="background-color:#D9E6F8" %)setSelectionRange(range : Object) : void(%%)
106 Sets rich text area's selection range. The range parameter must have these properties: ##startContainer## (the DOM node where the selection starts), ##startOffset## (the offset within the start container), ##endContainer## (the DOM node where the selection ends), ##endOffset## (the offset within the end container). Note that the range parameter follows [[Document Object Model Range>>http://www.w3.org/TR/DOM-Level-2-Traversal-Range/ranges.html]].
107
108 === CommandManager ===
109
110 {{code}}
111 if ( editor.getCommandManager().isEnabled('forecolor') ) {
112 editor.getCommandManager().execute('forecolor', 'yellow');
113 alert( editor.getCommandManager().getValue('forecolor') );
114 }
115 {{/code}}
116
117 **Methods**
118
119 * (% style="background-color:#D9E6F8" %)execute(commandName : String, parameter : String) : boolean(%%)
120 Executes the specified command with the given parameter on the current selection in the rich text area. Returns ##true## if the command was executed successfully, ##false## otherwise.
121 * (% style="background-color:#D9E6F8" %)getValue(commandName : String) : String(%%)
122 Returns the value of the specified command for the current selection in the rich text area.
123 * (% style="background-color:#D9E6F8" %)isEnabled(commandName : String) : boolean(%%)
124 Returns ##true## if the specified command can be executed on the current selection, ##false## otherwise.
125 * (% style="background-color:#D9E6F8" %)isExecuted(commandName : String) : boolean(%%)
126 Returns ##true## if the specified command was executed on the current selection, ##false## otherwise.
127 * (% style="background-color:#D9E6F8" %)isSupported(commandName : String) : boolean(%%)
128 Returns ##true## if the specified command is supported by the editor, ##false## otherwise.
129
130 === Custom events ===
131
132 {{code}}
133 document.observe('xwiki:wysiwyg:created', function(event) {
134 var editor = event.memo.instance;
135 alert('A new WYSIWYG editor has been created!');
136 });
137 {{/code}}
138
139 * (% style="background-color:#FEE6F8" %)xwiki:wysiwyg:created(%%)
140 Fired after a WYSIWYG editor is successfully created.
141 * (% style="background-color:#FEE6F8" %)xwiki:wysiwyg:loaded(%%)
142 Fired after a WYSIWYG editor is successfully loaded.
143 * (% style="background-color:#FEE6F8" %)xwiki:wysiwyg:showingWysiwyg(%%)
144 Fired when the WYSIWYG tab was clicked and the rich text area is about to be reloaded.
145 * (% style="background-color:#FEE6F8" %)xwiki:wysiwyg:showWysiwyg(%%)
146 Fired after the WYSIWYG tab was loaded.
147 * (% style="background-color:#FEE6F8" %)xwiki:wysiwyg:showingSource(%%)
148 Fired when the Source tab was clicked and the source text area is about to be reloaded.
149 * (% style="background-color:#FEE6F8" %)xwiki:wysiwyg:showSource(%%)
150 Fired after the Source tab was loaded.
151
152 The events fired when the WYSIWYG editor is loaded are, in this order: ##xwiki:wysiwyg:created##, ##xwiki:wysiwyg:loaded##, ##xwiki:wysiwyg:showWysiwyg##.
153
154 == Examples ==
155
156 === Spawn basic WYSIWYG in Wiki page ===
157
158 {{code language="none"}}
159 {{velocity}}
160 #set($lazy = false)
161 #wysiwyg_import($lazy)
162 {{/velocity}}
163
164 {{html clean=false}}
165 <textarea id="wysiwyg-demo"></textarea>
166 <script type="text/javascript">
167 document.observe('xwiki:dom:loaded', function () {
168 Wysiwyg.onModuleLoad(function() {
169 new WysiwygEditor({hookId:'wysiwyg-demo'});
170 });
171 });
172 </script>
173 {{/html}}
174 {{/code}}
175
176 === Custom configuration ===
177
178 {{code}}
179 {{velocity}}
180 {{html}}
181 #set($className = 'Blog.BlogPostClass')
182 ## Get the edited document. If you use this code in a sheet, then the edited document is $doc
183 #set($editedDocument = $xwiki.getDocument('Blog.BlogIntroduction'))
184 ## Get the edited object.
185 #set($editedObject = $editedDocument.getObject($className))
186 #set($propertyId = "${className}_0_content")
187 ## Manually output the plain text area that will be replaced by the WYSIWYG editor, instead of calling $editedDocument.display('content')
188 <textarea id="$propertyId">$!escapetool.xml($editedObject.getProperty('content').value)</textarea>
189 #set($parameters = $util.hashMap)
190 ## Get the default configuration parameters.
191 #wysiwyg_storeConfig($parameters $editedDocument $propertyId true)
192 ## Overwrite parameters here.
193 #set($discard = $parameters.put('plugins', '...'))
194 ## Load the WYSIWYG editor with the customized parameters.
195 #wysiwyg_editPropertyCustom($editedDocument $parameters)
196 {{/html}}
197 {{/velocity}}
198 {{/code}}
199
200 === Load on demand and show source text ===
201
202 {{code}}
203 {{velocity}}
204 #if($request.method.equalsIgnoreCase('post'))
205 == Submitted source ==
206
207 $request.getParameter('Blog.BlogPostClass_0_content')
208 #else
209 == Edit blog post ==
210 {{html wiki="true"}}
211 #wysiwyg_import(true)
212 {{html}}
213 <script type="text/javascript">
214 function hideAndShowLoadingAnimation(fieldId) {
215 var field = document.getElementById(fieldId);
216 if (field) {
217 // Hide the element that will be wrapped by the WYSIWYG editor.
218 field.style.visibility = 'hidden';
219 // Show the loading animation.
220 var loading = document.createElement('span');
221 loading.className = 'loading';
222 loading.style.display = 'block';
223 loading.style.position = 'absolute';
224 loading.style.width = field.offsetWidth + 'px';
225 loading.style.height = field.offsetHeight + 'px';
226 field.parentNode.insertBefore(loading, field);
227 // Remove the loading animation after the WYSIWYG module has been loaded.
228 Wysiwyg.onModuleLoad(function() {
229 loading.parentNode.removeChild(loading);
230 });
231 }
232 }
233 function loadOnDemand(fieldId) {
234 hideAndShowLoadingAnimation(fieldId);
235 Wysiwyg.onModuleLoad(function() {
236 Wysiwyg[fieldId] = new WysiwygEditor({
237 hookId: fieldId,
238 syntax: 'xwiki/2.1',
239 displayTabs: true,
240 defaultEditor: 'wysiwyg',
241 inputURL: '$xwiki.getURL('Blog.BlogIntroduction', 'edit', "xpage=wysiwyginput&token=$services.csrf.getToken()")',
242 plugins: 'submit line separator embed text valign list indent history format symbol link image table macro import',
243 menu: '[{"feature": "link", "subMenu":["linkEdit", "linkRemove", "linkWikiPage", "linkAttachment", "|", "linkWebPage", "linkEmail"]}, {"feature":"image", "subMenu":["imageInsertAttached", "imageInsertURL", "imageEdit", "imageRemove"]}, {"feature":"table", "subMenu":["inserttable", "insertcolbefore", "insertcolafter", "deletecol", "|", "insertrowbefore", "insertrowafter", "deleterow", "|", "deletetable"]}, {"feature":"macro", "subMenu":["macroInsert", "macroEdit", "|", "macroRefresh", "|", "macroCollapse", "macroExpand"]}, {"feature":"import", "subMenu":["importOffice"]}]',
244 toolbar: 'bold italic underline strikethrough | subscript superscript | unorderedlist orderedlist | outdent indent | undo redo | format | hr symbol',
245 wiki: 'xwiki',
246 space: 'Blog',
247 page: 'BlogIntroduction'
248 });
249 });
250 }
251 function showSourceText(fieldId) {
252 var editor = Wysiwyg[fieldId];
253 if (!editor) {
254 alert('Source: ' + $(fieldId).value);
255 } else {
256 editor.getSourceText(function onSuccess(result){
257 alert('Source: ' + result);
258 }, function(message) {
259 alert('Error: ' + message);
260 });
261 }
262 }
263 </script>
264 {{/html}}
265 <form action="" method="post">
266 <div>
267 $xwiki.getDocument('Blog.BlogIntroduction').display('content', 'edit')
268 <input type="submit" value="Submit"/>
269 </div>
270 </form>
271 <div>
272 <button onclick="loadOnDemand('Blog.BlogPostClass_0_content'); this.disabled=true">Load Editor</button>
273 <button onclick="showSourceText('Blog.BlogPostClass_0_content')">Show source text</button>
274 </div>
275 {{/html}}
276 #end
277 {{/velocity}}
278 {{/code}}
279
280 === Load on demand using velocity macros ===
281
282 {{code}}
283 {{velocity}}
284 {{html}}
285 ##
286 ## Specify what will be edited.
287 ##
288 #set($editedDocument = $xwiki.getDocument("Blog.BlogIntroduction"))
289 #set($editedProperty = "Blog.BlogPostClass_0_content")
290 ##
291 ## Configure the WYSIWYG editor.
292 ##
293 ## Import the JavaScript code.
294 #wysiwyg_import(true)
295 ## Define the map of parameters to be used to configure the WYSIWYG editor.
296 #set($parameters = {})
297 ## Store the default WYSIWYG editor configuration parameters in the $parameters map.
298 #wysiwyg_storeConfig($parameters $editedDocument $editedProperty false)
299 ## At this point you can customize the default WYSIWYG editor configuration parameters.
300 ##set($discard = $parameters.put('parameterName', 'parameterValue'))
301 ## Write the $parameters map to a JavaScript variable.
302 #wysiwyg_writeConfig("editorConfig" $parameters)
303 {{/html}}
304
305 ##
306 ## Display the content to be edited.
307 ##
308 (% id="preview" %)
309 (((
310 $editedDocument.display('content')
311 )))
312
313 ##
314 ## Hide the edit mode. Display it on demand.
315 ##
316 (% class="hidden" %)
317 (((
318 $editedDocument.display('content', 'edit')
319 )))
320
321 ##
322 ## Load the editor on demand.
323 ##
324 {{html}}
325 <div>
326 <script type="text/javascript">
327 function hideAndShowLoadingAnimation(fieldId) {
328 var field = document.getElementById(fieldId);
329 if (field) {
330 // Hide the element that will be wrapped by the WYSIWYG editor.
331 field.style.visibility = 'hidden';
332 // Show the loading animation.
333 var loading = document.createElement('span');
334 loading.className = 'loading';
335 loading.style.display = 'block';
336 loading.style.position = 'absolute';
337 loading.style.width = field.offsetWidth + 'px';
338 loading.style.height = field.offsetHeight + 'px';
339 field.parentNode.insertBefore(loading, field);
340 // Remove the loading animation after the WYSIWYG module has been loaded.
341 Wysiwyg.onModuleLoad(function() {
342 loading.parentNode.removeChild(loading);
343 });
344 }
345 }
346 function loadOnDemand(config) {
347 $('preview').hide();
348
349 $(config.hookId).up().removeClassName('hidden');
350 // Show the loading animation.
351 hideAndShowLoadingAnimation(config.hookId);
352
353 // Load the editor.
354 Wysiwyg.onModuleLoad(function() {
355 new WysiwygEditor(config);
356 });
357 }
358 </script>
359 <button onclick="loadOnDemand(window.editorConfig); this.disabled=true">Edit</button>
360 </div>
361 {{/html}}
362 {{/velocity}}
363 {{/code}}
364
365 === Edit in-place an object property ===
366
367 {{code}}
368 {{velocity}}
369 ##
370 ## Prepare the edited document/object.
371 ##
372 #set($blogPostReference = $services.model.createDocumentReference($doc.wiki, 'Blog', 'BlogIntroduction'))
373 #set($blogPostDocument = $xwiki.getDocument($blogPostReference))
374 #set($blogPostObject = $blogPostDocument.getObject('Blog.BlogPostClass'))
375 #set($editedPropertyId = 'Blog.BlogPostClass_0_content')
376
377 ##
378 ## View
379 ##
380 == $blogPostObject.getProperty('title').getValue() ==
381
382 (% id="${editedPropertyId}View" %)
383 (((
384 $blogPostObject.getProperty('content').getValue()
385 )))
386
387 ##
388 ## Edit
389 ##
390 {{html}}
391 ## Download the JavaScript files needed by the WYSIWYG editor (lazy=true).
392 #wysiwyg_import(true)
393 ## Download the JavaScript and style sheet for the Save button (AJAX Save).
394 $xwiki.jsfx.use('js/xwiki/actionbuttons/actionButtons.js', true)
395 $xwiki.ssfx.use('js/xwiki/actionbuttons/actionButtons.css', true)
396
397 ## Generate the WYSIWYG editor configuration
398 #set($parameters = $util.hashMap)
399 #wysiwyg_storeConfig($parameters $blogPostDocument $editedPropertyId false)
400 #set($jsVarName = "editorConfig$!{util.generateRandomString(4)}")
401 #wysiwyg_writeConfig($jsVarName $parameters)
402
403 ## Utility JavaScript functions.
404 <script type="text/javascript">
405 ## Map the editor configuration to the edited property id.
406 var WysiwygConfig = WysiwygConfig || {};
407 WysiwygConfig['$editedPropertyId'] = $jsVarName;
408
409 // Hides the text area with the specified id and displays a loading animation until the WYSIWYG editor is fully loaded.
410 function hideAndShowLoadingAnimation(fieldId) {
411 var field = document.getElementById(fieldId);
412 if (field) {
413 // Hide the element that will be wrapped by the WYSIWYG editor.
414 field.style.visibility = 'hidden';
415 // Show the loading animation.
416 var loading = document.createElement('span');
417 loading.className = 'loading';
418 loading.style.display = 'block';
419 loading.style.position = 'absolute';
420 loading.style.width = field.offsetWidth + 'px';
421 loading.style.height = field.offsetHeight + 'px';
422 field.parentNode.insertBefore(loading, field);
423 // Remove the loading animation after the WYSIWYG module has been loaded.
424 Wysiwyg.onModuleLoad(function() {
425 loading.parentNode.removeChild(loading);
426 });
427 }
428 }
429
430 // Hides the content and displays the WYSIWYG editor.
431 function onEdit(fieldId) {
432 $(fieldId + 'View').hide();
433 $(fieldId + 'EditIcon').hide();
434 $(fieldId + 'Edit').show();
435 hideAndShowLoadingAnimation(fieldId);
436 Wysiwyg.onModuleLoad(function() {
437 new WysiwygEditor(WysiwygConfig[fieldId]);
438 });
439 }
440
441 // Hides the WYSIWYG editor and displays the updated content.
442 function onClose(fieldId) {
443 var editor = Wysiwyg.getInstance(fieldId);
444 editor.getSourceText(function(sourceText) {
445 $(fieldId + 'View').update($(fieldId).value);
446 $(fieldId).value = sourceText;
447 editor.release();
448 // Remove the WYSIWYG editor from the document (it was inserted before the plain text area).
449 $(fieldId).previous().remove();
450 $(fieldId + 'View').show();
451 $(fieldId + 'EditIcon').show();
452 $(fieldId + 'Edit').hide();
453 });
454 }
455
456 // Inserts the edit icon at the end of the heading preceding the editable content.
457 function showEditIcon(fieldId) {
458 var editIcon = new Element('img', {"src" : "$xwiki.getSkinFile('icons/silk/pencil.gif')", "title" : "Edit", "alt" : "edit", "id" : fieldId + 'EditIcon'});
459 editIcon.observe('click', onEdit.bind(window, fieldId));
460 $(fieldId + 'View').previous().appendChild(editIcon);
461 }
462
463 // Insert the edit icons and set the action for the cancel buttons.
464 document.observe('xwiki:dom:loaded', function() {
465 showEditIcon('$editedPropertyId');
466
467 $$('.cancel').each(function(item) {
468 var fieldId = item.up('form').down('textarea').id;
469 item.observe('click', function(event) {
470 Event.stop(event);
471 onClose(fieldId);
472 }.bindAsEventListener(window));
473 });
474 });
475
476 // Hides the WYSIWYG editor and displays the updated content after a successful save action.
477 document.observe('xwiki:actions:save', function(event) {
478 if (event.stopped) {
479 return;
480 }
481 var form = $(event.memo.form);
482 var fieldId = form.down('textarea').id;
483 document.observe('xwiki:document:saved', function() {
484 document.stopObserving('xwiki:document:saved', arguments.callee);
485 onClose(fieldId);
486 });
487 });
488 </script>
489 {{/html}}
490
491 {{html wiki="true"}}
492 ## The edit form, hidden at first. It is displayed when the edit icon is clicked.
493 <div id="${editedPropertyId}Edit" style="display:none">
494 <form id="${editedPropertyId}EditForm" action="$blogPostDocument.getURL('save')" method="post" class="xform half">
495 <div class="hidden">
496 <input type="hidden" name="form_token" value="$services.csrf.getToken()" />
497 </div>
498 <div>
499 $blogPostDocument.display('content', 'edit')
500 </div>
501 <div class="buttons">
502 <span class="buttonwrapper"><input type="submit" value="Save" name="action_saveandcontinue" class="button"></span>
503 <span class="buttonwrapper"><button class="button secondary cancel">Cancel</button></span>
504 </div>
505 </form>
506 </div>
507 {{/html}}
508 {{/velocity}}
509 {{/code}}
510
511 === Adjust the editor UI from a JavaScript Extension ===
512
513 {{code}}
514 // Starting with XWiki 2.4 we can listen to 'xwiki:wysiwyg:loaded'
515 // event directly but this code was written to work with XWiki 2.1
516 Event.observe(document, 'xwiki:wysiwyg:created', function(event) {
517 var editor = event.memo.instance;
518 var iframe = editor.getRichTextArea();
519 Event.observe(iframe, 'load', function() {
520 Event.stopObserving(iframe, 'load', arguments.callee);
521 var toolBar = Element.previous(iframe, '.xToolbar');
522 // We expect the title list box to be the first one on the tool bar.
523 var titleSelect = Element.down(toolBar, 'select');
524 var replace = function(value, newLabel) {
525 for(var i=0; i<titleSelect.length; i++) {
526 if (titleSelect.options[i].value == value) {
527 titleSelect.options[i].text = newLabel;
528 break;
529 }
530 }
531 };
532 replace('h5', 'Custom 5');
533 replace('h6', 'Custom 6');
534 });
535 });
536 {{/code}}
537
538 === Use the WYSIWYG editor outside XWiki ===
539
540 {{code}}
541 <?xml version="1.0" encoding="UTF-8" ?>
542 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
543 "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
544 <html xmlns="http://www.w3.org/1999/xhtml" lang="en" xml:lang="en">
545 <head>
546 <title>WYSIWYG Editor Demo</title>
547 <script type="text/javascript" src="xwe/xwe.nocache.js"></script>
548 </head>
549 <body>
550 <form action="" method="post">
551 <dl>
552 <dt><label for="content">Content</label></dt>
553 <dd><textarea id="content">initial content</textarea></dd>
554 </dl>
555 <script type="text/javascript">
556 document.addEventListener('load', function() {
557 document.removeEventListener('load', arguments.callee, true);
558 var tryCounter = 10;
559 (function() {
560 // The load event is sometimes fired before the external JavaScript code is fully evaluated.
561 if (typeof WysiwygEditor != 'undefined') {
562 new WysiwygEditor({hookId: 'content'});
563 } else if (tryCounter-- > 0) {
564 setTimeout(arguments.callee, 100);
565 }
566 })();
567 }, true);
568 </script>
569 </form>
570 </body>
571 </html>
572 {{/code}}

Get Connected