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