Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

6345 - Uplift to enketo-core version 5.18.1 #7256

Merged
merged 201 commits into from
Aug 16, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
201 commits
Select commit Hold shift + click to select a range
6a41820
Switch enketo-xslt to enketo-transformer
jkuester Aug 16, 2021
0f04c84
Update enketo-core and jquery versions
jkuester Aug 16, 2021
74d0c1b
Fix Enketo css/js hacks to work with new version
jkuester Aug 13, 2021
c858b66
Remove unused webapp patches
jkuester Aug 16, 2021
ac16e4b
Bump up the bundle size of main.js
jkuester Aug 16, 2021
b424840
Update the enketo service in webapp to actually be able to load a form
jkuester Aug 17, 2021
57aa8a1
Bump openrosa-xpath-evaluator version
jkuester Aug 17, 2021
cb7cb2d
Fix up hacking for openrosa stuff
jkuester Aug 17, 2021
ba8c6fb
Clean up functions copied from openrosa and add unit tests
jkuester Aug 18, 2021
351b30b
Fix override language
jkuester Aug 18, 2021
3f59f16
Fix forward button functionality
jkuester Aug 18, 2021
f1f62bc
Re-introduce the updated enketo-inputs-always-relevant.patch
jkuester Aug 18, 2021
660456c
Remove the notewidget from the webapp and move markdown logic to api
jkuester Aug 23, 2021
ce1c6d1
Update CSS (remove .note, hide language picker, etc)
jkuester Aug 23, 2021
240efcc
Fix word-breaking in option labels
jkuester Aug 23, 2021
ce93925
Update wdio selector for phone input
jkuester Aug 25, 2021
eb8b474
Update Protractor selector for phone input
jkuester Aug 25, 2021
322fac7
Fix widgets and add new datepicker-widget
jkuester Aug 25, 2021
c11b7ef
Fix phone-widget unit tests
jkuester Aug 26, 2021
3e1cc17
Convert Enketo config.json to config.js
jkuester Aug 26, 2021
6a9ba75
Add custom Enketo file-manager
jkuester Aug 26, 2021
0bfcf9e
Add horizonal-choices widget
jkuester Aug 26, 2021
a6e2afa
Fix up the db-object-widget
jkuester Aug 27, 2021
2436174
Uplift OpenrosaXpathEvaluatorBinding
jkuester Aug 27, 2021
131b67c
Remove concat-xpath-string test
jkuester Aug 27, 2021
6254ff2
Fix z-score functionality/tests
jkuester Aug 30, 2021
68c84ae
Add custom filepicker-widget
jkuester Aug 30, 2021
693a8a8
Try going back to older style of OpenrosaXpathEvaluatorBInding
jkuester Aug 31, 2021
126878b
Use TAB to close date picker during default delivery tests
jkuester Sep 1, 2021
f9b0dd1
See if anything magical happens when adding the dynamic URL listener
jkuester Sep 1, 2021
72b3cf1
Reset the Submit button when going to previous page
jkuester Sep 1, 2021
731f3e1
Fix default delivery test
jkuester Sep 2, 2021
450cd7e
Clean up custom xpath functions and add tests
jkuester Sep 7, 2021
c967023
Revert "See if anything magical happens when adding the dynamic URL l…
jkuester Sep 2, 2021
aaa5e11
Add note about headless to TESTING doc
jkuester Sep 7, 2021
39aaaf7
Clean up Openrosa Xpath binding
jkuester Sep 7, 2021
cb78fa4
Add test for Enketo language
jkuester Sep 8, 2021
fa0aca0
Reset default delivery form
jkuester Sep 8, 2021
72d9184
Clean up Openrosa Xpath binding
jkuester Sep 8, 2021
75bfb80
Remove unnecessary datepicker and filepicker widgets
jkuester Sep 8, 2021
41feb8f
Remove unnecessary horizontal-choices widget
jkuester Sep 8, 2021
aa2d205
Convert all widgets to classes that extend Widget
jkuester Sep 8, 2021
b56d555
Fix phone widget issues
jkuester Sep 8, 2021
cb88e10
Fix flaking contact summary test
jkuester Sep 9, 2021
d5dda2a
Refactor phone-widget to return promise from constructor
jkuester Sep 9, 2021
d1701d1
Remove weird function code from widgets and see what breaks
jkuester Sep 8, 2021
c2ad0a3
Add additional enketo widgets
jkuester Sep 8, 2021
5b2a354
Add in all widget translactions
jkuester Sep 8, 2021
de6840f
Bump up enketo-transformer and node-html-parser to latest versions
jkuester Sep 9, 2021
9eace41
Reset the maxSize for the main.js bundle
jkuester Sep 10, 2021
e1f8fca
Update z-score function to properly load value from input node
jkuester Sep 10, 2021
abf6976
Revert "Reset the maxSize for the main.js bundle"
jkuester Sep 10, 2021
69a3c22
Go to 950 kB on bundle size
jkuester Sep 10, 2021
87f8b26
Add additional enketo widgets
jkuester Sep 13, 2021
c035718
Remove autocomplete widget
jkuester Sep 13, 2021
b8c375d
Update xsl to support new enketo types
jkuester Sep 13, 2021
2e8aa47
Add new widgets demo form
jkuester Sep 13, 2021
1d4db03
Update readme doc
jkuester Sep 16, 2021
1d619ce
Dedupe webapp
jkuester Sep 17, 2021
9c75516
Try building without extra widgets
jkuester Sep 17, 2021
c559bdb
Drop the CSS too
jkuester Sep 17, 2021
6e3fbc4
dedupe the webapp dependencies
jkuester Sep 17, 2021
6b27627
Add alias to exclude node-forge from bundle
jkuester Sep 17, 2021
1921b97
Bump the bundle size back up to 820 just to get a build
jkuester Sep 17, 2021
7b6c7eb
Bump the bundleSize to 825 kB and add widgets back in except draw/rank
jkuester Sep 20, 2021
9f68e29
Reset non-english translation files
jkuester Sep 20, 2021
d78b75f
Re-add the autocomplete widget
jkuester Sep 21, 2021
ef71ca0
Clean up demo forms
jkuester Sep 21, 2021
da16779
More cleanup on the demo form add proper public domain images
jkuester Sep 21, 2021
b722e00
Add dynamic-url widget
jkuester Sep 24, 2021
a6ed0f3
Remove translations for removed widgets
jkuester Sep 24, 2021
6893b47
Merge remote-tracking branch 'origin/master' into 6345-enketo-uplift
jkuester Sep 24, 2021
532c9a2
Update new Enketo widgets to match new format
jkuester Sep 27, 2021
68c4a19
Bump buildSize from 825 -> 830
jkuester Sep 27, 2021
1ab3e9e
Fix bugs in xpath functions
jkuester Sep 27, 2021
df08b9c
Merge remote-tracking branch 'origin/master' into 6345-enketo-uplift
jkuester Oct 12, 2021
845b6f0
Remove unnecessary language code
jkuester Oct 12, 2021
3cb901c
Add patch for enketo-repeat-name-collision
jkuester Oct 12, 2021
c2054f9
Add polyfils from core-js-pure and webcomponentsjs
jkuester Oct 22, 2021
d5b5db2
Fix linting issue in polyfills.ts
jkuester Oct 22, 2021
5e74a8f
Change core-js-pure to just be core-js
jkuester Oct 22, 2021
73461a2
Increase polyfill bundle size
jkuester Oct 22, 2021
84fc7d3
Remove unnecessary Promise.finally polyfill
jkuester Oct 25, 2021
8e688d2
Merge remote-tracking branch 'origin/master' into 6345-enketo-uplift
jkuester Oct 26, 2021
6a47a54
Update package-lock files
jkuester Oct 26, 2021
c62ee21
Fix package files
jkuester Oct 26, 2021
0963a7a
Fix medic-xpath-extensions
jkuester Oct 26, 2021
b6f71ce
Calibrate new bundle sizes
jkuester Oct 26, 2021
aa7129d
Add missing newline at the end of package-lock.json
jkuester Oct 26, 2021
75b64ee
Remove unnecessary indentation from widget files
jkuester Oct 26, 2021
cf09c9a
Fix medic-xpath-extensions test
jkuester Oct 26, 2021
acc16ab
Fix reports tests
jkuester Oct 27, 2021
209aa6a
Update TESTING doc for debugging wdio tests with Intellij
jkuester Oct 27, 2021
cfd1d27
Revert DEVELOPMENT doc changes
jkuester Oct 28, 2021
6e080fc
Revert Intellij markdown auto-corrections
jkuester Oct 28, 2021
accff65
Clean up markdown code in api
jkuester Nov 4, 2021
bad58d1
Fix linting issues in Markdown
jkuester Nov 4, 2021
a7aac57
Use replaceNode function that is compatible with Node < 11
jkuester Nov 5, 2021
2280b6c
FIx formatting in generate-xform and medic-xpath-extensions
jkuester Nov 5, 2021
9a3eeef
Fix dynamic-url handling in API
jkuester Nov 8, 2021
c6e7c86
Fix linting issues in medic-xpath-extensions
jkuester Nov 9, 2021
3b35852
Clean up date logic in medic-xpath-extensions
jkuester Nov 9, 2021
a4b0c1c
Clean up service code for enketo and z-score
jkuester Nov 9, 2021
5aef37c
Fix more linting issues
jkuester Nov 9, 2021
77c37ab
Merge remote-tracking branch 'origin/master' into 6345-enketo-uplift
jkuester Nov 12, 2021
9c7723f
Add test for phone widget selector
jkuester Nov 12, 2021
7c542b5
Clean up test
jkuester Nov 12, 2021
365d0c4
Fix jquery version
jkuester Nov 12, 2021
d50e4bc
Manually remove jquery from enketo block of package-lock
jkuester Nov 12, 2021
04bccff
Use npm-force-resolutions to force version of jquery
jkuester Nov 17, 2021
8f0210f
Remove unnecessary code from db-object-widget
jkuester Nov 17, 2021
86da179
Fix dynamic-url to open properly in xWalk
jkuester Nov 17, 2021
77ff144
ignore-scripts when running npm ci from grunt
jkuester Nov 18, 2021
2e36c13
Roll back npm-force-resolutions changes and use webpack alias
jkuester Nov 18, 2021
0dd3d05
Fix linting issues in dynamic-url
jkuester Nov 18, 2021
ca635f3
Block display of the input in the countdown widget
jkuester Nov 18, 2021
64ba0b5
Update to use new enketo event names
jkuester Nov 19, 2021
d7acb8d
Add a valuechanged listener to refresh navButtons
jkuester Nov 19, 2021
afce881
Update custom xsl to make notes never required
jkuester Nov 19, 2021
c5609a3
Merge branch 'master' into 6345-enketo-uplift
jkuester Nov 23, 2021
ea1d132
Remove isNil from medic-xpath-extensions
jkuester Nov 23, 2021
9b7e8dd
Try just disabling the delivery test to see if others fail
jkuester Nov 23, 2021
2eb1ae1
Wait for form button to be ready before trying to click it
jkuester Nov 23, 2021
1b78a19
Merge branch 'master' into 6345-enketo-uplift
jkuester Nov 24, 2021
7410a55
Move enketo-widgets demo form to support-scripts repo
jkuester Nov 24, 2021
d134926
Clean up generate-xform code and tests
jkuester Nov 29, 2021
0f2c21d
Add e2e test for required notes
jkuester Dec 1, 2021
782d211
Correct behavior of asDate in xpath-entensions
jkuester Dec 6, 2021
484ffb8
Properly import DynamicUrlWidget in tests
jkuester Dec 10, 2021
a5d69ba
Add comment about webpack jquery alias
jkuester Dec 10, 2021
184c21b
Fix db-object-widget selector
jkuester Dec 16, 2021
29096c0
Merge remote-tracking branch 'origin/master' into 6345-enketo-uplift
jkuester Dec 16, 2021
dc7bd4f
Merge remote-tracking branch 'origin/master' into 6345-enketo-uplift
jkuester Dec 20, 2021
8d7d2d4
Try seeding data for generate-xform test after login
jkuester Dec 20, 2021
ffdda66
Move required note test to submit-enketo-form file
jkuester Dec 20, 2021
4444137
Fix bug with Previous button getting improperly displayed
jkuester Dec 23, 2021
db5c397
Tweak CSS for backwards consistency
jkuester Dec 23, 2021
4a59cb4
Cleanup generate-xform.js
jkuester Jan 7, 2022
04e0bf7
Cleanup default delivery form e2e test
jkuester Jan 7, 2022
c7386d4
Merge remote-tracking branch 'origin/master' into 6345-enketo-uplift
jkuester Jan 7, 2022
d09fcfd
Fix removing from a repeat popping a confirmation dialog
jkuester Jan 7, 2022
f1ba7d0
Add patch for openrosa to use old behavior
jkuester Jan 19, 2022
389dd89
Fix css so that notes are not bold
jkuester Jan 21, 2022
2f1df27
Fix issue where form inputs are not always relevant
jkuester Jan 25, 2022
e0a0357
Revert "Add patch for openrosa to use old behavior"
jkuester Feb 24, 2022
2a5da45
Update default contact forms to coalesce unanswered birth month values
jkuester Feb 24, 2022
9a4b36b
Update standard collect delivery form to coalesce number properly
jkuester Feb 25, 2022
8fadc16
Update covid-19 contact forms to coalesce number properly
jkuester Feb 25, 2022
b4505a6
Fix calc in pregnancy_home_visit
jkuester Mar 1, 2022
a6e6b09
Remove unnecessary and broken logic from xPath evaluate
jkuester Mar 1, 2022
410789b
Side-load contact-summary as XmlDocument instead of string
jkuester Mar 1, 2022
652b7ab
Fix selector for inputs to be less restrictive when making relevant
jkuester Mar 2, 2022
d6f8ce3
Refactor standard forms with non-relevant questions with defaults
jkuester Mar 4, 2022
af5bd3e
Update embedded html logic to clear invalid whitespace from html tags
jkuester Mar 4, 2022
e89d571
Fix phone-widget selector so not applied to numbers string questions
jkuester Mar 8, 2022
0372a16
Add custom implementation for format-date xPath function
jkuester Mar 10, 2022
7c69f7f
Merge remote-tracking branch 'origin/master' into 6345-enketo-uplift
jkuester Mar 11, 2022
9af7b3d
Update webapp package-lock after merge
jkuester Mar 11, 2022
8debd10
Update api package-lock after merge
jkuester Mar 11, 2022
fe16217
Update default place create forms after merge
jkuester Mar 11, 2022
f07de14
Fix linting
jkuester Mar 14, 2022
1674637
Make android-datepicker text input readonly
jkuester Mar 16, 2022
d63ed71
Fix inputs validation logic to reset relevant if fails validation
jkuester Mar 28, 2022
c0b7da0
Merge branch 'master' into 6345-enketo-uplift
jkuester Mar 28, 2022
6d52eee
Improve regex readability (for real)
jkuester Apr 5, 2022
10e0a5e
Clean up a few things in the webapp
jkuester Apr 5, 2022
b7522bf
Update logic for inputs section to fix constraint issues
jkuester Apr 5, 2022
ab5594e
More updates for inputs section logic to just move back to patches
jkuester Apr 5, 2022
e340b2c
Fix standard delivery form to move still_pregnant field
jkuester Apr 5, 2022
7baac9c
Merge branch 'master' into 6345-enketo-uplift
jkuester Apr 5, 2022
657a5ec
Remove `data-required` from phone input to prevent
jkuester Apr 7, 2022
18bf9af
Merge branch 'master' into 6345-enketo-uplift
jkuester Apr 7, 2022
38514dd
Add custom impl for format-date-time
jkuester Apr 8, 2022
096809c
Clean up enketo service test
jkuester Apr 12, 2022
9baff20
Improve performance on enketo relevant patch
jkuester Apr 12, 2022
2cbb947
Merge branch 'master' into 6345-enketo-uplift
jkuester Apr 12, 2022
9ea7820
Fix loading contact-summary data into forms by polyfilling jQuery
jkuester Apr 14, 2022
530d139
Fix mrdt widget
jkuester Apr 14, 2022
c3b532a
Merge branch 'master' into 6345-enketo-uplift
jkuester Apr 14, 2022
8be75c7
Move jQuery fix out of polyfills so it does not get loaded in polyfills
jkuester Apr 14, 2022
772a4fe
Pause multimedia when navigating between form's pages (#7341)
latin-panda Apr 22, 2022
f1411b3
Merge branch 'master' into 6345-enketo-uplift
jkuester Apr 25, 2022
062cdbc
Merge branch 'master' into 6345-enketo-uplift
jkuester May 13, 2022
bfddfe7
Remove custom date format xpath functions
jkuester May 25, 2022
84f7c5a
Merge branch 'master' into 6345-enketo-uplift
jkuester May 26, 2022
5c09d56
Fix dob_approx calculations in default forms
jkuester Jun 13, 2022
8344c85
Merge branch 'master' into 6345-enketo-uplift
jkuester Jun 14, 2022
1edfb59
Fix decimal-date-time calculations in default delivery form
jkuester Jun 14, 2022
5832b3f
Update delivery and pregnancy-visit tests with new selectors
jkuester Jun 14, 2022
cab004f
Update Enketo file-manager to properly use maxAttachmentSize
jkuester Jun 21, 2022
94ec863
Update db-object-widget to trigger a re-validation of the field's con…
jkuester Jun 24, 2022
693508b
Remove extra line
jkuester Jun 24, 2022
4307554
Update db-object-widget to handle nested db-objects
jkuester Jul 13, 2022
48333c9
Update db-object-widget to proxy from select to input
jkuester Jul 19, 2022
bf328fb
Merge branch 'master' into 6345-enketo-uplift
jkuester Jul 19, 2022
fbc1844
Create brand new select in db-object-widget instead of cloning input
jkuester Jul 21, 2022
d0b19b6
Merge branch 'master' into 6345-enketo-uplift
jkuester Jul 22, 2022
4bfddb8
Fix merge conflict in standard immunization_visit form
jkuester Jul 22, 2022
3a02072
Merge remote-tracking branch 'origin/master' into 6345-enketo-uplift
jkuester Aug 12, 2022
bf71528
Fix api package-lock.json
jkuester Aug 12, 2022
d6b338b
Fix immunization visit e2e test selectors to work with new enketo
jkuester Aug 12, 2022
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 5 additions & 4 deletions Gruntfile.js
Original file line number Diff line number Diff line change
Expand Up @@ -541,11 +541,12 @@ module.exports = function(grunt) {
'patch webapp/node_modules/moment/locale/hi.js < webapp/patches/moment-hindi-use-euro-numerals.patch',

// patch enketo to always mark the /inputs group as relevant
'patch webapp/node_modules/enketo-core/src/js/Form.js < webapp/patches/enketo-inputs-always-relevant.patch',
'patch webapp/node_modules/enketo-core/src/js/form.js < webapp/patches/enketo-inputs-always-relevant_form.patch',
'patch webapp/node_modules/enketo-core/src/js/relevant.js < webapp/patches/enketo-inputs-always-relevant_relevant.patch',

// patch enketo so forms with no active pages are considered valid
// https://github.com/medic/medic/issues/5484
'patch webapp/node_modules/enketo-core/src/js/page.js < webapp/patches/enketo-handle-no-active-pages.patch',
// patch enketo to fix repeat name collision bug - this should be removed when upgrading to a new version of enketo-core
// https://github.com/enketo/enketo-core/issues/815
'patch webapp/node_modules/enketo-core/src/js/calculate.js < webapp/patches/enketo-repeat-name-collision.patch',

// patch messageformat to add a default plural function for languages not yet supported by make-plural #5705
'patch webapp/node_modules/messageformat/lib/plurals.js < webapp/patches/messageformat-default-plurals.patch',
Expand Down
849 changes: 845 additions & 4 deletions api/package-lock.json

Large diffs are not rendered by default.

3 changes: 2 additions & 1 deletion api/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@
"body-parser": "^1.19.2",
"buffer-shims": "^1.0.0",
"compression": "^1.7.4",
"enketo-xslt": "^1.15.2",
"enketo-transformer": "^2.0.0",
"express": "^4.17.1",
"google-libphonenumber": "^3.2.30",
"gsm": "^0.1.4",
Expand All @@ -33,6 +33,7 @@
"morgan": "^1.10.0",
"mustache": "^4.2.0",
"node-cache": "^5.1.2",
"node-html-parser": "^3.0.4",
"object-path": "^0.11.8",
"openrosa-formlist": "https://github.com/medic/openrosa-formlist#sax",
"pass-stream": "^1.0.0",
Expand Down
89 changes: 75 additions & 14 deletions api/src/services/generate-xform.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,18 +4,19 @@
*/
const childProcess = require('child_process');
const path = require('path');
const htmlParser = require('node-html-parser');
const logger = require('../logger');
const db = require('../db');
const formsService = require('./forms');
const markdown = require('enketo-transformer/src/markdown');

const FORM_ROOT_OPEN = '<root xmlns:xf="http://www.w3.org/2002/xforms" xmlns:orx="http://openrosa.org/xforms" xmlns:enk="http://enketo.org/xforms" xmlns:kb="http://kobotoolbox.org/xforms" xmlns:esri="http://esri.com/xforms" xmlns:oc="http://openclinica.org/xforms" xmlns:h="http://www.w3.org/1999/xhtml" xmlns:ev="http://www.w3.org/2001/xml-events" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:jr="http://openrosa.org/javarosa">';
const MODEL_ROOT_OPEN = '<root xmlns="http://www.w3.org/2002/xforms" xmlns:xf="http://www.w3.org/2002/xforms" xmlns:h="http://www.w3.org/1999/xhtml" xmlns:ev="http://www.w3.org/2001/xml-events" xmlns:xsd="http://www.w3.org/2001/XMLSchema">';
const ROOT_CLOSE = '</root>';
const JAVAROSA_SRC = / src="jr:\/\//gi;
const MEDIA_SRC_ATTR = ' data-media-src="';

const FORM_STYLESHEET = path.join(__dirname, '../xsl/openrosa2html5form.xsl');
const MODEL_STYLESHEET = path.join(__dirname, '../../node_modules/enketo-xslt/xsl/openrosa2xmlmodel.xsl');
const MODEL_STYLESHEET = path.join(__dirname, '../../node_modules/enketo-transformer/src/xsl/openrosa2xmlmodel.xsl');
const XSLTPROC_CMD = 'xsltproc';

const processErrorHandler = (xsltproc, err, reject) => {
Expand Down Expand Up @@ -70,33 +71,93 @@ const transform = (formXml, stylesheet) => {
});
};

