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 2003/10/03 15:40:41 UTC

cvs commit: cocoon-2.1/src/blocks/woody/java/org/apache/cocoon/woody/util JavaScriptHelper.java

sylvain     2003/10/03 06:40:41

  Modified:    src/blocks/woody/conf woody-binding.xconf
               src/blocks/woody/java/org/apache/cocoon/woody/binding
                        SimpleRepeaterJXPathBinding.java
                        SimpleRepeaterJXPathBindingBuilder.java
               src/blocks/woody/java/org/apache/cocoon/woody/datatype
                        EmptySelectionList.java
               src/blocks/woody/java/org/apache/cocoon/woody/event/impl
                        JavaScriptWidgetListener.java
                        JavaScriptWidgetListenerBuilder.java
  Added:       src/blocks/woody/java/org/apache/cocoon/woody/binding
                        JavaScriptJXPathBinding.java
                        JavaScriptJXPathBindingBuilder.java
               src/blocks/woody/java/org/apache/cocoon/woody/util
                        JavaScriptHelper.java
  Log:
  New JavaScriptBinding
  
  Revision  Changes    Path
  1.5       +1 -0      cocoon-2.1/src/blocks/woody/conf/woody-binding.xconf
  
  Index: woody-binding.xconf
  ===================================================================
  RCS file: /home/cvs/cocoon-2.1/src/blocks/woody/conf/woody-binding.xconf,v
  retrieving revision 1.4
  retrieving revision 1.5
  diff -u -r1.4 -r1.5
  --- woody-binding.xconf	8 Sep 2003 20:40:20 -0000	1.4
  +++ woody-binding.xconf	3 Oct 2003 13:40:41 -0000	1.5
  @@ -13,6 +13,7 @@
         <binding name="insert-node" src="org.apache.cocoon.woody.binding.InsertNodeJXPathBindingBuilder"/>
         <binding name="delete-node" src="org.apache.cocoon.woody.binding.DeleteNodeJXPathBindingBuilder"/>
         <binding name="insert-bean" src="org.apache.cocoon.woody.binding.InsertBeanJXPathBindingBuilder"/>
  +      <binding name="javascript" src="org.apache.cocoon.woody.binding.JavaScriptJXPathBindingBuilder"/>
       </bindings>
     </woody-binding>
   
  
  
  
  1.2       +18 -6     cocoon-2.1/src/blocks/woody/java/org/apache/cocoon/woody/binding/SimpleRepeaterJXPathBinding.java
  
  Index: SimpleRepeaterJXPathBinding.java
  ===================================================================
  RCS file: /home/cvs/cocoon-2.1/src/blocks/woody/java/org/apache/cocoon/woody/binding/SimpleRepeaterJXPathBinding.java,v
  retrieving revision 1.1
  retrieving revision 1.2
  diff -u -r1.1 -r1.2
  --- SimpleRepeaterJXPathBinding.java	8 Sep 2003 15:33:27 -0000	1.1
  +++ SimpleRepeaterJXPathBinding.java	3 Oct 2003 13:40:41 -0000	1.2
  @@ -72,20 +72,25 @@
       private final String repeaterId;
       private final String repeaterPath;
       private final String rowPath;
  +    private final boolean clearOnLoad;
       private final JXPathBindingBase rowBinding;
   
       public SimpleRepeaterJXPathBinding(
  -      String repeaterId, String repeaterPath, String rowPath, JXPathBindingBase rowBinding) {
  +      String repeaterId, String repeaterPath, String rowPath, boolean clearOnLoad, JXPathBindingBase rowBinding) {
           this.repeaterId = repeaterId;
           this.repeaterPath = repeaterPath;
           this.rowPath = rowPath;
           this.rowBinding = rowBinding;
  +        this.clearOnLoad = clearOnLoad;
       }
   
       public void loadFormFromModel(Widget frmModel, JXPathContext jctx) {
           // Find the repeater and clear it
           Repeater repeater = (Repeater) frmModel.getWidget(this.repeaterId);
  -        repeater.removeRows();
  +        
  +        if (this.clearOnLoad) {
  +            repeater.removeRows();
  +        }
   
           // Move to repeater context
           Pointer ptr = jctx.getPointer(this.repeaterPath);
  @@ -97,11 +102,18 @@
               Iterator rowPointers = repeaterContext.iteratePointers(this.rowPath);
   
               //iterate through it
  +            int rowNum = 0;
               while (rowPointers.hasNext()) {
  -                // create a new row, take that as the frmModelSubContext
  -                Repeater.RepeaterRow thisRow = repeater.addRow();
  -    
  -                // make a jxpath ObjectModelSubcontext on the iterated element
  +                // Get a row. It is created if needed (depends on clearOnLoad)
  +                Repeater.RepeaterRow thisRow;
  +                if (repeater.getSize() > rowNum) {
  +                    thisRow = repeater.getRow(rowNum);
  +                } else {
  +                    thisRow = repeater.addRow();
  +                }
  +                rowNum++;
  +     
  +                // make a jxpath sub context on the iterated element
                   Pointer jxp = (Pointer) rowPointers.next();
                   JXPathContext rowContext = repeaterContext.getRelativeContext(jxp);
       
  
  
  
  1.2       +2 -1      cocoon-2.1/src/blocks/woody/java/org/apache/cocoon/woody/binding/SimpleRepeaterJXPathBindingBuilder.java
  
  Index: SimpleRepeaterJXPathBindingBuilder.java
  ===================================================================
  RCS file: /home/cvs/cocoon-2.1/src/blocks/woody/java/org/apache/cocoon/woody/binding/SimpleRepeaterJXPathBindingBuilder.java,v
  retrieving revision 1.1
  retrieving revision 1.2
  diff -u -r1.1 -r1.2
  --- SimpleRepeaterJXPathBindingBuilder.java	8 Sep 2003 15:33:27 -0000	1.1
  +++ SimpleRepeaterJXPathBindingBuilder.java	3 Oct 2003 13:40:41 -0000	1.2
  @@ -77,10 +77,11 @@
               String repeaterId = DomHelper.getAttribute(bindingElem, "id");
               String parentPath = DomHelper.getAttribute(bindingElem, "parent-path");
               String rowPath = DomHelper.getAttribute(bindingElem, "row-path");
  +            boolean clearOnLoad = DomHelper.getAttributeAsBoolean(bindingElem, "clear-before-load", true);
   
               JXPathBindingBase[] childBindings = assistant.makeChildBindings(bindingElem);
   
  -            return new SimpleRepeaterJXPathBinding(repeaterId, parentPath, rowPath,
  +            return new SimpleRepeaterJXPathBinding(repeaterId, parentPath, rowPath, clearOnLoad,
                   new ComposedJXPathBindingBase(childBindings));
           } catch (BindingException e) {
               throw e;
  
  
  
  1.1                  cocoon-2.1/src/blocks/woody/java/org/apache/cocoon/woody/binding/JavaScriptJXPathBinding.java
  
  Index: JavaScriptJXPathBinding.java
  ===================================================================
  /*
  
   ============================================================================
                     The Apache Software License, Version 1.1
   ============================================================================
  
   Copyright (C) 1999-2003 The Apache Software Foundation. All rights reserved.
  
   Redistribution and use in source and binary forms, with or without modifica-
   tion, are permitted provided that the following conditions are met:
  
   1. Redistributions of  source code must  retain the above copyright  notice,
      this list of conditions and the following disclaimer.
  
   2. Redistributions in binary form must reproduce the above copyright notice,
      this list of conditions and the following disclaimer in the documentation
      and/or other materials provided with the distribution.
  
   3. The end-user documentation included with the redistribution, if any, must
      include  the following  acknowledgment:  "This product includes  software
      developed  by the  Apache Software Foundation  (http://www.apache.org/)."
      Alternately, this  acknowledgment may  appear in the software itself,  if
      and wherever such third-party acknowledgments normally appear.
  
   4. The names "Apache Cocoon" and  "Apache Software Foundation" must  not  be
      used to  endorse or promote  products derived from  this software without
      prior written permission. For written permission, please contact
      apache@apache.org.
  
   5. Products  derived from this software may not  be called "Apache", nor may
      "Apache" appear  in their name,  without prior written permission  of the
      Apache Software Foundation.
  
   THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES,
   INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
   FITNESS  FOR A PARTICULAR  PURPOSE ARE  DISCLAIMED.  IN NO  EVENT SHALL  THE
   APACHE SOFTWARE  FOUNDATION  OR ITS CONTRIBUTORS  BE LIABLE FOR  ANY DIRECT,
   INDIRECT, INCIDENTAL, SPECIAL,  EXEMPLARY, OR CONSEQUENTIAL  DAMAGES (INCLU-
   DING, BUT NOT LIMITED TO, PROCUREMENT  OF SUBSTITUTE GOODS OR SERVICES; LOSS
   OF USE, DATA, OR  PROFITS; OR BUSINESS  INTERRUPTION)  HOWEVER CAUSED AND ON
   ANY  THEORY OF LIABILITY,  WHETHER  IN CONTRACT,  STRICT LIABILITY,  OR TORT
   (INCLUDING  NEGLIGENCE OR  OTHERWISE) ARISING IN  ANY WAY OUT OF THE  USE OF
   THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  
   This software  consists of voluntary contributions made  by many individuals
   on  behalf of the Apache Software  Foundation and was  originally created by
   Stefano Mazzocchi  <st...@apache.org>. For more  information on the Apache
   Software Foundation, please see <http://www.apache.org/>.
  
  */
  package org.apache.cocoon.woody.binding;
  
  import java.util.HashMap;
  import java.util.Map;
  
  import org.apache.avalon.framework.CascadingRuntimeException;
  import org.apache.cocoon.components.CocoonComponentManager;
  import org.apache.cocoon.environment.ObjectModelHelper;
  import org.apache.cocoon.environment.Request;
  import org.apache.cocoon.woody.formmodel.Widget;
  import org.apache.cocoon.woody.util.JavaScriptHelper;
  import org.apache.commons.jxpath.JXPathContext;
  import org.apache.commons.jxpath.Pointer;
  import org.mozilla.javascript.Script;
  
  /**
   * 
   * @author <a href="http://www.apache.org/~sylvain/">Sylvain Wallez</a>
   * @version CVS $Id: JavaScriptJXPathBinding.java,v 1.1 2003/10/03 13:40:41 sylvain Exp $
   */
  public class JavaScriptJXPathBinding extends JXPathBindingBase {
      
      private final String id;
      private final String path;
      private final Script loadScript;
      private final Script saveScript;
      
      public JavaScriptJXPathBinding(String id, String path, Script loadScript, Script saveScript) {
          this.id = id;
          this.path = path;
          this.loadScript = loadScript;
          this.saveScript = saveScript;
      }
  
      public void loadFormFromModel(Widget frmModel, JXPathContext jctx) {
          
          if (this.loadScript == null) return;
          
          Widget widget = frmModel.getWidget(this.id);
          
          // Move to widget context
          Pointer pointer = jctx.getPointer(this.path);
          JXPathContext widgetCtx = jctx.getRelativeContext(pointer);
          if (pointer.getNode() != null) {
              // There are some nodes to load from
      
              // FIXME: remove this ugly hack and get the request from the Avalon context once
              // binding builder are real components
              Request request = ObjectModelHelper.getRequest(CocoonComponentManager.getCurrentEnvironment().getObjectModel());
              
              try {
                  Map values = new HashMap(3);
                  values.put("widget", widget);
                  values.put("jxpathContext", widgetCtx);
                  values.put("jxpathPointer", pointer);
                  
                  JavaScriptHelper.execScript(this.loadScript, values, request);
                  
              } catch(RuntimeException re) {
                  // rethrow
                  throw re;
              } catch(Exception e) {
                  throw new CascadingRuntimeException("Error invoking JavaScript event handler", e);
              }
          }
      }
  
      public void saveFormToModel(Widget frmModel, JXPathContext jctx) throws BindingException {
          if (this.saveScript == null) return;
          
          Widget widget = frmModel.getWidget(this.id);
  
          // Move to widget context and create the path if needed
          Pointer pointer = jctx.createPath(this.path);
          JXPathContext widgetCtx = jctx.getRelativeContext(pointer);
          try {
              // FIXME: remove this ugly hack and get the request from the Avalon context once
              // binding builder are real components
              Request request = ObjectModelHelper.getRequest(CocoonComponentManager.getCurrentEnvironment().getObjectModel());
  
              Map values = new HashMap();
              values.put("widget", widget);
              values.put("jxpathContext", widgetCtx);
              values.put("jxpathPointer", pointer);
  
              JavaScriptHelper.execScript(this.saveScript, values, request);
                  
          } catch(RuntimeException re) {
              // rethrow
              throw re;
          } catch(Exception e) {
              throw new CascadingRuntimeException("Error invoking JavaScript event handler", e);
          }
      }
  
  }
  
  
  
  1.1                  cocoon-2.1/src/blocks/woody/java/org/apache/cocoon/woody/binding/JavaScriptJXPathBindingBuilder.java
  
  Index: JavaScriptJXPathBindingBuilder.java
  ===================================================================
  /*
  
   ============================================================================
                     The Apache Software License, Version 1.1
   ============================================================================
  
   Copyright (C) 1999-2003 The Apache Software Foundation. All rights reserved.
  
   Redistribution and use in source and binary forms, with or without modifica-
   tion, are permitted provided that the following conditions are met:
  
   1. Redistributions of  source code must  retain the above copyright  notice,
      this list of conditions and the following disclaimer.
  
   2. Redistributions in binary form must reproduce the above copyright notice,
      this list of conditions and the following disclaimer in the documentation
      and/or other materials provided with the distribution.
  
   3. The end-user documentation included with the redistribution, if any, must
      include  the following  acknowledgment:  "This product includes  software
      developed  by the  Apache Software Foundation  (http://www.apache.org/)."
      Alternately, this  acknowledgment may  appear in the software itself,  if
      and wherever such third-party acknowledgments normally appear.
  
   4. The names "Apache Cocoon" and  "Apache Software Foundation" must  not  be
      used to  endorse or promote  products derived from  this software without
      prior written permission. For written permission, please contact
      apache@apache.org.
  
   5. Products  derived from this software may not  be called "Apache", nor may
      "Apache" appear  in their name,  without prior written permission  of the
      Apache Software Foundation.
  
   THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES,
   INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
   FITNESS  FOR A PARTICULAR  PURPOSE ARE  DISCLAIMED.  IN NO  EVENT SHALL  THE
   APACHE SOFTWARE  FOUNDATION  OR ITS CONTRIBUTORS  BE LIABLE FOR  ANY DIRECT,
   INDIRECT, INCIDENTAL, SPECIAL,  EXEMPLARY, OR CONSEQUENTIAL  DAMAGES (INCLU-
   DING, BUT NOT LIMITED TO, PROCUREMENT  OF SUBSTITUTE GOODS OR SERVICES; LOSS
   OF USE, DATA, OR  PROFITS; OR BUSINESS  INTERRUPTION)  HOWEVER CAUSED AND ON
   ANY  THEORY OF LIABILITY,  WHETHER  IN CONTRACT,  STRICT LIABILITY,  OR TORT
   (INCLUDING  NEGLIGENCE OR  OTHERWISE) ARISING IN  ANY WAY OUT OF THE  USE OF
   THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  
   This software  consists of voluntary contributions made  by many individuals
   on  behalf of the Apache Software  Foundation and was  originally created by
   Stefano Mazzocchi  <st...@apache.org>. For more  information on the Apache
   Software Foundation, please see <http://www.apache.org/>.
  
  */
  package org.apache.cocoon.woody.binding;
  
  import org.apache.cocoon.woody.binding.JXPathBindingManager.Assistant;
  import org.apache.cocoon.woody.util.DomHelper;
  import org.apache.cocoon.woody.util.JavaScriptHelper;
  import org.mozilla.javascript.Script;
  import org.w3c.dom.Element;
  
  /**
   * Builds a {@link Binding} based on two JavaScript snippets, respectively for loading and saving the form.
   * <p>
   * The syntax for this binding is as follows :
   * <pre>
   *   &lt;wb:javascript id="foo" path="@foo"&gt;
   *     &lt;wb:load-form&gt;
   *       var appValue = jxpathPointer.getValue();
   *       var formValue = doLoadConversion(appValue);
   *       widget.setValue(formValue);
   *     &lt;/wb:load-form&gt;
   *     &lt;wb:save-form&gt;
   *       var formValue = widget.getValue();
   *       var appValue = doSaveConversion(formValue);
   *       jxpathPointer.setValue(appValue);
   *     &lt;/wb:save-form&gt;
   *   &lt;/wb:javascript&gt;
   * </pre>
   * This example is rather trivial and could be replaced by a simple &lt;wb:value&gt;, but
   * it shows the available variables in the script:
   * <ul>
   * <li><code>widget</code>: the widget identified by the "id" attribute,
   * <li><code>jxpathPointer</code>: the JXPath pointer corresponding to the "path" attribute,
   * <li><code>jxpathContext</code> (not shown): the JXPath context corresponding to the "path" attribute
   * </ul>
   * The &lt;wb:save-form&gt; snippet should be ommitted if the "read-only" attribute is present.
   * 
   * @author <a href="http://www.apache.org/~sylvain/">Sylvain Wallez</a>
   * @version CVS $Id: JavaScriptJXPathBindingBuilder.java,v 1.1 2003/10/03 13:40:41 sylvain Exp $
   */
  public class JavaScriptJXPathBindingBuilder extends JXpathBindingBuilderBase {
  
      public JXPathBindingBase buildBinding(Element element, Assistant assistant) throws BindingException {
          try {
              String id = DomHelper.getAttribute(element, "id");
              String path = DomHelper.getAttribute(element, "path");
              
              boolean readOnly = DomHelper.getAttributeAsBoolean(element, "read-only", false);
          
  
              Element loadElem = DomHelper.getChildElement(element, BindingManager.NAMESPACE, "load-form");
              Script loadScript = JavaScriptHelper.buildScript(loadElem);
              
              Script saveScript;
              if (readOnly) {
                  saveScript = null;
              } else {
                  Element saveElem = DomHelper.getChildElement(element, BindingManager.NAMESPACE, "save-form");
                  saveScript = JavaScriptHelper.buildScript(saveElem);
              }
  
              return new JavaScriptJXPathBinding(id, path, loadScript, saveScript);
  
          } catch(Exception e) {
              throw new BindingException("Cannot build binding at " + DomHelper.getLocation(element), e);
          }
      }
  
  }
  
  
  
  1.2       +1 -2      cocoon-2.1/src/blocks/woody/java/org/apache/cocoon/woody/datatype/EmptySelectionList.java
  
  Index: EmptySelectionList.java
  ===================================================================
  RCS file: /home/cvs/cocoon-2.1/src/blocks/woody/java/org/apache/cocoon/woody/datatype/EmptySelectionList.java,v
  retrieving revision 1.1
  retrieving revision 1.2
  diff -u -r1.1 -r1.2
  --- EmptySelectionList.java	26 Sep 2003 14:44:07 -0000	1.1
  +++ EmptySelectionList.java	3 Oct 2003 13:40:41 -0000	1.2
  @@ -54,7 +54,6 @@
   
   import org.apache.cocoon.transformation.I18nTransformer;
   import org.apache.cocoon.woody.Constants;
  -import org.apache.cocoon.woody.datatype.typeimpl.StringType;
   import org.apache.cocoon.xml.AttributesImpl;
   import org.xml.sax.ContentHandler;
   import org.xml.sax.SAXException;
  
  
  
  1.4       +9 -43     cocoon-2.1/src/blocks/woody/java/org/apache/cocoon/woody/event/impl/JavaScriptWidgetListener.java
  
  Index: JavaScriptWidgetListener.java
  ===================================================================
  RCS file: /home/cvs/cocoon-2.1/src/blocks/woody/java/org/apache/cocoon/woody/event/impl/JavaScriptWidgetListener.java,v
  retrieving revision 1.3
  retrieving revision 1.4
  diff -u -r1.3 -r1.4
  --- JavaScriptWidgetListener.java	29 Sep 2003 13:01:03 -0000	1.3
  +++ JavaScriptWidgetListener.java	3 Oct 2003 13:40:41 -0000	1.4
  @@ -50,10 +50,11 @@
   */
   package org.apache.cocoon.woody.event.impl;
   
  +import java.util.HashMap;
  +
   import org.apache.avalon.framework.CascadingRuntimeException;
   import org.apache.cocoon.components.CocoonComponentManager;
   import org.apache.cocoon.components.flow.FlowHelper;
  -import org.apache.cocoon.components.flow.javascript.fom.FOM_JavaScriptFlowHelper;
   import org.apache.cocoon.environment.ObjectModelHelper;
   import org.apache.cocoon.environment.Request;
   import org.apache.cocoon.woody.event.ActionEvent;
  @@ -61,84 +62,49 @@
   import org.apache.cocoon.woody.event.ValueChangedEvent;
   import org.apache.cocoon.woody.event.ValueChangedListener;
   import org.apache.cocoon.woody.event.WidgetEvent;
  -import org.mozilla.javascript.Context;
  +import org.apache.cocoon.woody.util.JavaScriptHelper;
   import org.mozilla.javascript.Script;
  -import org.mozilla.javascript.Scriptable;
   
   /**
    * Listeners built by {@link org.apache.cocoon.woody.event.impl.JavaScriptWidgetListenerBuilder}
    * 
    * @author <a href="http://www.apache.org/~sylvain/">Sylvain Wallez</a>
  + * @version CVS $Id$
    */
   public abstract class JavaScriptWidgetListener {
       
  -    private static Scriptable _rootScope = null;
  -    
       private Script script;
       
       public JavaScriptWidgetListener(Script script) {
           this.script = script;
       }
       
  -    public static Scriptable getRootScope() {
  -        if (_rootScope == null) {
  -            // Create it if never used up to now
  -            Context ctx = Context.enter();
  -            try {
  -                _rootScope = ctx.initStandardObjects(null);
  -            } finally {
  -                Context.exit();
  -            }
  -        }
  -        
  -        return _rootScope;
  -        
  -    }
  -    
  -    public static Scriptable getParentScope(Request request) {
  -        // Try to get the flowscript scope
  -        Scriptable parentScope = (Scriptable)request.getAttribute(FOM_JavaScriptFlowHelper.FOM_SCOPE);
  -
  -        if (parentScope != null) {
  -            return parentScope;
  -        } else {
  -            return getRootScope();
  -        }
  -    }
  -
       /**
        * Call the script that implements the event handler
        */
       protected void callScript(WidgetEvent event) {
  -        Context ctx = Context.enter();
           try {
               
  +            HashMap values = new HashMap(2);
  +            values.put("event", event);
  +            
               // FIXME: remove this ugly hack and get the request from the Avalon context once
               // listener builder are real components
               Request request = ObjectModelHelper.getRequest(CocoonComponentManager.getCurrentEnvironment().getObjectModel());
  -
  -            Scriptable parentScope = getParentScope(request);
  -            
  -            // Create a new local scope for the event listener variables
  -            Scriptable scope = ctx.newObject(parentScope);
  -            scope.setPrototype(parentScope);
  -            scope.put("event", scope, Context.toObject(event, scope));
               
               // Add the biz data that was passed to showForm()
               Object viewData = request.getAttribute(FlowHelper.CONTEXT_OBJECT);
               if (viewData != null) {
  -                scope.put("viewData", scope, viewData);
  +                values.put("viewData", viewData);
               }
               
  -            script.exec(ctx, scope);
  +            JavaScriptHelper.execScript(this.script, values, request);
               
           } catch(RuntimeException re) {
               // rethrow
               throw re;
           } catch(Exception e) {
               throw new CascadingRuntimeException("Error invoking JavaScript event handler", e);
  -        } finally {
  -            Context.exit();
           }
       }
       
  
  
  
  1.2       +11 -23    cocoon-2.1/src/blocks/woody/java/org/apache/cocoon/woody/event/impl/JavaScriptWidgetListenerBuilder.java
  
  Index: JavaScriptWidgetListenerBuilder.java
  ===================================================================
  RCS file: /home/cvs/cocoon-2.1/src/blocks/woody/java/org/apache/cocoon/woody/event/impl/JavaScriptWidgetListenerBuilder.java,v
  retrieving revision 1.1
  retrieving revision 1.2
  diff -u -r1.1 -r1.2
  --- JavaScriptWidgetListenerBuilder.java	24 Sep 2003 20:47:06 -0000	1.1
  +++ JavaScriptWidgetListenerBuilder.java	3 Oct 2003 13:40:41 -0000	1.2
  @@ -50,14 +50,11 @@
   */
   package org.apache.cocoon.woody.event.impl;
   
  -import java.io.StringReader;
  -
   import org.apache.cocoon.woody.event.ActionListener;
  +import org.apache.cocoon.woody.event.ValueChangedEvent;
   import org.apache.cocoon.woody.event.WidgetListener;
   import org.apache.cocoon.woody.event.WidgetListenerBuilder;
  -import org.apache.cocoon.woody.event.ValueChangedEvent;
  -import org.apache.cocoon.woody.util.DomHelper;
  -import org.mozilla.javascript.Context;
  +import org.apache.cocoon.woody.util.JavaScriptHelper;
   import org.mozilla.javascript.Script;
   import org.w3c.dom.Element;
   
  @@ -79,25 +76,16 @@
   public class JavaScriptWidgetListenerBuilder implements WidgetListenerBuilder {
   
       public WidgetListener buildListener(Element element, Class listenerClass) throws Exception {
  -        String jsText = DomHelper.getElementText(element);
           
  -        String sourceName = DomHelper.getSystemIdLocation(element);
  +        Script script = JavaScriptHelper.buildScript(element);
           
  -        Context ctx = Context.enter();
  -        Script script = ctx.compileReader(
  -            JavaScriptWidgetListener.getRootScope(), //scope
  -            new StringReader(jsText), // in
  -            sourceName == null ? "<unknown>" : sourceName, // sourceName
  -            DomHelper.getLineLocation(element), // lineNo
  -            null // securityDomain
  -         );
  -         
  -         if (listenerClass == ActionListener.class) {
  -             return new JavaScriptWidgetListener.JSActionListener(script);
  -         } else if (listenerClass == ValueChangedEvent.class) {
  -             return new JavaScriptWidgetListener.JSValueChangedListener(script);
  -         } else {
  -             throw new Exception("Unkonwn event class: " + listenerClass);
  -         }
  +        if (listenerClass == ActionListener.class) {
  +            return new JavaScriptWidgetListener.JSActionListener(script);
  +        } else if (listenerClass == ValueChangedEvent.class) {
  +            return new JavaScriptWidgetListener.JSValueChangedListener(script);
  +        } else {
  +            throw new Exception("Unkonwn event class: " + listenerClass);
  +        }
       }
  +    
   }
  
  
  
  1.1                  cocoon-2.1/src/blocks/woody/java/org/apache/cocoon/woody/util/JavaScriptHelper.java
  
  Index: JavaScriptHelper.java
  ===================================================================
  /*
  
   ============================================================================
                     The Apache Software License, Version 1.1
   ============================================================================
  
   Copyright (C) 1999-2003 The Apache Software Foundation. All rights reserved.
  
   Redistribution and use in source and binary forms, with or without modifica-
   tion, are permitted provided that the following conditions are met:
  
   1. Redistributions of  source code must  retain the above copyright  notice,
      this list of conditions and the following disclaimer.
  
   2. Redistributions in binary form must reproduce the above copyright notice,
      this list of conditions and the following disclaimer in the documentation
      and/or other materials provided with the distribution.
  
   3. The end-user documentation included with the redistribution, if any, must
      include  the following  acknowledgment:  "This product includes  software
      developed  by the  Apache Software Foundation  (http://www.apache.org/)."
      Alternately, this  acknowledgment may  appear in the software itself,  if
      and wherever such third-party acknowledgments normally appear.
  
   4. The names "Apache Cocoon" and  "Apache Software Foundation" must  not  be
      used to  endorse or promote  products derived from  this software without
      prior written permission. For written permission, please contact
      apache@apache.org.
  
   5. Products  derived from this software may not  be called "Apache", nor may
      "Apache" appear  in their name,  without prior written permission  of the
      Apache Software Foundation.
  
   THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES,
   INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
   FITNESS  FOR A PARTICULAR  PURPOSE ARE  DISCLAIMED.  IN NO  EVENT SHALL  THE
   APACHE SOFTWARE  FOUNDATION  OR ITS CONTRIBUTORS  BE LIABLE FOR  ANY DIRECT,
   INDIRECT, INCIDENTAL, SPECIAL,  EXEMPLARY, OR CONSEQUENTIAL  DAMAGES (INCLU-
   DING, BUT NOT LIMITED TO, PROCUREMENT  OF SUBSTITUTE GOODS OR SERVICES; LOSS
   OF USE, DATA, OR  PROFITS; OR BUSINESS  INTERRUPTION)  HOWEVER CAUSED AND ON
   ANY  THEORY OF LIABILITY,  WHETHER  IN CONTRACT,  STRICT LIABILITY,  OR TORT
   (INCLUDING  NEGLIGENCE OR  OTHERWISE) ARISING IN  ANY WAY OUT OF THE  USE OF
   THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  
   This software  consists of voluntary contributions made  by many individuals
   on  behalf of the Apache Software  Foundation and was  originally created by
   Stefano Mazzocchi  <st...@apache.org>. For more  information on the Apache
   Software Foundation, please see <http://www.apache.org/>.
  
  */
  package org.apache.cocoon.woody.util;
  
  import java.io.IOException;
  import java.io.StringReader;
  import java.util.Iterator;
  import java.util.Map;
  
  import org.apache.avalon.framework.CascadingRuntimeException;
  import org.apache.cocoon.components.flow.javascript.fom.FOM_JavaScriptFlowHelper;
  import org.apache.cocoon.environment.Request;
  import org.mozilla.javascript.Context;
  import org.mozilla.javascript.JavaScriptException;
  import org.mozilla.javascript.Script;
  import org.mozilla.javascript.Scriptable;
  import org.w3c.dom.Element;
  
  /**
   * Helper methods to use JavaScript in various locations of the Woody configuration files
   * such as event listeners and bindings.
   * 
   * @author <a href="http://www.apache.org/~sylvain/">Sylvain Wallez</a>
   * @version CVS $Id: JavaScriptHelper.java,v 1.1 2003/10/03 13:40:41 sylvain Exp $
   */
  public class JavaScriptHelper {
      
      /**
       * A shared root scope, avoiding to recreate a new one each time.
       */
      private static Scriptable _rootScope = null;
      
      /**
       * Build a script with the content of a DOM element.
       * 
       * @param element the element containing the script
       * @return the compiled script
       * @throws IOException
       */
      public static Script buildScript(Element element) throws IOException {
          String jsText = DomHelper.getElementText(element);
          String sourceName = DomHelper.getSystemIdLocation(element);
          
          Context ctx = Context.enter();
          Script script;
          try {
              script = ctx.compileReader(
                  getRootScope(), //scope
                  new StringReader(jsText), // in
                  sourceName == null ? "<unknown>" : sourceName, // sourceName
                  DomHelper.getLineLocation(element), // lineNo
                  null // securityDomain
               );
          } finally {
              Context.exit();
          }
          
          return script;
      }
      
      /**
       * Get a root scope for building child scopes.
       * 
       * @return an appropriate root scope
       */
      private static Scriptable getRootScope() {
          if (_rootScope == null) {
              // Create it if never used up to now
              Context ctx = Context.enter();
              try {
                  _rootScope = ctx.initStandardObjects(null);
              } finally {
                  Context.exit();
              }
          }
          
          return _rootScope;
          
      }
      
      /**
       * Get a parent scope for building a child scope. The request is searched for an existing scope
       * that can be provided by a flowscript higher in the call stack, giving visibility to flowscript
       * functions and global (session) variables.
       * 
       * @param request a request where the flowscript scope will be searched (can be <code>null</code>).
       * @return an appropriate parent scope.
       */
      public static Scriptable getParentScope(Request request) {
          // Try to get the flowscript scope
          Scriptable parentScope = null;
          if (request != null) {
              parentScope = (Scriptable)request.getAttribute(FOM_JavaScriptFlowHelper.FOM_SCOPE);
          }
  
          if (parentScope != null) {
              return parentScope;
          } else {
              return getRootScope();
          }
      }
  
      public static Object execScript(Script script, Map values, Request request) throws JavaScriptException {
          Context ctx = Context.enter();
          try {
              
              Scriptable parentScope = getParentScope(request);
              
              // Create a new local scope for the event listener variables
              Scriptable scope;
              try {
                  scope = ctx.newObject(parentScope);
              } catch (Exception e) {
                  // Should normally not happen
                  throw new CascadingRuntimeException("Cannont create script scope", e);
              }
              
              scope.setPrototype(parentScope);
              
              // Populate the scope
              Iterator iter = values.entrySet().iterator();
              while(iter.hasNext()) {
                  Map.Entry entry = (Map.Entry)iter.next();
                  String key = (String)entry.getKey();
                  Object value = entry.getValue();
                  scope.put(key, scope, Context.toObject(value, scope));
              }
              
              return script.exec(ctx, scope);
             
          } finally {
              Context.exit();
          }
      }
  
  }