001    // Copyright 2004, 2005 The Apache Software Foundation
002    //
003    // Licensed under the Apache License, Version 2.0 (the "License");
004    // you may not use this file except in compliance with the License.
005    // You may obtain a copy of the License at
006    //
007    //     http://www.apache.org/licenses/LICENSE-2.0
008    //
009    // Unless required by applicable law or agreed to in writing, software
010    // distributed under the License is distributed on an "AS IS" BASIS,
011    // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
012    // See the License for the specific language governing permissions and
013    // limitations under the License.
014    package org.apache.tapestry.dojo.html;
015    
016    import org.apache.hivemind.ApplicationRuntimeException;
017    import org.apache.tapestry.*;
018    import org.apache.tapestry.dojo.AbstractWidget;
019    import org.apache.tapestry.engine.DirectServiceParameter;
020    import org.apache.tapestry.engine.IEngineService;
021    import org.apache.tapestry.json.JSONObject;
022    import org.apache.tapestry.link.DirectLink;
023    import org.apache.tapestry.listener.ListenerInvoker;
024    
025    import java.util.Collections;
026    import java.util.HashMap;
027    import java.util.List;
028    import java.util.Map;
029    
030    
031    /**
032     * Wraps a dojo InlineEditBox widget. 
033     * 
034     * <p>
035     * Manages a single string value that when hovered over can be edited "inline" in the document
036     * wherever it is referenced. Supports various modes of operation (ie disable/enabled), as well as 
037     * textarea or single line style edits.
038     * </p>
039     *
040     *
041     * <p>
042     * Some of the commonly used widget functions to listen to are:<br/>
043     * <ul>
044     *  <li><b>onSave - </b>When the save button is clicked. Default function listened to when updating
045     *  server side managed value.
046     *  </li>
047     *  <li><b>onUndo - </b>When cancel button is clicked.</li>
048     *  <li><b>onMouseOver - </b>Mouse moved over editable region.</li>
049     *  <li><b>onMouseOut - </b>Mouse moved away from editable region.</li>
050     * </ul>
051     * </p>
052     * 
053     */
054    public abstract class InlineEditBox extends AbstractWidget implements IDirect
055    {
056        /** 
057         * Default single line editing text mode. Use as one of two possible
058         * parameters to the <code>mode</code> parameter.
059         */
060        public static final String TEXT_MODE = "text";
061        
062        /** 
063         * Multi line editing text mode. Use as one of two possible
064         * parameters to the <code>mode</code> parameter.
065         */
066        public static final String TEXT_AREA_MODE = "textarea";
067        
068        public abstract String getValue();
069        public abstract void setValue(String value);
070        
071        public abstract String getMode();
072        
073        public abstract int getMinWidth();
074        
075        public abstract int getMinHeight();
076        
077        public abstract boolean getDoFade();
078        
079        public abstract boolean isDisabled();
080    
081        public abstract IActionListener getListener();
082    
083        public abstract Object getParameters();
084    
085        public abstract void setStateful(boolean value);
086    
087        /**
088         * {@inheritDoc}
089         */
090        public void renderWidget(IMarkupWriter writer, IRequestCycle cycle)
091        {
092            if (!cycle.isRewinding())
093            {    
094                writer.begin(getTemplateTagName()); // use whatever template tag they specified
095                renderInformalParameters(writer, cycle);
096                renderIdAttribute(writer, cycle);
097            }
098            
099            renderBody(writer, cycle);
100            
101            if (!cycle.isRewinding())
102            {    
103                writer.end();
104            }
105            
106            if(getMode() == null || (!TEXT_MODE.equals(getMode()) && !TEXT_AREA_MODE.equals(getMode())))
107                throw new ApplicationRuntimeException(WidgetMessages.invalidTextMode(getMode()));
108            
109            if (cycle.isRewinding())
110                return;
111            
112            JSONObject prop = new JSONObject();
113            prop.put("widgetId", getClientId());
114            prop.put("value", getValue());
115            prop.put("mode", getMode());
116            prop.put("minWidth", getMinWidth());
117            prop.put("minHeight", getMinHeight());
118            prop.put("doFade", getDoFade());
119            
120            Map parms = new HashMap();
121            parms.put("component", this);
122            parms.put("props", prop.toString());
123            
124            PageRenderSupport prs = TapestryUtils.getPageRenderSupport(cycle, this);
125            getScript().execute(this, cycle, prs, parms);
126        }
127        
128        /**
129         * Callback url used by client side widget to update server component.
130         *
131         * @return The url string to be used by the client side js function to notify
132         *          this component that an update has been made.
133         */
134        public String getUpdateUrl()
135        {
136            Object[] parameters = DirectLink.constructServiceParameters(getParameters());
137    
138            DirectServiceParameter dsp = new DirectServiceParameter(this, parameters);
139            
140            return getEngine().getLink(isStateful(), dsp).getURL();
141        }
142        
143        /**
144         * {@inheritDoc}
145         */
146        public List getUpdateComponents()
147        {
148            return Collections.EMPTY_LIST;
149        }
150    
151        /**
152         * {@inheritDoc}
153         */
154        public boolean isAsync()
155        {
156            return true;
157        }
158    
159        /**
160         * {@inheritDoc}
161         */
162        public boolean isJson()
163        {
164            return false;
165        }
166        
167        /**
168         * {@inheritDoc}
169         */
170        public void trigger(IRequestCycle cycle)
171        {
172            String newValue = cycle.getParameter(getClientId());
173            
174            setValue(newValue);
175    
176            if (getListener() != null)
177            {
178                getListenerInvoker().invokeListener(getListener(), this, cycle);
179            }
180        }
181        
182        /** Injected. */
183        public abstract IEngineService getEngine();
184        
185        /** Injected. */
186        public abstract IScript getScript();
187    
188        /** Injected. */
189        public abstract ListenerInvoker getListenerInvoker();
190    }