Repository: tapestry-5
Updated Branches:
  refs/heads/5.4.x b10fa77d2 -> d8a7dbf9d


TAP5-2225

Create client-side API to call a component's event handler methods

Project: http://git-wip-us.apache.org/repos/asf/tapestry-5/repo
Commit: http://git-wip-us.apache.org/repos/asf/tapestry-5/commit/19fe6853
Tree: http://git-wip-us.apache.org/repos/asf/tapestry-5/tree/19fe6853
Diff: http://git-wip-us.apache.org/repos/asf/tapestry-5/diff/19fe6853

Branch: refs/heads/5.4.x
Commit: 19fe685300d7eb12c6837fdfe165bc081415209d
Parents: b10fa77
Author: Thiago H. de Paula Figueiredo <[email protected]>
Authored: Sun Mar 19 13:07:00 2017 -0300
Committer: Thiago H. de Paula Figueiredo <[email protected]>
Committed: Sun Mar 19 16:15:04 2017 -0300

----------------------------------------------------------------------
 .../org/apache/tapestry5/TapestryConstants.java |  11 ++
 .../tapestry5/annotations/PublishEvent.java     |  50 ++++++
 .../corelib/mixins/PublishServerSideEvents.java | 151 +++++++++++++++++++
 .../tapestry5/internal/InternalConstants.java   |  17 +++
 .../internal/transform/OnEventWorker.java       |  54 ++++++-
 .../org/apache/tapestry5/t5-core-dom.coffee     |  56 +++++++
 .../src/test/app1/PublishEventDemo.tml          |   7 +
 .../components/PublishEventDemoComponent.java   |  32 ++++
 .../components/PublishEventDemoComponent2.java  |  32 ++++
 .../tapestry5/integration/app1/pages/Index.java |  21 +--
 .../app1/pages/PublishEventDemo.java            |  49 ++++++
 .../META-INF/assets/PublishEventDemo.js         |  11 ++
 .../components/PublishEventDemoComponent.tml    |   3 +
 .../components/PublishEventDemoComponent2.tml   |   4 +
 14 files changed, 482 insertions(+), 16 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/19fe6853/tapestry-core/src/main/java/org/apache/tapestry5/TapestryConstants.java
----------------------------------------------------------------------
diff --git 
a/tapestry-core/src/main/java/org/apache/tapestry5/TapestryConstants.java 
b/tapestry-core/src/main/java/org/apache/tapestry5/TapestryConstants.java
index ad1495a..cab8c46 100644
--- a/tapestry-core/src/main/java/org/apache/tapestry5/TapestryConstants.java
+++ b/tapestry-core/src/main/java/org/apache/tapestry5/TapestryConstants.java
@@ -12,6 +12,7 @@
 
 package org.apache.tapestry5;
 
+import org.apache.tapestry5.annotations.PublishEvent;
 import org.apache.tapestry5.internal.structure.PageResetListener;
 import org.apache.tapestry5.services.ComponentEventLinkEncoder;
 
@@ -68,4 +69,14 @@ public class TapestryConstants
      */
     public static final String DISABLE_JAVASCRIPT_MINIMIZATION = 
"tapestry.disable-javascript-minimization";
 
+    /**
+     * Name of the HTML data attribute which contains information about 
component events
+     * published by using the {@linkplain PublishEvent} annotation
+     * in a component event handler method.
+     * 
+     * @see PublishEvent
+     * @since 5.4.2
+     */
+    public static final String COMPONENT_EVENTS_ATTRIBUTE_NAME = 
"data-component-events";
+
 }

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/19fe6853/tapestry-core/src/main/java/org/apache/tapestry5/annotations/PublishEvent.java
----------------------------------------------------------------------
diff --git 
a/tapestry-core/src/main/java/org/apache/tapestry5/annotations/PublishEvent.java
 
