Created

Embed URL

HTTPS clone URL

SSH clone URL

You can clone with HTTPS or SSH.

Download Gist

XForms action in XML syntax and with tentative CoffeeScript syntax

View CoffeeScript with jQuery.coffee
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
instance = model.instances['fr-persistence-instance']
resources = x.models['fr-resources-model'].vars['$fr-fr-resources']
 
$('error', instance).replaceWith event.response-body
$('is-error', instance).replaceWith 'true'
 
x.message 'Error with submission: ' + event.submission-id, 'xxf:log-debug'
x.message event.response-body, 'xxf:log-debug'
 
switch event['error-type']
when 'validation-error'
$('message', instance).replaceWith $('detail messages form-validation-error', resources)
$('#fr-message-validation-error').toggle()
model.dispatch 'fr-visit-alerts'
x.models['fr-sections-model'].dispatch 'fr-expand-all'
when 'xxforms-pending-uploads'
x.message resources.detail.messages['upload-in-progress']
else
$('message', instance).replaceWith $('detail messages database-error', resources)
$('#fr-message-fatal-error').toggle()
View CoffeeScript with jQuery.coffee
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
instance = model.instances['fr-persistence-instance']
resources = x.models['fr-resources-model'].vars['$fr-fr-resources']
 
instance.error = event.response-body
instance['is-error'] = 'true'
 
x.message 'Error with submission: ' + event.submission-id, 'xxf:log-debug'
x.message event.response-body, 'xxf:log-debug'
 
switch event['error-type']
when 'validation-error'
instance.message = resources.detail.messages.form-validation-error
x.toggle 'fr-message-validation-error'
model.dispatch 'fr-visit-alerts'
x.models['fr-sections-model'].dispatch 'fr-expand-all'
when 'xxforms-pending-uploads'
x.message resources.detail.messages['upload-in-progress']
else
instance.message = resources.detail.messages.database-error
x.toggle 'fr-message-fatal-error'
View CoffeeScript with jQuery.coffee
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
val instance = model.instances("fr-persistence-instance")
val resources = models("fr-resources-model").vars("$fr-fr-resources")
 
instance \ "error" setvalue event.responseBody
instance \ "is-error" setvalue "true"
 
message("Error with submission: " + event.submissionId, "xxf:log-debug")
message(event("response-body"), "xxf:log-debug")
 
event("error-type") match {
case "validation-error" =>
instance \ "message" setvalue (resources \ "detail" \ "messages" \ "form-validation-error")
toggle("fr-message-validation-error")
model.dispatch("fr-visit-alerts")
models("fr-sections-model").dispatch("fr-expand-all")
case "xxforms-pending-uploads" =>
message(resources \ "detail" \ "messages" \ "upload-in-progress")
case _ =>
instance \ "message" setvalue (resources \ "detail" \ "messages" \ "database-error")
toggle("fr-message-fatal-error")
}
View CoffeeScript with jQuery.coffee
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29
<xf:action ev:event="fr-submit-error">
<!-- Remember there was an error -->
<xf:setvalue ref="instance('fr-persistence-instance')/error" value="event('response-body')"/>
<xf:setvalue ref="instance('fr-persistence-instance')/is-error">true</xf:setvalue>
<!-- Log error -->
<xf:message level="xxf:log-debug">Error with submission: <xf:output value="event('submission-id')"/></xf:message>
<xf:message level="xxf:log-debug"><xf:output value="event('response-body')"/></xf:message>
 
<!-- case validation-error => set error message and show validation error section in UI -->
<xf:action if="event('error-type') = 'validation-error'">
<xf:setvalue ref="instance('fr-persistence-instance')/message" value="$fr-fr-resources/detail/messages/form-validation-error"/>
<xf:toggle case="fr-message-validation-error"/>
<!-- Mark all active alerts as visited -->
<xf:dispatch name="fr-visit-alerts" target="fr-persistence-model"/>
<!-- Open all sections -->
<xf:dispatch name="fr-expand-all" target="fr-sections-model"/>
</xf:action>
 
<!-- case xxforms-pending-uploads => display a modal message -->
<xf:action if="event('error-type') = 'xxforms-pending-uploads'">
<xf:message model="fr-resources-model" value="$fr-fr-resources/detail/messages/upload-in-progress"/>
</xf:action>
 
