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