提交 4c834413 编写于 作者: K Kohsuke Kawaguchi

Generalized the lazy rendering of a fragment to <l:renderOnDemand> tag.

上级 134bf304
......@@ -71,6 +71,7 @@ import hudson.util.Secret;
import hudson.views.MyViewsTabBar;
import hudson.views.ViewsTabBar;
import hudson.widgets.HeteroListConfigPageRenderer;
import hudson.widgets.RenderOnDemandClosure;
import org.acegisecurity.providers.anonymous.AnonymousAuthenticationToken;
import org.apache.commons.jelly.JellyContext;
import org.apache.commons.jelly.JellyTagException;
......@@ -1304,7 +1305,7 @@ public class Functions {
return Boolean.getBoolean("hudson.security.ArtifactsPermission");
}
public static String createHeteroListConfigPageRendererProxy(Object it) {
return Stapler.getCurrentRequest().createJavaScriptProxy(new HeteroListConfigPageRenderer(it));
public static String createRenderOnDemandProxy(JellyContext context, String attributesToCapture) {
return Stapler.getCurrentRequest().createJavaScriptProxy(new RenderOnDemandClosure(context,attributesToCapture));
}
}
......@@ -23,39 +23,60 @@
*/
package hudson.widgets;
import hudson.model.AbstractProject;
import hudson.model.Descriptor;
import hudson.model.Hudson;
import org.kohsuke.stapler.ForwardToView;
import hudson.Util;
import hudson.util.IOException2;
import hudson.util.PackedMap;
import org.apache.commons.jelly.JellyContext;
import org.apache.commons.jelly.JellyTagException;
import org.apache.commons.jelly.Script;
import org.kohsuke.stapler.HttpResponse;
import org.kohsuke.stapler.HttpResponses;
import org.kohsuke.stapler.StaplerRequest;
import org.kohsuke.stapler.StaplerResponse;
import org.kohsuke.stapler.bind.JavaScriptMethod;
import org.kohsuke.stapler.jelly.DefaultScriptInvoker;
import javax.servlet.ServletException;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
/**
* Assists the lazy rendering of the configuration fragments from descriptor,
* by remembering the "it" object that points to the overall configured target
* (like {@link AbstractProject}).
*
* <p>
* See <tt>hetero-list.jelly</tt>
* Captured Jelly {@link Script} that can be rendered later on demand from JavaScript.
*
* @author Kohsuke Kawaguchi
* @since 1.402
*/
public class HeteroListConfigPageRenderer {
public final Object it;
public class RenderOnDemandClosure {
private final Script body;
private final Map<String,Object> variables;
public RenderOnDemandClosure(JellyContext context, String attributesToCapture) {
body = (Script) context.getVariable("org.apache.commons.jelly.body");
public HeteroListConfigPageRenderer(Object it) {
this.it = it;
Map<String,Object> variables = new HashMap<String, Object>();
for (String v : Util.fixNull(attributesToCapture).split(","))
variables.put(v,context.getVariable(v));
this.variables = PackedMap.of(variables);
}
/**
* Renders a configuration fragment.
* Renders the captured fragment.
*/
@JavaScriptMethod
public HttpResponse renderConfigPage(String id) {
Descriptor d = Hudson.getInstance().getDescriptor(id);
if (d==null) return HttpResponses.notFound();
return new ForwardToView(this,"render.jelly").with("target",it).with("descriptor",d);
public HttpResponse render() {
return new HttpResponse() {
public void generateResponse(StaplerRequest req, StaplerResponse rsp, Object node) throws IOException, ServletException {
try {
new DefaultScriptInvoker() {
@Override
protected void exportVariables(StaplerRequest req, StaplerResponse rsp, Script script, Object it, JellyContext context) {
super.exportVariables(req, rsp, script, it, context);
context.setVariables(variables);
}
}.invokeScript(req,rsp,body,null);
} catch (JellyTagException e) {
throw new IOException2("Failed to evaluate the template closure",e);
}
}
};
}
}
<!--
The MIT License
Copyright (c) 2004-2010, Sun Microsystems, Inc., Kohsuke Kawaguchi
Copyright (c) 2004-2010, Sun Microsystems, Inc., Kohsuke Kawaguchi, CloudBees, Inc.
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
......@@ -103,14 +103,17 @@ THE SOFTWARE.
<div class="repeatable-insertion-point" />
<div class="prototypes to-be-removed" proxy="${h.createHeteroListConfigPageRendererProxy(it)}">
<div class="prototypes to-be-removed">
<!-- render one prototype for each type -->
<j:set var="instance" value="${null}" />
<j:forEach var="descriptor" items="${attrs.descriptors}" varStatus="loop">
<div name="${attrs.name}" title="${descriptor.displayName}" tooltip="${descriptor.tooltip}" descriptorId="${descriptor.id}">
<local:body deleteCaption="${attrs.deleteCaption}">
<!-- marker for JavaScript to insert the actual fragment -->
<tr class="config-page"/>
<l:renderOnDemand tag="tr" clazz="config-page" capture="descriptor,it">
<l:ajax>
<st:include from="${descriptor}" page="${descriptor.configPage}" optional="true" />
</l:ajax>
</l:renderOnDemand>
</local:body>
</div>
</j:forEach>
......
......@@ -21,14 +21,22 @@ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
-->
<j:jelly xmlns:j="jelly:core" xmlns:st="jelly:stapler" xmlns:d="jelly:define" xmlns:l="/lib/layout" xmlns:t="/lib/hudson" xmlns:f="/lib/form" xmlns:x="jelly:xml">
<st:documentation>
<st:attribute name="tag">
Place holder HTML tag. By default it's DIV, but depending on where this is used,
you might need other tags (e.g., inside a table.)
</st:attribute>
<st:attribute name="clazz">
Additional CSS class names, so that you can discover this tag more easily from your JavaScript.
</st:attribute>
<st:attribute name="capture">
','-separated list of variables to capture and make available when later evaluating the body.
</st:attribute>
</st:documentation>
<!--
Render build histories.
-->
<j:jelly xmlns:j="jelly:core" xmlns:st="jelly:stapler" xmlns:d="jelly:define" xmlns:l="/lib/layout" xmlns:t="/lib/hudson" xmlns:f="/lib/form" xmlns:i="jelly:fmt">
<l:ajax>
<!-- 'it' gets overridden when we call Jelly, so pass the real 'it' as 'target' -->
<j:set var="it" value="${target}" />
<st:include page="${descriptor.configPage}" from="${descriptor}" optional="true"/>
</l:ajax>
<x:element name="${attrs.tag?:'div'}">
<x:attribute name="class">render-on-demand ${attrs.clazz}</x:attribute>
<x:attribute name="proxy">${h.createRenderOnDemandProxy(context,attrs.capture)}</x:attribute>
</x:element>
</j:jelly>
\ No newline at end of file
......@@ -421,6 +421,25 @@ function isInsideRemovable(e) {
return Element.ancestors(e).find(function(f){return f.hasClassName("to-be-removed");});
}
/**
* Render the template captured by &lt;l:renderOnDemand> at the element 'e' and replace 'e' by the content.
*
* @param {HTMLElement} e
* The place holder element to be lazy-rendered.
* @param {boolean} noBehaviour
* if specified, skip the application of behaviour rule.
*/
function renderOnDemand(e,callback,noBehaviour) {
if (!e) return;
var proxy = eval(e.getAttribute("proxy"));
proxy.render(function (t) {
Element.replace(e, t.responseText);
if (callback) callback(t);
noBehaviour || Behaviour.applySubtree(e);
});
}
var hudsonRules = {
"BODY" : function() {
tooltip = new YAHOO.widget.Tooltip("tt", {context:[], zindex:999});
......@@ -443,8 +462,6 @@ var hudsonRules = {
prototypes = prototypes.previousSibling;
var insertionPoint = prototypes.previousSibling; // this is where the new item is inserted.
var proxy = eval(prototypes.getAttribute("proxy")); // JavaScript proxy to HeteroListConfigPageRenderer
// extract templates
var templates = []; var i=0;
for(var n=prototypes.firstChild;n!=null;n=n.nextSibling,i++) {
......@@ -467,15 +484,13 @@ var hudsonRules = {
nc.setAttribute("name",t.name);
nc.innerHTML = t.html;
proxy.renderConfigPage(t.descriptorId, function (t) {
Element.replace(findElementsBySelector(nc,"TR.config-page")[0],t.responseText);
renderOnDemand(findElementsBySelector(nc,"TR.config-page")[0],function() {
insertionPoint.parentNode.insertBefore(nc, insertionPoint);
if(withDragDrop) prepareDD(nc);
hudsonRules['DIV.repeated-chunk'](nc); // applySubtree doesn't get nc itself
Behaviour.applySubtree(nc);
});
},true);
});
menuButton.getMenu().renderEvent.subscribe(function(type,args,value) {
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册