b/tapestry-core/src/main/java/org/apache/tapestry5/annotations/PublishEvent.java
new file mode 100644
index 0000000..18239d4
--- /dev/null
+++ 
b/tapestry-core/src/main/java/org/apache/tapestry5/annotations/PublishEvent.java
@@ -0,0 +1,50 @@
+// 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.tapestry5.annotations;
+
+import static java.lang.annotation.RetentionPolicy.RUNTIME;
+import static 
org.apache.tapestry5.ioc.annotations.AnnotationUseContext.COMPONENT;
+import static org.apache.tapestry5.ioc.annotations.AnnotationUseContext.PAGE;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.Target;
+
+import org.apache.tapestry5.ioc.annotations.UseWith;
+
+/**
+ * Marks an event handler method to be published as an event to be called in 
JavaScript
+ * through the <code>t5/core/triggerServerEvent</code> function.
+ * 
+ * The event information is stored in JSON format inside the 
+ * {@value 
org.apache.tapestry5.TapestryConstants#COMPONENT_EVENTS_ATTRIBUTE_NAME} 
attribute.
+ * 
+ * When used in a component method, the component must render at least one 
element,
+ * and that's what get the 
+ * {@value 
org.apache.tapestry5.TapestryConstants#COMPONENT_EVENTS_ATTRIBUTE_NAME} 
attribute above. 
+ * If it doesn't, an exception will be thrown.
+ * 
+ * When used in a page method, the page must render an &lt;body&gt; element,
+ * {@value 
org.apache.tapestry5.TapestryConstants#COMPONENT_EVENTS_ATTRIBUTE_NAME}. If it 
doesn't,
+ * an exception will be thrown.
+ * 
+ * @since 5.4.2
+ */
+@Target(ElementType.METHOD)
+@Retention(RUNTIME)
+@Documented
+@UseWith({ COMPONENT, PAGE })
+public @interface PublishEvent
+{
+}

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/19fe6853/tapestry-core/src/main/java/org/apache/tapestry5/corelib/mixins/PublishServerSideEvents.java
----------------------------------------------------------------------
diff --git 
a/tapestry-core/src/main/java/org/apache/tapestry5/corelib/mixins/PublishServerSideEvents.java
 
