FEATURE: Functioning search is here.

* added saving of state.
 * moved all state into the user profile, this will allow us to load state after a user logs in when we add user accounts later.
This commit is contained in:
walljm 2016-12-27 21:10:00 -05:00
parent dcfb927581
commit 8badd5dfc1
18 changed files with 338 additions and 215 deletions

View File

@ -10,7 +10,8 @@ import {SettingsPage} from "../pages/settings/settings";
@Component({
templateUrl: 'app.html'
})
export class MyApp {
export class MyApp
{
@ViewChild(Nav) nav: Nav;
// make HelloIonicPage the root (or first) page
@ -20,7 +21,8 @@ export class MyApp {
constructor(
public platform: Platform,
public menu: MenuController
) {
)
{
this.initializeApp();
// set our app's pages
@ -30,8 +32,10 @@ export class MyApp {
];
}
initializeApp() {
this.platform.ready().then(() => {
initializeApp()
{
this.platform.ready().then(() =>
{
// Okay, so the platform is ready and our plugins are available.
// Here you can do any higher level native things you might need.
StatusBar.styleDefault();
@ -39,7 +43,8 @@ export class MyApp {
});
}
openPage(page) {
openPage(page)
{
// close the menu when clicking a link from the menu
this.menu.close();
// navigate to the new page if it is not the current page

View File

@ -12,6 +12,7 @@ import {SettingsPage} from "../pages/settings/settings";
import {ComponentLoader} from "../components/component-loader/component-loader.ts";
import {Passage} from "../components/passage/passage.ts";
import {Strongs} from "../components/strongs/strongs.ts";
import {Words} from "../components/words/words.ts";
import {StrongsModal} from "../components/strongs-modal/strongs-modal.ts";
@NgModule({
@ -23,6 +24,7 @@ import {StrongsModal} from "../components/strongs-modal/strongs-modal.ts";
Passage,
Strongs,
StrongsModal,
Words
],
imports: [
IonicModule.forRoot(MyApp),
@ -36,6 +38,7 @@ import {StrongsModal} from "../components/strongs-modal/strongs-modal.ts";
Passage,
Strongs,
StrongsModal,
Words
],
providers: [{ provide: ErrorHandler, useClass: IonicErrorHandler }, Storage]
})

View File

@ -14,3 +14,8 @@
// To declare rules for a specific mode, create a child rule
// for the .md, .ios, or .wp mode classes. The mode class is
// automatically applied to the <body> element in the app.
.item-md {
padding: 0px !important;
padding-left: 16px !important;
}

View File

@ -27,7 +27,8 @@ export class BibleService
};
this.count = Number(section.end.chapter) - Number(section.start.chapter) + 1;
for (let i = Number(section.start.chapter); i <= Number(section.end.chapter); i++) {
for (let i = Number(section.start.chapter); i <= Number(section.end.chapter); i++)
{
const url = "data/bibles/kjv_strongs/" + section.start.book + "-" + i + ".json";
jQuery.ajax({
async: false,
@ -40,7 +41,7 @@ export class BibleService
},
error: function (request, status, error)
{
//Util.HandleError(error);
console.log(error);
}
});
}
@ -91,15 +92,14 @@ export class BibleService
if (section.start.book >= 40)
{
this.result.testament = "new";
} else
{
this.result.testament = "old";
}
return this.result;
} catch (err)
} catch (error)
{
//Util.HandleError(err);
console.log(error);
}
return null;
}

View File

@ -1,11 +0,0 @@
<ion-item class="title" padding>
{{item.prefix}}{{item.sn}}
<button ion-button icon-only item-right large clear (click)="close()">
<ion-icon name="close-circle"></ion-icon>
</button>
</ion-item>
<ion-card-content>
<p>
<b>{{item.def.tr}} ({{item.def.sn}})</b> - {{item.def.p}} - {{item.def.lemma}} - <span [innerHTML]="item.def.de"></span><br />
</p>
</ion-card-content>

View File

@ -1,23 +0,0 @@
import {EventEmitter, Component, Input, Output} from "@angular/core";
@Component({
selector: "search",
templateUrl: "search.html"
})
export class Search {
@Output()
onClose = new EventEmitter<CardItem>();
@Input()
item: SearchResult;
@Input()
cardItem: CardItem;
constructor() {
}
close() {
this.onClose.emit(this.cardItem);
}
}

View File

@ -27,11 +27,10 @@ export class StrongsModal {
this.viewCtrl.dismiss();
}
makePassage(p: string) {
return Reference.bookName(p.split(";")[0]) + ' ' + p.split(";")[1] + ":" + p.split(";")[2];
return Reference.bookName(parseInt(p.split(";")[0])) + ' ' + p.split(";")[1] + ":" + p.split(";")[2];
}
openPassage(p: string) {
let ref = this.makePassage(p);
//this.dismiss();
this.onPassageClicked.emit(ref);
}
}

View File

@ -21,11 +21,12 @@ export class Strongs {
constructor() {
}
close() {
close()
{
this.onClose.emit(this.cardItem);
}
makePassage(p: string) {
return Reference.bookName(p.split(";")[0]) + ' ' + p.split(";")[1] + ":" + p.split(";")[2];
return Reference.bookName(parseInt(p.split(";")[0])) + ' ' + p.split(";")[1] + ":" + p.split(";")[2];
}
openPassage(p: string) {
let ref = this.makePassage(p);

View File

@ -0,0 +1,15 @@
<ion-item class="title" padding>
{{item.refs.length}} results for {{item.word}}
<button ion-button icon-only item-right large clear (click)="close()">
<ion-icon name="close-circle"></ion-icon>
</button>
</ion-item>
<ion-card-content>
<ion-scroll scrollY="true">
<ion-grid>
<ion-row responsive-sm responsive-md wrap *ngFor="let i of getColumns()">
<ion-col width-25 *ngFor="let ref of item.refs | slice:(i*4):(i+1)*4" (click)="openPassage(ref)"><span class="button">{{makePassage(ref)}}</span></ion-col>
</ion-row>
</ion-grid>
</ion-scroll>
</ion-card-content>

View File

@ -0,0 +1,42 @@
import {EventEmitter, Component, Input, Output} from "@angular/core";
import { Reference } from '../../Reference.ts';
@Component({
selector: "words",
templateUrl: "words.html"
})
export class Words {
@Output()
onClose = new EventEmitter<CardItem>();
@Output()
onPassageClicked = new EventEmitter<string>();
@Input()
item: WordLookupResult;
@Input()
cardItem: CardItem;
constructor() {
}
close() {
this.onClose.emit(this.cardItem);
}
getColumns()
{
return Array.from(Array(Math.ceil(this.item.refs.length / 4)).keys())
}
makePassage(p: string)
{
return Reference.bookName(parseInt(p.split(":")[0])) + ' ' + p.split(":")[1] + ":" + p.split(":")[2];
}
openPassage(p: string)
{
let ref = this.makePassage(p);
this.onPassageClicked.emit(ref);
}
}

View File

@ -3,13 +3,14 @@
<button menuToggle large>
<ion-icon name="menu"></ion-icon>
</button>
<ion-searchbar (search)="getQuery($event)" (input)="setQuery($event)"></ion-searchbar>
<ion-searchbar (search)="getQuery($event)" (input)="setQuery($event)" [showCancelButton]="true"></ion-searchbar>
</ion-navbar>
</ion-header>
<ion-content padding class="search-card">
<ion-card *ngFor="let item of items">
<ion-card *ngFor="let item of user.items">
<passage *ngIf="isPassage(item.type)" [cardItem]="item" [item]="item.data" (onClose)="removeItem($event)" [dict]="item.dict" (onStrongsClicked)="getItems($event)"></passage>
<strongs *ngIf="isStrongs(item.type)" [cardItem]="item" [item]="item.data" (onClose)="removeItem($event)" (onPassageClicked)="getItems($event)"></strongs>
<words *ngIf="isWords(item.type)" [cardItem]="item" [item]="item.data" (onClose)="removeItem($event)" (onPassageClicked)="getItems($event)"></words>
<button ion-button icon-left clear small (click)="removeItem(item)">
<ion-icon name="close-circle"></ion-icon>
<div>Close</div>

View File

@ -9,7 +9,7 @@
.search-card {
.title {
background-color: gainsboro;
font-size: 2em;
font-size: 1.4em;
}
a {
@ -27,4 +27,24 @@ body {
.card-md h2 {
font-size: 2rem;
}
ion-scroll {
white-space: nowrap;
height: 250px;
}
ion-col {
//border-bottom: 1px solid #cbcbcb !important;
}
ion-col .button{
background-color: #fbfbfb;
padding: 9px 6px 9px 6px;
width: 100%;
height: 100%;
}
ion-col {
margin-bottom: 0px !important;
}

View File

@ -4,12 +4,15 @@ import {Reference} from "../../Reference";
import {BibleService} from "../../bible-service";
import {LoadingController, ModalController } from "ionic-angular";
import {StrongsService} from "../../strongs-service";
import {WordService} from "../../word-service";
import {Strongs} from "../../components/strongs/strongs";
import {Passage} from "../../components/passage/passage.ts";
import {StrongsModal} from "../../components/strongs-modal/strongs-modal.ts";
import {Storage} from '@ionic/storage';
import {Words} from '../../components/words/words.ts';
class Item {
class Item
{
id: number;
data: any;
type: Type<any>;
@ -18,81 +21,118 @@ class Item {
@Component({
templateUrl: "search.html",
providers: [BibleService, StrongsService],
providers: [BibleService, StrongsService, WordService],
})
export class SearchPage {
export class SearchPage
{
searchQuery: string = "";
items: CardItem[];
last: number;
user: User = { strongs_modal: true };
user: User = { strongs_modal: true, clear_search_after_query: true, items: [] };
constructor(
private strongsService: StrongsService
, private bibleService: BibleService
, private wordService: WordService
, public loadingCtrl: LoadingController
, public modalCtrl: ModalController
, public local: Storage) {
this.initializeItems();
, public local: Storage)
{
// Check if there is a profile saved in local storage
this.local.get('profile').then(profile => {
if (profile === null) {
this.local.get('profile').then(profile =>
{
let t = this.user;
if (profile === null)
this.local.set('profile', JSON.stringify(this.user));
}
else
this.user = JSON.parse(profile);
}).catch(error => {
{
t = JSON.parse(profile);
}
this.initializeItems(t);
}).catch(error =>
{
console.log(error);
});
}
initializeItems() {
this.items = [];
this.last = 0;
initializeItems(u: User)
{
this.last = u.items.length;
this.user = u;
}
presentStrongsModal(strongs: StrongsResult) {
presentStrongsModal(strongs: StrongsResult)
{
let modal = this.modalCtrl.create(StrongsModal, { strongsid: strongs, onPassageClicked: this });
modal.present();
}
setQuery(searchbar) {
setQuery(searchbar)
{
this.searchQuery = searchbar.target.value;
}
getQuery(searchbar) {
getQuery(searchbar)
{
this.getItems(this.searchQuery);
}
removeItem(item) {
let idx = this.items.indexOf(item);
this.items.splice(idx, 1);
removeItem(item)
{
let idx = this.user.items.indexOf(item);
this.user.items.splice(idx, 1);
// save the users settings.
this.saveSettings();
}
isPassage(t: Type<any>) {
return t === Passage;
isPassage(t: string)
{
return t === "Passage";
}
isStrongs(t: Type<any>) {
return t === Strongs;
isStrongs(t: string)
{
return t === "Strongs";
}
getItems(search) {
try {
isWords(t: string)
{
return t === "Words";
}
saveSettings()
{
this.local.set('profile', JSON.stringify(this.user));
}
getItems(search)
{
try
{
let qs = search.split(";");
for (let x in qs) {
if (qs.hasOwnProperty(x)) {
for (let x in qs)
{
if (qs.hasOwnProperty(x))
{
let q = qs[x].trim();
if (q !== "") {
if (q !== "")
{
// its a search term.
if (q.search(/[0-9]/i) === -1) {
// get new results.
//Words.FindReferences(q);
//$("#searchpanel").panel("open");
} else if (q.search(/(H|G)[0-9]/i) !== -1) {
if (q.search(/[0-9]/i) === -1)
{
let result = this.wordService.getResult(q);
this.user.items.unshift({ id: this.last++, data: result, type: "Words", dict: "na" });
}
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) {
if (dict.search(/h/i) !== -1)
{
dict = "heb";
} else {
} else
{
dict = "grk";
}
q = q.substring(1, q.length);
@ -100,25 +140,30 @@ export class SearchPage {
if (this.user.strongs_modal)
this.presentStrongsModal(result);
else
this.items.unshift({ id: this.last++, data: result, type: Strongs, dict: "na" });
} else {
this.user.items.unshift({ id: this.last++, data: result, type: "Strongs", dict: "na" });
}
else
{
// its a verse reference.
if (q.trim() !== "") {
if (q.trim() !== "")
{
let myref = new Reference(q.trim());
let r = this.bibleService.getResult(myref.Section);
r.ref = myref.toString();
this.items.unshift({ id: this.last++, data: r, type: Passage, dict: r.testament == 'new' ? "G" : "H" });
this.user.items.unshift({ id: this.last++, data: r, type: "Passage", dict: r.testament == 'new' ? "G" : "H" });
}
}
}
}
}
//loader.dismiss();
if (this.user.clear_search_after_query)
$(".searchbar-input").val("");
//Settings.SaveResults();
this.saveSettings();
}
catch (err) {
//Util.HandleError(err);
catch (error)
{
console.log(error);
}
}
}

View File

@ -12,4 +12,11 @@
<ion-label>Show Strongs as Modal</ion-label>
<ion-toggle color="dark" [(ngModel)]="user.strongs_modal" (ionChange)="save()"></ion-toggle>
</ion-item>
<ion-item *ngIf="user">
<ion-label>Clear Search Bar after Query</ion-label>
<ion-toggle color="dark" [(ngModel)]="user.clear_search_after_query" (ionChange)="save()"></ion-toggle>
</ion-item>
<ion-item *ngIf="user">
<button ion-button (click)="reset()">Reset Settings</button>
</ion-item>
</ion-content>

View File

@ -7,27 +7,38 @@ import { Storage } from '@ionic/storage';
selector: 'settings',
templateUrl: 'settings.html'
})
export class SettingsPage {
user: User = { strongs_modal: true };
constructor(public navCtrl: NavController, public local: Storage) {
export class SettingsPage
{
user: User = { strongs_modal: true, clear_search_after_query: true, items: [] };
constructor(public navCtrl: NavController, public local: Storage)
{
// Check if there is a profile saved in local storage
this.local.get('profile').then(profile => {
if (profile === null) {
this.local.get('profile').then(profile =>
{
if (profile === null)
this.save();
}
else
this.user = JSON.parse(profile);
}).catch(error => {
}).catch(error =>
{
console.log(error);
});
}
save() {
save()
{
this.local.set('profile', JSON.stringify(this.user));
}
ionViewDidLoad() {
reset()
{
this.user = { strongs_modal: true, clear_search_after_query: true, items: [] };
this.save();
}
ionViewDidLoad()
{
console.log('Hello SettingsPage Page');
}
}

View File

@ -4,124 +4,128 @@ import { Injectable } from "@angular/core";
import { Http } from "@angular/http";
@Injectable()
export class StrongsService {
export class StrongsService
{
result: StrongsResult;
count = 0;
constructor(private http: Http) {
constructor(private http: Http)
{
}
getResult(sn: number, dict: string): StrongsResult
try {
const self = this;
this.result = {
prefix: "",
sn: -1,
strongs: [],
def: null,
rmac: null,
crossrefs: null,
rmaccode: ""
};
let url = dict + Math.ceil(sn / 100) + ".json";
if (dict === "grk")
{
const self = this;
this.result = {
prefix: "",
sn: -1,
strongs: [],
def: null,
rmac: null,
crossrefs: null,
rmaccode: ""
};
let url = dict + Math.ceil(sn / 100) + ".json";
if (dict === "grk")
{
self.result.prefix = "G";
if (sn > 5624) return this.result;
} else
{
self.result.prefix = "H";
if (sn > 8674) return this.result;
}
this.result.sn = sn;
$.ajax({
async: false,
type: "GET",
url: `data/strongs/${url}`,
dataType: "json",
success: function (d: StrongsDefinition[], t, x)
{
self.result.prefix = "G";
if (sn > 5624) return this.result;
} else
self.result.strongs = d;
},
error: function (request, status, error)
{
self.result.prefix = "H";
if (sn > 8674) return this.result;
console.log(error);
}
this.result.sn = sn;
});
$.ajax({
async: false,
type: "GET",
url: `data/strongs/${url}`,
dataType: "json",
success: function (d: StrongsDefinition[], t, x)
{
self.result.strongs = d;
},
error: function (request, status, error)
{
//Util.HandleError(error);
}
});
self.result.def = self.result.strongs.find(el => (el.i === this.result.prefix + this.result.sn));
self.result.strongs = [];
self.result.def = self.result.strongs.find(el => (el.i === this.result.prefix + this.result.sn));
self.result.strongs = [];
$.ajax({
async: false,
type: "GET",
url: `data/strongscr/cr${url}`,
dataType: "json",
success: function (d: StrongsCrossReference[], t, x) {
for (let cr of d) {
if (cr.id.toUpperCase() == self.result.prefix + self.result.sn) {
self.result.crossrefs = cr;
break;
}
}
},
error: function (request, status, error)
{
//Util.HandleError(error);
}
});
if (dict === "grk")
$.ajax({
async: false,
type: "GET",
url: `data/strongscr/cr${url}`,
dataType: "json",
success: function (d: StrongsCrossReference[], t, x)
{
url = `data/rmac/rs${Math.ceil(sn / 1000)}.json`;
let rmac_cross_references: RMACCrossReference[];
for (let cr of d)
{
if (cr.id.toUpperCase() == self.result.prefix + self.result.sn)
{
self.result.crossrefs = cr;
break;
}
}
},
error: function (request, status, error)
{
console.log(error);
}
});
// rmac is a two get process.
if (dict === "grk")
{
url = `data/rmac/rs${Math.ceil(sn / 1000)}.json`;
let rmac_cross_references: RMACCrossReference[];
// rmac is a two get process.
$.ajax({
async: false,
type: "GET",
url: url,
dataType: "json",
success: function (d: RMACCrossReference[], t, x)
{
rmac_cross_references = d;
},
error: function (request, status, error)
{
console.log(error);
}
});
// deal with RMAC
this.result.rmaccode = $.grep<RMACCrossReference>(rmac_cross_references, (el, i) => { if (el.i == sn + "") { return true; } else { return false; } })[0].r;
if (this.result.rmaccode != undefined)
{
url = `data/rmac/r-${this.result.rmaccode.substring(0, 1)}.json`;
$.ajax({
async: false,
type: "GET",
url: url,
dataType: "json",
success: function (d: RMACCrossReference[], t, x)
success: function (d: RMACDefinition[], t, x)
{
rmac_cross_references = d;
for (let rmac of d)
{
if (rmac.id.toLowerCase() == self.result.rmaccode)
{
self.result.rmac = rmac;
break;
}
}
},
error: function (request, status, error)
{
//Util.HandleError(error);
console.log(error);
}
});
// deal with RMAC
this.result.rmaccode = $.grep<RMACCrossReference>(rmac_cross_references, (el, i) => { if (el.i == sn + "") { return true; } else { return false; } })[0].r;
if (this.result.rmaccode != undefined)
{
url = `data/rmac/r-${this.result.rmaccode.substring(0, 1)}.json`;
$.ajax({
async: false,
type: "GET",
url: url,
dataType: "json",
success: function (d: RMACDefinition[], t, x) {
for (let rmac of d) {
if (rmac.id.toLowerCase() == self.result.rmaccode) {
self.result.rmac = rmac;
break;
}
}
},
error: function (request, status, error)
{
//Util.HandleError(error);
}
});
}
}
return this.result;
} catch (err)
{
//Util.HandleError(err);
}
return null;
return this.result;
}
}

View File

@ -1,19 +1,21 @@
type SearchResult = {
type WordLookupResult = {
refs: string[],
word: string,
status: Status,
msg: string
}
enum Status {Success, Failure};
enum Status { Success, Failure };
type IndexResult = {
refs: string[];
word: string;
}
type CardItem = { id: number, data: any, type: any, dict: string}
type CardItem = { id: number, data: any, type: string, dict: string }
type User = {
strongs_modal: boolean
strongs_modal: boolean,
clear_search_after_query: boolean,
items: CardItem[]
}
type BiblePassage = {
@ -36,7 +38,6 @@ type BiblePassageResult = {
ref: string
}
type StrongsDefinition = { n: number, i: string, tr: string, de: string, lemma: string, p: string }
type StrongsCrossReference =
{

View File

@ -4,16 +4,13 @@ import { Injectable } from "@angular/core";
import { Http } from "@angular/http";
@Injectable()
export class SearchService
export class WordService
{
result: SearchResult;
count = 0;
constructor(private http: Http)
{
}
getResult(qry)
getResult(qry: string): WordLookupResult
{
qry = qry.toLowerCase();
let qs = qry.split(" ");
@ -52,20 +49,21 @@ export class SearchService
// that is shared by all of them. IF not, we can just return those refs.
if (results.length == 0)
{
this.result = { word: qry, refs: null, status: Status.Failure, msg: ":)" };
return { word: qry, refs: null, status: 1, msg: ":)" };
}
else if (results.length == 1)
{
this.result = { word: qry, refs: results[0].refs, status: Status.Success, msg: ":)" };
let temp = { word: qry, refs: results[0], status: 0, msg: ":)" };
return temp;
}
else
{
let shared = this.findSharedSet(results);
if (shared == null)
{
this.result = { word: qry, refs: null, status: Status.Failure, msg: "No passages found." };
return { word: qry, refs: null, status: 1, msg: "No passages found." };
}
this.result = { word: qry, refs: shared[0].refs, status: Status.Success, msg: ":)" };
return { word: qry, refs: shared[0], status: 0, msg: ":)" };
}
}
@ -91,7 +89,7 @@ export class SearchService
},
error: function (request, status, error)
{
//Util.HandleError(error);
console.log(error);
}
});