Skip to content

Commit ac0e877

Browse files
committed
Merge branch 'master' into fix_ci
2 parents c1a1e5b + 4035954 commit ac0e877

21 files changed

+3135
-1697
lines changed

lib/DataHarmonizer.js

+139-51
Original file line numberDiff line numberDiff line change
@@ -125,6 +125,7 @@ class DataHarmonizer {
125125
);
126126
this.columnHelpEntries = options.columnHelpEntries || [
127127
'column',
128+
'slot_uri',
128129
'description',
129130
'guidance',
130131
'examples',
@@ -162,6 +163,7 @@ class DataHarmonizer {
162163

163164
// Reset specify header modal values when the modal is closed
164165
$('#specify-headers-modal').on('hidden.bs.modal', () => {
166+
$('.mapping-row').remove();
165167
$('#specify-headers-err-msg').hide();
166168
$('#specify-headers-confirm-btn').unbind();
167169
});
@@ -176,7 +178,7 @@ class DataHarmonizer {
176178
(field) => field.title === field_reference
177179
);
178180
$('#field-description-text').html(
179-
urlToClickableAnchor(this.getComment(field))
181+
this.getComment(field)
180182
);
181183
$('#field-description-modal').modal('show');
182184
});
@@ -1037,6 +1039,30 @@ class DataHarmonizer {
10371039
hotInstance.render(); // Render the table to apply changes
10381040
}
10391041

