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
015package org.apache.tapestry5.internal.services.ajax;
016
017import org.apache.tapestry5.MarkupWriter;
018import org.apache.tapestry5.dom.Element;
019import org.apache.tapestry5.internal.services.PageRenderQueue;
020import org.apache.tapestry5.json.JSONObject;
021import org.apache.tapestry5.runtime.RenderCommand;
022import org.apache.tapestry5.runtime.RenderQueue;
023import org.apache.tapestry5.services.PartialMarkupRenderer;
024import 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 */
034public 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}