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]

Reply via email to