Tuesday, October 20, 2009

Link with confirmation

 

This is  a component that adds confirmation to a regular EventLink. It does this by using the TapestryExt.js library introduced in my previous post to trigger a link after intercepting and cancelling it first. It works both with and without zones.

It is used excactly like an EventLink, with an additional “message” parameter, to display in confirmation box.

For now, I only implemented a standard javascript confirm box. But it shouldn’t be too hard extending this with more fancy interaction with DHTML.

I’m not completely comfortable with the techniques used here. Some of it looks a lot like a hack in my opinion, especially the part about intercepting/cancelling a zone listener and re-adding it afterwards using copy-paste from tapestry.js.

ConfirmLink.java:

/**
 * Displays a javascript confirmation box before actually triggering the link.
 * 
 * @author Inge
 *
 */
@IncludeJavaScriptLibrary({"TapestryExt.js, "ConfirmLink.js"})
public class ConfirmLink implements ClientElement {    
  @Environmental
  private RenderSupport renderSupport;  
  
  @Parameter("literal:Do you really want to delete?")
  private String message;
  @Component(publishParameters="event,zone,context", inheritInformalParameters=true)
  private EventLink confirmLink;
  
  void afterRender() {
    String url = confirmLink.getLink().toRedirectURI();
    renderSupport.addScript("new ConfirmLink('%s', '%s', '%s')", confirmLink.getClientId(), url, message);
  }
  
  public String getClientId() {
    return confirmLink.getClientId();
  }
}

 



ConfirmLink.js



var ConfirmLink = Class.create({
  initialize: function(element, url, message) {
    this.element = $(element);
    this.url = url;
    this.message = message;
    this.initListeners = this.initListeners.bind(this);
    this.initListeners.defer();
    // Makes it run after Tapestry:init to be able to delete
    // zone listener added by Tapestry and start listening for
    // our modded version instead.    
  },
  onclick: function(event) {
    Event.stop(event);
    if (confirm(this.message)) {
      TapestryExt.triggerLink(this.element, this.url);
    }
  },
  initListeners: function() {
    this.element.stopObserving('click'); // Remove zone update, will be re-added later by TapestryExt.js.
    this.element.observe('click', this.onclick.bindAsEventListener(this));
  }
});

Friday, October 16, 2009

Missing javascript

I think there are some important things missing from Tapestry.js to release the full potential of Tapetsry 5 and AJAX. I have started working on a javascript class, TapestryExt, that extends the functionality of Tapestry.js.

My wish is to see all of this and more built in to tapestry.

 

/**
 * Commonly needed functions that are absent in the default Tapestry js lib.
 */
var TapestryExt = {
  /**
   * If the specified form listens for the Tapestry.FORM_PROCESS_SUBMIT_EVENT event
   * (all forms with a zone specified do), it will AJAX-submit and update its zone after.
   */
  submitZoneForm : function(element) {    
    element = $(element)
    if (!element) {
      Tapestry.error('Could not find form to trigger AJAX submit on');
      return;
    }
    element.fire(Tapestry.FORM_PROCESS_SUBMIT_EVENT);
  },
  /**
   * Trigger any link, zone or not. 
   * 
   * If no url is provided, the href attribute of element will be used.
   */
  triggerLink : function(element, url) {
    element = $(element);
    if (!url) {
      url = element.href;
    }    
    if (!url) {
      Tapestry.error('Unable to find url to trigger on element ' + element.id);
    }
    var zoneObject = Tapestry.findZoneManager(element);
    if (zoneObject) {    
      zoneObject.updateFromURL(url);
    }
    else {
      // Regular link
      // Note: this will skip all event observers on this link!
      window.location.href = url;
    }
  }  
}