Implementation Guide
enTermX provides the ability to prepare FHIR compatible Implementation Guide (IG).
TermX synchronizes terminology, wiki pages and models into the format suitable
for FHIR IG Publisher.
Read more about the IG confuguration
in Confluece, Mitre cource, FHIR IG guidance
and Jose Teixeira presentation.
Configuration
TermX Wiki uses several MD extensions that are not supported by the HL7 IG template out of the box. To extend the HL7 IG template rendering capabilities, we utilize the concept of IG template extension.
Read more about how to extend the IG template.
File structure
├── local-template
│ ├── content
│ | └── assets
│ | └── js
│ | └── **/*.js (extensions go here)
│ └── includes
| └── _append.fragment-feedback_form.html (manually created)
├── _genonce.sh
└── ...
Notes about extension
The extensions could be inserted directly into the HTML, but it’s advised to extract them into a JavaScript file.
<!-- _append.fragment-feedback_form.html -->
<script type="module">
window.addEventListener('load', () => {
// ...
})
</script>
<!-- _append.fragment-feedback_form.html -->
<script type="module" src="assets/js/file_name.js"></script>
Extensions
The
script
type
If you want to view IG locally, choose the"application/javascript"
type.
When using the"module"
type, CORS issues may occur, but it’s fine when served from the HTTP server.
Each extension relies on theimport
functionality. Refer to browser compatibility.
Mermaid
Create mermaid.js
file in /content/assets/js
folder and import it in the _append.fragment-feedback_form.html
.
window.addEventListener('load', ev => {
import('https://cdn.jsdelivr.net/npm/mermaid@10/dist/mermaid.esm.min.mjs').then(({default: mermaid}) => {
document.querySelectorAll('pre.language-mermaid').forEach(el => {
el.outerHTML = `<figure class="mermaid">${el.firstChild.innerText}</figure>`;
})
mermaid.run({nodes: document.getElementsByClassName('mermaid')});
})
})
import mermaid from 'https://cdn.jsdelivr.net/npm/mermaid@10/dist/mermaid.esm.min.mjs';
window.addEventListener('load', () => {
document.querySelectorAll('pre.language-mermaid').forEach(el => {
el.outerHTML = `<figure class="mermaid">${el.firstChild.innerText}</figure>`;
})
mermaid.run({nodes: document.getElementsByClassName('mermaid')});
})
PlantUML
Create plantuml.js
file in /content/assets/js
folder and import it in the _append.fragment-feedback_form.html
. Don’t forget to copy the utils!
window.addEventListener('load', () => {
import('https://cdn.jsdelivr.net/npm/pako@2.1.0/+esm').then(({default: pako}) => {
document.querySelectorAll('pre.language-plantuml').forEach((el, idx) => {
const codeElement = el.firstChild;
const umlCode = codeElement.innerText;
const imgUrl = composePlantUmlUrl(umlCode);
fetch(imgUrl).then(r => r.text()).then(svg => el.outerHTML = `<figure class="plantuml">${svg}</figure>`)
})
// paste utils here
})
});
import pako from 'https://cdn.jsdelivr.net/npm/pako@2.1.0/+esm'
window.addEventListener('load', () => {
document.querySelectorAll('pre.language-plantuml').forEach((el, idx) => {
const codeElement = el.firstChild;
const umlCode = codeElement.innerText;
const imgUrl = composePlantUmlUrl(umlCode);
fetch(imgUrl).then(r => r.text()).then(svg => el.outerHTML = `<figure class="plantuml">${svg}</figure>`)
})
});
// paste utils here
function composePlantUmlUrl(umlCode) {
const server = 'https://www.plantuml.com/plantuml';
const zippedCode = encode64(pako.deflate('@startuml' + '\n' + umlCode + '\n@enduml'));
return `${server}/svg/~1${zippedCode}`;
}
function encode64(data) {
let r = "";
for (let i = 0; i < data.length; i += 3) {
if (i + 2 === data.length) {
r += append3bytes(data[i], data[i + 1], 0);
} else if (i + 1 === data.length) {
r += append3bytes(data[i], 0, 0);
} else {
r += append3bytes(data[i], data[i + 1],
data[i + 2]);
}
}
return r;
}
function append3bytes(b1, b2, b3) {
let c1 = b1 >> 2;
let c2 = ((b1 & 0x3) << 4) | (b2 >> 4);
let c3 = ((b2 & 0xF) << 2) | (b3 >> 6);
let c4 = b3 & 0x3F;
let r = "";
r += encode6bit(c1 & 0x3F);
r += encode6bit(c2 & 0x3F);
r += encode6bit(c3 & 0x3F);
r += encode6bit(c4 & 0x3F);
return r;
}
function encode6bit(b) {
if (b < 10) {
return String.fromCharCode(48 + b);
}
b -= 10;
if (b < 26) {
return String.fromCharCode(65 + b);
}
b -= 26;
if (b < 26) {
return String.fromCharCode(97 + b);
}
b -= 26;
if (b === 0) {
return '-';
}
if (b === 1) {
return '_';
}
return '?';
}
Draw.io
Create drawio.js
file in /content/assets/js
folder and import it in the _append.fragment-feedback_form.html
.
window.addEventListener('load', () => {
document.querySelectorAll('pre.language-drawio').forEach(el => {
el.outerHTML = `<figure class="drawio"><img src="data:image/svg+xml;base64, ${el.innerText}"></figure>`
})
})
Result
The file structure should resemble the one displayed below:
├── local-template
│ ├── content
│ | └── assets
│ | └── js
│ | ├── drawio.js
│ | ├── mermaid.js
│ | └── plantuml.js
│ └── includes
| └── _append.fragment-feedback_form.html
└── ...
The _append.fragment-feedback_form.html
should contain three imports:
<script type="application/javascript" src="assets/js/mermaid.js"></script>
<script type="application/javascript" src="assets/js/drawio.js"></script>
<script type="application/javascript" src="assets/js/plantuml.js"></script>
<script type="module" src="assets/js/mermaid.js"></script>
<script type="module" src="assets/js/drawio.js"></script>
<script type="module" src="assets/js/plantuml.js"></script>