001    /*
002     * Apache License
003     * Version 2.0, January 2004
004     * http://www.apache.org/licenses/
005     *
006     * Copyright 2008-2010 by chenillekit.org
007     *
008     * Licensed under the Apache License, Version 2.0 (the "License");
009     * you may not use this file except in compliance with the License.
010     * You may obtain a copy of the License at
011     *
012     * http://www.apache.org/licenses/LICENSE-2.0
013     */
014    
015    package org.chenillekit.tapestry.core.mixins.yui;
016    
017    import org.apache.tapestry5.BindingConstants;
018    import org.apache.tapestry5.ComponentEventCallback;
019    import org.apache.tapestry5.ComponentResources;
020    import org.apache.tapestry5.Field;
021    import org.apache.tapestry5.Link;
022    import org.apache.tapestry5.MarkupWriter;
023    import org.apache.tapestry5.StreamResponse;
024    import org.apache.tapestry5.annotations.Environmental;
025    import org.apache.tapestry5.annotations.Import;
026    import org.apache.tapestry5.annotations.InjectContainer;
027    import org.apache.tapestry5.annotations.Parameter;
028    import org.apache.tapestry5.corelib.components.TextArea;
029    import org.apache.tapestry5.internal.util.Holder;
030    import org.apache.tapestry5.ioc.annotations.Inject;
031    import org.apache.tapestry5.json.JSONObject;
032    import org.apache.tapestry5.services.javascript.JavaScriptSupport;
033    import org.apache.tapestry5.upload.services.MultipartDecoder;
034    import org.apache.tapestry5.upload.services.UploadedFile;
035    import org.apache.tapestry5.util.TextStreamResponse;
036    import org.chenillekit.tapestry.core.base.AbstractYahooComponent;
037    
038    /**
039     * @version $Id: Editor.java 675 2010-07-30 14:49:17Z homburgs $
040     */
041    @Import(stack = {"yahoo"}, stylesheet = {"${yahoo.yui}/assets/skins/sam/skin.css"},
042                    library = {"../../Chenillekit.js",
043                                    "${yahoo.yui}/container/container_core${yahoo.yui.mode}.js",
044                                    "${yahoo.yui}/menu/menu${yahoo.yui.mode}.js",
045                                    "${yahoo.yui}/button/button${yahoo.yui.mode}.js",
046                                    "${yahoo.yui}/connection/connection${yahoo.yui.mode}.js",
047                                    "${yahoo.yui}/editor/editor${yahoo.yui.mode}.js",
048                                    "yui-image-uploader26.js",
049                                    "Editor.js"})
050    public class Editor extends AbstractYahooComponent
051    {
052            private static String INTERNAL_EVENT = "internalUploaded";
053            private static String UPLOAD_EVENT = "uploaded";
054    
055            /**
056             * Allow image uploads.
057             */
058            @Parameter(required = false, defaultPrefix = BindingConstants.PROP, value = "false")
059            private boolean allowUploads;
060    
061            /**
062             * RenderSupport to get unique client side id.
063             */
064            @Environmental
065            private JavaScriptSupport javascriptSupport;
066    
067            /**
068             * For blocks, messages, crete actionlink, trigger event.
069             */
070            @Inject
071            private ComponentResources resources;
072    
073            @Inject
074            private MultipartDecoder decoder;
075    
076            @InjectContainer
077            private Field clientElement;
078    
079            /**
080             * Tapestry render phase method.
081             * Start a tag here, end it in afterRender
082             *
083             * @param writer the markup writer
084             */
085            void beginRender(MarkupWriter writer)
086            {
087                    if (!(clientElement instanceof TextArea))
088                            throw new RuntimeException("Mixin 'yui/Editor' must have a TextArea as parent component");
089            }
090    
091    
092            /**
093             * Tapestry render phase method. End a tag here.
094             *
095             * @param writer the markup writer
096             */
097            void afterRender(MarkupWriter writer)
098            {
099                    JSONObject options = new JSONObject();
100    
101                    configure(options);
102    
103                    options.put("disabled", clientElement.isDisabled());
104                    options.put("handleSubmit", true);
105    
106                    Link uploadEventLink = null;
107                    if (allowUploads)
108                            uploadEventLink = resources.createEventLink(INTERNAL_EVENT);
109    
110                    javascriptSupport.addScript("new Ck.YuiEditor('%s', '%s', %s);", clientElement.getClientId(), uploadEventLink, options);
111            }
112    
113            StreamResponse onInternalUploaded()
114            {
115                    UploadedFile uploaded = decoder.getFileUpload("fileElement");
116    
117                    final Holder<JSONObject> valueHolder = Holder.create();
118    
119                    ComponentEventCallback callback = new ComponentEventCallback<JSONObject>()
120                    {
121                            public boolean handleResult(JSONObject result)
122                            {
123                                    valueHolder.put(result);
124                                    return true;
125                            }
126                    };
127    
128                    resources.triggerEvent(UPLOAD_EVENT, new Object[]{uploaded}, callback);
129    
130                    return new TextStreamResponse("text/html", valueHolder.get().toString());
131            }
132    
133            /**
134             * Invoked to allow subclasses to further configure the parameters passed to this mixin's javascript
135             * options. Subclasses may override this method to configure additional features of this mixin.
136             * <p/>
137             * This implementation does nothing.
138             *
139             * @param options option object
140             */
141            protected void configure(JSONObject options)
142            {
143            }
144    }