Return-Path: Delivered-To: apmail-cocoon-cvs-archive@www.apache.org Received: (qmail 18334 invoked from network); 20 Feb 2006 11:17:28 -0000 Received: from hermes.apache.org (HELO mail.apache.org) (209.237.227.199) by minotaur.apache.org with SMTP; 20 Feb 2006 11:17:22 -0000 Received: (qmail 3039 invoked by uid 500); 20 Feb 2006 11:16:35 -0000 Delivered-To: apmail-cocoon-cvs-archive@cocoon.apache.org Received: (qmail 2892 invoked by uid 500); 20 Feb 2006 11:16:34 -0000 Mailing-List: contact cvs-help@cocoon.apache.org; run by ezmlm Precedence: bulk Reply-To: dev@cocoon.apache.org list-help: list-unsubscribe: List-Post: List-Id: Delivered-To: mailing list cvs@cocoon.apache.org Received: (qmail 2880 invoked by uid 99); 20 Feb 2006 11:16:34 -0000 Received: from asf.osuosl.org (HELO asf.osuosl.org) (140.211.166.49) by apache.org (qpsmtpd/0.29) with ESMTP; Mon, 20 Feb 2006 03:16:34 -0800 X-ASF-Spam-Status: No, hits=-9.4 required=10.0 tests=ALL_TRUSTED,NO_REAL_NAME X-Spam-Check-By: apache.org Received: from [209.237.227.194] (HELO minotaur.apache.org) (209.237.227.194) by apache.org (qpsmtpd/0.29) with SMTP; Mon, 20 Feb 2006 03:16:30 -0800 Received: (qmail 17964 invoked by uid 65534); 20 Feb 2006 11:16:08 -0000 Message-ID: <20060220111608.17959.qmail@minotaur.apache.org> Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit Subject: svn commit: r379087 - in /cocoon/trunk/cocoon-forms/cocoon-forms-impl/src/main/java/org/apache/cocoon/forms: formmodel/ resources/ resources/css/ resources/js/ resources/mattkruse-lib/ Date: Mon, 20 Feb 2006 11:15:34 -0000 To: cvs@cocoon.apache.org From: sylvain@apache.org X-Mailer: svnmailer-1.0.6 X-Virus-Checked: Checked by ClamAV on apache.org X-Spam-Rating: minotaur.apache.org 1.6.2 0/1000/N Author: sylvain Date: Mon Feb 20 03:15:25 2006 New Revision: 379087 URL: http://svn.apache.org/viewcvs?rev=379087&view=rev Log: Migration of Ajax stuff to Dojo, orderable repeater and inline-edit styling Added: cocoon/trunk/cocoon-forms/cocoon-forms-impl/src/main/java/org/apache/cocoon/forms/resources/js/CFormsForm.js (with props) cocoon/trunk/cocoon-forms/cocoon-forms-impl/src/main/java/org/apache/cocoon/forms/resources/js/CFormsRepeater.js (with props) cocoon/trunk/cocoon-forms/cocoon-forms-impl/src/main/java/org/apache/cocoon/forms/resources/js/__package__.js (with props) cocoon/trunk/cocoon-forms/cocoon-forms-impl/src/main/java/org/apache/cocoon/forms/resources/js/common.js (with props) Removed: cocoon/trunk/cocoon-forms/cocoon-forms-impl/src/main/java/org/apache/cocoon/forms/resources/js/cforms.js Modified: cocoon/trunk/cocoon-forms/cocoon-forms-impl/src/main/java/org/apache/cocoon/forms/formmodel/AbstractWidget.java cocoon/trunk/cocoon-forms/cocoon-forms-impl/src/main/java/org/apache/cocoon/forms/formmodel/Form.java cocoon/trunk/cocoon-forms/cocoon-forms-impl/src/main/java/org/apache/cocoon/forms/formmodel/Repeater.java cocoon/trunk/cocoon-forms/cocoon-forms-impl/src/main/java/org/apache/cocoon/forms/formmodel/RepeaterAction.java cocoon/trunk/cocoon-forms/cocoon-forms-impl/src/main/java/org/apache/cocoon/forms/formmodel/RepeaterActionDefinition.java cocoon/trunk/cocoon-forms/cocoon-forms-impl/src/main/java/org/apache/cocoon/forms/formmodel/RepeaterDefinition.java cocoon/trunk/cocoon-forms/cocoon-forms-impl/src/main/java/org/apache/cocoon/forms/formmodel/RepeaterDefinitionBuilder.java cocoon/trunk/cocoon-forms/cocoon-forms-impl/src/main/java/org/apache/cocoon/forms/resources/css/forms.css cocoon/trunk/cocoon-forms/cocoon-forms-impl/src/main/java/org/apache/cocoon/forms/resources/forms-advanced-field-styling.xsl cocoon/trunk/cocoon-forms/cocoon-forms-impl/src/main/java/org/apache/cocoon/forms/resources/forms-field-styling.xsl cocoon/trunk/cocoon-forms/cocoon-forms-impl/src/main/java/org/apache/cocoon/forms/resources/js/forms-lib.js cocoon/trunk/cocoon-forms/cocoon-forms-impl/src/main/java/org/apache/cocoon/forms/resources/mattkruse-lib/PopupWindow.js Modified: cocoon/trunk/cocoon-forms/cocoon-forms-impl/src/main/java/org/apache/cocoon/forms/formmodel/AbstractWidget.java URL: http://svn.apache.org/viewcvs/cocoon/trunk/cocoon-forms/cocoon-forms-impl/src/main/java/org/apache/cocoon/forms/formmodel/AbstractWidget.java?rev=379087&r1=379086&r2=379087&view=diff ============================================================================== --- cocoon/trunk/cocoon-forms/cocoon-forms-impl/src/main/java/org/apache/cocoon/forms/formmodel/AbstractWidget.java (original) +++ cocoon/trunk/cocoon-forms/cocoon-forms-impl/src/main/java/org/apache/cocoon/forms/formmodel/AbstractWidget.java Mon Feb 20 03:15:25 2006 @@ -426,14 +426,11 @@ // top-level widget-containers like forms will have their id set to "" // for those the @id should not be included. if (getId().length() != 0) { - attrs.addCDATAAttribute("id", getRequestParameterName()); + attrs.addCDATAAttribute("id", getRequestParameterName()); } - // Add the "state" attribute if different from active (the default state) - WidgetState state = getCombinedState(); - if (state != WidgetState.ACTIVE) { - attrs.addCDATAAttribute("state", getCombinedState().getName()); - } + // Add the "state" attribute + attrs.addCDATAAttribute("state", getCombinedState().getName()); // Add the "listening" attribute is the value has change listeners if (this instanceof ValueChangedListenerEnabled && Modified: cocoon/trunk/cocoon-forms/cocoon-forms-impl/src/main/java/org/apache/cocoon/forms/formmodel/Form.java URL: http://svn.apache.org/viewcvs/cocoon/trunk/cocoon-forms/cocoon-forms-impl/src/main/java/org/apache/cocoon/forms/formmodel/Form.java?rev=379087&r1=379086&r2=379087&view=diff ============================================================================== --- cocoon/trunk/cocoon-forms/cocoon-forms-impl/src/main/java/org/apache/cocoon/forms/formmodel/Form.java (original) +++ cocoon/trunk/cocoon-forms/cocoon-forms-impl/src/main/java/org/apache/cocoon/forms/formmodel/Form.java Mon Feb 20 03:15:25 2006 @@ -314,17 +314,23 @@ // Find the submit widget, if not an action // This has to occur after reading from the request, to handle stateless forms // where the submit widget is recreated when the request is read (e.g. a row-action). - String submitId = formContext.getRequest().getParameter(SUBMIT_ID_PARAMETER); - if (!StringUtils.isEmpty(submitId)) { - // if the form has an ID, it is used as part of the submitId too and must be removed - if(!StringUtils.isEmpty(this.getId())) { - submitId = submitId.substring(submitId.indexOf('.')+1); + + // Note that we don't check this if the submit widget was already set, as it can cause problems + // if the user triggers submit with an input (which sets 'forms_submit_id'), then clicks back + // and submits using a regular submit button. + if (getSubmitWidget() == null) { + String submitId = formContext.getRequest().getParameter(SUBMIT_ID_PARAMETER); + if (!StringUtils.isEmpty(submitId)) { + // if the form has an ID, it is used as part of the submitId too and must be removed + if(!StringUtils.isEmpty(this.getId())) { + submitId = submitId.substring(submitId.indexOf('.')+1); + } + Widget submit = this.lookupWidget(submitId.replace('.', '/')); + if (submit == null) { + throw new IllegalArgumentException("Invalid submit id (no such widget): " + submitId); + } + setSubmitWidget(submit); } - Widget submit = this.lookupWidget(submitId.replace('.', '/')); - if (submit == null) { - throw new IllegalArgumentException("Invalid submit id (no such widget): " + submitId); - } - setSubmitWidget(submit); } // Fire events, still buffering them: this ensures they will be handled in the same Modified: cocoon/trunk/cocoon-forms/cocoon-forms-impl/src/main/java/org/apache/cocoon/forms/formmodel/Repeater.java URL: http://svn.apache.org/viewcvs/cocoon/trunk/cocoon-forms/cocoon-forms-impl/src/main/java/org/apache/cocoon/forms/formmodel/Repeater.java?rev=379087&r1=379086&r2=379087&view=diff ============================================================================== --- cocoon/trunk/cocoon-forms/cocoon-forms-impl/src/main/java/org/apache/cocoon/forms/formmodel/Repeater.java (original) +++ cocoon/trunk/cocoon-forms/cocoon-forms-impl/src/main/java/org/apache/cocoon/forms/formmodel/Repeater.java Mon Feb 20 03:15:25 2006 @@ -16,12 +16,15 @@ package org.apache.cocoon.forms.formmodel; import java.util.ArrayList; +import java.util.BitSet; import java.util.Iterator; import java.util.List; import java.util.Locale; +import org.apache.cocoon.environment.Request; import org.apache.cocoon.forms.FormsConstants; import org.apache.cocoon.forms.FormContext; +import org.apache.cocoon.forms.FormsRuntimeException; import org.apache.cocoon.forms.util.I18nMessage; import org.apache.cocoon.forms.event.WidgetEvent; import org.apache.cocoon.forms.validation.ValidationError; @@ -56,7 +59,8 @@ private final RepeaterDefinition definition; protected final List rows = new ArrayList(); protected ValidationError validationError; - + private boolean selectable = false; + private boolean orderable = false; public Repeater(RepeaterDefinition repeaterDefinition) { super(repeaterDefinition); @@ -66,6 +70,9 @@ for (int i = 0; i < this.definition.getInitialSize(); i++) { rows.add(new RepeaterRow(definition)); } + + this.selectable = this.definition.getSelectable(); + this.orderable = this.definition.getOrderable(); } public WidgetDefinition getDefinition() { @@ -235,7 +242,6 @@ */ public void removeRows() { clear(); - getForm().addWidgetUpdate(this); } /** @@ -267,7 +273,10 @@ return; // read number of rows from request, and make an according number of rows - String sizeParameter = formContext.getRequest().getParameter(getRequestParameterName() + ".size"); + Request req = formContext.getRequest(); + String paramName = getRequestParameterName(); + + String sizeParameter = req.getParameter(paramName + ".size"); if (sizeParameter != null) { int size = 0; try { @@ -299,6 +308,55 @@ RepeaterRow row = (RepeaterRow)rowIt.next(); row.readFromRequest(formContext); } + + // Handle selection + if (this.selectable) { + String[] selectedIds = req.getParameterValues(paramName + ".select"); + BitSet selection = new BitSet(getSize()); + + // Create selection bitmask + if (selectedIds != null) { + for (int i = 0; i < selectedIds.length; i++) { + int rowId = Integer.parseInt(selectedIds[i]); + selection.set(rowId); + } + } + + // And update the selected state of all rows + for (int i = 0; i < getSize(); i++) { + getRow(i).setSelected(selection.get(i)); + } + } + + // Handle repeater-level actions + String action = req.getParameter(paramName + ".action"); + if (action == null) { + return; + } + + // Handle row move. It's important for this to happen *after* row.readFromRequest, + // as reordering rows changes their IDs and therefore their child widget's ID too. + if (action.equals("move")) { + if (!this.orderable) { + throw new FormsRuntimeException(this + " is not orderable", getLocation()); + } + int from = Integer.parseInt(req.getParameter(paramName + ".from")); + int before = Integer.parseInt(req.getParameter(paramName + ".before")); + + Object row = this.rows.get(from); + // Add to the new location + this.rows.add(before, row); + // Remove from the previous one, taking into account potential location change + // because of the previous add() + if (before < from) from++; + this.rows.remove(from); + + // Needs refresh + getForm().addWidgetUpdate(this); + + } else { + throw new FormsRuntimeException("Unknown action " + action + " for " + this, getLocation()); + } } /** @@ -446,6 +504,7 @@ private int cachedPosition = -100; private String cachedId = "--undefined--"; + private boolean selected = false; public String getId() { int pos = rows.indexOf(this); @@ -479,6 +538,17 @@ Iterator it = this.getChildren(); while(it.hasNext()) { ((Widget)it.next()).initialize(); + } + } + + public boolean getSelected() { + return this.selected; + } + + public void setSelected(boolean selected) { + if (selected != this.selected) { + this.selected = selected; + getForm().addWidgetUpdate(this); } } Modified: cocoon/trunk/cocoon-forms/cocoon-forms-impl/src/main/java/org/apache/cocoon/forms/formmodel/RepeaterAction.java URL: http://svn.apache.org/viewcvs/cocoon/trunk/cocoon-forms/cocoon-forms-impl/src/main/java/org/apache/cocoon/forms/formmodel/RepeaterAction.java?rev=379087&r1=379086&r2=379087&view=diff ============================================================================== --- cocoon/trunk/cocoon-forms/cocoon-forms-impl/src/main/java/org/apache/cocoon/forms/formmodel/RepeaterAction.java (original) +++ cocoon/trunk/cocoon-forms/cocoon-forms-impl/src/main/java/org/apache/cocoon/forms/formmodel/RepeaterAction.java Mon Feb 20 03:15:25 2006 @@ -15,8 +15,6 @@ */ package org.apache.cocoon.forms.formmodel; -import org.apache.cocoon.forms.FormContext; - /** * An action that acts on a repeater. * @@ -57,35 +55,5 @@ } return this.repeater; - } - - public static class Move extends RepeaterAction { - private int from; - private int to; - - public Move(RepeaterActionDefinition definition) { - super(definition); - } - - public void readFromRequest(FormContext formContext) { - String fullName = getFullName(); - String fromStr = formContext.getRequest().getParameter(fullName + ".from"); - if (fromStr != null) { - from = Integer.parseInt(fromStr); - to = Integer.parseInt(formContext.getRequest().getParameter(fullName + ".to")); - } else { - from = -1; - to = -1; - } - super.readFromRequest(formContext); - } - - public int getFrom() { - return from; - } - - public int getTo() { - return to; - } } } Modified: cocoon/trunk/cocoon-forms/cocoon-forms-impl/src/main/java/org/apache/cocoon/forms/formmodel/RepeaterActionDefinition.java URL: http://svn.apache.org/viewcvs/cocoon/trunk/cocoon-forms/cocoon-forms-impl/src/main/java/org/apache/cocoon/forms/formmodel/RepeaterActionDefinition.java?rev=379087&r1=379086&r2=379087&view=diff ============================================================================== --- cocoon/trunk/cocoon-forms/cocoon-forms-impl/src/main/java/org/apache/cocoon/forms/formmodel/RepeaterActionDefinition.java (original) +++ cocoon/trunk/cocoon-forms/cocoon-forms-impl/src/main/java/org/apache/cocoon/forms/formmodel/RepeaterActionDefinition.java Mon Feb 20 03:15:25 2006 @@ -198,21 +198,4 @@ }); } } - - public static class MoveRowActionDefinition extends RepeaterActionDefinition { - - public MoveRowActionDefinition(String repeaterName) { - super(repeaterName); - this.addActionListener(new ActionListener() { - public void actionPerformed(ActionEvent event) { - RepeaterAction.Move move = (RepeaterAction.Move)event.getSource(); - Repeater repeater = move.getRepeater(); - repeater.moveRow(move.getFrom(), move.getTo()); - } - }); - } - public Widget createInstance() { - return new RepeaterAction.Move(this); - } - } } Modified: cocoon/trunk/cocoon-forms/cocoon-forms-impl/src/main/java/org/apache/cocoon/forms/formmodel/RepeaterDefinition.java URL: http://svn.apache.org/viewcvs/cocoon/trunk/cocoon-forms/cocoon-forms-impl/src/main/java/org/apache/cocoon/forms/formmodel/RepeaterDefinition.java?rev=379087&r1=379086&r2=379087&view=diff ============================================================================== --- cocoon/trunk/cocoon-forms/cocoon-forms-impl/src/main/java/org/apache/cocoon/forms/formmodel/RepeaterDefinition.java (original) +++ cocoon/trunk/cocoon-forms/cocoon-forms-impl/src/main/java/org/apache/cocoon/forms/formmodel/RepeaterDefinition.java Mon Feb 20 03:15:25 2006 @@ -24,12 +24,16 @@ private int initialSize = 0; private int minSize; private int maxSize; + private boolean selectable; + private boolean orderable; - public RepeaterDefinition(int initialSize, int minSize, int maxSize) { + public RepeaterDefinition(int initialSize, int minSize, int maxSize, boolean selectable, boolean orderable) { super(); this.initialSize = initialSize; this.minSize = minSize; this.maxSize = maxSize; + this.selectable = selectable; + this.orderable = orderable; } /** @@ -62,5 +66,13 @@ public int getMinSize() { return this.minSize; + } + + public boolean getOrderable() { + return this.orderable; + } + + public boolean getSelectable() { + return this.selectable; } } Modified: cocoon/trunk/cocoon-forms/cocoon-forms-impl/src/main/java/org/apache/cocoon/forms/formmodel/RepeaterDefinitionBuilder.java URL: http://svn.apache.org/viewcvs/cocoon/trunk/cocoon-forms/cocoon-forms-impl/src/main/java/org/apache/cocoon/forms/formmodel/RepeaterDefinitionBuilder.java?rev=379087&r1=379086&r2=379087&view=diff ============================================================================== --- cocoon/trunk/cocoon-forms/cocoon-forms-impl/src/main/java/org/apache/cocoon/forms/formmodel/RepeaterDefinitionBuilder.java (original) +++ cocoon/trunk/cocoon-forms/cocoon-forms-impl/src/main/java/org/apache/cocoon/forms/formmodel/RepeaterDefinitionBuilder.java Mon Feb 20 03:15:25 2006 @@ -47,8 +47,11 @@ // initial size is at least the min size initialSize = minSize > initialSize ? minSize : initialSize; - - RepeaterDefinition repeaterDefinition = new RepeaterDefinition(initialSize, minSize, maxSize); + + boolean orderable = DomHelper.getAttributeAsBoolean(repeaterElement, "orderable", false); + boolean selectable = DomHelper.getAttributeAsBoolean(repeaterElement, "selectable", false); + + RepeaterDefinition repeaterDefinition = new RepeaterDefinition(initialSize, minSize, maxSize, selectable, orderable); super.setupDefinition(repeaterElement, repeaterDefinition); setDisplayData(repeaterElement, repeaterDefinition); Modified: cocoon/trunk/cocoon-forms/cocoon-forms-impl/src/main/java/org/apache/cocoon/forms/resources/css/forms.css URL: http://svn.apache.org/viewcvs/cocoon/trunk/cocoon-forms/cocoon-forms-impl/src/main/java/org/apache/cocoon/forms/resources/css/forms.css?rev=379087&r1=379086&r2=379087&view=diff ============================================================================== --- cocoon/trunk/cocoon-forms/cocoon-forms-impl/src/main/java/org/apache/cocoon/forms/resources/css/forms.css (original) +++ cocoon/trunk/cocoon-forms/cocoon-forms-impl/src/main/java/org/apache/cocoon/forms/resources/css/forms.css Mon Feb 20 03:15:25 2006 @@ -73,3 +73,8 @@ .forms-doubleList input { width: 40px; } + +/** Style for drag'n drop indicator */ +.forms-dropIndicator { + border-top: 4px solid black; +} \ No newline at end of file Modified: cocoon/trunk/cocoon-forms/cocoon-forms-impl/src/main/java/org/apache/cocoon/forms/resources/forms-advanced-field-styling.xsl URL: http://svn.apache.org/viewcvs/cocoon/trunk/cocoon-forms/cocoon-forms-impl/src/main/java/org/apache/cocoon/forms/resources/forms-advanced-field-styling.xsl?rev=379087&r1=379086&r2=379087&view=diff ============================================================================== --- cocoon/trunk/cocoon-forms/cocoon-forms-impl/src/main/java/org/apache/cocoon/forms/resources/forms-advanced-field-styling.xsl (original) +++ cocoon/trunk/cocoon-forms/cocoon-forms-impl/src/main/java/org/apache/cocoon/forms/resources/forms-advanced-field-styling.xsl Mon Feb 20 03:15:25 2006 @@ -223,4 +223,31 @@ + + + + + + + + + dojo.byId('{@id}:input').value = arguments[0]; + + forms_submitForm(dojo.byId('{@id}:input')) + + + + + + + + + + + + + + Modified: cocoon/trunk/cocoon-forms/cocoon-forms-impl/src/main/java/org/apache/cocoon/forms/resources/forms-field-styling.xsl URL: http://svn.apache.org/viewcvs/cocoon/trunk/cocoon-forms/cocoon-forms-impl/src/main/java/org/apache/cocoon/forms/resources/forms-field-styling.xsl?rev=379087&r1=379086&r2=379087&view=diff ============================================================================== --- cocoon/trunk/cocoon-forms/cocoon-forms-impl/src/main/java/org/apache/cocoon/forms/resources/forms-field-styling.xsl (original) +++ cocoon/trunk/cocoon-forms/cocoon-forms-impl/src/main/java/org/apache/cocoon/forms/resources/forms-field-styling.xsl Mon Feb 20 03:15:25 2006 @@ -27,21 +27,25 @@ exclude-result-prefixes="fi"> + + + + + + + - forms_onload(); - - - - - + @@ -554,12 +558,19 @@
- forms_onsubmit(); + + + CFormsForm + + + + + + forms_onsubmit(); + +
- - - Added: cocoon/trunk/cocoon-forms/cocoon-forms-impl/src/main/java/org/apache/cocoon/forms/resources/js/CFormsForm.js URL: http://svn.apache.org/viewcvs/cocoon/trunk/cocoon-forms/cocoon-forms-impl/src/main/java/org/apache/cocoon/forms/resources/js/CFormsForm.js?rev=379087&view=auto ============================================================================== --- cocoon/trunk/cocoon-forms/cocoon-forms-impl/src/main/java/org/apache/cocoon/forms/resources/js/CFormsForm.js (added) +++ cocoon/trunk/cocoon-forms/cocoon-forms-impl/src/main/java/org/apache/cocoon/forms/resources/js/CFormsForm.js Mon Feb 20 03:15:25 2006 @@ -0,0 +1,174 @@ +/* + * Copyright 1999-2006 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +dojo.provide("cocoon.forms.CFormsForm"); +dojo.require("dojo.event"); +dojo.require("dojo.widget.DomWidget"); +dojo.require("cocoon.ajax.BUHandler"); + +/** + * Dojo widget for forms, that handles the Ajax interaction with the server. + * + * @version $Id$ + */ +// Extends the base DomWidget class. We don't need all the HtmlWidget stuff +// but need traversal of the DOM to build child widgets +cocoon.forms.CFormsForm = function() { + dojo.widget.DomWidget.call(this); +}; + +dojo.inherits(cocoon.forms.CFormsForm, dojo.widget.DomWidget); + +dojo.lang.extend(cocoon.forms.CFormsForm, { + // Properties + + // Widget definition + widgetType: "CFormsForm", + isContainer: true, + buildRendering: function(args, parserFragment, parentWidget) { + + // Magical statement to get the dom node, stolen in DomWidget + this.domNode = parserFragment["dojo:"+this.widgetType.toLowerCase()].nodeRef; + + this.id = this.domNode.getAttribute("id"); + + this.domNode.setAttribute("dojoWidgetId", this.widgetId); + + dojo.event.connect("around", this.domNode, "onsubmit", this, "_browserSubmit"); + dojo.event.connect(this.domNode, "onclick", this, "_grabClickTarget"); + }, + + _grabClickTarget: function(event) { + // Keep targets of onclick so that we can know what input triggered the submit + // (the event in onsubmit() is the HTMLFormElement). + this.lastClickTarget = dojo.html.getEventTarget(event); + }, + + /** Connected to the forms 'onsubmit' event, called when the user clicks a submit input */ + _browserSubmit: function(invocation) { + if (invocation.proceed() == false) { + // onsubmit handlers stopped submission + return false; + } + + var event = invocation.args[0] || window.event; + // Interestingly, FF provides the explicitOriginalTarget property that can avoid + // grabClickTarget above, but avoid browser specifics for now. + var target = /*event.explicitOriginalTarget ||*/ this.lastClickTarget; + + this.submit(target.name); + // If real submit has to occur, it's taken care of in submit() + return false; + }, + + /** + * Submit the form, choosing automatically Ajax or fullpage mode depending on the + * widgets in the form. + * + * @param name the name of the widget that triggered the submit (if any) + * @param params an object containing additional parameters to be added to the + * query string (optional) + */ + submit: function(name, params) { + var form = this.domNode; + + var query = cocoon.forms.buildQueryString(form, name); + if (!query) { + if (params) alert("FIXME: handle additional params in CFormsForm.submit()"); + // Some inputs are not ajax-compatible. Fall back to full page reload + form["forms_submit_id"].value = name; + form.submit(); + return; + } + + query += cocoon.forms.encodeParams(params, true); + + // Provide feedback that something is happening. + document.body.style.cursor = "wait"; + + // The "ajax-action" attribute specifies an alternate submit location used in Ajax mode. + // This allows to use Ajax in the portal where forms are normally posted to the portal URL. + var uri = form.getAttribute("ajax-action"); + if (!uri) uri = form.action; + if (uri == "") uri = document.location; + + // FIXME: revisit with dojo.io.bind(), but need to see what happens if we say + // mimetype="text/xml" and no XML is sent back + var req = dojo.hostenv.getXmlhttpObject() + + req.open("POST", uri, true); + req.setRequestHeader("Content-Type", "application/x-www-form-urlencoded; charset=UTF-8"); + var thisWidget = this; + req.onreadystatechange = function() { + if (req.readyState == 4) { + thisWidget._handleBrowserUpdate(req); + } + } + req.send(query); + }, + + /** + * Handle the server response + */ + _handleBrowserUpdate: function(request) { + // Restore normal cursor + document.body.style.cursor = "auto"; + var updater = new cocoon.ajax.BUHandler(); + if (request.status == 200) { + // Handle browser update directives + var doc = request.responseXML; + if (!doc) { + cocoon.ajax.BUHandler.handleError("No xml answer", request); + return; + } + + var thisWidget = this; + updater.handlers['continue'] = function() { thisWidget._continue(); } + updater.processResponse(doc, request); + } else { + updater.handleError("Request failed - status=" + request.status, request); + } + }, + + _continue: function() { + var form = this.domNode; + if (form.method.toLowerCase() == "post") { + // Create a fake form and post it + var div = document.createElement("div"); + var content = "" + + ""; + if (form.elements["continuation-id"]) { + content += ""; + } + content += ""; + div.innerHTML = content; + document.body.appendChild(div); + div.firstChild.submit(); + } else { + // Redirect to the form's action URL + var contParam = '?cocoon-ajax-continue=true'; + if (form.elements["continuation-id"]) { + contParam += "&continuation-id=" + form.elements["continuation-id"].value; + } + window.location.href = form.action + contParam; + } + } +}); + +dojo.widget.tags.addParseTreeHandler("dojo:CFormsForm"); +// Register this module as a widget package +dojo.widget.manager.registerWidgetPackage("cocoon.forms"); + Propchange: cocoon/trunk/cocoon-forms/cocoon-forms-impl/src/main/java/org/apache/cocoon/forms/resources/js/CFormsForm.js ------------------------------------------------------------------------------ svn:eol-style = native Propchange: cocoon/trunk/cocoon-forms/cocoon-forms-impl/src/main/java/org/apache/cocoon/forms/resources/js/CFormsForm.js ------------------------------------------------------------------------------ svn:keywords = Id Added: cocoon/trunk/cocoon-forms/cocoon-forms-impl/src/main/java/org/apache/cocoon/forms/resources/js/CFormsRepeater.js URL: http://svn.apache.org/viewcvs/cocoon/trunk/cocoon-forms/cocoon-forms-impl/src/main/java/org/apache/cocoon/forms/resources/js/CFormsRepeater.js?rev=379087&view=auto ============================================================================== --- cocoon/trunk/cocoon-forms/cocoon-forms-impl/src/main/java/org/apache/cocoon/forms/resources/js/CFormsRepeater.js (added) +++ cocoon/trunk/cocoon-forms/cocoon-forms-impl/src/main/java/org/apache/cocoon/forms/resources/js/CFormsRepeater.js Mon Feb 20 03:15:25 2006 @@ -0,0 +1,152 @@ +/* + * Copyright 1999-2006 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +dojo.provide("cocoon.forms.CFormsRepeater"); +dojo.require("dojo.dnd.HtmlDragAndDrop"); +dojo.require("dojo.event"); +dojo.require("dojo.widget.DomWidget"); + +/** + * Dojo widget for repeaters, that handles drag'n drop reordering and selection + * by clicking in the rows. + *

