001: /*
002: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
003: *
004: * Copyright 1997-2007 Sun Microsystems, Inc. All rights reserved.
005: *
006: * The contents of this file are subject to the terms of either the GNU
007: * General Public License Version 2 only ("GPL") or the Common
008: * Development and Distribution License("CDDL") (collectively, the
009: * "License"). You may not use this file except in compliance with the
010: * License. You can obtain a copy of the License at
011: * http://www.netbeans.org/cddl-gplv2.html
012: * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
013: * specific language governing permissions and limitations under the
014: * License. When distributing the software, include this License Header
015: * Notice in each file and include the License file at
016: * nbbuild/licenses/CDDL-GPL-2-CP. Sun designates this
017: * particular file as subject to the "Classpath" exception as provided
018: * by Sun in the GPL Version 2 section of the License file that
019: * accompanied this code. If applicable, add the following below the
020: * License Header, with the fields enclosed by brackets [] replaced by
021: * your own identifying information:
022: * "Portions Copyrighted [year] [name of copyright owner]"
023: *
024: * Contributor(s):
025: *
026: * The Original Software is NetBeans. The Initial Developer of the Original
027: * Software is Sun Microsystems, Inc. Portions Copyright 1997-2007 Sun
028: * Microsystems, Inc. All Rights Reserved.
029: *
030: * If you wish your version of this file to be governed by only the CDDL
031: * or only the GPL Version 2, indicate your decision by adding
032: * "[Contributor] elects to include this software in this distribution
033: * under the [CDDL or GPL Version 2] license." If you do not indicate a
034: * single choice of license, a recipient has the option to distribute
035: * your version of this file under either the CDDL, the GPL Version 2 or
036: * to extend the choice of license to its licensees as provided above.
037: * However, if you add GPL Version 2 code and therefore, elected the GPL
038: * Version 2 license, then the option applies only if the new code is
039: * made subject to such option by the copyright holder.
040: */
041: package org.netbeans.modules.visualweb.faces.dt;
042:
043: import com.sun.rave.designtime.CheckedDisplayAction;
044: import com.sun.rave.designtime.DesignBean;
045: import com.sun.rave.designtime.DesignProperty;
046: import com.sun.rave.designtime.Result;
047: import com.sun.rave.designtime.impl.BasicDisplayAction;
048: import org.netbeans.modules.visualweb.faces.dt.component.html.HtmlFormDesignInfo;
049: import org.netbeans.modules.visualweb.faces.dt.util.ComponentBundle;
050: import javax.faces.component.NamingContainer;
051: import java.util.regex.Pattern;
052: import java.util.regex.Matcher;
053: import javax.faces.component.html.HtmlSelectBooleanCheckbox;
054: import javax.faces.component.html.HtmlSelectManyCheckbox;
055: import javax.faces.component.html.HtmlSelectOneRadio;
056:
057: public class AutoSubmitOnChangeCheckedAction extends BasicDisplayAction
058: implements CheckedDisplayAction {
059:
060: private static final ComponentBundle bundle = ComponentBundle
061: .getBundle(AutoSubmitOnChangeCheckedAction.class);
062:
063: private static final Pattern this DotFormDotSubmitPattern = Pattern
064: .compile("this\\s*\\.\\s*form\\s*\\.\\s*submit\\s*\\(\\s*\\)\\s*;?"); //NOI18N
065:
066: private static final String EE5_TIMEOUT_FUNCTION = "webui.suntheme.common.timeoutSubmitForm"; //NOI18N
067: private static final String EE4_TIMEOUT_FUNCTION = "common_timeoutSubmitForm"; //NOI18N
068:
069: private static final String EE4_PAGE = "com.sun.rave.web.ui.component.Page"; //NOI18N
070: private static final String EE5_PAGE = "com.sun.webui.jsf.component.Page"; //NOI18N
071:
072: private static final String SUBMIT_PATTERN_SUFFIX = "\\s*\\(\\s*this\\s*\\.\\s*form\\s*,\\s*'\\S+'\\s*\\)\\s*;?"; //NOI18N
073:
074: private String timeoutFunction;
075:
076: private Pattern submitPattern;
077:
078: protected DesignBean bean;
079:
080: public AutoSubmitOnChangeCheckedAction(DesignBean bean) {
081: super (bundle.getMessage("autoSubmit")); //NOI18N
082: this .bean = bean;
083: //default to ee4 value:
084: this .timeoutFunction = EE5_PAGE.equals(getPageClassName()) ? EE5_TIMEOUT_FUNCTION
085: : EE4_TIMEOUT_FUNCTION;
086: this .submitPattern = Pattern.compile(this .timeoutFunction
087: + SUBMIT_PATTERN_SUFFIX);
088: }
089:
090: public void setAutoSubmit(boolean autoSubmit) {
091: //remove any submit script from onchange if submit property is onclick
092: cleanOnchangeIfAppropriate();
093: DesignProperty prop = getSubmitProperty();
094: if (prop != null) {
095: String value = (String) prop.getValue();
096: if (value == null)
097: value = ""; //NOI18N
098: //get rid of "this.form.submit()" if it's there
099: value = this DotFormDotSubmitPattern.matcher(value)
100: .replaceFirst(""); //NOI18N
101: Matcher m = submitPattern.matcher(value);
102: if (autoSubmit) {
103: //if submitPattern is not found, append it
104: if (!m.find()) {
105: prop.setValue(getSubmitScript(value));
106: }
107: } else {
108: //erase the submit pattern
109: String newValue = m.replaceFirst("");
110: if (newValue.length() < 1) {
111: prop.unset();
112: } else {
113: prop.setValue(newValue); //NOI18N
114: }
115: }
116: if (getPageClassName() != null) {
117: return; //don't touch immediate property if this is a recognized ee4 or ee5 page
118: }
119: prop = bean.getProperty("immediate"); //NOI18N
120: if (prop != null) {
121: if (autoSubmit) {
122: prop.setValue(Boolean.TRUE);
123: } else {
124: prop.unset();
125: }
126: }
127: }
128: }
129:
130: public boolean isAutoSubmit() {
131: DesignProperty property = getSubmitProperty();
132: if (property == null)
133: return false;
134: String value = (String) property.getValue();
135: if (value == null)
136: return false;
137: return submitPattern.matcher(value).find()
138: || this DotFormDotSubmitPattern.matcher(value).find();
139: }
140:
141: public void toggleAutoSubmit() {
142: //remove any submit script from onchange if submit property is onclick
143: cleanOnchangeIfAppropriate();
144: DesignProperty prop = getSubmitProperty();
145: if (prop != null) {
146: boolean isON = isAutoSubmit();
147: String value = (String) prop.getValue();
148: if (value == null || value.length() == 0) {
149: // If no property value, set it
150: prop.setValue(getSubmitScript(null));
151: } else {
152: //get rid of "this.form.submit()" if it's there
153: value = this DotFormDotSubmitPattern.matcher(value)
154: .replaceFirst(""); //NOI18N
155: if (isON) {
156: // If property value contains the onSubmit script, remove it
157: prop.setValue(submitPattern.matcher(value)
158: .replaceFirst("")); //NOI18N
159: } else {
160: // Otherwise, append the onSubmit script
161: prop.setValue(getSubmitScript(value));
162: }
163: }
164: if (getPageClassName() != null) {
165: return; //don't touch immediate property if this is a recognized ee4 or ee5 page
166: }
167: prop = bean.getProperty("immediate"); //NOI18N
168: if (prop != null) {
169: if (isON) {
170: prop.unset();
171: } else {
172: prop.setValue(Boolean.TRUE);
173: }
174: }
175: }
176: }
177:
178: public boolean isChecked() {
179: return isAutoSubmit();
180: }
181:
182: public Result invoke() {
183: toggleAutoSubmit();
184: return Result.SUCCESS;
185: }
186:
187: /**
188: * Returns the <code>onchange</code> property for all components except
189: * checkbox and radio button types, for which <code>onclick</code> is
190: * returned. Special casing for these components needed by Internet
191: * Explorer.
192: */
193: DesignProperty getSubmitProperty() {
194: return bean.getProperty(getSubmitPropertyName());
195: }
196:
197: private String getSubmitPropertyName() {
198: Object beanInstance = bean.getInstance();
199: if (beanInstance instanceof HtmlSelectBooleanCheckbox
200: || beanInstance instanceof HtmlSelectManyCheckbox
201: || beanInstance instanceof HtmlSelectOneRadio)
202: return "onclick"; //NOI18N
203: else
204: return "onchange"; //NOI18N
205: }
206:
207: String getSubmitScript(String previousScript) {
208: StringBuffer buffer = new StringBuffer();
209: if (previousScript != null) {
210: buffer.append(previousScript);
211: if (!Pattern.compile(";\\s*$").matcher(previousScript)
212: .find()) {
213: buffer.append(';');
214: }
215: if (!Pattern.compile("\\s+$").matcher(buffer.toString())
216: .find()) {
217: buffer.append(' ');
218: }
219: }
220: String id = HtmlFormDesignInfo.getFullyQualifiedId(bean);
221: if (id == null) {
222: id = bean.getInstanceName();
223: } else if (id.startsWith(String
224: .valueOf(NamingContainer.SEPARATOR_CHAR))
225: && id.length() > 1) {
226: //fully qualified id (starting with ":") could look intimidating to users. so just chop off leading ":"
227: id = id.substring(1, id.length());
228: }
229: buffer.append(this .timeoutFunction);
230: buffer.append("(this.form, '");
231: buffer.append(id);
232: buffer.append("');");
233: return buffer.toString();
234: }
235:
236: //in old pages, onchange might have been used for radiobutton and checkbox types
237: //if this is an old page and the correct submit property is onclick,
238: //then clean up onchange
239: private void cleanOnchangeIfAppropriate() {
240: if (getPageClassName() == null
241: && "onclick".equals(getSubmitPropertyName())) { //NOI18N
242: //remove any onsubmit script from onchange handler
243: DesignProperty onchangeProp = bean.getProperty("onchange"); //NOI18N
244: if (onchangeProp != null) {
245: String onchangeValue = (String) onchangeProp.getValue();
246: if (onchangeValue != null) {
247: onchangeValue = this DotFormDotSubmitPattern
248: .matcher(onchangeValue).replaceFirst(""); //NOI18N
249: onchangeProp.setValue(submitPattern.matcher(
250: onchangeValue).replaceFirst("")); //NOI18N
251: }
252: }
253: }
254: }
255:
256: private String getPageClassName() {
257: DesignBean testBean = bean;
258: while (testBean != null) {
259: Object instance = testBean.getInstance();
260: if (instance != null) {
261: String className = instance.getClass().getName();
262: if (EE4_PAGE.equals(className)
263: || EE5_PAGE.equals(className)) {
264: return className;
265: }
266: }
267: testBean = testBean.getBeanParent();
268: }
269: return null;
270: }
271: }
|