const removeLast = (haystack, needle) => {
const index = haystack.lastIndexOf(needle);
if (index === -1) {
return haystack;
}
return haystack.slice(0, index) + haystack.slice(index + needle.length);
const convertDynamicUrls = (original) => original.replace(
/<a[^>]+href="([^"]*---output[^"]*)"[^>]*>(.*?)<\/a>/gm,
'<a href="#" target="_blank" rel="noopener" class="dynamic-url">' +
'$2<span class="url hidden">$1</span>' +
'</a>');

const convertEmbeddedHtml = (original) => original
.replace(/&lt;\s*(\/)?\s*([\s\S]*?)\s*&gt;/gm, '<$1$2>')
.replace(/&quot;/g, '"')
.replace(/&#039;/g, '\'')
.replace(/&amp;/g, '&');

const replaceNode = (currentNode, newNode) => {
const { parentNode } = currentNode;
const idx = parentNode.childNodes.findIndex((child) => child === currentNode);
parentNode.childNodes = [
...parentNode.childNodes.slice(0, idx),
newNode,
...parentNode.childNodes.slice(idx + 1),
];
};

const removeRootNode = (string, node) => {
return removeLast(string.replace(node, ''), ROOT_CLOSE);
// Based on enketo/enketo-transformer
// https://github.com/enketo/enketo-transformer/blob/377caf14153586b040367f8c2de53c9d794c19d4/src/transformer.js#L430
const replaceAllMarkdown = (formString) => {
const replacements = {};
const form = htmlParser.parse(formString).querySelector('form');

// First turn all outputs into text so *<span class="or-output></span>* can be detected
form.querySelectorAll('span.or-output').forEach((el, index) => {
const key = `---output-${index}`;
const textNode = el.childNodes[0];
replacements[key] = el.toString();
textNode.textContent = key;
replaceNode(el, textNode);
// Note that we end up in a situation where we likely have sibling text nodes...
});

// Now render markdown
const questions = form.querySelectorAll('span.question-label');
dianabarsan marked this conversation as resolved.
Show resolved Hide resolved
const hints = form.querySelectorAll('span.or-hint');
questions.concat(hints).forEach((el, index) => {
const original = el.innerHTML;
let rendered = markdown.toHtml(original);
rendered = convertDynamicUrls(rendered);
rendered = convertEmbeddedHtml(rendered);

if (original !== rendered) {
const key = `$$$${index}`;
replacements[key] = rendered;
el.innerHTML = key;
}
});

let result = form.toString();

// Now replace the placeholders with the rendered HTML
// in reverse order so outputs are done last
Object.keys(replacements).reverse().forEach(key => {
const replacement = replacements[key];
if (replacement) {
result = result.replace(key, replacement);
}
});

return result;
};

const generateForm = formXml => {
return transform(formXml, FORM_STYLESHEET).then(form => {
form = replaceAllMarkdown(form);
// rename the media src attributes so the browser doesn't try and
// request them, instead leaving it to custom code in the Enketo
// service to load them asynchronously
form = form.replace(JAVAROSA_SRC, MEDIA_SRC_ATTR);
// remove the root node leaving just the HTML to be rendered
return removeRootNode(form, FORM_ROOT_OPEN);
return form.replace(JAVAROSA_SRC, MEDIA_SRC_ATTR);
});
};

const generateModel = formXml => {
return transform(formXml, MODEL_STYLESHEET).then(model => {
// remove the root node leaving just the model
return removeRootNode(model, MODEL_ROOT_OPEN);
model = model.replace(MODEL_ROOT_OPEN, '');
const index = model.lastIndexOf(ROOT_CLOSE);
if (index === -1) {
return model;
}
return model.slice(0, index) + model.slice(index + ROOT_CLOSE.length);
});
};

Expand Down
174 changes: 168 additions & 6 deletions api/src/xsl/openrosa2html5form.xsl
Original file line number Diff line number Diff line change
Expand Up @@ -2,24 +2,186 @@
<!--
This stylesheet extends the default one to allow for additional input types.
-->
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:xf="http://www.w3.org/2002/xforms"
xmlns:enk="http://enketo.org/xforms"
xmlns:jr="http://openrosa.org/javarosa"
xmlns:orx="http://openrosa.org/xforms">

<xsl:import href="../../node_modules/enketo-xslt/xsl/openrosa2html5form.xsl"/>

<xsl:import href="../../node_modules/enketo-transformer/src/xsl/openrosa2html5form.xsl"/>

<!-- Overwrite binding-attributes declaration from openrosa2html5form.xsl to include custom code -->
<!-- Prevent notes from ever being required -->
<xsl:template name="binding-attributes">
<xsl:param name="binding"/>
<xsl:param name="nodeset"/>
<xsl:param name="type"/>
<xsl:variable name="xml-type">
<xsl:call-template name="xml_type">
<xsl:with-param name="nodeset" select="$nodeset"/>
<!--<xsl:with-param name="binding" select="$binding"/>-->
</xsl:call-template>
</xsl:variable>
<xsl:variable name="html-input-type">
<xsl:call-template name="html_type">
<xsl:with-param name="xml_type" select="$xml-type" />
</xsl:call-template>
</xsl:variable>
<xsl:choose>
<xsl:when test="$type = 'select_multiple'">
<xsl:attribute name="multiple">multiple</xsl:attribute>
</xsl:when>
<xsl:when test="$type = 'select_one'"></xsl:when>
<xsl:when test="$type = 'textarea'"></xsl:when>
<xsl:when test="$type = 'rank'">
<xsl:attribute name="type">rank</xsl:attribute>
</xsl:when>
<xsl:otherwise>
<xsl:attribute name="type">
<xsl:value-of select="$html-input-type"/>
</xsl:attribute>
</xsl:otherwise>
</xsl:choose>
<xsl:attribute name="name">
<xsl:value-of select="normalize-space($nodeset)" />
</xsl:attribute>
<xsl:if test="$html-input-type = 'radio'">
<xsl:attribute name="data-name">
<xsl:value-of select="normalize-space($nodeset)" />
</xsl:attribute>
</xsl:if>
<xsl:if test="local-name() = 'item'">
<xsl:attribute name="value">
<xsl:value-of select="./xf:value"/>
</xsl:attribute>
</xsl:if>
<!-- Medic specific section start -->
<!-- Do not copy the required attribute for notes -->
<xsl:if test="(string-length($binding/@required) &gt; 0) and not($binding/@required = 'false()') and not(local-name() = 'bind') and not($binding/@type='string' and $binding/@readonly='true()' and not(string-length($binding/@calculate) &gt; 0))">
<!-- Medic specific section end -->
<xsl:attribute name="data-required">
<xsl:value-of select="$binding/@required" />
</xsl:attribute>
</xsl:if>
<xsl:if test="$binding/@constraint">
<xsl:attribute name="data-constraint">
<xsl:value-of select="$binding/@constraint" />
</xsl:attribute>
</xsl:if>
<xsl:if test="$binding/@relevant">
<xsl:attribute name="data-relevant">
<xsl:value-of select="$binding/@relevant"/>
</xsl:attribute>
</xsl:if>
<xsl:if test="$binding/@calculate">
<xsl:attribute name="data-calculate">
<xsl:value-of select="$binding/@calculate" />
</xsl:attribute>
</xsl:if>
<xsl:if test="$binding/@jr:preload">
<xsl:attribute name="data-preload">
<xsl:value-of select="$binding/@jr:preload"/>
</xsl:attribute>
<xsl:attribute name="data-preload-params">
<xsl:value-of select="$binding/@jr:preloadParams"/>
</xsl:attribute>
</xsl:if>
<xsl:if test="$binding/@enk:for">
<xsl:attribute name="data-for">
<xsl:value-of select="normalize-space($binding/@enk:for)" />
</xsl:attribute>
</xsl:if>
<xsl:if test="$openclinica = 1">
<xsl:for-each select="$binding/@*[starts-with(name(), 'oc:') and not(substring-before(name(), 'Msg'))]" >
<xsl:attribute name="{concat('data-oc-', local-name(.))}">
<xsl:value-of select="normalize-space(.)" />
</xsl:attribute>
</xsl:for-each>
</xsl:if>
<xsl:if test="$binding/@orx:max-pixels">
<xsl:attribute name="data-max-pixels">
<xsl:value-of select="normalize-space($binding/@orx:max-pixels)" />
</xsl:attribute>
</xsl:if>
<xsl:attribute name="data-type-xml">
<xsl:value-of select="$xml-type" />
</xsl:attribute>
<xsl:if test="$xml-type = 'decimal'">
<xsl:attribute name="step">any</xsl:attribute>
</xsl:if>
<xsl:if test="$binding/@readonly = 'true()' and not($html-input-type = 'hidden')" >
<!--
This also adds a readonly attribute to <select> which is not valid HTML.
We could add some logic to avoid that (the <option>s already get the disabled attribute),
but it's an extra line of defence and doesn't really hurt. The input change handler in
Enketo Core ignores changes on a <select readonly>.
-->
<xsl:attribute name="readonly">readonly</xsl:attribute>
</xsl:if>
<xsl:if test="local-name() = 'range'">
<!-- note that due to the unhelpful default value behavior of input type=range in HTML, we use type=number -->
<xsl:if test="@start">
<xsl:attribute name="min">
<xsl:value-of select="@start" />
</xsl:attribute>
</xsl:if>
<xsl:if test="@end">
<xsl:attribute name="max">
<xsl:value-of select="@end" />
</xsl:attribute>
</xsl:if>
<xsl:if test="@step">
<xsl:attribute name="step">
<xsl:value-of select="@step" />
</xsl:attribute>
</xsl:if>
</xsl:if>
<xsl:if test="$html-input-type = 'file'">
<xsl:attribute name="accept">
<xsl:choose>
<xsl:when test="@accept">
<xsl:value-of select="@accept" />
</xsl:when>
<xsl:when test="@mediatype">
<xsl:value-of select="@mediatype" />
</xsl:when>
</xsl:choose>
</xsl:attribute>
<!-- Note, this test captures new, new-front, new-rear -->
<xsl:if test="contains(@appearance, 'new')">
<xsl:attribute name="capture">
<xsl:choose>
<xsl:when test="contains(@appearance, 'new-front')">
<xsl:value-of select="'user'"/>
</xsl:when>
<xsl:when test="contains(@appearance, 'new-rear')">
<xsl:value-of select="'environment'"/>
</xsl:when>
<!-- else (if appearance="new"), the capture attribute remains empty, by design -->
</xsl:choose>
</xsl:attribute>
</xsl:if>
</xsl:if>
</xsl:template>

<!-- Overwrite html_type declaration from openrosa2html5form.xsl to include custom code -->
<!-- Allow custom Medic types -->
<xsl:template name="html_type">
<xsl:param name="xml_type" />
<xsl:choose>
<xsl:when test="local-name(..) = 'select1' or $xml_type='select1' or local-name(.) = 'trigger'">radio</xsl:when>
<xsl:when test="local-name(..) = 'select' or $xml_type='select'">checkbox</xsl:when>
<xsl:when test="local-name() = 'bind'">hidden</xsl:when>
<xsl:when test="$xml_type = 'dateTime'">datetime</xsl:when>
<xsl:when test="local-name() = 'range'">number</xsl:when>
<xsl:when test="$xml_type = 'dateTime'">datetime-local</xsl:when>
<xsl:when test="$xml_type = 'date'">date</xsl:when>
<!-- note, it may not actually be possible to support 'file' with offline storage -->
<xsl:when test="$xml_type = 'binary'">file</xsl:when>
<xsl:when test="$xml_type = 'time'">time</xsl:when>
<xsl:when test="$xml_type = 'rank'">text</xsl:when>
<xsl:when
test="$xml_type = 'decimal' or $xml_type = 'float' or $xml_type = 'double' or $xml_type = 'int' or $xml_type = 'integer'"
>number</xsl:when>
test="$xml_type = 'decimal' or $xml_type = 'float' or $xml_type = 'double' or $xml_type = 'int' or $xml_type = 'integer'"
>number</xsl:when>
<xsl:when test="$xml_type = 'string' and contains(./@appearance, 'numbers')">tel</xsl:when>
<xsl:when test="$xml_type = 'string'">text</xsl:when>
<xsl:when test="$xml_type = 'barcode' or $xml_type = 'geopoint' or $xml_type = 'geotrace' or $xml_type = 'geoshape'" >
Expand Down
Loading