aapssfc/book/common/js/user-highlights.js
2015-03-03 15:56:44 +01:00

364 lines
15 KiB
JavaScript

/*global variable declarations*/
var myHighlightApplier;
var cssClassApplierModule = rangy.modules.CssClassApplier;
var range, sel, highlightAction = "save";
var highlightResponseText;
var extendHighlightClass;
var urlList;
var extendType;
function enableUserHighlights(){
//check if it's not the contents or index page.
if ((window.location.href).toLowerCase().indexOf("index.html") == -1){
//checksum generator for each div.section and paragraph. Add that checksum as a class _[checksumValue]
$('body p, body .section').each(function(index) {
var s = $(this).text();
var i;
var chk = 0;
for (i = 0; i < s.length; i++) {
chk += (s.charCodeAt(i)*i);
}
$(this).addClass("_"+chk);
});
var lastPositionVal = $.getUrlVar('lastPosition');
if ( typeof lastPositionVal !== "undefined"){
$("body").append('<img src="../_static/last-point.png" style="position:absolute; padding-top:40px; left: 10px; top: '+parseInt(lastPositionVal)+'px;"/>');
$("html, body").animate({scrollTop: parseInt(lastPositionVal)}, 1000);
}
//Add the highlights on the page
restoreSelection();
//Add a container for highlights in the sidebar and populate
$(".sphinxsidebarwrapper").append('<div id="highlightbox"><h3>My Highlights</h3><ul></ul></div>');
updateHighlightBox();
var sec = $("body .section");
sec.splice(0,1);
sec.each(function(index) {
$(this).waypoint(function(direction) {
processPageState($(this));
});
});
$("body").append('<ul class="dropdown-menu" id="highlight-option-box" style="display:none;"><li><a href="javascript:void(0);" id="option-highlight-text" style="display:block;">Highlight</a></li></ul>');
$('body .section').on("mouseup", function(evt) {
sel = rangy.getSelection();
if (typeof sel !== "undefined" && sel.anchorNode != null && sel.focusNode != null){
var currAnchorNode = sel.anchorNode.parentElement;
var currFocusNode = sel.focusNode.parentElement;
}
if (typeof sel === "undefined" || (sel.anchorOffset == sel.focusOffset) && sel.anchorNode == sel.focusNode) {
$("#highlight-option-box").hide();
}
else if($(currAnchorNode).hasClass("my-highlighted-text") && $(currFocusNode).hasClass("my-highlighted-text")){
sel.expand("word"); //expands selection to closest word only if user selects atleast one character
highlightAction = "delete";
toggleHighlightOptionBox(evt,"Delete Highlight");
}
else if($(sel.getRangeAt(0).getNodes([1])).hasClass("my-highlighted-text")){
sel.expand("word");
toggleHighlightOptionBox(evt,"Extend Highlight");
if($(sel.getRangeAt(0).startContainer.parentElement).hasClass("my-highlighted-text")){ //extendEnd
var classList = $(sel.getRangeAt(0).startContainer.parentElement).attr('class').split(/\s+/); //get all classes applied to anchor element
extendType = "extendEnd";
}
else if($(sel.getRangeAt(0).endContainer.parentElement).hasClass("my-highlighted-text")){ //extendBeginning
var classList = $(sel.getRangeAt(0).endContainer.parentElement).attr('class').split(/\s+/); //get all classes applied to focus element
extendType = "extendBeginning";
}
else{ //extendBoth
var classList = "";
$(sel.getRangeAt(0).getNodes([1])).each(function(index, value) {
if($(value).hasClass("my-highlighted-text")){
classList = $(value).attr('class').split(/\s+/);
}
});
extendType = "extendBoth";
}
extendHighlightClass = findHighlightClass(classList);
highlightAction = "extend";
}
else if(!($(currAnchorNode).hasClass("my-highlighted-text") || $(currFocusNode).hasClass("my-highlighted-text"))){
sel.expand("word");
toggleHighlightOptionBox(evt,"Highlight");
highlightAction = "save";
}
});
$("#option-highlight-text").on('click', function(){
$("#highlight-option-box").hide();
switch(highlightAction){
case "save":
{
var uniqueId = "hl"+saveSelection(sel);
myHighlightApplier = rangy.createCssClassApplier("my-highlighted-text "+uniqueId, {normalize: true});
myHighlightApplier.applyToSelection();
$("."+uniqueId).first().attr("id",uniqueId);
window.getSelection().removeAllRanges();
updateHighlightBox();
break;
}
case "delete":
{
var classList =$($(sel.anchorNode)[0].parentElement).attr('class').split(/\s+/); //get all classes applied to element
var toDeleteHighlightClass = findHighlightClass(classList);
range = rangy.createRange();
myHighlightApplier = rangy.createCssClassApplier("my-highlighted-text", {normalize: true});
$(".hl"+toDeleteHighlightClass).each(function() { //loop over all nodes with the given class and remove the my-highlighted-text class
range.selectNodeContents(this);
myHighlightApplier.undoToRange(range);
});
window.getSelection().removeAllRanges();
toDelete = false;
deleteHighlight(toDeleteHighlightClass);
$(".hl"+toDeleteHighlightClass).attr("id","");
$(".hl"+toDeleteHighlightClass).removeClass("hl"+toDeleteHighlightClass);
updateHighlightBox();
break;
}
case "extend":
{
var existingHighlight = $(".hl"+extendHighlightClass);
var range = sel.getRangeAt(0);
//expand the selection to include the original highlight based on if it is extendEnd or extendBeginning
if (extendType == "extendEnd")
range.setStartBefore(existingHighlight[0]);
else if (extendType == "extendBeginning")
range.setEndAfter(existingHighlight[existingHighlight.length -1]);
sel.removeAllRanges(); //remove any existing ranges in selection
sel.addRange(range); //add the new expanded range to selection
//delete old highlight and save the expanded range as a new highlight
$(existingHighlight).removeClass("my-highlighted-text");
$(".hl"+extendHighlightClass).attr("id","");
$(".hl"+extendHighlightClass).removeClass("hl"+extendHighlightClass);
deleteHighlight(extendHighlightClass);
var newExtendHighlightClass = saveSelection(sel);
myHighlightApplier = rangy.createCssClassApplier("my-highlighted-text "+"hl"+newExtendHighlightClass, {normalize: true});
myHighlightApplier.applyToSelection();
$(".hl"+newExtendHighlightClass).first().attr("id","hl"+newExtendHighlightClass);
window.getSelection().removeAllRanges();
updateHighlightBox();
break;
}
}
});
}
else if ((window.location.href).toLowerCase().indexOf("/index.html") != -1){
var data = {course:eBookConfig.course};
jQuery.get(eBookConfig.ajaxURL+'getlastpage', data, function(data) {
if (data !="None"){
lastPageData = $.parseJSON(data);
if (lastPageData[0].lastPageChapter != null){
$("body .section .section:first").before('<div id="jump-to-chapter" class="alert" ><strong>You were Last Reading:</strong> '+lastPageData[0].lastPageChapter+ ((lastPageData[0].lastPageSubchapter) ? ' &gt; '+lastPageData[0].lastPageSubchapter : "")+' <a href="'+lastPageData[0].lastPageUrl+'?lastPosition='+lastPageData[0].lastPageScrollLocation+lastPageData[0].lastPageHash+'" style="float:right; margin-right:20px;">Continue Reading</a></div>');
}
}
});
}
};
function findHighlightClass(classList){
var className;
$.each( classList, function(index, item){
if (item.indexOf("hl") !== -1) { //locate class with hl
className = item;
}
});
return className.replace("hl","");
}
function toggleHighlightOptionBox(event, highlightOptionName){
$("#option-highlight-text").text(highlightOptionName);
$("#highlight-option-box").show().offset({
top: event.pageY + 5,
left: event.pageX + 5
});
}
//function to process the selection made by the user to identify the range and the parent selector. Calls function saveHighlight
function saveSelection(sel) {
var parentNode = sel._ranges[0].commonAncestorContainer;
var parentSelectorClass;
while(!(($(parentNode).is("p") || $(parentNode).is("div")) && $(parentNode).attr('class'))){
parentNode = $(parentNode)[0].parentElement;
}
$.each($(parentNode).attr('class').split(' '), function(index, value) {
if (value.indexOf("_") == 0){
parentSelectorClass = value;
}
});
var currentRange = sel.saveCharacterRanges(parentNode);
if(currentRange.length > 1){
currentRange[0].range.end = currentRange[currentRange.length -1].range.end;
var tempRange = currentRange.slice(0,1);
currentRange = tempRange;
}
var serializedRange = JSON.stringify(currentRange);
return saveHighlight(parentSelectorClass,serializedRange,"self");
}
//function called to save a new highlight
function saveHighlight(parentSelectorClass,serializedRange,saveMethod) {
var currPage = window.location.pathname;
var newId;
var currSection = window.location.pathname+window.location.hash;
var data = {parentClass:parentSelectorClass, range:serializedRange, method:saveMethod, page:currPage, pageSection: currSection, course:eBookConfig.course};
$(document).ajaxError(function(e,jqhxr,settings,exception){
console.log("Request Failed for "+settings.url);
});
jQuery.ajax({url: eBookConfig.ajaxURL+'savehighlight',data: data, async: false}).done(function(returndata) {
newId = returndata;
});
if (eBookConfig.logLevel > 0){
logBookEvent({'event':'highlight','act': 'save', 'div_id':currPage}); // Log the run event
}
return newId;
}
//function called to delete an existing highlight
function deleteHighlight(uniqueId) {
var currPage = window.location.pathname;
var data = {uniqueId: uniqueId};
$(document).ajaxError(function(e,jqhxr,settings,exception){
console.log("Request Failed for"+settings.url)
});
jQuery.post(eBookConfig.ajaxURL+'deletehighlight',data);
if (eBookConfig.logLevel > 0){
logBookEvent({'event':'highlight','act': 'delete', 'div_id':currPage}); // Log the run event
}
}
//add links to the highlights in sidebar on the right. Function called on page load and every edit of highlight
function updateHighlightBox() {
$("#highlightbox ul").html("");
var highlightJumpText = "";
var highlightLink;
var processingHighlight = false;
$("body .my-highlighted-text").each(function(index,value){
if($(value).attr("id")){
if (processingHighlight){
highlightJumpText = highlightJumpText.split(/\s+/, 12).join(" ")+"...";
$("#highlightbox ul").append("<li><a class='sidebar-highlights' href='"+window.location.pathname+"#"+highlightLink+"'>"+highlightJumpText+"</a></li><br/>");
}
highlightJumpText = "";
highlightLink = $(value).attr("id");
if ($(value)[0].firstChild)
highlightJumpText += $(value)[0].firstChild.textContent;
else
highlightJumpText +=$(value)[0].textContent;
processingHighlight = true;
}
else{
if ($(value)[0].firstChild)
highlightJumpText += $(value)[0].firstChild.textContent;
else
highlightJumpText +=$(value)[0].textContent;
}
});
if (processingHighlight){
highlightJumpText = highlightJumpText.split(/\s+/, 12).join(" ")+"...";
$("#highlightbox ul").append("<li><a class='sidebar-highlights' href='"+window.location.pathname+"#"+highlightLink+"'>"+highlightJumpText+"</a></li><br/>");
}
}
//function called at load time to fetch all highlights from database for the user and rendered on the page
function restoreSelection() {
rangy.init();
var currPage = window.location.pathname;
var data = {page: currPage ,course:eBookConfig.course};
jQuery.ajax({url: eBookConfig.ajaxURL+'gethighlights',data: data, async: false}).done(function(data) {
highlightResponseText = $.parseJSON(data);
var parentClassName, uniqueId;
$.each(highlightResponseText, function(index, value) {
parentClassName = "."+value.parentClass;
highlightClassName = "hl"+value.uniqueId;
rangy.getSelection().restoreCharacterRanges($(parentClassName)[0], $.parseJSON(value.range));
myHighlightApplier = rangy.createCssClassApplier("my-highlighted-text "+highlightClassName, {normalize: true});
myHighlightApplier.toggleSelection();
$("."+highlightClassName).first().attr("id",highlightClassName);
window.getSelection().removeAllRanges();
});
});
}
function processPageState(subChapterSectionElement){
/*Get the chapter name and subchaptername from the Waypoints jQuery plugin. Store in the database for last visited page*/
var chapterName, subChapterName;
chapterName = $("h1:first").text();
chapterName = chapterName.substring(0,chapterName.length -1); // strip out permalink character
subChapterName = subChapterSectionElement.find("h2").text();
subChapterName = subChapterName.substring(0, subChapterName.length -1); // strip out permalink character
subChapterId = subChapterSectionElement.attr("id");
var currentLink = subChapterId
/*Log last page visited*/
var currentPathname = window.location.pathname;
if (currentPathname.indexOf("?") !== -1)
currentPathname = currentPathname.substring(0, currentPathname.lastIndexOf("?"));
var data = {lastPageUrl:currentPathname, lastPageHash: currentLink, lastPageChapter:chapterName, lastPageSubchapter:subChapterName, lastPageScrollLocation: $(window).scrollTop(), course:eBookConfig.course};
$(document).ajaxError( function(e,jqhxr,settings,exception) {
console.log("Request Failed for "+settings.url)
} );
jQuery.ajax({url: eBookConfig.ajaxURL+'updatelastpage',data: data});
}
/*function processPageUnloadState(){
var chapterName, subChapterName;
var currentLink = "";
chapterName = $("h1:first").text();
chapterName = chapterName.substring(0,chapterName.length -1);
console.log("The current scrolled position is "+$(window).scrollTop());
$(urlList).each(function(index){
var currentID = $(urlList[index]).attr("href");
if ($(currentID).position()){
if ($(window).scrollTop() >= $(currentID).position().top && (index == (urlList.length - 1) || $(window).scrollTop() < $($(urlList[index+1]).attr("href")).position().top) ){
currentLink = $(this).attr("href");
}
}
if(currentID == currentLink){ //matches current opened subchapter
subChapterName = $(this).html();
}
});
/*Log last page visited*/
/* var currentPathname = window.location.pathname;
if (currentPathname.indexOf("?") !== -1)
currentPathname = currentPathname.substring(0, currentPathname.lastIndexOf("?"));
var data = {lastPageUrl:currentPathname, lastPageHash: currentLink, lastPageChapter:chapterName, lastPageSubchapter:subChapterName, lastPageScrollLocation: $(window).scrollTop(), course:eBookConfig.course};
$(document).ajaxError( function(e,jqhxr,settings,exception) {
alert("Request Failed for "+settings.url)
} );
jQuery.ajax({url: eBookConfig.ajaxURL+'updatelastpage',data: data, async: false});
}*/
$.extend({
getUrlVars: function(){
var vars = [], hash;
var hashes = window.location.search.slice(window.location.search.indexOf('?') + 1).split('&');
for(var i = 0; i < hashes.length; i++)
{
hash = hashes[i].split('=');
vars.push(hash[0]);
vars[hash[0]] = hash[1];
}
return vars;
},
getUrlVar: function(name){
return $.getUrlVars()[name];
}
});