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