+ * The drop indicator can be styled with the "forms-dropIndicator" CSS class. + * + * @version $Id$ + */ +// Extends the base DomWidget class. We don't need all the HtmlWidget stuff +// but need traversal of the DOM to build child widgets +cocoon.forms.CFormsRepeater = function() { + dojo.widget.DomWidget.call(this); +}; + +dojo.inherits(cocoon.forms.CFormsRepeater, dojo.widget.DomWidget); + +dojo.lang.extend(cocoon.forms.CFormsRepeater, { + // Properties + orderable: false, + select: "none", + + // Widget definition + widgetType: "CFormsRepeater", + isContainer: true, + buildRendering: function(args, parserFragment, parentWidget) { + // FIXME: we should destroy all drag sources and drop targets when the widget is destroyed + // Magical statement to get the dom node, stolen in DomWidget + this.domNode = parserFragment["dojo:"+this.widgetType.toLowerCase()].nodeRef; + + this.id = this.domNode.getAttribute("id"); + dojo.debug("Creating repeater " + this.id); + if (!this.orderable && this.select == "none") { + dojo.debug("CFormsRepeater '" + this.id + "' is not orderable nor selectable"); + } + + if (this.orderable) { + // Get the parent of the first repeater row (may be different from this.domNode) + var firstRow = dojo.byId(this.id + ".0"); + if (!firstRow) return; + + // Check that TR's are in TBODY otherwise it doesn't work + if (firstRow.tagName.toLowerCase() == "tr" && firstRow.parentNode.tagName.toLowerCase() != "tbody") { + throw "CFormsRepeater requires TR's to be in a TBODY (check '" + this.id + "')"; + } + + var type = "cforms-" + this.id; + var dropTarget = new dojo.dnd.HtmlDropTarget(firstRow.parentNode, [type]); + + dropTarget.createDropIndicator = function() { + this.dropIndicator = document.createElement("div"); + this.dropIndicator.className = "forms-dropIndicator"; + with (this.dropIndicator.style) { + position = "absolute"; + zIndex = 1; + width = dojo.style.getInnerWidth(this.domNode) + "px"; + left = dojo.style.getAbsoluteX(this.domNode) + "px"; + } + }; + dojo.event.connect(dropTarget, "insert", this, "afterInsert"); + + var row; + for (var idx = 0; row = dojo.byId(this.id + "." + idx); idx++) { + var dragSource = new dojo.dnd.HtmlDragSource(row, type); + row.style.cursor = "move"; + } + } + + if (true || this.select == "single" || this.select == "multiple") { + var row; + var widget = this; + for (var idx = 0; row = dojo.byId(this.id + "." + idx); idx++) { + (function() { + var localIdx = idx; // to use it in the closure + var localRow = row; + dojo.event.connect(row, "onclick", function(e) { widget.selectRow(e, localRow, localIdx) }) + })() + } + } + }, + + /** + * Called after a dropped node has been inserted at its target position + * @param e the event (has a "dragObject" property) + * @param refNode the reference node for the insertion + * @param the insertion position relative to refNode ("before" or "after") + */ + afterInsert: function(e, refNode, position) { + var parts = e.dragObject.domNode.getAttribute("id").split('.'); + var source = parseInt(parts[parts.length - 1]); + parts = refNode.getAttribute("id").split('.'); + var before = parseInt(parts[parts.length - 1]); + // Compute the row number before which to place the moved row + if (position == "after") before++; + if (before == source || before == source + 1) return; // no change needed + +// dojo.debug("moving row " + source + " before " + before + " (" + position + ")"); + + // submit the form to update server-side model + var form = cocoon.forms.getForm(this.domNode); + var params = {}; + params[this.id + ".action"] = "move"; + params[this.id + ".from"] = source; + params[this.id + ".before"] = before; + dojo.widget.byId(form.getAttribute("dojoWidgetId")).submit(this.id, params); + }, + + isValidEvent: function(e) { + var elt = dojo.html.getEventTarget(e); + if (!elt) return true; + if (elt.onclick) return false; + var name = elt.tagName.toLowerCase(); + return (name != "input" && name != "a"); + }, + + selectRow: function(e, row, idx) { + if (this.isValidEvent(e)) { + if (row.getAttribute("selected") == "true") { + row.setAttribute("selected", "false"); + row.style.background = "none"; + } else { + row.setAttribute("selected", "true"); + row.style.background = "green"; + } + dojo.debug("clic " + idx); //+ " from " + elt.tagName + " onclick=" + elt.onclick); + } + } +}); + +dojo.widget.tags.addParseTreeHandler("dojo:CFormsRepeater"); +// Register this module as a widget package +dojo.widget.manager.registerWidgetPackage("cocoon.forms"); + Propchange: cocoon/trunk/cocoon-forms/cocoon-forms-impl/src/main/java/org/apache/cocoon/forms/resources/js/CFormsRepeater.js ------------------------------------------------------------------------------ svn:eol-style = native Propchange: cocoon/trunk/cocoon-forms/cocoon-forms-impl/src/main/java/org/apache/cocoon/forms/resources/js/CFormsRepeater.js ------------------------------------------------------------------------------ svn:keywords = Id Added: cocoon/trunk/cocoon-forms/cocoon-forms-impl/src/main/java/org/apache/cocoon/forms/resources/js/__package__.js URL: http://svn.apache.org/viewcvs/cocoon/trunk/cocoon-forms/cocoon-forms-impl/src/main/java/org/apache/cocoon/forms/resources/js/__package__.js?rev=379087&view=auto ============================================================================== --- cocoon/trunk/cocoon-forms/cocoon-forms-impl/src/main/java/org/apache/cocoon/forms/resources/js/__package__.js (added) +++ cocoon/trunk/cocoon-forms/cocoon-forms-impl/src/main/java/org/apache/cocoon/forms/resources/js/__package__.js Mon Feb 20 03:15:25 2006 @@ -0,0 +1,24 @@ +/* + * Copyright 1999-2006 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +dojo.hostenv.conditionalLoadModule({ + common: [ + "cocoon.forms.common", + "cocoon.forms.CFormsForm", + "cocoon.forms.CFormsRepeater" + ] +}); + +dojo.hostenv.moduleLoaded("cocoon.forms.*"); Propchange: cocoon/trunk/cocoon-forms/cocoon-forms-impl/src/main/java/org/apache/cocoon/forms/resources/js/__package__.js ------------------------------------------------------------------------------ svn:eol-style = native Propchange: cocoon/trunk/cocoon-forms/cocoon-forms-impl/src/main/java/org/apache/cocoon/forms/resources/js/__package__.js ------------------------------------------------------------------------------ svn:keywords = Id Added: cocoon/trunk/cocoon-forms/cocoon-forms-impl/src/main/java/org/apache/cocoon/forms/resources/js/common.js URL: http://svn.apache.org/viewcvs/cocoon/trunk/cocoon-forms/cocoon-forms-impl/src/main/java/org/apache/cocoon/forms/resources/js/common.js?rev=379087&view=auto ============================================================================== --- cocoon/trunk/cocoon-forms/cocoon-forms-impl/src/main/java/org/apache/cocoon/forms/resources/js/common.js (added) +++ cocoon/trunk/cocoon-forms/cocoon-forms-impl/src/main/java/org/apache/cocoon/forms/resources/js/common.js Mon Feb 20 03:15:25 2006 @@ -0,0 +1,149 @@ +/* + * Copyright 2005 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * Utility functions for form handling. + * + * @version $Id$ + */ +// Can be loaded either through "cocoon.forms" or "cocoon.forms.common" +// or individually out of Dojo. +if (dojo) { + dojo.provide("cocoon.forms"); + dojo.provide("cocoon.forms.common"); +} else { + cocoon = cocoon || {}; + cocoon.forms = cocoon.forms || {}; +} + +/** + * Get the form of an element + */ +cocoon.forms.getForm = function(element) { + while(element != null && element.tagName != "FORM") { + element = element.parentNode; + } + return element; +} + +/** + * Submits a form. If ajax mode is on and the browser is ajax-aware, the page isn't reloaded + */ +cocoon.forms.submitForm = function(element, name) { + var form = this.getForm(element); + if (form == null) { + alert("Cannot find form for " + element); + return; + } + + if (!name) name = element.name; + + var dojoId = form.getAttribute("dojoWidgetId"); + if (dojoId) { + // Delegate to the CFormsForm widget + dojo.widget.byId(dojoId).submit(name); + + } else { + // Regular submit. How old-fashioned :-) + + // Send the identifier of the widget that triggered the submit + form["forms_submit_id"].value = name; + + // A form's onsubmit is only called when submit is triggered by user action, but not when + // called by a script. So don't forget to call it, cancelling the submit if (and only if) + // it returns false + if (!form.onsubmit || form.onsubmit() != false) { + form.submit(); + } + } +} + +// Override the default forms_submitForm +forms_submitForm = function() { cocoon.forms.submitForm.apply(cocoon.forms, arguments) }; + +/** + * Build a query string with all form inputs. + * + * @parameter form the form element + * @parameter submitId the ID of the widget that submitted the form + * @return the query string for the form, or null if some inputs cannot be + * send in Ajax mode (e.g. file inputs) + */ +cocoon.forms.buildQueryString = function(form, submitId) { + // Indicate to the server that we're in ajax mode + var result = "cocoon-ajax=true"; + + // If the form has a forms_submit_id input, use it to avoid sending the value twice + if (form["forms_submit_id"]) { + form["forms_submit_id"].value = submitId; + } else { + if (submitId) result += "&forms_submit_id=" + submitId; + } + + // Iterate on all form controls + for (var i = 0; i < form.elements.length; i++) { + input = form.elements[i]; + if (typeof(input.type) == "undefined") { + // Skip fieldset + continue; + } + if (input.type == "submit" || input.type == "image" || input.type == "button") { + // Skip buttons + continue; + } + if ((input.type == "checkbox" || input.type == "radio") && !input.checked) { + // Skip unchecked checkboxes and radio buttons + continue; + } + if (input.type == "file") { + // Can't send files in Ajax mode. Fall back to full page + return null; + } + if (input.tagName.toLowerCase() == "select" && input.multiple) { + var name = encodeURIComponent(input.name); + var options = input.options; + for (var zz = 0; zz < options.length; zz++) { + if (options[zz].selected) { + result += "&" + name + "=" + encodeURIComponent(options[zz].value); + } + } + // don't use the default fallback + continue; + } + + // text, passwod, textarea, hidden, single select + result += "&" + encodeURIComponent(input.name) + "=" + encodeURIComponent(input.value); + } + return result; +} + +/** + * Encode an object as querystring parameters. + * + * @parameter params the object to encode + * @isAppending if true, "&" is prepended to the result + * @return the querystring + */ +cocoon.forms.encodeParams = function(params, isAppending) { + if (!params) return ""; + var result = ""; + var sep = isAppending ? "&" : ""; + for (var name in params) { + result += sep + encodeURIComponent(name) + "=" + encodeURIComponent(params[name]); + sep = "&"; + } + return result; +} Propchange: cocoon/trunk/cocoon-forms/cocoon-forms-impl/src/main/java/org/apache/cocoon/forms/resources/js/common.js ------------------------------------------------------------------------------ svn:eol-style = native Propchange: cocoon/trunk/cocoon-forms/cocoon-forms-impl/src/main/java/org/apache/cocoon/forms/resources/js/common.js ------------------------------------------------------------------------------ svn:keywords = Id Modified: cocoon/trunk/cocoon-forms/cocoon-forms-impl/src/main/java/org/apache/cocoon/forms/resources/js/forms-lib.js URL: http://svn.apache.org/viewcvs/cocoon/trunk/cocoon-forms/cocoon-forms-impl/src/main/java/org/apache/cocoon/forms/resources/js/forms-lib.js?rev=379087&r1=379086&r2=379087&view=diff ============================================================================== --- cocoon/trunk/cocoon-forms/cocoon-forms-impl/src/main/java/org/apache/cocoon/forms/resources/js/forms-lib.js (original) +++ cocoon/trunk/cocoon-forms/cocoon-forms-impl/src/main/java/org/apache/cocoon/forms/resources/js/forms-lib.js Mon Feb 20 03:15:25 2006 @@ -15,6 +15,10 @@ */ /** * Runtime JavaScript library for Cocoon forms. + * NOTE: This file will be trimmed down to contain only the necessary + * features for dynamic behaviour on non Ajax-capable browsers. + * Advanced widgets such as double selection list and multivalue + * field will be refactored as Dojo widgets. * * @version $Id$ */ @@ -58,18 +62,14 @@ * 'forms_submit_id' field the name of the element which triggered the submit. */ function oldforms_submitForm(element, name) { - // Mac IE 5 doesn't recognize key word 'undefined', so use typeof and compare strings - if (typeof(name) == "undefined") { - name = element.name; - } + name = name || element.name; var form = forms_getForm(element); if (form == null) { alert("Cannot find form for " + element); } else { form["forms_submit_id"].value = name; - // FIXME: programmatically submitting the form doesn't trigger onsubmit ? (both in IE and Moz) - if (forms_onsubmit()) { + if (!form.onsubmit || form.onsubmit() != false) { form.submit(); } } Modified: cocoon/trunk/cocoon-forms/cocoon-forms-impl/src/main/java/org/apache/cocoon/forms/resources/mattkruse-lib/PopupWindow.js URL: http://svn.apache.org/viewcvs/cocoon/trunk/cocoon-forms/cocoon-forms-impl/src/main/java/org/apache/cocoon/forms/resources/mattkruse-lib/PopupWindow.js?rev=379087&r1=379086&r2=379087&view=diff ============================================================================== --- cocoon/trunk/cocoon-forms/cocoon-forms-impl/src/main/java/org/apache/cocoon/forms/resources/mattkruse-lib/PopupWindow.js (original) +++ cocoon/trunk/cocoon-forms/cocoon-forms-impl/src/main/java/org/apache/cocoon/forms/resources/mattkruse-lib/PopupWindow.js Mon Feb 20 03:15:25 2006 @@ -277,7 +277,11 @@ } window.popupWindowOldEventListener = document.onmouseup; if (window.popupWindowOldEventListener != null) { - document.onmouseup = new Function("window.popupWindowOldEventListener(); PopupWindow_hidePopupWindows();"); + document.onmouseup = function(e) { + window.popupWindowOldEventListener(e); + PopupWindow_hidePopupWindows(e); + } + //document.onmouseup = new Function("window.popupWindowOldEventListener(); PopupWindow_hidePopupWindows();"); } else { document.onmouseup = PopupWindow_hidePopupWindows;