diff --git a/app/db/src/app/app.module.ts b/app/db/src/app/app.module.ts index 8b46842a..d8ed9af1 100644 --- a/app/db/src/app/app.module.ts +++ b/app/db/src/app/app.module.ts @@ -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: [ diff --git a/app/db/src/app/common/card.component.ts b/app/db/src/app/common/card.component.ts index 55ac6b84..133f6dad 100644 --- a/app/db/src/app/common/card.component.ts +++ b/app/db/src/app/common/card.component.ts @@ -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) { diff --git a/app/db/src/app/models/app-state.ts b/app/db/src/app/models/app-state.ts index bf7f9308..3028ac76 100644 --- a/app/db/src/app/models/app-state.ts +++ b/app/db/src/app/models/app-state.ts @@ -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 { + 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 { - 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 diff --git a/app/db/src/app/search/components/passage/passage.component.ts b/app/db/src/app/search/components/passage/passage.component.ts index c285c86b..fbf7489c 100644 --- a/app/db/src/app/search/components/passage/passage.component.ts +++ b/app/db/src/app/search/components/passage/passage.component.ts @@ -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) diff --git a/app/db/src/app/search/components/search-page/search.page.html b/app/db/src/app/search/components/search-page/search.page.html index 7b5fe833..bf5af1c2 100644 --- a/app/db/src/app/search/components/search-page/search.page.html +++ b/app/db/src/app/search/components/search-page/search.page.html @@ -42,6 +42,12 @@ (onClose)="removeCard(item)" (onItemClicked)="getItemsNextToCard($event)" > + diff --git a/app/db/src/app/search/components/search-page/search.page.ts b/app/db/src/app/search/components/search-page/search.page.ts index 37d23e2a..347e9cf7 100644 --- a/app/db/src/app/search/components/search-page/search.page.ts +++ b/app/db/src/app/search/components/search-page/search.page.ts @@ -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 !== '') { diff --git a/app/db/src/app/search/components/strongs/strongs.component.html b/app/db/src/app/search/components/strongs/strongs.component.html new file mode 100644 index 00000000..db963920 --- /dev/null +++ b/app/db/src/app/search/components/strongs/strongs.component.html @@ -0,0 +1,84 @@ +
+ article + {{ cardItem.qry }} + +
+
+
+

+ {{ cardItem.data.def.tr }} + - {{ cardItem.data.def.p }} - {{ cardItem.data.def.lemma }} - + {{ part.sn }}
+

+ +

RMAC

+ {{ cardItem.data.rmac.id }} +
+
    +
  • + {{ c }} +
  • +
+
+
+
+

Cross References

+    Translated as + {{ cardItem.data.crossrefs.ss.length }} word(s) +
+
+
+ {{ wrd.w }}, {{ wrd.rs.length }}: + {{ makePassage(p.r) }}, + +
+
+
+
+
+
+ + + + + + + + + +
diff --git a/app/db/src/app/search/components/strongs/strongs.component.scss b/app/db/src/app/search/components/strongs/strongs.component.scss new file mode 100644 index 00000000..0bb9318f --- /dev/null +++ b/app/db/src/app/search/components/strongs/strongs.component.scss @@ -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); +} diff --git a/app/db/src/app/search/components/strongs/strongs.component.ts b/app/db/src/app/search/components/strongs/strongs.component.ts new file mode 100644 index 00000000..aadc864e --- /dev/null +++ b/app/db/src/app/search/components/strongs/strongs.component.ts @@ -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, + }); + } +} diff --git a/app/db/src/app/services/app.service.ts b/app/db/src/app/services/app.service.ts index a365ca63..8d4660de 100644 --- a/app/db/src/app/services/app.service.ts +++ b/app/db/src/app/services/app.service.ts @@ -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('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(`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(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(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. diff --git a/app/db/src/assets/icon/favicon.ico b/app/db/src/assets/icon/favicon.ico deleted file mode 100644 index be4fd22f..00000000 Binary files a/app/db/src/assets/icon/favicon.ico and /dev/null differ diff --git a/app/db/src/favicon.ico b/app/db/src/favicon.ico index 997406ad..be4fd22f 100644 Binary files a/app/db/src/favicon.ico and b/app/db/src/favicon.ico differ diff --git a/app/db/src/styles/app.scss b/app/db/src/styles/app.scss index c97d0a26..a55dbd6b 100644 --- a/app/db/src/styles/app.scss +++ b/app/db/src/styles/app.scss @@ -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 {