A few more days, a few more bugs discovered. Specifically, I wasn't
uncovering controls if client side validation failed. Here's a patch to
my earlier code that takes care of this (inspired by AjaxStatus)
in the script files:
<body>
<unique>
dojo.require("dojo.event.common");
dojo.require("tapestry.form");
dojo.require("tapestry.form.validation");
dojo.event.connectOnce(tapestry.form.validation,
"summarizeErrors", clearOverlays);
</unique>
</body>
modified js file contents:
var coverings = []
function clearOverlays() {
for (var index in coverings) {
var covering = coverings[index]
covering.parentNode.removeChild(covering)
}
coverings = []
}
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"
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)
coverings.push(covering)
}
I also ripped out the offsetLeft hack because that didn't really fix my
IE problems. I think it just didn't like being applied in a float=right
div there.
Steve Shucker wrote:
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]