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;
029
030import org.opencms.acacia.client.css.I_CmsLayoutBundle;
031import org.opencms.acacia.client.entity.CmsEntityBackend;
032import org.opencms.acacia.shared.CmsContentDefinition;
033import org.opencms.acacia.shared.CmsEntity;
034import org.opencms.acacia.shared.CmsEntityAttribute;
035import org.opencms.acacia.shared.CmsTabInfo;
036import org.opencms.gwt.client.ui.CmsTabbedPanel;
037import org.opencms.gwt.shared.CmsGwtConstants;
038
039import java.util.List;
040
041import com.google.gwt.core.client.JavaScriptObject;
042import com.google.gwt.dom.client.Element;
043import com.google.gwt.json.client.JSONObject;
044import com.google.gwt.json.client.JSONParser;
045import com.google.gwt.user.client.ui.FlowPanel;
046import com.google.gwt.user.client.ui.Panel;
047
048/**
049 * CmsRenderer which delegates the rendering of an entity to native Javascript.
050 *
051 * This renderer will interpret its configuration string as a JSON object (which we will call 'config').
052 * To render an entity, it will take the name of a function from config.render and then call the function
053 * with the entity to render, the parent element, a VIE wrapper, and the configuration object as parameters.
054 */
055public class CmsNativeComplexWidgetRenderer implements I_CmsEntityRenderer {
056
057    /** The entity CSS class. */
058    public static final String ENTITY_CLASS = I_CmsLayoutBundle.INSTANCE.form().entity();
059
060    /** The attribute label CSS class. */
061    public static final String LABEL_CLASS = I_CmsLayoutBundle.INSTANCE.form().label();
062
063    /** The widget holder CSS class. */
064    public static final String WIDGET_HOLDER_CLASS = I_CmsLayoutBundle.INSTANCE.form().widgetHolder();
065
066    /** The configuration string. */
067    private String m_configuration;
068
069    /** The parsed JSON value from the configuration string. */
070    private JSONObject m_jsonConfig;
071
072    /** The native renderer instance. */
073    private JavaScriptObject m_nativeInstance;
074
075    /**
076     * Default constructor.<p>
077     */
078    public CmsNativeComplexWidgetRenderer() {
079
080    }
081
082    /**
083     * Creates a new configured instance.<p>
084     *
085     * @param configuration the configuration string
086     */
087    public CmsNativeComplexWidgetRenderer(String configuration) {
088
089        m_configuration = configuration;
090        m_jsonConfig = JSONParser.parseLenient(configuration).isObject();
091    }
092
093    /**
094     * @see org.opencms.acacia.client.I_CmsEntityRenderer#configure(java.lang.String)
095     */
096    public CmsNativeComplexWidgetRenderer configure(String configuration) {
097
098        return new CmsNativeComplexWidgetRenderer(configuration);
099    }
100
101    /**
102     * @see org.opencms.acacia.client.I_CmsEntityRenderer#getName()
103     */
104    public String getName() {
105
106        return CmsContentDefinition.NATIVE_RENDERER;
107    }
108
109    /**
110     * @see org.opencms.acacia.client.I_CmsEntityRenderer#renderAttributeValue(org.opencms.acacia.shared.CmsEntity, org.opencms.acacia.client.CmsAttributeHandler, int, com.google.gwt.user.client.ui.Panel)
111     */
112    public void renderAttributeValue(
113        CmsEntity parentEntity,
114        CmsAttributeHandler attributeHandler,
115        int attributeIndex,
116        Panel context) {
117
118        notSupported();
119    }
120
121    /**
122     * @see org.opencms.acacia.client.I_CmsEntityRenderer#renderForm(org.opencms.acacia.shared.CmsEntity, java.util.List, com.google.gwt.user.client.ui.Panel, org.opencms.acacia.client.I_CmsAttributeHandler, int)
123     */
124    public CmsTabbedPanel<FlowPanel> renderForm(
125        CmsEntity entity,
126        List<CmsTabInfo> tabInfos,
127        Panel context,
128        I_CmsAttributeHandler parentHandler,
129        int attributeIndex) {
130
131        throw new UnsupportedOperationException("Custom renderer does not support tabs!");
132
133    }
134
135    /**
136     * @see org.opencms.acacia.client.I_CmsEntityRenderer#renderForm(org.opencms.acacia.shared.CmsEntity, com.google.gwt.user.client.ui.Panel, org.opencms.acacia.client.I_CmsAttributeHandler, int)
137     */
138    public void renderForm(
139        final CmsEntity entity,
140        Panel context,
141        final I_CmsAttributeHandler parentHandler,
142        final int attributeIndex) {
143
144        context.addStyleName(ENTITY_CLASS);
145        context.getElement().setAttribute("typeof", entity.getTypeName());
146        context.getElement().setAttribute(CmsGwtConstants.ATTR_DATA_ID, entity.getId());
147        String initFunction = CmsContentDefinition.FUNCTION_RENDER_FORM;
148        renderNative(
149            getNativeInstance(),
150            initFunction,
151            context.getElement(),
152            entity,
153            m_jsonConfig.isObject().getJavaScriptObject());
154    }
155
156    /**
157     * @see org.opencms.acacia.client.I_CmsEntityRenderer#renderInline(org.opencms.acacia.shared.CmsEntity, org.opencms.acacia.client.I_CmsInlineFormParent, org.opencms.acacia.client.I_CmsInlineHtmlUpdateHandler, org.opencms.acacia.client.I_CmsAttributeHandler, int)
158     */
159    public void renderInline(
160        CmsEntity entity,
161        I_CmsInlineFormParent formParent,
162        I_CmsInlineHtmlUpdateHandler updateHandler,
163        I_CmsAttributeHandler parentHandler,
164        int attributeIndex) {
165
166        notSupported();
167    }
168
169    /**
170     * @see org.opencms.acacia.client.I_CmsEntityRenderer#renderInline(org.opencms.acacia.shared.CmsEntity, java.lang.String, org.opencms.acacia.client.I_CmsInlineFormParent, org.opencms.acacia.client.I_CmsInlineHtmlUpdateHandler, org.opencms.acacia.client.I_CmsAttributeHandler, int, int, int)
171     */
172    public void renderInline(
173        CmsEntity parentEntity,
174        String attributeName,
175        I_CmsInlineFormParent formParent,
176        I_CmsInlineHtmlUpdateHandler updateHandler,
177        I_CmsAttributeHandler parentHandler,
178        int attributeIndex,
179        int minOccurrence,
180        int maxOccurrence) {
181
182        CmsEntityAttribute attribute = parentEntity.getAttribute(attributeName);
183        String renderInline = CmsContentDefinition.FUNCTION_RENDER_INLINE;
184        if (attribute != null) {
185            List<CmsEntity> values = attribute.getComplexValues();
186            List<Element> elements = CmsEntityBackend.getInstance().getAttributeElements(
187                parentEntity,
188                attributeName,
189                formParent.getElement());
190            for (int i = 0; i < elements.size(); i++) {
191                Element element = elements.get(i);
192                if (i < values.size()) {
193                    CmsEntity value = values.get(i);
194                    renderNative(getNativeInstance(), renderInline, element, value, m_jsonConfig.getJavaScriptObject());
195                }
196            }
197        }
198    }
199
200    /**
201     * Creates the native renderer instance.<p>
202     *
203     * @param initCall the name of the native function which creates the native renderer instance
204     *
205     * @return the native renderer instance
206     */
207    protected native JavaScriptObject createNativeInstance(String initCall) /*-{
208                if ($wnd[initCall]) {
209                        return $wnd[initCall]();
210                } else {
211                        throw ("No init function found: " + initCall);
212                }
213    }-*/;
214
215    /**
216     * Gets the native renderer instance.<p>
217     *
218     * @return the native renderer instance
219     */
220    protected JavaScriptObject getNativeInstance() {
221
222        if (m_nativeInstance == null) {
223            m_nativeInstance = createNativeInstance(
224                m_jsonConfig.get(CmsContentDefinition.PARAM_INIT_CALL).isString().stringValue());
225        }
226        return m_nativeInstance;
227    }
228
229    /**
230     * Calls the native render function.<p>
231     *
232     * @param nativeRenderer the native renderer instance
233     * @param renderFunction the name of the render function
234     * @param element the element in which to render the entity
235     * @param entity the entity to render
236     * @param config the configuration
237     */
238    protected native void renderNative(
239        JavaScriptObject nativeRenderer,
240        String renderFunction,
241        com.google.gwt.dom.client.Element element,
242        CmsEntity entity,
243        JavaScriptObject config) /*-{
244                var entityWrapper = new $wnd.acacia.CmsEntityWrapper();
245                entityWrapper.setEntity(entity);
246                var backEndWrapper = new $wnd.acacia.CmsEntityBackendWrapper();
247                if (nativeRenderer && nativeRenderer[renderFunction]) {
248                        nativeRenderer[renderFunction](element, entityWrapper,
249                                        backEndWrapper, config);
250                } else if ($wnd.console) {
251                        $wnd.console.log("Rendering function not found: " + renderFunction);
252                }
253    }-*/;
254
255    /**
256     * Throws an error indicating that a method is not supported.<p>
257     */
258    private void notSupported() {
259
260        throw new UnsupportedOperationException("method not supported by this renderer!");
261    }
262}