You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@myfaces.apache.org by sk...@apache.org on 2008/07/25 15:09:55 UTC

svn commit: r679791 - in /myfaces/orchestra/trunk/flow/src/main/java/org/apache/myfaces/orchestra/flow/components: ./ ModalFlow.java ModalFlowTag.java

Author: skitching
Date: Fri Jul 25 06:09:54 2008
New Revision: 679791

URL: http://svn.apache.org/viewvc?rev=679791&view=rev
Log:
Add components to support starting a called flow in a modal popup window.

Added:
    myfaces/orchestra/trunk/flow/src/main/java/org/apache/myfaces/orchestra/flow/components/
    myfaces/orchestra/trunk/flow/src/main/java/org/apache/myfaces/orchestra/flow/components/ModalFlow.java   (with props)
    myfaces/orchestra/trunk/flow/src/main/java/org/apache/myfaces/orchestra/flow/components/ModalFlowTag.java   (with props)

Added: myfaces/orchestra/trunk/flow/src/main/java/org/apache/myfaces/orchestra/flow/components/ModalFlow.java
URL: http://svn.apache.org/viewvc/myfaces/orchestra/trunk/flow/src/main/java/org/apache/myfaces/orchestra/flow/components/ModalFlow.java?rev=679791&view=auto
==============================================================================
--- myfaces/orchestra/trunk/flow/src/main/java/org/apache/myfaces/orchestra/flow/components/ModalFlow.java (added)
+++ myfaces/orchestra/trunk/flow/src/main/java/org/apache/myfaces/orchestra/flow/components/ModalFlow.java Fri Jul 25 06:09:54 2008
@@ -0,0 +1,232 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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.myfaces.orchestra.flow.components;
+
+import java.io.IOException;
+import java.util.HashMap;
+import java.util.Map;
+
+import javax.faces.FacesException;
+import javax.faces.component.UIComponentBase;
+import javax.faces.context.FacesContext;
+import javax.faces.context.ResponseWriter;
+
+/**
+ * A component which allows an Orchestra Flow to be rendered into a popup window embedded
+ * in the page that calls the flow.
+ * <p>
+ * When this component is present in a page, and a postback of the page triggers 
+ * navigation to the entry point of a flow, then instead of actually navigating to
+ * the flow entry page the current page is re-rendered. This component will then
+ * take care of rendering appropriate javascript to open the popup window and load
+ * the flow entry page into it.
+ * <p>
+ * This component does not implement a "modal dialog" itself; it assumes that some other
+ * library is used to actually manage the dialog (eg the s:modalDialog component from
+ * the Tomahawk Sandbox). Instead, the page author is responsible for placing a hidden
+ * modal dialog component in the page, and then configuring this component  with an
+ * appropriate javascript command to execute when a flow begins. This
+ * component then renders that javascript only in the right circumstances.
+ * <p>
+ * This component has no effect at all on navigation that is not a "flow call". 
+ * <p>
+ * Note that triggering a flow is always done via a normal postback of the calling
+ * page, just as it happens for a non-modal flow call. This keeps things consistent.
+ * When using flow.xml files for configuration, the decision on whether a particular
+ * navigation is a flow call or not is done only in the flow.xml file, and not in the
+ * page. But whether a flow (if one is triggered) is normal or modal is made only in
+ * the page, and not in the flow.xml files. There is no overlap in responsibility
+ * here, ie no place where configuration must be consistent in two different places
+ * in order for the system to work. Whether a navigation is to a flow is a programmer
+ * decision; whether it is a popup or not is a UI designer decision and keeping these
+ * separated is important.
+ * <p>
+ * The alternative of popping up a window then posting from that is not used because
+ * that would mean that the page is making assumptions about whether a flow call is
+ * going to happen or not; it couples the page and the flow behaviour too tightly.
+ * If the postback did *not* trigger the start of a flow for example, then things
+ * would get very confusing.
+ * <p>
+ * This design should be fully compatible with AJAX; an AJAX postback can trigger
+ * a flow on the server. As long as the page "updated region" includes this modalFlow
+ * component, and the javascript returned to the browser in that region is executed
+ * then a popup modal flow should also work fine.
+ */
+public class ModalFlow extends UIComponentBase
+{
+    public static final String COMPONENT_FAMILY = "javax.faces.Component";
+    public static final String COMPONENT_TYPE = "org.apache.myfaces.orchestra.flow.components.ModalFlow";
+
+    private String outcome;
+    private String onEntry;
+
+    // transient property
+    private boolean active = false;
+
+    public String getFamily()
+    {
+        return COMPONENT_FAMILY;
+    }
+
+    /**
+     * The optional flow outcome that causes this component to render the onEntry script.
+     * <p>
+     * When set, then this component will render the onEntry script (ie cause a new flow
+     * to be modal) only when a new flow is triggered by a matching outcome value. Calls
+     * to flows triggered by other outcomes will cause the current page to be replaced
+     * by the flow entry page (as normal) rather than running the flow in a modal window.
+     * <p>
+     * When not set (ie when null), any flowCall triggered by the containing page will
+     * activate this component (run as a modal flow).
+     * <p>
+     * Static value only (EL expressions not supported).
+     */
+    public String getOutcome()
+    {
+        return outcome;
+    }
+
+    public void setOutcome(String outcome)
+    {
+        this.outcome = outcome;
+    }
+
+    /**
+     * Specify some javascript that will be executed when this component is
+     * triggered by a flow call.
+     * <p>
+     * Static value only (EL expressions not supported).
+     */
+    public String getOnEntry()
+    {
+        return onEntry;
+    }
+
+    public void setOnEntry(String script)
+    {
+        this.onEntry = script;
+    }
+
+    /**
+     * Cause this component to render the onEntry script that shows the associated modal dialog.
+     * <p> 
+     * This is called by the Orchestra Flow framework when the containing view has returned an
+     * outcome which triggers a flow and which matches the outcome property of this component.
+     */
+    public void setActive(boolean state)
+    {
+        this.active = state;
+    }
+
+    // ================ State Methods =================
+
+    public void restoreState(FacesContext context, Object state)
+    throws FacesException
+    {
+        Object[] states = (Object[]) state;
+        super.restoreState(context, states[0]);
+        outcome = (String) states[1];
+        onEntry = (String) states[2];
+
+        // While restoring view, add self to request scope, so that the
+        // FlowNavigationHandler can find it, activate it, and trigger
+        // re-render of the current view rather than actually doing
+        // navigation to the flow entry page.
+        //
+        // Note that a null outcome is valid.
+        
+        Map reqMap = context.getExternalContext().getRequestMap();
+        Map flowMap = (Map) reqMap.get("modalFlows");
+        if (flowMap == null)
+        {
+            flowMap = new HashMap();
+            reqMap.put("modalFlows", flowMap);
+        }
+        if (flowMap.containsKey(outcome))
+        {
+            throw new FacesException("Duplicate ModalFlows with same outcome");
+        }
+        flowMap.put(outcome, this);
+    }
+
+    public Object saveState(FacesContext context)
+    {
+        return new Object[]
+            {
+                super.saveState(context),
+                outcome,
+                onEntry,
+            };
+    }
+
+    // ============ Renderer methods =================
+
+    /**
+     * When this component is active (postback for the containing view
+     * has just triggered a flowcall using an outcome matching this
+     * component), render the onEntry javascript.
+     * <p>
+     * When this component is not active, nothing is rendered.
+     */
+    public void encodeBegin(FacesContext context) throws IOException
+    {
+        super.encodeBegin(context);
+        
+        if (active)
+        {
+            // Here, output script. We assume that this component is later
+            // within the page than whatever defines the function that this
+            // script calls.
+            //
+            // TODO: maybe here we should use StringSubstitutor to insert
+            // variables like ${viewURL} into the provided script?
+            ResponseWriter rw = context.getResponseWriter();
+            rw.startElement("script", this);
+            rw.write(onEntry);
+            rw.endElement("script");
+        }
+    }
+
+    // ============ Static methods =================
+
+    /**
+     * Determines whether the most recently restored view contains a ModalFlow
+     * component that maps to this outcome;
+     */
+    public static ModalFlow getForOutcome(FacesContext context, String outcome)
+    {
+        Map reqMap = context.getExternalContext().getRequestMap();
+        Map flowMap = (Map) reqMap.get("modalFlows");
+        if (flowMap == null)
+        {
+            return null;
+        }
+
+        ModalFlow mf = (ModalFlow) flowMap.get(outcome);
+        if (mf != null)
+        {
+            return mf;
+        }
+
+        // look for a global one
+        return (ModalFlow) flowMap.get(null);
+    }
+
+}

