Skip to content

Commit 3f764c6

Browse files
committed
HACK: switch web, email, tel urls to use embedded /jmp
We were using milestones for web, email, and tel urls, but this didn't work when they were in \s headings. Proskomma doesn't support \jmp yet. Pass these links through as /jmp and convert in ScriptureViewSofria. When Proskomma supports \jmp, switch and remove convertJmp code.
1 parent b882c68 commit 3f764c6

File tree

3 files changed

+51
-75
lines changed

3 files changed

+51
-75
lines changed

convert/convertMarkdown.test.ts

Lines changed: 8 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -15,21 +15,17 @@ describe('convertMarkdownsToMilestones', () => {
1515
});
1616
it('converts a telephone markdown to a milestone', () => {
1717
// Gen 3:14 translates this [TEL](tel:6145551212)
18-
expect(modifiedContent).toContain(
19-
'\\ztellink-s | link="tel%3A6145551212"\\*TEL \\ztellink-e\\*'
20-
);
18+
expect(modifiedContent).toContain('/jmp TEL|href="tel%3A6145551212"/jmp*');
2119
});
2220
it('converts an email markdown to a milestone', () => {
2321
// Gen 3:14 translates this [EMAIL DAVID](mailto:[email protected])
2422
expect(modifiedContent).toContain(
25-
'\\zelink-s | link="mailto%3Adavid_moore1%40sil.org"\\*EMAIL DAVID \\zelink-e\\*'
23+
'/jmp EMAIL DAVID|href="mailto%3Adavid_moore1%40sil.org"/jmp*'
2624
);
2725
});
2826
it('converts a web link markdown to a milestone', () => {
2927
// Gen 3:13 translates this [Web Link](https://www.sil.org/)
30-
expect(modifiedContent).toContain(
31-
'\\zweblink-s | link="https%3A%2F%2Fwww.sil.org%2F"\\*Web Link \\zweblink-e\\*'
32-
);
28+
expect(modifiedContent).toContain('/jmp Web Link|href="https%3A%2F%2Fwww.sil.org%2F"/jmp*');
3329
});
3430
it('adds an empty markdown as text ', () => {
3531
// Gen 3:13 adds [Empty Markdown to text]
@@ -38,31 +34,31 @@ describe('convertMarkdownsToMilestones', () => {
3834
it('converts an audio clip markdown to a milestone', () => {
3935
// Gen 3:12 translates this [Audio](audioclip.mp3)
4036
expect(modifiedContent).toContain(
41-
'\\zaudioc-s | link="audioclip.mp3" \\*Audio \\zaudioc-e\\*'
37+
'\\zaudioc-s |link="audioclip.mp3" \\*Audio\\zaudioc-e\\*'
4238
);
4339
});
4440
it('converts a full reference markdown to a milestone', () => {
4541
// Gen 3:11 translates [Beatitudes](C01.MAT.5.1)
4642
expect(modifiedContent).toContain(
47-
'\\zreflink-s | link="C01.MAT.5.1"\\*Beatitudes \\zreflink-e\\*'
43+
'\\zreflink-s |link="C01.MAT.5.1"\\*Beatitudes\\zreflink-e\\*'
4844
);
4945
});
5046
it('converts a markdown reference without a book collection', () => {
5147
// Gen 3:10 translates [No BC Link](MAT.5.1)
5248
expect(modifiedContent).toContain(
53-
'\\zreflink-s | link="C01.MAT.5.1"\\*No BC Link \\zreflink-e\\*'
49+
'\\zreflink-s |link="C01.MAT.5.1"\\*No BC Link\\zreflink-e\\*'
5450
);
5551
});
5652
it('converts a markdown reference without book collection or verse', () => {
5753
// Gen 3:9 translates [No BC No Verse Link](MAT.5)
5854
expect(modifiedContent).toContain(
59-
'\\zreflink-s | link="C01.MAT.5.1"\\*No BC No Verse Link \\zreflink-e\\*'
55+
'\\zreflink-s |link="C01.MAT.5.1"\\*No BC No Verse Link\\zreflink-e\\*'
6056
);
6157
});
6258
it('converts a markdown reference with just chapter verse', () => {
6359
// Gen 3:8 translates [Just chapter verse](7.1)
6460
expect(modifiedContent).toContain(
65-
'\\zreflink-s | link="C01.GEN.7.1"\\*Just chapter verse \\zreflink-e\\*'
61+
'\\zreflink-s |link="C01.GEN.7.1"\\*Just chapter verse\\zreflink-e\\*'
6662
);
6763
});
6864
});

convert/convertMarkdown.ts

Lines changed: 10 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -143,17 +143,13 @@ function isImageLink(ref: string, excl: string): boolean {
143143
return result;
144144
}
145145
function audioUSFM(link: string, text: string): string {
146-
// \zaudioc-s | link="audioclip.mp3"\*audioclip.mp3\zaudioc-e\*
146+
// \zaudioc-s |link="audioclip.mp3"\*audioclip.mp3\zaudioc-e\*
147147
let result = '';
148148
const refLower = link.toLowerCase();
149149
const ext = getFilenameExt(refLower);
150150
if (ext === 'mp3' || ext === 'wav') {
151151
result =
152-
' \\zaudioc-s | link="' +
153-
encodeURIComponent(link) +
154-
'" \\*' +
155-
text +
156-
' \\zaudioc-e\\* ';
152+
' \\zaudioc-s |link="' + encodeURIComponent(link) + '" \\*' + text + '\\zaudioc-e\\* ';
157153
}
158154
return result;
159155
}
@@ -163,21 +159,18 @@ function imageUSFM(link: string, text: string): string {
163159
return result;
164160
}
165161
function weblinkUSFM(link: string, text: string): string {
166-
// \zweblink-s | link="https://www.sil.org/"\*Web Link \zweblink-e\*
167-
const result =
168-
' \\zweblink-s | link="' + encodeURIComponent(link) + '"\\*' + text + ' \\zweblink-e\\* ';
162+
// HACK: USFM supports web links through \jmp, Proskomma doesn't support \jmp. Pass them through as /jmp in text and process in ScriptureViewSofria.
163+
const result = `/jmp ${text}|href="${encodeURIComponent(link)}"/jmp* `;
169164
return result;
170165
}
171166
function emailUSFM(link: string, text: string): string {
172-
// \zelink-s | link="mailto:[email protected]"\*EMAIL DAVID \zelink-e\*
173-
const result =
174-
' \\zelink-s | link="' + encodeURIComponent(link) + '"\\*' + text + ' \\zelink-e\\* ';
167+
// HACK: USFM supports web links through \jmp, Proskomma doesn't support \jmp. Pass them through as /jmp in text and process in ScriptureViewSofria.
168+
const result = `/jmp ${text}|href="${encodeURIComponent(link)}"/jmp* `;
175169
return result;
176170
}
177171
function telUSFM(link: string, text: string): string {
178-
// \ztellink-s | link="tel:6144323864"\*CAMB \ztellink-e\*
179-
const result =
180-
' \\ztellink-s | link="' + encodeURIComponent(link) + '"\\*' + text + ' \\ztellink-e\\* ';
172+
// HACK: USFM supports web links through \jmp, Proskomma doesn't support \jmp. Pass them through as /jmp in text and process in ScriptureViewSofria.
173+
const result = `/jmp ${text}|href="${encodeURIComponent(link)}"/jmp* `;
181174
return result;
182175
}
183176
function referenceUSFM(link: string, text: string, bcId: string, bookid: string): string {
@@ -208,11 +201,11 @@ function referenceUSFM(link: string, text: string, bcId: string, bookid: string)
208201
const reference =
209202
refCollection + '.' + refBook + '.' + refChapter.toString() + '.' + refVerse.toString();
210203
result =
211-
' \\zreflink-s | link="' +
204+
' \\zreflink-s |link="' +
212205
encodeURIComponent(reference) +
213206
'"\\*' +
214207
text +
215-
' \\zreflink-e\\* ';
208+
'\\zreflink-e\\* ';
216209
}
217210
return result;
218211
}

src/lib/components/ScriptureViewSofria.svelte

Lines changed: 33 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -284,8 +284,7 @@ LOGGING:
284284
spanV.addEventListener('click', onClick, false);
285285
workspace.tableCellElement.appendChild(spanV);
286286
if (i < references.length - 1) {
287-
const textNode = document.createTextNode('; ');
288-
workspace.tableCellElement.appendChild(textNode);
287+
appendTextToElement(workspace.tableCellElement, '; ');
289288
}
290289
}
291290
} else {
@@ -358,6 +357,9 @@ LOGGING:
358357
359358
return callerSymbol;
360359
};
360+
const appendTextToElement = (element: HTMLElement, text: string) => {
361+
element.innerHTML = element.innerHTML + text;
362+
};
361363
const addGraftText = (workspace, text, textType, usfmType) => {
362364
if (workspace.textType.includes(textType)) {
363365
if (isDefined(workspace.footnoteDiv)) {
@@ -452,15 +454,13 @@ LOGGING:
452454
}
453455
aElement.setAttribute('match', matchWord.trim());
454456
aElement.setAttribute('href', ' ');
455-
const refText = document.createTextNode(phrase);
456457
aElement.classList.add('glossary');
457-
aElement.appendChild(refText);
458+
appendTextToElement(aElement, phrase);
458459
spanElement.appendChild(aElement);
459460
break;
460461
}
461462
default: {
462-
child = document.createTextNode(phrase);
463-
spanElement.appendChild(child);
463+
appendTextToElement(spanElement, phrase);
464464
break;
465465
}
466466
}
@@ -475,8 +475,7 @@ LOGGING:
475475
if (workspace.showWordsOfJesus) {
476476
div = usfmSpan(div, usfmWrapperType, phrase);
477477
} else {
478-
const textNode = document.createTextNode(phrase);
479-
div.appendChild(textNode);
478+
appendTextToElement(div, phrase);
480479
}
481480
break;
482481
}
@@ -495,8 +494,7 @@ LOGGING:
495494
}
496495
}
497496
} else {
498-
const textNode = document.createTextNode(phrase);
499-
div.appendChild(textNode);
497+
appendTextToElement(div, phrase);
500498
}
501499
return div;
502500
};
@@ -641,8 +639,7 @@ LOGGING:
641639
glossarySpan.append(block.key);
642640
glossaryDiv.append(glossarySpan);
643641
const blockText = block.text.slice(glossaryLink.length);
644-
const glossaryText = document.createTextNode(blockText);
645-
glossaryDiv.append(glossaryText);
642+
appendTextToElement(glossaryDiv, blockText);
646643
const glossaryHTML = glossaryDiv.outerHTML;
647644
footnotes.push(glossaryHTML);
648645
}
@@ -924,8 +921,7 @@ LOGGING:
924921
textDiv.onclick = (event) => planClicked();
925922
}
926923
textDiv.classList.add(divClass);
927-
const textNode = document.createTextNode(stringId);
928-
textDiv.append(textNode);
924+
appendTextToElement(textDiv, stringId);
929925
progressDiv.append(textDiv);
930926
}
931927
function getPlanReferenceString(ref) {
@@ -1164,8 +1160,7 @@ LOGGING:
11641160
divFigureText.classList.add('caption');
11651161
const spanFigureText = document.createElement('span');
11661162
spanFigureText.classList.add('caption');
1167-
const spanFigureTextNode = document.createTextNode(caption);
1168-
spanFigureText.append(spanFigureTextNode);
1163+
appendTextToElement(spanFigureText, caption);
11691164
divFigureText.append(spanFigureText);
11701165
return divFigureText;
11711166
}
@@ -1735,11 +1730,10 @@ LOGGING:
17351730
workspace.titleGraft
17361731
)
17371732
) {
1738-
const text = context.sequences[0].element.text;
1733+
const text = convertJmp(context.sequences[0].element.text);
17391734
switch (currentTextType(workspace)) {
17401735
case 'title': {
1741-
const child = document.createTextNode(text);
1742-
workspace.titleSpan.append(child);
1736+
appendTextToElement(workspace.titleSpan, text);
17431737
break;
17441738
}
17451739
case 'heading': {
@@ -1750,8 +1744,7 @@ LOGGING:
17501744
// which contain references inline
17511745
workspace.headerInnerDiv.innerHTML = refText;
17521746
} else {
1753-
const child = document.createTextNode(text);
1754-
workspace.headerInnerDiv.appendChild(child);
1747+
appendTextToElement(workspace.headerInnerDiv, text);
17551748
}
17561749
break;
17571750
}
@@ -1766,10 +1759,7 @@ LOGGING:
17661759
break;
17671760
}
17681761
case 'audioc':
1769-
case 'reflink':
1770-
case 'tellink':
1771-
case 'elink':
1772-
case 'weblink': {
1762+
case 'reflink': {
17731763
workspace.milestoneText = text;
17741764
break;
17751765
}
@@ -2297,27 +2287,6 @@ LOGGING:
22972287
);
22982288
break;
22992289
}
2300-
case 'usfm:zweblink': {
2301-
workspace.textType.push('weblink');
2302-
workspace.milestoneLink = decodeURIComponent(
2303-
element.atts['link'][0]
2304-
);
2305-
break;
2306-
}
2307-
case 'usfm:ztellink': {
2308-
workspace.textType.push('tellink');
2309-
workspace.milestoneLink = decodeURIComponent(
2310-
element.atts['link'][0]
2311-
);
2312-
break;
2313-
}
2314-
case 'usfm:zelink': {
2315-
workspace.textType.push('elink');
2316-
workspace.milestoneLink = decodeURIComponent(
2317-
element.atts['link'][0]
2318-
);
2319-
break;
2320-
}
23212290
default: {
23222291
break;
23232292
}
@@ -2425,6 +2394,24 @@ LOGGING:
24252394
}
24262395
};
24272396
2397+
function convertJmp(text: string): string {
2398+
return text.replace(
2399+
/\/jmp ([^|]+)\| href="([^"]+)"\/jmp\*/g,
2400+
(_match, url, encodedHref) => {
2401+
const decodedHref = decodeURIComponent(encodedHref);
2402+
2403+
const className = decodedHref.startsWith('mailto')
2404+
? 'email-link'
2405+
: decodedHref.startsWith('tel')
2406+
? 'tel-link'
2407+
: 'web-link';
2408+
const attributes =
2409+
className === 'web-link' ? 'target="_blank" rel="noreferrer"' : '';
2410+
return `<a ${attributes} class="${className}" href="${decodedHref}">${url}</a>`;
2411+
}
2412+
);
2413+
}
2414+
24282415
function videosForChapter(docSet: string, bookCode: string, chapter: string) {
24292416
let collection = docSet.split('_')[1];
24302417
let videos = config.videos?.filter(

0 commit comments

Comments
 (0)