1042+
renderSemanticID(curieOrURI, as_markup = false) {
1043+
if (curieOrURI) {
1044+
if (curieOrURI.toLowerCase().startsWith('http')) {
1045+
if (as_markup)
1046+
return `[${curieOrURI}](${curieOrURI})`;
1047+
1048+
return `<a href="${curieOrURI}" target="_blank">${curieOrURI}</a>`;
1049+
}
1050+
else if (curieOrURI.includes(':')) {
1051+
const [prefix, reference] = curieOrURI.split(':',2);
1052+
if (prefix && reference && (prefix in this.schema.prefixes)) {
1053+
// Lookup curie
1054+
let url = this.schema.prefixes[prefix]['prefix_reference'] + reference;
1055+
if (as_markup)
1056+
return `[${curieOrURI}](${url})`;
1057+
return `<a href="${url}" target="_blank">${curieOrURI}</a>`;
1058+
}
1059+
else
1060+
return `${curieOrURI}`;
1061+
}
1062+
}
1063+
return '';
1064+
}
1065+
10401066
/**
10411067
* Presents reference guide in a popup.
10421068
* @param {String} mystyle simple css stylesheet commands to override default.
@@ -1046,6 +1072,7 @@ class DataHarmonizer {
10461072

10471073
let style = `
10481074
body {
1075+
background-color:#fff;
10491076
font-family: arial;
10501077
margin:5% 5% 5% 5%;
10511078
}
@@ -1080,17 +1107,19 @@ class DataHarmonizer {
10801107
let row_html = '';
10811108
for (const section of this.sections) {
10821109
row_html += `<tr class="section">
1083-
<td colspan="${this.columnHelpEntries.length}"><h3>${
1110+
<td colspan="${this.columnHelpEntries.length-1}"><h3>${
10841111
section.title || section.name
10851112
}</h3></td>
10861113
</tr>
10871114
`;
10881115
for (const slot of section.children) {
10891116
const slot_dict = this.getCommentDict(slot);
10901117

1118+
const slot_uri = this.renderSemanticID(slot_dict.slot_uri);
1119+
10911120
row_html += '<tr>';
10921121
if (this.columnHelpEntries.includes('column')) {
1093-
row_html += `<td class="label">${slot_dict.title}</td>`;
1122+
row_html += `<td class="label">${slot_dict.title}<br>${slot_uri}</td>`;
10941123
}
10951124
if (this.columnHelpEntries.includes('description')) {
10961125
row_html += `<td>${slot_dict.description}</td>`;
@@ -1102,38 +1131,62 @@ class DataHarmonizer {
11021131
row_html += `<td>${slot_dict.examples}</td>`;
11031132
}
11041133
if (this.columnHelpEntries.includes('menus')) {
1105-
row_html += ` <td>${slot_dict.sources || ''}</td>`;
1134+
row_html += ` <td>${slot_dict.menus || ''}</td>`;
11061135
}
11071136
row_html += '</tr>';
11081137
}
11091138
}
11101139

1140+
// Note this may include more enumerations than exist in a given template.
1141+
let enum_html = ``;
1142+
for (const key of Object.keys(this.schema.enums).sort()) {
1143+
const enumeration = this.schema.enums[key];
1144+
let title = enumeration.title != enumeration.name ? enumeration.title : '';
1145+
enum_html += `<tr class="section">
1146+
<td colspan="2" id="${enumeration.name}">${enumeration.name}</td>
1147+
<td colspan="2" style="font-size:1.2rem;">"${title}"<br>${this.renderSemanticID(enumeration.enum_uri)}</td>
1148+
</tr>`;
1149+
1150+
for (const item_key in enumeration.permissible_values) {
1151+
const item = enumeration.permissible_values[item_key];
1152+
let text = item.text != item_key ? item.text : '';
1153+
enum_html += `<tr>
1154+
<td>${this.renderSemanticID(item.meaning)}</td>
1155+
<td>${item_key}</td>
1156+
<td>${text}</td>
1157+
<td></td>
1158+
</tr>`;
1159+
}
1160+
}
1161+
11111162
var win = window.open(
11121163
'',
11131164
'Reference',
1114-
'toolbar=no,location=no,directories=no,status=no,menubar=no,scrollbars=yes,resizable=yes,width=1000,height=600'
1165+
'toolbar=no,location=yes,directories=no,status=no,menubar=no,scrollbars=yes,resizable=yes,width=1000,height=600'
11151166
);
11161167

1117-
win.document.head.innerHTML = `
1118-
<meta charset="utf-8">
1119-
<title>${i18next.t('reference_guide_title')} "${
1168+
win.document.open(); // For reloads
1169+
win.document.write(`<!DOCTYPE html>
1170+
<html lang="en">
1171+
<head>
1172+
<meta charset="utf-8">
1173+
<title>${i18next.t('reference_guide_title')} "${
11201174
schema_template.title || schema_template.name
11211175
}" template</title>
1122-
<meta name="description" content="${schema_template.description || ''}">
1123-
<style>${style}</style>
1124-
`;
1125-
1126-
win.document.body.innerHTML = `
1127-
<div>
1176+
<meta name="description" content="${schema_template.description || ''}">
1177+
<style>${style}</style>
1178+
</head>
1179+
<body>
1180+
<div>
11281181
<h2>${i18next.t('reference_guide_title')} "${
11291182
schema_template.title || schema_template.name
11301183
}" template</h2>
1131-
<hr size="2"/>
1184+
<hr/>
11321185
<p>${schema_template.description || ''}</p>
11331186
11341187
<table>
1135-
<thead>
1136-
<tr>
1188+
<thead>
1189+
<tr>
11371190
${
11381191
this.columnHelpEntries.includes('column')
11391192
? `<th class="label">${i18next.t('help-sidebar__column')}</th>`
@@ -1161,16 +1214,25 @@ class DataHarmonizer {
11611214
? `<th class="data_status">${i18next.t('help-sidebar__menus')}</th>`
11621215
: ''
11631216
}
1164-
</tr>
1165-
</thead>
1166-
<tbody>
1167-
${row_html}
1168-
</tbody>
1169-
</table>
1217+
</tr>
1218+
</thead>
1219+
<tbody>
1220+
${row_html}
1221+
</tbody>
1222+
</table>
11701223
</div>
1171-
</body>
1172-
</html>
1173-
`;
1224+
<div>
1225+
<table>
1226+
<thead>
1227+
<tr class="section">
1228+
<th colspan="4">${i18next.t('help-picklists')}</th>
1229+
</tr>
1230+
</thead>
1231+
<tbody>${enum_html}</tbody>
1232+
</table>
1233+
</div>
1234+
</body>
1235+
</html>`);
11741236
return false;
11751237
}
11761238

@@ -1346,23 +1408,20 @@ class DataHarmonizer {
13461408
let flatHeaders = this.getFlatHeaders();
13471409
const self = this;
13481410
if (flatHeaders) {
1349-
$('#field-mapping').prepend(
1350-
'<col></col>'.repeat(flatHeaders[1].length + 1)
1351-
);
1352-
$('#expected-headers-tr').html(
1353-
'<td><b>Expected second row</b></td> <td>' +
1354-
flatHeaders[1].join('</td><td>') +
1355-
'</td>'
1356-
);
1357-
$('#actual-headers-tr').html(
1358-
'<td><b>Imported second row</b></td> <td>' +
1359-
matrix[1].join('</td><td>') +
1360-
'</td>'
1361-
);
1362-
flatHeaders[1].forEach(function (item, i) {
1363-
if (item != matrix[1][i]) {
1364-
$('#field-mapping col').get(i + 1).style.backgroundColor = 'orange';
1411+
const $fieldMappingBody = $('#field-mapping-body');
1412+
flatHeaders[1].forEach(function (expectedHeader, i) {
1413+
const expectedHeaderCell =
1414+
`<td class="field-mapping-cell">${expectedHeader}</td>`
1415+
const actualHeaderCell =
1416+
`<td class="field-mapping-cell">${matrix[1][i]}</td>`;
1417+
const rowCells = expectedHeaderCell + actualHeaderCell;
1418+
let row;
1419+
if (expectedHeader !== matrix[1][i]) {
1420+
row = $(`<tr class="table-warning mapping-row">${rowCells}</tr>`);
1421+
} else {
1422+
row = $(`<tr class="mapping-row">${rowCells}</tr>`);
13651423
}
1424+
$fieldMappingBody.append(row);
13661425
});
13671426

13681427
$('#specify-headers-modal').modal('show');
@@ -1455,8 +1514,8 @@ class DataHarmonizer {
14551514
// Close current dialog and switch to error message
14561515
//$('specify-headers-modal').modal('hide');
14571516
//$('#unmapped-headers-modal').modal('hide');
1458-
const errMsg = `The template for the loaded file has a configuration error:<br/>
1459-
<strong>${parent.title}</strong><br/>
1517+
const errMsg = `The template for the loaded file has a configuration error:<br>
1518+
<strong>${parent.title}</strong><br>
14601519
This is a field that has no parent, or a section that has no fields.`;
14611520
$('#unmapped-headers-list').html(errMsg);
14621521
$('#unmapped-headers-modal').modal('show');
@@ -1491,8 +1550,16 @@ class DataHarmonizer {
14911550
// Map current column indices to their indices in matrix to map
14921551
const headerMap = {};
14931552
const unmappedHeaders = [];
1494-
for (const [i, expectedVal] of expectedSecondaryHeaders.entries()) {
1553+
for (let [i, expectedVal] of expectedSecondaryHeaders.entries()) {
14951554
headerMap[i] = actualSecondaryHeaders.findIndex((actualVal) => {
1555+
// Case insensitivity
1556+
if (typeof actualVal === 'string' || actualVal instanceof String) {
1557+
actualVal = actualVal.toLowerCase()
1558+
}
1559+
if (typeof expectedVal === 'string' || expectedVal instanceof String) {
1560+
expectedVal = expectedVal.toLowerCase()
1561+
}
1562+
14961563
return actualVal === expectedVal;
14971564
});
14981565
if (headerMap[i] === -1) {
@@ -1868,6 +1935,14 @@ class DataHarmonizer {
18681935
)}</strong>: ${field.title || field.name}</p>`;
18691936
}
18701937

1938+
// Requires markup treatment of URLS.
1939+
const slot_uri = this.renderSemanticID(field.slot_uri);
1940+
if (field.slot_uri && this.columnHelpEntries.includes('slot_uri')) {
1941+
ret += `<p><strong data-i18n="help-sidebar__column">${i18next.t(
1942+
'help-sidebar__slot_uri'
1943+
)}</strong>: ${slot_uri}</p>`;
1944+
}
1945+
18711946
if (field.description && this.columnHelpEntries.includes('description')) {
18721947
ret += `<p><strong data-i18n="help-sidebar__description">${i18next.t(
18731948
'help-sidebar__description'
@@ -1907,10 +1982,12 @@ class DataHarmonizer {
19071982
let guide = {
19081983
title: field.title,
19091984
name: field.name,
1910-
description: field.description || '',
1985+
slot_uri: field.slot_uri,
1986+
description: urlToClickableAnchor(field.description) || '',
19111987
guidance: '',
19121988
examples: '',
19131989
sources: '',
1990+
menus: ''
19141991
};
19151992

19161993
let guidance = [];
@@ -1919,7 +1996,7 @@ class DataHarmonizer {
19191996
}
19201997
if (field.pattern) {
19211998
guidance.push(
1922-
i18next.t('reference_guide_msg_pattern_regex') + ' ' + field.pattern
1999+
i18next.t('reference_guide_msg_pattern_regex') + '<br>' + field.pattern
19232000
);
19242001
}
19252002
if (field.structured_pattern) {
@@ -1955,7 +2032,13 @@ class DataHarmonizer {
19552032
guidance.push(i18next.t('reference_guide_msg_unique_record'));
19562033
}
19572034
if (field.sources && field.sources.length) {
1958-
let sources = [];
2035+
let menus = [];
2036+
for (const item of field.sources) {
2037+
menus.push('<a href="#'+ item + '" target="Reference">' + item +'</a>');
2038+
}
2039+
guide.menus = '<ul><li>' + menus.join('</li><li>') + '</li></ul>';
2040+
/*
2041+
// List null value menu items directly
19592042
for (const [, item] of Object.entries(field.sources)) {
19602043
// List null value menu items directly
19612044
if (item === 'NullValueMenu') {
@@ -1967,7 +2050,8 @@ class DataHarmonizer {
19672050
sources.push(item);
19682051
}
19692052
}
1970-
guide.sources = '<ul><li>' + sources.join('</li>\n<li>') + '</li></ul>';
2053+
*/
2054+
guide.sources = '<ul><li>' + field.sources.join('</li><li>') + '</li></ul>';
19712055
}
19722056
if (field.multivalued) {
19732057
guidance.push(i18next.t('reference_guide_msg_more_than_one_selection'));
@@ -1979,6 +2063,10 @@ class DataHarmonizer {
19792063
})
19802064
.join('\n');
19812065

