lforms 29.3.0 → 33.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +261 -0
- package/README.md +97 -14
- package/changed-features.md +99 -0
- package/dist/lforms/LICENSE.md +70 -0
- package/dist/lforms/README.md +100 -0
- package/dist/lforms/fhir/R4/lformsFHIR.min.js +2 -0
- package/dist/lforms/fhir/R4/lformsFHIR.min.js.map +1 -0
- package/dist/lforms/fhir/STU3/lformsFHIR.min.js +2 -0
- package/dist/lforms/fhir/STU3/lformsFHIR.min.js.map +1 -0
- package/dist/lforms/fhir/lformsFHIRAll.min.js +2 -0
- package/dist/lforms/fhir/lformsFHIRAll.min.js.map +1 -0
- package/dist/lforms/webcomponent/assets/lib/zone.min.js +134 -0
- package/dist/lforms/webcomponent/down_arrow_gray_10_10.png +0 -0
- package/dist/lforms/webcomponent/favicon.ico +0 -0
- package/dist/lforms/webcomponent/index.html +9 -0
- package/dist/lforms/webcomponent/lhc-forms.js +2471 -0
- package/dist/lforms/webcomponent/magnifying_glass.png +0 -0
- package/dist/lforms/webcomponent/main.js +2464 -0
- package/dist/lforms/webcomponent/main.js.map +1 -0
- package/dist/lforms/webcomponent/polyfills.js +2 -0
- package/dist/lforms/webcomponent/polyfills.js.map +1 -0
- package/dist/lforms/webcomponent/runtime.js +2 -0
- package/dist/lforms/webcomponent/runtime.js.map +1 -0
- package/dist/lforms/webcomponent/scripts.js +3 -0
- package/dist/lforms/webcomponent/scripts.js.map +1 -0
- package/dist/lforms/webcomponent/styles.css +3 -0
- package/dist/lforms/webcomponent/styles.css.map +1 -0
- package/form_definition.md +382 -0
- package/lforms-33.2.0.tgz +0 -0
- package/package.json +94 -88
- package/r4-support.md +147 -0
- package/sdc-support.md +127 -0
- package/app/.npmignore +0 -3
- package/app/images/blank.gif +0 -0
- package/app/images/signal-stop.png +0 -0
- package/app/index.html +0 -10
- package/app/lforms.js +0 -56
- package/app/lforms.tpl.js +0 -964
- package/app/scripts/angular-packages.js +0 -11
- package/app/scripts/bootstrap-decorators.js +0 -31
- package/app/scripts/bower-index.js +0 -14
- package/app/scripts/fhir/R4/export.js +0 -33
- package/app/scripts/fhir/R4/fhirRequire.js +0 -36
- package/app/scripts/fhir/R4/lformsFHIR.js +0 -27260
- package/app/scripts/fhir/R4/sdc-export.js +0 -455
- package/app/scripts/fhir/R4/sdc-import.js +0 -483
- package/app/scripts/fhir/STU3/export.js +0 -27
- package/app/scripts/fhir/STU3/fhirRequire.js +0 -36
- package/app/scripts/fhir/STU3/lformsFHIR.js +0 -27291
- package/app/scripts/fhir/STU3/sdc-export.js +0 -493
- package/app/scripts/fhir/STU3/sdc-import.js +0 -494
- package/app/scripts/fhir/diagnostic-report.js +0 -707
- package/app/scripts/fhir/export-common.js +0 -209
- package/app/scripts/fhir/expression-processor.js +0 -670
- package/app/scripts/fhir/extensions/rendering-style.js +0 -23
- package/app/scripts/fhir/fhir-common.js +0 -3
- package/app/scripts/fhir/obs-prepop.mjs +0 -97
- package/app/scripts/fhir/runtime-common.js +0 -33
- package/app/scripts/fhir/sdc-common.js +0 -334
- package/app/scripts/fhir/sdc-export-common.js +0 -1046
- package/app/scripts/fhir/sdc-import-common.js +0 -1343
- package/app/scripts/fhir/versions.js +0 -8
- package/app/scripts/index.js +0 -20
- package/app/scripts/lforms-config.js +0 -12
- package/app/scripts/lforms-constants.js +0 -10
- package/app/scripts/lforms-controllers.js +0 -1196
- package/app/scripts/lforms-directives.js +0 -424
- package/app/scripts/lforms-index.js +0 -20
- package/app/scripts/lib/cross_browser.js +0 -21
- package/app/scripts/lib/lforms-data.js +0 -3591
- package/app/scripts/lib/lforms-hl7.js +0 -525
- package/app/scripts/lib/lforms-util.js +0 -1122
- package/app/scripts/lib/lforms-validate.js +0 -277
- package/app/scripts/lib/polyfill.js +0 -81
- package/app/scripts/themeList.js +0 -17
- package/app/styles/lforms.css +0 -1219
- package/app/styles/redmond-theme/README.txt +0 -2
- package/app/styles/redmond-theme/images/ui-bg_glass_75_d0e5f5_1x400.png +0 -0
- package/app/styles/redmond-theme/images/ui-bg_glass_85_dfeffc_1x400.png +0 -0
- package/app/styles/redmond-theme/images/ui-bg_glass_95_fef1ec_1x400.png +0 -0
- package/app/styles/redmond-theme/images/ui-bg_gloss-wave_55_5c9ccc_500x100.png +0 -0
- package/app/styles/redmond-theme/images/ui-bg_inset-hard_100_f5f8f9_1x100.png +0 -0
- package/app/styles/redmond-theme/images/ui-bg_inset-hard_100_fcfdfd_1x100.png +0 -0
- package/app/styles/redmond-theme/images/ui-icons_217bc0_256x240.png +0 -0
- package/app/styles/redmond-theme/images/ui-icons_2e83ff_256x240.png +0 -0
- package/app/styles/redmond-theme/images/ui-icons_469bdd_256x240.png +0 -0
- package/app/styles/redmond-theme/images/ui-icons_6da8d5_256x240.png +0 -0
- package/app/styles/redmond-theme/images/ui-icons_cd0a0a_256x240.png +0 -0
- package/app/styles/redmond-theme/images/ui-icons_d8e7f3_256x240.png +0 -0
- package/app/styles/redmond-theme/images/ui-icons_f9bd01_256x240.png +0 -0
- package/app/styles/redmond-theme/jquery-ui.css +0 -1311
- package/app/styles/redmond-theme/jquery-ui.min.css +0 -7
- package/app/styles/redmond-theme/theme.css +0 -443
- package/app/styles/themes.css +0 -1541
- package/app/styles/themes.css.map +0 -9
- package/app/styles/themes.scss +0 -411
- package/app/version.json +0 -1
- package/app/views/partials/attachment.html +0 -38
- package/app/views/partials/field-answers.html +0 -67
- package/app/views/partials/field-units.html +0 -24
- package/app/views/partials/form-controls.html +0 -19
- package/app/views/partials/form-header.html +0 -35
- package/app/views/partials/form-options.html +0 -50
- package/app/views/partials/form-title.html +0 -20
- package/app/views/partials/form-view.html +0 -13
- package/app/views/partials/item-options.html +0 -48
- package/app/views/partials/item.html +0 -126
- package/app/views/partials/itemPrefixAndText.html +0 -4
- package/app/views/partials/layout-horizontal.html +0 -156
- package/app/views/partials/layout-matrix.html +0 -145
- package/app/views/partials/popover-content.html +0 -1
- package/app/views/partials/repeating-button.html +0 -16
- package/app/views/partials/table-item.html +0 -30
- package/app/views/partials/template-table.html +0 -69
- package/app/views/partials/uib-popover-templates/uib-popover-template.html +0 -13
- package/app/views/partials/uib-popover-templates/uib-popover.html +0 -11
|
@@ -1,525 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* A package to generate HL7 messgages from LForms form data
|
|
3
|
-
*/
|
|
4
|
-
var LForms = require('../../lforms.js');
|
|
5
|
-
import {LOINC_URI} from '../fhir/fhir-common';
|
|
6
|
-
|
|
7
|
-
LForms.HL7 = (function() {
|
|
8
|
-
"use strict";
|
|
9
|
-
return {
|
|
10
|
-
|
|
11
|
-
LOINC_CS: 'LN',
|
|
12
|
-
obrFieldNum: 43,
|
|
13
|
-
obxFieldNum: 17,
|
|
14
|
-
|
|
15
|
-
// HL7 V2 data types
|
|
16
|
-
DataType : {
|
|
17
|
-
//Alphanumeric
|
|
18
|
-
"ST": "String",
|
|
19
|
-
"TX": "Text data",
|
|
20
|
-
"FT": "Formatted text",
|
|
21
|
-
//Numerical
|
|
22
|
-
"CQ": "Composite quantity with units",
|
|
23
|
-
"MO": "Money",
|
|
24
|
-
"NM": "Numeric",
|
|
25
|
-
"SI": "Sequence ID",
|
|
26
|
-
"SN": "Structured numeric",
|
|
27
|
-
//Identifier
|
|
28
|
-
"ID": "Coded values for HL7 tables",
|
|
29
|
-
"IS": "Coded values for user-defined tables",
|
|
30
|
-
"HD": "Hierarchic designator",
|
|
31
|
-
"EI": "Entity identifier",
|
|
32
|
-
"RP": "Reference pointer",
|
|
33
|
-
"PL": "Person location",
|
|
34
|
-
"PT": "Processing type",
|
|
35
|
-
//Date/Time
|
|
36
|
-
"DT": "Date",
|
|
37
|
-
"DTM": "Date/Time",
|
|
38
|
-
"TM": "Time",
|
|
39
|
-
"TS": "Time stamp",
|
|
40
|
-
//Code Values
|
|
41
|
-
"CE": "Coded element",
|
|
42
|
-
"CF": "Coded element with formatted values",
|
|
43
|
-
"CK": "Composite ID with check digit",
|
|
44
|
-
"CN": "Composite ID number and name",
|
|
45
|
-
"CX": "Extended composite ID with check digit",
|
|
46
|
-
"XCN": "Extended composite ID number and name",
|
|
47
|
-
//Generic
|
|
48
|
-
"CM": "Composite",
|
|
49
|
-
//Demographics
|
|
50
|
-
"AD": "Address",
|
|
51
|
-
"PN": "Person name",
|
|
52
|
-
"TN": "Telephone number",
|
|
53
|
-
"XAD": "Extended address",
|
|
54
|
-
"XPN": "Extended person name",
|
|
55
|
-
"XON": "Extended composite name and ID number for organizations",
|
|
56
|
-
"XTN": "Extended telecommunications number",
|
|
57
|
-
//Specialty/Chapter specific
|
|
58
|
-
"CD": "Channel definition",
|
|
59
|
-
"MA": "Multiplexed array",
|
|
60
|
-
"NA": "Numeric array",
|
|
61
|
-
"ED": "Encapsulated data",
|
|
62
|
-
"CP": "Composite price",
|
|
63
|
-
"FC": "Financial class",
|
|
64
|
-
//Extended Queries
|
|
65
|
-
"QSC": "Query selection criteria",
|
|
66
|
-
"QIP": "Query input parameter list",
|
|
67
|
-
"RCD": "Row column definition",
|
|
68
|
-
//Master Files
|
|
69
|
-
"DLN": "Driver’s license number",
|
|
70
|
-
"JCC": "Job code/class",
|
|
71
|
-
"VH": "Visiting hours",
|
|
72
|
-
//Medical Records/Info Mgmt
|
|
73
|
-
"PPN": "Performing person time stamp",
|
|
74
|
-
//Time Series
|
|
75
|
-
"DR": "Date/time range",
|
|
76
|
-
"RI": "Repeat interval",
|
|
77
|
-
"SCV": "Scheduling class value pair",
|
|
78
|
-
"TQ": "Timing/quantity"
|
|
79
|
-
},
|
|
80
|
-
|
|
81
|
-
// message delimiters
|
|
82
|
-
delimiters : {
|
|
83
|
-
segment: "\r", // "\r\n" for display
|
|
84
|
-
field: "|",
|
|
85
|
-
component: "^",
|
|
86
|
-
subcomponent: "&",
|
|
87
|
-
repetition: "~",
|
|
88
|
-
escape: "\\"
|
|
89
|
-
},
|
|
90
|
-
|
|
91
|
-
// OBX segment
|
|
92
|
-
OBX: [
|
|
93
|
-
{"seq":1, "len":4, "dt":"SI", "opt":"O","name":"Set ID"},
|
|
94
|
-
{"seq":2, "len":2, "dt":"ID", "opt":"R","name":"Value Type"},
|
|
95
|
-
{"seq":3, "len":590, "dt":"CE", "opt":"R","name":"Observation Identifier"},
|
|
96
|
-
{"seq":4, "len":20, "dt":"ST", "opt":"O","name":"Observation Sub-ID"},
|
|
97
|
-
{"seq":5, "len":65536, "dt":"ST", "opt":"O","name":"Observation Value"},
|
|
98
|
-
{"seq":6, "len":60, "dt":"CE", "opt":"O","name":"Units"},
|
|
99
|
-
{"seq":7, "len":10, "dt":"ST", "opt":"O","name":"Reference Range"},
|
|
100
|
-
{"seq":8, "len":5, "dt":"ID", "opt":"O","name":"Abnormal Flags"},
|
|
101
|
-
{"seq":9, "len":5, "dt":"NM", "opt":"O","name":"Probability"},
|
|
102
|
-
{"seq":10, "len":2, "dt":"ID", "opt":"O","name":"Nature of Abnormal Test"},
|
|
103
|
-
{"seq":11, "len":1, "dt":"ID", "opt":"R","name":"Observation Result Status"},
|
|
104
|
-
{"seq":12, "len":26, "dt":"TS", "opt":"O","name":"Date Last Obs Normal Values"},
|
|
105
|
-
{"seq":13, "len":20, "dt":"ST", "opt":"O","name":"User Defined Access Checks"},
|
|
106
|
-
{"seq":14, "len":26, "dt":"TS", "opt":"O","name":"Date/Time of the Observation"},
|
|
107
|
-
{"seq":15, "len":60, "dt":"CE", "opt":"O","name":"Producer's ID"},
|
|
108
|
-
{"seq":16, "len":80, "dt":"XCN", "opt":"O","name":"Responsible Observer"},
|
|
109
|
-
{"seq":17, "len":80, "dt":"CE", "opt":"O","name":"Observation Method"}
|
|
110
|
-
],
|
|
111
|
-
|
|
112
|
-
// OBR segment
|
|
113
|
-
OBR: [
|
|
114
|
-
{"seq":1, "len":4, "dt":"SI", "opt":"C","name":"Set ID - OBR"},
|
|
115
|
-
{"seq":2, "len":75 , "dt":"EI", "opt":"C","name":"Placer Order Number"},
|
|
116
|
-
{"seq":3, "len":75 , "dt":"EI", "opt":"C","name":"Filler Order Number"},
|
|
117
|
-
{"seq":4, "len":200, "dt":"CE", "opt":"R","name":"Universal Service ID"},
|
|
118
|
-
{"seq":5, "len":2, "dt":"ID", "opt":"B","name":"Priority"},
|
|
119
|
-
{"seq":6, "len":26 , "dt":"TS", "opt":"B","name":"Requested Date/time"},
|
|
120
|
-
{"seq":7, "len":26 , "dt":"TS", "opt":"C","name":"Observation Date/Time"},
|
|
121
|
-
{"seq":8, "len":26 , "dt":"TS", "opt":"O","name":"Observation End Date/Time"},
|
|
122
|
-
{"seq":9, "len":20 , "dt":"CQ", "opt":"O","name":"Collection Volume"},
|
|
123
|
-
{"seq":10,"len":60 ,"dt":"XCN","opt":"O","name":"Collector Identifier"},
|
|
124
|
-
{"seq":11,"len":1 ,"dt":"ID", "opt":"O","name":"Specimen Action Code"},
|
|
125
|
-
{"seq":12,"len":60 ,"dt":"CE", "opt":"O","name":"Danger Code"},
|
|
126
|
-
{"seq":13,"len":300 ,"dt":"ST", "opt":"O","name":"Relevant Clinical Info."},
|
|
127
|
-
{"seq":14,"len":26 ,"dt":"TS", "opt":"C","name":"Specimen Received Date/Time"},
|
|
128
|
-
{"seq":15,"len":300 ,"dt":"CM", "opt":"O","name":"Specimen Source"},
|
|
129
|
-
{"seq":16,"len":80 ,"dt":"XCN","opt":"O","name":"Ordering Provider"},
|
|
130
|
-
{"seq":17,"len":40 ,"dt":"XTN","opt":"O","name":"Order Callback Phone Number"},
|
|
131
|
-
{"seq":18,"len":60 ,"dt":"ST", "opt":"O","name":"Placer field 1"},
|
|
132
|
-
{"seq":19,"len":60 ,"dt":"ST", "opt":"O","name":"Placer field 2"},
|
|
133
|
-
{"seq":20,"len":60 ,"dt":"ST", "opt":"O","name":"Filler Field 1"},
|
|
134
|
-
{"seq":21,"len":60 ,"dt":"ST", "opt":"O","name":"Filler Field 2"},
|
|
135
|
-
{"seq":22,"len":26 ,"dt":"TS", "opt":"C","name":"Results Rpt/Status Chng - Date/Time"},
|
|
136
|
-
{"seq":23,"len":40 ,"dt":"CM", "opt":"O","name":"Charge to Practice"},
|
|
137
|
-
{"seq":24,"len":10 ,"dt":"ID", "opt":"O","name":"Diagnostic Serv Sect ID"},
|
|
138
|
-
{"seq":25,"len":1 ,"dt":"ID", "opt":"C","name":"Result Status"},
|
|
139
|
-
{"seq":26,"len":400 ,"dt":"CM", "opt":"O","name":"Parent Result"},
|
|
140
|
-
{"seq":27,"len":200 ,"dt":"TQ", "opt":"O","name":"Quantity/Timing"},
|
|
141
|
-
{"seq":28,"len":150 ,"dt":"XCN","opt":"O","name":"Result Copies To"},
|
|
142
|
-
{"seq":29,"len":150 ,"dt":"CM", "opt":"O","name":"Parent"},
|
|
143
|
-
{"seq":30,"len":20 ,"dt":"ID", "opt":"O","name":"Transportation Mode"},
|
|
144
|
-
{"seq":31,"len":300 ,"dt":"CE", "opt":"O","name":"Reason for Study"},
|
|
145
|
-
{"seq":32,"len":200 ,"dt":"CM", "opt":"O","name":"Principal Result Interpreter"},
|
|
146
|
-
{"seq":33,"len":200 ,"dt":"CM", "opt":"O","name":"Assistant Result Interpreter"},
|
|
147
|
-
{"seq":34,"len":200 ,"dt":"CM", "opt":"O","name":"Technician"},
|
|
148
|
-
{"seq":35,"len":200 ,"dt":"CM", "opt":"O","name":"Transcriptionist"},
|
|
149
|
-
{"seq":36,"len":26 ,"dt":"TS", "opt":"O","name":"Scheduled Date/Time"},
|
|
150
|
-
{"seq":37,"len":4 ,"dt":"NM", "opt":"O","name":"Number of Sample Containers"},
|
|
151
|
-
{"seq":38,"len":60 ,"dt":"CE", "opt":"O","name":"Transport Logistics of Collected Sample"},
|
|
152
|
-
{"seq":39,"len":200 ,"dt":"CE", "opt":"O","name":"Collector’s Comment"},
|
|
153
|
-
{"seq":40,"len":60 ,"dt":"CE", "opt":"O","name":"Transport Arrangement Responsibility"},
|
|
154
|
-
{"seq":41,"len":30 ,"dt":"ID", "opt":"O","name":"Transport Arranged"},
|
|
155
|
-
{"seq":42,"len":1 ,"dt":"ID", "opt":"O","name":"Escort Required"},
|
|
156
|
-
{"seq":43,"len":200 ,"dt":"CE", "opt":"O","name":"Planned Patient Transport Comment"}
|
|
157
|
-
],
|
|
158
|
-
|
|
159
|
-
getHL7V2DataType: function(lformsDataType) {
|
|
160
|
-
|
|
161
|
-
var ret;
|
|
162
|
-
switch (lformsDataType) {
|
|
163
|
-
case "INT":
|
|
164
|
-
case "REAL":
|
|
165
|
-
case "QTY":
|
|
166
|
-
ret = "NM";
|
|
167
|
-
break;
|
|
168
|
-
case "NR":
|
|
169
|
-
case "TX":
|
|
170
|
-
case "DT":
|
|
171
|
-
case "DTM":
|
|
172
|
-
case "TM":
|
|
173
|
-
case "CNE":
|
|
174
|
-
case "CWE":
|
|
175
|
-
ret = lformsDataType;
|
|
176
|
-
break;
|
|
177
|
-
// Commenting out these cases which are handled by the default, but
|
|
178
|
-
// leaving them here for reference.
|
|
179
|
-
/*
|
|
180
|
-
case "BIN":
|
|
181
|
-
case "RTO":
|
|
182
|
-
case "YEAR":
|
|
183
|
-
case "MONTH":
|
|
184
|
-
case "DAY":
|
|
185
|
-
case "URL":
|
|
186
|
-
case "EMAIL":
|
|
187
|
-
case "PHONE":
|
|
188
|
-
case "BL":
|
|
189
|
-
case "":
|
|
190
|
-
case "ST":
|
|
191
|
-
ret = "ST";
|
|
192
|
-
break; */
|
|
193
|
-
default:
|
|
194
|
-
ret = "ST";
|
|
195
|
-
}
|
|
196
|
-
|
|
197
|
-
return ret;
|
|
198
|
-
},
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
// create HL7 OBR and OBX segments only
|
|
202
|
-
/**
|
|
203
|
-
* Convert LForms form data into HL7 OBR and OBX segments
|
|
204
|
-
* @param lfData a LForms form data object
|
|
205
|
-
* @returns {string}
|
|
206
|
-
*/
|
|
207
|
-
toHL7Segments: function(lfData) {
|
|
208
|
-
var hl7String = '';
|
|
209
|
-
var formInfo = {
|
|
210
|
-
obrIndex: 1,
|
|
211
|
-
obxIndex: 1
|
|
212
|
-
};
|
|
213
|
-
|
|
214
|
-
// get form data with questions that have no values
|
|
215
|
-
var formData = lfData.getFormData(false, true);
|
|
216
|
-
|
|
217
|
-
this._generateOBX4(formData);
|
|
218
|
-
|
|
219
|
-
// form level info
|
|
220
|
-
var formObrArray = new Array(this.obrFieldNum); // initial value is undefined
|
|
221
|
-
// index = seq - 1
|
|
222
|
-
formObrArray[0] = "OBR";
|
|
223
|
-
formObrArray[1] = "1";
|
|
224
|
-
formObrArray[4] = formData.code + this.delimiters.component + formData.name + this.delimiters.component + this.LOINC_CS;
|
|
225
|
-
|
|
226
|
-
if (formData.templateOptions.formHeaderItems &&
|
|
227
|
-
formData.templateOptions.formHeaderItems.length > 0) {
|
|
228
|
-
for (var i= 0, iLen=formData.templateOptions.formHeaderItems.length; i< iLen; i++) {
|
|
229
|
-
if (formData.templateOptions.formHeaderItems[i].questionCode === "date_done" &&
|
|
230
|
-
formData.templateOptions.formHeaderItems[i].value) {
|
|
231
|
-
formObrArray[7] = LForms.Util.formatDate(formData.templateOptions.formHeaderItems[i].value, this._DTM_FMT);
|
|
232
|
-
}
|
|
233
|
-
else if (formData.templateOptions.formHeaderItems[i].questionCode === "where_done" &&
|
|
234
|
-
formData.templateOptions.formHeaderItems[i].value) {
|
|
235
|
-
formObrArray[13] = formData.templateOptions.formHeaderItems[i].value.text;
|
|
236
|
-
}
|
|
237
|
-
}
|
|
238
|
-
}
|
|
239
|
-
|
|
240
|
-
// ignore ending empty fields
|
|
241
|
-
var foundValue = false;
|
|
242
|
-
for(var i=this.obrFieldNum-1; i>=0; i--) {
|
|
243
|
-
if (!foundValue && formObrArray[i] === undefined) {
|
|
244
|
-
continue;
|
|
245
|
-
}
|
|
246
|
-
else if (formObrArray[i] !== undefined) {
|
|
247
|
-
hl7String = formObrArray[i] + this.delimiters.field + hl7String;
|
|
248
|
-
}
|
|
249
|
-
else {
|
|
250
|
-
hl7String += this.delimiters.field;
|
|
251
|
-
}
|
|
252
|
-
}
|
|
253
|
-
hl7String += this.delimiters.segment;
|
|
254
|
-
|
|
255
|
-
// process the questions/sections
|
|
256
|
-
if (formData.items) {
|
|
257
|
-
var obxIndex = 0;
|
|
258
|
-
for (var j = 0, jLen = formData.items.length; j < jLen; j++) {
|
|
259
|
-
if (formData.items[j].dataType !== "TITLE") {
|
|
260
|
-
// Note: OBX1 value is not reset for sub panels in the current design.
|
|
261
|
-
// if (formData.items[j].header) {
|
|
262
|
-
// formInfo.obxIndex = 1;
|
|
263
|
-
// }
|
|
264
|
-
hl7String += this._itemToHL7v2(formData.items[j], formInfo);
|
|
265
|
-
}
|
|
266
|
-
}
|
|
267
|
-
}
|
|
268
|
-
return hl7String;
|
|
269
|
-
},
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
/**
|
|
273
|
-
* Calculate OBX4 values of each item in the form
|
|
274
|
-
* @param formData form data that also includes user data
|
|
275
|
-
* @private
|
|
276
|
-
*/
|
|
277
|
-
_generateOBX4: function(formData) {
|
|
278
|
-
|
|
279
|
-
if (formData && formData.items) {
|
|
280
|
-
this._precessOBX4AtOneLevel("", formData.items)
|
|
281
|
-
}
|
|
282
|
-
},
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
/**
|
|
286
|
-
* Calculate OBX4 values for questions/sections at one level
|
|
287
|
-
* @param parentOBX4 the containing section item's obx4 value
|
|
288
|
-
* @param items, the list of items at the level
|
|
289
|
-
* @private
|
|
290
|
-
*/
|
|
291
|
-
_precessOBX4AtOneLevel: function(parentOBX4, items) {
|
|
292
|
-
var sectionSN = 0;
|
|
293
|
-
var repeatingIndex = 1;
|
|
294
|
-
var prevItem = null;
|
|
295
|
-
// go through questions/sections from top to bottom
|
|
296
|
-
for (var i=0, iLen=items.length; i<iLen; i++) {
|
|
297
|
-
var item = items[i];
|
|
298
|
-
// if it's a section
|
|
299
|
-
if (item.dataType === "SECTION") {
|
|
300
|
-
|
|
301
|
-
// if it repeats
|
|
302
|
-
var max = item.questionCardinality.max;
|
|
303
|
-
if (max && (max === "*" || parseInt(max) > 1)) {
|
|
304
|
-
// skip if all questions within it have no values
|
|
305
|
-
if (!this._isSectionEmpty(item)) {
|
|
306
|
-
// get the repeating instance letter
|
|
307
|
-
if (!prevItem || prevItem && prevItem.questionCode !== item.questionCode) {
|
|
308
|
-
repeatingIndex = 1;
|
|
309
|
-
sectionSN += 1;
|
|
310
|
-
}
|
|
311
|
-
else {
|
|
312
|
-
repeatingIndex +=1;
|
|
313
|
-
}
|
|
314
|
-
var repeatingLetter = LForms.Util.getNextLetter(repeatingIndex);
|
|
315
|
-
item._obx4 = parentOBX4 ? parentOBX4 + "." + sectionSN + repeatingLetter : sectionSN + repeatingLetter;
|
|
316
|
-
this._precessOBX4AtOneLevel(item._obx4, item.items);
|
|
317
|
-
}
|
|
318
|
-
// skip if it is an empty section, not to set prevItem
|
|
319
|
-
else {
|
|
320
|
-
continue;
|
|
321
|
-
}
|
|
322
|
-
}
|
|
323
|
-
// if it does not repeat
|
|
324
|
-
// Note: not to skip even if all questions within is has no values,
|
|
325
|
-
// because the SN still increases in this case.
|
|
326
|
-
else {
|
|
327
|
-
repeatingIndex = 1;
|
|
328
|
-
sectionSN += 1;
|
|
329
|
-
item._obx4 = parentOBX4 ? parentOBX4 + "." + sectionSN: sectionSN;
|
|
330
|
-
this._precessOBX4AtOneLevel(item._obx4, item.items);
|
|
331
|
-
}
|
|
332
|
-
}
|
|
333
|
-
// if it's a question
|
|
334
|
-
else{
|
|
335
|
-
// if it repeats
|
|
336
|
-
var max = item.questionCardinality.max;
|
|
337
|
-
if (max && (max === "*" || parseInt(max) > 1)) {
|
|
338
|
-
// if it has value
|
|
339
|
-
if (!LForms.Util.isItemValueEmpty(item.value)) {
|
|
340
|
-
// get the repeating instance letter
|
|
341
|
-
if (!prevItem || prevItem && prevItem.questionCode !== item.questionCode) {
|
|
342
|
-
repeatingIndex = 1;
|
|
343
|
-
}
|
|
344
|
-
else {
|
|
345
|
-
repeatingIndex += 1;
|
|
346
|
-
}
|
|
347
|
-
var repeatingLetter = LForms.Util.getNextLetter(repeatingIndex);
|
|
348
|
-
item._obx4 = parentOBX4 ? parentOBX4 + "." + repeatingLetter : repeatingLetter;
|
|
349
|
-
}
|
|
350
|
-
// skip if it has no values, not to set prevItem
|
|
351
|
-
else {
|
|
352
|
-
continue;
|
|
353
|
-
}
|
|
354
|
-
}
|
|
355
|
-
// if it does not repeat
|
|
356
|
-
else {
|
|
357
|
-
item._obx4 = parentOBX4 ? parentOBX4 : "";
|
|
358
|
-
repeatingIndex = 1;
|
|
359
|
-
}
|
|
360
|
-
|
|
361
|
-
}
|
|
362
|
-
prevItem = item;
|
|
363
|
-
}
|
|
364
|
-
},
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
/**
|
|
368
|
-
* Constructs an OBX5 for a list item (CNE/CWE)
|
|
369
|
-
* @param itemVal a value for a list item
|
|
370
|
-
* @param dataType the data type of the item (CNE or CWE)
|
|
371
|
-
* @return the OBX5 field string
|
|
372
|
-
*/
|
|
373
|
-
_generateOBX5: function(itemVal, dataType, answerCS) {
|
|
374
|
-
var rtn;
|
|
375
|
-
var code = itemVal.code;
|
|
376
|
-
if (dataType === 'CWE' && !code && code !== 0) {
|
|
377
|
-
// For non-coded values, the text goes in OBX 5.9
|
|
378
|
-
rtn = this.delimiters.component.repeat(8) + itemVal.text;
|
|
379
|
-
}
|
|
380
|
-
else {
|
|
381
|
-
var answerCS = !itemVal.system ? "" : (itemVal.system === 'LOINC' || itemVal.system === LOINC_URI) ?
|
|
382
|
-
this.LOINC_CS : itemVal.system;
|
|
383
|
-
rtn = code + this.delimiters.component +
|
|
384
|
-
itemVal.text + this.delimiters.component + answerCS;
|
|
385
|
-
}
|
|
386
|
-
return rtn;
|
|
387
|
-
},
|
|
388
|
-
|
|
389
|
-
_DT_FMT: 'YYYYMMDD',
|
|
390
|
-
_DTM_FMT: 'YYYYMMDDHHmmss',
|
|
391
|
-
/**
|
|
392
|
-
* Convert an item to one or more HL7 v2 OBX records.
|
|
393
|
-
* @param item an item in LForms form data
|
|
394
|
-
* @param formInfo index info of the form
|
|
395
|
-
* @returns {string}
|
|
396
|
-
*/
|
|
397
|
-
_itemToHL7v2: function(item, formInfo) {
|
|
398
|
-
var hl7Seg = "";
|
|
399
|
-
var questionCS = this.LOINC_CS;
|
|
400
|
-
|
|
401
|
-
if (item.dataType !== "TITLE") {
|
|
402
|
-
var itemObrArray = new Array(this.obrFieldNum);
|
|
403
|
-
|
|
404
|
-
// a sub panel
|
|
405
|
-
if (item.header) {
|
|
406
|
-
var obrSeg = "";
|
|
407
|
-
itemObrArray[0] = "OBR";
|
|
408
|
-
itemObrArray[1] = ++formInfo.obrIndex;
|
|
409
|
-
|
|
410
|
-
itemObrArray[4] = item.questionCode + this.delimiters.component +
|
|
411
|
-
item.question + this.delimiters.component + questionCS;
|
|
412
|
-
|
|
413
|
-
// ignore ending empty fields
|
|
414
|
-
var foundValue = false;
|
|
415
|
-
for(var i=this.obrFieldNum-1; i>=0; i--) {
|
|
416
|
-
if (!foundValue && itemObrArray[i] === undefined) {
|
|
417
|
-
continue;
|
|
418
|
-
}
|
|
419
|
-
else if (itemObrArray[i] !== undefined) {
|
|
420
|
-
obrSeg = itemObrArray[i] + this.delimiters.field + obrSeg;
|
|
421
|
-
}
|
|
422
|
-
else {
|
|
423
|
-
obrSeg += this.delimiters.field;
|
|
424
|
-
}
|
|
425
|
-
}
|
|
426
|
-
obrSeg += this.delimiters.segment;
|
|
427
|
-
|
|
428
|
-
//// Note: not to add obr segments for now.
|
|
429
|
-
//hl7Seg += obrSeg;
|
|
430
|
-
|
|
431
|
-
if(item.items) {
|
|
432
|
-
var obxIndex = 0;
|
|
433
|
-
for(var j=0, jLen=item.items.length; j<jLen; j++) {
|
|
434
|
-
// Note: OBX1 value is not reset for sub panels in the current design.
|
|
435
|
-
// if (item.items[j].header) {
|
|
436
|
-
// //formInfo.obxIndex = 1;
|
|
437
|
-
// }
|
|
438
|
-
hl7Seg += this._itemToHL7v2(item.items[j], formInfo);
|
|
439
|
-
}
|
|
440
|
-
}
|
|
441
|
-
}
|
|
442
|
-
// a question, only when it has value
|
|
443
|
-
else if (!LForms.Util.isItemValueEmpty(item.value)) {
|
|
444
|
-
var isArrayVal = Array.isArray(item.value);
|
|
445
|
-
var vals = isArrayVal ? item.value : [item.value];
|
|
446
|
-
|
|
447
|
-
var itemObxArray = [];
|
|
448
|
-
itemObxArray[0] = "OBX";
|
|
449
|
-
itemObxArray[1] = formInfo.obxIndex++;
|
|
450
|
-
itemObxArray[2] = this.getHL7V2DataType(item.dataType);
|
|
451
|
-
itemObxArray[3] = item.questionCode + this.delimiters.component +
|
|
452
|
-
item.question + this.delimiters.component + questionCS;
|
|
453
|
-
// unit
|
|
454
|
-
if (item.unit) {
|
|
455
|
-
var unitName ="";
|
|
456
|
-
if (item.unit.name !== undefined) {
|
|
457
|
-
unitName = item.unit.name;
|
|
458
|
-
}
|
|
459
|
-
itemObxArray[6] = unitName + this.delimiters.component + unitName + this.delimiters.component + this.LOINC_CS;
|
|
460
|
-
}
|
|
461
|
-
|
|
462
|
-
for (var i=0, len=vals.length; i<len; ++i) {
|
|
463
|
-
var val = vals[i];
|
|
464
|
-
// OBX4 - sub id
|
|
465
|
-
itemObxArray[4] = item._obx4;
|
|
466
|
-
if (isArrayVal) {
|
|
467
|
-
if (item._obx4 !== '')
|
|
468
|
-
itemObxArray[4] += ".";
|
|
469
|
-
itemObxArray[4] += LForms.Util.getNextLetter(i+1);
|
|
470
|
-
}
|
|
471
|
-
|
|
472
|
-
// OBX5 (answer value)
|
|
473
|
-
if (item.dataType === 'CNE' || item.dataType === 'CWE') {
|
|
474
|
-
itemObxArray[5] = this._generateOBX5(val, item.dataType);
|
|
475
|
-
}
|
|
476
|
-
else if (item.dataType === 'DT' || item.dataType === 'DTM') {
|
|
477
|
-
var dv = (typeof val === 'string')? LForms.Util.stringToDate(val): val;
|
|
478
|
-
itemObxArray[5] = LForms.Util.formatDate(dv, item.dataType === 'DT'? this._DT_FMT: this._DTM_FMT);
|
|
479
|
-
}
|
|
480
|
-
else {
|
|
481
|
-
itemObxArray[5] = val.toString();
|
|
482
|
-
}
|
|
483
|
-
// ignore ending empty fields
|
|
484
|
-
hl7Seg += itemObxArray.join(this.delimiters.field)
|
|
485
|
-
+ this.delimiters.field + this.delimiters.segment;
|
|
486
|
-
}
|
|
487
|
-
|
|
488
|
-
} // if value is not empty
|
|
489
|
-
}
|
|
490
|
-
return hl7Seg;
|
|
491
|
-
},
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
/**
|
|
495
|
-
* Check if all questions within a section have no values
|
|
496
|
-
* @param section a section item
|
|
497
|
-
* @private
|
|
498
|
-
*/
|
|
499
|
-
_isSectionEmpty: function(sectionItem) {
|
|
500
|
-
var empty = true;
|
|
501
|
-
if (sectionItem.items) {
|
|
502
|
-
for(var i=0, iLen=sectionItem.items.length; i<iLen && empty; i++) {
|
|
503
|
-
var item = sectionItem.items[i];
|
|
504
|
-
// sub section
|
|
505
|
-
if (item.dataType === "SECTION") {
|
|
506
|
-
// has been checked already
|
|
507
|
-
if (item._emptySection === true || item._emptySection === false) {
|
|
508
|
-
empty = item._emptySection;
|
|
509
|
-
}
|
|
510
|
-
else {
|
|
511
|
-
empty = this._isSectionEmpty(item);
|
|
512
|
-
}
|
|
513
|
-
}
|
|
514
|
-
// questions
|
|
515
|
-
else {
|
|
516
|
-
empty = LForms.Util.isItemValueEmpty(item.value);
|
|
517
|
-
}
|
|
518
|
-
} // end of for loop
|
|
519
|
-
}
|
|
520
|
-
// set the flag
|
|
521
|
-
sectionItem._emptySection = empty;
|
|
522
|
-
return empty;
|
|
523
|
-
}
|
|
524
|
-
} // return
|
|
525
|
-
})();
|