001// Copyright 2009-2013 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.corelib.components; 016 017import org.apache.tapestry5.*; 018import org.apache.tapestry5.annotations.Environmental; 019import org.apache.tapestry5.annotations.Events; 020import org.apache.tapestry5.annotations.Parameter; 021import org.apache.tapestry5.annotations.SupportsInformalParameters; 022import org.apache.tapestry5.ioc.annotations.Inject; 023import org.apache.tapestry5.services.compatibility.DeprecationWarning; 024import org.apache.tapestry5.services.javascript.JavaScriptSupport; 025 026import java.io.IOException; 027 028/** 029 * A component used to implement the <a 030 * href="http://en.wikipedia.org/wiki/Progressive_enhancement">progressive 031 * enhancement</a> web design strategy; the component renders itself with a 032 * simplified initial content (i.e., "loading 033 * ...") and an Ajax request then supplies the component's true body. This 034 * results in much faster page loads. You can 035 * even nest these! 036 * <p/> 037 * The component simply does not render its body on initial render. On the subsequent action event request, it fires a 038 * {@link org.apache.tapestry5.EventConstants#PROGRESSIVE_DISPLAY} event to inform the container about the (optional) 039 * event context. The event handler method may return a renderable object; if not then the component's body is rendered 040 * as the partial markup response. 041 * 042 * @tapestrydoc 043 * @since 5.1.0.1 044 */ 045@SupportsInformalParameters 046@Events(EventConstants.PROGRESSIVE_DISPLAY) 047@SuppressWarnings("all") 048public class ProgressiveDisplay 049{ 050 /** 051 * The initial content to display until the real content arrives. Defaults 052 * to "Loading ..." and an Ajax activity 053 * icon. 054 */ 055 @Parameter(defaultPrefix = BindingConstants.LITERAL, value = "block:defaultInitial") 056 private Block initial; 057 058 /** 059 * If provided, this is the event context, which will be provided via the 060 * {@link org.apache.tapestry5.EventConstants#PROGRESSIVE_DISPLAY event}. 061 */ 062 @Parameter 063 private Object[] context; 064 065 @Inject 066 private ComponentResources resources; 067 068 @Environmental 069 private JavaScriptSupport jsSupport; 070 071 @Environmental 072 private TrackableComponentEventCallback eventCallback; 073 074 @Inject 075 private DeprecationWarning deprecationWarning; 076 077 /** 078 * Name of a function on the client-side Tapestry.ElementEffect object that 079 * is invoked after the elements's body 080 * content has been updated. If not specified, then the basic "highlight" 081 * method is used, which performs a classic 082 * "yellow fade" to indicate to the user that and update has taken place. 083 * 084 * @deprecated Deprecated in 5.4 with no replacement. 085 */ 086 @Parameter(defaultPrefix = BindingConstants.LITERAL) 087 private String update; 088 089 void pageLoaded() { 090 deprecationWarning.ignoredComponentParameters(resources, "update"); 091 } 092 093 Block beginRender(MarkupWriter writer) 094 { 095 String clientId = jsSupport.allocateClientId(resources); 096 String elementName = resources.getElementName("div"); 097 098 writer.element(elementName, "id", clientId, "data-container-type", "zone"); 099 resources.renderInformalParameters(writer); 100 101 Link link = resources.createEventLink(EventConstants.ACTION, context); 102 103 jsSupport.require("t5/core/zone").invoke("deferredZoneUpdate").with(clientId, link.toURI()); 104 105 // Return the placeholder for the full content. That will render instead of the main body 106 // of the component. 107 return initial; 108 } 109 110 Object onAction(EventContext context) throws IOException 111 { 112 resources.triggerContextEvent(EventConstants.PROGRESSIVE_DISPLAY, context, eventCallback); 113 114 if (eventCallback.isAborted()) 115 return null; 116 117 return getBody(); 118 } 119 120 boolean beforeRenderBody() 121 { 122 return false; 123 } 124 125 void afterRender(MarkupWriter writer) 126 { 127 writer.end(); 128 } 129 130 /** 131 * Returns the body of the ProgressiveDisplay, which is sometimes (in the 132 * context of a 133 * {@linkplain org.apache.tapestry5.services.ajax.AjaxResponseRenderer#addRender(org.apache.tapestry5.ClientBodyElement)} partial page render}) 134 * the content to be included. 135 * 136 * @return body of component 137 * @since 5.2.0 138 */ 139 public Block getBody() 140 { 141 return resources.getBody(); 142 } 143}