Usage:
<input type=”text” t:type=”textField” value=”myValue” t:mixins=”zoneUpdater” zone=”searchResultZone” event=”performSearch” clientEvent=”onkeyup”/>
Then all you have to do is providing a listener method for the performSearch-event in your component/page class.
There is some room for improvement here in terms of more flexibility on event link context and other things. But it works.
There might be improvements in the Tapestry js library to make it easier to obtain and trigger zones. This code was developed with T 5.0.18.
ZoneUpdater.java
@IncludeJavaScriptLibrary("ZoneUpdater.js")
public class ZoneUpdater {
public static final String PLACEHOLDER = "XXX";
@Inject
private ComponentResources resources;
@Environmental
private RenderSupport renderSupport;
@Parameter(defaultPrefix = BindingConstants.LITERAL)
private String clientEvent;
@Parameter(defaultPrefix = BindingConstants.LITERAL, required = true)
private String event;
@InjectContainer
private ClientElement element;
@Parameter
private Object[] context;
@Parameter(defaultPrefix = BindingConstants.LITERAL)
// To enable popups to fire events on this document, enter "document" here.
private String listeningElement;
@Parameter(defaultPrefix = BindingConstants.LITERAL, required = true)
private String zone;
protected Link createLink(Object[] context) {
if (context == null) {
context = new Object[1];
}
context = ArrayUtils.add(context, PLACEHOLDER); // To be replaced by javascript
return resources.createEventLink(event, context);
}
void afterRender() {
String link = createLink(context).toAbsoluteURI();
String elementId = element.getClientId();
if (clientEvent == null) {
clientEvent = event;
}
if (listeningElement == null) {
listeningElement = "$('" + elementId + "')";
}
renderSupport.addScript("new ZoneUpdater('%s', %s, '%s', '%s', '%s', '%s')", elementId, listeningElement, clientEvent, link, zone, PLACEHOLDER);
}
}
ZoneUpdater.js
var ZoneUpdater = Class.create();
ZoneUpdater.prototype = {
initialize: function(zoneElementId, listeningElement, event, link, zone, placeholder) {
this.zoneElement = $(zoneElementId);
this.event = event;
this.link = link;
this.placeholder = placeholder;
$T(this.zoneElement).zoneId = zone;
listeningElement.observe(this.event, this.updateZone.bindAsEventListener(this));
},
updateZone: function(event) {
var zoneObject = Tapestry.findZoneManager(this.zoneElement);
if ( !zoneObject ) return;
var param;
if (this.zoneElement.value) {
param = this.zoneElement.value;
}
if (!param) param = ' ';
param = this.encodeForUrl(param);
var updatedLink = this.link.gsub(this.placeholder, param);
zoneObject.updateFromURL(updatedLink);
},
encodeForUrl: function(string) {
/**
* See equanda.js for updated version of this
*/
string = string.replace(/\r\n/g,"\n");
var res = "";
for (var n = 0; n < string.length; n++)
{
var c = string.charCodeAt( n );
if ( '$' == string.charAt( n ) )
{
res += '$$';
}
else if ( this.inRange( c, "AZ" ) || this.inRange( c, "az" ) || this.inRange( c, "09" ) || this.inRange( c, ".." ) )
{
res += string.charAt( n )
}
else
{
var tmp = c.toString(16);
while ( tmp.length < 4 ) tmp = "0" + tmp;
res += '$' + tmp;
}
}
return res;
},
inRange: function(code, range) {
return code >= range.charCodeAt( 0 ) && code <= range.charCodeAt( 1 );
}
}