Index: apps/showcase/src/main/webapp/ajax/remotediv/example1.jsp =================================================================== --- apps/showcase/src/main/webapp/ajax/remotediv/example1.jsp (revision 465340) +++ apps/showcase/src/main/webapp/ajax/remotediv/example1.jsp (working copy) @@ -7,15 +7,14 @@ + + href="/AjaxTest.action"> Initial Content Index: apps/showcase/src/main/webapp/ajax/remotediv/example10.jsp =================================================================== --- apps/showcase/src/main/webapp/ajax/remotediv/example10.jsp (revision 0) +++ apps/showcase/src/main/webapp/ajax/remotediv/example10.jsp (revision 0) @@ -0,0 +1,30 @@ +<%@ page contentType="text/html;charset=UTF-8" language="java" %> +<%@ taglib prefix="s" uri="/struts-tags" %> + + + + Ajax Examples + + + + + + + + + Initial Content + + + + + Index: apps/showcase/src/main/webapp/ajax/remotediv/example2.jsp =================================================================== --- apps/showcase/src/main/webapp/ajax/remotediv/example2.jsp (revision 465340) +++ apps/showcase/src/main/webapp/ajax/remotediv/example2.jsp (working copy) @@ -7,17 +7,18 @@ + - Initial Content - + + Initial Content + Index: apps/showcase/src/main/webapp/ajax/remotediv/example3.jsp =================================================================== --- apps/showcase/src/main/webapp/ajax/remotediv/example3.jsp (revision 465340) +++ apps/showcase/src/main/webapp/ajax/remotediv/example3.jsp (working copy) @@ -15,7 +15,7 @@ href="/AjaxTest.action" theme="ajax" delay="2000" - updateFreq="%{#parameters.period}" + updateInterval="%{#parameters.period}" errorText="There was an error">Initial Content Index: apps/showcase/src/main/webapp/ajax/remotediv/example4.jsp =================================================================== --- apps/showcase/src/main/webapp/ajax/remotediv/example4.jsp (revision 465340) +++ apps/showcase/src/main/webapp/ajax/remotediv/example4.jsp (working copy) @@ -15,7 +15,7 @@ href="/AjaxTest.action" theme="ajax" delay="1000" - updateFreq="5000" + updateInterval="5000" errorText="There was an error" loadingText="reloading">loading now Index: apps/showcase/src/main/webapp/ajax/remotediv/example7.jsp =================================================================== --- apps/showcase/src/main/webapp/ajax/remotediv/example7.jsp (revision 465340) +++ apps/showcase/src/main/webapp/ajax/remotediv/example7.jsp (working copy) @@ -15,7 +15,7 @@ href="/Test3.action" theme="ajax" delay="1000" - showErrorTransportText="true" + executeScripts="true" loadingText="reloading">loading now Index: apps/showcase/src/main/webapp/ajax/remotediv/example8.jsp =================================================================== --- apps/showcase/src/main/webapp/ajax/remotediv/example8.jsp (revision 465340) +++ apps/showcase/src/main/webapp/ajax/remotediv/example8.jsp (working copy) @@ -1,4 +1,3 @@ - <%@ page contentType="text/html;charset=UTF-8" language="java" %> <%@ taglib prefix="s" uri="/struts-tags" %> @@ -10,18 +9,38 @@ + + + + + + - Initial Content ... should not change + loadingText="Loading..." + refreshListenTopic="/refresh" + startTimerListenTopic="/startTimer" + stopTimerListenTopic="/stopTimer" + updateInterval="3000" + > + Initial Content - - Index: apps/showcase/src/main/webapp/ajax/remotediv/example9.jsp =================================================================== --- apps/showcase/src/main/webapp/ajax/remotediv/example9.jsp (revision 0) +++ apps/showcase/src/main/webapp/ajax/remotediv/example9.jsp (revision 0) @@ -0,0 +1,47 @@ +<%@ page contentType="text/html;charset=UTF-8" language="java" %> +<%@ taglib prefix="s" uri="/struts-tags" %> + + + + Ajax Examples + + + + + + + + + + + + + Initial Content + + + + + Index: apps/showcase/src/main/webapp/ajax/remotediv/index.jsp =================================================================== --- apps/showcase/src/main/webapp/ajax/remotediv/index.jsp (revision 465340) +++ apps/showcase/src/main/webapp/ajax/remotediv/index.jsp (working copy) @@ -14,6 +14,10 @@
  • A simple DIV that refreshes only once
  • + +
  • + A simple DIV that uses a custom handler +
  • A simple DIV that updates every 2 seconds @@ -25,25 +29,25 @@
  • - A simple DIV that updates every 5 seconds with loading text and reloading text + A simple DIV that updates every 5 seconds with loading text and reloading text and delay
  • - A simple DIV's that cannot contact the server + A simple DIV's that cannot contact the serverm, with fixed error message
  • -
  • - A simple DIV's that cannot contact the server and displays the transport error - message -
  • A div that calls the server, and JS in the resulting page is executed
  • - A div that will not update itself (updateFreq=0 and delay=0) + A div that will listen to events to refresh and start/stop autoupdate
  • + +
  • + A div that will listen to events to refresh and start/stop autoupdate and will call beforeLoading and afterLoading functions +
  • Index: apps/showcase/src/main/webapp/ajax/remotelink/index.jsp =================================================================== --- apps/showcase/src/main/webapp/ajax/remotelink/index.jsp (revision 465340) +++ apps/showcase/src/main/webapp/ajax/remotelink/index.jsp (working copy) @@ -5,107 +5,70 @@ Ajax Examples + + + -One Component: -Initial Content +
    Div 1
    -

    +
    -Two Component: -Initial Content +
    Div 2
    +

    -Three Component: -Initial Content -

    + href="/AjaxTest.action" + targets="t1,t2">Update 'Div 1' and 'Div 2' -Fourth Component: -Initial Content

    - - - - -Remote link 1 updating "One Component" and "Two Component"
    - -Update + href="/AjaxNoUrl.jsp" + errorText="Error Loading" + targets="t1">Try to update 'Div 1', use custom error message +

    -Remote link 2 updating "Two Component" and "Three Component"
    -Update -

    - -Remote DIV that is not connected to any remote links: -Initial Content + loadingText="Loading!!!" + beforeLoading="before()" + afterLoading="after()" + targets="t1">Update 'Div 1', use custom loading message, execute javascript functions before and after the request is made +

    -A Remote link that doesn't trigger any remote DIV updates
    - -Update - + href="/Test3.action" + executeScripts="true" + targets="t2">Update 'Div 2' and execute returned javascript +

    -A Remote link that will update "Fourth Component" -Update -

    + href="/AjaxTest.action" + handler="handler" + targets="t2">Update 'Div 2' using a custom handler + +

    + Index: apps/showcase/src/main/webapp/ajax/tabbedpanel/example1.jsp =================================================================== --- apps/showcase/src/main/webapp/ajax/tabbedpanel/example1.jsp (revision 465340) +++ apps/showcase/src/main/webapp/ajax/tabbedpanel/example1.jsp (working copy) @@ -28,79 +28,79 @@ - + This is the first pane

    -
    - + + This is the second panel - - + + This is the three - +
    - + This is the left pane

    -
    - - + + + middle tab

    -
    - + +
    - + - - - + + + - + Outer one
    - Inner 1 - Inner 2 - Inner 3 + Inner 1 + Inner 2 + Inner 3 -
    - + + Outer two
    - Inner 21 - Inner 22 - Inner 23 + Inner 21 + Inner 22 + Inner 23 -
    - + + Outer three
    - Inner 31 - Inner 32 - Inner 33 + Inner 31 + Inner 32 + Inner 33 -
    +
    Index: apps/showcase/src/main/webapp/ajax/tabbedpanel/example2.jsp =================================================================== --- apps/showcase/src/main/webapp/ajax/tabbedpanel/example2.jsp (revision 465340) +++ apps/showcase/src/main/webapp/ajax/tabbedpanel/example2.jsp (working copy) @@ -7,44 +7,23 @@ "> - "> - " media="print"> - - + + - - - - -
    - - - This is the first pane
    - -
    - -
    -
    - - This is the second panel - - - This is the three - -
    -
    + + + I'm a Tab!!! + + + I'm the other Tab!!! + + + + + Index: apps/showcase/src/main/webapp/ajax/tabbedpanel/example3.jsp =================================================================== --- apps/showcase/src/main/webapp/ajax/tabbedpanel/example3.jsp (revision 465340) +++ apps/showcase/src/main/webapp/ajax/tabbedpanel/example3.jsp (working copy) @@ -28,23 +28,23 @@ - - + + This is the left pane

    -
    - - + + + middle tab

    -
    - + +
    Index: apps/showcase/src/main/webapp/ajax/tabbedpanel/example4.jsp =================================================================== --- apps/showcase/src/main/webapp/ajax/tabbedpanel/example4.jsp (revision 0) +++ apps/showcase/src/main/webapp/ajax/tabbedpanel/example4.jsp (revision 0) @@ -0,0 +1,31 @@ +<%@ page contentType="text/html;charset=UTF-8" language="java" %> +<%@ taglib prefix="s" uri="/struts-tags" %> + + + + Ajax examples - tabbled panel + + + "> + + + + + + + + + I'm a Tab!!! + + + I'm the other Tab!!! + + + + + + + + + + Index: apps/showcase/src/main/webapp/ajax/tabbedpanel/example5.jsp =================================================================== --- apps/showcase/src/main/webapp/ajax/tabbedpanel/example5.jsp (revision 465340) +++ apps/showcase/src/main/webapp/ajax/tabbedpanel/example5.jsp (working copy) @@ -1,27 +1,31 @@ -<%@ page language="java" contentType="text/html; charset=UTF-8" - pageEncoding="UTF-8"%> -<%@taglib prefix="s" uri="/struts-tags" %> - +<%@ page contentType="text/html;charset=UTF-8" language="java" %> +<%@ taglib prefix="s" uri="/struts-tags" %> + - -Insert title here + Ajax examples - tabbled panel - - + + "> + + + - - - - - - - - - - + + + I'm a Tab!!! + + + I'm the other Tab!!! + + + + + + + + - Index: apps/showcase/src/main/webapp/ajax/tabbedpanel/index.jsp =================================================================== --- apps/showcase/src/main/webapp/ajax/tabbedpanel/index.jsp (revision 465340) +++ apps/showcase/src/main/webapp/ajax/tabbedpanel/index.jsp (working copy) @@ -11,17 +11,11 @@

      -
    1. A local tabbed panel
    2. -
    3. A remote and local tabbed panel
    4. -
    5. Various remote and local tabbed panels (with enclosed tabbed pannels)
    6. -
    7. - - Only remove tabbed panel -
    8. -
    9. - - Remote form validation inside tabbed panel -
    10. +
    11. A local tabbed panel width fixed size (doLayout="true")
    12. +
    13. A remote(href != "") and local tabbed panel
    14. +
    15. Various remote and local tabbed panels (with enclosed tabbed pannels) with layout (doLayout="false")
    16. +
    17. A local tabbed panel width fixed size (doLayout="true") with close button on tabs(closeButton="tab"), and tabs on the right (labelposition="righ")
    18. +
    19. A local tabbed panel width fixed size (doLayout="true") with close button on the tab pane(closeButton="pane"), and tabs on the bottom (labelposition="bottom")
    Index: core/src/main/java/org/apache/struts2/components/Anchor.java =================================================================== --- core/src/main/java/org/apache/struts2/components/Anchor.java (revision 466128) +++ core/src/main/java/org/apache/struts2/components/Anchor.java (working copy) @@ -26,8 +26,9 @@ * * * A tag that creates a HTML <a href='' /> that when clicked calls a URL remote XMLHttpRequest call via the dojo - * framework. The result from the URL is executed as JavaScript. If a "listenTopics" is supplied, it will publish a - * 'click' message to that topic when the result is returned. + * framework. The 'targets' attribute can hold a comma-delimited list of ids of the elements whose + * content will be replaced with the response of the request.The result from the URL is executed as JavaScript is executeScripts is set to 'true'. If a + * 'refreshListenTopic' is supplied, it will listen to that event and update its targets contents. * * * @@ -35,7 +36,7 @@ * *
      * 
    - * <s:a id="link1" theme="ajax" href="/DoIt.action" errorText="An error ocurred" showErrorTransportText="true">
    + * <s:a id="link1" theme="ajax" href="/DoIt.action" errorText="An error ocurred" loadingText="Loading...">
      *     <img border="none" src="<%=request.getContextPath()%>/images/delete.gif"/>
      *     <s:param name="id" value="1"/>
      * </s:a>
    @@ -54,8 +55,7 @@
      *
      * 
      * 
    - * <a dojoType="BindAnchor" evalResult="true" id="link1" href="/DoIt.action?id=1" errorHtml="An error ocurred"
    - * showTransportError="true"></a>
    + * <a dojoType="BindAnchor" executeScripts="true" id="link1" href="/DoIt.action?id=1" errorText="An error ocurred"></a>
      * 
      * 
    * @@ -63,7 +63,7 @@ * * * - * Here is an example that uses the postInvokeJS. This example is in altSyntax=true: + * Here is an example that uses the beforeLoading. This example is in altSyntax=true: * * * @@ -71,23 +71,22 @@ * *
      * 
    - * <s:a id="test" theme="ajax" href="/simpeResult.action" preInvokeJS="confirm(\'You sure\')">
    + * <s:a id="test" theme="ajax" href="/simpeResult.action" beforeLoading="confirm(\'You sure\')">
      * 	A
      * </s:a>
      * 
      * 
    * * @s.tag name="a" tld-body-content="JSP" tld-tag-class="org.apache.struts2.views.jsp.ui.AnchorTag" - * description="Render a HTML href element that when clicked calls a URL via remote XMLHttpRequest" - * + * description="Render a HTML href element that when clicked calls a URL via remote XMLHttpRequest and updates its targets" + * */ public class Anchor extends RemoteCallUIBean { final public static String OPEN_TEMPLATE = "a"; final public static String TEMPLATE = "a-close"; final public static String COMPONENT_NAME = Anchor.class.getName(); - protected String notifyTopics; - protected String preInvokeJS; + protected String targets; public Anchor(ValueStack stack, HttpServletRequest request, HttpServletResponse response) { super(stack, request, response); @@ -104,13 +103,8 @@ public void evaluateExtraParams() { super.evaluateExtraParams(); - if (notifyTopics != null) { - addParameter("notifyTopics", findString(notifyTopics)); - } - - if (preInvokeJS != null) { - addParameter("preInvokeJS", findString(preInvokeJS)); - } + if(targets != null) + addParameter("targets", findString(targets)); } /** @@ -122,18 +116,11 @@ } /** - * Topic names to post an event to after the remote call has been made - * @s.tagattribute required="false" - */ - public void setNotifyTopics(String notifyTopics) { - this.notifyTopics = notifyTopics; - } - - /** - * A javascript snippet that will be invoked prior to the execution of the target href. If provided must return true or false. True indicates to continue executing target, false says do not execute link target. Possible uses are for confirm dialogs. + * Comma delimited list of ids of the elements whose content will be updated * @s.tagattribute required="false" type="String" */ - public void setPreInvokeJS(String preInvokeJS) { - this.preInvokeJS = preInvokeJS; + public void setTargets(String targets) { + this.targets = targets; } + } Index: core/src/main/java/org/apache/struts2/components/Div.java =================================================================== --- core/src/main/java/org/apache/struts2/components/Div.java (revision 466128) +++ core/src/main/java/org/apache/struts2/components/Div.java (working copy) @@ -20,50 +20,44 @@ import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; -import org.apache.struts2.views.util.UrlHelper; - import com.opensymphony.xwork2.util.ValueStack; /** - * - * The div tag is primarily an AJAX tag, providing a remote call from the current page to update a section - * of content without having to refresh the entire page.

    + * The div tag is primarily an AJAX tag, providing a remote call + * from the current page to update a section of content without having to refresh the entire page.

    * - * It creates a HTML <DIV /> that obtains it's content via a remote XMLHttpRequest call - * via the dojo framework.

    + * It creates a HTML <DIV /> that obtains it's content via a remote XMLHttpRequest call via + * the dojo framework.

    * - * If a "listenTopics" is supplied, it will listen to that topic and refresh it's content when any message - * is received.

    - * + * If a "refreshListenTopic" is supplied, it will listen to that topic and refresh it's content when any + * message is received.

    * - * Important: Be sure to setup the page containing this tag to be Configured for AJAX

    + * Important: Be sure to setup the page containing this tag to be Configured for AJAX + *

    * *

    Examples * *

    - * 
    - * <s:div ... />
    - * 
    + *       <!-- START SNIPPET: example -->
    + *       <s:div ... />
    + *       <!-- END SNIPPET: example -->
      * 
    * * @s.tag name="div" tld-body-content="JSP" tld-tag-class="org.apache.struts2.views.jsp.ui.DivTag" - * description="Render HTML div providing content from remote call via AJAX" - */ + * description="Render HTML div providing content from remote call via AJAX" + */ public class Div extends RemoteCallUIBean { - - private static final Log _log = LogFactory.getLog(Div.class); - public static final String TEMPLATE = "div"; public static final String TEMPLATE_CLOSE = "div-close"; public static final String COMPONENT_NAME = Div.class.getName(); - protected String updateFreq; + protected String updateInterval; + protected String autoStart; protected String delay; - protected String loadingText; - protected String listenTopics; + protected String startTimerListenTopic; + protected String stopTimerListenTopic; + protected String refreshOnShow; public Div(ValueStack stack, HttpServletRequest request, HttpServletResponse response) { super(stack, request, response); @@ -80,60 +74,32 @@ public void evaluateExtraParams() { super.evaluateExtraParams(); - if (null != updateFreq && !"".equals(updateFreq)) { - addParameter("updateFreq", findString(updateFreq)); - } else { - addParameter("updateFreq", "0"); - } - - if (null != delay && !"".equals(delay)) { - addParameter("delay", findString(delay)); - } else { - addParameter("delay", "0"); - } - - String tmpUpdateFreq = (String) getParameters().get("delay"); - String tmpDelay = (String) getParameters().get("updateFreq"); - try { - int _updateFreq = Integer.parseInt(tmpUpdateFreq); - int _delay = Integer.parseInt(tmpDelay); - - if (_updateFreq <= 0 && _delay <= 0) { - addParameter("autoStart", "false"); - } - } - catch(NumberFormatException e) { - // too bad, invalid updateFreq or delay provided, we - // can't determine autoStart mode. - _log.info("error while parsing updateFreq ["+tmpUpdateFreq+"] or delay ["+tmpDelay+"] to integer, cannot determine autoStart mode", e); - } - - if (loadingText != null) { - addParameter("loadingText", findString(loadingText)); - } - - if (listenTopics != null) { - addParameter("listenTopics", findString(listenTopics)); - } - - if (href != null) { - - // This is needed for portal and DOJO ajax stuff! - addParameter("href", null); - addParameter("href", UrlHelper.buildUrl(findString(href), request, response, null)); - } + if (updateInterval != null) + addParameter("updateInterval", findValue(updateInterval, Integer.class)); + if (autoStart != null) + addParameter("autoStart", findValue(autoStart, Boolean.class)); + if (refreshOnShow != null) + addParameter("refreshOnShow", findValue(refreshOnShow, Boolean.class)); + if (delay != null) + addParameter("delay", findValue(delay, Integer.class)); + if (startTimerListenTopic != null) + addParameter("startTimerListenTopic", findValue(startTimerListenTopic, String.class)); + if (stopTimerListenTopic != null) + addParameter("stopTimerListenTopic", findValue(stopTimerListenTopic, String.class)); } /** - * How often to re-fetch the content (in milliseconds) - * @s.tagattribute required="false" type="Integer" default="0" + * Start timer automatically + * + * @s.tagattribute required="false" type="Boolean" default="true" */ - public void setUpdateFreq(String updateFreq) { - this.updateFreq = updateFreq; + public void setAutoStart(String autoStart) { + this.autoStart = autoStart; } /** * How long to wait before fetching the content (in milliseconds) + * * @s.tagattribute required="false" type="Integer" default="0" */ public void setDelay(String delay) { @@ -141,19 +107,38 @@ } /** - * The text to display to the user while the new content is being fetched (especially good if the content will take awhile) - * @s.tagattribute required="false" rtexprvalue="true" + * How often to re-fetch the content (in milliseconds) + * + * @s.tagattribute required="false" type="Integer" default="0" */ - public void setLoadingText(String loadingText) { - this.loadingText = loadingText; + public void setUpdateInterval(String updateInterval) { + this.updateInterval = updateInterval; } /** - * Topic name to listen to (comma delimited), that will cause the DIV's content to be re-fetched - * @s.tagattribute required="false" + * Topic that will start the timer (for autoupdate) + * + * @s.tagattribute required="false" type="String" */ - public void setListenTopics(String listenTopics) { - this.listenTopics = listenTopics; + public void setStartTimerListenTopic(String startTimerListenTopic) { + this.startTimerListenTopic = startTimerListenTopic; } + /** + * Topic that will stop the timer (for autoupdate) + * + * @s.tagattribute required="false" type="String" + */ + public void setStopTimerListenTopic(String stopTimerListenTopic) { + this.stopTimerListenTopic = stopTimerListenTopic; + } + + /** + * Content will be loaded when div becomes visible + * + * @s.tagattribute required="false" type="String" default="false" + */ + public void setRefreshOnShow(String refreshOnShow) { + this.refreshOnShow = refreshOnShow; + } } Index: core/src/main/java/org/apache/struts2/components/RemoteCallUIBean.java =================================================================== --- core/src/main/java/org/apache/struts2/components/RemoteCallUIBean.java (revision 466128) +++ core/src/main/java/org/apache/struts2/components/RemoteCallUIBean.java (working copy) @@ -20,6 +20,8 @@ import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; +import org.apache.struts2.views.util.UrlHelper; + import com.opensymphony.xwork2.util.ValueStack; /** @@ -30,8 +32,12 @@ protected String href; protected String errorText; - protected String showErrorTransportText; protected String afterLoading; + protected String beforeLoading; + protected String executeScripts; + protected String loadingText; + protected String refreshListenTopic; + protected String handler; public RemoteCallUIBean(ValueStack stack, HttpServletRequest request, HttpServletResponse response) { super(stack, request, response); @@ -40,24 +46,34 @@ public void evaluateExtraParams() { super.evaluateExtraParams(); - if (href != null) { - addParameter("href", findString(href)); - } - - if (showErrorTransportText != null) { - addParameter("showErrorTransportText", findValue(showErrorTransportText, Boolean.class)); - } - - if (errorText != null) { + if (href != null) + addParameter("href", UrlHelper.buildUrl(findString(href), request, response, null)); + if (errorText != null) addParameter("errorText", findString(errorText)); - } - - if (afterLoading != null) { + if (loadingText != null) + addParameter("loadingText", findString(loadingText)); + if (afterLoading != null) addParameter("afterLoading", findString(afterLoading)); - } + if (beforeLoading != null) + addParameter("beforeLoading", findString(beforeLoading)); + if (executeScripts != null) + addParameter("executeScripts", findValue(executeScripts, Boolean.class)); + if (refreshListenTopic != null) + addParameter("refreshListenTopic", findValue(refreshListenTopic, String.class)); + if (handler != null) + addParameter("handler", findString(handler)); } /** + * Topic that will trigger a re-fetch + * + * @s.tagattribute required="false" type="String" + */ + public void setRefreshListenTopic(String refreshListenTopic) { + this.refreshListenTopic = refreshListenTopic; + } + + /** * The theme to use for the element. This tag will usually use the ajax theme. * @s.tagattribute required="false" type="String" */ @@ -82,18 +98,44 @@ } /** - * when to show the error message as content when the URL had problems + * Javascript code name that will be executed after the content has been fetched + * @s.tagattribute required="false" type="String" + */ + public void setAfterLoading(String afterLoading) { + this.afterLoading = afterLoading; + } + + /** + * Javascript code that will be executed before the content has been fetched + * @s.tagattribute required="false" type="String" + */ + public void setBeforeLoading(String beforeLoading) { + this.beforeLoading = beforeLoading; + } + + /** + * Javascript code in the fetched content will be executed * @s.tagattribute required="false" type="Boolean" default="false" */ - public void setShowErrorTransportText(String showErrorTransportText) { - this.showErrorTransportText = showErrorTransportText; + public void setExecuteScripts(String executeScripts) { + this.executeScripts = executeScripts; } /** - * Javascript code that will be executed after the content has been fetched + * Text to be shown while content is being fetched + * + * @s.tagattribute required="false" type="String" default="Loading..." + */ + public void setLoadingText(String loadingText) { + this.loadingText = loadingText; + } + + /** + * Javascript function name that will make the request + * * @s.tagattribute required="false" type="String" */ - public void setAfterLoading(String afterLoading) { - this.afterLoading = afterLoading; + public void setHandler(String handler) { + this.handler = handler; } } Index: core/src/main/java/org/apache/struts2/components/TabbedPanel.java =================================================================== --- core/src/main/java/org/apache/struts2/components/TabbedPanel.java (revision 466128) +++ core/src/main/java/org/apache/struts2/components/TabbedPanel.java (working copy) @@ -17,8 +17,7 @@ */ package org.apache.struts2.components; -import java.util.ArrayList; -import java.util.List; +import java.awt.Panel; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; @@ -97,40 +96,32 @@ public static final String TEMPLATE_CLOSE = "tabbedpanel-close"; final private static String COMPONENT_NAME = TabbedPanel.class.getName(); - protected List tabs = new ArrayList(); + protected String selectedTab; + protected String closeButton; + protected String doLayout ; public TabbedPanel(ValueStack stack, HttpServletRequest request, HttpServletResponse response) { super(stack, request, response); } - /** - * Add a new panel to be rendered. - * - * @param pane a new panel to be rendered - */ - public void addTab(Panel pane) { - tabs.add(pane); - } - /** - * Get the list of panel tabs for this tab panel. - * - * @return the list of panel tabs for this tab panel - */ - public List getTabs() { - return tabs; - } - - public String getTopicName() { - return "topic_tab_" + id + "_selected"; - } - protected void evaluateExtraParams() { super.evaluateExtraParams(); - addParameter("topicName", "topic_tab_" + id + "_selected"); - addParameter("tabs", tabs); - + if(selectedTab != null) + addParameter("selectedTab", findString(selectedTab)); + if(closeButton != null) + addParameter("closeButton", findString(closeButton)); + addParameter("doLayout", doLayout != null ? findValue(doLayout, Boolean.class) : Boolean.FALSE); + if(labelPosition != null) { + //dojo has some weird name for label positions + if(labelPosition.equalsIgnoreCase("left")) + labelPosition = "left-h"; + if(labelPosition.equalsIgnoreCase("right")) + labelPosition = "right-h"; + addParameter("labelPosition", null); + addParameter("labelPosition", labelPosition); + } } public String getDefaultOpenTemplate() { @@ -153,4 +144,29 @@ // This is required to override tld generation attributes to required=true super.setId(id); } + + + /** + * The id of the tab that will be selected by default + * @s.tagattribute required="false" type="String" + */ + public void setSelectedTab(String selectedTab) { + this.selectedTab = selectedTab; + } + + /** + * Where the close button will be placed, possible values are "tab" and "pane" + * @s.tagattribute required="false" type="String" + */ + public void setCloseButton(String closeButton) { + this.closeButton = closeButton; + } + + /** + * If doLayout is false, the tab container's height equals the height of the currently selected tab + * @s.tagattribute required="false" default="false" type="Boolean" + */ + public void setDoLayout(String doLayout) { + this.doLayout = doLayout; + } } Index: core/src/main/java/org/apache/struts2/views/freemarker/tags/StrutsModels.java =================================================================== --- core/src/main/java/org/apache/struts2/views/freemarker/tags/StrutsModels.java (revision 466128) +++ core/src/main/java/org/apache/struts2/views/freemarker/tags/StrutsModels.java (working copy) @@ -49,7 +49,6 @@ protected I18nModel i18n; protected IncludeModel include; protected LabelModel label; - protected PanelModel panel; protected PasswordModel password; protected PushModel push; protected ParamModel param; @@ -78,8 +77,8 @@ protected ElseModel elseModel; protected ElseIfModel elseIfModel; protected TimePickerModel timePickerModel; - + public StrutsModels(ValueStack stack, HttpServletRequest req, HttpServletResponse res) { this.stack = stack; this.req = req; @@ -325,14 +324,6 @@ return tabbedPanel; } - public PanelModel getPanel() { - if (panel == null) { - panel = new PanelModel(stack, req, res); - } - - return panel; - } - public BeanModel getBean() { if (bean == null) { bean = new BeanModel(stack, req, res); @@ -404,7 +395,7 @@ return fielderror; } - + public OptionTransferSelectModel getOptiontransferselect() { if (optiontransferselect == null) { optiontransferselect = new OptionTransferSelectModel(stack, req, res); @@ -418,42 +409,42 @@ } return treeModel; } - + public UpDownSelectModel getUpdownselect() { if (updownselect == null) { updownselect = new UpDownSelectModel(stack, req, res); } return updownselect; } - + public OptGroupModel getOptgroup() { if (optGroupModel == null) { optGroupModel = new OptGroupModel(stack, req, res); } return optGroupModel; } - + public IfModel getIf() { if (ifModel == null) { ifModel = new IfModel(stack, req, res); } return ifModel; } - + public ElseModel getElse() { if (elseModel == null) { elseModel = new ElseModel(stack, req, res); } return elseModel; } - + public ElseIfModel getElseif() { if (elseIfModel == null) { elseIfModel = new ElseIfModel(stack, req, res); } return elseIfModel; } - + public TimePickerModel getTimepicker() { if (timePickerModel == null) { timePickerModel = new TimePickerModel(stack, req, res); Index: core/src/main/java/org/apache/struts2/views/jsp/ui/AnchorTag.java =================================================================== --- core/src/main/java/org/apache/struts2/views/jsp/ui/AnchorTag.java (revision 466128) +++ core/src/main/java/org/apache/struts2/views/jsp/ui/AnchorTag.java (working copy) @@ -28,17 +28,12 @@ /** * @see Anchor */ -public class AnchorTag extends AbstractClosingTag { - +public class AnchorTag extends AbstractRemoteCallUITag { + private static final long serialVersionUID = -1034616578492431113L; - - protected String href; - protected String errorText; - protected String showErrorTransportText; - protected String notifyTopics; - protected String afterLoading; - protected String preInvokeJS; + protected String targets; + public Component getBean(ValueStack stack, HttpServletRequest req, HttpServletResponse res) { return new Anchor(stack, req, res); } @@ -47,37 +42,12 @@ super.populateParams(); Anchor link = (Anchor) component; - - link.setHref(href); - link.setErrorText(errorText); - link.setShowErrorTransportText(showErrorTransportText); - link.setNotifyTopics(notifyTopics); - link.setAfterLoading(afterLoading); - link.setPreInvokeJS(preInvokeJS); - } - public void setHref(String href) { - this.href = href; + link.setTargets(targets); } - public void setErrorText(String errorText) { - this.errorText = errorText; + public void setTargets(String targets) { + this.targets = targets; } - - public void setShowErrorTransportText(String showErrorTransportText) { - this.showErrorTransportText = showErrorTransportText; - } - - public void setNotifyTopics(String notifyTopics) { - this.notifyTopics = notifyTopics; - } - - public void setAfterLoading(String afterLoading) { - this.afterLoading = afterLoading; - } - - public void setPreInvokeJS(String preInvokeJS) { - this.preInvokeJS = preInvokeJS; - } } Index: core/src/main/java/org/apache/struts2/views/jsp/ui/DivTag.java =================================================================== --- core/src/main/java/org/apache/struts2/views/jsp/ui/DivTag.java (revision 466128) +++ core/src/main/java/org/apache/struts2/views/jsp/ui/DivTag.java (working copy) @@ -25,19 +25,17 @@ import com.opensymphony.xwork2.util.ValueStack; -public class DivTag extends AbstractClosingTag { - - private static final long serialVersionUID = 5309231035916461758L; - - protected String href; - protected String updateFreq; - protected String delay="1"; - protected String loadingText; - protected String errorText; - protected String showErrorTransportText; - protected String listenTopics; - protected String afterLoading; +public class DivTag extends AbstractRemoteCallUITag { + private static final long serialVersionUID = 5309231035916461758L; + + protected String updateInterval; + protected String autoStart; + protected String delay; + protected String startTimerListenTopic; + protected String stopTimerListenTopic; + protected String refreshOnShow; + public Component getBean(ValueStack stack, HttpServletRequest req, HttpServletResponse res) { return new Div(stack, req, res); } @@ -46,45 +44,34 @@ super.populateParams(); Div div = (Div) component; - div.setHref(href); - div.setUpdateFreq(updateFreq); + div.setUpdateInterval(updateInterval); + div.setAutoStart(autoStart); div.setDelay(delay); - div.setLoadingText(loadingText); - div.setErrorText(errorText); - div.setShowErrorTransportText(showErrorTransportText); - div.setListenTopics(listenTopics); - div.setAfterLoading(afterLoading); + div.setStartTimerListenTopic(startTimerListenTopic); + div.setStopTimerListenTopic(stopTimerListenTopic); } - public void setHref(String href) { - this.href = href; + public void setAutoStart(String autoStart) { + this.autoStart = autoStart; } - public void setUpdateFreq(String updateFreq) { - this.updateFreq = updateFreq; - } - public void setDelay(String delay) { this.delay = delay; } - public void setLoadingText(String loadingText) { - this.loadingText = loadingText; + public void setUpdateInterval(String updateInterval) { + this.updateInterval = updateInterval; } - public void setErrorText(String errorText) { - this.errorText = errorText; + public void setStartTimerListenTopic(String startTimerListenTopic) { + this.startTimerListenTopic = startTimerListenTopic; } - public void setShowErrorTransportText(String showErrorTransportText) { - this.showErrorTransportText = showErrorTransportText; + public void setStopTimerListenTopic(String stopTimerListenTopic) { + this.stopTimerListenTopic = stopTimerListenTopic; } - public void setListenTopics(String listenTopics) { - this.listenTopics = listenTopics; + public void setRefreshOnShow(String refreshOnShow) { + this.refreshOnShow = refreshOnShow; } - - public void setAfterLoading(String afterLoading) { - this.afterLoading = afterLoading; - } } Index: core/src/main/java/org/apache/struts2/views/jsp/ui/TabbedPanelTag.java =================================================================== --- core/src/main/java/org/apache/struts2/views/jsp/ui/TabbedPanelTag.java (revision 466128) +++ core/src/main/java/org/apache/struts2/views/jsp/ui/TabbedPanelTag.java (working copy) @@ -17,13 +17,10 @@ */ package org.apache.struts2.views.jsp.ui; -import java.util.List; - import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import org.apache.struts2.components.Component; -import org.apache.struts2.components.Panel; import org.apache.struts2.components.TabbedPanel; import com.opensymphony.xwork2.util.ValueStack; @@ -32,19 +29,35 @@ * @see TabbedPanel */ public class TabbedPanelTag extends AbstractClosingTag { - - private static final long serialVersionUID = -4719930205515386252L; - public Component getBean(ValueStack stack, HttpServletRequest req, HttpServletResponse res) { + private static final long serialVersionUID = -4719930205515386252L; + + private String selectedTab; + private String closeButton; + private String doLayout; + + public Component getBean(ValueStack stack, HttpServletRequest req, HttpServletResponse res) { return new TabbedPanel(stack, req, res); } - public List getTabs() { - return ((TabbedPanel) component).getTabs(); + protected void populateParams() { + super.populateParams(); + TabbedPanel tabbedPanel = (TabbedPanel) component; + tabbedPanel.setSelectedTab(selectedTab); + tabbedPanel.setCloseButton(closeButton); + tabbedPanel.setDoLayout(doLayout); + tabbedPanel.setLabelposition(labelPosition); } - public void addTab(Panel pane) { - ((TabbedPanel) component).addTab(pane); + public void setSelectedTab(String selectedTab) { + this.selectedTab = selectedTab; } + public void setCloseButton(String closeButton) { + this.closeButton = closeButton; + } + + public void setDoLayout(String doLayout) { + this.doLayout = doLayout; + } } Index: core/src/main/java/org/apache/struts2/views/velocity/VelocityManager.java =================================================================== --- core/src/main/java/org/apache/struts2/views/velocity/VelocityManager.java (revision 466128) +++ core/src/main/java/org/apache/struts2/views/velocity/VelocityManager.java (working copy) @@ -63,7 +63,6 @@ import org.apache.struts2.views.velocity.components.IncludeDirective; import org.apache.struts2.views.velocity.components.LabelDirective; import org.apache.struts2.views.velocity.components.OptionTransferSelectDirective; -import org.apache.struts2.views.velocity.components.PanelDirective; import org.apache.struts2.views.velocity.components.ParamDirective; import org.apache.struts2.views.velocity.components.PasswordDirective; import org.apache.struts2.views.velocity.components.PropertyDirective; @@ -127,7 +126,7 @@ * Names of contexts that will be chained on every request */ private String[] chainedContextNames; - + private Properties velocityProperties; protected VelocityManager() { @@ -282,8 +281,8 @@ // now apply our systemic defaults, then allow user to override applyDefaultConfiguration(context, properties); - + String defaultUserDirective = properties.getProperty("userdirective"); /** @@ -355,7 +354,7 @@ } } } - + // overide with programmatically set properties if (this.velocityProperties != null) { Iterator keys = this.velocityProperties.keySet().iterator(); @@ -375,7 +374,7 @@ properties.setProperty("userdirective", userdirective); - + // for debugging purposes, allows users to dump out the properties that have been configured if (log.isDebugEnabled()) { log.debug("Initializing Velocity with the following properties ..."); @@ -488,7 +487,7 @@ Properties p = loadConfiguration(context); VelocityEngine velocityEngine = new VelocityEngine(); - + // Set the velocity attribute for the servlet context // if this is not set the webapp loader WILL NOT WORK velocityEngine.setApplicationAttribute(ServletContext.class.getName(), @@ -584,7 +583,6 @@ addDirective(sb, I18nDirective.class); addDirective(sb, IncludeDirective.class); addDirective(sb, LabelDirective.class); - addDirective(sb, PanelDirective.class); addDirective(sb, ParamDirective.class); addDirective(sb, PasswordDirective.class); addDirective(sb, PushDirective.class); Index: core/src/main/resources/META-INF/struts-tags.tld =================================================================== --- core/src/main/resources/META-INF/struts-tags.tld (revision 466128) +++ core/src/main/resources/META-INF/struts-tags.tld (working copy) @@ -2306,7 +2306,7 @@ - updateFreq + updateInterval false true @@ -2314,6 +2314,22 @@ + handler + false + true + + + + + + executeScripts + false + true + + + + + delay false true @@ -2322,6 +2338,14 @@ + autoStart + false + true + + 0) or loads contents when created]]> + + + loadingText false true @@ -2331,7 +2355,7 @@ - listenTopics + refreshListenTopic false true @@ -2340,6 +2364,24 @@ + startTimerListenTopic + false + true + + + + + + + stopTimerListenTopic + false + true + + + + + + theme false true @@ -2366,11 +2408,12 @@ - showErrorTransportText + beforeLoading false true - + + @@ -2973,9 +3016,9 @@ flush false true - + - + @@ -7297,35 +7340,46 @@ a org.apache.struts2.views.jsp.ui.AnchorTag JSP + - + + - id + executeScripts false true - + - notifyTopics + handler false true - + - preInvokeJS + loadingText false true - + + refreshListenTopic + false + true + + + + + + theme false true @@ -7352,11 +7406,12 @@ - showErrorTransportText + beforeLoading false true - + + @@ -7618,7 +7673,24 @@ + + id + false + true + + + + + + targets + false + true + + + + + @@ -8916,376 +8988,6 @@ - panel - org.apache.struts2.views.jsp.ui.PanelTag - JSP - - - - tabName - true - true - - - - - - subscribeTopicName - false - true - - - - - - remote - false - true - - - - - - - updateFreq - false - true - - - - - - delay - false - true - - - - - - loadingText - false - true - - - - - - - listenTopics - false - true - - - - - - - theme - false - true - - - This tag will usually use the ajax theme.]]> - - - - href - false - true - - - - - - errorText - false - true - - - - - - - showErrorTransportText - false - true - - - - - - afterLoading - false - true - - - - - - - openTemplate - false - true - - - - - - templateDir - false - true - - - - - - - template - false - true - - - - - - cssClass - false - true - - - - - - cssStyle - false - true - - - - - - title - false - true - - - - - - disabled - false - true - - - - - - label - false - true - - - - - - labelposition - false - true - - - - - - requiredposition - false - true - - - - - - name - false - true - - - - - - required - false - true - - - - - - - tabindex - false - true - - - - - - value - false - true - - - - - - onclick - false - true - - - - - - ondblclick - false - true - - - - - - onmousedown - false - true - - - - - - onmouseup - false - true - - - - - - onmouseover - false - true - - - - - - onmousemove - false - true - - - - - - onmouseout - false - true - - - - - - onfocus - false - true - - - - - - onblur - false - true - - - - - - onkeypress - false - true - - - - - - onkeydown - false - true - - - - - - onkeyup - false - true - - - - - - onselect - false - true - - - - - - onchange - false - true - - - - - - accesskey - false - true - - - - - - tooltip - false - true - - - - - - tooltipConfig - false - true - - - - - - id - false - true - - - - - - - - - actionmessage org.apache.struts2.views.jsp.ui.ActionMessageTag empty @@ -10070,6 +9772,36 @@ + selectedTab + false + true + + + + + + + + closeButton + false + true + + + + + + + + doLayout + false + true + + + + + + + openTemplate false true @@ -10147,7 +9879,7 @@ false true - + Index: core/src/main/resources/org/apache/struts2/static/CommonFunctions.js =================================================================== --- core/src/main/resources/org/apache/struts2/static/CommonFunctions.js (revision 466128) +++ core/src/main/resources/org/apache/struts2/static/CommonFunctions.js (working copy) @@ -1,97 +1,52 @@ - -/** - * Methods for the tabbed component - */ -var unselectedClass = "tab_default tab_unselected"; -var unselectedContentsClass = "tab_contents_hidden"; -var unselectedOverClass = "tab_default tab_unselected tab_unselected_over"; -var selectedClass = "tab_default tab_selected"; -var selectedContentsClass = "tab_contents_header"; - -function mouseIn(tab) { - var className = tab.className; - if (className.indexOf('unselected') > -1) { - className = unselectedOverClass; - tab.className = className; - } -} - -function mouseOut(tab) { - var className = tab.className; - if (className.indexOf('unselected') > -1) { - className = unselectedClass; - tab.className = className; - } -} - -/* - * An object that represents a tabbed page. - * - * @param htmlId the id of the element that represents the tab page - * @param remote whether this is a remote element and needs refreshing - */ -function TabContent( htmlId, remote ) { - - this.elementId = htmlId; - this.isRemote = remote; - var selected = false; - var self = this; - - /* - * Shows or hides this page depending on whether the visible - * tab id matches this objects id. - * - * @param visibleTabId the id of the tab that was selected - */ - this.updateVisibility = function( visibleTabId ) { - var thElement = document.getElementById( 'tab_header_'+self.elementId ); - var tcElement = document.getElementById( 'tab_contents_'+self.elementId ); - if (!selected && visibleTabId==self.elementId) { - thElement.className = selectedClass; - tcElement.className = selectedContentsClass; - self.selected = true; - - } else { - thElement.className = unselectedClass; - tcElement.className = unselectedContentsClass; - self.selected = false; - } - if (self.isRemote==true && visibleTabId==self.elementId) { - var rel = window['tab_contents_update_'+self.elementId]; - // If the first tab is a remote tab, rel is null on initial loading... - // so don't try to call a method that doesn't exist. This is only - // for IE, and the workaround is to use a - // as the content of the DIV. - if (rel.bind) - rel.bind(); - } - } - -} - -/** - * Checks whether the current form include an ajax-ified submit button, if so - * we return true (otherwise false). - * - * @param form the HTML form element to check - */ -function isAjaxFormSubmit( form ) { - // we check whether this exists - // - var thisForm = document.getElementById(form.id); - var matchUrl = /\s+dojoAttachPoint/; - if( thisForm.innerHTML.match(matchUrl) ) { - return false; - } - for( i=0; i -1) { + className = unselectedOverClass; + tab.className = className; + } +} + +function mouseOut(tab) { + var className = tab.className; + if (className.indexOf('unselected') > -1) { + className = unselectedClass; + tab.className = className; + } +} + +/** + * Checks whether the current form include an ajax-ified submit button, if so + * we return true (otherwise false). + * + * @param form the HTML form element to check + */ +function isAjaxFormSubmit( form ) { + // we check whether this exists + // + var thisForm = document.getElementById(form.id); + var matchUrl = /\s+dojoAttachPoint/; + if( thisForm.innerHTML.match(matchUrl) ) { + return false; + } + for( i=0; i 0) { + var scripts = ""; + for(var i = 0; i < parsed.scripts.length; i++){ + scripts += parsed.scripts[i]; + } + (new Function('_container_', scripts+'; return this;'))(self); + } + self.setContent(parsed.text); + } + else { + self.setContent(data); + } + } else { + var message = dojo.string.isBlank(self.errorText) ? e.message : self.errorText; + self.setContent(message); + } + }; + + this.reloadContents = function() { + if(!dojo.string.isBlank(self.handler)) { + //use custom handler + self.log("Invoking handler: " + self.handler); + eval(self.handler + "(self, self.domNode)"); + } + else { + //pre script + if(!dojo.string.isBlank(self.beforeLoading)) { + self.log("Executing " + self.beforeLoading); + eval(self.beforeLoading); + } + try { + self.log("Loading content from " + self.href); + self.setContent(self.loadingText); + dojo.io.bind({ + url: self.href, + useCache: false, + preventCache: true, + handler: self.bindHandler, + mimetype: "text/html" + }); + } + catch(ex) { + var message = dojo.string.isBlank(self.errorText) ? ex : self.errorText; + self.setContent(message); + } + } + }; + + //from Dojo's ContentPane + this.parse = function(s) { + self.log("Parsing: " + s); + var match = []; + var tmp = []; + var scripts = []; + while(match){ + match = s.match(/]*)>([\s\S]*?)<\/script>/i); + if(!match){ break; } + if(match[1]){ + attr = match[1].match(/src=(['"]?)([^"']*)\1/i); + if(attr){ + // remove a dojo.js or dojo.js.uncompressed.js from remoteScripts + // we declare all files with dojo.js as bad, regardless of folder + var tmp2 = attr[2].search(/.*(\bdojo\b(?:\.uncompressed)?\.js)$/); + if(tmp2 > -1){ + self.log("Security note! inhibit:"+attr[2]+" from beeing loaded again."); + } + } + } + if(match[2]){ + // strip out all djConfig variables from script tags nodeValue + // this is ABSOLUTLY needed as reinitialize djConfig after dojo is initialised + // makes a dissaster greater than Titanic, update remove writeIncludes() to + var sc = match[2].replace(/(?:var )?\bdjConfig\b(?:[\s]*=[\s]*\{[^}]+\}|\.[\w]*[\s]*=[\s]*[^;\n]*)?;?|dojo\.hostenv\.writeIncludes\(\s*\);?/g, ""); + if(!sc){ continue; } + + // cut out all dojo.require (...) calls, if we have execute + // scripts false widgets dont get there require calls + // does suck out possible widgetpackage registration as well + tmp = []; + while(tmp){ + tmp = sc.match(/dojo\.(?:(?:require(?:After)?(?:If)?)|(?:widget\.(?:manager\.)?registerWidgetPackage)|(?:(?:hostenv\.)?setModulePrefix))\((['"]).*?\1\)\s*;?/); + if(!tmp){ break;} + sc = sc.replace(tmp[0], ""); + } + scripts.push(sc); + } + s = s.replace(/]*>[\s\S]*?<\/script>/i, ""); + } + + return { + text: s, + scripts: scripts + }; + }; +}; + +dojo.inherits(struts.widgets.BindAnchor, dojo.widget.HtmlWidget); + +dojo.widget.tags.addParseTreeHandler("dojo:BindAnchor"); Index: core/src/main/resources/org/apache/struts2/static/dojo/struts/widgets/BindDiv.js =================================================================== --- core/src/main/resources/org/apache/struts2/static/dojo/struts/widgets/BindDiv.js (revision 466128) +++ core/src/main/resources/org/apache/struts2/static/dojo/struts/widgets/BindDiv.js (working copy) @@ -1,157 +1,153 @@ -dojo.provide("struts.widgets.BindDiv"); -dojo.provide("struts.widgets.HTMLBindDiv"); - -dojo.require("dojo.io.*"); -dojo.require("dojo.event.*"); -dojo.require("dojo.widget.*"); -dojo.require("dojo.xml.Parse"); - -dojo.require("struts.Util"); -dojo.require("struts.widgets.HTMLBind"); - -/* - * Component to do remote updating of a DOM tree. - */ - -struts.widgets.HTMLBindDiv = function() { - - // inheritance - // see: http://www.cs.rit.edu/~atk/JavaScript/manuals/jsobj/ - struts.widgets.HTMLBind.call(this); - var self = this; - - this.widgetType = "BindDiv"; - this.templatePath = dojo.uri.dojoUri("struts/widgets/BindDiv.html"); - - - // register a global object to use for window.setTimeout callbacks - this.callback = struts.Util.makeGlobalCallback(this); - - // - // default properties that can be provided by the widget user - // - - // html to display while loading remote content - this.loadingHtml = ""; - - // initial dealy before fetching content - this.delay = 0; - - // how often to update the content from the server, after the initial delay - this.refresh = 0; - - // does the timeout loop start automatically ? - this.autoStart = true; - - // dom node in the template that will contain the remote content - this.contentDiv = null; - - // support a toggelable div - each listenEvent will trigger a change in the display state - // the bind call will only happen when the remote div is displayed - this.toggle = false; - - this._nextTimeout = function(millis) { - struts.Util.setTimeout(self.callback, "afterTimeout", millis); - } - - var super_fillInTemplate = this.fillInTemplate; - this.fillInTemplate = function(args, frag) { - super_fillInTemplate(args, frag); - - if (self.id == "") { - self.contentDiv.id = struts.Util.nextId(); - }else { - self.contentDiv.id = self.id; - } - - self.targetDiv = self.contentDiv.id; - - struts.Util.passThroughArgs(self.extraArgs, self.contentDiv); - struts.Util.passThroughWidgetTagContent(self, frag, self.contentDiv); - - // hook into before the bind operation to display the loading message - // do this always - to allow for on the fuy changes to the loadingHtml - dojo.event.kwConnect({ - srcObj: self, - srcFunc: "bind", - adviceObj: self, - adviceFunc: "loading" - }); - - if (self.autoStart) { - self.start(); - } - - if (self.toggle) { - dojo.event.kwConnect({ - type: 'around', - srcObj: self, - srcFunc: "bind", - adviceObj: self, - adviceFunc: "__toggleInterceptor" - }); - } - - } - - this.__toggleInterceptor = function(invocation) { - var hidden = self.contentDiv.style.display == 'none'; - self.contentDiv.style.display = (hidden)?'':'none'; - if (hidden) { - invocation.proceed(); - } - } - - this.error = function(type, error) { - //for (a in error) dojo.debug("error." + a + ":" + error[a]); - if (self.showTransportError) { - self.contentDiv.innerHTML = error.message; - }else{ - self.contentDiv.innerHTML = self.errorHtml; - } - } - - this.loading = function() { - if( self.loadingHtml != "" ) { - self.contentDiv.innerHTML = self.loadingHtml; - } - } - - this.afterTimeout = function() { - if (running) { - - // do the bind - self.bind(); - - // setup the next timeout - if (self.refresh > 0) { - self._nextTimeout(self.refresh); - } - } - } - - - var running = false; - this.stop = function() { - if (!running) return; - running = false; - struts.Util.clearTimeout(self.callback); - } - - this.start = function() { - if (running) return; - running = true; - - if (self.delay > 0) { - self._nextTimeout(self.delay); - } - } - -} -dojo.inherits(struts.widgets.HTMLBindDiv, struts.widgets.HTMLBind); - -// make it a tag -dojo.widget.tags.addParseTreeHandler("dojo:BindDiv"); - -// HACK - register this module as a widget package - to be replaced when dojo implements a propper widget namspace manager -dojo.widget.manager.registerWidgetPackage('struts.widgets'); +dojo.provide("struts.widgets.BindDiv"); + +dojo.require("dojo.widget.*"); +dojo.require("dojo.io.*"); +dojo.require("dojo.widget.ContentPane"); +dojo.require("dojo.animation.Timer"); + +struts.widgets.BindDiv = function() { + dojo.widget.html.ContentPane.call(this); + var self = this; + + this.widgetType = "BindDiv"; + + //from ContentPane + this.href = ""; + this.extractContent = false; + this.parseContent = false; + this.cacheContent = false; + this.refreshOnShow = false; + this.executeScripts = false; + + //update times + this.updateInterval = 0; + this.delay = 0; + this.autoStart = true; + this.timer = null; + + //messages + this.loadingText = "Loading..."; + this.errorText = ""; + + //pub/sub events + this.refreshListenTopic = ""; + this.stopTimerListenTopic = ""; + this.startTimerListenTopic = ""; + + //callbacks + this.beforeLoading = ""; + this.afterLoading = ""; + + this.onDownloadStart = function(event) { + if(!dojo.string.isBlank(self.beforeLoading)) { + self.log("Executing " + self.beforeLoading); + eval(self.beforeLoading); + } + if(!dojo.string.isBlank(self.loadingText)) { + event.text = self.loadingText; + } + }; + + this.onDownloadError = function(event) { + self.onError(event); + }; + + this.onContentError = function(event) { + self.onError(event); + }; + + this.onExecError = function(event) { + self.onError(event); + }; + + this.onError = function(event) { + if(!dojo.string.isBlank(self.errorText)) { + event.text = self.errorText; + } + }; + + this.postCreate = function() { + if(self.updateInterval > 0) { + self.timer = new dojo.animation.Timer(self.updateInterval); + self.timer.onTick = self.reloadContents; + + //start the timer + if(self.autoStart) { + //start after delay + dojo.lang.setTimeout(self.delay, self.startTimer); + if(self.delay === 0) { + //load content now + self.reloadContents(); + } + } + } + else { + if(self.autoStart) { + //start after delay + dojo.lang.setTimeout(self.delay, self.reloadContents); + } + } + + //attach listeners + if(!dojo.string.isBlank(self.refreshListenTopic)) { + self.log("Listening to " + self.refreshListenTopic + " to refresh"); + dojo.event.topic.subscribe(self.refreshListenTopic, self, "reloadContents"); + } + if(!dojo.string.isBlank(self.stopTimerListenTopic)) { + self.log("Listening to " + self.stopTimerListenTopic + " to stop timer"); + dojo.event.topic.subscribe(self.stopTimerListenTopic, self, "stopTimer"); + } + if(!dojo.string.isBlank(self.startTimerListenTopic)) { + self.log("Listening to " + self.startTimerListenTopic + " to start timer"); + dojo.event.topic.subscribe(self.startTimerListenTopic, self, "startTimer"); + } + + if(!dojo.string.isBlank(self.afterLoading)) { + dojo.event.connect("after", self, "onDownloadEnd", function(){ + self.log("Executing " + self.afterLoading); + eval(self.afterLoading); + }); + } + }; + + this.log = function(text) { + dojo.debug("[" + self.widgetId + "] " + text); + }; + + this.reloadContents = function() { + if(!dojo.string.isBlank(self.handler)) { + //use custom handler + self.log("Invoking handler: " + self.handler); + eval(self.handler + "(self, self.domNode)"); + } else { + //refresh is not visible in ContentPane + self.log("Updating content"); + self.isLoaded = false; + try { + self.loadContents(); + } + catch(ex) { + var message = dojo.string.isBlank(self.errorText) ? ex : self.errorText; + self.setContent(message); + } + } + }; + + this.stopTimer = function() { + if(self.timer && self.timer.isRunning) { + self.log("stopping timer"); + self.timer.stop(); + } + }; + + this.startTimer = function() { + if(self.timer && !self.timer.isRunning) { + self.log("starting timer with update interval " + self.updateInterval); + self.timer.start(); + } + }; +}; + +dojo.inherits(struts.widgets.BindDiv, dojo.widget.html.ContentPane); + +dojo.widget.tags.addParseTreeHandler("dojo:BindDiv"); Index: core/src/main/resources/template/ajax/a.ftl =================================================================== --- core/src/main/resources/template/ajax/a.ftl (revision 466128) +++ core/src/main/resources/template/ajax/a.ftl (working copy) @@ -1,33 +1,51 @@ - -<#if parameters.id?if_exists != ""> - id="${parameters.id?html}"<#rt/> - -<#if parameters.href?if_exists != ""> - href="${parameters.href}"<#rt/> - -<#if parameters.notifyTopics?exists> - notifyTopics="${parameters.notifyTopics}"<#rt/> - -<#if parameters.errorText?if_exists != ""> - errorHtml="${parameters.errorText?html}"<#rt/> - -<#if parameters.showErrorTransportText?exists> - showTransportError="true"<#rt/> - -<#if parameters.afterLoading?exists> - onLoad="${parameters.afterLoading}"<#rt/> - -<#if parameters.preInvokeJS?exists> - preInvokeJS="${parameters.preInvokeJS}"<#rt/> - -<#if parameters.tabindex?exists> - tabindex="${parameters.tabindex?html}"<#rt/> - -<#if parameters.cssClass?exists> - class="${parameters.cssClass?html}"<#rt/> - -<#if parameters.cssStyle?exists> - style="${parameters.cssStyle?html}"<#rt/> - -<#include "/${parameters.templateDir}/simple/scripting-events.ftl"/> + + id="${parameters.id?html}"<#rt/> + + <#if parameters.tabindex?if_exists != ""> + tabindex="${parameters.tabindex?html}"<#rt/> + + <#if parameters.cssClass?if_exists != ""> + class="${parameters.cssClass?html}"<#rt/> + + <#if parameters.cssStyle?if_exists != ""> + style="${parameters.cssStyle?html}"<#rt/> + + <#if parameters.label?if_exists != ""> + label="${parameters.label?html}"<#rt/> + + <#if parameters.title?if_exists != ""> + title="${parameters.title?html}"<#rt/> + + <#if parameters.name?if_exists != ""> + name="${parameters.name?html}"<#rt/> + + <#if parameters.href?if_exists != ""> + href="${parameters.href}"<#rt/> + + <#if parameters.loadingText?if_exists != ""> + loadingText="${parameters.loadingText?html}"<#rt/> + + <#if parameters.errorText?if_exists != ""> + errorText="${parameters.errorText?html}"<#rt/> + + <#if parameters.executeScripts?exists> + executeScripts="${parameters.executeScripts?string?html}"<#rt/> + + <#if parameters.refreshListenTopic?if_exists != ""> + refreshListenTopic="${parameters.refreshListenTopic?html}"<#rt/> + + <#if parameters.beforeLoading?if_exists != ""> + beforeLoading="${parameters.beforeLoading?html}"<#rt/> + + <#if parameters.afterLoading?if_exists != ""> + afterLoading="${parameters.afterLoading?html}"<#rt/> + + <#if parameters.targets?if_exists != ""> + targets="${parameters.targets?html}"<#rt/> + + <#if parameters.handler?if_exists != ""> + handler="${parameters.handler?html}"<#rt/> + + <#include "/${parameters.templateDir}/simple/scripting-events.ftl" /> > Index: core/src/main/resources/template/ajax/div.ftl =================================================================== --- core/src/main/resources/template/ajax/div.ftl (revision 466128) +++ core/src/main/resources/template/ajax/div.ftl (working copy) @@ -1,25 +1,63 @@ -
    id="${parameters.id?html}" - <#if parameters.title?exists>title="${parameters.title?html}" - <#if parameters.name?exists>name="${parameters.name?html}" - <#if parameters.href?if_exists != "">href="${parameters.href}" - <#if parameters.loadingText?if_exists != "">loadingHtml="${parameters.loadingText?html}" - <#if parameters.errorText?if_exists != "">errorHtml="${parameters.errorText?html}" - <#if parameters.showErrorTransportText?exists>showTransportError='true' - <#if parameters.delay?exists>delay='${parameters.delay}' - <#if parameters.updateFreq?exists>refresh='${parameters.updateFreq}' - <#if parameters.listenTopics?exists>listenTopics='${parameters.listenTopics}' - <#if parameters.afterLoading?exists>onLoad='${parameters.afterLoading}' - <#if parameters.autoStart?exists>autoStart='${parameters.autoStart}' - -<#if parameters.tabindex?exists> - tabindex="${parameters.tabindex?html}"<#rt/> - -<#if parameters.cssClass?exists> - class="${parameters.cssClass?html}"<#rt/> - -<#if parameters.cssStyle?exists> - style="${parameters.cssStyle?html}"<#rt/> - -<#include "/${parameters.templateDir}/simple/scripting-events.ftl" /> +
    + id="${parameters.id?html}"<#rt/> + + <#if parameters.tabindex?if_exists != ""> + tabindex="${parameters.tabindex?html}"<#rt/> + + <#if parameters.cssClass?if_exists != ""> + class="${parameters.cssClass?html}"<#rt/> + + <#if parameters.cssStyle?if_exists != ""> + style="${parameters.cssStyle?html}"<#rt/> + + <#if parameters.label?if_exists != ""> + label="${parameters.label?html}"<#rt/> + + <#if parameters.title?if_exists != ""> + title="${parameters.title?html}"<#rt/> + + <#if parameters.name?if_exists != ""> + name="${parameters.name?html}"<#rt/> + + <#if parameters.href?if_exists != ""> + href="${parameters.href}"<#rt/> + + <#if parameters.loadingText?if_exists != ""> + loadingText="${parameters.loadingText?html}"<#rt/> + + <#if parameters.errorText?if_exists != ""> + errorText="${parameters.errorText?html}"<#rt/> + + <#if parameters.delay?exists> + delay="${parameters.delay?c}"<#rt/> + + <#if parameters.updateInterval?exists> + updateInterval="${parameters.updateInterval?c}"<#rt/> + + <#if parameters.autoStart?exists> + autoStart="${parameters.autoStart?string?html}"<#rt/> + + <#if parameters.executeScripts?exists> + executeScripts="${parameters.executeScripts?string?html}"<#rt/> + + <#if parameters.refreshListenTopic?if_exists != ""> + refreshListenTopic="${parameters.refreshListenTopic?html}"<#rt/> + + <#if parameters.startTimerListenTopic?if_exists != ""> + startTimerListenTopic="${parameters.startTimerListenTopic?html}"<#rt/> + + <#if parameters.stopTimerListenTopic?if_exists != ""> + stopTimerListenTopic="${parameters.stopTimerListenTopic?html}"<#rt/> + + <#if parameters.beforeLoading?if_exists != ""> + beforeLoading="${parameters.beforeLoading?html}"<#rt/> + + <#if parameters.afterLoading?if_exists != ""> + afterLoading="${parameters.afterLoading?html}"<#rt/> + + <#if parameters.handler?if_exists != ""> + handler="${parameters.handler?html}"<#rt/> + + <#include "/${parameters.templateDir}/simple/scripting-events.ftl" /> > Index: core/src/main/resources/template/simple/head.ftl =================================================================== --- core/src/main/resources/template/simple/head.ftl (revision 466128) +++ core/src/main/resources/template/simple/head.ftl (working copy) @@ -2,7 +2,7 @@ // Dojo configuration djConfig = { baseRelativePath: "<@s.url includeParams='none' value='/struts/dojo' includeParams="none" encode='false'/>", - isDebug: ${parameters.debug?default(false)}, + isDebug: true, bindEncoding: "${parameters.encoding}", debugAtAllCosts: true // not needed, but allows the Venkman debugger to work with the includes }; Index: core/src/main/resources/template/simple/tabbedpanel-close.ftl =================================================================== --- core/src/main/resources/template/simple/tabbedpanel-close.ftl (revision 466128) +++ core/src/main/resources/template/simple/tabbedpanel-close.ftl (working copy) @@ -1,14 +1 @@ -<#assign topic = parameters.topicName /> -<#assign tpid = parameters.id /> - +
    Index: core/src/main/resources/template/simple/tabbedpanel.ftl =================================================================== --- core/src/main/resources/template/simple/tabbedpanel.ftl (revision 466128) +++ core/src/main/resources/template/simple/tabbedpanel.ftl (working copy) @@ -1 +1,29 @@ -
    + + +
    + style="${parameters.cssStyle?html}"<#rt/> + + <#if parameters.id?if_exists != ""> + style="${parameters.id?html}"<#rt/> + + <#if parameters.cssClass?if_exists != ""> + class="${parameters.cssClass?html}"<#rt/> + + <#if parameters.selectedTab?if_exists != ""> + selectedTab="${parameters.selectedTab?html}"<#rt/> + + <#if parameters.labelPosition?if_exists != ""> + labelPosition="${parameters.labelPosition?html}"<#rt/> + + <#if parameters.closeButton?if_exists != ""> + closeButton="${parameters.closeButton?html}"<#rt/> + + <#if parameters.doLayout?exists> + doLayout="${parameters.doLayout?string?html}"<#rt/> + +> Index: core/src/test/java/org/apache/struts2/components/UIComponentTest.java =================================================================== --- core/src/test/java/org/apache/struts2/components/UIComponentTest.java (revision 466128) +++ core/src/test/java/org/apache/struts2/components/UIComponentTest.java (working copy) @@ -19,6 +19,7 @@ import org.apache.struts2.TestConfigurationProvider; import org.apache.struts2.views.jsp.AbstractUITagTest; +import org.apache.struts2.views.jsp.ui.AbstractRemoteCallUITag; import org.apache.struts2.views.jsp.ui.ActionErrorTag; import org.apache.struts2.views.jsp.ui.ActionMessageTag; import org.apache.struts2.views.jsp.ui.AnchorTag; @@ -174,7 +175,7 @@ try { t.doStartTag(); - DivTag tag = new DivTag(); + AbstractRemoteCallUITag tag = new DivTag(); tag.setPageContext(pageContext); tag.doStartTag(); assertEquals(tag.getComponent().getComponentStack().peek(), tag.getComponent()); Index: core/src/test/java/org/apache/struts2/views/jsp/ui/AnchorTest.java =================================================================== --- core/src/test/java/org/apache/struts2/views/jsp/ui/AnchorTest.java (revision 466128) +++ core/src/test/java/org/apache/struts2/views/jsp/ui/AnchorTest.java (working copy) @@ -37,9 +37,12 @@ tag.setTheme("ajax"); tag.setHref("a"); tag.setErrorText("c"); - tag.setShowErrorTransportText("true"); - tag.setNotifyTopics("g"); - tag.setAfterLoading("h"); + tag.setLoadingText("d"); + tag.setAfterLoading("e"); + tag.setBeforeLoading("f"); + tag.setRefreshListenTopic("g"); + tag.setTargets("h"); + tag.setHandler("i"); tag.doStartTag(); tag.doEndTag(); Index: core/src/test/java/org/apache/struts2/views/jsp/ui/DivTest.java =================================================================== --- core/src/test/java/org/apache/struts2/views/jsp/ui/DivTest.java (revision 466128) +++ core/src/test/java/org/apache/struts2/views/jsp/ui/DivTest.java (working copy) @@ -27,17 +27,17 @@ public void testGenericSimple() throws Exception { - DivTag tag = new DivTag(); + AbstractRemoteCallUITag tag = new DivTag(); verifyGenericProperties(tag, "simple", new String[]{"value","tabindex","disabled"}); } public void testGenericXhtml() throws Exception { - DivTag tag = new DivTag(); + AbstractRemoteCallUITag tag = new DivTag(); verifyGenericProperties(tag, "xhtml", new String[]{"value","tabindex","disabled"}); } public void testGenericAjax() throws Exception { - DivTag tag = new DivTag(); + AbstractRemoteCallUITag tag = new DivTag(); verifyGenericProperties(tag, "ajax", new String[]{"value","tabindex","disabled"}); } @@ -53,12 +53,16 @@ tag.setHref("a"); tag.setLoadingText("b"); tag.setErrorText("c"); - tag.setShowErrorTransportText("true"); + tag.setAutoStart("true"); tag.setDelay("4000"); - tag.setUpdateFreq("1000"); - tag.setListenTopics("g"); - tag.setAfterLoading("h"); - + tag.setUpdateInterval("1000"); + tag.setRefreshListenTopic("g"); + tag.setStartTimerListenTopic("h"); + tag.setStopTimerListenTopic("i"); + tag.setBeforeLoading("j"); + tag.setAfterLoading("k"); + tag.setRefreshOnShow("true"); + tag.setHandler("l"); tag.doStartTag(); tag.doEndTag(); Index: core/src/test/resources/org/apache/struts2/views/jsp/ui/div-1.txt =================================================================== --- core/src/test/resources/org/apache/struts2/views/jsp/ui/div-1.txt (revision 466128) +++ core/src/test/resources/org/apache/struts2/views/jsp/ui/div-1.txt (working copy) @@ -1,12 +1,15 @@ -
    Index: core/src/test/resources/org/apache/struts2/views/jsp/ui/href-1.txt =================================================================== --- core/src/test/resources/org/apache/struts2/views/jsp/ui/href-1.txt (revision 466128) +++ core/src/test/resources/org/apache/struts2/views/jsp/ui/href-1.txt (working copy) @@ -1 +1,12 @@ -
    + + \ No newline at end of file