diff --git a/web/templates/entry_edit.html b/web/templates/entry_edit.html
index 0423b23..3963cc7 100644
--- a/web/templates/entry_edit.html
+++ b/web/templates/entry_edit.html
@@ -212,7 +212,21 @@
["jude","Jude"],["revelation","Re"]
]);
- // Numbered-series acceptance (prose abbreviations like "2 Sam.", "1 Chron.", "2 Cor.", "1 Thes.", "2 Tim.", "1 Pet.", "1 Jn.")
+ // Common short full-name forms (with or without period) → WOL code
+ const ALIAS = new Map([
+ // OT shorts
+ ["gen","Ge"],["exod","Ex"],["lev","Le"],["num","Nu"],["deut","De"],
+ ["josh","Jos"],["judg","Jg"],["ps","Ps"],["prov","Pr"],["eccl","Ec"],["song","Ca"],["cant","Ca"],
+ ["isa","Isa"],["jer","Jer"],["lam","La"],["ezek","Eze"],["dan","Da"],["hos","Ho"],["joel","Joe"],
+ ["amos","Am"],["obad","Ob"],["jon","Jon"],["mic","Mic"],["nah","Na"],["hab","Hab"],["zeph","Zep"],
+ ["hag","Hag"],["zech","Zec"],["mal","Mal"],
+ // NT shorts
+ ["matt","Mt"],["mark","Mr"],["luke","Lu"],["john","Joh"],["acts","Ac"],["rom","Ro"],
+ ["gal","Ga"],["eph","Eph"],["phil","Php"],["col","Col"],["heb","Heb"],["jas","Jas"],
+ ["jude","Jude"],["rev","Re"]
+ ]);
+
+ // Numbered-series prose forms like "2 Sam.", "1 Chron.", "2 Cor.", "1 Thes.", "2 Tim.", "1 Pet.", "1 Jn."
const NUMBERED = [
{ prefixes: ["sam","samu","samuel"], codes: {1:"1Sa",2:"2Sa"} },
{ prefixes: ["ki","king","kings","kgs"], codes: {1:"1Ki",2:"2Ki"} },
@@ -231,15 +245,18 @@
}
function lookupBookCode(bookRaw) {
- // Trim and strip trailing period(s), collapse whitespace
+ // 1) trim, strip trailing periods, collapse spaces
let b = bookRaw.trim().replace(/\.+$/, "").replace(/\s+/g, " ");
+ const lower = b.toLowerCase();
- // 1) Full-name match (case-insensitive)
- const fullKey = b.toLowerCase();
- if (FULL.has(fullKey)) return FULL.get(fullKey);
+ // 2) Full-name match
+ if (FULL.has(lower)) return FULL.get(lower);
- // 2) Numbered-series prose abbreviations: e.g., "2 Sam", "1 Chron", "2 Cor", "1 Thes", "2 Tim", "1 Pet", "1 Jn"
- const m = b.toLowerCase().match(/^([1-3])\s*([a-z]+)$/);
+ // 3) Short full-name alias (un-numbered)
+ if (ALIAS.has(lower)) return ALIAS.get(lower);
+
+ // 4) Numbered series, prose short forms (e.g., "2 Sam", "1 Chron", "1 Jn")
+ const m = lower.match(/^([1-3])\s*([a-z]+)$/);
if (m) {
const num = parseInt(m[1], 10);
const base = m[2];
@@ -251,17 +268,19 @@
}
}
- // 3) WOL abbreviation (allow optional space after number and allow trailing period)
+ // 5) WOL abbreviations (allow optional space after number)
const abbr = b.replace(/^([1-3])\s+([A-Za-z]+)/, (_, n, letters) => n + letters);
if (WOL.has(abbr)) return abbr;
- // Also try without spaces just in case
const abbrTight = b.replace(/\s+/g, "");
if (WOL.has(abbrTight)) return abbrTight;
return null;
}
- // Chapter only | chapter:verses | lists | ranges | cross-chapter range
+ // Accept:
+ // - chapter only: "Ps 23"
+ // - chapter:verse list: "1 John 4:8, 16, 19"
+ // - verse ranges and cross-chapter ranges: "Joh 3:16-4:2", "Ro 12:1-3, 5"
const versesRe =
/^(\d{1,3})$|^(\d{1,3}):\s*(\d{1,3}(?:\s*-\s*(?:\d{1,3}|\d{1,3}:\d{1,3}))?(?:\s*,\s*\d{1,3}(?:\s*-\s*(?:\d{1,3}|\d{1,3}:\d{1,3}))?)*)$/;