001/*
002 * This library is part of OpenCms -
003 * the Open Source Content Management System
004 *
005 * Copyright (C) Alkacon Software (http://www.alkacon.com)
006 *
007 * This library is free software; you can redistribute it and/or
008 * modify it under the terms of the GNU Lesser General Public
009 * License as published by the Free Software Foundation; either
010 * version 2.1 of the License, or (at your option) any later version.
011 *
012 * This library is distributed in the hope that it will be useful,
013 * but WITHOUT ANY WARRANTY; without even the implied warranty of
014 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
015 * Lesser General Public License for more details.
016 *
017 * For further information about Alkacon Software, please see the
018 * company website: http://www.alkacon.com
019 *
020 * For further information about OpenCms, please see the
021 * project website: http://www.opencms.org
022 *
023 * You should have received a copy of the GNU Lesser General Public
024 * License along with this library; if not, write to the Free Software
025 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
026 */
027
028package org.opencms.acacia.client.widgets;
029
030import org.opencms.acacia.client.CmsEditorBase;
031import org.opencms.acacia.client.css.I_CmsLayoutBundle;
032import org.opencms.gwt.client.CmsCoreProvider;
033import org.opencms.gwt.client.util.CmsDomUtil;
034import org.opencms.gwt.client.util.CmsDomUtil.Style;
035
036import com.google.gwt.core.client.JavaScriptObject;
037import com.google.gwt.core.client.Scheduler;
038import com.google.gwt.core.client.Scheduler.ScheduledCommand;
039import com.google.gwt.dom.client.Document;
040import com.google.gwt.dom.client.Element;
041import com.google.gwt.dom.client.NativeEvent;
042import com.google.gwt.event.dom.client.ClickEvent;
043import com.google.gwt.event.dom.client.ClickHandler;
044import com.google.gwt.event.dom.client.DomEvent;
045import com.google.gwt.event.logical.shared.HasResizeHandlers;
046import com.google.gwt.event.logical.shared.ResizeEvent;
047import com.google.gwt.event.logical.shared.ResizeHandler;
048import com.google.gwt.event.logical.shared.ValueChangeEvent;
049import com.google.gwt.event.logical.shared.ValueChangeHandler;
050import com.google.gwt.event.shared.HandlerRegistration;
051import com.google.gwt.user.client.DOM;
052
053/**
054 * This class is used to start TinyMCE for editing the content of an element.<p>
055 *
056 * After constructing the instance, the actual editor is opened using the init() method, and destroyed with the close()
057 * method. While the editor is opened, the edited contents can be accessed using the methods of the HasValue interface.
058 */
059public final class CmsTinyMCEWidget extends A_CmsEditWidget implements HasResizeHandlers, I_CmsHasDisplayDirection {
060
061    /** Use as option to disallow any HTML or formatting the content. */
062    public static final String NO_HTML_EDIT = "no_html_edit";
063
064    /** The disabled style element id. */
065    private static final String DISABLED_STYLE_ID = "editorDisabledStyle";
066
067    /** The minimum editor height. */
068    private static final int MIN_EDITOR_HEIGHT = 70;
069
070    /** A flag which indicates whether the editor is currently active. */
071    protected boolean m_active;
072
073    /** The current content. */
074    protected String m_currentContent;
075
076    /** The TinyMCE editor instance. */
077    protected JavaScriptObject m_editor;
078
079    /** The DOM ID of the editable element. */
080    protected String m_id;
081
082    /** The original HTML content of the editable element. */
083    protected String m_originalContent;
084
085    /** The maximal width of the widget. */
086    protected int m_width;
087
088    /** The editor height to set. */
089    int m_editorHeight;
090
091    /** Flag indicating the editor has been initialized. */
092    boolean m_initialized;
093
094    /** The element to store the widget content in. */
095    private Element m_contentElement;
096
097    /** Indicates the value has been set from external, not from within the widget. */
098    private boolean m_externalValueChange;
099
100    /** Indicating if the widget has been attached yet. */
101    private boolean m_hasBeenAttached;
102
103    /** Flag indicating if in line editing is used. */
104    private boolean m_inline;
105
106    /** The editor options. */
107    private Object m_options;
108
109    /**
110     * Creates a new instance for the given element. Use this constructor for in line editing.<p>
111     *
112     * @param element the DOM element
113     * @param options the tinyMCE editor options to extend the default settings
114     */
115    public CmsTinyMCEWidget(Element element, Object options) {
116
117        this(element, options, true);
118    }
119
120    /**
121     * Creates a new instance with the given options. Use this constructor for form based editing.<p>
122     *
123     * @param options the tinyMCE editor options to extend the default settings
124     */
125    public CmsTinyMCEWidget(Object options) {
126
127        this(DOM.createDiv(), options, false);
128    }
129
130    /**
131     * Constructor.<p>
132     *
133     * @param element the DOM element
134     * @param options the tinyMCE editor options to extend the default settings
135     * @param inline flag indicating if in line editing is used
136     */
137    private CmsTinyMCEWidget(Element element, Object options, boolean inline) {
138
139        super(element);
140        m_originalContent = "";
141        m_options = options;
142        m_active = true;
143        m_inline = inline;
144        if (m_inline) {
145            m_contentElement = element;
146        } else {
147            // using a child DIV as content element
148            m_contentElement = getElement().appendChild(DOM.createDiv());
149        }
150    }
151
152    /**
153     * Returns the disabled text color.<p>
154     *
155     * @return the disabled text color
156     */
157    private static String getDisabledTextColor() {
158
159        return I_CmsLayoutBundle.INSTANCE.constants().css().textColorDisabled();
160    }
161
162    /**
163     * @see com.google.gwt.event.logical.shared.HasResizeHandlers#addResizeHandler(com.google.gwt.event.logical.shared.ResizeHandler)
164     */
165    public HandlerRegistration addResizeHandler(ResizeHandler handler) {
166
167        return addHandler(handler, ResizeEvent.getType());
168    }
169
170    /**
171     * @see org.opencms.acacia.client.widgets.A_CmsEditWidget#addValueChangeHandler(com.google.gwt.event.logical.shared.ValueChangeHandler)
172     */
173    @Override
174    public HandlerRegistration addValueChangeHandler(ValueChangeHandler<String> handler) {
175
176        return addHandler(handler, ValueChangeEvent.getType());
177    }
178
179    /**
180     * @see org.opencms.acacia.client.widgets.I_CmsHasDisplayDirection#getDisplayingDirection()
181     */
182    public Direction getDisplayingDirection() {
183
184        return Direction.above;
185    }
186
187    /**
188     * Gets the main editable element.<p>
189     *
190     * @return the editable element
191     */
192    public Element getMainElement() {
193
194        return m_contentElement;
195    }
196
197    /**
198     * @see com.google.gwt.user.client.ui.HasValue#getValue()
199     */
200    @Override
201    public String getValue() {
202
203        if (m_editor != null) {
204            return getContent().trim();
205        }
206        return m_originalContent.trim();
207    }
208
209    /**
210     * @see org.opencms.acacia.client.widgets.I_CmsEditWidget#isActive()
211     */
212    public boolean isActive() {
213
214        return m_active;
215    }
216
217    /**
218     * @see org.opencms.acacia.client.widgets.I_CmsEditWidget#setActive(boolean)
219     */
220    public void setActive(boolean active) {
221
222        if (m_active == active) {
223            return;
224        }
225        m_active = active;
226        if (m_editor != null) {
227            if (m_active) {
228                getElement().removeClassName(I_CmsLayoutBundle.INSTANCE.form().inActive());
229                removeEditorDisabledStyle();
230                fireValueChange(true);
231            } else {
232                getElement().addClassName(I_CmsLayoutBundle.INSTANCE.form().inActive());
233                setEditorDisabledStyle();
234            }
235        }
236    }
237
238    /**
239     * @see org.opencms.acacia.client.widgets.I_CmsEditWidget#setName(java.lang.String)
240     */
241    public void setName(String name) {
242
243        // no input field so nothing to do
244
245    }
246
247    /**
248     * @see com.google.gwt.user.client.ui.HasValue#setValue(java.lang.Object)
249     */
250    public void setValue(String value) {
251
252        setValue(value, false);
253    }
254
255    /**
256     * @see com.google.gwt.user.client.ui.HasValue#setValue(java.lang.Object, boolean)
257     */
258    public void setValue(String value, boolean fireEvents) {
259
260        if (value != null) {
261            value = value.trim();
262        }
263        setPreviousValue(value);
264        if (m_editor == null) {
265            // editor has not been initialized yet
266            m_originalContent = value;
267        } else {
268            m_externalValueChange = true;
269            setContent(value);
270        }
271        if (fireEvents) {
272            fireValueChange(true);
273        }
274    }
275
276    /**
277     * Checks whether the necessary Javascript libraries are available by accessing them.
278     */
279    protected native void checkLibraries() /*-{
280                // fail early if tinymce is not available
281                var w = $wnd;
282                var init = w.tinyMCE.init;
283    }-*/;
284
285    /**
286     * Gives an element an id if it doesn't already have an id, and then returns the element's id.<p>
287     *
288     * @param element the element for which we want to add the id
289     *
290     * @return the id
291     */
292    protected String ensureId(Element element) {
293
294        String id = element.getId();
295        if ((id == null) || "".equals(id)) {
296            id = Document.get().createUniqueId();
297            element.setId(id);
298        }
299        return id;
300    }
301
302    /**
303     * Returns the editor parent element.<p>
304     *
305     * @return the editor parent element
306     */
307    protected Element getEditorParentElement() {
308
309        String parentId = m_id + "_parent";
310        Element result = getElementById(parentId);
311        return result;
312    }
313
314    /**
315     * Gets an element by its id.<p>
316     *
317     * @param id the id
318     * @return the element with the given id
319     */
320    protected native Element getElementById(String id) /*-{
321                return $doc.getElementById(id);
322    }-*/;
323
324    /**
325     * Gets the toolbar element.<p>
326     *
327     * @return the toolbar element
328     */
329    protected Element getToolbarElement() {
330
331        String toolbarId = m_id + "_external";
332        Element result = getElementById(toolbarId);
333        return result;
334    }
335
336    /**
337     * Returns if the widget is used in inline mode.<p>
338     *
339     * @return <code>true</code> if the widget is used in inline mode
340     */
341    protected boolean isInline() {
342
343        return m_inline;
344    }
345
346    /**
347     * @see com.google.gwt.user.client.ui.FocusWidget#onAttach()
348     */
349    @Override
350    protected void onAttach() {
351
352        super.onAttach();
353        if (!m_hasBeenAttached) {
354            m_hasBeenAttached = true;
355            Scheduler.get().scheduleDeferred(new ScheduledCommand() {
356
357                public void execute() {
358
359                    if (isAttached()) {
360                        m_editorHeight = calculateEditorHeight();
361                        m_id = ensureId(getMainElement());
362                        m_width = calculateWidth();
363                        checkLibraries();
364                        if (isInline()) {
365                            if (CmsDomUtil.getCurrentStyleInt(getElement(), Style.zIndex) < 1) {
366                                getElement().getStyle().setZIndex(1);
367                            }
368                            addDomHandler(new ClickHandler() {
369
370                                public void onClick(ClickEvent event) {
371
372                                    // prevent event propagation while editing inline, to avoid following links in ancestor nodes
373                                    event.stopPropagation();
374                                    event.preventDefault();
375                                }
376                            }, ClickEvent.getType());
377                        }
378                        initNative(CmsCoreProvider.get().getWpLanguage());
379                        if (!m_active) {
380                            getElement().addClassName(I_CmsLayoutBundle.INSTANCE.form().inActive());
381                        }
382                    } else {
383                        resetAtachedFlag();
384                    }
385                }
386            });
387        }
388    }
389
390    /**
391     * @see com.google.gwt.user.client.ui.Widget#onDetach()
392     */
393    @Override
394    protected void onDetach() {
395
396        try {
397            detachEditor();
398        } catch (Throwable t) {
399            // may happen in rare cases, can be ignored
400        }
401        super.onDetach();
402    }
403
404    /**
405     * Propagates the a focus event.<p>
406     */
407    protected void propagateFocusEvent() {
408
409        if (m_initialized) {
410            NativeEvent nativeEvent = Document.get().createFocusEvent();
411            DomEvent.fireNativeEvent(nativeEvent, this, getElement());
412        }
413    }
414
415    /**
416     * Propagates a native mouse event.<p>
417     *
418     * @param eventType the mouse event type
419     * @param eventSource the event source
420     */
421    protected native void propagateMouseEvent(String eventType, Element eventSource) /*-{
422                var doc = $wnd.document;
423                var event;
424                if (doc.createEvent) {
425                        event = doc.createEvent("MouseEvents");
426                        event.initEvent(eventType, true, true);
427                        eventSource.dispatchEvent(event);
428                } else {
429                        eventSource.fireEvent("on" + eventType);
430                }
431    }-*/;
432
433    /**
434     * Removes the editor instance.<p>
435     */
436    protected native void removeEditor() /*-{
437                var editor = this.@org.opencms.acacia.client.widgets.CmsTinyMCEWidget::m_editor;
438                editor.remove();
439    }-*/;
440
441    /**
442     * Sets the main content of the element which is inline editable.<p>
443     *
444     * @param html the new content html
445     */
446    protected native void setMainElementContent(String html) /*-{
447                var instance = this;
448                var elementId = instance.@org.opencms.acacia.client.widgets.CmsTinyMCEWidget::m_id;
449                var mainElement = $wnd.document.getElementById(elementId);
450                mainElement.innerHTML = html;
451    }-*/;
452
453    /**
454     * Checks if the main element contains the current text selection.<p>
455     *
456     * @return <code>true</code> if the main element contains the current text selection
457     */
458    protected boolean shouldReceiveFocus() {
459
460        return m_inline && CmsEditorBase.shouldFocusOnInlineEdit(getElement());
461    }
462
463    /**
464     * Calculates the needed editor height.<p>
465     *
466     * @return the calculated editor height
467     */
468    int calculateEditorHeight() {
469
470        int result = getElement().getOffsetHeight() + 30;
471        return result > MIN_EDITOR_HEIGHT ? result : MIN_EDITOR_HEIGHT;
472    }
473
474    /**
475     * Calculates the widget width.<p>
476     *
477     * @return the widget width
478     */
479    int calculateWidth() {
480
481        int result;
482        if (m_inline && CmsDomUtil.getCurrentStyle(getElement(), Style.display).equals("inline")) {
483            com.google.gwt.dom.client.Element parentBlock = getElement().getParentElement();
484            while (CmsDomUtil.getCurrentStyle(parentBlock, Style.display).equals("inline")) {
485                parentBlock = parentBlock.getParentElement();
486            }
487            result = parentBlock.getOffsetWidth();
488        } else {
489            result = getElement().getOffsetWidth();
490        }
491        return result - 2;
492    }
493
494    /**
495     * Initializes the TinyMCE instance.
496     *
497     * @param locale the UI locale
498     */
499    native void initNative(String locale) /*-{
500
501                function merge() {
502                        var result = {}, length = arguments.length;
503                        for (i = 0; i < length; i++) {
504                                for (key in arguments[i]) {
505                                        if (arguments[i].hasOwnProperty(key)) {
506                                                result[key] = arguments[i][key];
507                                        }
508                                }
509                        }
510                        return result;
511                }
512
513
514        var languageMap = { "it": "it_IT", "cs": "cs_CZ", "ru": "ru_RU", "zh": "zh_CN"};
515        var translatedLanguage = languageMap[locale];
516        if (translatedLanguage) {
517            locale = translatedLanguage;
518        }
519
520
521
522                var self = this;
523                var needsRefocus = self.@org.opencms.acacia.client.widgets.CmsTinyMCEWidget::shouldReceiveFocus()();
524                var elementId = self.@org.opencms.acacia.client.widgets.CmsTinyMCEWidget::m_id;
525                var mainElement = $wnd.document.getElementById(elementId);
526                var editorHeight = self.@org.opencms.acacia.client.widgets.CmsTinyMCEWidget::m_editorHeight;
527
528                var fireChange = function() {
529                        self.@org.opencms.acacia.client.widgets.CmsTinyMCEWidget::fireChangeFromNative()();
530                };
531                var options = this.@org.opencms.acacia.client.widgets.CmsTinyMCEWidget::m_options;
532                if (options != null && options.editorHeight) {
533                        editorHeight = options.editorHeight;
534                        delete options.editorHeight;
535                }
536                // default options:
537                var defaults;
538                if (@org.opencms.acacia.client.widgets.CmsTinyMCEWidget::NO_HTML_EDIT == options) {
539                        // disallow any formatting
540                        defaults = {
541                                selector : mainElement.tagName + "#" + elementId,
542                                entity_encoding : "raw",
543                                mode : "exact",
544                                theme : "silver",
545                                plugins : "paste",
546                                paste_as_text : true,
547                                toolbar : "undo redo",
548                                menubar : false,
549                                forced_root_block : false
550                        };
551                        options = null;
552                } else {
553                        defaults = {
554                                selector : mainElement.tagName + "#" + elementId,
555                                relative_urls : false,
556                                remove_script_host : false,
557                                entity_encoding : "raw",
558                                skin_variant : 'ocms',
559                                mode : "exact",
560                                theme : "silver",
561                                plugins : "autolink lists pagebreak table save codemirror hr image link emoticons spellchecker insertdatetime preview media searchreplace print paste directionality noneditable visualchars nonbreaking template wordcount advlist",
562                                paste_as_text : true,
563                                menubar : false,
564                        };
565                }
566                if (this.@org.opencms.acacia.client.widgets.CmsTinyMCEWidget::m_inline) {
567                        self.@org.opencms.acacia.client.widgets.CmsTinyMCEWidget::m_currentContent = mainElement.innerHTML;
568                        defaults.inline = true;
569                        defaults.width = this.@org.opencms.acacia.client.widgets.CmsTinyMCEWidget::m_width;
570                } else {
571                        self.@org.opencms.acacia.client.widgets.CmsTinyMCEWidget::m_currentContent = self.@org.opencms.acacia.client.widgets.CmsTinyMCEWidget::m_originalContent;
572                        defaults.min_height = 100;
573                        defaults.max_height = editorHeight;
574                        defaults.width = '100%';
575                        defaults.resize = 'both';
576                }
577                // extend the defaults with any given options
578                if (options != null) {
579                        if (options.style_formats) {
580                                // tinymce performs a type test for arrays wich fails in case the array was not created in the same window context
581                                var formats = new $wnd.Array();
582                                for (var i = 0; i < options.style_formats.length; i++) {
583                                        formats[i] = options.style_formats[i];
584                                }
585                                options.style_formats = formats;
586                        }
587                        defaults = merge(defaults, options);
588                }
589                if (this.@org.opencms.acacia.client.widgets.CmsTinyMCEWidget::m_inline) {
590                        delete defaults.content_css;
591                } else {
592                        // enable autoresize
593                        defaults.plugins = "autoresize " + defaults.plugins;
594                }
595                if (needsRefocus) {
596                        defaults.auto_focus = elementId;
597                }
598
599                // add the setup function
600                defaults.setup = function(ed) {
601                        self.@org.opencms.acacia.client.widgets.CmsTinyMCEWidget::m_editor = ed;
602                        ed.on('SetContent', fireChange);
603                        ed.on('change', fireChange);
604                        ed.on('KeyDown', fireChange);
605                        ed
606                                        .on(
607                                                        'LoadContent',
608                                                        function() {
609                                                                if (!self.@org.opencms.acacia.client.widgets.CmsTinyMCEWidget::m_inline) {
610                                                                        // firing resize event on resize of the editor iframe
611                                                                        ed.dom
612                                                                                        .bind(
613                                                                                                        ed.getWin(),
614                                                                                                        'resize',
615                                                                                                        function() {
616                                                                                                                self.@org.opencms.acacia.client.widgets.CmsTinyMCEWidget::fireResizeEvent()();
617                                                                                                        });
618                                                                        var content = self.@org.opencms.acacia.client.widgets.CmsTinyMCEWidget::m_originalContent;
619                                                                        if (content != null) {
620                                                                                ed.setContent(content);
621                                                                        }
622                                                                }
623                                                        });
624                        ed
625                                        .on(
626                                                        'init',
627                                                        function() {
628                                                                self.@org.opencms.acacia.client.widgets.CmsTinyMCEWidget::scheduleInitializationDone()();
629                                                        });
630
631                        if (!self.@org.opencms.acacia.client.widgets.CmsTinyMCEWidget::m_inline) {
632
633                                ed
634                                                .on(
635                                                                'Click',
636                                                                function(event) {
637                                                                        self.@org.opencms.acacia.client.widgets.CmsTinyMCEWidget::propagateFocusEvent()();
638                                                                });
639                                ed
640                                                .on(
641                                                                'activate',
642                                                                function(event) {
643                                                                        self.@org.opencms.acacia.client.widgets.CmsTinyMCEWidget::propagateFocusEvent()();
644                                                                });
645                                ed
646                                                .on(
647                                                                'focus',
648                                                                function(event) {
649                                                                        self.@org.opencms.acacia.client.widgets.CmsTinyMCEWidget::propagateFocusEvent()();
650                                                                });
651                        }
652                };
653
654                // initialize tinyMCE
655                defaults.language = locale;
656                $wnd.tinymce.init(defaults);
657    }-*/;
658
659    /**
660     * Removes the disabled editor styling.<p>
661     */
662    native void removeEditorDisabledStyle()/*-{
663                var ed = this.@org.opencms.acacia.client.widgets.CmsTinyMCEWidget::m_editor;
664                var styleEl = ed
665                                .getDoc()
666                                .getElementById(
667                                                @org.opencms.acacia.client.widgets.CmsTinyMCEWidget::DISABLED_STYLE_ID);
668                if (styleEl != null) {
669                        ed.getDoc().head.removeChild(styleEl);
670                }
671    }-*/;
672
673    /**
674     * Resets the attached flag.<p>
675     */
676    void resetAtachedFlag() {
677
678        m_hasBeenAttached = false;
679    }
680
681    /**
682     * Scheduling to set the initialized flag.<p>
683     */
684    void scheduleInitializationDone() {
685
686        Scheduler.get().scheduleDeferred(new ScheduledCommand() {
687
688            public void execute() {
689
690                m_initialized = true;
691                if (m_active) {
692                    removeEditorDisabledStyle();
693                } else {
694                    setEditorDisabledStyle();
695                }
696            }
697        });
698    }
699
700    /**
701     * Sets the editor disabled styling.<p>
702     */
703    native void setEditorDisabledStyle()/*-{
704                var ed = this.@org.opencms.acacia.client.widgets.CmsTinyMCEWidget::m_editor;
705                if (ed
706                                .getDoc()
707                                .getElementById(
708                                                @org.opencms.acacia.client.widgets.CmsTinyMCEWidget::DISABLED_STYLE_ID) == null) {
709                        var styleEl = ed.getDoc().createElement("style");
710                        styleEl
711                                        .setAttribute("id",
712                                                        @org.opencms.acacia.client.widgets.CmsTinyMCEWidget::DISABLED_STYLE_ID);
713                        var styleText = ed
714                                        .getDoc()
715                                        .createTextNode(
716                                                        "body, body *{ color: "
717                                                                        + @org.opencms.acacia.client.widgets.CmsTinyMCEWidget::getDisabledTextColor()()
718                                                                        + " !important;}");
719                        styleEl.appendChild(styleText);
720                        ed.getDoc().head.appendChild(styleEl);
721                }
722    }-*/;
723
724    /**
725     * Removes the editor.<p>
726     */
727    private native void detachEditor() /*-{
728
729                var ed = this.@org.opencms.acacia.client.widgets.CmsTinyMCEWidget::m_editor;
730                if (ed != null) {
731                        ed.remove();
732                }
733                // in IE somehow the whole document will be selected, empty the selection to resolve that
734                if ($wnd.document.selection != null) {
735                        $wnd.document.selection.empty();
736                }
737    }-*/;
738
739    /**
740     * Used to fire the value changed event from native code.<p>
741     */
742    private void fireChangeFromNative() {
743
744        // skip firing the change event, if the external flag is set
745        if (m_initialized && !m_externalValueChange && m_active) {
746            Scheduler.get().scheduleDeferred(new ScheduledCommand() {
747
748                public void execute() {
749
750                    try {
751                        fireValueChange(false);
752                    } catch (Throwable t) {
753                        // this may happen when returning from full screen mode, nothing to be done
754                    }
755                }
756            });
757        }
758        // reset the external flag
759        m_externalValueChange = false;
760    }
761
762    /**
763     * Fires the resize event.<p>
764     */
765    private void fireResizeEvent() {
766
767        ResizeEvent.fire(this, getOffsetWidth(), getOffsetHeight());
768    }
769
770    /**
771     * Returns the editor content.<p>
772     *
773     * @return the editor content
774     */
775    private native String getContent() /*-{
776                var editor = this.@org.opencms.acacia.client.widgets.CmsTinyMCEWidget::m_editor;
777                return editor.getContent();
778    }-*/;
779
780    /**
781     * Sets the content of the TinyMCE editor.<p>
782     *
783     * @param newContent the new content
784     */
785    private native void setContent(String newContent) /*-{
786                var editor = this.@org.opencms.acacia.client.widgets.CmsTinyMCEWidget::m_editor;
787                editor.setContent(newContent);
788    }-*/;
789
790}