    001    // Copyright 2009, 2010, 2011 The Apache Software Foundation
    002    //
    003    // Licensed under the Apache License, Version 2.0 (the "License");
    004    // you may not use this file except in compliance with the License.
    005    // You may obtain a copy of the License at
    006    //
    007    // http://www.apache.org/licenses/LICENSE-2.0
    008    //
    009    // Unless required by applicable law or agreed to in writing, software
    010    // distributed under the License is distributed on an "AS IS" BASIS,
    011    // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    012    // See the License for the specific language governing permissions and
    013    // limitations under the License.
    014
    015    package org.apache.tapestry5.internal.services.ajax;
    016
    017    import org.apache.tapestry5.MarkupWriter;
    018    import org.apache.tapestry5.dom.Element;
    019    import org.apache.tapestry5.internal.services.PageRenderQueue;
    020    import org.apache.tapestry5.json.JSONObject;
    021    import org.apache.tapestry5.runtime.RenderCommand;
    022    import org.apache.tapestry5.runtime.RenderQueue;
    023    import org.apache.tapestry5.services.PartialMarkupRenderer;
    024    import org.apache.tapestry5.services.PartialMarkupRendererFilter;
    025
    026    /**
    027     * Responsible for capturing the content for a single zone and storing it into the JSON reply object. As a {@link PartialMarkupRendererFilter} , this
    028     * has access to the {@link JSONObject} for the reply, and can {@linkplain PageRenderQueue#addPartialRenderer(org.apache.tapestry5.runtime.RenderCommand) add renderers that generate and package the markup content}.
    029     *
    030     * @see org.apache.tapestry5.ajax.MultiZoneUpdate
    031     * @see org.apache.tapestry5.services.ajax.AjaxResponseRenderer#addRender(String, Object)
    032     * @since 5.1.0.1
    033     */
    034    public class SingleZonePartialRendererFilter implements PartialMarkupRendererFilter
    035    {
    036        private final String zoneId;
    037
    038        private final RenderCommand zoneRenderCommand;
    039
    040        private final PageRenderQueue queue;
    041
    042        private final AjaxFormUpdateController ajaxFormUpdateController;
    043
    044        public SingleZonePartialRendererFilter(String zoneId, RenderCommand zoneRenderCommand, PageRenderQueue queue,
    045                                               AjaxFormUpdateController ajaxFormUpdateController)
    046        {
    047            this.zoneId = zoneId;
    048            this.zoneRenderCommand = zoneRenderCommand;
    049            this.queue = queue;
    050            this.ajaxFormUpdateController = ajaxFormUpdateController;
    051        }
    052
    053        public void renderMarkup(MarkupWriter writer, final JSONObject reply, PartialMarkupRenderer renderer)
    054        {
    055            RenderCommand forZone = new RenderCommand()
    056            {
    057                public void render(MarkupWriter writer, RenderQueue queue)
    058                {
    059                    // Create an element to contain the content for the zone. We give it a mnemonic
    060                    // element name and attribute just to help with debugging (the element itself is discarded).
    061
    062                    final Element zoneContainer = writer.element("zone-update", "zoneId", zoneId);
    063
    064                    ajaxFormUpdateController.setupBeforePartialZoneRender(writer);
    065
    066                    queue.push(new RenderCommand()
    067                    {
    068                        public void render(MarkupWriter writer, RenderQueue queue)
    069                        {
    070                            writer.end(); // the zoneContainer element
    071
    072                            // Need to do this Ajax Form-related cleanup here, before we extract the zone content.
    073
    074                            ajaxFormUpdateController.cleanupAfterPartialZoneRender();
    075
    076                            String zoneUpdateContent = zoneContainer.getChildMarkup();
    077
    078                            zoneContainer.remove();
    079
    080                            if (!reply.has("zones"))
    081                            {
    082                                reply.put("zones", new JSONObject());
    083                            }
    084
    085                            reply.getJSONObject("zones").put(zoneId, zoneUpdateContent);
    086                        }
    087                    });
    088
    089                    // Make sure the zone's actual rendering command is processed first, then the inline
    090                    // RenderCommand just above.
    091
    092                    queue.push(zoneRenderCommand);
    093                }
    094            };
    095
    096            queue.addPartialRenderer(forZone);
    097
    098            renderer.renderMarkup(writer, reply);
    099        }
    100    }