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