Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
120 changes: 119 additions & 1 deletion step-web/src/main/webapp/js/backbone/step_router.js
Original file line number Diff line number Diff line change
Expand Up @@ -224,18 +224,136 @@ var StepRouter = Backbone.Router.extend({

var searchType = passageModel.get("searchType");
if (searchType == 'PASSAGE') {
// if passage has not changed, get the verse index
var scrollPosVerseIndex = this.getScrollPosVerseIndex(passageModel);
//destroy all views for this column
passageModel.trigger("destroyViews");
new PassageDisplayView({
var passageView = new PassageDisplayView({
model: passageModel,
partRendered: partRendered
});
// set passage on the element for getScrollPosVerseIndex
$(passageView.el).attr("data-osis-id", passageModel.attributes.osisId);
if (scrollPosVerseIndex) {
this.handleRenderScrollPosition(passageView, scrollPosVerseIndex);
doNotScroll = true;
}
} else {
this.handleSearchResults(passageModel, partRendered);
}
this._renderSummary(passageModel);
step.util.hideNavBarOnPhones(doNotScroll);
},
getScrollPosVerseIndex: function(passageModel) {
var currentPassageID = passageModel.get("passageId");
var passageContainer = step.util.getPassageContainer(currentPassageID);
// if this is due to an options change, and we are staying on the same
// book and chapter, we want to preserve the scrolling position
var sameOsisIdAsPrevious = false;
var passageContent = passageContainer.find(".passageContent");
var previousOsisId = passageContent.attr("data-osis-id");
var currentOsisId = passageModel.attributes.osisId;
if (previousOsisId == currentOsisId) {
sameOsisIdAsPrevious = true;
}
if (!sameOsisIdAsPrevious) {
return null;
}
// get top-most visible verse
// first get the offset of the content holder
var contentHolder = passageContainer.find(".passageContentHolder");
var contentHolderOffset = contentHolder.offset().top;
// if the first element in the contentHolder is within view,
// we can just leave the scroll position at the top
var firstElement = contentHolder.find(":first");
if (firstElement[0].getBoundingClientRect().y >= contentHolderOffset) {
return null;
}
// otherwise, we are looking for the first verse that is within view
var verses = this.getVerseElementsFromContentHolder(contentHolder);
var topOffset = contentHolderOffset;
if (step.touchDevice && !step.touchWideDevice) {
var parent = passageContainer[0].parentElement;
var passageOptionsGroup = $(parent).find(".passageOptionsGroup");
var optionsGroupOffset = passageOptionsGroup[0].clientHeight;
topOffset = optionsGroupOffset;
}
for (var v = 0; v < verses.length; v++) {
var verse = verses[v];
if (verse.getBoundingClientRect().y > topOffset) {
return v;
}
}
return null;
},
handleRenderScrollPosition: function (passageDisplayView, verseIndex) {
var passageContainer = $(passageDisplayView.el);
var contentHolder = passageContainer.find(".passageContentHolder");
var verses = this.getVerseElementsFromContentHolder(contentHolder);
var verse = verses[verseIndex];
if (!verse) {
return;
}
if (step.touchDevice && !step.touchWideDevice) {
// mobile needs this to be put behind a timeout
// because hideNavBarOnPhones sets height: 'auto' on the contentHolder
// scroll to top first to deal with top bar calculation
window.scrollTo(0, 0);
setTimeout(function() {
// mobile should use window.scrollTo
var parent = passageContainer[0].parentElement;
var passageOptionsGroup = $(parent).find(".passageOptionsGroup");
var optionsGroupOffset = passageOptionsGroup[0].clientHeight;
var offset = verse.getBoundingClientRect().y - 50;
window.scrollTo(0, offset);
}, 0);
} else {
// desktop should just scroll the div
var contentHolderOffset = contentHolder.offset().top;
var offset = verse.getBoundingClientRect().y - contentHolderOffset - 10;
contentHolder[0].scrollTo(0, offset);
}
},
getVerseElementsFromContentHolder: function (contentHolder) {
if (contentHolder.find(".interlinear").first().length) {
return contentHolder.find(".verseNumber");
}
var firstClass = contentHolder.find("> :not(.notesPane)").first().attr("class");
if (firstClass.includes("table")) {
return contentHolder.find("tr.row").filter(function(e, el) {
// ignoring verse-0 in the count for table-based views
return e === 0 ? !$(el).find("a.verseLink[name$='.0']").length : true;
});
} else if (firstClass.includes("verseGrouping")) {
var versionReferenceEnabled = (
!contentHolder.find(".verseGrouping .verseNumber").first().length
);
return contentHolder.find(".verseGrouping").filter(function(e, el) {
// ignoring any verse-0 in the count for interleaved views
if (e === 0) {
// if version reference is disabled,
// the first grouping should contain a verseNumber
if (!versionReferenceEnabled) {
if (!$(el).find(".verseNumber").first().length) {
return false;
}
}
// if version reference is enabled,
// we need to inspect the inner HTML of smallResultKey
var keys = $(el).find(".smallResultKey");
for (var k = 0; k < keys.length; k++) {
var key = $(keys[k]);
if (key.html().endsWith(":0)")) {
return false;
}
}
}
return true;
});
} else {
return contentHolder.find(".verse");
}
},

_renderSummary: function (passageModel) {
var searchTokens = passageModel.get("searchTokens");
Expand Down