$.fn.scrollTo = function( target, options, callback ){ if(typeof options == 'function' && arguments.length == 2){ callback = options; options = target; } var settings = $.extend({ scrollTarget : target, offsetTop : 50, duration : 500, easing : 'swing' }, options); return this.each(function(){ var scrollPane = $(this); var scrollTarget = (typeof settings.scrollTarget == "number") ? settings.scrollTarget : $(settings.scrollTarget); var scrollY = (typeof scrollTarget == "number") ? scrollTarget : scrollTarget.offset().top + scrollPane.scrollTop() - parseInt(settings.offsetTop); scrollPane.animate({scrollTop : scrollY }, parseInt(settings.duration), settings.easing, function(){ if (typeof callback == 'function') { callback.call(this); } }); }); } var IframeNotes = Class.extend({ iframe: null, // not sure we even need this? nw: null, // pop up window we'll display notes in showNotes: function() { safe_log("showNotes()"); if (this.nw === null || this.nw.closed) { var win_name = iframe_wrapper.getBookId() + "NotesSuppWin"; // create the pop up window this.nw = window.open("notes.html", win_name, "top=10px,left=10px,width=600,height=800,resizable,scrollbars", true); this.nw.focus(); } else { //this.nw.location.reload(); //safe_log("reload notes"); this.nw.focus(); this.nw.scrollToCurrentSection(); } }, closeNotes: function() { if (this.nw !== null && !this.nw.closed) { this.nw.close(); } }, init: function() { safe_log("IframeNotes.init()"); } }); var IframeFloatMenu = Class.extend({ bookId: null, // string iframe: null, // passed in from Iframe so we can load new pages in frame urlPath: null, // passed in from Iframe so we know the URL host notes: null, // correction notes /* These next two do not correspond with the page URL but rather with their place in the toc array */ url_path: null, // this is the URL path up to the 'chap_sec.html' toc: [], // array that holds toc data (toc[chap]{page}) - do these stay // in order??? toc_order: [], // array that holds the order of the chapters in the toc // don't really need these anymore since we can find them from toc_order[] first_chapter: null, // int last_chapter: null, /* These next two do not correspond with the page URL but rather with their place in the toc array */ curr_chapter: null, // (int) curr_page: null, // (int) // this stores the current index in toc_order[] toc_order_index: null, // (int) // this is the current file name (e.g. roark5e_ch16_1) curr_section: null, toc_html: null, // holds the html for the toc toc_in: null, menu_html: null, // html for menu //bottom_menu_html: null, // html for bottom nav menu // options for menu // all of these are true by default unless set to false during init doGlossary: false, // do we include glossary link in menu? doIndex: false, // do we include index link in menu? doTOC: true, // do we include TOC link in menu? doNotes: true, // notes are on by default unless we turn them off in toc.html // Since DF allows people to use uppercase on subtypes but then converts // the filenames to lowercase we need to map the filename sutype to the real // subtype. Developers SHOULD be using all lowercase in their subtypes but // once in a while someone forgets and so we need this mapping. subtype_alias: {}, // Setting this to true will turn on student view in the wrapper. This is done // with data-student-view="on" student_view: "off", getToc: function() { return this.toc; }, /* returns the bookID by parsing the section */ getBookIdFromSection: function (section) { console.log('getBookIdFromSection: ', section); if (section === undefined) { return null; } if (!(/\//.test(section))) { console.log('returning bookId ', this.bookId); return this.bookId; } //var match = section.match(/(.*\/)?(.*)_ch\d+_\d+(\.html)?/); var match = section.match(/(.*\/)?(.*?)_([a-z\d]+_\d+)$/); if (match !== null) { // check if we have an alias for this subtype if (match[2] in this.subtype_alias) { safe_log("getBookIdFromSection: found subtype alias for " + match[2] + " [" + this.subtype_alias[match[2]] + "]"); return this.subtype_alias[match[2]]; } safe_log("getBookIdFromSection: " + match[2]); return match[2]; } // allow for chapter level publishing var match2 = section.match(/(.*\/)?(.*?)_[a-z]+\d+$/); if (match2 !== null) { safe_log("getBookIdFromSection: chapter level publishing: " + match2[2]); return match2[2]; } return null; }, getSectionFromUrl: function (url) { if (url === undefined) { return null; } //safe_log("getSectionFromUrl: url = " + url); //var match = url.match(/(.*\/)?(.*_ch\d+_\d+)(\.html)?/); var match = url.match(/(.*\/)?(.*?)_(\d+)/); if (match !== null) { return match[2] + "_" + match[3]; } // allow pages published at chapter level var match2 = url.match(/(.*\/)?(.*?\d+)\.html/); if (match2 !== null) { safe_log("getSectionFromUrl: chapter published page: " + match2[2]); return match2[2]; } safe_log("getSectionFromUrl: oops, returning null for " + url); return null; }, // If no chap is passed in then we just return the first page in the book. // If chap is passed in and it exists then we return first page in chap, // otherwise we return null. getFirstSection: function (chap) { var toc_a = this.toc; var toc_order_a = this.toc_order; //safe_log("getFirstSection: chap = " + chap); // chapter passed in, return first section of chapter if (chap !== undefined) { if (toc_a[chap] === undefined) { safe_log("getFirstSection: chapter " + chap + " is not found in toc[]"); return null; } //safe_log("getFirstSection(1) returning " + toc_a[chap][1].file); return toc_a[chap][1].file; } // start at first chapter var toc_chap_num; //safe_log("getFirstSection: toc_order.length = " + toc_order_a.length); for (i = -1, n = toc_order_a.length; ++i < n;) { toc_chap_num = toc_order_a[i]; if (toc_a[toc_chap_num] !== undefined) { //safe_log("getFirstSection(2) returning " + toc_a[toc_chap_num][1].file); return toc_a[toc_chap_num][1].file; } } safe_log("getFirstSection: error"); }, // If no chap is passed in then we just return the last page in the book. // If chap is passed in and it exists then we return last page in chap, // otherwise we return null. getLastSection: function (chap) { var toc_a = this.toc; var chap_num; var chap_length; // first, get the chap number // if no chap num passed in then set to last chapter if (chap === undefined) { chap_num = this.getLastChapter(); } // otherwise, set to chapter passed in else { chap_num = chap; // if the chap num passed in doesn't exist then set to last chapter if (toc_a[chap_num] === undefined) { chap_num = this.getLastChapter(); } } //safe_log("getLastSection: chap_num = " + chap_num); // now return last section in the chapter var chap_length = toc_a[chap_num].length; //safe_log("getLastSection: " + toc_a[chap_num]); return toc_a[chap_num][chap_length-1].file; // no chapter passed, find last section in last chapter //if (chap === undefined) { //last_chap_num = toc_order_a[toc_order_a.length-1]; //last_chap_length = toc_a[last_chap_num].length - 1; //var toc_length = toc_a.length - 1; //var last_chapter_length = toc_a[toc_length].length - 1; //return toc_a[last_chap_num][last_chap_length].file; //} //if (toc_a[chap] === undefined) { //return null; //} //var chapter_length = toc_a[chap].length - 1; //return toc_a[chap][chapter_length].file; }, /* these next two will be need by the notes subsystem */ getCurrentSection: function () { return this.curr_section; }, getCurrentChapter: function () { return this.curr_chapter; }, getCurrentChapterLength: function () { //safe_log("getCurrentChapterLength: current chapter = " + this.getCurrentChapter()); return this.toc[this.getCurrentChapter()].length; }, // pass in a sec and get the section's chapter getSectionChapter: function(sec) { //safe_log("getSectionChapter: " + sec); if (sec === undefined) { return null; } // so we basically have to go through toc[] and find the sec var toc = this.toc; for (var i=-1, n=toc.length; ++i < n;) { if (toc[i] !== undefined) { for (var k=-1, z=toc[i].length; ++k < z;) { if (toc[i][k].file == sec) { return i; } } } } // if we don't find it (which is bad) return null return null; }, getNumberOfChapters: function () { return this.toc_order.length; }, getFirstChapter: function () { return this.toc_order[0]; }, getLastChapter: function () { //safe_log("getLastChapter: " + this.toc_order[this.toc_order.length-1]); return this.toc_order[this.toc_order.length-1]; }, getCurrentPage: function () { return this.curr_page; }, getPreviousSection: function (option) { var c_page = this.getCurrentPage(); var c_chap = this.getCurrentChapter(); var toc_a = this.toc; var toc_order_a = this.toc_order; var toc_order_index = this.toc_order_index; //safe_log("getPreviousSection: toc_order_index = " + toc_order_index + ", c_chap = " + c_chap); // if we are already at the first page in the book we are done if (this.getCurrentSection() == this.getFirstSection()) { //safe_log("getPreviousSection: already at first section"); return null; } // first check for previous page in the current chapter while (c_page > 1) { if (toc_a[c_chap][(c_page - 1)].skip === undefined) { if (option !== undefined && option === "title") { return toc_a[c_chap][(c_page - 1)].title; } return toc_a[c_chap][(c_page - 1)].file; } c_page--; } //safe_log("getPreviousSection: couldn't find previous page in current chapter " + c_chap); // if we are here then there is no previous page in the current // chapter and we need to find the last page in the preceding // chapter (this assumes that the last page would not be a skip) // if we are currently in the first chapter in the book then we are done if (toc_order_index == 0) { safe_log("getPreviousSection: toc_order_index is 0, we probably shouldn't be here"); return null; } var prev_chap_num = toc_order_a[toc_order_index - 1]; //var prev_chap_length = toc_a[prev_chap_num].length; //for (var i = (c_chap - 1); i > 0; i--) { //safe_log("getPreviousSection: prev_chap_num = " + prev_chap_num); if (toc_a[prev_chap_num] !== undefined) { var last_page_prev_chap = toc_a[prev_chap_num].length -1; if (option !== undefined && option === "title") { toc_a[prev_chap_num][last_page_prev_chap].title; } return toc_a[prev_chap_num][last_page_prev_chap].file; } // if we get here (and we probably shouldn't) that means there is no previous page safe_log("getPreviousSection: returning null at the end"); return null; }, // returns section name (e.g. roark5e_ch16_1) or null if current section // is the last in book getNextSection: function (option) { var c_page = this.getCurrentPage(); var c_chap = this.getCurrentChapter(); var toc_a = this.toc; var toc_order = this.toc_order; var toc_order_index = this.toc_order_index; //safe_log("getNextSection: " + c_page + ", " + c_chap); // if we are already at the last page we are done if (this.getCurrentSection() === this.getLastSection()) { //safe_log("getNextSection: current page == last section, returning null"); return null; } //safe_log("getNextSection: " + this.getCurrentSection() + ", " + this.getLastSection()); // first check for next page in the current chapter var curr_chap_length = this.getCurrentChapterLength(); //safe_log("getNextSection: " + curr_chap_length); while (c_page < (curr_chap_length - 1)) { if (toc_a[c_chap][(c_page + 1)].skip === undefined) { if (option !== undefined && option === "title") { return toc_a[c_chap][(c_page + 1)].title; } //safe_log("getNextSection: found next page in current chapter (" + toc_a[c_chap][(c_page + 1)].file + ")"); return toc_a[c_chap][(c_page + 1)].file; } c_page++; } // if we made it here than we are at the last page in the current chapter // so find the first page in the next chapter //var last_chap = this.getLastChapter(); var toc_order_length = toc_order.length; //for (var i = toc_order_index + 1; i <= toc_order_length; i++) { var next_chap_num = toc_order[toc_order_index + 1]; //safe_log("getNextSection: finding first section in next chapter (" + next_chap_num + ")"); if (toc_a[next_chap_num] !== undefined) { // a chapter always starts with page "1" if (toc_a[next_chap_num][1] !== undefined) { if (option !== undefined && option === "title") { return toc_a[next_chap_num][1].title; } return toc_a[next_chap_num][1].file; } // we shouldn't get here but just in case else { return null; } } // if we get here (and we probably shouldn't) that means there is no next page return null; }, loadSection: function(section) { var page_book_id = this.getBookIdFromSection(section); this.iframe.attr('src', "../../" + page_book_id + "/" + section + ".html"); if (this.viewingAs() == "student") { this.showMessage("You are currently in STUDENT VIEW"); } }, showMessage: function(mesg) { var $wrap_mesg = $('#wrapper_message'); $wrap_mesg.html(mesg); $wrap_mesg.show().delay(2000).fadeOut(); }, viewingAs: function() { if ($("body").hasClass("wrapper_student_view")) { return "student"; } else { return "instructor"; } }, // called only the first time showToc() is called createTocHtml: function () { var toc_a = this.toc; var toc_order_a = this.toc_order; var book_id = this.bookId; var html = "