s around rawhtml
removeRawHtmlDivs: "off",
// set to "on" to enable 'show answer' button
showAnswer: "off",
// set to "off" to turn off auto wrapping of answers embedded in xml
showAnswerWrapThis: "on",
// set to "on" to automatically move box title (h3) out of inner box
Box_moveTitle: "off",
// block_types (separated by commas)
Box_moveTitleExclude: "",
// Needed for LC activity links to b-heads
// Holds the 'anchor_id' passed in via the query string
anchorId: undefined,
// If we're in the PX frame, we have to do a number of special things regarding scrolling and such
// so we'll set fne_jq to the focused & engaged frameset if we're there
fne_jq: null,
scrolling_window_jq: null,
rightnav_page_off_not_showing_html: "◌", // dotted open circle
rightnav_page_off_showing_html: "○", // open circle
rightnav_page_on_html: "●", // closed circle
rightnav_navmode_html: "▣",
last_section_showing: 0,
next_unit_item: function() {
try {
if (top.PxPage == null) {
console.log("Not in PX frameset");
} else {
top.$(top.PxPage.switchboard).trigger("fneclickNextNodeTitle");
}
} catch(e) {
console.log("Not in PX frameset (2)");
}
},
switch_to_px_item: function(itemid) {
try {
if (top.PxPage == null) {
console.log("Not in PX frameset");
} else {
PxPage.openContent({id:itemid});
}
} catch(e) {
console.log("Not in PX frameset (3)");
}
},
show_navigation: function() {
// show read on button -- the text here is configurable for each ebook
var html = UI_Elements.get_button_html({
"id": "readon_button"
, "label": this.md.next_page_button
, "fn": 'player.show_section("next")'
, "extra_class": "readon_button"
});
$("#manuscript").append(html);
// activate button
UI_Elements.activate_buttons();
// if there are no subsections, there's no more navigation to show
if (this.sections.length == 1) {
return;
}
var html = "
";
for (var i = 0; i < this.sections.length; ++i) {
var s = this.sections[i];
var entity = this.rightnav_page_off_not_showing_html;
if (i <= this.last_section_showing) {
entity = this.rightnav_page_off_showing_html;
}
html += "
" + entity + "
"
}
html += "
" + this.rightnav_navmode_html + "
"
html += "
"; // rightnav
$("#manuscript").append(html);
// activate events for rightnav
// hover/click for pages
$(".rightnav_page").hover(function() {
var jq = $(this);
var section_index = jq.attr("section_index") * 1;
var s = player.sections[section_index];
var title = s.title;
if (s.number != null) {
title = s.number + " " + title;
}
var html = "
" + title + "
"
+ player.rightnav_page_on_html;
$(this).html(html);
}, function() {
var jq = $(this);
var section_index = jq.attr("section_index") * 1;
if (section_index == player.section_currently_showing) {
jq.html(player.rightnav_page_on_html);
} else {
var entity = player.rightnav_page_off_not_showing_html;
if (section_index <= player.last_section_showing) {
entity = player.rightnav_page_off_showing_html;
}
jq.html(entity);
}
}).click(function() {
var jq = $(this);
var section_index = jq.attr("section_index") * 1;
player.show_section(section_index);
});
// nav mode
$("#rightnav_navmode_button").hover(function() {
var jq = $(this);
// add links to show TOC / toggle nav mode
var html = "
"
+ "
SHOW ALL SECTIONS
"
+ "
TABLE OF CONTENTS
"
+ "
"
;
$("#rightnav_navmode_button_inner").before(html);
$("#show_all_div").click(function() {
player.show_all_sections();
});
$("#show_toc_div").click(function() {
player.show_toc();
});
}, function() {
$(".rightnav_navmode_title").remove();
});
$("#rightnav_navmode_button_inner").click(function() {
player.show_all_sections();
});
// position rightnav
player.update_right_nav();
},
show_all_sections: function(force) {
if (this.last_section_showing == this.sections.length - 1) {
return;
}
// add class to all but the last section
for (var i = 0; i < this.sections.length - 1; ++i) {
this.sections[i].jq.addClass("singlepage");
}
// make sure all sections are represented by rightnav_page_off_showing_html
for (var i = 0; i < this.sections.length; ++i) {
// (except the currently showing section)
if (i != this.section_currently_showing) {
$(".rightnav_page").filter("[section_index=" + i + "]").html(player.rightnav_page_off_showing_html);
}
}
// show all sections
$("[data-type=section]").show();
this.last_section_showing = this.sections.length - 1;
this.last_available_section = this.sections.length;
this.switch_readon_button_to_next_unit_item();
// register the last_available_section in ARGA
Set_ARGA_Data("LASX", this.last_available_section);
this.activity.ARGA_submit_data(false);
// cancel hover menu
$(".rightnav_navmode_title").remove();
},
show_section: function(section_to_show) {
// if this is the last section, go to the next item in the LP instead of the next section
if (section_to_show == "next" && player.section_currently_showing == (player.sections.length - 1)) {
player.next_unit_item();
} else {
this._super(section_to_show);
}
},
/*
This is the old version of show_section_animate. Keeping it around for
reference if needed.
*/
show_section_animate_old: function(section_to_show, force) {
// parent function includes direction as param; we just define it here
// and include the "force" parameter
var direction;
if (section_to_show == this.section_currently_showing && force != "force") {
return;
} else if (section_to_show < this.section_currently_showing) {
direction = "left";
} else {
direction = "right";
}
// make sure modal window is closed -- not needed unless we bring toc_dialog back
$("#toc_dialog").dialog("close");
// if we're not already showing all sections...
if (this.last_section_showing < this.sections.length - 1 || this.sections.length == 1) {
// if we're showing a later section, make sure that
// all sections between the current and the new section are showing
var i = this.section_currently_showing;
if (i == null) {
i = 0;
}
if (section_to_show >= i) {
for (; i <= section_to_show; ++i) {
if (i < section_to_show) {
this.sections[i].jq.addClass("singlepage");
}
this.sections[i].jq.show();
$(".rightnav_page").filter("[section_index=" + i + "]").html(player.rightnav_page_off_showing_html);
}
}
}
// update last_section_showing if necessary
if (this.last_section_showing < section_to_show) {
this.last_section_showing = section_to_show;
}
// scroll to the top of the section we're jumping to
var scroll_top = Math.round(this.sections[section_to_show].jq.offset().top) - 20;
// have to do this after a delay, in case the PX code is resizing the window
setTimeout("player.scrolling_window_jq.scrollTop(" + scroll_top + ")", 100);
this.section_currently_showing = section_to_show;
// update right nav
this.update_right_nav();
// if this is the last section, change the readon button to go to the next item
if (this.section_currently_showing == (this.sections.length - 1)) {
this.switch_readon_button_to_next_unit_item();
}
player.update_last_viewed_section();
}, // end show_section_animate_old
/*
This is the new version of show_section_animate, updated to work with b-head
links in LC activites
Added by Bruce, 04-06-2014.
*/
/*
section_to_show: (integer) number of the section to scroll to
force:
anchor: (string) ID of element to target(auto-scroll to) on page
*/
show_section_animate: function(section_to_show, force, anchor) {
// parent function includes direction as param; we just define it here
// and include the "force" parameter
var direction;
// section_to_show is usually the number of the section div to
// scroll to. If it is something other than a number then assume it is
// an ID on the page and find the section div number that the ID is located
// in. If anchor was not passed in then set it to the ID passed in through
// section_to_show.
if (!(/^\d+$/.test(section_to_show))) {
if (!xBookUtils.emptyValue(anchor)) {
anchor = section_to_show;
}
section_to_show = xBookUtils.getSectionNumForId(section_to_show);
if (section_to_show === undefined) {
section_to_show = 0;
}
}
// At this point, section_to_show should contain an int, let's make sure
// it does :-)
section_to_show = Number(section_to_show);
if (section_to_show == this.section_currently_showing && force != "force") {
return;
}
else if (section_to_show < this.section_currently_showing) {
direction = "left";
}
else {
direction = "right";
}
// make sure modal window is closed -- not needed unless we bring toc_dialog back
$("#toc_dialog").dialog("close");
// if we're not already showing all sections...
if (this.last_section_showing < this.sections.length - 1 || this.sections.length == 1) {
// if we're showing a later section, make sure that
// all sections between the current and the new section are showing
var i = this.section_currently_showing;
if (i == null) {
i = 0;
}
if (section_to_show >= i) {
for (; i <= section_to_show; ++i) {
if (i < section_to_show) {
this.sections[i].jq.addClass("singlepage");
}
this.sections[i].jq.show();
$(".rightnav_page").filter("[section_index=" + i + "]").html(player.rightnav_page_off_showing_html);
}
}
}
// update last_section_showing if necessary
if (this.last_section_showing < section_to_show) {
this.last_section_showing = section_to_show;
}
// scroll to the top of the section we're jumping to
var scroll_top = Math.round(this.sections[section_to_show].jq.offset().top) - 20;
// Get parent iframe wrapping ebook page. The ebook page will have
// a class of 'show-sec-animate' on . So we look for the iframe
// that contains page.
var $parentIFrame = $();
(function() {
var $iframes;
try {
$iframes = $("iframe", window.parent.document);
}
catch(err) {
$iframes = $();
}
$iframes.each(function(index, element) {
$this = $(element);
try {
var $child = $this.contents().find("html");
if ($child.hasClass("show-sec-animate")) {
$parentIFrame = $this;
return false;
}
}
catch (err) { }
});
})();
var $scrollingWindow;
// If we aren't in a frame or we are in the LC dialog page viewer or
// DF wrapper then the iframe does the scrolling as usual so we want
// to set both the scrollingWindow and parentIframe to .
if ($parentIFrame.length == 0 || xBookUtils.inLCViewer() || xBookUtils.inDFWrapper()) {
// this needs to be $(document) or Chrome won't work correctly
$scrollingWindow = $(document);
$parentIFrame = $scrollingWindow;
}
else {
$scrollingWindow = this.scrolling_window_jq;
}
// Now attempt to scroll to the section by checking to make sure the
// page is tall enough to scroll there. Keep trying until the page
// is long enough or we run out of tries.
if (($parentIFrame.length > 0) && ($scrollingWindow.length > 0)) {
var numIntervalTries = 50;
var scrollTo = scroll_top;
var timerID = setInterval(function(){
numIntervalTries--;
// This is a pure hack for right now, we need to do this to force the
// parent iframe to resize itself to the height of the page. Once
// we get an actual javascript function that we can call to force
// the iframe to resize we can use it instead.
if (xBookUtils.inPXFrame()) {
$("body").trigger('click');
}
// If the height of parentIFrame is larger than where we
// want to scroll to then we are safe to scroll there
if (scrollTo < $parentIFrame.height()) {
$scrollingWindow.scrollTop(scrollTo);
clearInterval(timerID);
}
// Safety shutoff valve to make sure we don't get stuck in an
// infinite loop
else if (numIntervalTries < 1) {
// One last try
$scrollingWindow.scrollTop(scrollTo);
clearInterval(timerID);
}
},100);
}
// If we have an anchor then go to it
if (!xBookUtils.emptyValue(anchor)) {
// We only need to scroll if we are targetting something other
// than section_to_show
if (("digfir_section_" + section_to_show) !== anchor) {
var $anchor = $("#" + anchor);
if ($anchor.length > 0) {
safe_log("found anchor, scrolling to ID " + anchor);
$.scrollTo($anchor, 100);
// we need to wait for all images to load since our images
// don't have heights set on them
$('#manuscript').imagesLoaded(function() {
safe_log("scrolling to anchor " + anchor + " after imagesLoaded");
$.scrollTo($anchor, 100);
});
}
}
}
this.section_currently_showing = section_to_show;
// update right nav
this.update_right_nav();
// if this is the last section, change the readon button to go to the next item
if (this.section_currently_showing == (this.sections.length - 1)) {
this.switch_readon_button_to_next_unit_item();
}
player.update_last_viewed_section();
// Set widths on figure divs if needed. If the image wasn't visible during
// imagesLoaded callback then the wrapper div will have data-resize-img-div="1".
$('[data-resize-img-div="1"]').each(function() {
var $this = $(this);
var $img = $this.children('img');
var img_width = $img.width();
if (img_width > 0) {
$this.css("width", img_width + "px");
$this.attr('data-resize-img-div', '0');
}
});
}, // end show_section_animate
switch_readon_button_to_next_unit_item: function() {
UI_Elements.update_button_label("readon_button", "Next");
// Add class so we can hide this button in the LC dialog page viewer
$('#readon_button').addClass('label-next');
},
update_right_nav: function() {
$(".rightnav_page").removeClass("rightnav_curpage").each(function(){
var jq = $(this);
var section_index = jq.attr("section_index") * 1;
if (section_index <= player.last_section_showing) {
jq.html(player.rightnav_page_off_showing_html);
} else {
jq.html(player.rightnav_page_off_not_showing_html);
}
});
$(".rightnav_page").filter("[section_index=" + this.section_currently_showing + "]").html(player.rightnav_page_on_html).addClass("rightnav_curpage");
// move interface to the top of the page (setting "bottom" didn't work nearly as well)
var w_top = Math.floor(player.scrolling_window_jq.scrollTop()) + 10;
$("#rightnav").css("top", w_top + "px");
},
page_scrolled: function() {
// if we're currently auto-scrolling, return
if (player.currently_auto_scrolling == true) {
return;
}
// find out where the window is scrolled to
var w_top = Math.floor(player.scrolling_window_jq.scrollTop());
// now find out what section we're in
var section_showing = null;
for (var i = 0; i <= player.last_section_showing; ++i) {
var s = player.sections[i];
var s_top = Math.floor(s.jq.offset().top);
if ((s_top - 200) > w_top && section_showing == null) {
section_showing = i;
}
}
if (section_showing == null) {
section_showing = player.last_section_showing;
} else if (section_showing > 0) {
section_showing -= 1;
}
// special case: if we're scrolled to the very top of the page, we *must*
// be in the first section
if (w_top == 0) {
section_showing = 0;
}
// another special case: if we're scrolled to the very bottom of the page,
// we *must* be in the *last* section
if (w_top > ($("#manuscript").height() - player.scrolling_window_jq.height())) {
section_showing = player.last_section_showing;
}
// save the fact that we're on this section
player.section_currently_showing = section_showing;
player.update_right_nav();
player.update_last_viewed_section();
// process iframes for the section, unless all were preloaded
if (player.md.preload_all_iframes != "true") {
player.figures.process_iframes(player.sections[section_showing].jq);
}
// console.log("w_top: " + w_top + "; ms height: " + $("#manuscript").height() + "; w height: " + scrolling_window_jq.height() + "; bot: " + bot);
},
update_last_viewed_section: function() {
// if ARGA is initialized and we need to restore the user to his last position when he returns,
if (this.ARGA_running && player.md.restore_last_viewed_section == "true") {
// if we're viewing a page other than the one currently saved as LVS (last-viewed section)
var lvs = Get_ARGA_Data("LVSX");
if (this.section_currently_showing != null && this.section_currently_showing != lvs) {
// store LVS/LAS to register the last-viewed/last-available page,
// and save ARGA so it gets registered
Set_ARGA_Data("LVSX", this.section_currently_showing);
Set_ARGA_Data("LASX", this.last_available_section);
this.activity.ARGA_submit_data(false);
}
}
},
show_toc: function() {
// cancel hover menu
$(".rightnav_navmode_title").remove();
$("#toc_dialog").remove();
var html = "";
for (var i = 0; i < this.sections.length; ++i) {
var s = this.sections[i];
var extra_style = "";
if (this.md.sequenced_sections == "true" && i > this.last_available_section) {
extra_style = "toc_section_not_available";
}
html += ""
;
}
if (this.md.sequenced_sections == "true") {
html = "
Click on a slide to view it. Note: Grey slides are not accessible until preceding slides have been viewed or completed.
" + html;
}
html = "
" + html + "
";
$("body").append(html);
$("#toc_dialog").dialog({title:"Jump To...", width:450, modal:true, buttons: [ {text:"OK", click: function() {$("#toc_dialog").dialog("close");}}]});
},
// if we stored the last-viewed section in ARGA the standard way, restore
restore_section: function() {
// this should only be called if ARGA is initialized
var lvs = Get_ARGA_Data("LVSX");
var las = Get_ARGA_Data("LASX");
// if we have a last available section, make sure all sections up to that one are showing
if (las != "") {
this.last_available_section = las * 1;
// note that last_available_section can equal this.sections.length; last_section_showing can't
this.last_section_showing = this.last_available_section;
if (this.last_section_showing >= this.sections.length) {
this.last_section_showing = this.sections.length - 1;
}
// show all sections up to las or sections.length (whichever comes first)
for (var i = 0; i <= this.last_available_section && i < this.sections.length; ++i) {
// don't add the "singlepage" class to the last-showing section
if (i < this.last_section_showing) {
this.sections[i].jq.addClass("singlepage");
}
this.sections[i].jq.show();
$(".rightnav_page").filter("[section_index=" + i + "]").html(player.rightnav_page_off_showing_html);
}
// if we're showing all sections, call switch_readon_button_to_next_unit_item
if (this.last_section_showing == this.sections.length - 1) {
this.switch_readon_button_to_next_unit_item();
}
}
// now go to section 0;
// first set LVS now so that we *don't* save to ARGA in update_section_status --
// the last visited section is actually still what it was before.
Set_ARGA_Data("LVSX", "0");
this.show_section(0);
// if we have a previously-stored LVS, we could in theory show it now, but a) we don't know when
// the highlighting/notes code will complete, and b) it might be disconcerting to users
// if (lvs != "") {
// player.show_section(lvs * 1);
// }
},
extract_activity_metadata: function() {
this._super();
this.required_metadata_val("next_page_button", "Read on", true);
this.required_metadata_val("previous_page_button", "Back up", true);
// by default we do not require students to go through slides in order,
// and we restore them to their last-viewed slide when they return.
this.required_metadata_val("sequenced_sections", "false");
this.required_metadata_val("restore_last_viewed_section", "true");
this.required_metadata_val("section_sequence_message", "You must read each page, and complete any questions on the page, in sequence.");
},
show_activity_questions: function(button) {
var jq = $(button).parents().find("[data-block_type=activity_with_questions]");
$(button).hide();
$("[data-block_type=question_sequence]").show();
},
initialize_sections: function() {
// Added by Bruce 11/03/2013
// Save original ID on each section to data-sec-id before _super replaces it.
$('[data-type="section"]').each(function() {
var $this = $(this);
$this.attr('data-sec-id', $this.attr('id'));
});
this._super();
// Add class to body if we are viewing page in supp window
(function() {
try {
var $supp_iframe = $('#xBookSuppWinNavPageFrame', window.parent.document);
if ($supp_iframe.length != 0) {
$("body").addClass("xBookSuppWinNavPage");
}
}
catch(err) { }
})();
if (this.removeRawHtmlDivs === "on") {
$('[data-type="rawhtml"]').each(function() {
var $this = $(this);
var raw_content = $this.contents();
$this.replaceWith(raw_content);
});
}
var boxMoveTitle = this.Box_moveTitle;
if (boxMoveTitle === "all") {
var excludes_array = this.Box_moveTitleExclude.split(",");
$('[data-type="box"]').each(function() {
$this = $(this);
var block_type = $this.attr('data-block_type');
if (!xBookUtils.emptyValue(block_type)) {
if ($.inArray(block_type, excludes_array) >= 0) {
return;
}
}
$this.each(xBookUtils.moveBoxTitle);
});
}
else if (boxMoveTitle !== "off") {
var includes_array = this.Box_moveTitle.split(",");
$('[data-type="box"]').each(function() {
$this = $(this);
var block_type = $this.attr('data-block_type');
if (!xBookUtils.emptyValue(block_type)) {
if ($.inArray(block_type, includes_array) >= 0) {
$this.each(xBookUtils.moveBoxTitle);
}
}
});
}
if (this.showAnswer === "on") {
// Add click handler for show answer buttons
$('.show_answer_button').live("click", function() {
$this = $(this);
// Show Answer button must have a target (this should
// always be the case but we'll check anyway)
var target_id = $this.attr('data-target');
if (xBookUtils.emptyValue(target_id)) {
safe_log("showAnswer: no target set on button");
return;
}
// Make sure target(answer) container exists
var $container = $("#" + target_id);
if ($container.length < 1) {
safe_log("showAnswer: target #" + target_id + " does not exist");
return;
}
// Toggle the 'show_answer_button_on' class for both the
// button and the answer container
$this.toggleClass('show_answer_button_on');
$container.toggleClass('show_answer_button_on');
});
// Look for any elements with data-show-answer
var wrap_answer = this.showAnswerWrapThis;
$('[data-show-answer]').each(function() {
var $this = $(this);
// If we've already found an answer for this element we are done
if ($this.attr('data-found-show-answer') === "true") {
return;
}
var answer_id = $this.attr('id');
var type = $this.attr('data-show-answer');
if (type === "this") {
var this_wrap = $this.attr('data-show-answer-wrap');
$this.attr('data-found-show-answer', "true");
// Do we need to wrap this answer in a box?
if ((wrap_answer === "on" && this_wrap !== "false") ||
this_wrap === "true") {
$this.before("
");
$this.wrap(function() {
return "
";
});
$this.before("
");
}
else {
$this.before("
");
$this.addClass('show_answer_container');
}
}
else if (type === "array") {
// Check if answer is stored in xBookUtils.showAnswers array
$this.each(xBookUtils.checkShowAnswer);
}
});
} // end showAnswer === "on"
}, // end initialize_sections
initialize: function(id) {
// activity_questions blocks
$("[data-block_type=activity_with_questions]").each(function(index, element) {
var jq = $(element);
jq.find("[data-block_type=question_sequence]").hide();
var html = UI_Elements.get_button_html({"label":"Show Questions", "fn":'player.show_activity_questions(this)', "extra_class":"activity_questions_button"});
jq.append(html);
});
$(".activity_questions_button").button();
// determine if we're in the F&E window
this.fne_jq = null;
this.scrolling_window_jq = $(window);
// If we are viewing page in LC page viewer then the scrolling window
// is $(window)
if (xBookUtils.inLCViewer()) {
$('body').addClass('lc-dialog-viewer');
// While we are here, let's fix the header
(function() {
try {
var $ui_title = $('.ui-dialog-titlebar .ui-dialog-title', window.parent.document);
if ($ui_title.length > 0) {
var title_html = $ui_title.html();
$ui_title.html(title_html.replace(/<(\/)?(sup|sub|em|i|strong|b)>/g,"<$1$2>"));
}
}
catch(err) { }
})();
}
// otherwise check to see if we are in F&E window
else {
try {
this.fne_jq = $("#fne-content",window.parent.document);
if (this.fne_jq.length == 0) {
this.fne_jq = null;
} else {
this.scrolling_window_jq = this.fne_jq;
}
} catch(e) {}
}
// set an event to keep track of where we are
this.scrolling_window_jq.scroll(player.page_scrolled);
// We need to do this before _super because the original XRefs.create_links
// will wipe out any custom data-attributes we have set on the link spans
// and it won't honor the target set in the XML.
//
// Really, we should change XRefs.create_links do everything that
// xBookUtils.create_links is doing and then it wouldn't be necessary
// to call this here or even extend XRefs in the first place.
xBookUtils.create_links($("body"));
// Needed for LC activity b-head links
$("html").addClass("show-sec-animate");
var anchor_id = xBookUtils.getURLParameter('anchor_id');
if (anchor_id !== undefined) {
this.anchorId = anchor_id;
}
/* brb: 20140711 - temporary fix for inline tags in PX fne-title */
if (xBookUtils.inPXFrame()) {
(function() {
try {
var $fne_title = $('#fne-title', window.parent.document);
if ($fne_title.length > 0) {
var title_html = $fne_title.html();
$fne_title.html(title_html.replace(/<(\/)?(sup|sub|em|i|strong|b)>/g,"<$1$2>"));
}
}
catch(err) { }
})();
}
this._super(id);
// Add height to
around