orbeon / orbeon-forms

Orbeon Forms is an open source web forms solution. It includes an XForms engine, the Form Builder web-based form editor, and the Form Runner runtime.
http://www.orbeon.com/
GNU Lesser General Public License v2.1
514 stars 220 forks source link

Embedding: support multiple forms per page #1854

Open ebruchez opened 10 years ago

ebruchez commented 10 years ago

This doesn't work fully yet. Examples:

See #1808.

ebruchez commented 10 years ago

The embedding API now only namespace resources it knows require URL rewriting:

JS files, in particular, are not namespaces. There can be two or more references to a JS file such as:

/orbeon/o/xforms-server/4.x.y.z/orbeon-076541a93fd0f3847fdd9f9aa40b6949c1b3d8ef.js

However, the proxy portlet should ensure there is only a single reference, if possible at all, for performance reasons.

avernet commented 6 years ago

+1 from user

ebruchez commented 6 years ago

+1 from evaluator

avernet commented 5 years ago

+1 from evaluator

ebruchez commented 2 years ago

+1 from customer

ebruchez commented 2 years ago

Using the JavaScript API, I can sometimes load two forms in "new" mode, depending on the forms, but in some cases only one shows, and if both show the second one doesn't work.

ebruchez commented 2 years ago

With the JavaScript API, one issue is that ids are not namespaced. We retrieve the HTML for the form using ?orbeon-embeddable=true and that's it. We do not perform any rewriting on the resulting source.

In order to namespace ids, we need some kind of rewriting done. We are able to do this with the Java embedding API, and we should be able to do so as well with the JavaScript embedding API.

In fact, we had an issue where, based on the Orbeon-Client header, we would run the WSRPURLRewriter. This would now be a feature, not a bug!

The JavaScript embedding API implementation would then have to pass the HTML through the rewriting logic, at least to rewrite ids, which would be fairly easy to do.

ebruchez commented 2 years ago
ebruchez commented 2 years ago

With the Java embedding API, the server-side has:

The remote Form Runner encodes the HTML with WSRP markers so that the Java API implementation can rewrite ids and URLs based on the current application's paths, etc.

Resources are proxied because they have to, since Form Runner can be remote and not directly accessible from the client.

The /dynamic/ JavaScript is rewritten because it contains ids. Maybe we can change this so that the initialization code handles that?

The requests for CSS from Form Runner do support an ns= URL parameter, however the Java embedding API does not make use of this because we don't add a namespace right now with the the Java embedding API. I thought we did. But, probably, the rationale was that we only support one form so namespacing is not needed.

ebruchez commented 2 years ago

Here is an example of Initializations coming in:

Initializations(
   "46fda591b318c489d0ceed0b1d3fbee3b1c6c578",
   "wsrp_rewrite_xforms-form",
   "wsrp_rewrite_fr-language-selector-select≡xf-534,wsrp_rewrite_xf-309,wsrp_rewrite_error-summary-control-bottom≡er,wsrp_rewrite_xf-460,wsrp_rewrite_xf-492",
   "wsrp_rewrite_fr-language-selector-select≡xf-534 1,wsrp_rewrite_xf-309 0,wsrp_rewrite_error-summary-control-bottom≡er 0,wsrp_rewrite_xf-460 1,wsrp_rewrite_xf-492 0",
   "wsrp_rewrite?wsrp-urlType=resource&wsrp-navigationalState=orbeon.path%3D%252Fxforms-server/wsrp_rewrite",
   Some(
     "wsrp_rewrite?wsrp-urlType=blockingAction&wsrp-navigationalState=orbeon.path%3D%252Fxforms-server-submit/wsrp_rewrite"
   ),
   Some(
     "wsrp_rewrite?wsrp-urlType=resource&wsrp-navigationalState=orbeon.path%3D%252Fxforms-server-submit/wsrp_rewrite"
   ),
   "wsrp_rewrite?wsrp-urlType=resource&wsrp-navigationalState=orbeon.path%3D%252Fxforms-server%252Fupload/wsrp_rewrite",
   List(
     Control("wsrp_rewrite_fr-lease-renew-dialog≡dialog", None),
     Control("wsrp_rewrite_xf-466≡xf-873⊙5", None),
     Control("wsrp_rewrite_xf-466≡xf-873⊙6", None),
     Control("wsrp_rewrite_fr-clear-confirm-dialog", None),
     Control("wsrp_rewrite_fr-submission-result-dialog", None),
     Control("wsrp_rewrite_fr-validation-dialog", None),
     Control("wsrp_rewrite_fr-error-dialog≡dialog", None),
     Control("wsrp_rewrite_fr-confirmation-dialog≡dialog", None)
   ),
   List(),
   None,
   List(
     UserScript(
       "xf_959b6f3a16cd71061bfc49284e80bbd054596880",
       "wsrp_rewrite_fr-data-safe",
       "wsrp_rewrite_fr-view",
       List("46fda591b318c489d0ceed0b1d3fbee3b1c6c578", "true")
     ),
     UserScript(
       "xf_959b6f3a16cd71061bfc49284e80bbd054596880",
       "wsrp_rewrite_fr-warn-when-data-unsafe",
       "wsrp_rewrite_fr-view",
       List("46fda591b318c489d0ceed0b1d3fbee3b1c6c578", "true")
     )
   )
 )

And also:

function xformsPageLoadedServer() {
    ORBEON.xforms.Controls.setFocus("wsrp_rewrite_contact-section≡grid-1-grid≡first-name-control");
}
ebruchez commented 2 years ago

xformsPageLoadedServer() must be handled through Initializations too!

Right now, we load the /dynamic/ JavaScript by inserting a <script> element in the <head> and pointing the src to the resource. This means that we don't have a chance to modify the content of the script to rewrite ids. It's unclear whether we could change that to rewrite the content and create an inline script.

Possibilities:

  1. Somehow pass the namespace to initializeFormWithInitData(). However, this is a "callback" from an anonymous function which completes when that script is loaded, so I am not sure we have an opportunity to do that cleanly.
  2. Load the script with a ns= URL parameter, so that if the parameter is present, the replacements are done on the server. For a portlet, the URL parameter would be omitted, and the replacement would still be done within the portlet, as we have URLs to create.
  3. Same as 2 but the ns would then be passed to the initializeFormWithInitData() callback.
ebruchez commented 2 years ago

For solution 3 to work, we need to pass everything to initializeFormWithInitData(), including xformsPageLoadedServer() and opsXFormsProperties.

Then the wrapping function and call can be done separately, so we can pass the ns to it:

s"""(function(){ORBEON.xforms.InitSupport.initializeFormWithInitData(${quoteString(jsonString)})}).call(this);"""

On the client, we can do the WSRP replacement iif the ns is passed. We'd call the same function that embedForm() would call to process the resulting HTML.

ebruchez commented 2 years ago
ebruchez commented 2 years ago
ebruchez commented 1 year ago

Most of the fixes so far are going to be present in 2022.1, and have also been included in 2022.1.5. However, we don't yet "officially" support multiple forms per page.

ebruchez commented 1 year ago

We just had two indications that server-side embedding doesn't work with two forms:

ebruchez commented 1 year ago

For the server-side embedding, one issue is to make sure we include the baseline JavaScript only once.