2066+
// Makes full URIs that aren't in markup into <a href>
2067+
if (guide.guidance)
2068+
guide.guidance = urlToClickableAnchor(guide.guidance);
2069+
19822070
if (field.examples && field.examples.length) {
19832071
let examples = [];
19842072
let first_item = true;
@@ -1994,9 +2082,9 @@ class DataHarmonizer {
19942082

19952083
if (first_item === true) {
19962084
first_item = false;
1997-
examples += '<ul><li>' + i18next.t(item.value) + '</li>\n';
2085+
examples += '<ul><li>' + i18next.t(item.value) + '</li>';
19982086
} else {
1999-
examples += '<li>' + i18next.t(item.value) + '</li>\n';
2087+
examples += '<li>' + i18next.t(item.value) + '</li>';
20002088
}
20012089
}
20022090
guide.examples = examples + '</ul>';

lib/Toolbar.js

+14
Original file line numberDiff line numberDiff line change
@@ -818,6 +818,10 @@ class Toolbar {
818818
for (const dh in this.context.dhs) {
819819
this.context.dhs[dh].renderReference();
820820
}
821+
// Prevents another popup on repeated click if user focuses away from
822+
// previous popup.
823+
return false;
824+
821825
}
822826

823827
showError(prefix, message) {
@@ -862,6 +866,15 @@ class Toolbar {
862866
template_name = Object.keys(schema.classes).find(
863867
(e) => schema.classes[e].is_a === 'dh_interface'
864868
);
869+
// We need to get template name from first Container attributes'
870+
// class's range.
871+
if (!template_name && 'Container' in schema.classes) {
872+
Object.entries(schema.classes.Container.attributes).forEach(([class_name, class_obj]) => {
873+
if (class_obj.range in schema.classes) {
874+
template_name = class_obj.range;
875+
}
876+
});
877+
}
865878
} catch (err) {
866879
console.error(err);
867880
return null;
@@ -1016,6 +1029,7 @@ class Toolbar {
10161029
}
10171030

10181031
setupJumpToModal(dh) {
1032+
10191033
const columnCoordinates = dh.getColumnCoordinates();
10201034

10211035
// Initialize and reset the jump-to input field

0 commit comments

Comments
 (0)