mirror of
https://gitlab.com/walljm/dynamicbible.git
synced 2025-07-23 07:19:50 -04:00
add strongs support
This commit is contained in:
parent
d74b713c1b
commit
6a8903f905
@ -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: [
|
||||
|
@ -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) {
|
||||
|
@ -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
|
||||
|
@ -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)
|
||||
|
@ -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>
|
||||
|
@ -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 !== '') {
|
||||
|
@ -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>
|
||||
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>
|
@ -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);
|
||||
}
|
@ -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,
|
||||
});
|
||||
}
|
||||
}
|
@ -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 |
@ -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 {
|
||||
|
Loading…
x
Reference in New Issue
Block a user