You are viewing a plain text version of this content. The canonical link for it is here.
Posted to cvs@cocoon.apache.org by sy...@apache.org on 2005/09/28 12:25:30 UTC
svn commit: r292158 [1/4] - in /cocoon: blocks/ajax/ blocks/ajax/trunk/
blocks/ajax/trunk/WEB-INF/ blocks/ajax/trunk/WEB-INF/xconf/
blocks/ajax/trunk/java/ blocks/ajax/trunk/java/org/
blocks/ajax/trunk/java/org/apache/ blocks/ajax/trunk/java/org/apache...
Author: sylvain
Date: Wed Sep 28 03:24:51 2005
New Revision: 292158
URL: http://svn.apache.org/viewcvs?rev=292158&view=rev
Log:
New Ajax block, and prototypic CForms suggestion-lists
Added:
cocoon/blocks/ajax/
cocoon/blocks/ajax/trunk/
cocoon/blocks/ajax/trunk/WEB-INF/
cocoon/blocks/ajax/trunk/WEB-INF/xconf/
cocoon/blocks/ajax/trunk/WEB-INF/xconf/cocoon-ajax.xconf (with props)
cocoon/blocks/ajax/trunk/java/
cocoon/blocks/ajax/trunk/java/org/
cocoon/blocks/ajax/trunk/java/org/apache/
cocoon/blocks/ajax/trunk/java/org/apache/cocoon/
cocoon/blocks/ajax/trunk/java/org/apache/cocoon/ajax/
cocoon/blocks/ajax/trunk/java/org/apache/cocoon/ajax/AjaxHelper.java (with props)
cocoon/blocks/ajax/trunk/java/org/apache/cocoon/ajax/AjaxRequestMatcher.java (with props)
cocoon/blocks/ajax/trunk/java/org/apache/cocoon/ajax/AjaxRequestSelector.java (with props)
cocoon/blocks/ajax/trunk/java/org/apache/cocoon/ajax/BrowserUpdateTransformer.java (with props)
cocoon/blocks/ajax/trunk/java/org/apache/cocoon/ajax/GetContinuationAction.java (with props)
cocoon/blocks/ajax/trunk/java/org/apache/cocoon/ajax/resources/
cocoon/blocks/ajax/trunk/java/org/apache/cocoon/ajax/resources/js/
cocoon/blocks/ajax/trunk/java/org/apache/cocoon/ajax/resources/js/LICENSE-prototype.txt (with props)
cocoon/blocks/ajax/trunk/java/org/apache/cocoon/ajax/resources/js/LICENSE-scriptaculous.txt (with props)
cocoon/blocks/ajax/trunk/java/org/apache/cocoon/ajax/resources/js/cocoon-ajax.js (with props)
cocoon/blocks/ajax/trunk/java/org/apache/cocoon/ajax/resources/js/controls.js (with props)
cocoon/blocks/ajax/trunk/java/org/apache/cocoon/ajax/resources/js/dragdrop.js (with props)
cocoon/blocks/ajax/trunk/java/org/apache/cocoon/ajax/resources/js/effects.js (with props)
cocoon/blocks/ajax/trunk/java/org/apache/cocoon/ajax/resources/js/prototype.js (with props)
cocoon/blocks/ajax/trunk/java/org/apache/cocoon/ajax/resources/js/scriptaculous.js (with props)
cocoon/blocks/ajax/trunk/java/org/apache/cocoon/ajax/resources/js/slider.js (with props)
cocoon/blocks/ajax/trunk/java/org/apache/cocoon/ajax/resources/js/unittest.js (with props)
cocoon/blocks/ajax/trunk/java/org/apache/cocoon/ajax/resources/js/util.js (with props)
cocoon/blocks/ajax/trunk/java/org/apache/cocoon/transformation/
cocoon/blocks/ajax/trunk/java/org/apache/cocoon/transformation/BrowserUpdateTransformer.java (with props)
cocoon/blocks/ajax/trunk/pom.xml (with props)
cocoon/blocks/ajax/trunk/samples/
cocoon/blocks/ajax/trunk/samples/ajax.xsamples
cocoon/blocks/ajax/trunk/samples/display-suggestions.xml (with props)
cocoon/blocks/ajax/trunk/samples/file-browser-suggest.xml (with props)
cocoon/blocks/ajax/trunk/samples/file-browser.xml (with props)
cocoon/blocks/ajax/trunk/samples/flow.js (with props)
cocoon/blocks/ajax/trunk/samples/sitemap.xmap (with props)
cocoon/blocks/ajax/trunk/samples/welcome.xml (with props)
cocoon/blocks/forms/trunk/java/org/apache/cocoon/forms/generation/SelectionListFilter.java (with props)
cocoon/blocks/forms/trunk/java/org/apache/cocoon/forms/generation/SuggestionListGenerator.java (with props)
cocoon/blocks/forms/trunk/samples/forms/ajax_suggest_form.xml (with props)
cocoon/blocks/forms/trunk/samples/forms/ajax_suggest_template.xml (with props)
cocoon/blocks/forms/trunk/samples/suggest-list.xsl (with props)
Removed:
cocoon/trunk/src/java/org/apache/cocoon/transformation/BrowserUpdateTransformer.java
Modified:
cocoon/blocks/forms/trunk/java/org/apache/cocoon/forms/flow/javascript/Form.js
cocoon/blocks/forms/trunk/java/org/apache/cocoon/forms/formmodel/AbstractDatatypeWidgetDefinitionBuilder.java
cocoon/blocks/forms/trunk/java/org/apache/cocoon/forms/formmodel/AbstractWidget.java
cocoon/blocks/forms/trunk/java/org/apache/cocoon/forms/formmodel/Field.java
cocoon/blocks/forms/trunk/java/org/apache/cocoon/forms/formmodel/FieldDefinition.java
cocoon/blocks/forms/trunk/java/org/apache/cocoon/forms/formmodel/FieldDefinitionBuilder.java
cocoon/blocks/forms/trunk/java/org/apache/cocoon/forms/generation/JXMacrosHelper.java
cocoon/blocks/forms/trunk/java/org/apache/cocoon/forms/generation/jx-macros.xml
cocoon/blocks/forms/trunk/samples/flow/forms_flow_example.js
cocoon/blocks/forms/trunk/samples/forms/form1_template.xml
cocoon/blocks/forms/trunk/samples/forms/sampletree_template.xml
cocoon/blocks/forms/trunk/samples/sitemap.xmap
cocoon/blocks/forms/trunk/samples/welcome.xml
cocoon/trunk/src/java/org/apache/cocoon/components/flow/WebContinuation.java
cocoon/trunk/src/java/org/apache/cocoon/components/flow/javascript/fom/FOM_WebContinuation.java
Added: cocoon/blocks/ajax/trunk/WEB-INF/xconf/cocoon-ajax.xconf
URL: http://svn.apache.org/viewcvs/cocoon/blocks/ajax/trunk/WEB-INF/xconf/cocoon-ajax.xconf?rev=292158&view=auto
==============================================================================
--- cocoon/blocks/ajax/trunk/WEB-INF/xconf/cocoon-ajax.xconf (added)
+++ cocoon/blocks/ajax/trunk/WEB-INF/xconf/cocoon-ajax.xconf Wed Sep 28 03:24:51 2005
@@ -0,0 +1,3 @@
+<components>
+ <!-- nothing special here for now -->
+</components>
Propchange: cocoon/blocks/ajax/trunk/WEB-INF/xconf/cocoon-ajax.xconf
------------------------------------------------------------------------------
svn:eol-style = native
Propchange: cocoon/blocks/ajax/trunk/WEB-INF/xconf/cocoon-ajax.xconf
------------------------------------------------------------------------------
svn:keywords = Id
Added: cocoon/blocks/ajax/trunk/java/org/apache/cocoon/ajax/AjaxHelper.java
URL: http://svn.apache.org/viewcvs/cocoon/blocks/ajax/trunk/java/org/apache/cocoon/ajax/AjaxHelper.java?rev=292158&view=auto
==============================================================================
--- cocoon/blocks/ajax/trunk/java/org/apache/cocoon/ajax/AjaxHelper.java (added)
+++ cocoon/blocks/ajax/trunk/java/org/apache/cocoon/ajax/AjaxHelper.java Wed Sep 28 03:24:51 2005
@@ -0,0 +1,52 @@
+/*
+ * Copyright 1999-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.
+ */
+package org.apache.cocoon.ajax;
+
+import org.apache.cocoon.environment.Request;
+
+/**
+ * Helper class to handle Ajax requests
+ *
+ * @version $Id$
+ * @since 2.1.8
+ */
+public class AjaxHelper {
+
+ private AjaxHelper() {
+ // Forbid instanciation
+ }
+
+ /**
+ * The request parameter that, if set, indicates an Ajax request.
+ */
+ public static final String AJAX_REQUEST_PARAMETER = "cocoon-ajax";
+
+ /**
+ * The namespace URI of the "browser update" xml dialect
+ */
+ public static final String BROWSER_UPDATE_URI = "http://apache.org/cocoon/browser-update/1.0";
+
+ /**
+ * Is the request an Ajax request?
+ *
+ * @param req the request
+ * @return true if this is an Ajax request
+ */
+ public static boolean isAjaxRequest(Request req) {
+ return req.getParameter(AJAX_REQUEST_PARAMETER) != null;
+ }
+
+}
Propchange: cocoon/blocks/ajax/trunk/java/org/apache/cocoon/ajax/AjaxHelper.java
------------------------------------------------------------------------------
svn:eol-style = native
Propchange: cocoon/blocks/ajax/trunk/java/org/apache/cocoon/ajax/AjaxHelper.java
------------------------------------------------------------------------------
svn:keywords = Id
Added: cocoon/blocks/ajax/trunk/java/org/apache/cocoon/ajax/AjaxRequestMatcher.java
URL: http://svn.apache.org/viewcvs/cocoon/blocks/ajax/trunk/java/org/apache/cocoon/ajax/AjaxRequestMatcher.java?rev=292158&view=auto
==============================================================================
--- cocoon/blocks/ajax/trunk/java/org/apache/cocoon/ajax/AjaxRequestMatcher.java (added)
+++ cocoon/blocks/ajax/trunk/java/org/apache/cocoon/ajax/AjaxRequestMatcher.java Wed Sep 28 03:24:51 2005
@@ -0,0 +1,49 @@
+/*
+ * Copyright 1999-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.
+ */
+package org.apache.cocoon.ajax;
+
+import java.util.Collections;
+import java.util.Map;
+
+import org.apache.avalon.framework.parameters.Parameters;
+import org.apache.avalon.framework.thread.ThreadSafe;
+import org.apache.cocoon.environment.ObjectModelHelper;
+import org.apache.cocoon.environment.Request;
+import org.apache.cocoon.matching.Matcher;
+import org.apache.cocoon.sitemap.PatternException;
+
+/**
+ * A matcher that tests if the current request is an Ajax request. This matcher
+ * provides no sitemap variables.
+ * <p>
+ * Example:
+ * <pre>
+ * <map:match type="ajax-request">
+ * ... ajax request ...
+ * </map:match>
+ * </pre>
+ *
+ * @since 2.1.8
+ * @version $Id$
+ */
+public class AjaxRequestMatcher implements Matcher, ThreadSafe {
+
+ public Map match(String pattern, Map objectModel, Parameters parameters) throws PatternException {
+ Request req = ObjectModelHelper.getRequest(objectModel);
+
+ return AjaxHelper.isAjaxRequest(req) ? Collections.EMPTY_MAP : null;
+ }
+}
Propchange: cocoon/blocks/ajax/trunk/java/org/apache/cocoon/ajax/AjaxRequestMatcher.java
------------------------------------------------------------------------------
svn:eol-style = native
Propchange: cocoon/blocks/ajax/trunk/java/org/apache/cocoon/ajax/AjaxRequestMatcher.java
------------------------------------------------------------------------------
svn:keywords = Id
Added: cocoon/blocks/ajax/trunk/java/org/apache/cocoon/ajax/AjaxRequestSelector.java
URL: http://svn.apache.org/viewcvs/cocoon/blocks/ajax/trunk/java/org/apache/cocoon/ajax/AjaxRequestSelector.java?rev=292158&view=auto
==============================================================================
--- cocoon/blocks/ajax/trunk/java/org/apache/cocoon/ajax/AjaxRequestSelector.java (added)
+++ cocoon/blocks/ajax/trunk/java/org/apache/cocoon/ajax/AjaxRequestSelector.java Wed Sep 28 03:24:51 2005
@@ -0,0 +1,57 @@
+/*
+ * Copyright 1999-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.
+ */
+package org.apache.cocoon.ajax;
+
+import java.util.Map;
+
+import org.apache.avalon.framework.parameters.Parameters;
+import org.apache.avalon.framework.thread.ThreadSafe;
+import org.apache.cocoon.environment.ObjectModelHelper;
+import org.apache.cocoon.environment.Request;
+import org.apache.cocoon.selection.AbstractSwitchSelector;
+import org.apache.commons.lang.BooleanUtils;
+
+/**
+ * Choose a select branch depending on if the current request is an Ajax request.
+ * The test value can be either "<code>true</code>" or "<code>false</code>".
+ *
+ * <pre>
+ * <map:select type="ajax-request">
+ * <map:when test="true">
+ * ... ajax request ...
+ * </map:when>
+ * <map:otherwise>
+ * ... non ajax request ...
+ * </map:otherwise>
+ * </map:select>
+ * </pre>
+ *
+ * @since 2.1.8
+ * @version $Id$
+ */
+public class AjaxRequestSelector extends AbstractSwitchSelector implements ThreadSafe {
+
+ public Object getSelectorContext(Map objectModel, Parameters parameters) {
+ Request req = ObjectModelHelper.getRequest(objectModel);
+ return BooleanUtils.toBooleanObject(AjaxHelper.isAjaxRequest(req));
+ }
+
+ public boolean select(String expression, Object selectorContext) {
+ boolean test = BooleanUtils.toBoolean(expression);
+
+ return test == ((Boolean)selectorContext).booleanValue();
+ }
+}
Propchange: cocoon/blocks/ajax/trunk/java/org/apache/cocoon/ajax/AjaxRequestSelector.java
------------------------------------------------------------------------------
svn:eol-style = native
Propchange: cocoon/blocks/ajax/trunk/java/org/apache/cocoon/ajax/AjaxRequestSelector.java
------------------------------------------------------------------------------
svn:keywords = Id
Added: cocoon/blocks/ajax/trunk/java/org/apache/cocoon/ajax/BrowserUpdateTransformer.java
URL: http://svn.apache.org/viewcvs/cocoon/blocks/ajax/trunk/java/org/apache/cocoon/ajax/BrowserUpdateTransformer.java?rev=292158&view=auto
==============================================================================
--- cocoon/blocks/ajax/trunk/java/org/apache/cocoon/ajax/BrowserUpdateTransformer.java (added)
+++ cocoon/blocks/ajax/trunk/java/org/apache/cocoon/ajax/BrowserUpdateTransformer.java Wed Sep 28 03:24:51 2005
@@ -0,0 +1,180 @@
+/*
+ * Copyright 1999-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.
+ */
+package org.apache.cocoon.ajax;
+
+import java.io.IOException;
+import java.util.Map;
+
+import org.apache.avalon.framework.parameters.Parameters;
+import org.apache.cocoon.ProcessingException;
+import org.apache.cocoon.environment.ObjectModelHelper;
+import org.apache.cocoon.environment.Request;
+import org.apache.cocoon.environment.SourceResolver;
+import org.apache.cocoon.transformation.AbstractTransformer;
+import org.apache.cocoon.xml.AttributesImpl;
+import org.apache.cocoon.xml.RedundantNamespacesFilter;
+import org.xml.sax.Attributes;
+import org.xml.sax.Locator;
+import org.xml.sax.SAXException;
+import org.xml.sax.SAXParseException;
+
+/**
+ *
+ * @version $Id$
+ */
+
+public class BrowserUpdateTransformer extends AbstractTransformer {
+
+ public static final String AJAXMODE_PARAM = "cocoon-ajax";
+
+ public static final String BU_NSURI = "http://apache.org/cocoon/browser-update/1.0";
+
+ private boolean ajaxRequest = false;
+
+ private int replaceDepth = 0;
+
+ private boolean inUpdateTag = false;
+ private String updateTagId = null;
+
+ Locator locator;
+
+ public void setup(SourceResolver resolver, Map objectModel, String src, Parameters par) throws ProcessingException, SAXException, IOException {
+
+ Request request = ObjectModelHelper.getRequest(objectModel);
+ this.ajaxRequest = request.getParameter(AJAXMODE_PARAM) != null;
+ }
+
+ public void setDocumentLocator(Locator locator) {
+ super.setDocumentLocator(locator);
+ this.locator = locator;
+ }
+
+ public void startDocument() throws SAXException {
+
+ if (ajaxRequest) {
+ // Add the namespace filter to our own output.
+ // This is needed as flattening bu:* elements can lead to some weird reordering of
+ // namespace declarations...
+ RedundantNamespacesFilter nsPipe = new RedundantNamespacesFilter();
+ if (this.xmlConsumer != null) {
+ nsPipe.setConsumer(this.xmlConsumer);
+ } else {
+ nsPipe.setContentHandler(this.contentHandler);
+ }
+ setConsumer(nsPipe);
+ }
+
+ super.startDocument();
+ if (ajaxRequest) {
+ // Add a root element. The original one is very likely to be stripped
+ super.startPrefixMapping("bu", BU_NSURI);
+ super.startElement(BU_NSURI, "document", "bu:document", new AttributesImpl());
+ }
+ }
+
+ public void startPrefixMapping(String prefix, String uri) throws SAXException {
+ // Passthrough if not in ajax mode or if in a bu:replace
+ if (!this.ajaxRequest || this.replaceDepth > 0) {
+ super.startPrefixMapping(prefix, uri);
+ }
+ }
+
+ public void startElement(String uri, String loc, String raw, Attributes attrs) throws SAXException {
+ if (BU_NSURI.equals(uri) && "replace".equals(loc)) {
+ // Keep the id attribute. It may be null, in which case the one of the
+ // child element will be used.
+ this.updateTagId = attrs.getValue("id");
+ this.inUpdateTag = true;
+ if (this.ajaxRequest && this.replaceDepth == 0) {
+ // Pass this element through
+ super.startElement(uri, loc, raw, attrs);
+ }
+ replaceDepth++;
+ } else {
+ // Passthrough if not in ajax mode or if in a bu:replace
+
+ // Is the enclosing element a bu:replace?
+ if (this.inUpdateTag) {
+ this.inUpdateTag = false;
+ // Is there already an id?
+ String localId = attrs.getValue("id");
+ if (localId != null) {
+ // Yes: check it's the same
+ if (this.updateTagId != null && !localId.equals(this.updateTagId)) {
+ throw new SAXParseException("Id on bu:replace (" + this.updateTagId + ") and " + raw + " (" +
+ localId + ") don't match.", this.locator);
+ }
+ } else {
+ // No: add it
+ if (this.updateTagId == null) {
+ throw new SAXParseException("Neither bu:replace nor " + raw + " have an id attribute.", this.locator);
+ }
+ AttributesImpl newAttrs = new AttributesImpl(attrs);
+ newAttrs.addCDATAAttribute("id", this.updateTagId);
+ attrs = newAttrs;
+ }
+ this.updateTagId = null;
+ }
+ if (!this.ajaxRequest || this.replaceDepth > 0) {
+ super.startElement(uri, loc, raw, attrs);
+ }
+ }
+ }
+
+ public void characters(char[] buffer, int offset, int len) throws SAXException {
+ if (this.inUpdateTag) {
+ // Check that it's only spaces
+ for (int i = offset; i < len; i++) {
+ if (!Character.isWhitespace(buffer[i])) {
+ throw new SAXParseException("bu:replace must include a single child element and no text.", this.locator);
+ }
+ }
+ }
+ if (!this.ajaxRequest || this.replaceDepth > 0) {
+ super.characters(buffer, offset, len);
+ }
+ }
+
+ public void endElement(String uri, String loc, String raw) throws SAXException {
+ if (BU_NSURI.equals(uri) && "replace".equals(loc)) {
+ replaceDepth--;
+ if (this.ajaxRequest && this.replaceDepth == 0) {
+ // Pass this element through
+ super.endElement(uri, loc, raw);
+ }
+ } else {
+ // Passthrough if not in ajax mode or if in a bu:replace
+ if (!this.ajaxRequest || this.replaceDepth > 0) {
+ super.endElement(uri, loc, raw);
+ }
+ }
+ }
+
+ public void endPrefixMapping(String prefix) throws SAXException {
+ // Passthrough if not in ajax mode or if in a bu:replace
+ if (!this.ajaxRequest || this.replaceDepth > 0) {
+ super.endPrefixMapping(prefix);
+ }
+ }
+
+ public void endDocument() throws SAXException {
+ if (ajaxRequest) {
+ super.endElement(BU_NSURI, "document", "bu:document");
+ super.endPrefixMapping("bu");
+ }
+ super.endDocument();
+ }
+}
Propchange: cocoon/blocks/ajax/trunk/java/org/apache/cocoon/ajax/BrowserUpdateTransformer.java
------------------------------------------------------------------------------
svn:eol-style = native
Propchange: cocoon/blocks/ajax/trunk/java/org/apache/cocoon/ajax/BrowserUpdateTransformer.java
------------------------------------------------------------------------------
svn:keywords = Id
Added: cocoon/blocks/ajax/trunk/java/org/apache/cocoon/ajax/GetContinuationAction.java
URL: http://svn.apache.org/viewcvs/cocoon/blocks/ajax/trunk/java/org/apache/cocoon/ajax/GetContinuationAction.java?rev=292158&view=auto
==============================================================================
--- cocoon/blocks/ajax/trunk/java/org/apache/cocoon/ajax/GetContinuationAction.java (added)
+++ cocoon/blocks/ajax/trunk/java/org/apache/cocoon/ajax/GetContinuationAction.java Wed Sep 28 03:24:51 2005
@@ -0,0 +1,81 @@
+/*
+ * Copyright 1999-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.
+ */
+package org.apache.cocoon.ajax;
+
+import java.util.Collections;
+import java.util.Map;
+
+import org.apache.avalon.framework.activity.Disposable;
+import org.apache.avalon.framework.parameters.Parameters;
+import org.apache.avalon.framework.service.ServiceException;
+import org.apache.avalon.framework.service.ServiceManager;
+import org.apache.avalon.framework.service.Serviceable;
+import org.apache.avalon.framework.thread.ThreadSafe;
+import org.apache.cocoon.acting.AbstractAction;
+import org.apache.cocoon.components.flow.ContinuationsManager;
+import org.apache.cocoon.components.flow.FlowHelper;
+import org.apache.cocoon.components.flow.WebContinuation;
+import org.apache.cocoon.environment.ObjectModelHelper;
+import org.apache.cocoon.environment.Redirector;
+import org.apache.cocoon.environment.SourceResolver;
+import org.apache.cocoon.sitemap.SitemapParameters;
+
+/**
+ * Get a continuation knowing its identifier, and set it as the current continuation
+ * in the object model, in the same manner as <code>cocoon.sendPageAndWait()</code> does.
+ * This action is useful when an Ajax request is made that needs to access data related
+ * to the continuation that originally displayed the current page.
+ * <p>
+ * The continuation id is either the <code>src</code> attribute in <code><map:act></code>
+ * or, if not specified, the <code>continuation-id</code> request parameter.
+ * <p>
+ * This action is successful if the continuation exists and is still valid.
+ *
+ * @since 2.1.8
+ * @version $Id$
+ */
+public class GetContinuationAction extends AbstractAction implements ThreadSafe, Serviceable, Disposable {
+ ServiceManager manager;
+ ContinuationsManager contManager;
+
+ public void service(ServiceManager manager) throws ServiceException {
+ this.manager = manager;
+ this.contManager = (ContinuationsManager)manager.lookup(ContinuationsManager.ROLE);
+ }
+
+ public Map act(Redirector redirector, SourceResolver resolver, Map objectModel, String source, Parameters parameters) throws Exception {
+ String continuationId;
+ if (source == null) {
+ continuationId = ObjectModelHelper.getRequest(objectModel).getParameter("continuation-id");
+ } else {
+ continuationId = source;
+ }
+
+ // The interpreter id is the sitemap's URI
+ String interpreterId = SitemapParameters.getLocation(parameters).getURI();
+ WebContinuation wk = this.contManager.lookupWebContinuation(continuationId, interpreterId);
+ if (wk == null || wk.disposed()) {
+ return null;
+ } else {
+ FlowHelper.setWebContinuation(objectModel, wk);
+ return Collections.EMPTY_MAP;
+ }
+ }
+
+ public void dispose() {
+ this.manager.release(this.contManager);
+ }
+}
Propchange: cocoon/blocks/ajax/trunk/java/org/apache/cocoon/ajax/GetContinuationAction.java
------------------------------------------------------------------------------
svn:eol-style = native
Propchange: cocoon/blocks/ajax/trunk/java/org/apache/cocoon/ajax/GetContinuationAction.java
------------------------------------------------------------------------------
svn:keywords = Id
Added: cocoon/blocks/ajax/trunk/java/org/apache/cocoon/ajax/resources/js/LICENSE-prototype.txt
URL: http://svn.apache.org/viewcvs/cocoon/blocks/ajax/trunk/java/org/apache/cocoon/ajax/resources/js/LICENSE-prototype.txt?rev=292158&view=auto
==============================================================================
--- cocoon/blocks/ajax/trunk/java/org/apache/cocoon/ajax/resources/js/LICENSE-prototype.txt (added)
+++ cocoon/blocks/ajax/trunk/java/org/apache/cocoon/ajax/resources/js/LICENSE-prototype.txt Wed Sep 28 03:24:51 2005
@@ -0,0 +1,16 @@
+Copyright (c) 2005 Sam Stephenson
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
Propchange: cocoon/blocks/ajax/trunk/java/org/apache/cocoon/ajax/resources/js/LICENSE-prototype.txt
------------------------------------------------------------------------------
svn:eol-style = native
Propchange: cocoon/blocks/ajax/trunk/java/org/apache/cocoon/ajax/resources/js/LICENSE-prototype.txt
------------------------------------------------------------------------------
svn:keywords = Id
Added: cocoon/blocks/ajax/trunk/java/org/apache/cocoon/ajax/resources/js/LICENSE-scriptaculous.txt
URL: http://svn.apache.org/viewcvs/cocoon/blocks/ajax/trunk/java/org/apache/cocoon/ajax/resources/js/LICENSE-scriptaculous.txt?rev=292158&view=auto
==============================================================================
--- cocoon/blocks/ajax/trunk/java/org/apache/cocoon/ajax/resources/js/LICENSE-scriptaculous.txt (added)
+++ cocoon/blocks/ajax/trunk/java/org/apache/cocoon/ajax/resources/js/LICENSE-scriptaculous.txt Wed Sep 28 03:24:51 2005
@@ -0,0 +1,20 @@
+Copyright (c) 2005 Thomas Fuchs (http://script.aculo.us, http://mir.aculo.us)
+
+Permission is hereby granted, free of charge, to any person obtaining
+a copy of this software and associated documentation files (the
+"Software"), to deal in the Software without restriction, including
+without limitation the rights to use, copy, modify, merge, publish,
+distribute, sublicense, and/or sell copies of the Software, and to
+permit persons to whom the Software is furnished to do so, subject to
+the following conditions:
+
+The above copyright notice and this permission notice shall be
+included in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
\ No newline at end of file
Propchange: cocoon/blocks/ajax/trunk/java/org/apache/cocoon/ajax/resources/js/LICENSE-scriptaculous.txt
------------------------------------------------------------------------------
svn:eol-style = native
Propchange: cocoon/blocks/ajax/trunk/java/org/apache/cocoon/ajax/resources/js/LICENSE-scriptaculous.txt
------------------------------------------------------------------------------
svn:keywords = Id
Added: cocoon/blocks/ajax/trunk/java/org/apache/cocoon/ajax/resources/js/cocoon-ajax.js
URL: http://svn.apache.org/viewcvs/cocoon/blocks/ajax/trunk/java/org/apache/cocoon/ajax/resources/js/cocoon-ajax.js?rev=292158&view=auto
==============================================================================
--- cocoon/blocks/ajax/trunk/java/org/apache/cocoon/ajax/resources/js/cocoon-ajax.js (added)
+++ cocoon/blocks/ajax/trunk/java/org/apache/cocoon/ajax/resources/js/cocoon-ajax.js Wed Sep 28 03:24:51 2005
@@ -0,0 +1,41 @@
+/*
+ * Copyright 1999-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.
+ */
+var Cocoon = {
+ // Dynamic JS loading code copied from scriptaculous.js
+ require: function(libraryName) {
+ // inserting via DOM fails in Safari 2.0, so brute force approach
+ document.write('<script type="text/javascript" src="'+libraryName+'"></script>');
+ },
+
+ load: function() {
+ var scriptTags = document.getElementsByTagName("script");
+ for(var i=0;i<scriptTags.length;i++) {
+ if(scriptTags[i].src && scriptTags[i].src.match(/cocoon-ajax\.js$/)) {
+ var path = scriptTags[i].src.replace(/cocoon-ajax\.js$/,'');
+ this.require(path + 'prototype.js');
+ this.require(path + 'util.js');
+ this.require(path + 'effects.js');
+ this.require(path + 'dragdrop.js');
+ this.require(path + 'controls.js');
+ this.require(path + 'slider.js');
+ return;
+ }
+ }
+ alert("Could not load Cocoon Ajax libraries");
+ }
+}
+
+Cocoon.load();
\ No newline at end of file
Propchange: cocoon/blocks/ajax/trunk/java/org/apache/cocoon/ajax/resources/js/cocoon-ajax.js
------------------------------------------------------------------------------
svn:eol-style = native
Propchange: cocoon/blocks/ajax/trunk/java/org/apache/cocoon/ajax/resources/js/cocoon-ajax.js
------------------------------------------------------------------------------
svn:keywords = Id
Added: cocoon/blocks/ajax/trunk/java/org/apache/cocoon/ajax/resources/js/controls.js
URL: http://svn.apache.org/viewcvs/cocoon/blocks/ajax/trunk/java/org/apache/cocoon/ajax/resources/js/controls.js?rev=292158&view=auto
==============================================================================
--- cocoon/blocks/ajax/trunk/java/org/apache/cocoon/ajax/resources/js/controls.js (added)
+++ cocoon/blocks/ajax/trunk/java/org/apache/cocoon/ajax/resources/js/controls.js Wed Sep 28 03:24:51 2005
@@ -0,0 +1,703 @@
+// Copyright (c) 2005 Thomas Fuchs (http://script.aculo.us, http://mir.aculo.us)
+// (c) 2005 Ivan Krstic (http://blogs.law.harvard.edu/ivan)
+// (c) 2005 Jon Tirsen (http://www.tirsen.com)
+// Contributors:
+// Richard Livsey
+// Rahul Bhargava
+// Rob Wills
+//
+// See scriptaculous.js for full license.
+
+// Autocompleter.Base handles all the autocompletion functionality
+// that's independent of the data source for autocompletion. This
+// includes drawing the autocompletion menu, observing keyboard
+// and mouse events, and similar.
+//
+// Specific autocompleters need to provide, at the very least,
+// a getUpdatedChoices function that will be invoked every time
+// the text inside the monitored textbox changes. This method
+// should get the text for which to provide autocompletion by
+// invoking this.getToken(), NOT by directly accessing
+// this.element.value. This is to allow incremental tokenized
+// autocompletion. Specific auto-completion logic (AJAX, etc)
+// belongs in getUpdatedChoices.
+//
+// Tokenized incremental autocompletion is enabled automatically
+// when an autocompleter is instantiated with the 'tokens' option
+// in the options parameter, e.g.:
+// new Ajax.Autocompleter('id','upd', '/url/', { tokens: ',' });
+// will incrementally autocomplete with a comma as the token.
+// Additionally, ',' in the above example can be replaced with
+// a token array, e.g. { tokens: [',', '\n'] } which
+// enables autocompletion on multiple tokens. This is most
+// useful when one of the tokens is \n (a newline), as it
+// allows smart autocompletion after linebreaks.
+
+var Autocompleter = {}
+Autocompleter.Base = function() {};
+Autocompleter.Base.prototype = {
+ baseInitialize: function(element, update, options) {
+ this.element = $(element);
+ this.update = $(update);
+ this.hasFocus = false;
+ this.changed = false;
+ this.active = false;
+ this.index = 0;
+ this.entryCount = 0;
+
+ if (this.setOptions)
+ this.setOptions(options);
+ else
+ this.options = options || {};
+
+ this.options.paramName = this.options.paramName || this.element.name;
+ this.options.tokens = this.options.tokens || [];
+ this.options.frequency = this.options.frequency || 0.4;
+ this.options.minChars = this.options.minChars || 1;
+ this.options.onShow = this.options.onShow ||
+ function(element, update){
+ if(!update.style.position || update.style.position=='absolute') {
+ update.style.position = 'absolute';
+ Position.clone(element, update, {setHeight: false, offsetTop: element.offsetHeight});
+ }
+ new Effect.Appear(update,{duration:0.15});
+ };
+ this.options.onHide = this.options.onHide ||
+ function(element, update){ new Effect.Fade(update,{duration:0.15}) };
+
+ if (typeof(this.options.tokens) == 'string')
+ this.options.tokens = new Array(this.options.tokens);
+
+ this.observer = null;
+
+ this.element.setAttribute('autocomplete','off');
+
+ Element.hide(this.update);
+
+ Event.observe(this.element, "blur", this.onBlur.bindAsEventListener(this));
+ Event.observe(this.element, "keypress", this.onKeyPress.bindAsEventListener(this));
+ },
+
+ show: function() {
+ if(Element.getStyle(this.update, 'display')=='none') this.options.onShow(this.element, this.update);
+ if(!this.iefix && (navigator.appVersion.indexOf('MSIE')>0) && (Element.getStyle(this.update, 'position')=='absolute')) {
+ new Insertion.After(this.update,
+ '<iframe id="' + this.update.id + '_iefix" '+
+ 'style="display:none;position:absolute;filter:progid:DXImageTransform.Microsoft.Alpha(opacity=0);" ' +
+ 'src="javascript:false;" frameborder="0" scrolling="no"></iframe>');
+ this.iefix = $(this.update.id+'_iefix');
+ }
+ if(this.iefix) {
+ Position.clone(this.update, this.iefix);
+ this.iefix.style.zIndex = 1;
+ this.update.style.zIndex = 2;
+ Element.show(this.iefix);
+ }
+ },
+
+ hide: function() {
+ if(Element.getStyle(this.update, 'display')!='none') this.options.onHide(this.element, this.update);
+ if(this.iefix) Element.hide(this.iefix);
+ },
+
+ startIndicator: function() {
+ if(this.options.indicator) Element.show(this.options.indicator);
+ },
+
+ stopIndicator: function() {
+ if(this.options.indicator) Element.hide(this.options.indicator);
+ },
+
+ onKeyPress: function(event) {
+ if(this.active)
+ switch(event.keyCode) {
+ case Event.KEY_TAB:
+ case Event.KEY_RETURN:
+ this.selectEntry();
+ Event.stop(event);
+ case Event.KEY_ESC:
+ this.hide();
+ this.active = false;
+ Event.stop(event);
+ return;
+ case Event.KEY_LEFT:
+ case Event.KEY_RIGHT:
+ return;
+ case Event.KEY_UP:
+ this.markPrevious();
+ this.render();
+ if(navigator.appVersion.indexOf('AppleWebKit')>0) Event.stop(event);
+ return;
+ case Event.KEY_DOWN:
+ this.markNext();
+ this.render();
+ if(navigator.appVersion.indexOf('AppleWebKit')>0) Event.stop(event);
+ return;
+ }
+ else
+ if(event.keyCode==Event.KEY_TAB || event.keyCode==Event.KEY_RETURN)
+ return;
+
+ this.changed = true;
+ this.hasFocus = true;
+
+ if(this.observer) clearTimeout(this.observer);
+ this.observer =
+ setTimeout(this.onObserverEvent.bind(this), this.options.frequency*1000);
+ },
+
+ onHover: function(event) {
+ var element = Event.findElement(event, 'LI');
+ if(this.index != element.autocompleteIndex)
+ {
+ this.index = element.autocompleteIndex;
+ this.render();
+ }
+ Event.stop(event);
+ },
+
+ onClick: function(event) {
+ var element = Event.findElement(event, 'LI');
+ this.index = element.autocompleteIndex;
+ this.selectEntry();
+ this.hide();
+ },
+
+ onBlur: function(event) {
+ // needed to make click events working
+ setTimeout(this.hide.bind(this), 250);
+ this.hasFocus = false;
+ this.active = false;
+ },
+
+ render: function() {
+ if(this.entryCount > 0) {
+ for (var i = 0; i < this.entryCount; i++)
+ this.index==i ?
+ Element.addClassName(this.getEntry(i),"selected") :
+ Element.removeClassName(this.getEntry(i),"selected");
+
+ if(this.hasFocus) {
+ this.show();
+ this.active = true;
+ }
+ } else this.hide();
+ },
+
+ markPrevious: function() {
+ if(this.index > 0) this.index--
+ else this.index = this.entryCcount-1;
+ },
+
+ markNext: function() {
+ if(this.index < this.entryCount-1) this.index++
+ else this.index = 0;
+ },
+
+ getEntry: function(index) {
+ return this.update.firstChild.childNodes[index];
+ },
+
+ getCurrentEntry: function() {
+ return this.getEntry(this.index);
+ },
+
+ selectEntry: function() {
+ this.active = false;
+ this.updateElement(this.getCurrentEntry());
+ },
+
+ updateElement: function(selectedElement) {
+ if (this.options.updateElement) {
+ this.options.updateElement(selectedElement);
+ return;
+ }
+
+ var value = Element.collectTextNodesIgnoreClass(selectedElement, 'informal');
+ var lastTokenPos = this.findLastToken();
+ if (lastTokenPos != -1) {
+ var newValue = this.element.value.substr(0, lastTokenPos + 1);
+ var whitespace = this.element.value.substr(lastTokenPos + 1).match(/^\s+/);
+ if (whitespace)
+ newValue += whitespace[0];
+ this.element.value = newValue + value;
+ } else {
+ this.element.value = value;
+ }
+ this.element.focus();
+
+ if (this.options.afterUpdateElement)
+ this.options.afterUpdateElement(this.element, selectedElement);
+ },
+
+ updateChoices: function(choices) {
+ if(!this.changed && this.hasFocus) {
+ this.update.innerHTML = choices;
+ Element.cleanWhitespace(this.update);
+ Element.cleanWhitespace(this.update.firstChild);
+
+ if(this.update.firstChild && this.update.firstChild.childNodes) {
+ this.entryCount =
+ this.update.firstChild.childNodes.length;
+ for (var i = 0; i < this.entryCount; i++) {
+ var entry = this.getEntry(i);
+ entry.autocompleteIndex = i;
+ this.addObservers(entry);
+ }
+ } else {
+ this.entryCount = 0;
+ }
+
+ this.stopIndicator();
+
+ this.index = 0;
+ this.render();
+ }
+ },
+
+ addObservers: function(element) {
+ Event.observe(element, "mouseover", this.onHover.bindAsEventListener(this));
+ Event.observe(element, "click", this.onClick.bindAsEventListener(this));
+ },
+
+ onObserverEvent: function() {
+ this.changed = false;
+ if(this.getToken().length>=this.options.minChars) {
+ this.startIndicator();
+ this.getUpdatedChoices();
+ } else {
+ this.active = false;
+ this.hide();
+ }
+ },
+
+ getToken: function() {
+ var tokenPos = this.findLastToken();
+ if (tokenPos != -1)
+ var ret = this.element.value.substr(tokenPos + 1).replace(/^\s+/,'').replace(/\s+$/,'');
+ else
+ var ret = this.element.value;
+
+ return /\n/.test(ret) ? '' : ret;
+ },
+
+ findLastToken: function() {
+ var lastTokenPos = -1;
+
+ for (var i=0; i<this.options.tokens.length; i++) {
+ var thisTokenPos = this.element.value.lastIndexOf(this.options.tokens[i]);
+ if (thisTokenPos > lastTokenPos)
+ lastTokenPos = thisTokenPos;
+ }
+ return lastTokenPos;
+ }
+}
+
+Ajax.Autocompleter = Class.create();
+Object.extend(Object.extend(Ajax.Autocompleter.prototype, Autocompleter.Base.prototype), {
+ initialize: function(element, update, url, options) {
+ this.baseInitialize(element, update, options);
+ this.options.asynchronous = true;
+ this.options.onComplete = this.onComplete.bind(this);
+ this.options.defaultParams = this.options.parameters || null;
+ this.url = url;
+ },
+
+ getUpdatedChoices: function() {
+ entry = encodeURIComponent(this.options.paramName) + '=' +
+ encodeURIComponent(this.getToken());
+
+ this.options.parameters = this.options.callback ?
+ this.options.callback(this.element, entry) : entry;
+
+ if(this.options.defaultParams)
+ this.options.parameters += '&' + this.options.defaultParams;
+
+ new Ajax.Request(this.url, this.options);
+ },
+
+ onComplete: function(request) {
+ this.updateChoices(request.responseText);
+ }
+
+});
+
+// The local array autocompleter. Used when you'd prefer to
+// inject an array of autocompletion options into the page, rather
+// than sending out Ajax queries, which can be quite slow sometimes.
+//
+// The constructor takes four parameters. The first two are, as usual,
+// the id of the monitored textbox, and id of the autocompletion menu.
+// The third is the array you want to autocomplete from, and the fourth
+// is the options block.
+//
+// Extra local autocompletion options:
+// - choices - How many autocompletion choices to offer
+//
+// - partialSearch - If false, the autocompleter will match entered
+// text only at the beginning of strings in the
+// autocomplete array. Defaults to true, which will
+// match text at the beginning of any *word* in the
+// strings in the autocomplete array. If you want to
+// search anywhere in the string, additionally set
+// the option fullSearch to true (default: off).
+//
+// - fullSsearch - Search anywhere in autocomplete array strings.
+//
+// - partialChars - How many characters to enter before triggering
+// a partial match (unlike minChars, which defines
+// how many characters are required to do any match
+// at all). Defaults to 2.
+//
+// - ignoreCase - Whether to ignore case when autocompleting.
+// Defaults to true.
+//
+// It's possible to pass in a custom function as the 'selector'
+// option, if you prefer to write your own autocompletion logic.
+// In that case, the other options above will not apply unless
+// you support them.
+
+Autocompleter.Local = Class.create();
+Autocompleter.Local.prototype = Object.extend(new Autocompleter.Base(), {
+ initialize: function(element, update, array, options) {
+ this.baseInitialize(element, update, options);
+ this.options.array = array;
+ },
+
+ getUpdatedChoices: function() {
+ this.updateChoices(this.options.selector(this));
+ },
+
+ setOptions: function(options) {
+ this.options = Object.extend({
+ choices: 10,
+ partialSearch: true,
+ partialChars: 2,
+ ignoreCase: true,
+ fullSearch: false,
+ selector: function(instance) {
+ var ret = []; // Beginning matches
+ var partial = []; // Inside matches
+ var entry = instance.getToken();
+ var count = 0;
+
+ for (var i = 0; i < instance.options.array.length &&
+ ret.length < instance.options.choices ; i++) {
+
+ var elem = instance.options.array[i];
+ var foundPos = instance.options.ignoreCase ?
+ elem.toLowerCase().indexOf(entry.toLowerCase()) :
+ elem.indexOf(entry);
+
+ while (foundPos != -1) {
+ if (foundPos == 0 && elem.length != entry.length) {
+ ret.push("<li><strong>" + elem.substr(0, entry.length) + "</strong>" +
+ elem.substr(entry.length) + "</li>");
+ break;
+ } else if (entry.length >= instance.options.partialChars &&
+ instance.options.partialSearch && foundPos != -1) {
+ if (instance.options.fullSearch || /\s/.test(elem.substr(foundPos-1,1))) {
+ partial.push("<li>" + elem.substr(0, foundPos) + "<strong>" +
+ elem.substr(foundPos, entry.length) + "</strong>" + elem.substr(
+ foundPos + entry.length) + "</li>");
+ break;
+ }
+ }
+
+ foundPos = instance.options.ignoreCase ?
+ elem.toLowerCase().indexOf(entry.toLowerCase(), foundPos + 1) :
+ elem.indexOf(entry, foundPos + 1);
+
+ }
+ }
+ if (partial.length)
+ ret = ret.concat(partial.slice(0, instance.options.choices - ret.length))
+ return "<ul>" + ret.join('') + "</ul>";
+ }
+ }, options || {});
+ }
+});
+
+// AJAX in-place editor
+//
+// The constructor takes three parameters. The first is the element
+// that should support in-place editing. The second is the url to submit
+// the changed value to. The server should respond with the updated
+// value (the server might have post-processed it or validation might
+// have prevented it from changing). The third is a hash of options.
+//
+// Supported options are (all are optional and have sensible defaults):
+// - okText - The text of the submit button that submits the changed value
+// to the server (default: "ok")
+// - cancelText - The text of the link that cancels editing (default: "cancel")
+// - savingText - The text being displayed as the AJAX engine communicates
+// with the server (default: "Saving...")
+// - formId - The id given to the <form> element
+// (default: the id of the element to edit plus '-inplaceeditor')
+
+Ajax.InPlaceEditor = Class.create();
+Ajax.InPlaceEditor.defaultHighlightColor = "#FFFF99";
+Ajax.InPlaceEditor.prototype = {
+ initialize: function(element, url, options) {
+ this.url = url;
+ this.element = $(element);
+
+ this.options = Object.extend({
+ okText: "ok",
+ cancelText: "cancel",
+ savingText: "Saving...",
+ clickToEditText: "Click to edit",
+ okText: "ok",
+ rows: 1,
+ onComplete: function(transport, element) {
+ new Effect.Highlight(element, {startcolor: this.options.highlightcolor});
+ },
+ onFailure: function(transport) {
+ alert("Error communicating with the server: " + transport.responseText.stripTags());
+ },
+ callback: function(form) {
+ return Form.serialize(form);
+ },
+ handleLineBreaks: true,
+ loadingText: 'Loading...',
+ savingClassName: 'inplaceeditor-saving',
+ formClassName: 'inplaceeditor-form',
+ highlightcolor: Ajax.InPlaceEditor.defaultHighlightColor,
+ highlightendcolor: "#FFFFFF",
+ externalControl: null,
+ ajaxOptions: {}
+ }, options || {});
+
+ if(!this.options.formId && this.element.id) {
+ this.options.formId = this.element.id + "-inplaceeditor";
+ if ($(this.options.formId)) {
+ // there's already a form with that name, don't specify an id
+ this.options.formId = null;
+ }
+ }
+
+ if (this.options.externalControl) {
+ this.options.externalControl = $(this.options.externalControl);
+ }
+
+ this.originalBackground = Element.getStyle(this.element, 'background-color');
+ if (!this.originalBackground) {
+ this.originalBackground = "transparent";
+ }
+
+ this.element.title = this.options.clickToEditText;
+
+ this.onclickListener = this.enterEditMode.bindAsEventListener(this);
+ this.mouseoverListener = this.enterHover.bindAsEventListener(this);
+ this.mouseoutListener = this.leaveHover.bindAsEventListener(this);
+ Event.observe(this.element, 'click', this.onclickListener);
+ Event.observe(this.element, 'mouseover', this.mouseoverListener);
+ Event.observe(this.element, 'mouseout', this.mouseoutListener);
+ if (this.options.externalControl) {
+ Event.observe(this.options.externalControl, 'click', this.onclickListener);
+ Event.observe(this.options.externalControl, 'mouseover', this.mouseoverListener);
+ Event.observe(this.options.externalControl, 'mouseout', this.mouseoutListener);
+ }
+ },
+ enterEditMode: function() {
+ if (this.saving) return;
+ if (this.editing) return;
+ this.editing = true;
+ this.onEnterEditMode();
+ if (this.options.externalControl) {
+ Element.hide(this.options.externalControl);
+ }
+ Element.hide(this.element);
+ this.form = this.getForm();
+ this.element.parentNode.insertBefore(this.form, this.element);
+ Field.focus(this.editField);
+ // stop the event to avoid a page refresh in Safari
+ if (arguments.length > 1) {
+ Event.stop(arguments[0]);
+ }
+ },
+ getForm: function() {
+ form = document.createElement("form");
+ form.id = this.options.formId;
+ Element.addClassName(form, this.options.formClassName)
+ form.onsubmit = this.onSubmit.bind(this);
+
+ this.createEditField(form);
+
+ if (this.options.textarea) {
+ var br = document.createElement("br");
+ form.appendChild(br);
+ }
+
+ okButton = document.createElement("input");
+ okButton.type = "submit";
+ okButton.value = this.options.okText;
+ form.appendChild(okButton);
+
+ cancelLink = document.createElement("a");
+ cancelLink.href = "#";
+ cancelLink.appendChild(document.createTextNode(this.options.cancelText));
+ cancelLink.onclick = this.onclickCancel.bind(this);
+ form.appendChild(cancelLink);
+ return form;
+ },
+ hasHTMLLineBreaks: function(string) {
+ if (!this.options.handleLineBreaks) return false;
+ return string.match(/<br/i) || string.match(/<p>/i);
+ },
+ convertHTMLLineBreaks: function(string) {
+ return string.replace(/<br>/gi, "\n").replace(/<br\/>/gi, "\n").replace(/<\/p>/gi, "\n").replace(/<p>/gi, "");
+ },
+ createEditField: function(form) {
+ if (this.options.rows == 1 && !this.hasHTMLLineBreaks(this.getText())) {
+ this.options.textarea = false;
+ var textField = document.createElement("input");
+ textField.type = "text";
+ textField.name = "value";
+ textField.value = this.getText();
+ textField.style.backgroundColor = this.options.highlightcolor;
+ var size = this.options.size || this.options.cols || 0;
+ if (size != 0)
+ textField.size = size;
+ form.appendChild(textField);
+ this.editField = textField;
+ } else {
+ this.options.textarea = true;
+ var textArea = document.createElement("textarea");
+ textArea.name = "value";
+ textArea.value = this.convertHTMLLineBreaks(this.getText());
+ textArea.rows = this.options.rows;
+ textArea.cols = this.options.cols || 40;
+ form.appendChild(textArea);
+ this.editField = textArea;
+ }
+ },
+ getText: function() {
+ if (this.options.loadTextURL) {
+ this.loadExternalText();
+ return this.options.loadingText;
+ } else {
+ return this.element.innerHTML;
+ }
+ },
+ loadExternalText: function() {
+ new Ajax.Request(
+ this.options.loadTextURL,
+ {
+ asynchronous: true,
+ onComplete: this.onLoadedExternalText.bind(this)
+ }
+ );
+ },
+ onLoadedExternalText: function(transport) {
+ this.form.value.value = transport.responseText.stripTags();
+ },
+ onclickCancel: function() {
+ this.onComplete();
+ this.leaveEditMode();
+ return false;
+ },
+ onFailure: function(transport) {
+ this.options.onFailure(transport);
+ if (this.oldInnerHTML) {
+ this.element.innerHTML = this.oldInnerHTML;
+ this.oldInnerHTML = null;
+ }
+ return false;
+ },
+ onSubmit: function() {
+ this.saving = true;
+ new Ajax.Updater(
+ {
+ success: this.element,
+ // don't update on failure (this could be an option)
+ failure: null
+ },
+ this.url,
+ Object.extend({
+ parameters: this.options.callback(this.form, this.editField.value),
+ onComplete: this.onComplete.bind(this),
+ onFailure: this.onFailure.bind(this)
+ }, this.options.ajaxOptions)
+ );
+ this.onLoading();
+ // stop the event to avoid a page refresh in Safari
+ if (arguments.length > 1) {
+ Event.stop(arguments[0]);
+ }
+ return false;
+ },
+ onLoading: function() {
+ this.saving = true;
+ this.removeForm();
+ this.leaveHover();
+ this.showSaving();
+ },
+ showSaving: function() {
+ this.oldInnerHTML = this.element.innerHTML;
+ this.element.innerHTML = this.options.savingText;
+ Element.addClassName(this.element, this.options.savingClassName);
+ this.element.style.backgroundColor = this.originalBackground;
+ Element.show(this.element);
+ },
+ removeForm: function() {
+ if(this.form) {
+ Element.remove(this.form);
+ this.form = null;
+ }
+ },
+ enterHover: function() {
+ if (this.saving) return;
+ this.element.style.backgroundColor = this.options.highlightcolor;
+ if (this.effect) {
+ this.effect.cancel();
+ }
+ Element.addClassName(this.element, this.options.hoverClassName)
+ },
+ leaveHover: function() {
+ if (this.options.backgroundColor) {
+ this.element.style.backgroundColor = this.oldBackground;
+ }
+ Element.removeClassName(this.element, this.options.hoverClassName)
+ if (this.saving) return;
+ this.effect = new Effect.Highlight(this.element, {
+ startcolor: this.options.highlightcolor,
+ endcolor: this.options.highlightendcolor,
+ restorecolor: this.originalBackground
+ });
+ },
+ leaveEditMode: function() {
+ Element.removeClassName(this.element, this.options.savingClassName);
+ this.removeForm();
+ this.leaveHover();
+ this.element.style.backgroundColor = this.originalBackground;
+ Element.show(this.element);
+ if (this.options.externalControl) {
+ Element.show(this.options.externalControl);
+ }
+ this.editing = false;
+ this.saving = false;
+ this.oldInnerHTML = null;
+ this.onLeaveEditMode();
+ },
+ onComplete: function(transport) {
+ this.leaveEditMode();
+ this.options.onComplete.bind(this)(transport, this.element);
+ },
+ onEnterEditMode: function() {},
+ onLeaveEditMode: function() {},
+ dispose: function() {
+ if (this.oldInnerHTML) {
+ this.element.innerHTML = this.oldInnerHTML;
+ }
+ this.leaveEditMode();
+ Event.stopObserving(this.element, 'click', this.onclickListener);
+ Event.stopObserving(this.element, 'mouseover', this.mouseoverListener);
+ Event.stopObserving(this.element, 'mouseout', this.mouseoutListener);
+ if (this.options.externalControl) {
+ Event.stopObserving(this.options.externalControl, 'click', this.onclickListener);
+ Event.stopObserving(this.options.externalControl, 'mouseover', this.mouseoverListener);
+ Event.stopObserving(this.options.externalControl, 'mouseout', this.mouseoutListener);
+ }
+ }
+};
\ No newline at end of file
Propchange: cocoon/blocks/ajax/trunk/java/org/apache/cocoon/ajax/resources/js/controls.js
------------------------------------------------------------------------------
svn:eol-style = native
Propchange: cocoon/blocks/ajax/trunk/java/org/apache/cocoon/ajax/resources/js/controls.js
------------------------------------------------------------------------------
svn:keywords = Id
Added: cocoon/blocks/ajax/trunk/java/org/apache/cocoon/ajax/resources/js/dragdrop.js
URL: http://svn.apache.org/viewcvs/cocoon/blocks/ajax/trunk/java/org/apache/cocoon/ajax/resources/js/dragdrop.js?rev=292158&view=auto
==============================================================================
--- cocoon/blocks/ajax/trunk/java/org/apache/cocoon/ajax/resources/js/dragdrop.js (added)
+++ cocoon/blocks/ajax/trunk/java/org/apache/cocoon/ajax/resources/js/dragdrop.js Wed Sep 28 03:24:51 2005
@@ -0,0 +1,504 @@
+// Copyright (c) 2005 Thomas Fuchs (http://script.aculo.us, http://mir.aculo.us)
+//
+// Element.Class part Copyright (c) 2005 by Rick Olson
+//
+// See scriptaculous.js for full license.
+
+/*--------------------------------------------------------------------------*/
+
+var Droppables = {
+ drops: [],
+
+ remove: function(element) {
+ this.drops = this.drops.reject(function(e) { return e==element });
+ },
+
+ add: function(element) {
+ element = $(element);
+ var options = Object.extend({
+ greedy: true,
+ hoverclass: null
+ }, arguments[1] || {});
+
+ // cache containers
+ if(options.containment) {
+ options._containers = [];
+ var containment = options.containment;
+ if((typeof containment == 'object') &&
+ (containment.constructor == Array)) {
+ containment.each( function(c) { options._containers.push($(c)) });
+ } else {
+ options._containers.push($(containment));
+ }
+ }
+
+ Element.makePositioned(element); // fix IE
+ options.element = element;
+
+ this.drops.push(options);
+ },
+
+ isContained: function(element, drop) {
+ var parentNode = element.parentNode;
+ return drop._containers.detect(function(c) { return parentNode == c });
+ },
+
+ isAffected: function(pX, pY, element, drop) {
+ return (
+ (drop.element!=element) &&
+ ((!drop._containers) ||
+ this.isContained(element, drop)) &&
+ ((!drop.accept) ||
+ (Element.Class.has_any(element, drop.accept))) &&
+ Position.within(drop.element, pX, pY) );
+ },
+
+ deactivate: function(drop) {
+ if(drop.hoverclass)
+ Element.Class.remove(drop.element, drop.hoverclass);
+ this.last_active = null;
+ },
+
+ activate: function(drop) {
+ if(this.last_active) this.deactivate(this.last_active);
+ if(drop.hoverclass)
+ Element.Class.add(drop.element, drop.hoverclass);
+ this.last_active = drop;
+ },
+
+ show: function(event, element) {
+ if(!this.drops.length) return;
+ var pX = Event.pointerX(event);
+ var pY = Event.pointerY(event);
+ Position.prepare();
+
+ var i = this.drops.length-1; do {
+ var drop = this.drops[i];
+ if(this.isAffected(pX, pY, element, drop)) {
+ if(drop.onHover)
+ drop.onHover(element, drop.element, Position.overlap(drop.overlap, drop.element));
+ if(drop.greedy) {
+ this.activate(drop);
+ return;
+ }
+ }
+ } while (i--);
+
+ if(this.last_active) this.deactivate(this.last_active);
+ },
+
+ fire: function(event, element) {
+ if(!this.last_active) return;
+ Position.prepare();
+
+ if (this.isAffected(Event.pointerX(event), Event.pointerY(event), element, this.last_active))
+ if (this.last_active.onDrop)
+ this.last_active.onDrop(element, this.last_active.element);
+ },
+
+ reset: function() {
+ if(this.last_active)
+ this.deactivate(this.last_active);
+ }
+}
+
+var Draggables = {
+ observers: [],
+ addObserver: function(observer) {
+ this.observers.push(observer);
+ },
+ removeObserver: function(element) { // element instead of obsever fixes mem leaks
+ this.observers = this.observers.reject( function(o) { return o.element==element });
+ },
+ notify: function(eventName, draggable) { // 'onStart', 'onEnd'
+ this.observers.invoke(eventName, draggable);
+ }
+}
+
+/*--------------------------------------------------------------------------*/
+
+var Draggable = Class.create();
+Draggable.prototype = {
+ initialize: function(element) {
+ var options = Object.extend({
+ handle: false,
+ starteffect: function(element) {
+ new Effect.Opacity(element, {duration:0.2, from:1.0, to:0.7});
+ },
+ reverteffect: function(element, top_offset, left_offset) {
+ var dur = Math.sqrt(Math.abs(top_offset^2)+Math.abs(left_offset^2))*0.02;
+ new Effect.MoveBy(element, -top_offset, -left_offset, {duration:dur});
+ },
+ endeffect: function(element) {
+ new Effect.Opacity(element, {duration:0.2, from:0.7, to:1.0});
+ },
+ zindex: 1000,
+ revert: false
+ }, arguments[1] || {});
+
+ this.element = $(element);
+ this.handle = options.handle ? $(options.handle) : this.element;
+
+ Element.makePositioned(this.element); // fix IE
+
+ this.offsetX = 0;
+ this.offsetY = 0;
+ this.originalLeft = this.currentLeft();
+ this.originalTop = this.currentTop();
+ this.originalX = this.element.offsetLeft;
+ this.originalY = this.element.offsetTop;
+ this.originalZ = parseInt(this.element.style.zIndex || "0");
+
+ this.options = options;
+
+ this.active = false;
+ this.dragging = false;
+
+ this.eventMouseDown = this.startDrag.bindAsEventListener(this);
+ this.eventMouseUp = this.endDrag.bindAsEventListener(this);
+ this.eventMouseMove = this.update.bindAsEventListener(this);
+ this.eventKeypress = this.keyPress.bindAsEventListener(this);
+
+ Event.observe(this.handle, "mousedown", this.eventMouseDown);
+ },
+ destroy: function() {
+ Event.stopObserving(this.handle, "mousedown", this.eventMouseDown);
+ this.unregisterEvents();
+ },
+ registerEvents: function() {
+ if(this.active) return;
+ Event.observe(document, "mouseup", this.eventMouseUp);
+ Event.observe(document, "mousemove", this.eventMouseMove);
+ Event.observe(document, "keypress", this.eventKeypress);
+ },
+ unregisterEvents: function() {
+ if(!this.active) return;
+ Event.stopObserving(document, "mouseup", this.eventMouseUp);
+ Event.stopObserving(document, "mousemove", this.eventMouseMove);
+ Event.stopObserving(document, "keypress", this.eventKeypress);
+ },
+ currentLeft: function() {
+ return parseInt(this.element.style.left || '0');
+ },
+ currentTop: function() {
+ return parseInt(this.element.style.top || '0')
+ },
+ startDrag: function(event) {
+ if(Event.isLeftClick(event)) {
+
+ // abort on form elements, fixes a Firefox issue
+ var src = Event.element(event);
+ if(src.tagName && (
+ src.tagName=='INPUT' ||
+ src.tagName=='SELECT' ||
+ src.tagName=='BUTTON' ||
+ src.tagName=='TEXTAREA')) return;
+
+ this.registerEvents();
+ this.active = true;
+ var pointer = [Event.pointerX(event), Event.pointerY(event)];
+ var offsets = Position.cumulativeOffset(this.element);
+ this.offsetX = (pointer[0] - offsets[0]);
+ this.offsetY = (pointer[1] - offsets[1]);
+ Event.stop(event);
+ }
+ },
+ finishDrag: function(event, success) {
+ this.unregisterEvents();
+
+ this.active = false;
+ this.dragging = false;
+
+ if(this.options.ghosting) {
+ Position.relativize(this.element);
+ Element.remove(this._clone);
+ this._clone = null;
+ }
+
+ if(success) Droppables.fire(event, this.element);
+ Draggables.notify('onEnd', this);
+
+ var revert = this.options.revert;
+ if(revert && typeof revert == 'function') revert = revert(this.element);
+
+ if(revert && this.options.reverteffect) {
+ this.options.reverteffect(this.element,
+ this.currentTop()-this.originalTop,
+ this.currentLeft()-this.originalLeft);
+ } else {
+ this.originalLeft = this.currentLeft();
+ this.originalTop = this.currentTop();
+ }
+
+ this.element.style.zIndex = this.originalZ;
+
+ if(this.options.endeffect)
+ this.options.endeffect(this.element);
+
+
+ Droppables.reset();
+ },
+ keyPress: function(event) {
+ if(this.active) {
+ if(event.keyCode==Event.KEY_ESC) {
+ this.finishDrag(event, false);
+ Event.stop(event);
+ }
+ }
+ },
+ endDrag: function(event) {
+ if(this.active && this.dragging) {
+ this.finishDrag(event, true);
+ Event.stop(event);
+ }
+ this.active = false;
+ this.dragging = false;
+ },
+ draw: function(event) {
+ var pointer = [Event.pointerX(event), Event.pointerY(event)];
+ var offsets = Position.cumulativeOffset(this.element);
+ offsets[0] -= this.currentLeft();
+ offsets[1] -= this.currentTop();
+ var style = this.element.style;
+ if((!this.options.constraint) || (this.options.constraint=='horizontal'))
+ style.left = (pointer[0] - offsets[0] - this.offsetX) + "px";
+ if((!this.options.constraint) || (this.options.constraint=='vertical'))
+ style.top = (pointer[1] - offsets[1] - this.offsetY) + "px";
+ if(style.visibility=="hidden") style.visibility = ""; // fix gecko rendering
+ },
+ update: function(event) {
+ if(this.active) {
+ if(!this.dragging) {
+ var style = this.element.style;
+ this.dragging = true;
+ if(style.position=="") style.position = "relative";
+ style.zIndex = this.options.zindex;
+
+ if(this.options.ghosting) {
+ this._clone = this.element.cloneNode(true);
+ Position.absolutize(this.element);
+ this.element.parentNode.insertBefore(this._clone, this.element);
+ }
+
+ Draggables.notify('onStart', this);
+ if(this.options.starteffect) this.options.starteffect(this.element);
+ }
+
+ Droppables.show(event, this.element);
+ this.draw(event);
+ if(this.options.change) this.options.change(this);
+
+ // fix AppleWebKit rendering
+ if(navigator.appVersion.indexOf('AppleWebKit')>0) window.scrollBy(0,0);
+
+ Event.stop(event);
+ }
+ }
+}
+
+/*--------------------------------------------------------------------------*/
+
+var SortableObserver = Class.create();
+SortableObserver.prototype = {
+ initialize: function(element, observer) {
+ this.element = $(element);
+ this.observer = observer;
+ this.lastValue = Sortable.serialize(this.element);
+ },
+ onStart: function() {
+ this.lastValue = Sortable.serialize(this.element);
+ },
+ onEnd: function() {
+ Sortable.unmark();
+ if(this.lastValue != Sortable.serialize(this.element))
+ this.observer(this.element)
+ }
+}
+
+var Sortable = {
+ sortables: new Array(),
+ options: function(element){
+ element = $(element);
+ return this.sortables.detect(function(s) { return s.element == element });
+ },
+ destroy: function(element){
+ element = $(element);
+ this.sortables.findAll(function(s) { return s.element == element }).each(function(s){
+ Draggables.removeObserver(s.element);
+ s.droppables.each(function(d){ Droppables.remove(d) });
+ s.draggables.invoke('destroy');
+ });
+ this.sortables = this.sortables.reject(function(s) { return s.element == element });
+ },
+ create: function(element) {
+ element = $(element);
+ var options = Object.extend({
+ element: element,
+ tag: 'li', // assumes li children, override with tag: 'tagname'
+ dropOnEmpty: false,
+ tree: false, // fixme: unimplemented
+ overlap: 'vertical', // one of 'vertical', 'horizontal'
+ constraint: 'vertical', // one of 'vertical', 'horizontal', false
+ containment: element, // also takes array of elements (or id's); or false
+ handle: false, // or a CSS class
+ only: false,
+ hoverclass: null,
+ ghosting: false,
+ onChange: function() {},
+ onUpdate: function() {}
+ }, arguments[1] || {});
+
+ // clear any old sortable with same element
+ this.destroy(element);
+
+ // build options for the draggables
+ var options_for_draggable = {
+ revert: true,
+ ghosting: options.ghosting,
+ constraint: options.constraint,
+ handle: options.handle };
+
+ if(options.starteffect)
+ options_for_draggable.starteffect = options.starteffect;
+
+ if(options.reverteffect)
+ options_for_draggable.reverteffect = options.reverteffect;
+ else
+ if(options.ghosting) options_for_draggable.reverteffect = function(element) {
+ element.style.top = 0;
+ element.style.left = 0;
+ };
+
+ if(options.endeffect)
+ options_for_draggable.endeffect = options.endeffect;
+
+ if(options.zindex)
+ options_for_draggable.zindex = options.zindex;
+
+ // build options for the droppables
+ var options_for_droppable = {
+ overlap: options.overlap,
+ containment: options.containment,
+ hoverclass: options.hoverclass,
+ onHover: Sortable.onHover,
+ greedy: !options.dropOnEmpty
+ }
+
+ // fix for gecko engine
+ Element.cleanWhitespace(element);
+
+ options.draggables = [];
+ options.droppables = [];
+
+ // make it so
+
+ // drop on empty handling
+ if(options.dropOnEmpty) {
+ Droppables.add(element,
+ {containment: options.containment, onHover: Sortable.onEmptyHover, greedy: false});
+ options.droppables.push(element);
+ }
+
+ (this.findElements(element, options) || []).each( function(e) {
+ // handles are per-draggable
+ var handle = options.handle ?
+ Element.Class.childrenWith(e, options.handle)[0] : e;
+ options.draggables.push(
+ new Draggable(e, Object.extend(options_for_draggable, { handle: handle })));
+ Droppables.add(e, options_for_droppable);
+ options.droppables.push(e);
+ });
+
+ // keep reference
+ this.sortables.push(options);
+
+ // for onupdate
+ Draggables.addObserver(new SortableObserver(element, options.onUpdate));
+
+ },
+
+ // return all suitable-for-sortable elements in a guaranteed order
+ findElements: function(element, options) {
+ if(!element.hasChildNodes()) return null;
+ var elements = [];
+ $A(element.childNodes).each( function(e) {
+ if(e.tagName && e.tagName==options.tag.toUpperCase() &&
+ (!options.only || (Element.Class.has(e, options.only))))
+ elements.push(e);
+ if(options.tree) {
+ var grandchildren = this.findElements(e, options);
+ if(grandchildren) elements.push(grandchildren);
+ }
+ });
+
+ return (elements.length>0 ? elements.flatten() : null);
+ },
+
+ onHover: function(element, dropon, overlap) {
+ if(overlap>0.5) {
+ Sortable.mark(dropon, 'before');
+ if(dropon.previousSibling != element) {
+ var oldParentNode = element.parentNode;
+ element.style.visibility = "hidden"; // fix gecko rendering
+ dropon.parentNode.insertBefore(element, dropon);
+ if(dropon.parentNode!=oldParentNode)
+ Sortable.options(oldParentNode).onChange(element);
+ Sortable.options(dropon.parentNode).onChange(element);
+ }
+ } else {
+ Sortable.mark(dropon, 'after');
+ var nextElement = dropon.nextSibling || null;
+ if(nextElement != element) {
+ var oldParentNode = element.parentNode;
+ element.style.visibility = "hidden"; // fix gecko rendering
+ dropon.parentNode.insertBefore(element, nextElement);
+ if(dropon.parentNode!=oldParentNode)
+ Sortable.options(oldParentNode).onChange(element);
+ Sortable.options(dropon.parentNode).onChange(element);
+ }
+ }
+ },
+
+ onEmptyHover: function(element, dropon) {
+ if(element.parentNode!=dropon) {
+ dropon.appendChild(element);
+ }
+ },
+
+ unmark: function() {
+ if(Sortable._marker) Element.hide(Sortable._marker);
+ },
+
+ mark: function(dropon, position) {
+ // mark on ghosting only
+ var sortable = Sortable.options(dropon.parentNode);
+ if(sortable && !sortable.ghosting) return;
+
+ if(!Sortable._marker) {
+ Sortable._marker = $('dropmarker') || document.createElement('DIV');
+ Element.hide(Sortable._marker);
+ Element.Class.add(Sortable._marker, 'dropmarker');
+ Sortable._marker.style.position = 'absolute';
+ document.getElementsByTagName("body").item(0).appendChild(Sortable._marker);
+ }
+ var offsets = Position.cumulativeOffset(dropon);
+ Sortable._marker.style.top = offsets[1] + 'px';
+ if(position=='after') Sortable._marker.style.top = (offsets[1]+dropon.clientHeight) + 'px';
+ Sortable._marker.style.left = offsets[0] + 'px';
+ Element.show(Sortable._marker);
+ },
+
+ serialize: function(element) {
+ element = $(element);
+ var sortableOptions = this.options(element);
+ var options = Object.extend({
+ tag: sortableOptions.tag,
+ only: sortableOptions.only,
+ name: element.id
+ }, arguments[1] || {});
+ return $A(element.childNodes).collect( function(item) {
+ return (encodeURIComponent(options.name) + "[]=" +
+ encodeURIComponent(item.id.split("_")[1]));
+ }).join("&");
+ }
+}
\ No newline at end of file
Propchange: cocoon/blocks/ajax/trunk/java/org/apache/cocoon/ajax/resources/js/dragdrop.js
------------------------------------------------------------------------------
svn:eol-style = native
Propchange: cocoon/blocks/ajax/trunk/java/org/apache/cocoon/ajax/resources/js/dragdrop.js
------------------------------------------------------------------------------
svn:keywords = Id