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