<!-- case _ => set error message and show fatal error section in UI -->
<xf:action if="not(event('error-type') = ('validation-error', 'xxforms-pending-uploads'))">
<xf:setvalue ref="instance('fr-persistence-instance')/message" value="$fr-fr-resources/detail/messages/database-error"/>
<xf:toggle case="fr-message-fatal-error"/>
</xf:action>
</xf:action>
View CoffeeScript with jQuery.coffee
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28
let $instance := xf:instance('fr-persistence-instance')
let $resources := xf:model('fr-resources-model', 'fr-fr-resources')
let $messages := $resources/detail/messages
return
(
replace value of node $instance/error with xf:event('response-body'),
replace value of node $instance/is-error with 'true',
 
xf:message(
('Error with submission: ', xf:event('submission-id'), 'xxf:log-debug')
'xxf:log-debug'),
xf:message(xf:event('response-body'), 'xxf:log-debug'),
 
switch ( xf:event('error-type') )
case 'validation-error' return (
replace value of node $instance/message with $messages/form-validation-error,
xf:toggle('fr-message-validation-error'),
xf:dispatch('fr-visit-alerts', xf:model('fr-persistence-model')),
xf:dispatch('fr-expand-all', xf:model('fr-sections-model'))
)
case 'xxforms-pending-uploads' return (
xf:message($messages/upload-in-progress)
)
default return (
replace value of node $instance/message with $messages/form-validation-error,
xf:toggle('fr-message-fatal-error')
)
)
Owner

The idea here is to explore how one can rewrite complex actions written with the XForms action syntax into a more lightweight notation, here CoffeeScript.

The original example is taken from an actual action in Form Runner. It is just one example of a non-trivial action (and there are way more complex ones in Form Runner!).

The API is very tentative. Ideas include:

  • expose an object-oriented JavaScript API
  • provide native XML navigation into XML data, for example through E4X (JavaScript) or at least simple "dot" notation

The runat attribute is useful only for server-side implementations, to differentiate between scripts that must run on the client.

Comments welcome.

Being more jQuery-like, for things that have ids (controls, instances, models…), you could imagine, instead of:

x.toggle "fr-message-validation-error"

To write:

$("#fr-message-validation-error").toggle()
Owner

That that would be an option. I see two distinct uses:

  • XForms objects such as controls, models, binds (jQuery-like, as we might not actually have a DOM to work on)
  • instance data (actual jQuery)

For access to instance data, there are several options:

  • XPath API
  • jQuery
  • E4X or E4X-like
  • DOM (don't need to use this directly, except if it's as basis for jQuery)
Owner

I added an attempt at using jQuery syntax for both accessing controls and data.

The following:

$('error', instance).replaceWith event.response-body

Feels like it perverts the jQuery interface. In jQuery, if something has an id, you'd expect to be able to use $("#id"), not $("id", collection). Also, maybe it is just fine to say xforms.instances["invoice"], which looks similar to document.forms["some-form"]. In some cases, this will allow one to write xforms.instances.invoice, which is syntactically lighter.

Owner

Mmh, $('error', instance) means selecting an element called error in the document instance. It's the same as instance('instance')//error.

Ah, yes, in that case I agree. I incorrectly assumed $('error', instance) meant instance('error') instead of instance('instance')//error.

Shouldn't this:

model.dispatch 'fr-visit-alerts'

actually be this instead?:

x.models['fr-persistence-model'].dispatch 'fr-visit-alerts'

In response to http://twitter.com/ebruchez/status/30046769760964608 . I thought more about integrating XForms within XQuery or the other way around, instead of replicating the XForms features in another language. But I guess something like the following would do (you know, more or less):

See file

Owner

I think model.dispatch 'fr-visit-alerts' is right: model is implicitly pointing to the fr-persistence-model model. The idea was to have some JS objects automatically scoped for convenience, and model would tentatively one of them.

Owner

@fgeorges Thanks for the XQuery example. It looks similar enough to the JS and CS examples. I put it up as a file a the top (not sure how I can allow others to edit/add files?).

@ebruchez You're saying that model could be automatically bound to an object representing the current model?

Owner

@avernet Yes, as if the enclosing xf:action passed it as a function parameter.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Something went wrong with that request. Please try again.