PageSourceSearch

https://www.stepbible.org/js/passage_selection.js

js stepbible.org collected 2026-10-02 04:12:17 UTC 30,836 bytes, 636 lines download raw bytes

1window.step = window.step || {};
2step.passageSelect = {
3	version: "ESV_th",
4	userLang: "en",
5	hasEnglishBible: false,
6	modalMode: 'book',
7	lastOsisID: '',
8	lastNumOfChapters: '',
9	bookDisplayNames: {},
10	arrayOfTyplicalBooksChapters: [],
11	osisChapterJsword: [ // Array of OSIS id, number of chapters in the book and the JSword name (if it is different from OSIS id
12		["Gen", 50, [31,25,24,26,32,22,24,22,29,32,32,20,18,24,21,16,27,33,38,18,34,24,20,67,34,35,46,22,35,43,55,32,20,31,29,43,36,30,23,23,57,38,34,34,28,34,31,22,33,26]],
13		["Exo", 40, [22,25,22,31,23,30,25,32,35,29,10,51,22,31,27,36,16,27,25,26,36,31,33,18,40,37,21,43,46,38,18,35,23,35,35,38,29,31,43,38], "Exod"],
14		["Lev", 27, [17,16,17,35,19,30,38,36,24,20,47,8,59,57,33,34,16,30,37,27,24,33,44,23,55,46,34]],
15		["Num", 36, [54,34,51,49,31,27,89,26,23,36,35,16,33,45,41,50,13,32,22,29,35,41,30,25,18,65,23,31,40,16,54,42,56,29,34,13]],
16		["Deu", 34, [46,37,29,49,33,25,26,20,29,22,32,32,18,29,23,22,20,22,21,20,23,30,25,22,19,19,26,68,29,20,30,52,29,12], "Deut"],
17		["Jos", 24, [18,24,17,24,15,27,26,35,27,43,23,24,33,15,63,10,18,28,51,9,45,34,16,33], "Josh"],
18		["Judg", 21, [36,23,31,24,31,40,25,35,57,18,40,15,25,20,20,31,13,31,30,48,25]],
19		["Rut", 4,  [22,23,18,22], "Ruth"],
20		["1Sa", 31, [28,36,21,22,12,21,17,22,27,27,15,25,23,52,35,23,58,30,24,42,15,23,29,22,44,25,12,25,11,31,13], "1Sam"],
21		["2Sa", 24, [27,32,39,12,25,23,29,18,13,19,27,31,39,33,37,23,29,33,43,26,22,51,39,25], "2Sam"],
22		["1Ki", 22, [53,46,28,34,18,38,51,66,28,29,43,33,34,31,34,34,24,46,21,43,29,53], "1Kgs"],
23		["2Ki", 25, [18,25,27,44,27,33,20,29,37,36,21,21,25,29,38,20,41,37,37,21,26,20,37,20,30], "2Kgs"],
24		["1Ch", 29, [54,55,24,43,26,81,40,40,44,14,47,40,14,17,29,43,27,17,19,8,30,19,32,31,31,32,34,21,30], "1Chr"],
25		["2Ch", 36, [17,18,17,22,14,42,22,18,31,19,23,16,22,15,19,14,19,34,11,37,20,12,21,27,28,23,9,27,36,27,21,33,25,33,27,23], "2Chr"],
26		["Ezr", 10, [11,70,13,24,17,22,28,36,15,44], "Ezra"],
27		["Neh", 13, [11,20,32,23,19,19,73,18,38,39,36,47,31]],
28		["Est", 10, [22,23,15,17,14,14,10,17,32,3], "Esth"],
29		["Job", 42, [22,13,26,21,27,30,21,22,35,22,20,25,28,22,35,22,16,21,29,29,34,30,17,25,6,14,23,28,25,31,40,22,33,37,16,33,24,41,30,24,34,17]],
30		["Psa", 150, [6,12,8,8,12,10,17,9,20,18,7,8,6,7,5,11,15,50,14,9,13,31,6,10,22,12,14,9,11,12,24,11,22,22,28,12,40,22,13,17,13,11,5,26,17,11,9,14,20,23,19,9,6,7,23,13,11,11,17,12,8,12,11,10,13,20,7,35,36,5,24,20,28,23,10,12,20,72,13,19,16,8,18,12,13,17,7,18,52,17,16,15,5,23,11,13,12,9,9,5,8,28,22,35,45,48,43,13,31,7,10,10,9,8,18,19,2,29,176,7,8,9,4,8,5,6,5,6,8,8,3,18,3,3,21,26,9,8,24,13,10,7,12,15,21,10,20,14,9,6], "Ps"],
31		["Pro", 31, [33,22,35,27,23,35,27,36,18,32,31,28,25,35,33,33,28,24,29,30,31,29,35,34,28,28,27,28,27,33,31], "Prov"],
32		["Ecc", 12, [18,26,22,16,20,12,29,17,18,20,10,14], "Eccl"],
33		["Song", 8, [17,17,11,16,16,13,13,14]],
34		["Isa", 66, [31,22,26,6,30,13,25,22,21,34,16,6,22,32,9,14,14,7,25,6,17,25,18,23,12,21,13,29,24,33,9,20,24,17,10,22,38,22,8,31,29,25,28,28,25,13,15,22,26,11,23,15,12,17,13,12,21,14,21,22,11,12,19,12,25,24]],
35		["Jer", 52, [19,37,25,31,31,30,34,22,26,25,23,17,27,22,21,21,27,23,15,18,14,30,40,10,38,24,22,17,32,24,40,44,26,22,19,32,21,28,18,16,18,22,13,30,5,28,7,47,39,46,64,34]],
36		["Lam", 5, [22,22,66,22,22]],
37		["Eze", 48, [28,10,27,17,17,14,27,18,11,22,25,28,23,23,8,63,24,32,14,49,32,31,49,27,17,21,36,26,21,26,18,32,33,31,15,38,28,23,29,49,26,20,27,31,25,24,23,35], "Ezek"],
38		["Dan", 12, [21,49,30,37,31,28,28,27,27,21,45,13]],
39		["Hos", 14, [11,23,5,19,15,11,16,14,17,15,12,14,16,9]],
40		["Joe", 3, [20,32,21], "Joel"],
41		["Amo", 9, [15,16,15,13,27,14,17,14,15], "Amos"],
42		["Obd", 1, [21], "Obad"],
43		["Jon", 4, [17,10,10,11], "Jonah"],
44		["Mic", 7, [16,13,12,13,15,16,20]],
45		["Nah", 3, [15,13,19]],
46		["Hab", 3, [17,20,19]],
47		["Zep", 3, [18,15,20], "Zeph"],
48		["Hag", 2, [15,23]],
49		["Zec", 14, [21,13,10,14,11,15,14,23,17,12,17,14,9,21], "Zech"],
50		["Mal", 4, [14,17,18,6]],
51		["Mat", 28, [25,23,17,25,48,34,29,34,38,42,30,50,58,36,39,28,27,35,30,34,46,46,39,51,46,75,66,20], "Matt"],
52		["Mar", 16, [45,28,35,41,43,56,37,38,50,52,33,44,37,72,47,20], "Mark"],
53		["Luk", 24, [80,52,38,44,39,49,50,56,62,42,54,59,35,35,32,31,37,43,48,47,38,71,56,53], "Luke"],
54		["Joh", 21, [51,25,36,54,47,71,53,59,41,42,57,50,38,31,27,33,26,40,42,31,25], "John"],
55		["Act", 28, [26,47,26,37,42,15,60,40,43,48,30,25,52,28,41,40,34,28,41,38,40,30,35,27,27,32,44,31], "Acts"],
56		["Rom", 16, [32,29,31,25,21,23,25,39,33,21,36,21,14,23,33,27]],
57		["1Cor", 16, [31,16,23,21,13,20,40,13,27,33,34,31,13,40,58,24]],
58		["2Cor", 13, [24,17,18,18,21,18,16,24,15,18,33,21,14]],
59		["Gal", 6, [24,21,29,31,26,18]],
60		["Eph", 6, [23,22,21,32,33,24]],
61		["Phili", 4, [30,30,21,23], "Phil"],
62		["Col", 4, [29,23,25,18]],
63		["1Th", 5, [10,20,13,18,28], "1Thess"],
64		["2Th", 3, [12,17,18], "2Thess"],
65		["1Ti", 6, [20,15,16,16,25,21], "1Tim"],
66		["2Ti", 4, [18,26,17,22], "2Tim"],
67		["Tit", 3, [16,15,15], "Titus"],
68		["Phile", 1, [25], "Phlm"],
69		["Heb", 13, [14,18,19,16,14,20,28,13,28,39,40,29,25]],
70		["Jam", 5, [27,26,18,17,20], "Jas"],
71		["1Pe", 5, [25,25,22,19,14], "1Pet"],
72		["2Pe", 3, [21,22,18], "2Pet"],
73		["1Jo", 5, [10,29,24,21,21], "1John"],
74		["2Jo", 1, [13], "2John"],
75		["3Jo", 1, [15], "3John"],
76		["Jude", 1, [25]],
77		["Rev", 22, [20,29,22,11,14,17,17,13,21,11,19,17,18,20,8,21,18,24,21,15,27,21]]
78	],
79
80	initPassageSelect: function(summaryMode) {
81        this.version = "ESV_th";
82		this.userLang = step.state.language() || "en-US";
83		this.modalMode = 'book';
84		this.lastOsisID = '';
85		this.lastNumOfChapters = '';
86		this.bookDisplayNames = {};
87		this.arrayOfTyplicalBooksChapters = JSON.parse(__s.list_of_bibles_books);
88		step.util.closeModal('searchSelectionModal');
89		var hideAppend = false;
90		if (step.util.getPassageContainer(step.util.activePassageId()).find(".resultsLabel").text() !== "") {
91			$('#append_to_panel').hide();
92			hideAppend = true;
93		}
94		if (($('.passageContainer.active').width() < 500) || (step.touchDevice && !step.touchWideDevice))
95			$('#displayLocForm').hide();
96		this._displayListOfBooks(summaryMode);
97		if ((typeof step.keyedVersions[this.version] === "object") && 
98			(typeof step.keyedVersions[this.version].hasAllNTOTorBoth === "string") &&
99			(step.keyedVersions[this.version].hasAllNTOTorBoth === " ")) {
100				$("div#passageSelectionModal span#select_verse_number").hide();
101				$("div#passageSelectionModal div.onoffswitch2.append.pull-right").hide();
102
103		}
104		$("textarea#enterYourPassage").on('input', function(e){
105			step.passageSelect._handleKeyboardEntry(e);
106		});
107	},
108
109	_handleKeyboardEntry: function(e) {
110		var input = $('textarea#enterYourPassage').val();
111		var returnKey = (input.slice(-1) === "\n") || (e.originalEvent.inputType === "insertLineBreak");
112		input = input.replace(/[\n\r]/g, '').replace(/[\t]/g, ' ').replace(/\s\s+/g, ' ').replace(/,,/g, ',').replace(/^\s+/g, '')
113		input = input.replace(/[–—]/g, '-'); // replace n-dash and m-dash with hyphen
114		$("td").css("background-color", "var(--clrBackground)");
115		var lastPassageEntered  = input.replace(/\s+$/g, '').split(/,|;/);
116		lastPassageEntered  = lastPassageEntered[lastPassageEntered.length -1].replace(/^\s+/g, '').replace(/\s+$/g, '');
117		var firstWord = lastPassageEntered.split(/\.|:|\s/)[0].toLowerCase();
118		if (firstWord.length > 0) {
119			if (firstWord === "jas") firstWord = "jam";
120			else if (firstWord === "obd") firstWord = "obad";
121			else if ((firstWord === "phi") || (firstWord === "phil")) firstWord = "ph(il|lm)"; // Can be either Philippians or Philemon
122			else if (firstWord.length > 3) {
123				for (var i = 0; i < this.arrayOfTyplicalBooksChapters.length; i ++) {
124					var checkString = this.arrayOfTyplicalBooksChapters[i][0].toLowerCase();
125					var first2Char = checkString.substr(0, 2);
126					if ((first2Char === "1 ") || (first2Char === "2 ") || (first2Char === "3 "))
127						checkString = checkString.substr(0,1) + checkString.substr(2);
128					if (checkString.indexOf(firstWord) == 0) {
129						firstWord = (this.osisChapterJsword[i].length == 4) ? this.osisChapterJsword[i][3] : this.osisChapterJsword[i][0];
130						firstWord = firstWord.toLowerCase();
131						break;
132					}
133				}
134			}
135			var regex1 = RegExp("^" + firstWord, "i")
136			$("td").filter(function () { return regex1.test($(this).text());}).css("background-color", "fafad2");
137		}
138		if (returnKey) this._handleEnteredPassage(false, input); // 13 is return
139		else if ((e.originalEvent.inputType === "insertText") && (e.originalEvent.data === ",")) this._handleEnteredPassage(true, input); // user entered a comma
140		else if ( (e.originalEvent.inputType === "deleteContentBackward") ||
141			((e.originalEvent.inputType === "insertText") && (e.originalEvent.data === ".")) ) $('#userEnterPassageError').text(""); // 8 is backspace, 46 is .
142	},
143
144	_displayListOfBooks: function(summaryMode) {
145        $('#bookchaptermodalbody').empty();
146		translationType = this._getTranslationType();
147		var html = this._buildBookHeaderAndSkeleton(summaryMode);
148		$('#bookchaptermodalbody').append(html);
149		$('#keyboardEntry').show();
150		this._buildBookTable(summaryMode, translationType);
151		$('#pssgModalBackButton').hide();
152	},
153
154	_buildBookTable: function(summaryMode, translationType) {
155		$('#enterYourPassage').show();
156		if (((this.userLang.toLowerCase().indexOf("en") == 0) || (this.userLang.toLowerCase().indexOf("es") == 0) || (this.userLang.toLowerCase().indexOf("zh") == 0)) &&
157			(translationType !== "")) {
158			this._buildBookHTMLTable(translationType, summaryMode);
159		}
160		else {
161			var url = SEARCH_AUTO_SUGGESTIONS + "%20%20/" + EXAMPLE_DATA + "%3D" + REFERENCE + URL_SEPARATOR + LIMIT + "%3D" + REFERENCE + URL_SEPARATOR + VERSION + "%3D" + this.version + URL_SEPARATOR + "?lang=" + this.userLang;
162			$.getJSON(url, function (data) {
163				step.passageSelect._buildBookHTMLTable(data, summaryMode);
164			}).fail(function() {
165                changeBaseURL();
166            });
167		}	
168	},
169
170	_getTranslationType: function() {
171		var versionAltName = '';
172		var atLeastOneEnglishBible = false;
173		var data = step.util.activePassage().get("searchTokens") || [];
174		var foundFirstVersion = false;
175		for (var i = 0; i < data.length; i++) {
176			if (data[i].itemType == VERSION) {
177				if (!foundFirstVersion) {
178					this.version = data[i].item.initials;
179					versionAltName = data[i].item.shortInitials;
180					foundFirstVersion = true;
181				}
182				if (!atLeastOneEnglishBible)
183					atLeastOneEnglishBible = ((typeof step.keyedVersions[data[i].item.initials] === "object") &&
184									  (step.keyedVersions[data[i].item.initials].languageCode === "en"));
185			}
186		}
187		this.hasEnglishBible = atLeastOneEnglishBible;
188		var versionName = this.version.replace(/_sb$/, "").replace(/_th$/, "");
189		versionAltName = versionAltName.replace(/_sb$/, "").replace(/_th$/, "");
190		var hasAllNTOTorBoth = "";
191		if (typeof step.keyedVersions[versionName] === "object")
192			hasAllNTOTorBoth = step.keyedVersions[versionName].hasAllNTOTorBoth;
193		else if (typeof step.keyedVersions[versionAltName] === "object")
194			hasAllNTOTorBoth = step.keyedVersions[versionAltName].hasAllNTOTorBoth;
195		if (hasAllNTOTorBoth === "B") // Both OT and NT 66 books
196			return "OTNT";
197		else if (hasAllNTOTorBoth === "N") // NT's 27 books
198			return "NT";
199		else if (hasAllNTOTorBoth === "O") // OT's 39 books
200			return "OT";
201		return "";
202	},
203
204	_buildBookHTMLTable: function(data, summaryMode) {
205		var ot = "Gen Exod Lev Num Deut Josh Judg Ruth 1Sam 2Sam 1Kgs 2Kgs 1Chr 2Chr Ezra Neh Esth Job Ps Prov Eccl Song Isa Jer Lam Ezek Dan Hos Joel Amos Obad Jonah Mic Nah Hab Zeph Hag Zech Mal";
206		var nt = "Matt Mark Luke John Acts Rom 1Cor 2Cor Gal Eph Phil Col 1Thess 2Thess 1Tim 2Tim Titus Phlm Heb Jas 1Pet 2Pet 1John 2John 3John Jude Rev";
207		var counter = 0;
208		var notSeenNT = true;
209		var browserWidth = $(window).width();
210		var columns = 7;
211		var maxLength = 5;
212		var bookDescription = {};
213        if (!summaryMode) {
214            if (browserWidth < 1100) {
215                columns = 6;
216                maxLength = 4;
217                if (browserWidth < 735) {
218                    columns = 5;
219                    maxLength = 3;
220                    if ((browserWidth < 370) && (this.userLang.toLowerCase().indexOf("zh") == 0))
221                        maxLength = 2;
222                }
223            }
224		}
225        else {
226            columns = 1;
227			bookDescription = {gen:"", exod:"", lev:"", num:"", deut:"", josh:"", judg:"", ruth:"", "1sam":"", "2sam":"", "1kgs":"", "2kgs":"", "1chr":"", "2chr":"", ezra:"", neh:"", esth:"", job:"", ps:"", prov:"", eccl:"", song:"", isa:"", jer:"", lam:"", ezek:"", dan:"", hos:"", joel:"", amos:"", obad:"", jonah:"", mic:"", nah:"", hab:"", zeph:"", hag:"", zech:"", mal:"", matt:"", mark:"", luke:"", john:"", acts:"", rom:"", "1cor":"", "2cor":"", gal:"", eph:"", phil:"", col:"", "1thess":"", "2thess":"", "1tim":"", "2tim":"", titus:"", phlm:"", heb:"", jas:"", "1pet":"", "2pet":"", "1john":"", "2john":"", "3jo":"", jude:"", rev:""};
228            $.ajaxSetup({async: false});
229            $.getJSON("html/json/book_description.json", function(desc) {
230                for (key in desc) {
231                    bookDescription[key] = desc[key];
232                }
233            });
234            $.ajaxSetup({async: true});
235        }
236		var tableHTML = this._buildBookTableHeader(columns, summaryMode);
237		var typlicalBooksChapters = false;
238		var start = 0;
239		var end = 0;
240		if (typeof data === "string") {
241			if (data === "OTNT") end = 66;
242			else if (data === "OT") {
243				end = 39;
244			}
245			else if (data === "NT") {
246				start = 39;
247				end = 66;
248			}
249			typlicalBooksChapters = true;
250		}
251		else {
252			end = data.length;
253		}
254		var additionalBooks = false;
255		var chineseSuffix1ForBooks = "書記歌錄书记歌录"; // suffix for book, record, song, ...
256		var chineseSuffix2ForBooks = "福音"; // suffix for gospel (e.g.: John gospel)
257		for (var i = start; i < end; i++) {
258			var currentOsisID;
259			var shortNameToDisplay;
260			var longNameToDisplay;
261			var numOfChapters;
262			if (typlicalBooksChapters) {
263				currentOsisID = (this.osisChapterJsword[i].length === 4) ? this.osisChapterJsword[i][3] : this.osisChapterJsword[i][0];
264				numOfChapters = this.osisChapterJsword[i][1];
265				longNameToDisplay = this.arrayOfTyplicalBooksChapters[i][0];
266				shortNameToDisplay = (this.arrayOfTyplicalBooksChapters[i].length === 2) ? this.arrayOfTyplicalBooksChapters[i][1] : currentOsisID;
267			}
268			else {
269				currentOsisID = data[i].suggestion.osisID;
270				numOfChapters = 0; // don't know yet, need to find out
271				longNameToDisplay = data[i].suggestion.fullName;
272				shortNameToDisplay = (this.userLang.toLowerCase().indexOf("en") == 0) ? currentOsisID : data[i].suggestion.shortName.replace(/ /g, "").substr(0, 6);
273			}
274			this.bookDisplayNames[currentOsisID] = longNameToDisplay;
275			var newTestament = (nt.indexOf(currentOsisID) > -1);
276			if (!newTestament) oldTestament = (ot.indexOf(currentOsisID) > -1);
277			if ((newTestament) && (notSeenNT)) {
278				notSeenNT = false;
279				counter = 0; // reset counter for NT table
280				tableHTML += '</tr></table>';
281				$('#ot_table').append(tableHTML);
282				tableHTML = this._buildBookTableHeader(columns, summaryMode);
283			}
284			var bookDisplayName = longNameToDisplay;
285			if (this.userLang.toLowerCase().indexOf("zh") == 0) {
286				if (((bookDisplayName.length == maxLength) || (bookDisplayName.length == maxLength + 1)) &&
287					(chineseSuffix1ForBooks.indexOf(bookDisplayName.substr(-1)) > -1)) // If it is one character too long. Remove the last word 書記歌书记歌 (book, record or song)
288					bookDisplayName = bookDisplayName.substr(0, bookDisplayName.length - 1);
289				else if ( 	(	(bookDisplayName.length == maxLength + 1) || // If it is one or two characters too long. Remove the last two words 福音 (gospel)
290								(bookDisplayName.length == maxLength + 2)) &&
291							(chineseSuffix2ForBooks.indexOf(bookDisplayName.substr(-2)) > -1)) 
292					bookDisplayName = bookDisplayName.substr(0, bookDisplayName.length - 2);
293			}
294			if ((bookDisplayName.length > 0) && (bookDisplayName.length <= maxLength))
295				shortNameToDisplay = bookDisplayName;
296			if (!newTestament && !oldTestament) {
297				shortNameToDisplay += '<span style="color:brown">*</span>';
298				additionalBooks = true;
299			}
300            if ((summaryMode) &&
301                (typeof bookDescription[currentOsisID.toLowerCase() + "_header"] === "string")) {
302                tableHTML += '<td style="font-size:18px;text-align:left;padding:0"><b>' +
303                    bookDescription[currentOsisID.toLowerCase() + "_header"] +
304                '</b></td></tr><tr>';
305            }
306			var curBookDescription = ""
307			if (summaryMode) {
308				if (!newTestament && !oldTestament) curBookDescription = '<span style="color:brown">*</span>';
309				if (typeof bookDescription[currentOsisID.toLowerCase()] === "string")
310					curBookDescription += " - " + bookDescription[currentOsisID.toLowerCase()];
311			}
312			tableHTML += '<td title="' + longNameToDisplay + '">' +
313				'<a href="javascript:step.passageSelect.getChapters(\'' + currentOsisID + '\', \'' + this.version + '\', \'' + this.userLang + '\', ' + numOfChapters + ',' + 
314				((summaryMode) ? 'true' : 'false') + ');"' +
315                ((summaryMode) ? ' style="text-align:left;padding:0" ' : "") + '>' +
316                ((summaryMode) ? longNameToDisplay + curBookDescription : shortNameToDisplay) +
317                '</a></td>';
318			counter++;
319			if ((counter % columns) == 0) {
320				tableHTML += '</tr><tr>';
321			}
322		}
323		tableHTML += '</tr></table>';
324		if (additionalBooks) tableHTML += '<p style="color:brown">* Deuterocanonical or other books</p>';
325		if (notSeenNT) $('#ot_table').append(tableHTML);
326		else $('#nt_table').append(tableHTML);
327		this.checkForBiblesWithoutOneTestament(this.version);
328	},
329	checkForBiblesWithoutOneTestament: function(version) {
330		if ((typeof step.keyedVersions[version] === "object") && (typeof step.keyedVersions[version].shortInitials === "string"))
331			version = step.keyedVersions[version].shortInitials;
332		if ($("#nt_table").text() === "")
333			$("#nt_header").html('<b>' + __s.nt_short + '</b> ' + __s.is_not_available_in + ' ' + version);
334		else if ($("#ot_table").text() === "")
335			$("#ot_header").html('<b>' + __s.ot_short + '</b> ' + __s.is_not_available_in + ' ' + version);
336	},
337	_buildBookHeaderAndSkeleton: function(summaryMode) {
338		var html = '<div class="header" style="overflow-y:auto">' +
339			'<h4>' + __s.please_select_book + '</h4>';
340		if ((this.userLang.toLowerCase().indexOf("en") == 0) || (this.hasEnglishBible))
341			html +=
342				'<button style="font-size:10px;line-height:10px;vertical-align:middle" type="button" onclick="step.passageSelect.initPassageSelect(' +
343				((summaryMode) ? 'false' : 'true') +
344				')" title="Show summary information" class="select-version stepButton' +
345				((summaryMode) ? ' stepPressedButton">Summary -' : '">Summary +') +
346				'</button>';
347		html +=
348			'</div>' +
349			'<span id="ot_header" class="stepFgBg" style="font-size:18px"><b>' + __s.old_testament + '</b></span>' +
350			'<div id="ot_table"/>' +
351			'<span id="nt_header" class="stepFgBg" style="font-size:18px"><b>' + __s.new_testament + '</b></span>' +
352			'<div id="nt_table"/>' +
353			'</div>';
354		return html;
355	},
356
357	_buildBookTableHeader: function(columns, summaryMode) {
358		var columnPercent = Math.floor(100 / columns);
359		html = '<table>' +
360			'<colgroup>';
361		for (var i = 0; i < columns; i++) {
362			html += '<col span="1" style="width:' + columnPercent + '%;">';
363		}
364		html += '</colgroup>';
365		html += '<tr>';
366		return html;
367	},
368
369	goToPassage: function(osisID, chptrOrVrsNum) {
370		var bookID = osisID.substring(0, osisID.indexOf("."));
371		if (bookID === "") bookID = osisID;
372		if ((chptrOrVrsNum != 0) && ($("#select_verse_number").hasClass("checked")) && 
373			(this.modalMode === "chapter")) {
374			var numOfVerse = 0;
375			for (var i = 0; i < this.osisChapterJsword.length; i++) {
376				var currentOsisID = (this.osisChapterJsword[i].length === 4) ? this.osisChapterJsword[i][3] : this.osisChapterJsword[i][0];
377				if (bookID === currentOsisID) {
378					numOfVerse = this.osisChapterJsword[i][2][Math.abs(chptrOrVrsNum)-1] || 0; // -1 is used for books with 1 chapter (e.g.: Jude)
379					break;
380				}
381			}
382			if (numOfVerse > 0) {
383				this._buildChptrVrsTbl(null, osisID, numOfVerse, false);
384				return;
385			}
386			else alert('Cannot determine the number of verse in ' + osisID + '.  Will proceed to display the chapter.');
387		}
388		var activePassageData = step.util.activePassage().get("searchTokens") || [];
389		var allVersions = "";
390		var existingReferences = "";
391		var selectedDisplayLoc = $( "#displayLocation option:selected" ).val();
392		for (var i = 0; i < activePassageData.length; i++) {
393			if (activePassageData[i].itemType === VERSION) {
394				if (allVersions.length > 0) allVersions += URL_SEPARATOR + VERSION + "=";
395				allVersions += activePassageData[i].item.shortInitials;
396			}
397			else if ((selectedDisplayLoc === "append") && (activePassageData[i].itemType === "reference")) {
398				existingReferences += URL_SEPARATOR + "reference=" + activePassageData[i].item.osisID;
399			}
400		}
401		step.util.closeModal('passageSelectionModal');
402		if (selectedDisplayLoc === "append") {
403			var url = VERSION + '=' + allVersions + existingReferences + URL_SEPARATOR + REFERENCE + '=' + osisID;
404			step.router.navigateSearch(url, true, true); // skip QFilter
405		}
406		else {
407			if (selectedDisplayLoc === "new") {
408				step.util.createNewColumn();
409			}
410			if (this.modalMode === "verse") {
411				ap=step.util.activePassage();
412				var numOfChaptersInBook = this.getNumOfChapters(bookID);
413				if (numOfChaptersInBook === 1) {
414					var tmpOsisID = osisID.substring(0, osisID.indexOf(".")) + '.1.' + osisID.substring(osisID.indexOf(".") + 1);
415					ap.save({targetLocation: tmpOsisID}, {silent: true});
416				}
417				else ap.save({targetLocation: osisID}, {silent: true});
418				osisID = osisID.substring(0, osisID.lastIndexOf('.'));
419			}
420			step.router.navigatePreserveVersions("reference=" + osisID, false, true, true);
421		}
422	},
423
424	getNumOfChapters: function(bookID) {
425		for (var i = 0; i < this.osisChapterJsword.length; i++) {
426			var currentOsisID = (this.osisChapterJsword[i].length === 4) ? this.osisChapterJsword[i][3] : this.osisChapterJsword[i][0];
427			if (bookID === currentOsisID) {
428				return this.osisChapterJsword[i][1];
429			}
430		}
431	},
432
433	getChapters: function(bookOsisID, version, userLang, numOfChptrsOrVrs, summaryMo
433de) {
434		$('#pssgModalBackButton').show();
435		if (numOfChptrsOrVrs > 0) {
436			this._buildChptrVrsTbl(null, bookOsisID, numOfChptrsOrVrs, true, version, userLang, summaryMode);
437		}
438		else {
439            var url = SEARCH_AUTO_SUGGESTIONS + bookOsisID + "/limit%3D" + REFERENCE + URL_SEPARATOR + VERSION + "%3D" + version + URL_SEPARATOR + REFERENCE + "%3D" + bookOsisID + URL_SEPARATOR + "?lang=" + userLang;
440			$.getJSON(url, function (data) {
441				step.passageSelect._buildChptrVrsTbl(data, bookOsisID, numOfChptrsOrVrs, true, version, userLang, summaryMode);
442			}).fail(function() {
443                changeBaseURL();
444            });
445		}
446	},
447	_handleEnteredPassage: function(verifyOnly, input) {
448		if (input !== null) userInput = input;
449		else {
450			userInput = $('textarea#enterYourPassage').val();
451			userInput = userInput.replace(/[\n\r]/g, '').replace(/[\t]/g, ' ').replace(/\s\s+/g, ' ').replace(/,,/g, ',').replace(/^\s+/g, '')
452			userInput = userInput.replace(/[–—]/g, '-'); // replace n-dash and m-dash with hyphen
453		}
454		var url = SEARCH_AUTO_SUGGESTIONS + userInput + "/limit%3D" + REFERENCE + URL_SEPARATOR + VERSION + "%3D" + this.version + URL_SEPARATOR + "?lang=" + this.userLang;
455		$.getJSON(url, function (data) {
456			if (data.length > 0) {
457				if (data[0].suggestion.passage) {
458					console.log("Program error: unexpected result from SEARCH_AUTO_SUGGESTIONS");
459					console.log(data);
460				}
461				else if (!verifyOnly) step.passageSelect.goToPassage(data[0].suggestion.osisID, 0); // 0 is ready to go to passage
462			}
463			else {
464				var errorText = (userInput != "") ? ' for "' + userInput + '"' : "";
465				$('#userEnterPassageError').text("No match" + errorText + ", please update the passage you entered.");
466				$('textarea#enterYourPassage').focus();
467				if (!verifyOnly) $('textarea#enterYourPassage').val(userInput);
468			}
469		}).fail(function() {
470            changeBaseURL();
471        });
472	},
473	// SM for Arabic/Farsi numeral display
474	changeNumberForm: function(chptrOrVrsNum) {
475	    var anums = ['Ù ','Ù¡','Ù¢','Ù£','Ù¤','Ù¥','Ù¦','Ù§','Ù¨','Ù©'];
476	    var fnums = ['Û°','Û±','Û²','Û³','Û´','Ûµ','Û¶','Û·','Û¸','Û¹'];
477	    if (this.userLang=="ar"){
478	        return chptrOrVrsNum.toString().replace(/[0-9]/g, function(n){return anums[+n];});
479	    }
480	    else if (this.userLang=="fa")
481	    {
482	        return chptrOrVrsNum.toString().replace(/[0-9]/g, function(n){return fnums[+n];});
483	    }
484	    else{
485	        return chptrOrVrsNum;
486	    }
487	},
488
489	_buildChptrVrsTbl: function(data, bookOsisID, numOfChptrsOrVrs, isChapter, version, userLang, summaryMode) {
490		var headerMsg;
491		$('#enterYourPassage').hide();
492		if (isChapter) {
493			headerMsg = __s.please_select_chapter;
494			this.modalMode = 'chapter';
495		}
496		else {
497			headerMsg = __s.please_select_verse;
498			this.modalMode = 'verse';
499		}
500		var tableColumns = 10;
501		var widthPercent = 10;
502		if (step.touchDevice) {
503			var ua = navigator.userAgent.toLowerCase();
504			if ( (ua.indexOf("android") > -1) ||
505				 ((step.appleTouchDevice) &&
506					(ua.indexOf("safari/60") > -1)) ) {
507				tableColumns = 7;
508				widthPercent = 14;
509			}
510		}
511        var chapterDescription = [];
512        if (summaryMode) {
513            tableColumns = 1;
514            for (var i = 0; i <= numOfChptrsOrVrs; i++) {
515                chapterDescription.push("");
516            }
517            $.ajaxSetup({async: false});
518            $.getJSON("html/json/" + bookOsisID.toLowerCase() + ".json", function(desc) {
519                for (key in desc) {
520                    if (key.indexOf("chapter_") == 0) {
521                        var pos = key.indexOf("_description");
522                        if (pos > -1) {
523                            var chapter = key.substr(8, pos - 8);
524                            if ((desc[key] === "*") || (desc[key] === "**"))
525                                chapterDescription[chapter] = desc["chapter_" + chapter + "_overview"];
526                            else chapterDescription[chapter] = desc[key];
527                        }
528                        else if (key.indexOf("_header") > 8)
529                            chapterDescription[key] = desc[key];
530                    }
531                }
532            });
533            $.ajaxSetup({async: true});
534        }
535        
536		var bookNameToDisplay = this.bookDisplayNames[bookOsisID.split('.')[0]] || '';
537		var html = ((bookNameToDisplay) ? '<span id="selectedBookName" class="stepFgBg" style="font-size:18px"><b>' + bookNameToDisplay + '</b></span>' : '') +
538			'<div class="header">' +
539            '<h4>' + headerMsg + '</h4>';
540        if ((isChapter) && 
541			 ((userLang.toLowerCase().indexOf("en") == 0) || (this.hasEnglishBible)) &&
542			 (step.util.bookOrderInBible(bookOsisID) > -1) )
543			html +=
544				'<button style="font-size:10px;line-height:10px;vertical-align:middle" type="button" onclick="step.passageSelect.getChapters(\'' +
545					bookOsisID + '\',\'' + version + '\',\'' + userLang + '\',' + numOfChptrsOrVrs + ',' +
546					((summaryMode) ? 'false' : 'true') +
547					')" title="Show summary information" class="select-version stepButton' +
548					((summaryMode) ? ' stepPressedButton">Summary -' : '">Summary +') +
549					'</button>';
550        html +=
551            '</div>' +
552			'<div style="overflow-y:auto">' +
553			'<table>' +
554			'<colgroup>';
555		for (var c = 0; c < tableColumns; c++) {
556			html += '<col span="1" style="width:' + widthPercent + '%">';
557		}
558		html += '</colgroup>' +
559			'<tr>';
560
561		var chptrOrVrsNum = 0;
562		var osisIDLink = "";
563		if (numOfChptrsOrVrs > 0) {
564			if (isChapter) {
565				this.lastNumOfChapters = numOfChptrsOrVrs;
566				this.lastOsisID = bookOsisID;
567			}
568			for (var i = 0; i < numOfChptrsOrVrs; i++) {
569				chptrOrVrsNum++;
570				osisIDLink = (numOfChptrsOrVrs === 1) ? bookOsisID : bookOsisID + '.' + chptrOrVrsNum;
571                if ((summaryMode) &&
572                    (typeof chapterDescription["chapter_" + chptrOrVrsNum + "_header"] === "string")) {
573                    html += '<td style="font-size:18px;text-align:left;padding:0"><b>' +
574                        chapterDescription["chapter_" + chptrOrVrsNum + "_header"] +
575                    '</b></td></tr><tr>';
576                }
577				var curChptrDesc = "";
578				if (typeof chapterDescription[chptrOrVrsNum] === "string")
579					curChptrDesc = " - " + chapterDescription[chptrOrVrsNum];
580				html += '<td><a href="javascript:step.passageSelect.goToPassage(\'' + osisIDLink + '\', \'' + chptrOrVrsNum + '\');"' +
581                    ((summaryMode) ? ' style="text-align:left;padding:0px 0px 0px 22px;text-indent: -22px;" ' : "") +
582                    '>' + this.changeNumberForm(chptrOrVrsNum) +
583                    ((summaryMode) ? curChptrDesc : "") +
584                    '</a></td>'
585				if ((chptrOrVrsNum > (tableColumns - 1)) && ((chptrOrVrsNum % tableColumns) == 0)) {
586					html += '</tr><tr>';
587				}
588			}
589		}
590		else {
591			for (var i = 0; i < data.length; i++) {
592				if (data[i].suggestion.sectionType === "PASSAGE") {
593					chptrOrVrsNum++;
594					osisIDLink = data[i].suggestion.osisID;
595					var curChptrDesc = "";
596					if (typeof chapterDescription[chptrOrVrsNum] === "string")
597						curChptrDesc = " - " + chapterDescription[chptrOrVrsNum];
598					html += '<td><a href="javascript:step.passageSelect.goToPassage(\'' + osisIDLink + '\', \'' + chptrOrVrsNum + '\');"' +
599                        ((summaryMode) ? ' style="text-align:left;padding:0" ' : "") +
600                        '>' + this.changeNumberForm(chptrOrVrsNum) +
601                        ((summaryMode) ? curChptrDesc : "") +
602                        '</a></td>'
603					if ((chptrOrVrsNum > (tableColumns - 1)) && ((chptrOrVrsNum % tableColumns) == 0)) {
604						html += '</tr><tr>';
605					}
606				}
607			}
608			if (isChapter) {
609				this.lastOsisID = osisIDLink.substring(0, osisIDLink.indexOf('.'));
610				this.lastNumOfChapters = chptrOrVrsNum;
611			}
612		}
613		if (chptrOrVrsNum === 1) {
614			this.goToPassage(osisIDLink, -1); // If there is only one chapter, just go to it.
615			return;
616		}
617		html +=
618			'</tr></table></div>' +
619			'</div>';
620		$('#bookchaptermodalbody').empty();
621		$('#bookchaptermodalbody').append(html);
622	},
623
624	goBackToPreviousPage: function() {
625		if ((this.modalMode === 'verse') && (this.lastOsisID !== '')) {
626			// _buildChptrVrsTbl sets modalMode itself: 'chapter' normally, 'verse'
627			// when a single-chapter book's auto-jump lands back on the verse grid.
628			this._buildChptrVrsTbl(null, this.lastOsisID, this.lastNumOfChapters, true, this.version, this.userLang);
629		}
630		else {
631			$('#bookchaptermodalbody').empty();
632			this.modalMode = "book";
633			this._displayListOfBooks();
634		}
635	}
636};

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.