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--;
// 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) {
// we need to wait for all images to load since our images
// don't have heights set on them
$('#manuscript').imagesLoaded(function() {
$.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.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.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.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.data('found-show-answer') === "true") {
return;
}
var answer_id = $this.attr('id');
var type = $this.data('show-answer');
if (type === "this") {
var this_wrap = $this.attr('data-show-answer-wrap');
$this.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');
}
// 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;
}
this._super(id);
// set some global config variables
this.removeRawHtmlDivs = this.cfg_removeRawHtmlDivs || this.removeRawHtmlDivs;
this.showAnswer = this.cfg_showAnswer || this.showAnswer;
this.showAnswerWrapThis = this.cfg_showAnswerWrapThis || this.showAnswerWrapThis;
this.Box_moveTitle = this.cfg_Box_moveTitle || this.Box_moveTitle;
this.Box_moveTitleExclude = this.cfg_Box_moveTitleExclude || this.Box_moveTitleExclude;
// after we call this.super, re-initialize the activity to the custom
// activity type for this manuscript
this.activity = new Activity_manuscript_type();
},
initialize2: function() {
this._super();
// If the hash anchor is attached to the end of the URL and anchorId
// hasn't already been set somewhere else then snag it
if (this.anchorId == undefined) {
var anchor = xBookUtils.pageCompleteURL.attr('fragment');
if (!xBookUtils.emptyValue(anchor)) {
this.anchorId = anchor;
}
}
// Needed for LC activity links to b-heads
// Check if we need to scroll to the anchorId
var secNumToShow = xBookUtils.getSectionNumForId(this.anchorId);
if (secNumToShow !== undefined) {
this.show_section_animate(secNumToShow, null, this.anchorId);
}
// Check if we need to process questions
(function () {
var $questions = $('[data-type="question"]').has('[data-type="query_display"]');
if ($questions.length > 0) {
xBookUtils.procNativePXQuestions($questions);
}
})();
// add tabindex to any elements that are clickable
$('[data-href]').each(function() {
$this = $(this);
var tabindex = $this.attr('tabindex');
if (xBookUtils.emptyValue(tabindex)) {
$this.attr('tabindex', '0');
}
});
// Call page_scrolled once to start ??
// have to do this here, after last-viewed section (if any) has been restored
// player.page_scrolled();
}
}); // end Player_manuscript_type
player = new Player_manuscript_type();
/********************************************************
xBookUtils: Library of common functionality for ebooks.
*********************************************************/
/*
* inflection-js: find singular/plural of noun
* http://code.google.com/p/inflection-js/
*/
if(window&&!window.InflectionJS){window.InflectionJS=null}InflectionJS={uncountable_words:['equipment','information','rice','money','species','series','fish','sheep','moose','deer','news'],plural_rules:[[new RegExp('(m)an$','gi'),'$1en'],[new RegExp('(pe)rson$','gi'),'$1ople'],[new RegExp('(child)$','gi'),'$1ren'],[new RegExp('^(ox)$','gi'),'$1en'],[new RegExp('(ax|test)is$','gi'),'$1es'],[new RegExp('(octop|vir)us$','gi'),'$1i'],[new RegExp('(alias|status)$','gi'),'$1es'],[new RegExp('(bu)s$','gi'),'$1ses'],[new RegExp('(buffal|tomat|potat)o$','gi'),'$1oes'],[new RegExp('([ti])um$','gi'),'$1a'],[new RegExp('sis$','gi'),'ses'],[new RegExp('(?:([^f])fe|([lr])f)$','gi'),'$1$2ves'],[new RegExp('(hive)$','gi'),'$1s'],[new RegExp('([^aeiouy]|qu)y$','gi'),'$1ies'],[new RegExp('(x|ch|ss|sh)$','gi'),'$1es'],[new RegExp('(matr|vert|ind)ix|ex$','gi'),'$1ices'],[new RegExp('([m|l])ouse$','gi'),'$1ice'],[new RegExp('(quiz)$','gi'),'$1zes'],[new RegExp('s$','gi'),'s'],[new RegExp('$','gi'),'s']],singular_rules:[[new RegExp('(m)en$','gi'),'$1an'],[new RegExp('(pe)ople$','gi'),'$1rson'],[new RegExp('(child)ren$','gi'),'$1'],[new RegExp('([ti])a$','gi'),'$1um'],[new RegExp('((a)naly|(b)a|(d)iagno|(p)arenthe|(p)rogno|(s)ynop|(t)he)ses$','gi'),'$1$2sis'],[new RegExp('(hive)s$','gi'),'$1'],[new RegExp('(tive)s$','gi'),'$1'],[new RegExp('(curve)s$','gi'),'$1'],[new RegExp('([lr])ves$','gi'),'$1f'],[new RegExp('([^fo])ves$','gi'),'$1fe'],[new RegExp('([^aeiouy]|qu)ies$','gi'),'$1y'],[new RegExp('(s)eries$','gi'),'$1eries'],[new RegExp('(m)ovies$','gi'),'$1ovie'],[new RegExp('(x|ch|ss|sh)es$','gi'),'$1'],[new RegExp('([m|l])ice$','gi'),'$1ouse'],[new RegExp('(bus)es$','gi'),'$1'],[new RegExp('(o)es$','gi'),'$1'],[new RegExp('(shoe)s$','gi'),'$1'],[new RegExp('(cris|ax|test)es$','gi'),'$1is'],[new RegExp('(octop|vir)i$','gi'),'$1us'],[new RegExp('(alias|status)es$','gi'),'$1'],[new RegExp('^(ox)en','gi'),'$1'],[new RegExp('(vert|ind)ices$','gi'),'$1ex'],[new RegExp('(matr)ices$','gi'),'$1ix'],[new RegExp('(quiz)zes$','gi'),'$1'],[new RegExp('s$','gi'),'']],apply_rules:function(str,rules,skip,override){if(override){str=override}else{var ignore=(skip.indexOf(str.toLowerCase())>-1);if(!ignore){for(var x=0;x
>0,curr=arguments[2];while(i=this.min){g=g+d.top+h.scrollTop()-this.min}if(g>f){g=f}return({marginTop:g+"px"})}}};a.fn.jScrollElement.defaults={speed:"fast",top:10}})(jQuery);
/*
* jQuery imagesLoaded plugin v2.1.2
* http://github.com/desandro/imagesloaded
*
* MIT License. by Paul Irish et al.
*/
/*
This plugin allows you to execute a callback function once all of
the images on the page have been loaded:
$('#manuscript').imagesLoaded(callback);
*/
(function(c,q){var m="data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///ywAAAAAAQABAAACAUwAOw==";c.fn.imagesLoaded=function(f){function n(){var b=c(j),a=c(h);d&&(h.length?d.reject(e,b,a):d.resolve(e));c.isFunction(f)&&f.call(g,e,b,a)}function p(b){k(b.target,"error"===b.type)}function k(b,a){b.src===m||-1!==c.inArray(b,l)||(l.push(b),a?h.push(b):j.push(b),c.data(b,"imagesLoaded",{isBroken:a,src:b.src}),r&&d.notifyWith(c(b),[a,e,c(j),c(h)]),e.length===l.length&&(setTimeout(n),e.unbind(".imagesLoaded",
p)))}var g=this,d=c.isFunction(c.Deferred)?c.Deferred():0,r=c.isFunction(d.notify),e=g.find("img").add(g.filter("img")),l=[],j=[],h=[];c.isPlainObject(f)&&c.each(f,function(b,a){if("callback"===b)f=a;else if(d)d[b](a)});e.length?e.bind("load.imagesLoaded error.imagesLoaded",p).each(function(b,a){var d=a.src,e=c.data(a,"imagesLoaded");if(e&&e.src===d)k(a,e.isBroken);else if(a.complete&&a.naturalWidth!==q)k(a,0===a.naturalWidth||0===a.naturalHeight);else if(a.readyState||a.complete)a.src=m,a.src=d}):
n();return d?d.promise(g):g}})(jQuery);
// purl object for easy access to URL info
xBookUtils.pageCompleteURL = $.url();
// glossary/footnotes hash table
xBookUtils.terms = {};
// show answer hash table
xBookUtils.showAnswers = {};
// store link aliases
xBookUtils.links = {};
/*
getBookId: Return book ID (pulled from the URL). If for some reason this
fails (which it really shouldn't) return undefined.
*/
xBookUtils.getBookId = function() {
var baseURL = xBookUtils.getBaseUrl();
var match = baseURL.match(/\/([^\/]+)\/$/);
if (match != null) {
// redefine function so we don't have to do all this work next time
xBookUtils.getBookId = function() { return match[1]; }
return match[1];
}
return undefined;
}
/*
getChapter: Returns the current (numeric) chapter. Return undefined if
chapter can't be determined.
1. Looks for data-chapter-number on manuscript div (this should always happen)
2. Look for chapter number in URL (as a backup in case the above failed)
*/
xBookUtils.getChapter = function () {
// Check for data-chapter-number on manuscript div
var $manuscript = $("#manuscript");
if ($manuscript.length > 0) {
var chapter_number = $manuscript.data('chapter-number');
if (!xBookUtils.emptyValue(chapter_number)) {
// redefine function so we don't have to do all this work next time
xBookUtils.getChapter = function() { return chapter_number; }
return chapter_number;
}
}
// Look at URL
var pageUrl = xBookUtils.getPageUrl();
var match = pageUrl.match(/_ch(\d+)_/);
if (match != null) {
// redefine function so we don't have to do all this work next time
xBookUtils.getChapter = function() { return match[1]; }
return match[1];
}
return undefined;
}
/*
getPageUrl: Returns URL of page (not including hash fragment or query string).
*/
xBookUtils.getPageUrl = function() {
// Check query string for "ContentUrl" or Url"
var url = xBookUtils.getURLParameter('ContentUrl');
if (url === undefined) {
url = xBookUtils.getURLParameter('Url');
}
if (url !== undefined) {
// redefine function so we don't have to do all this work next time
xBookUtils.getPageUrl = function() { return url; }
return url;
}
// Otherwise return standard url
var returnUrl = xBookUtils.pageCompleteURL.attr('protocol') + "://" + xBookUtils.pageCompleteURL.attr('host') + xBookUtils.pageCompleteURL.attr('path');
// redefine function so we don't have to do all this work next time
xBookUtils.getPageUrl = function() { return returnUrl; }
return returnUrl;
}
/*
getBaseUrl: Get the 'base' URL for the book (the url for the main[root]
directory of the book). You can then tack on filename paths to create a URL
to a specific page.
This function always returns a URL with a trailing '/'.
*/
xBookUtils.getBaseUrl = function() {
// We must use getPageUrl to make sure we get the correct
// URL on PX
var curr_page_url = xBookUtils.getPageUrl();
// remove trailing filename (everything after the last '/')
var match = curr_page_url.match(/(.*\/).*/);
var base_url = match[1];
// remove asset/ (and all trailing directories) if found
base_url = base_url.replace(/\/asset\/.*/, "/");
// redefine function so we don't have to do all this work next time
xBookUtils.getBaseUrl = function() { return base_url; }
return base_url;
}
/*
getURLParameter: Return value of query string URL parameter.
Return undefined if parameter does not exist in query string.
*/
xBookUtils.getURLParameter = function(paramName) {
return xBookUtils.pageCompleteURL.param(paramName);
}
/*
externalUrl: Return true if the url is pointing to an external resource.
Otherwise return false.
*/
xBookUtils.externalUrl = function(url) {
if (typeof url !== "string") {
return false;
}
var trimmedUrl = $.trim(url);
if (/^[a-zA-Z0-9\+\.\-]+:\/\//.test(trimmedUrl)) {
return true;
}
return false;
}
/*
getSectionNumForId(id): Returns the section number for the 'id' that can then be
passed into show_section().
- If 'id' is already an ID of a section then return its section number
- If 'id' is an ID of any other element on the page then return the
parent section number of that element
- Otherwise, return undefined.
This function assumes it will not be called until all the section IDs have been
set by player.initialize_sections().
*/
xBookUtils.getSectionNumForId = function(id) {
// If id is undefined, return null
if (id === undefined || id === null) {
return undefined;
}
if (/^\d+$/.test(id)) {
return id;
}
var secMatch = id.match(/^digfir_section_(\d+)$/);
if (secMatch !== null) {
return secMatch[1];
}
// Find parent 'section div' of 'id' and return parent's ID
var $elem = $("#" + id);
if ($elem.length > 0) {
var $parent = $elem.first().parents("[data-type='section']");
if ($parent.length > 0) {
var p_id = $parent.first().attr("id");
if (p_id != undefined) {
var parMatch = p_id.match(/^digfir_section_(\d+)$/);
if (parMatch != null) {
return parMatch[1];
}
}
}
}
// We didn't find anything
return undefined;
}
/*
ebookPage: Return true if the url is pointing to an internal ebook page.
Otherwise return false.
*/
xBookUtils.ebookPage = function(url) {
if (/^[a-zA-Z0-9_\- ]+\.html([#\?].*)?$/.test(url)) {
return true;
}
return false;
}
/*
emptyValue(value): Returns true if the value is:
- undefined
- null
- zero length
- contains only space characters (no non-space characters)
Otherwise returns false.
This function is primarily used to ensure that an attribute has a defined value.
*/
xBookUtils.emptyValue = function (value) {
if (value === undefined || value === null ||
value.length == 0 || !/\S/.test(value)) {
return true;
}
return false;
}
/*
inPX: Return true if the page is being viewed in PX, otherwise return false.
*/
xBookUtils.inPX = function() {
// Check if we are in the PX frame.
if (xBookUtils.inPXFrame()) {
return true;
}
// We could still be in a supp window in PX, so check the URL.
// P.S. Not sure if this is the most reliable way to check this?
if (/dlap\.bfwpub\.com/.test(window.location.href)) {
return true;
}
return false;
}
/*
inPXFrame: Return true if the page is being viewed in the main PX content frame,
otherwise return false.
*/
xBookUtils.inPXFrame = function() {
try {
if (top.PxPage) {
return true;
}
}
catch(err) { }
return false;
}
/*
inMainContentFrame: Return true if we are viewing the page in the PX main
content frame or the DF wrapper main content frame or as just a stand-alone
page on DF. Otherwise return false.
This is used primarily to figure out if the page is being viewed in a supp
window.
*/
xBookUtils.inMainContentFrame = function() {
// Check if we are in the supp win nav page
if (xBookUtils.inSuppWinNavPage()) {
xBookUtils.inMainContentFrame = function() { return false; }
return false;
}
if (xBookUtils.inPX()) {
if (xBookUtils.inPXFrame()) {
xBookUtils.inMainContentFrame = function() { return true; }
return true;
}
xBookUtils.inMainContentFrame = function() { return false; }
return false;
}
// DF checks
try {
if (top.DFwrapper) {
xBookUtils.inMainContentFrame = function() { return true; }
return true;
}
}
catch(err) { }
xBookUtils.inMainContentFrame = function() { return false; }
return false;
}
/*
inDFWrapper: Return true if we are viewing the page in the DF wrapper,
otherwise return false;
*/
xBookUtils.inDFWrapper = function() {
try {
if (top.DFwrapper) {
return true;
}
}
catch(err) { }
return false;
}
/*
inSuppWinNavPage: Return true if we are viewing page in the special supplemental
window navigation page for ebook pages. Otherwise return false.
*/
xBookUtils.inSuppWinNavPage = function() {
var $supp_iframe;
try {
$supp_iframe = $('#xBookSuppWinNavPageFrame', window.parent.document);
}
catch(err) {
return false;
}
if ($supp_iframe.length > 0) {
xBookUtils.inSuppWinNavPage = function() { return true; }
return true;
}
xBookUtils.inSuppWinNavPage = function() { return false; }
return false;
}
/*
inLCViewer: Returns true if we are viewing the page in the LC dialog page viewer,
otherwise returns false.
*/
xBookUtils.inLCViewer = function() {
try {
// This is the best test I can find for determining if we are
// viewing the page in the LC page viewer.
var $fne_lc_div = $("iframe#content", window.parent.document);
if ($fne_lc_div.length == 1) {
xBookUtils.inLCViewer = function() { return true; }
return true;
}
}
catch (err) { }
xBookUtils.inLCViewer = function() { return false; }
return false;
}
/*
openSuppWin: Opens a URL (should not be an ebook page) in a supp window. The URL
can be to an external resource (e.g. http://www.slashdot.org) or an internal book
resource (e.g. asset/ch5/ch5_fig_1.jpg). The URL should not be another ebook
page (please use xBookUtils.openPageSuppWin to open ebook pages in supp window).
This function takes a context object as its argument. A url is required in the
context:
xBookUtils.openSuppWin({url: URL});
If the url is not fully qualified then it will be assumed that it is a relative
path to a file in the book.
Other context variables that may be passed in (you should not use these
unless you really know what you are doing and have a very good reason):
- name (the name of the supp window object)
- width (width of supp window)
- height (height of supp window)
- top (pixels from top of screen where it will be displayed [do not include "px"])
- left (pixels from left of screen where it will be displayed [do not include "px"])
*** READ THIS ***
To reiterate, if you need to open an ebook page in a supp window, please use:
xBookUtils.openPageSuppWin
*/
xBookUtils.openSuppWin = function (context) {
if (context.url === undefined) {
safe_log("xBookUtils.openSuppWin: url not defined");
return false;
}
var defaults = {
name: "xBookSuppWin",
width: 780,
height: 600,
top: 10,
left: 10
};
if (!xBookUtils.emptyValue(player.cfg_suppWinWidth) &&
/^\d+$/.test(player.cfg_suppWinWidth)) {
defaults.width = player.cfg_suppWinWidth;
}
var args = $.extend(defaults, context);
// If url is not fully qualified then assume it is a path to a file name
// for the current book and open it with the base url
if (!xBookUtils.externalUrl(args.url)) {
args.url = xBookUtils.getBaseUrl() + args.url;
}
// Open supp window
var suppWin = window.open(args.url, args.name, "top=" + args.top + ",left=" + args.left + ",width=" + args.width + ",height=" + args.height + ",menubar,resizable,scrollbars", true);
suppWin.focus();
return true;
}
/*
openPageSuppWin: Open an ebook page in a supp window. The context object should
contain the filename of the page to open:
xBookUtils.openPageSuppWin({page: "strayer2e_ch1_1.html"});
You will also need the supp_win.html file in the book's asset/ directory (see
Bruce if you don't have a copy).
*/
xBookUtils.openPageSuppWin = function(context) {
if (context.page === undefined) {
safe_log("xBookUtils.openPageSuppWin: page not passed into context");
return false;
}
var page = context.page;
// We may have a hash fragment
var match = page.match(/^(\/)?([a-zA-Z0-9_\- ]+\.html)(#.*)?$/);
if (match === null) {
safe_log("xBookUtils.openPageSuppWin: Invalid page (" + page + ")");
return false;
}
var target = "";
if (/^#.+/.test(match[3])) {
target = match[3];
target = target.slice(1);
target = "&target=" + target;
}
var suppWinLink = xBookUtils.getBaseUrl() + "asset/supp_win.html?bookid=" + xBookUtils.getBookId() + "&manuscript=" + match[2] + target + "&baseurl=" + xBookUtils.getBaseUrl();
xBookUtils.openSuppWin({url: suppWinLink, name: "xBookSuppWinNavPage", width: 875, height: 900});
}
/*
create_links(jQuery_Object): Converts all the link s in the jQuery
Object to tags. Unlike the original XRefs.create_links, this one
will honor the target attribute set in the XML and will also include
any custom data attributes.
This is used to replace the original create_links in XRefs.
*/
xBookUtils.create_links = function($jqObj) {
$jqObj.find("[data-type='link']").each(function() {
var $linkElement = $(this);
var linkUrl = $.trim($linkElement.data("href"));
var linkTarget = $.trim($linkElement.data("target"));
// This should never happen, but just in case
// This can be empty now. Must be dealt with in LinkHandler.
/*
if (xBookUtils.emptyValue(linkUrl)) {
return true;
}
*/
// include any custom data attributes
var data_attrs = "";
var data = $linkElement.data();
for(var prop in data){
if (prop !== "type" && prop !== "href" && prop !== "target" &&
prop !== "xrefs-target") {
data_attrs = data_attrs + " data-" + prop + "=\"" + data[prop] + "\"";
}
}
/* brb: We don't need to do this any more since the link
handler can take care of default targets for us but some
books might still depend on this or some books may not use
the link handler. So add a custom data attribute if we
set the default so that we know it was set here
and then we can override it somewhere else if needed. */
var data_xrefs_def = "";
if (xBookUtils.emptyValue(linkTarget)) {
// XRefs.create_links sets all links to target="_blank"
// so if no target was set in XML then do the same
linkTarget="_blank";
data_xrefs_def = " data-xrefs-target=\"1\"";
}
$linkElement.replaceWith("" + $linkElement.html() + "");
});
}
/*
procNativePXQuestions: This does a bunch of internal processing if your book
uses Native PX (html) questions. You will never call the function directly
in your javascript.
*/
xBookUtils.procNativePXQuestions = function($questions) {
/* Define some private helper functions */
function convertTags(b){var a=$("");a.append(b);var c=a.find('[data-type="link"]');if(c.length>0){a.find('[data-type="link"]').replaceWith(function(){var d=$(this);var e=false;var f="";if(this.attributes!==undefined){$.each(this.attributes,function(){if(this.specified){var g=this.name;var h=this.value;if(g==="data-type"){return true}if(g==="data-href"){g="href"}if(g==="data-target"){g="target";e=true}f=f+" "+g+"='"+h+"'"}})}if(!e){f=f+" target='_blank' data-xrefs-target='1'"}return"
"+d.html()+""})}return a.html()};
function getQuestionType(b){var a;if(b!=undefined){a=b}else{a=$('[data-type="question"]')}if(a.length<1){return null}var c=a.first().find('[data-encrypted="true"]');if(c.length==0){return"PX"}return"ARGA"};
function loadPXQuestions(g){var a;if(g!=undefined){a=g}else{a=$('[data-type="question"]')}if(a.length<1){return null}function j(l){if(l===undefined){safe_log("fix_xml: text undefined");return l}l=l.replace(//g,"");l=l.replace(/<(\?xml [^>]+|requests [^>]+|\/requests|\/?output)>/g,"");l=l.replace(//g,"
");l=l.replace(/
]+ questionid="([^"]+)" score="([^"]+)">/g,"");l=l.replace(/
]+ questionid="([^"]+)"([^>]+)?>/g,"");l=l.replace(/
]+)?>/g,"");l=l.replace(/<\/(interaction|question|body)>/g,"
");l=l.replace(/(.*?)<\/value><\/answer>/g,"$1
");l=l.replace(/.*?<\/meta>/g,"");l=l.replace(/]+)?>/g,"
");l=l.replace(/<\/div><\/choice>/g,"
");l=l.replace(/<\/div>
(.*?)<\/feedback>/g,"$1
");return l}var h=xBookUtils.getPageUrl();var e=h.replace(/(.*)\.html$/,"$1");var c=e+"_dlap.xml";var i=null;try{$.ajax({url:c,cache:false,dataType:"text",async:false,success:function(l){i=l},error:function(l,n,m){safe_log("Couldn't read "+c)}})}catch(d){safe_log("ajax error retrieving "+c+": "+d.message);return}if(i==null){return}var b=j(i);var f=$("").append(b).remove();var k=1;a.each(function(q,p){var m=$(p);var o=m.find("[data-type='query_display']");var n=o.attr("questionid");var r=f.find("#"+n);var v=r.find(".interaction");var t;if(v.data("type")=="essay"){var s=r.find(".body").html();t="
";o.html(t)}else{if(v.data("type")=="choice"){t="
undefined. ";var l=r.find(".body").html();t+=l+"
";var u=1;r.find(".choice").each(function(w,x){var y=$(x);t+="◯ | "+y.html()+" |
";u++});t+="
";o.html(t)}else{if(v.data("type")=="text"){t="
";o.html(t)}}}k++;m.children("[data-type='query_display']").css("display","block")})};
// Get all the questions on the page
//var $questions = $('[data-type="question"]');
// If there are no questions then we are done
if ($questions.length < 1) {
return;
}
// If they aren't Native PX questions then we are done
if (getQuestionType($questions) != "PX") {
return;
}
// If we are in a supp window then we need to load the question text
if (!xBookUtils.inMainContentFrame()) {
loadPXQuestions($questions);
}
// Else if we are in DF then we need to load the complete questions
else if (!xBookUtils.inPX()) {
var df_wrapper_script = document.createElement('script');
df_wrapper_script.setAttribute('type','text/javascript');
df_wrapper_script.setAttribute('src', "../../../wrapper/asset/wrapper_xbook.js");
document.getElementsByTagName("body")[0].appendChild(df_wrapper_script);
}
// Fix up tags in question text:
// - convert links s to s
// Constants to use for the timer
var MAX_TIMER_RUNS = 40;
var CURR_TIMER_RUN = 1;
var $remainingQuestions = $();
// Go through each question and process the question text. Keep trying
// until all questions have been processed.
var quesTimerId = setInterval(function() {
// when we start each timer interval we assume we will
// have no questions left to process by the end
$remainingQuestions = $(); // length = 0
// go through each question and process question text
$questions.each(function(index, element) {
var $quesElem = $(element);
// Get the question text.
// brb: The following selector is horrific but we have no choice
// because PX does not put a class on the containing the
// question text.
var $quesText = $quesElem.find('[data-type="query_display"] > .question-render > div > .bh > div:first-child');
// If there is no question text yet then we need to wait longer
if ($quesText.length == 0) {
// save off the remaining questions we have left to process
$remainingQuestions = $questions.slice(index);
// exit each() loop
return false;
}
// process the question text
$quesText.html(convertTags($quesText.html()));
// If this is an M/C question then we need to processs each option
if ($quesElem.find(".multiple-choice-question").length > 0) {
var $optionText = $quesElem.find("td.question-choice + td");
$optionText.each(function() {
var $this = $(this);
$this.html(convertTags($this.html()));
});
}
}); // end each()
// if we don't have any questions left, we are done
if ($remainingQuestions.length < 1) {
clearInterval(quesTimerId);
return;
}
// fallback safety trigger so we don't do this indefinitely
if (CURR_TIMER_RUN >= MAX_TIMER_RUNS) {
safe_log("We ran out of attempts while processing question text");
clearInterval(quesTimerId);
return;
}
$questions = $remainingQuestions;
CURR_TIMER_RUN++;
}, 200); // end setInterval()
}
// Old function to process Native PX Questions. Had to be called manually
// in initialize2. Not needed any more.
xBookUtils.processNativePXQuestions = function() {
return true;
}
/*
checkShowAnswer: This function is designed to be used with jQuery each(). Each
element is checked for a corresponding answer in xBookUtils.showAnswers. If found,
a 'show answer' button is attached to the element which will display the answer.
*/
xBookUtils.checkShowAnswer = function() {
var $this = $(this);
// The element needs to have an ID
var elem_id = $this.attr('id');
if (xBookUtils.emptyValue(elem_id)) {
return;
}
// If we've already found an answer for this element we are done
if ($this.data('found-show-answer') === "true") {
return;
}
var tag = this.nodeName.toLowerCase();
if (elem_id in xBookUtils.showAnswers) {
if (tag === "div") {
$this.append("
" + xBookUtils.showAnswers[elem_id] + "");
}
else {
$this.after("
" + xBookUtils.showAnswers[elem_id] + "");
}
$this.data('found-show-answer', 'true');
}
}
/*
moveBoxTitle: This function is designed to be used with jQuery each(). Moves
the h3 box title out of the inner box.
*/
xBookUtils.moveBoxTitle = function() {
var $this = $(this);
if (($this.attr('data-type') !== "box") ||
($this.attr('data-move-title') === "false")) {
return;
}
var $inner_box = $this.children('[data-type="box_inner"]');
if ($inner_box.length != 1) {
return;
}
var $h3_title = $inner_box.children('h3[data-for_type="box"]');
if ($h3_title.length != 1) {
return;
}
$inner_box.before($h3_title);
}
/*
prepareMarkup(content): Before dynamically inserting content into the page
(such as glossary defs/footnotes) we need to fix it up (such as adding the
domain to the src attribute).
*/
xBookUtils.prepareMarkup = function (content) {
// Fix src attribute if needed
content = content.replace(/src=['"]([^"']+)['"]/g, function($0, $1) {
if (!/^http/.test($1)) {
return "src='" + xBookUtils.getBaseUrl() + $1 + "'";
}
});
return content;
}
/*
inBrainhoneyPlayer: Returns true if the page has been sent through the
brainhoney player (primarily if the book was built with HTML Quiz q.d.m).
Otherwise returns false.
*/
xBookUtils.inBrainhoneyPlayer = function() {
if (/Content\/Exam\/Player\.aspx/.test(xBookUtils.pageCompleteURL.attr('path'))) {
return true;
}
return false;
}