b/tapestry-core/src/main/java/org/apache/tapestry5/corelib/mixins/PublishServerSideEvents.java
new file mode 100644
index 0000000..3d73746
--- /dev/null
+++ 
b/tapestry-core/src/main/java/org/apache/tapestry5/corelib/mixins/PublishServerSideEvents.java
@@ -0,0 +1,151 @@
+// 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.tapestry5.corelib.mixins;
+
+import org.apache.tapestry5.ComponentResources;
+import org.apache.tapestry5.MarkupWriter;
+import org.apache.tapestry5.MarkupWriterListener;
+import org.apache.tapestry5.TapestryConstants;
+import org.apache.tapestry5.annotations.PublishEvent;
+import org.apache.tapestry5.dom.Element;
+import org.apache.tapestry5.internal.InternalConstants;
+import org.apache.tapestry5.ioc.annotations.Inject;
+import org.apache.tapestry5.json.JSONArray;
+import org.apache.tapestry5.json.JSONObject;
+import org.apache.tapestry5.model.ComponentModel;
+
+/**
+ * Tapestry internal mixin used to implement the {@link PublishEvent} event 
logic. Don't use directly.
+ */
+public class PublishServerSideEvents
+{
+    
+    private static final String PUBLISH_COMPONENT_EVENTS_URL_PROPERTY = 
InternalConstants.PUBLISH_COMPONENT_EVENTS_URL_PROPERTY;
+    private static final String COMPONENT_EVENTS_ATTRIBUTE_NAME = 
TapestryConstants.COMPONENT_EVENTS_ATTRIBUTE_NAME;
+    
+    @Inject
+    private ComponentResources resources;
+    
+    void beginRender(final MarkupWriter writer) {
+    
+        final Element element = writer.getElement();
+        
+        // When the component is actually a page, nothing was rendered yet.
+        // The listener we add here will add the events attribute to the 
<body> element
+        // later
+        if (element == null) {
+            writer.addListener(new BodyElementListener(writer));
+        }
+        else {
+            writer.addListener(new DelayedListener(writer));
+        }
+        
+    }
+    
+    private void addEventsAttribute(final Element element)
+    {
+        
+        if (element == null)
+        {
+            throw new IllegalStateException("@PublishEvent used inside a page 
which didn't generate a <body> element");
+        }
+
+        final ComponentResources containerResources = 
resources.getContainerResources();
+        final ComponentModel componentModel = 
containerResources.getComponentModel();
+        final String metaValue = 
componentModel.getMeta(InternalConstants.PUBLISH_COMPONENT_EVENTS_META);
+        final JSONArray componentEvents = new JSONArray(metaValue);
+        final JSONObject events = new JSONObject();
+        final String existingValue = 
element.getAttribute(COMPONENT_EVENTS_ATTRIBUTE_NAME);
+        
+        if (existingValue != null) 
+        {
+            final JSONObject existing = new JSONObject(existingValue);
+            for (String key : existing.keys()) {
+                events.put(key, existing.get(key));
+            }
+        }
+        
+        for (int i = 0; i < componentEvents.length(); i++) 
+        {
+            final String eventName = componentEvents.getString(i);
+            JSONObject event = new JSONObject();
+            event.put(PUBLISH_COMPONENT_EVENTS_URL_PROPERTY, 
containerResources.createEventLink(eventName).toString());
+            events.put(eventName, event);
+        }
+        
+        
element.forceAttributes(TapestryConstants.COMPONENT_EVENTS_ATTRIBUTE_NAME, 
events.toString());
+    }
+
+    final private class DelayedListener implements MarkupWriterListener {
+        
+        private MarkupWriter writer;
+        
+        private Element element;
+        
+        public DelayedListener(MarkupWriter writer)
+        {
+            super();
+            this.writer = writer;
+        }
+
+        @Override
+        public void elementDidStart(Element element)
+        {
+            // Store first element generated by rendering the component
+            if (this.element == null)
+            {
+                this.element = element;
+            }
+        }
+
+        @Override
+        public void elementDidEnd(Element element)
+        {
+            if (this.element == null)
+            {
+                throw new IllegalStateException("@PublishEvent used inside a 
component which didn't generate any HTML elements");
+            }
+            addEventsAttribute(this.element);
+            writer.removeListener(this);
+        }
+        
+    }
+    
+    final private class BodyElementListener implements MarkupWriterListener {
+        
+        private MarkupWriter writer;
+        
+        public BodyElementListener(MarkupWriter writer)
+        {
+            super();
+            this.writer = writer;
+        }
+
+        @Override
+        public void elementDidStart(Element element)
+        {
+            if (element.getName().equals("body")) 
+            {
+                addEventsAttribute(element);
+                writer.removeListener(this);
+            }
+        }
+
+        @Override
+        public void elementDidEnd(Element element)
+        {
+        }
+        
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/19fe6853/tapestry-core/src/main/java/org/apache/tapestry5/internal/InternalConstants.java
----------------------------------------------------------------------
diff --git 
a/tapestry-core/src/main/java/org/apache/tapestry5/internal/InternalConstants.java
 
b/tapestry-core/src/main/java/org/apache/tapestry5/internal/InternalConstants.java
index 32b80a6..8370ae0 100644
--- 
a/tapestry-core/src/main/java/org/apache/tapestry5/internal/InternalConstants.java
+++ 
b/tapestry-core/src/main/java/org/apache/tapestry5/internal/InternalConstants.java
@@ -13,8 +13,10 @@
 package org.apache.tapestry5.internal;
 
 import org.apache.tapestry5.ContentType;
+import org.apache.tapestry5.annotations.PublishEvent;
 import org.apache.tapestry5.dom.MarkupModel;
 import org.apache.tapestry5.ioc.util.TimeInterval;
+import org.apache.tapestry5.model.ComponentModel;
 import org.apache.tapestry5.services.javascript.JavaScriptStack;
 
 public final class InternalConstants
@@ -213,4 +215,19 @@ public final class InternalConstants
      * @since 5.4
      */
     public static final ContentType JAVASCRIPT_CONTENT_TYPE = new 
ContentType("text/javascript");
+    
+    /**
+     * Name of the {@linkplain ComponentModel} metadata key whiche stores the 
{@linkplain PublishEvent}
+     * data.
+     * @since 5.4.2
+     */
+    public static final String PUBLISH_COMPONENT_EVENTS_META = 
"meta.publish-component-events";
+    
+    /**
+     * Name of the JSONObject key name which holds the name of the event to be 
published.
+     * 
+     * @since 5.4.2
+     */
+    public static final String PUBLISH_COMPONENT_EVENTS_URL_PROPERTY = "url";
+
 }

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/19fe6853/tapestry-core/src/main/java/org/apache/tapestry5/internal/transform/OnEventWorker.java
----------------------------------------------------------------------
diff --git 
a/tapestry-core/src/main/java/org/apache/tapestry5/internal/transform/OnEventWorker.java
 
b/tapestry-core/src/main/java/org/apache/tapestry5/internal/transform/OnEventWorker.java
index fb4502b..fdb2dc9 100644
--- 
a/tapestry-core/src/main/java/org/apache/tapestry5/internal/transform/OnEventWorker.java
+++ 
b/tapestry-core/src/main/java/org/apache/tapestry5/internal/transform/OnEventWorker.java
@@ -12,15 +12,23 @@
 
 package org.apache.tapestry5.internal.transform;
 
+import java.lang.reflect.Array;
+import java.util.Arrays;
+import java.util.List;
+import java.util.Map;
+
 import org.apache.tapestry5.ComponentResources;
 import org.apache.tapestry5.EventContext;
 import org.apache.tapestry5.ValueEncoder;
 import org.apache.tapestry5.annotations.OnEvent;
+import org.apache.tapestry5.annotations.PublishEvent;
 import org.apache.tapestry5.annotations.RequestParameter;
+import org.apache.tapestry5.corelib.mixins.PublishServerSideEvents;
 import org.apache.tapestry5.func.F;
 import org.apache.tapestry5.func.Flow;
 import org.apache.tapestry5.func.Mapper;
 import org.apache.tapestry5.func.Predicate;
+import org.apache.tapestry5.internal.InternalConstants;
 import org.apache.tapestry5.internal.services.ComponentClassCache;
 import org.apache.tapestry5.ioc.OperationTracker;
 import org.apache.tapestry5.ioc.internal.util.CollectionFactory;
@@ -28,8 +36,19 @@ import org.apache.tapestry5.ioc.internal.util.InternalUtils;
 import org.apache.tapestry5.ioc.internal.util.TapestryException;
 import org.apache.tapestry5.ioc.util.ExceptionUtils;
 import org.apache.tapestry5.ioc.util.UnknownValueException;
+import org.apache.tapestry5.json.JSONArray;
 import org.apache.tapestry5.model.MutableComponentModel;
-import org.apache.tapestry5.plastic.*;
+import org.apache.tapestry5.plastic.Condition;
+import org.apache.tapestry5.plastic.InstructionBuilder;
+import org.apache.tapestry5.plastic.InstructionBuilderCallback;
+import org.apache.tapestry5.plastic.LocalVariable;
+import org.apache.tapestry5.plastic.LocalVariableCallback;
+import org.apache.tapestry5.plastic.MethodAdvice;
+import org.apache.tapestry5.plastic.MethodDescription;
+import org.apache.tapestry5.plastic.MethodInvocation;
+import org.apache.tapestry5.plastic.PlasticClass;
+import org.apache.tapestry5.plastic.PlasticField;
+import org.apache.tapestry5.plastic.PlasticMethod;
 import org.apache.tapestry5.runtime.ComponentEvent;
 import org.apache.tapestry5.runtime.Event;
 import org.apache.tapestry5.runtime.PageLifecycleListener;
@@ -39,11 +58,6 @@ import org.apache.tapestry5.services.ValueEncoderSource;
 import org.apache.tapestry5.services.transform.ComponentClassTransformWorker2;
 import org.apache.tapestry5.services.transform.TransformationSupport;
 
-import java.lang.reflect.Array;
-import java.util.Arrays;
-import java.util.List;
-import java.util.Map;
-
 /**
  * Provides implementations of the
  * {@link 
org.apache.tapestry5.runtime.Component#dispatchComponentEvent(org.apache.tapestry5.runtime.ComponentEvent)}
@@ -151,6 +165,8 @@ public class OnEventWorker implements 
ComponentClassTransformWorker2
         int minContextValues = 0;
 
         boolean handleActivationEventContext = false;
+        
+        final PublishEvent publishEvent;
 
         EventHandlerMethod(PlasticMethod method)
         {
@@ -165,6 +181,8 @@ public class OnEventWorker implements 
ComponentClassTransformWorker2
 
             eventType = extractEventType(methodName, onEvent);
             componentId = extractComponentId(methodName, onEvent);
+            
+            publishEvent = method.getAnnotation(PublishEvent.class);
         }
 
         void buildMatchAndInvocation(InstructionBuilder builder, final 
LocalVariable resultVariable)
@@ -343,9 +361,31 @@ public class OnEventWorker implements 
ComponentClassTransformWorker2
         implementDispatchMethod(plasticClass, isRoot, model, 
eventHandlerMethods);
 
         addComponentIdValidationLogicOnPageLoad(plasticClass, 
eventHandlerMethods);
+        
+        addPublishEventInfo(eventHandlerMethods, model);
+    }
+
+    private void addPublishEventInfo(Flow<EventHandlerMethod> 
eventHandlerMethods,
+            MutableComponentModel model)
+    {
+        JSONArray publishEvents = new JSONArray();
+        for (EventHandlerMethod eventHandlerMethod : eventHandlerMethods)
+        {
+            if (eventHandlerMethod.publishEvent != null)
+            {
+                publishEvents.put(eventHandlerMethod.eventType.toLowerCase());
+            }
+        }
+        
+        // If we do have events to publish, we apply the mixin and pass
+        // event information to it.
+        if (publishEvents.length() > 0) {
+            model.addMixinClassName(PublishServerSideEvents.class.getName(), 
"after:*");
+            model.setMeta(InternalConstants.PUBLISH_COMPONENT_EVENTS_META, 
publishEvents.toString());
+        }
     }
 
-    private void addComponentIdValidationLogicOnPageLoad(PlasticClass 
plasticClass, Flow<EventHandlerMethod> eventHandlerMethods)
+       private void addComponentIdValidationLogicOnPageLoad(PlasticClass 
plasticClass, Flow<EventHandlerMethod> eventHandlerMethods)
     {
         ComponentIdValidator[] validators = 
extractComponentIdValidators(eventHandlerMethods);
 

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/19fe6853/tapestry-core/src/main/preprocessed-coffeescript/org/apache/tapestry5/t5-core-dom.coffee
----------------------------------------------------------------------
diff --git 
a/tapestry-core/src/main/preprocessed-coffeescript/org/apache/tapestry5/t5-core-dom.coffee
 
b/tapestry-core/src/main/preprocessed-coffeescript/org/apache/tapestry5/t5-core-dom.coffee
index 9d419bc..9b975d4 100644
--- 
a/tapestry-core/src/main/preprocessed-coffeescript/org/apache/tapestry5/t5-core-dom.coffee
+++ 
b/tapestry-core/src/main/preprocessed-coffeescript/org/apache/tapestry5/t5-core-dom.coffee
@@ -906,6 +906,60 @@ define ["underscore", "./utils", "./events", "jquery"],
       events = utils.split events
 #endif
       onevent elements, events, match, handler
+      
+    # Returns the URL of a component event based on its name and an optional 
element
+    # or null if the event information is not found. When the element isn't 
passed
+    # or it's null, the event data is taken from the <body> element.
+    #
+    # * eventName - (string) name of the component event
+    # * element - (object) HTML DOM element to be used as the begining of the 
event data search. Optional.
+    getEventUrl = (eventName, element) ->
+
+      if not (eventName?)
+        throw 'dom.getEventUrl: the eventName parameter cannot be null'
+
+      if not _.isString eventName
+        throw 'dom.getEventUrl: the eventName parameter should be a string'
+        
+      eventName = eventName.toLowerCase()
+        
+      if element is null
+        element = document.getElementsByTagName('body')[0]
+
+      # Look for event data in itself first, then in the preceding siblings
+      # if not found
+      url = null
+  
+      while not url? and element.previousElementSibling?
+        data = getDataAttributeAsObject(element, 'component-events')
+        url = data?[eventName]?.url
+        element = element.previousElementSibling
+
+      if not url?
+    
+        # Look at parent elements recursively
+        while not url? and element.parentElement?
+          data = getDataAttributeAsObject(element, 'component-events')
+          url = data?[eventName]?.url
+          element = element.parentElement;
+      
+      return url;      
+           
+    # Returns the value of a given data attribute as an object.
+    # The "data-" prefix is added automatically.
+    # element - (object) HTML dom element
+    # attribute - (string) name of the data attribute without the "data-" 
prefix.
+    getDataAttributeAsObject = (element, attribute) ->
+       
+#if jquery
+      value = $(element).data(attribute)
+#elseif prototype
+      value = JSON.parse($(element).readAttribute('data-' + attribute))
+      if value isnt null
+        value = JSON.parse(value)
+      else 
+        value = {} 
+#endif
 
     # onDocument() is used to add an event handler to the document object; 
this is used
     # for global (or default) handlers.
@@ -919,5 +973,7 @@ define ["underscore", "./utils", "./events", "jquery"],
     body: wrapElement document.body
 
     scanner: scanner
+    
+    getEventUrl : getEventUrl
 
   return exports

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/19fe6853/tapestry-core/src/test/app1/PublishEventDemo.tml
----------------------------------------------------------------------
diff --git a/tapestry-core/src/test/app1/PublishEventDemo.tml 
b/tapestry-core/src/test/app1/PublishEventDemo.tml
new file mode 100644
index 0000000..43c2bd7
--- /dev/null
+++ b/tapestry-core/src/test/app1/PublishEventDemo.tml
@@ -0,0 +1,7 @@
+<t:border xmlns:t="http://tapestry.apache.org/schema/tapestry_5_0_0.xsd";
+          xmlns:p="tapestry:parameter">
+    <div id="page">
+           <t:PublishEventDemoComponent/>
+           <t:PublishEventDemoComponent2/>
+    </div>
+</t:border>
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/19fe6853/tapestry-core/src/test/java/org/apache/tapestry5/integration/app1/components/PublishEventDemoComponent.java
----------------------------------------------------------------------
diff --git 
a/tapestry-core/src/test/java/org/apache/tapestry5/integration/app1/components/PublishEventDemoComponent.java
 
b/tapestry-core/src/test/java/org/apache/tapestry5/integration/app1/components/PublishEventDemoComponent.java
new file mode 100644
index 0000000..b8054f9
--- /dev/null
+++ 
b/tapestry-core/src/test/java/org/apache/tapestry5/integration/app1/components/PublishEventDemoComponent.java
@@ -0,0 +1,32 @@
+// 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.tapestry5.integration.app1.components;
+
+import org.apache.tapestry5.annotations.OnEvent;
+import org.apache.tapestry5.annotations.PublishEvent;
+import org.apache.tapestry5.json.JSONObject;
+
+public class PublishEventDemoComponent
+{
+    @OnEvent("answer")
+    @PublishEvent
+    JSONObject answer() {
+        return new JSONObject("origin", "component");
+    }
+    
+    @PublishEvent
+    JSONObject onAction()
+    {
+        return new JSONObject("origin", "component");
+    }
+    
+}

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/19fe6853/tapestry-core/src/test/java/org/apache/tapestry5/integration/app1/components/PublishEventDemoComponent2.java
----------------------------------------------------------------------
diff --git 
a/tapestry-core/src/test/java/org/apache/tapestry5/integration/app1/components/PublishEventDemoComponent2.java
 
b/tapestry-core/src/test/java/org/apache/tapestry5/integration/app1/components/PublishEventDemoComponent2.java
new file mode 100644
index 0000000..7771557
--- /dev/null
+++ 
b/tapestry-core/src/test/java/org/apache/tapestry5/integration/app1/components/PublishEventDemoComponent2.java
@@ -0,0 +1,32 @@
+// 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.tapestry5.integration.app1.components;
+
+import org.apache.tapestry5.annotations.OnEvent;
+import org.apache.tapestry5.annotations.PublishEvent;
+import org.apache.tapestry5.json.JSONObject;
+
+public class PublishEventDemoComponent2
+{
+    @PublishEvent
+    JSONObject onAction()
+    {
+        return new JSONObject("origin", "component");
+    }
+    
+    @OnEvent("answer")
+    @PublishEvent
+    JSONObject answer() {
+        return new JSONObject("origin", "component");
+    }
+    
+}

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/19fe6853/tapestry-core/src/test/java/org/apache/tapestry5/integration/app1/pages/Index.java
----------------------------------------------------------------------
diff --git 
a/tapestry-core/src/test/java/org/apache/tapestry5/integration/app1/pages/Index.java
 
b/tapestry-core/src/test/java/org/apache/tapestry5/integration/app1/pages/Index.java
index d7d76d6..e78a874 100644
--- 
a/tapestry-core/src/test/java/org/apache/tapestry5/integration/app1/pages/Index.java
+++ 
b/tapestry-core/src/test/java/org/apache/tapestry5/integration/app1/pages/Index.java
@@ -57,32 +57,35 @@ public class Index
 
     private static final List<Item> ITEMS = CollectionFactory
             .newList(
-                    new Item("ZoneFormDemo", "Zone Form Decoration", "Fields 
inside an Ajax-updatd Form are still decorated properly."),
+                    
+                  new Item("PublishEventDemo", "@PublishEvent Demo", 
"Publishing server-side events to client-side code (JavaScript)"),
+
+//                    new Item("ZoneFormDemo", "Zone Form Decoration", "Fields 
inside an Ajax-updatd Form are still decorated properly."),
 
-                    new Item("AjaxValidationDemo", "Ajax Validation", 
"Demonstrated proper integration of server-side validation and client-side 
field decoration."),
+//                    new Item("AjaxValidationDemo", "Ajax Validation", 
"Demonstrated proper integration of server-side validation and client-side 
field decoration."),
 
                     new Item("OverrideEventHandlerDemo", "Event Handler 
Override Demo", "Event Handler methods overridden by sub-classes invoke 
base-class correctly."),
 
-                    new Item("LogoSubclass", "Base class Assets in 
sub-classes", "Assets are resolved for the parent class if that's where the 
annotations are."),
+//                    new Item("LogoSubclass", "Base class Assets in 
sub-classes", "Assets are resolved for the parent class if that's where the 
annotations are."),
 
                     new Item("MissingRequiredARP", "Missing Query Parameter 
for @ActivationRequestParameter", "Activating a page with a required 
@ActivationRequestParameter, but no matching query parameter, is an error."),
 
-                    new Item("DateFieldValidationDemo", "DateField Validation 
Demo",
-                            "Use of DateField component when client validation 
is disabled."),
+//                    new Item("DateFieldValidationDemo", "DateField 
Validation Demo",
+//                            "Use of DateField component when client 
validation is disabled."),
 
                     new Item("MixinParameters54", "Strict Mixin Parameters", 
"In the 5.4 DTD, Parameter Mixins must be qualified with the mixin id."),
 
-                    new Item("AsyncDemo", "Async Links and Forms Demo", "Async 
(XHR) Updates without a containing Zone."),
+//                    new Item("AsyncDemo", "Async Links and Forms Demo", 
"Async (XHR) Updates without a containing Zone."),
 
                     new Item("FormCancelActionDemo", "Form Cancel Action 
Demo", "FormSupport.addCancel() support"),
 
                     new Item("AjaxRadioDemo", "Ajax Radio Demo", "Radio 
components inside an Ajax form"),
 
-                    new Item("TimeIntervalDemo", "TimeInterval Demo", 
"Interval component, based on Moment.js"),
+//                    new Item("TimeIntervalDemo", "TimeInterval Demo", 
"Interval component, based on Moment.js"),
 
-                    new Item("LocalDateDemo", "LocalDate Demo", "LocalDate 
component, based on Moment.js"),
+//                    new Item("LocalDateDemo", "LocalDate Demo", "LocalDate 
component, based on Moment.js"),
 
-                    new Item("EmptyIfDemo", "Empty If Demo", "Ensure an empty 
If can still render."),
+//                    new Item("EmptyIfDemo", "Empty If Demo", "Ensure an 
empty If can still render."),
 
                     new Item("MissingAssetDemo", "Missing Asset Demo", "Error 
when injecting an asset that does not exist."),
 

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/19fe6853/tapestry-core/src/test/java/org/apache/tapestry5/integration/app1/pages/PublishEventDemo.java
----------------------------------------------------------------------
diff --git 
a/tapestry-core/src/test/java/org/apache/tapestry5/integration/app1/pages/PublishEventDemo.java
 
b/tapestry-core/src/test/java/org/apache/tapestry5/integration/app1/pages/PublishEventDemo.java
new file mode 100644
index 0000000..1876de5
--- /dev/null
+++ 
b/tapestry-core/src/test/java/org/apache/tapestry5/integration/app1/pages/PublishEventDemo.java
@@ -0,0 +1,49 @@
+// Copyright 2016 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.
+
+// 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.tapestry5.integration.app1.pages;
+
+import org.apache.tapestry5.annotations.Import;
+import org.apache.tapestry5.annotations.OnEvent;
+import org.apache.tapestry5.annotations.PublishEvent;
+import org.apache.tapestry5.json.JSONObject;
+
+@Import(stack = "core", library = "PublishEventDemo.js")
+public class PublishEventDemo
+{
+
+    @PublishEvent
+    JSONObject onAction()
+    {
+        return new JSONObject("origin", "page");
+    }
+    
+    @OnEvent("answer")
+    @PublishEvent
+    JSONObject answer() {
+        return new JSONObject("origin", "page");
+    }
+    
+}

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/19fe6853/tapestry-core/src/test/resources/META-INF/assets/PublishEventDemo.js
----------------------------------------------------------------------
diff --git 
a/tapestry-core/src/test/resources/META-INF/assets/PublishEventDemo.js 
b/tapestry-core/src/test/resources/META-INF/assets/PublishEventDemo.js
new file mode 100644
index 0000000..20c0406
--- /dev/null
+++ b/tapestry-core/src/test/resources/META-INF/assets/PublishEventDemo.js
@@ -0,0 +1,11 @@
+require(["t5/core/dom", "t5/core/ajax", "jquery"], function (dom, ajax, $) {
+
+    $(document).ready(function() {
+        console.log('dom.getEventURL()   : ' + dom.getEventUrl('answer', 
document.getElementById("page")));
+        console.log('dom.getEventURL() 1 : ' + dom.getEventUrl('answer', 
document.getElementById("componentParagraph")));
+        console.log('dom.getEventURL() 2 : ' + dom.getEventUrl('answer', 
document.getElementById("componentParagraph2")));
+        console.log('dom.getEventURL() 3 : ' + dom.getEventUrl('answer', 
document.getElementById("componentParagraph3")));
+    });
+    
+});
+

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/19fe6853/tapestry-core/src/test/resources/org/apache/tapestry5/integration/app1/components/PublishEventDemoComponent.tml
----------------------------------------------------------------------
diff --git 
a/tapestry-core/src/test/resources/org/apache/tapestry5/integration/app1/components/PublishEventDemoComponent.tml
 
b/tapestry-core/src/test/resources/org/apache/tapestry5/integration/app1/components/PublishEventDemoComponent.tml
new file mode 100644
index 0000000..2d2b5f1
--- /dev/null
+++ 
b/tapestry-core/src/test/resources/org/apache/tapestry5/integration/app1/components/PublishEventDemoComponent.tml
@@ -0,0 +1,3 @@
+<div id="component" 
xmlns:t="http://tapestry.apache.org/schema/tapestry_5_0_0.xsd";>
+       <p id="componentParagraph">I'm a component</p>
+</div>

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/19fe6853/tapestry-core/src/test/resources/org/apache/tapestry5/integration/app1/components/PublishEventDemoComponent2.tml
----------------------------------------------------------------------
diff --git 
a/tapestry-core/src/test/resources/org/apache/tapestry5/integration/app1/components/PublishEventDemoComponent2.tml
 
b/tapestry-core/src/test/resources/org/apache/tapestry5/integration/app1/components/PublishEventDemoComponent2.tml
new file mode 100644
index 0000000..b10d020
--- /dev/null
+++ 
b/tapestry-core/src/test/resources/org/apache/tapestry5/integration/app1/components/PublishEventDemoComponent2.tml
@@ -0,0 +1,4 @@
+<t:container xmlns:t="http://tapestry.apache.org/schema/tapestry_5_0_0.xsd";>
+       <p id="componentParagraph2">I'm another component</p>
+       <p id="componentParagraph3">I'm another component</p>
+</t:container>

Reply via email to