add strongs support

This commit is contained in:
Jason Wall 2020-07-21 21:15:45 -04:00
parent d74b713c1b
commit 6a8903f905
13 changed files with 413 additions and 29 deletions

View File

@ -9,6 +9,7 @@ import { HttpClientModule } from '@angular/common/http';
import { SearchPage } from './search/components/search-page/search.page';
import { PassageComponent } from './search/components/passage/passage.component';
import { StrongsComponent } from './search/components/strongs/strongs.component';
import { VersePickerModalComponent } from './search/components/verse-picker/verse-picker-modal.component';
import { MatCheckboxModule } from '@angular/material/checkbox';
@ -53,6 +54,7 @@ import { ClipboardModule } from '@angular/cdk/clipboard';
AppComponent,
SearchPage,
PassageComponent,
StrongsComponent,
VersePickerModalComponent,
],
imports: [

View File

@ -22,6 +22,17 @@ export class CardComponent {
constructor(protected elementRef: ElementRef) {}
protected copyToClip(text: string, html: string) {
function listener(e: ClipboardEvent) {
e.clipboardData.setData('text/html', html);
e.clipboardData.setData('text/plain', text);
e.preventDefault();
}
document.addEventListener('copy', listener);
document.execCommand('copy');
document.removeEventListener('copy', listener);
}
close(ev) {
let translate = 'translate3d(200%, 0, 0)';
if (ev != null && ev.direction === 2) {

View File

@ -11,7 +11,7 @@ export interface Error {
readonly msg: string;
}
export type Data = BiblePassageResult;
export type Data = BiblePassageResult | StrongsResult;
export interface DisplaySettings {
readonly showStrongsAsModal: boolean;
@ -25,6 +25,18 @@ export interface DisplaySettings {
readonly showParagraphHeadings: boolean;
}
export type OpenData = {
card: CardItem;
qry: string;
from_search_bar: boolean;
};
export interface HashTable<T> {
readonly [key: string]: T;
}
//#region Pages and Cards
export interface SavedPage {
readonly queries: readonly CardItem[];
readonly title: string;
@ -37,12 +49,6 @@ export interface CardItem {
readonly dict: string;
}
export type OpenData = {
card: CardItem;
qry: string;
from_search_bar: boolean;
};
export class Page {
readonly title: string;
// readonly component: any;
@ -50,6 +56,10 @@ export class Page {
readonly icon?: string;
}
//#endregion
//#region Passage
export interface BiblePassageResult {
readonly cs: readonly BibleParagraphPassage[];
readonly testament: string;
@ -86,6 +96,58 @@ export interface Paragraph {
readonly p: number;
}
export interface HashTable<T> {
readonly [key: string]: T;
//#endregion
//#region Strongs
export type DictionaryType = 'heb' | 'grk';
export interface StrongsResult {
readonly prefix: string;
readonly sn: number;
readonly def: StrongsDefinition;
readonly rmac: RMACDefinition;
readonly crossrefs: StrongsCrossReference;
readonly rmaccode: string;
}
export interface StrongsDefinition {
readonly n: number;
readonly i: string;
readonly tr: string;
readonly de: readonly StrongsDefinitionPart[];
readonly lemma: string;
readonly p: string;
}
export interface StrongsDefinitionPart {
readonly sn: string;
readonly w: string;
}
export interface StrongsCrossReference {
readonly id: string; // strongs id H1|G1
readonly t: string; // strongs testament grk|heb
readonly d: string; // strongs word/data Aaron {ah-ar-ohn'}
readonly ss: readonly [
{
readonly w: string;
readonly rs: readonly [
{
readonly r: string;
}
];
}
];
}
export interface RMACDefinition {
readonly id: string;
readonly d: readonly string[];
}
export interface RMACCrossReference {
readonly i: string;
readonly r: string;
}
//#endregion

View File

@ -46,17 +46,6 @@ export class PassageComponent extends CardComponent implements OnInit {
this.copyToClip(text, html);
}
copyToClip(text: string, html: string) {
function listener(e: ClipboardEvent) {
e.clipboardData.setData('text/html', html);
e.clipboardData.setData('text/plain', text);
e.preventDefault();
}
document.addEventListener('copy', listener);
document.execCommand('copy');
document.removeEventListener('copy', listener);
}
next() {
const lastVerseForEnd = this.ref.Section.end.book.chapters[
parseInt(this.ref.Section.end.chapter, 10)

View File

@ -42,6 +42,12 @@
(onClose)="removeCard(item)"
(onItemClicked)="getItemsNextToCard($event)"
></app-passage>
<app-strongs
*ngIf="isStrongs(item)"
[cardItem]="item"
(onClose)="removeCard(item)"
(onItemClicked)="getItemsNextToCard($event)"
></app-strongs>
</mat-card>
</ng-template>
<ng-template #nocards>

View File

@ -72,15 +72,10 @@ export class SearchPage implements OnInit {
// // its a search term.
// list.push({ qry: q, dict: 'na', type: 'Words' });
} else if (q.search(/(H|G)[0-9]/i) !== -1) {
// // its a strongs lookup
// let dict = q.substring(0, 1);
// if (dict.search(/h/i) !== -1) {
// dict = 'heb';
// } else {
// dict = 'grk';
// }
// q = q.substring(1, q.length);
// list.push({ qry: q, dict, type: 'Strongs' });
// its a strongs lookup
const dict = q.substring(0, 1).search(/h/i) !== -1 ? 'heb' : 'grk';
const strongsNumber = q.substring(1, q.length);
this.appService.getNewStrongs(strongsNumber, dict);
} else {
// its a verse reference.
if (q !== '') {

View File

@ -0,0 +1,84 @@
<div class="card-title passage-title">
<mat-icon aria-hidden="false" aria-label="Strongs Entry Icon"
>article</mat-icon
>
<span *ngIf="cardItem">{{ cardItem.qry }}</span>
<button
mat-icon-button
class="card-close-button"
aria-label="Remove the strongs card from the list"
(click)="close($event)"
>
<mat-icon>cancel</mat-icon>
</button>
</div>
<div class="card-content" *ngIf="cardItem" #strongs>
<div class="strongs-def">
<p>
<b>{{ cardItem.data.def.tr }}</b>
- {{ cardItem.data.def.p }} - {{ cardItem.data.def.lemma }} -
<span *ngFor="let part of cardItem.data.def.de"
><ng-template [ngIf]="part.sn"
><a (click)="openItem(part.sn)">{{ part.sn }}</a></ng-template
><ng-template [ngIf]="part.w"
><span [innerHTML]="part.w"></span></ng-template></span
><br />
</p>
<ng-template [ngIf]="cardItem.data.rmac">
<h2>RMAC</h2>
<b>{{ cardItem.data.rmac.id }}</b>
<br />
<ul>
<li *ngFor="let c of cardItem.data.rmac.d">
{{ c }}
</li>
</ul>
</ng-template>
</div>
<div
class="strongs-cross"
*ngIf="cardItem.data.crossrefs && cardItem.data.crossrefs.ss"
>
<h2>Cross References</h2>
&nbsp;&nbsp;&nbsp;Translated as
{{ cardItem.data.crossrefs.ss.length }} word(s)
<div class="strongs-crossrefs">
<dl>
<dd *ngFor="let wrd of cardItem.data.crossrefs.ss">
<strong>{{ wrd.w }}, {{ wrd.rs.length }}</strong
>:
<span *ngFor="let p of wrd.rs"
><a (click)="openPassage(p.r)">{{ makePassage(p.r) }}</a
>,
</span>
</dd>
</dl>
</div>
</div>
</div>
<div class="card-actions">
<span class="card-actions-left">
<button
mat-icon-button
aria-label="Remove the passage card from the list"
(click)="close($event)"
>
<mat-icon>cancel</mat-icon>
</button>
</span>
<span class="card-actions-right">
<button
mat-icon-button
[matMenuTriggerFor]="moreMenu"
aria-label="Example icon-button with a menu"
>
<mat-icon>more_vert</mat-icon>
</button>
<mat-menu #moreMenu="matMenu">
<button mat-menu-item (click)="copy()">
<mat-icon>content_copy</mat-icon>
<span>Copy Passage</span>
</button>
</mat-menu>
</span>
</div>

View File

@ -0,0 +1,11 @@
.passage-title {
background-color: var(--strongs-color-primary);
}
.card-close-button {
color: var(--strongs-color-accent);
}
.card-actions {
color: var(--strongs-color-primary);
}

View File

@ -0,0 +1,68 @@
import { Component, ElementRef, ViewChild } from '@angular/core';
import { BibleReference } from '../../../common/bible-reference';
import { AppService } from '../../../services/app.service';
import { CardComponent } from '../../../common/card.component';
@Component({
selector: 'app-strongs',
templateUrl: 'strongs.component.html',
styleUrls: ['./strongs.component.scss'],
preserveWhitespaces: true,
})
export class StrongsComponent extends CardComponent {
@ViewChild('strongs') strongsElement;
constructor(
protected elementRef: ElementRef,
private appService: AppService
) {
super(elementRef);
}
// @HostListener('window:resize', ['$event'])
// onResize(evt) {
// $('strongs ion-scroll').each((i, el) => {
// let len = $(el).find('.scroll-content .scroll-zoom-wrapper dl span')
// .length;
// len += $(el).find('.scroll-content .scroll-zoom-wrapper dl dd').length;
// if (len < 20) $(el).css('height', Math.ceil(len / 3) * 30 + 30);
// });
// }
// ngAfterViewChecked(): void {
// this.onResize(null);
// }
copy() {
const html = this.strongsElement.nativeElement.innerHTML;
const text = this.strongsElement.nativeElement.innerText;
this.copyToClip(text, html);
}
openItem(p: string) {
this.onItemClicked.emit({
card: this.cardItem,
qry: p,
from_search_bar: false,
});
}
makePassage(p: string) {
return (
BibleReference.bookName(parseInt(p.split(';')[0], 10)).name +
' ' +
p.split(';')[1] +
':' +
p.split(';')[2]
);
}
openPassage(p: string) {
const ref = this.makePassage(p);
this.onItemClicked.emit({
card: this.cardItem,
qry: ref,
from_search_bar: false,
});
}
}

View File

@ -12,6 +12,12 @@ import {
BibleParagraph,
BibleParagraphPassage,
CardItem,
DictionaryType,
StrongsResult,
StrongsDefinition,
StrongsCrossReference,
RMACCrossReference,
RMACDefinition,
} from '../models/app-state';
import { Section, BibleReference } from '../common/bible-reference';
import { PageTitles } from '../constants';
@ -178,6 +184,151 @@ export class AppService extends createStateService(reducer, initialState) {
});
}
//#region Strongs
async getNewStrongs(strongsNumber: string, dict: DictionaryType) {
const result = await this.getStrongsFromApi(strongsNumber, dict);
const d = dict === 'grk' ? 'G' : 'H';
const card = {
qry: `${d}${strongsNumber}`,
dict: d,
type: 'Strongs',
data: result,
};
this.dispatch({
type: 'ADD_CARD',
card,
});
}
private async getStrongsFromApi(strongsNumber: string, dict: string) {
const sn = parseInt(strongsNumber, 10);
const result = {
prefix: '',
sn,
def: null,
rmac: null,
crossrefs: null,
rmaccode: '',
};
if (dict === 'grk') {
result.prefix = 'G';
if (sn > 5624 || sn < 1) {
this.dispatch({
type: 'UPDATE_ERROR',
error: {
msg: `Strong's Number G${sn} is out of range. Strong's numbers range from 1 - 5624 in the New Testament.`,
},
});
return;
}
} else {
result.prefix = 'H';
if (sn > 8674 || sn < 1) {
this.dispatch({
type: 'UPDATE_ERROR',
error: {
msg: `Strong's Number H${sn} is out of range. Strong's numbers range from 1 - 8674 in the Old Testament.`,
},
});
return;
}
}
let url = `${dict}${Math.ceil(sn / 100)}.json`;
try {
const d = await this.http
.get<StrongsDefinition[]>('assets/data/strongs/' + url)
.toPromise();
result.def = d.find((el) => el.i === result.prefix + result.sn);
} catch (err) {
this.dispatch({
type: 'UPDATE_ERROR',
error: {
msg: `Unable to retrieve Strong's Data for ${result.prefix}${result.sn}`,
},
});
return;
}
try {
const d = await this.http
.get<StrongsCrossReference[]>(`assets/data/strongscr/cr${url}`)
.toPromise();
for (const cr of d) {
if (cr.id.toUpperCase() === result.prefix + result.sn) {
result.crossrefs = cr;
break;
}
}
} catch (err) {
this.dispatch({
type: 'UPDATE_ERROR',
error: {
msg: `Unable to retrieve Strong\'s Cross References for ${result.prefix}${result.sn}`,
},
});
return;
}
if (dict === 'grk') {
url = `assets/data/rmac/rs${Math.ceil(sn / 1000)}.json`;
let rmacCrossReferences: RMACCrossReference[];
// rmac is a two get process.
try {
const d = await this.http.get<RMACCrossReference[]>(url).toPromise();
rmacCrossReferences = d;
} catch (err) {
this.dispatch({
type: 'UPDATE_ERROR',
error: {
msg: 'Unable to retrieve RMAC',
},
});
return;
}
// deal with RMAC
const tmp = rmacCrossReferences.filter((el, i) => {
return el.i === sn + '';
});
if (tmp.length === 0) {
return result;
}
result.rmaccode = tmp[0].r;
if (result.rmaccode !== undefined) {
url = `assets/data/rmac/r-${result.rmaccode.substring(0, 1)}.json`;
try {
const d = await this.http.get<RMACDefinition[]>(url).toPromise();
for (const rmac of d) {
if (rmac.id.toLowerCase() === result.rmaccode) {
result.rmac = rmac;
break;
}
}
} catch (err) {
this.dispatch({
type: 'UPDATE_ERROR',
error: {
msg: 'Unable to retrieve RMAC',
},
});
return;
}
}
}
return result;
}
//#endregion
//#region Bible Passages
async getNewPassage(ref: BibleReference) {
@ -206,6 +357,7 @@ export class AppService extends createStateService(reducer, initialState) {
data: result,
};
}
private async getPassageFromApi(section: Section) {
try {
const chapters = []; // the verses from the chapter.

Binary file not shown.

Before

Width:  |  Height:  |  Size: 37 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 948 B

After

Width:  |  Height:  |  Size: 37 KiB

View File

@ -12,6 +12,10 @@ html {
--passage-color-primary: rgb(25, 68, 109);
--passage-color-accent: rgb(122, 166, 206);
--passage-heading-font-family: "Roboto Condensed";
--strongs-color-primary: rgb(17, 70, 29);
--strongs-color-accent: rgb(122, 206, 143);
--strongs-heading-font-family: "Roboto Condensed";
}
body {