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.components;
016
017 import java.io.UnsupportedEncodingException;
018 import java.util.List;
019
020 import org.apache.tapestry5.BindingConstants;
021 import org.apache.tapestry5.ClientElement;
022 import org.apache.tapestry5.ComponentResources;
023 import org.apache.tapestry5.EventConstants;
024 import org.apache.tapestry5.Link;
025 import org.apache.tapestry5.MarkupWriter;
026 import org.apache.tapestry5.StreamResponse;
027 import org.apache.tapestry5.annotations.Environmental;
028 import org.apache.tapestry5.annotations.Import;
029 import org.apache.tapestry5.annotations.Parameter;
030 import org.apache.tapestry5.annotations.SupportsInformalParameters;
031 import org.apache.tapestry5.ioc.Messages;
032 import org.apache.tapestry5.ioc.annotations.Inject;
033 import org.apache.tapestry5.json.JSONObject;
034 import org.apache.tapestry5.services.Request;
035 import org.apache.tapestry5.services.javascript.JavaScriptSupport;
036 import org.apache.tapestry5.util.TextStreamResponse;
037
038
039 /**
040 * a "just in place" edit component that dont must emmbedded in a form.
041 *
042 * @version $Id: InPlaceEditor.java 704 2010-10-16 10:17:41Z homburgs $
043 */
044 @SupportsInformalParameters
045 @Import(library = {"${tapestry.scriptaculous}/controls.js", "InPlaceEditor.js"})
046 public class InPlaceEditor implements ClientElement
047 {
048 public final static String SAVE_EVENT = "save";
049
050 /**
051 * The id used to generate a page-unique client-side identifier for the component. If a
052 * component renders multiple times, a suffix will be appended to the to id to ensure
053 * uniqueness. The uniqued value may be accessed via the
054 * {@link #getClientId() clientId property}.
055 */
056 @Parameter(value = "prop:componentResources.id", defaultPrefix = BindingConstants.LITERAL)
057 private String clientId;
058
059 /**
060 * The value to be read and updated. This is not necessarily a string, a translator may be provided to convert
061 * between client side and server side representations. If not bound, a default binding is made to a property of the
062 * container matching the component's id. If no such property exists, then you will see a runtime exception due to
063 * the unbound value parameter.
064 */
065 @Parameter(required = true, principal = true)
066 private String value;
067
068 /**
069 * Size of the input text tag.
070 */
071 @Parameter(value = "20", required = false, defaultPrefix = BindingConstants.PROP)
072 private int size;
073
074 /**
075 * The context for the link (optional parameter). This list of values will be converted into strings and included in
076 * the URI.
077 */
078 @Parameter(required = false)
079 private List<?> context;
080
081 @Inject
082 private ComponentResources resources;
083
084 @Inject
085 private Messages messages;
086
087 @Environmental
088 private JavaScriptSupport javascriptSupport;
089
090 @Inject
091 private Request request;
092
093 private String assignedClientId;
094
095 private Object[] contextArray;
096
097 void setupRender()
098 {
099 assignedClientId = javascriptSupport.allocateClientId(clientId);
100 contextArray = context == null ? new Object[0] : context.toArray();
101 }
102
103 void beginRender(MarkupWriter writer)
104 {
105 writer.element("span", "id", getClientId());
106
107 if (value != null && value.length() > 0)
108 writer.write(value);
109 else
110 writer.writeRaw(messages.get("empty"));
111 }
112
113 void afterRender(MarkupWriter writer)
114 {
115 Link link = resources.createEventLink(EventConstants.ACTION, contextArray);
116 JSONObject spec = new JSONObject();
117
118 writer.end();
119
120 spec.put("clientId", getClientId());
121 spec.put("href", link.toURI());
122 JSONObject opts = new JSONObject();
123 opts.put("cancelControl", "button");
124 opts.put("cancelText", messages.get("cancelbutton"));
125 opts.put("clickToEditText", messages.get("title"));
126 opts.put("savingText", messages.get("saving"));
127 opts.put("okText", messages.get("savebutton"));
128 opts.put("okText", messages.get("savebutton"));
129 opts.put("htmlResponse", Boolean.TRUE);
130 opts.put("size", size);
131 opts.put("stripLoadedTextTags", Boolean.TRUE);
132 spec.put("options", opts);
133
134 javascriptSupport.addInitializerCall("ckinplaceeditor", spec);
135 }
136
137 StreamResponse onAction(String value) throws UnsupportedEncodingException
138 {
139 String valueText = request.getParameter("value");
140
141 resources.triggerEvent(SAVE_EVENT, new Object[]{value, valueText}, null);
142
143 if (valueText == null || valueText.length() == 0)
144 valueText = messages.get("empty");
145
146 return new TextStreamResponse("text/html", new String(valueText.getBytes("UTF8")));
147 }
148
149 /**
150 * Returns a unique id for the element. This value will be unique for any given rendering of a page. This value is
151 * intended for use as the id attribute of the client-side element, and will be used with any DHTML/Ajax related
152 * JavaScript.
153 */
154 public String getClientId()
155 {
156 return assignedClientId;
157 }
158 }