This was written by our brilliant Jive Engineer Edward Venaglia!
The approach involves an old-school HTML form, and a few iFrames to get around the browser's cross domain security policies. It also requires you to run your app from the /public folder of an add-on zip.
The Process
- We setup and submit the firm by invoking submitForm().
- We need to first obtain the Jive cross domain token from the Jive container.
- Next set the cross-domain token on the form's parameters.
- Calculate the Jive URL, and append the v3 path; this becomes the form's "action".
- Set the target of the form to the iframe we have added just for this purpose.
- Apply any extra form data, specific to our needs.
- Submit the form.
- The form is sent to Jive
- The response to loaded into the iframe named "uploadFrame".
- The script in "cross-domain-relay.html" is polling the iframe named "uploadFrame" and detects the newly loaded document.
- The body of the response is parsed and sent to the parent window (our app) using window.postMessage().
- Our message listener is invoked.
- After validation, our callback is invoked, passing the cross-domain response to the form post.
Limitations
- The app must be hosted using /public resources of the add-on.
- This requires Jive 8.0 or Jive Cloud to use /public resources.
- The JSON response content type does not work with older versions of IE. Test it first!
The Code
First we need to add the form tag:
Next we need some iFrames, one of which is the target of the form we just added:
Now for some JavaScript to set the src of those iFrames:
$('iframe[name="uploadFrame"]').attr('src', getAddonURL() + '/blank.html'); $('iframe[name="cross-domain-relay"]').attr('src', getAddonURL() + '/cross-domainrelay.html?uploadFrame'); function getAddonURL() { var matches = window.location.href.match(/.*?[?&]url=([^&]+)%2F.*$/); if (matches.length == 2) { return decodeURIComponent(matches[1]); } else { osapi.jive.core.container.sendNotification( { "severity" : "error", "message": "Could not parse addon URL from window location " + window.location.href } ); return ''; } }
Responses are delivered by cross-domain message, so we need a handler:
var postCallback; var originDomain = document.referrer.substring(0, document.referrer.indexOf('/', 8)); window.addEventListener('message', function(event) { var eventData = JSON.parse(event.data); if (event.origin !== originDomain || !eventData || typeof(eventData['form-postcross-domain-relay']) === "undefined") { return; } console.log('Received data', eventData); var error = eventData['form-post-cross-domain-relay'].error; if ( error ) { console.error('error.statics.upload', ' ' + error.message); return; } if ( postCallback ) { postCallback(eventData['form-post-cross-domain-relay']); } // unwire the post callback; callers must set it again postCallback = null; });
Submitting the form is done using JavaScript:
function submitForm(v3uri, callback) { var $postForm = $("#j-post-form"); osapi.jive.core.container.requestXJToken( {}, function(newToken) { setupToken(newToken, formDomID); var tokenName = newToken['jive.token.name']; $postForm.find('.j-form-token') .attr('name', tokenName) .val(newToken[tokenName]); $postForm.find('input[name=\'jive.token.name\']').val(tokenName); var jiveURL = getJiveURL(); var actionURL = jiveURL + '/api/core/v3' + v3uri; $postForm .attr('action', actionURL ) .attr('method', 'POST' ) .attr('target', 'uploadFrame' ) .removeAttr('onsubmit'); // Set any other form post data you need to set before uploading postCallback = callback; $postForm.submit(); }); } function getJiveURL() { var href = getAddonURL(); return href.substring(0, href.indexOf('/resources/add-ons')); }
Finally, we add a few files to our add-on zip: (sources are attached)
- blank.html
- cross-domain-relay.html
Comments