I'm a bit nutty about writing clean code, and I didn't want to clutter
things up with binding events left and right or extra script tags for
each handled async submit. I ended up just subclassing Submit and
LinkSubmit to include my own tweaks. This code injects a <div> as the
first element of each of the updateComponents. It's an 80% opaque block
with a small animated loading icon. When the ajax call is complete, the
whole component gets overwritten so my progress <div> vanishes. The
<div> also prevents clicking on anything underneath it. The ugly bit to
figure out how to set the "left" css attribute of the <div> can probably
be omitted - it fixes a weird layout issue that's probably unique to one
of my pages and IE6. It works 95% of the time without setting "left"
But you asked for code, so I'll give you code:
SubmitBindings.script:
extra include:
<include-script resource-path="/com/vms/infrastructure/scripts/util.js"/>
in the submit handling function:
<foreach key="component" expression="submit.updateComponents">
cover('${component}', '${submit.loadingImageUrl}')
</foreach>
util.js contains the following script:
function cover(componentId, imgPath) {
var component = document.getElementById(componentId)
var covering = document.createElement("div")
covering.style.width = component.clientWidth + "px"
covering.style.height = component.clientHeight + "px"
covering.style.zIndex = 1200
covering.style.position = "absolute"
covering.style.backgroundColor = "white"
covering.style.opacity = "0.8"
covering.style.filter = "alpha(opacity=80)"
covering.style.overflow = "hidden"
// RF: workaround for IE lying about offsetLeft and bad positioning
var nextParent = component
var left = component.offsetLeft
while (nextParent = nextParent.parentNode) {
if (nextParent.offsetLeft &&
nextParent.getAttribute("suppressOffset") != "true") {
left += nextParent.offsetLeft
}
}
covering.style.left = left
var img = document.createElement('img')
img.src = imgPath
img.style.width = "16px"
img.style.height = "16px"
img.style.margin = "8px"
covering.appendChild(img)
component.insertBefore(covering,component.firstChild)
}
My subclass of LinkSubmit:
@ComponentClass(allowBody = true, allowInformalParameters = true,
reservedParameters = "name,href")
public abstract class ShadyLinkSubmit extends AnnotatedLinkSubmit {
@InjectScript("ShadyLinkSubmitBindings.script")
public abstract IScript getSubmitScript();
@Asset("classpath:/com/vms/infrastructure/images/loading.gif")
public abstract IAsset getLoadingImage();
public String getLoadingImageUrl() {
return getLoadingImage().buildURL();
}
@SuppressWarnings("unchecked")
protected void renderFormComponent(IMarkupWriter writer,
IRequestCycle cycle) {
boolean disabled = isDisabled();
IForm form = getForm();
String type = getSubmitType();
Defense.notNull(type, "submitType");
List update = getUpdateComponents();
boolean isAsync = isAsync() || update != null && update.size() > 0;
if (!disabled) {
writer.begin("a");
String js = "tapestry.form." + type + "('" +
form.getClientId() + "', '" + getName() + "'";
if (isAsync) {
JSONObject json = new JSONObject();
json.put(new JSONLiteral("async"), Boolean.TRUE);
json.put(new JSONLiteral("json"), isJson());
DirectServiceParameter dsp = new
DirectServiceParameter(form, null, this);
json.put(new JSONLiteral("url"), new
JSONLiteral("this.href"));
StringBuffer coverCalls = new StringBuffer();
String imageUrl = getLoadingImageUrl();
for (String updateComponent : (List<String>)update) {
coverCalls.append("cover('").append(updateComponent).append("',
'").append(imageUrl).append("');");
}
writer.attribute("href",
getDirectService().getLink(true, dsp).getURL());
writer.attribute("onClick", js + "," + json.toString() +
"); " + coverCalls.toString() + "return false;");
} else {
writer.attribute("href", "javascript:" + js + ");");
}
renderIdAttribute(writer, cycle);
renderInformalParameters(writer, cycle);
}
renderBody(writer, cycle);
if (!disabled) {
writer.end();
}
PageRenderSupport prs =
TapestryUtils.getPageRenderSupport(cycle, this);
getSubmitScript().execute(this, cycle, prs, Collections.EMPTY_MAP);
}
}
the script there just has the include line for my util.js
Here's my Submit subclass:
@ComponentClass(allowBody = false, allowInformalParameters = true,
reservedParameters = "name,type,defer")
public abstract class ShadySubmit extends AnnotatedSubmit {
@InjectScript("ShadySubmitBindings.script")
public abstract IScript getSubmitScript();
@Asset("classpath:/com/vms/infrastructure/images/loading.gif")
public abstract IAsset getLoadingImage();
public String getLoadingImageUrl() {
return getLoadingImage().buildURL();
}
}
The Annotated(Link)Submit classes that I'm subclassing are trivial
subclasses that inject the binding via annotations instead of *.jwc files.
Thanks for pointing out that AjaxStatus component - I'd never seen it
before.
-Steve
Andreas Andreou wrote:
Hi,
so, SubmitBindings.script actually calls tapestry.form.submit
and/or tapestry.form.refresh, tapestry.form.cancel
so, why not just connect around those and do whetever you want?
You can completely bypass them, or just have your code run before or
after those...
BTW, I remember someone doing something similar some time ago using
http://tapestry.apache.org/tapestry4.1/tapestry-contrib/componentreference/ajaxstatus.html
and overlaying on top of everything... i would be interested in
finding out more about
your implementation, esp. some code :)
On Dec 3, 2007 11:30 PM, Steve Shucker <[EMAIL PROTECTED]> wrote:
Is it possible to globally replace the SubmitBindings.script file used
by all the AbstractSubmit subclasses to wire up ajax events with my own
version? I've got a script that imposes an overlay on top of the
components being updated and prevents double-clicks. Right now, I can
wire it up to each individual button with a @Script, but it would be
cleaner if I could just replace the asset where the submit script is
wired. That way it would be automatically applied to all ajax submits.
I'd like to do this without hacking up my tapestry jar.
It might be nice to disable or unwire non-ajax submit buttons when
they're clicked as well, but I haven't tried implementing that yet.
-Steve
---------------------------------------------------------------------
To unsubscribe, e-mail: [EMAIL PROTECTED]
For additional commands, e-mail: [EMAIL PROTECTED]
---------------------------------------------------------------------
To unsubscribe, e-mail: [EMAIL PROTECTED]
For additional commands, e-mail: [EMAIL PROTECTED]