Propchange: myfaces/orchestra/trunk/flow/src/main/java/org/apache/myfaces/orchestra/flow/components/ModalFlow.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: myfaces/orchestra/trunk/flow/src/main/java/org/apache/myfaces/orchestra/flow/components/ModalFlow.java
------------------------------------------------------------------------------
    svn:executable = *

Added: myfaces/orchestra/trunk/flow/src/main/java/org/apache/myfaces/orchestra/flow/components/ModalFlowTag.java
URL: http://svn.apache.org/viewvc/myfaces/orchestra/trunk/flow/src/main/java/org/apache/myfaces/orchestra/flow/components/ModalFlowTag.java?rev=679791&view=auto
==============================================================================
--- myfaces/orchestra/trunk/flow/src/main/java/org/apache/myfaces/orchestra/flow/components/ModalFlowTag.java (added)
+++ myfaces/orchestra/trunk/flow/src/main/java/org/apache/myfaces/orchestra/flow/components/ModalFlowTag.java Fri Jul 25 06:09:54 2008
@@ -0,0 +1,61 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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.myfaces.orchestra.flow.components;
+
+import javax.faces.component.UIComponent;
+
+import org.apache.myfaces.shared_orchestra.taglib.UIComponentTagBase;
+
+/**
+ * Tag for ModalFlow component.
+ */
+public class ModalFlowTag extends UIComponentTagBase
+{
+    private String outcome;
+    private String onEntry;
+
+    public String getComponentType()
+    {
+        return ModalFlow.COMPONENT_TYPE;
+    }
+
+    protected void setProperties(UIComponent component)
+    {
+        super.setProperties(component);
+
+        setStringProperty(component, "outcome", outcome);
+        setStringProperty(component, "onEntry", onEntry);
+    }
+
+    public void setOutcome(String outcome)
+    {
+        this.outcome = outcome;
+    }
+
+    public void setOnEntry(String onEntry)
+    {
+        this.onEntry = onEntry;
+    }
+
+    public String getRendererType()
+    {
+        return null;
+    }
+}

Propchange: myfaces/orchestra/trunk/flow/src/main/java/org/apache/myfaces/orchestra/flow/components/ModalFlowTag.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: myfaces/orchestra/trunk/flow/src/main/java/org/apache/myfaces/orchestra/flow/components/ModalFlowTag.java
------------------------------------------------------------------------------
    svn:executable = *