diff --git a/assets.yml b/assets.yml index bedbdf965..40ec03e47 100644 --- a/assets.yml +++ b/assets.yml @@ -63,7 +63,6 @@ javascripts: - media/js/vendor/bootstrap-transition.js - media/js/vendor/highlight.js - media/js/vendor/fitvid.js - - media/js/vendor/bigfoot.js - media/js/newsblur/reader/reader_utils.js - media/js/newsblur/reader/reader.js - media/js/newsblur/reader/reader_popover.js @@ -121,7 +120,6 @@ stylesheets: - media/css/jquery.tipsy.css - media/css/vendor/bootstrap-progressbar.css - media/css/vendor/highlight.css - - media/css/vendor/bigfoot.css - media/css/*.css mobile: - media/css/mobile/jquery.mobile-1.0b1.css diff --git a/media/css/vendor/bigfoot.css b/media/css/vendor/bigfoot.css deleted file mode 100644 index 8d5a73a0c..000000000 --- a/media/css/vendor/bigfoot.css +++ /dev/null @@ -1,295 +0,0 @@ -.footnote-button { - position: relative; - z-index: 5; - top: -0.15em; - box-sizing: border-box; - -moz-box-sizing: border-box; - display: inline-block; - padding: 0.34em; - margin: 0 0.1em 0 0.2em; - border: none; - border-radius: 0.3em; - cursor: pointer; - opacity: 0.3; - background-color: #464646; - line-height: 0; - vertical-align: middle; - text-decoration: none; - font-smoothing: antialiased; - -webkit-transition: opacity; - -moz-transition: opacity; - -ms-transition: opacity; - transition: opacity; - -webkit-transition-duration: 0.25s; - -moz-transition-duration: 0.25s; - transition-duration: 0.25s; -} -.footnote-button:hover { - opacity: 0.6; -} -.footnote-button:active { - opacity: 0.6; -} -.footnote-button.active { - opacity: 0.9; - -webkit-transition-delay: 0.15s; - -moz-transition-delay: 0.15s; - transition-delay: 0.15s; -} - -.footnote-circle { - display: inline-block; - width: 0.32em; - height: 0.32em; - margin-right: 0.224em; - border-radius: 100%; - background-color: #e6e6e6; - border: none; -} -.footnote-circle:last-child { - margin-right: 0; -} - -@media not print { - .footnote-print-only { - display: none !important; - } -} -@media print { - .footnote-button { - display: none !important; - } -} -.footnote-content { - position: fixed; - z-index: 10; - bottom: auto; - left: auto; - box-sizing: border-box; - -moz-box-sizing: border-box; - max-width: 90%; - margin: 1.21924em auto; - display: inline-block; - background: #fafafa; - opacity: 0; - border-radius: 0.5em; - border: 1px solid #c3c3c3; - box-shadow: 0px 0px 8px rgba(0, 0, 0, 0.3); - -webkit-transition: opacity, -webkit-transform; - -moz-transition: opacity, -moz-transform; - -ms-transition: opacity, -ms-transform; - transition: opacity, transform; - -webkit-transition-duration: 0.25s; - -moz-transition-duration: 0.25s; - transition-duration: 0.25s; -} -.footnote-content:not(.fixed-bottom) { - -webkit-transform: scale(0.1) translateZ(0); - -moz-transform: scale(0.1) translateZ(0); - -ms-transform: scale(0.1) translateZ(0); - -o-transform: scale(0.1) translateZ(0); - transform: scale(0.1) translateZ(0); - -webkit-transform-origin: 50% 0; - -moz-transform-origin: 50% 0; - -ms-transform-origin: 50% 0; - -o-transform-origin: 50% 0; - transform-origin: 50% 0; -} -.footnote-content.active:not(.fixed-bottom) { - -webkit-transform: scale(1) translateZ(0); - -moz-transform: scale(1) translateZ(0); - -ms-transform: scale(1) translateZ(0); - -o-transform: scale(1) translateZ(0); - transform: scale(1) translateZ(0); - opacity: 0.97; -} -.footnote-content.bottom { - -webkit-transform-origin: top; - -moz-transform-origin: top; - -ms-transform-origin: top; - -o-transform-origin: top; - transform-origin: top; -} -.footnote-content.top { - -webkit-transform-origin: bottom; - -moz-transform-origin: bottom; - -ms-transform-origin: bottom; - -o-transform-origin: bottom; - transform-origin: bottom; -} -.footnote-content.fixed-bottom { - bottom: 0 !important; - top: auto !important; - left: 0 !important; - width: 100%; - max-width: 100%; - margin: 0; - -webkit-transform: translateY(105%); - -moz-transform: translateY(105%); - -ms-transform: translateY(105%); - -o-transform: translateY(105%); - transform: translateY(105%); - border-radius: 0; - opacity: 1; - -webkit-transition: -webkit-transform; - -moz-transition: -moz-transform; - -ms-transition: -ms-transform; - transition: transform; - -webkit-transition-duration: 0.25s; - -moz-transition-duration: 0.25s; - transition-duration: 0.25s; -} -.footnote-content.fixed-bottom.active { - -webkit-transform: translateY(0); - -moz-transform: translateY(0); - -ms-transform: translateY(0); - -o-transform: translateY(0); - transform: translateY(0); -} -.footnote-content.fixed-bottom .footnote-main-wrapper { - max-width: 90%; - width: 22em; - margin: 0 auto; -} -.footnote-content.fixed-bottom .tooltip { - display: none; -} -.footnote-content.scrollable:after { - content: '...'; - position: fixed; - bottom: 0.45em; - right: 50%; - z-index: 20; - width: 1.5em; - margin-right: -0.75em; - opacity: 1; - background-color: #fafafa; - font-family: Georgia; - font-weight: bold; - font-size: 1.8em; - text-align: center; - color: rgba(0, 0, 0, 0.08); - line-height: 0; - -webkit-transition: opacity; - -moz-transition: opacity; - -ms-transition: opacity; - transition: opacity; - -webkit-transition-duration: 0.25s; - -moz-transition-duration: 0.25s; - transition-duration: 0.25s; - -webkit-transition-delay: 0.4s; - -moz-transition-delay: 0.4s; - transition-delay: 0.4s; -} -.footnote-content.scrollable.fully-scrolled:after { - opacity: 0; - -webkit-transition-delay: 0s; - -moz-transition-delay: 0s; - transition-delay: 0s; -} -.footnote-content.scrollable .footnote-main-wrapper:before, .footnote-content.scrollable .footnote-main-wrapper:after { - content: ' '; - position: absolute; - width: 100%; - z-index: 12; -} -.footnote-content.scrollable .footnote-main-wrapper:before { - top: -1px; - left: 0; - height: 1.1em; - border-radius: 0.5em 0.5em 0 0; - background: #fafafa; - background: -moz-linear-gradient(top, #fafafa 0%, #fafafa 50%, rgba(250, 250, 250, 0) 100%); - background: -webkit-gradient(linear, left top, left bottom, color-stop(0%, #fafafa), color-stop(50%, #fafafa), color-stop(100%, rgba(250, 250, 250, 0))); - background: -webkit-linear-gradient(top, #fafafa 0%, #fafafa 50%, rgba(250, 250, 250, 0) 100%); - background: -o-linear-gradient(top, #fafafa 0%, #fafafa 50%, rgba(250, 250, 250, 0) 100%); - background: -ms-linear-gradient(top, #fafafa 0%, #fafafa 50%, rgba(250, 250, 250, 0) 100%); - background: linear, to bottom, #fafafa 0%, #fafafa 50%, rgba(250, 250, 250, 0) 100%; -} -.footnote-content.scrollable .footnote-main-wrapper:after { - bottom: -1px; - left: 0; - height: 1.2em; - border-radius: 0 0 0.5em 0.5em; - background: #fafafa; - background: -moz-linear-gradient(bottom, #fafafa 0%, #fafafa 50%, rgba(250, 250, 250, 0) 100%); - background: -webkit-gradient(linear, left bottom, left top, color-stop(0%, #fafafa), color-stop(50%, #fafafa), color-stop(100%, rgba(250, 250, 250, 0))); - background: -webkit-linear-gradient(bottom, #fafafa 0%, #fafafa 50%, rgba(250, 250, 250, 0) 100%); - background: -o-linear-gradient(bottom, #fafafa 0%, #fafafa 50%, rgba(250, 250, 250, 0) 100%); - background: -ms-linear-gradient(bottom, #fafafa 0%, #fafafa 50%, rgba(250, 250, 250, 0) 100%); - background: linear, to top, #fafafa 0%, #fafafa 50%, rgba(250, 250, 250, 0) 100%; -} -.footnote-content ::-webkit-scrollbar { - display: none; -} - -.footnote-main-wrapper { - position: relative; - z-index: 14; - box-sizing: border-box; - -moz-box-sizing: border-box; - overflow: hidden; - margin: 0; - max-width: 22em; - background-color: #fafafa; - border-radius: 0.5em; - -webkit-transition: max-height; - -moz-transition: max-height; - -ms-transition: max-height; - transition: max-height; - -webkit-transition-duration: 0.25s; - -moz-transition-duration: 0.25s; - transition-duration: 0.25s; -} - -.footnote-content-wrapper { - position: relative; - z-index: 8; - max-height: 15em; - padding: 1.1em 1.3em 1.2em; - box-sizing: border-box; - -moz-box-sizing: border-box; - overflow: auto; - -webkit-overflow-scrolling: touch; - background: #fafafa; - border-radius: 0.5em; - -webkit-font-smoothing: subpixel-antialiased; -} -.footnote-content-wrapper img { - max-width: 100%; -} -.footnote-content-wrapper *:last-child { - margin-bottom: 0; -} -.footnote-content-wrapper *:first-child { - margin-top: 0; -} - -.tooltip { - position: absolute; - z-index: 12; - box-sizing: border-box; - -moz-box-sizing: border-box; - margin-left: -0.65em; - width: 1.3em; - height: 1.3em; - -webkit-transform: rotate(45deg); - -moz-transform: rotate(45deg); - -ms-transform: rotate(45deg); - -o-transform: rotate(45deg); - transform: rotate(45deg); - background: #fafafa; - border: 1px solid #c3c3c3; - box-shadow: 0px 0px 8px rgba(0, 0, 0, 0.3); - border-top-left-radius: 0; -} - -.bottom .tooltip { - top: -0.65em; - bottom: auto; -} - -.top .tooltip { - bottom: -0.65em; - top: auto; -} diff --git a/media/js/newsblur/views/story_detail_view.js b/media/js/newsblur/views/story_detail_view.js index 2f2609c7d..a76bf6d94 100644 --- a/media/js/newsblur/views/story_detail_view.js +++ b/media/js/newsblur/views/story_detail_view.js @@ -87,12 +87,15 @@ NEWSBLUR.Views.StoryDetailView = Backbone.View.extend({ this.toggle_intelligence(); this.generate_gradients(); this.render_comments(); + + return this; + }, + + attach_handlers: function() { + this.watch_images_for_story_height(); this.attach_audio_handler(); - this.attach_footnotes_handler(); this.attach_syntax_highlighter_handler(); this.attach_fitvid_handler(); - - return this; }, render_header: function(model, value, options) { @@ -536,17 +539,7 @@ NEWSBLUR.Views.StoryDetailView = Backbone.View.extend({ this.$('pre').each(function(i, e) { hljs.highlightBlock(e); }); - }, this), 1000); - }, - - attach_footnotes_handler: function() { - _.delay(_.bind(function() { - $.bigfoot({ - scope: this.$el, - actionOriginalFN: 'ignore' - }); - }, this), 500); - + }, this), 100); }, attach_fitvid_handler: function() { @@ -555,7 +548,7 @@ NEWSBLUR.Views.StoryDetailView = Backbone.View.extend({ this.$el.fitVids({ customSelector: "iframe[src*='youtu.be'],iframe[src*='www.flickr.com'],iframe[src*='view.vzaar.com']" }); - }, this), 500); + }, this), 50); }, // ========== @@ -564,13 +557,14 @@ NEWSBLUR.Views.StoryDetailView = Backbone.View.extend({ click_link_in_story: function(e) { if (NEWSBLUR.hotkeys.shift) return; + var $target = $(e.currentTarget); e.preventDefault(); e.stopPropagation(); if (e.which >= 2) return; if (e.which == 1 && $('.NB-menu-manage-container:visible').length) return; - var href = $(e.currentTarget).attr('href'); + var href = $target.attr('href'); if (NEWSBLUR.assets.preference('new_window') == 1) { window.open(href, '_blank'); diff --git a/media/js/newsblur/views/story_list_view.js b/media/js/newsblur/views/story_list_view.js index 108d6ca3a..b8fc4d473 100644 --- a/media/js/newsblur/views/story_list_view.js +++ b/media/js/newsblur/views/story_list_view.js @@ -64,7 +64,7 @@ NEWSBLUR.Views.StoryListView = Backbone.View.extend({ } else { this.$el.html(_.pluck(stories, 'el')); } - _.invoke(stories, 'watch_images_for_story_height'); + _.invoke(stories, 'attach_handlers'); this.show_correct_feed_in_feed_title_floater(); this.stories = stories; _.defer(this.check_feed_view_scrolled_to_bottom); @@ -86,7 +86,7 @@ NEWSBLUR.Views.StoryListView = Backbone.View.extend({ if (!NEWSBLUR.assets.preference('feed_view_single_story')) { this.$el.append(_.pluck(stories, 'el')); } - _.invoke(stories, 'watch_images_for_story_height'); + _.invoke(stories, 'attach_handlers'); this.stories = this.stories.concat(stories); _.defer(this.check_feed_view_scrolled_to_bottom); diff --git a/media/js/newsblur/views/story_title_view.js b/media/js/newsblur/views/story_title_view.js index e681879c2..8ef6e1e5d 100644 --- a/media/js/newsblur/views/story_title_view.js +++ b/media/js/newsblur/views/story_title_view.js @@ -84,7 +84,7 @@ NEWSBLUR.Views.StoryTitleView = Backbone.View.extend({ inline_story_title: true }).render(); this.$(".NB-story-detail").html(this.story_detail.$el); - this.story_detail.watch_images_for_story_height(); + this.story_detail.attach_handlers(); } }, diff --git a/media/js/vendor/bigfoot.js b/media/js/vendor/bigfoot.js deleted file mode 100644 index 20c9a5517..000000000 --- a/media/js/vendor/bigfoot.js +++ /dev/null @@ -1,1241 +0,0 @@ -// _______ ________ _______ ______ ______ ______ _________ -// /_______/\ /_______/\/______/\ /_____/\ /_____/\ /_____/\ /________/\ -// \::: _ \ \ \__.::._\/\::::__\/__\::::_\/_\:::_ \ \\:::_ \ \\__.::.__\/ -// \::(_) \/_ \::\ \ \:\ /____/\\:\/___/\\:\ \ \ \\:\ \ \ \ \::\ \ -// \:: _ \ \ _\::\ \__\:\\_ _\/ \:::._\/ \:\ \ \ \\:\ \ \ \ \::\ \ -// \::(_) \ \/__\::\__/\\:\_\ \ \ \:\ \ \:\_\ \ \\:\_\ \ \ \::\ \ -// \_______\/\________\/ \_____\/ \_\/ \_____\/ \_____\/ \__\/ -// _________________________________________________________________ -// /________________________________________________________________/\ -// \________________________________________________________________\/ - -// PURPOSE ----- -// Looks through the page's markup to identify footnote links/ content. -// It then creates footnote buttons in place of the footnote links and hides the content. -// Finally, creates and positions footnotes when the generated buttons are pressed. - -// IN ---------- -// An optional object literal specifying script settings. - -// OUT --------- -// Returns an object with the following methods: -// close: closes footnotes matching the jQuery selector passed to the function. -// activate: activates the footnote button matching the jQuery selector passed to the function. - -// INFO -------- -// Developed and maintained by Chris Sauve (http://pxldot.com) -// Documentation, license, and other information can be found at http://cmsauve.com/projects/bigfoot. - -// TODO -------- -// - Better handling of hover -// - Ability to position/ size popover relative to a containing element (rather than the window) -// - Compensate for zoom position on mobile -// - Update numbered style to handle more than 9 footnotes - -// KNOWN ISSUES - -// - Safari 7 doesn't properly calculate the scrollheight of the content wrapper and, as a result, will not -// properly indicate a scrollable footnote -// - Popovers that are instantiated at a smaller font size which is then resized to a larger one won't adhere -// to your chosen max-height (in CSS) since JS tries to keep it from running off the top/ bottom of the page -// but does so using pixel values tied to the sizes of the footnote content when it was originally activated. -// If anyone has any ideas on this, please let me know! - - - -(function($) { - - $.bigfoot = function(options) { - - - // ______ ______ _________ _________ ________ ___ __ _______ ______ - // /_____/\ /_____/\ /________/\/________/\/_______/\/__/\ /__/\ /______/\ /_____/\ - // \::::_\/_\::::_\/_\__.::.__\/\__.::.__\/\__.::._\/\::\_\\ \ \\::::__\/__\::::_\/_ - // \:\/___/\\:\/___/\ \::\ \ \::\ \ \::\ \ \:. `-\ \ \\:\ /____/\\:\/___/\ - // \_::._\:\\::___\/_ \::\ \ \::\ \ _\::\ \__\:. _ \ \\:\\_ _\/ \_::._\:\ - // /____\:\\:\____/\ \::\ \ \::\ \ /__\::\__/\\. \`-\ \ \\:\_\ \ \ /____\:\ - // \_____\/ \_____\/ \__\/ \__\/ \________\/ \__\/ \__\/ \_____\/ \_____\/ - // - - var bigfoot; - - var settings = $.extend( - { - actionOriginalFN : "hide", // "delete", "hide", or "ignore" - activateCallback : function() {}, - activateOnHover : false, - allowMultipleFN : false, - appendPopoversTo : undefined, - breakpoints : {}, - deleteOnUnhover : false, - hoverDelay : 250, - numberResetSelector : undefined, - popoverDeleteDelay : 300, - popoverCreateDelay : 100, - positionNextToBlock : true, - positionContent : true, - preventPageScroll : true, - scope : false, - - contentMarkup : "", - - buttonMarkup : "" + - "" + - "" + - "" + - "" - }, options); - - - - // ________ ___ __ ________ _________ - // /_______/\/__/\ /__/\ /_______/\/________/\ - // \__.::._\/\::\_\\ \ \ \__.::._\/\__.::.__\/ - // \::\ \ \:. `-\ \ \ \::\ \ \::\ \ - // _\::\ \__\:. _ \ \ _\::\ \__ \::\ \ - // /__\::\__/\\. \`-\ \ \/__\::\__/\ \::\ \ - // \________\/ \__\/ \__\/\________\/ \__\/ - // - - - // FUNCTION ---- - // Footnote button/ content initializer (run on doc.ready) - - // PURPOSE ----- - // Finds the likely footnote links and then uses their target to find the content - - var footnoteInit = function() { - - // Get all of the possible footnote links - var footnoteButtonSearchQuery; - footnoteButtonSearchQuery = !settings.scope ? $("a[href*=\"#\"]") : settings.scope.find(" a[href*=\"#\"]"); - - // Filter down to links that: - // - have an HREF referencing a footnote, OR - // - have a rel attribute of footnote - // AND that aren't a descendant of a footnote (prevents backlinks) - var $footnoteAnchors = footnoteButtonSearchQuery.filter(function() { - var $this = $(this); - var relAttr = $this.attr("rel"); - if(!relAttr || relAttr == "null") { - relAttr = ""; - } - return ($this.attr("href") + relAttr).match(/(fn|footnote|note)[:\-_\d]/gi) && $this.closest("[class*=footnote]:not(a):not(sup)").length < 1; - }); // End of footnote link .filter() - - var footnotes = [], - footnoteLinks = [], - finalFNLinks = [], - relatedFN, - $closestFootnoteLi; - - // Resolve issues with superscript/ anchor combination - cleanFootnoteLinks($footnoteAnchors, footnoteLinks); - - // Get the footnote that the link was pointing to - $(footnoteLinks).each(function() { - // escape symbols with special jQuery/ CSS selector meaning - relatedFN = $(this).attr("data-footnote-ref").replace(/[:.+~*\]\[]/g, "\\$&"); - $closestFootnoteLi = $(relatedFN).closest("li"); - if($closestFootnoteLi.length > 0) { - footnotes.push($closestFootnoteLi); - finalFNLinks.push(this); - } - }); - - var $lastResetElement, - $curResetElement, - footnoteNum = 1, - footnoteContent, - footnoteIDNum, - $relevantFNLink, - $relevantFootnote, - footnoteButton, - $footnoteButton; - - // Initiates the button with the footnote content - // Also performs the desired action on the original footnotes - for(var i = 0; i/< symbols to prevent conflicts - footnoteContent = removeBackLinks($(footnotes[i]).html().trim(), $(finalFNLinks[i]) - .data("footnote-backlink-ref")).replace(/"/g, """) - .replace(/</g, "<sym;").replace(/>/g, ">sym;"); - footnoteIDNum = +(i + 1); - footnoteButton = ""; - $relevantFNLink = $(finalFNLinks[i]); - $relevantFootnote = $(footnotes[i]); - - // Determines whether this is in the same number reset container (as defined in settings) - // as the last footnote and changes the footnote number accordingly - if(settings.numberResetSelector) { - $curResetElement = $relevantFNLink.closest(settings.numberResetSelector); - if($curResetElement.is($lastResetElement)) { - footnoteNum += 1; - } else { - footnoteNum = 1; - } - $lastResetElement = $curResetElement; - } else { - footnoteNum = footnoteIDNum; - } - - // Add a paragraph container if the footnote was written directly in the list element - if(footnoteContent.indexOf("<") !== 0) { - footnoteContent = "

" + footnoteContent + "

"; - } - - // Gives default button markup unless custom one is defined - // Gets the easy replacements out of the way - footnoteButton = settings.buttonMarkup.replace(/\{\{FOOTNOTENUM\}\}/g, footnoteNum) - .replace(/\{\{FOOTNOTEID\}\}/g, footnoteIDNum) - .replace(/\{\{FOOTNOTECONTENT\}\}/g, footnoteContent); - - // Handles replacements of SUP/FN attribute requests - footnoteButton = replaceWithReferenceAttributes(footnoteButton, "SUP", $relevantFNLink); - footnoteButton = replaceWithReferenceAttributes(footnoteButton, "FN", $relevantFootnote); - - $footnoteButton = $(footnoteButton).insertBefore($relevantFNLink); - - var $parent = $relevantFootnote.parent(); - switch(settings.actionOriginalFN.toLowerCase()) { - case "delete": - $relevantFNLink.remove(); - $relevantFootnote.remove(); - deleteEmptyOrHR($parent); - break; - case "hide": - $relevantFNLink.addClass("footnote-print-only"); - $relevantFootnote.addClass("footnote-print-only"); - deleteEmptyOrHR($parent); - break; - case "ignore": - $relevantFNLink.addClass("footnote-print-only"); - break; - } - } // end of loop through footnotes - }; - - - // FUNCTION ---- - // cleanFootnoteLinks - - // PURPOSE ----- - // Groups the ID and HREF of a superscript/ anchor tag pair in data attributes - // This resolves the issue of the href and backlink id being separated between the two elements - - // IN ---------- - // Anchors that link to footnotes - - // OUT --------- - // Array of top-level emenets with data attributes for combined ID/ HREF - - var cleanFootnoteLinks = function($footnoteAnchors, footnoteLinks) { - var $supParent, - $supChild, - linkHREF, - linkID; - - // Problem: backlink ID might point to containing superscript of the fn link - // Solution: Check if there is a superscript and move the href/ ID up to it. - // The combined id/ href of the sup/a pair are stored in sup using data attributes - $footnoteAnchors.each(function() { - var $this = $(this); - linkHREF = "#" + ($this.attr("href")).split("#")[1]; // just the fragment ID - $supParent = $this.closest("sup"); - $supChild = $this.find("sup"); - - if($supParent.length > 0) { - // Assign the link ID to be the parent's and child's combined - linkID = ($supParent.attr("id") || "") + ($this.attr("id") || ""); - footnoteLinks.push( - $supParent.attr({ - "data-footnote-backlink-ref": linkID, - "data-footnote-ref": linkHREF - }) - ); - } else if($supChild.length > 0) { - linkID = ($supChild.attr("id") || "") + ($this.attr("id") || ""); - footnoteLinks.push( - $this.attr({ - "data-footnote-backlink-ref": linkID, - "data-footnote-ref": linkHREF - }) - ); - } else { - // || "" protects against undefined ID's - linkID = $this.attr("id") || ""; - footnoteLinks.push( - $this.attr({ - "data-footnote-backlink-ref": linkID, - "data-footnote-ref": linkHREF - }) - ); - } - }); - }; - - - // FUNCTION ---- - // deleteEmptyOrHR - - // PURPOSE ----- - // Propogates the decision of deleting/ hiding the original footnotes up the hierarchy, - // eliminating any empty/ fully-hidden elements containing the footnotes and - // any horizontal rules used to denote the start of the footnote section - - // IN ---------- - // Container of the footnote that was deleted/ hidden - - // OUT --------- - // Array of top-level emenets with data attributes for combined ID/ HREF - - var deleteEmptyOrHR = function($el) { - - var $parent; - // If it has no children or all children have been hidden - if($el.is(":empty") || $el.children(":not(.footnote-print-only)").length === 0) { - $parent = $el.parent(); - if(settings.actionOriginalFN.toLowerCase() === "delete") { - $el.remove(); - } else { - $el.addClass("footnote-print-only"); - } - - // Propogate up to the container element - deleteEmptyOrHR($parent); - - } else if($el.children(":not(.footnote-print-only)").length == $el.children("hr:not(.footnote-print-only)").length) { - - // If the only child not hidden/ removed is a horizontal rule, remove the entire container - $parent = $el.parent(); - if(settings.actionOriginalFN.toLowerCase() === "delete") { - $el.remove(); - } else { - $el.children("hr").addClass("footnote-print-only"); - $el.addClass("footnote-print-only"); - } - - // Propogate up to the container element - deleteEmptyOrHR($parent); - } - }; - - - // FUNCTION ---- - // removeBackLinks - - // PURPOSE ----- - // Removes any links from the footnote back to the footnote link - // as these don't make sense when the footnote is shown inline - - // IN ---------- - // HTML of the footnote possibly containing the backlink and - // the ID(s) of the footnote link - - // OUT --------- - // New HTML string with relevant links taken out - - var removeBackLinks = function(footnoteHTML, backlinkID) { - - // First, though, take care of multiple ID's by getting rid of spaces - if(backlinkID.indexOf(" ") >= 0) { - backlinkID = backlinkID.trim().replace(/ +/g, "|").replace(/(.*)/g, "($1)"); - } - - // Regex finds the preceding space/ nbsp, the anchor tag and contents - var regex = new RegExp("(\\s| )*<\\s*a[^#<]*#" + backlinkID + "[^>]*>(.*?)<\\s*/\\s*a>", "g"); - return footnoteHTML.replace(regex, "").replace("[]", ""); - }; - - - // FUNCTION ---- - // replaceWithReferenceAttributes - - // PURPOSE ----- - // Replaces the reference attributes (encased in {{}}) with the relevant attributes - // from the desired element; for example, {{SUP:id}} will be replaced with the ID of the - // superscript element passed as $referenceElement - - // IN ---------- - // String to do replacements on, the reference keyword to look for (i.e., BUTTON or SUP), - // and the associated element to search through for the identified attribute(s) - - // OUT --------- - // New string with replacements performed - - var replaceWithReferenceAttributes = function(string, referenceKeyword, $referenceElement) { - var refRegex = new RegExp("\\{\\{" + referenceKeyword + ":([^\\}]*)\\}\\}", "g"), - refMatches, - refReplaceText, - refReplaceRegex; - - // Performs the regex and does the replacement until it doesn't find any more matches - refMatches = refRegex.exec(string); - while (refMatches) { - // refMatches[1] stores the attribute that is to be matched - if(refMatches[1]) { - refReplaceText = $referenceElement.attr(refMatches[1]) || ""; - string = string.replace("{{" + referenceKeyword + ":" + refMatches[1] + "}}", refReplaceText); - } - refMatches = refRegex.exec(string); - } - return string; - }; - - - - // ________ ______ _________ ________ __ __ ________ _________ ______ - // /_______/\ /_____/\/________/\/_______/\/_/\ /_/\ /_______/\ /________/\/_____/\ - // \::: _ \ \\:::__\/\__.::.__\/\__.::._\/\:\ \\ \ \\::: _ \ \\__.::.__\/\::::_\/_ - // \::(_) \ \\:\ \ __ \::\ \ \::\ \ \:\ \\ \ \\::(_) \ \ \::\ \ \:\/___/\ - // \:: __ \ \\:\ \/_/\ \::\ \ _\::\ \__\:\_/.:\ \\:: __ \ \ \::\ \ \::___\/_ - // \:.\ \ \ \\:\_\ \ \ \::\ \ /__\::\__/\\ ..::/ / \:.\ \ \ \ \::\ \ \:\____/\ - // \__\/\__\/ \_____\/ \__\/ \________\/ \___/_( \__\/\__\/ \__\/ \_____\/ - // - - - // FUNCTION ---- - // buttonHover - - // PURPOSE ----- - // To activate the popover of a hovered footnote button - // Also removes other popovers, if allowMultipleFN is false - - // IN ---------- - // Event that contains the target of the mouseenter event - - var buttonHover = function(e) { - if(settings.activateOnHover) { - var $buttonHovered = $(e.target).closest(".footnote-button"), - dataIdentifier = "[data-footnote-identifier=\"" + $buttonHovered.attr("data-footnote-identifier") + "\"]"; - if($buttonHovered.hasClass("active")) return; - - $buttonHovered.addClass("hover-instantiated"); - - // Delete other popovers, unless overriden in the settings - if(!settings.allowMultipleFN) { - var otherPopoverSelector = ".footnote-content:not(" + dataIdentifier + ")"; - removePopovers(otherPopoverSelector); - } - createPopover(".footnote-button" + dataIdentifier).addClass("hover-instantiated"); - } - }; - - - // FUNCTION ---- - // touchClick - - // PURPOSE ----- - // Activates the button the was clicked/ taps - // Also removes other popovers, if allowMultipleFN is false - // Finally, removes all popovers if something non-fn related was clicked/ tapped - - // IN ---------- - // Event that contains the target of the tap/click event - - var touchClick = function(e){ - var $target = $(e.target), - $nearButton = $target.closest(".footnote-button"); - $nearFootnote = $target.closest(".footnote-content"); - - // If a button was tapped/ clicked - if($nearButton.length > 0) { - // Button was clicked - // Cancel the link, if it exists - e.preventDefault(); - - // Do the button clicking - clickButton($nearButton); - - } else if($nearFootnote.length < 1) { - // Something other than a button or popover was pressed - if($(".footnote-content").length > 0) { - removePopovers(); - } - - } - }; - - - // FUNCTION ---- - // clickButton - - // PURPOSE ----- - // Handles the logic of clicking/ tapping the footnote button - // That is, activates the popover if it isn't already active (+ deactivate others, if appropriate) - // or, deactivates the popover if it is already active - - // IN ---------- - // Button being clicked/ pressed - - var clickButton = function($button) { - - // Cancel blur - $button.blur(); - - // Get the identifier of the footnote - var dataIdentifier = "data-footnote-identifier=\"" + $button.attr("data-footnote-identifier") + "\""; - - // Only create footnote if it's not already active - // If it's activating, ignore the new activation until the popover is fully formed. - if($button.hasClass("changing")) { - - return; - - } else if(!$button.hasClass("active")) { - - $button.addClass("changing"); - setTimeout(function() { - $button.removeClass("changing"); - }, settings.popoverCreateDelay); - createPopover(".footnote-button[" + dataIdentifier + "]"); - $button.addClass("click-instantiated"); - - // Delete all other footnote popovers if we are only allowing one - if(!settings.allowMultipleFN) { - removePopovers(".footnote-content:not([" + dataIdentifier + "])"); - } - - } else { - - // A fully instantiated footnote; either remove it or all footnotes, depending on settings - if(!settings.allowMultipleFN) { - removePopovers(); - } else { - removePopovers(".footnote-content[" + dataIdentifier + "]"); - } - - } - }; - - - // FUNCTION ---- - // createPopover - - // PURPOSE ----- - // Instantiates the footnote popover of the buttons matching the passed selector. - // This includes replacing any variables in the content markup, decoding any special characters, - // Adding the new element to the page, calling the position function, and adding the scroll handler - - // IN ---------- - // Selector of buttons that are to be activated - - // OUT --------- - // All footnotes activated by the function - - var createPopover = function(selector) { - - selector = selector || ".footnote-button"; - - // Activate all matching if multiple footnotes are allowed - // Or only the first matching element otherwise - var $buttons; - if(typeof(selector) !== "string" && settings.allowMultipleFN) { - $buttons = selector; - } else if(typeof(selector) !== "string") { - $buttons = selector.first(); - } else if(settings.allowMultipleFN) { - $buttons = $(selector).closest(".footnote-button"); - } else { - $buttons = $(selector + ":first").closest(".footnote-button"); - } - - var $popoversCreated = $(); - - $buttons.each(function() { - var $this = $(this), - content; - - try { - // Gets the easy replacements out of the way (try is there to ignore the "replacing undefined" error if it's activated too freuqnetly) - content = settings.contentMarkup - .replace(/\{\{FOOTNOTENUM\}\}/g, $this.attr("data-footnote-number")) - .replace(/\{\{FOOTNOTEID\}\}/g, $this.attr("data-footnote-identifier")) - .replace(/\{\{FOOTNOTECONTENT\}\}/g, $this.attr("data-footnote-content") - .replace(/>sym;/, ">").replace(/<sym;/, "<")); - - // Handles replacements of BUTTON attribute requests - content = replaceWithReferenceAttributes(content, "BUTTON", $this); - } finally { - - // Create content and activate user-defined callback on it - $content = $(content); - try { settings.activateCallback($content); } catch(err) {} - - if(!settings.appendPopoversTo) { - - // Insert content after next block-level element, or after the nearest footnote - $nearestBlock = $this.closest("p, div, pre, li, ul, section, article, main, aside"); - $siblingFootnote = $nearestBlock.siblings(".footnote-content:last"); - - if($siblingFootnote.length > 0) { - $content.insertAfter($siblingFootnote); - } else { - $content.insertAfter($nearestBlock); - } - - } else { - - $content.appendTo(settings.appendPopoversTo + ":first"); - } - - // Instantiate the max-height for storage and use in repositioning - $content.attr("data-bigfoot-max-height", $content.height()); - - repositionFeet(); - $this.addClass("active"); - - // Bind the scroll handler to the popover - $content.find(".footnote-content-wrapper").bindScrollHandler(); - $popoversCreated = $popoversCreated.add($content); - } - }); - - // Add active class after a delay to give it time to transition - setTimeout(function() { - $popoversCreated.addClass("active"); - }, settings.popoverCreateDelay); - - return $popoversCreated; - }; - - - // FUNCTION ---- - // bindScrollHandler - - // PURPOSE ----- - // Prevents scrolling of the page when you reach the top/ bottom - // of scrolling a scrollable footnote popover - - // IN ---------- - // Run on popover(s) that are to have the event bound - - // SOURCE ------ - // adapted from: http://stackoverflow.com/questions/16323770/stop-page-from-scrolling-if-hovering-div - - $.fn.bindScrollHandler = function() { - // Don't even bother checking if option is set to false - if(!settings.preventPageScroll) { return; } - - $(this).on("DOMMouseScroll mousewheel", function(e) { - - var $this = $(this), - scrollTop = $this.scrollTop(), - scrollHeight = $this[0].scrollHeight, - height = parseInt($this.css("height")), - $popover = $this.closest(".footnote-content"); - - // Fix for Safari 7 not properly calculating scrollHeight() - // Just add the class as soon as there is any scrolling - if($this.scrollTop() > 0 && $this.scrollTop() < 10) { - $popover.addClass("scrollable"); - } - - // Return if the element isn't scrollable - if(!$popover.hasClass("scrollable")) { return; } - - var delta = (e.type == 'DOMMouseScroll' ? - e.originalEvent.detail * -40 : - e.originalEvent.wheelDelta), // Get the change in scroll position - up = delta > 0; // Decide whether the scroll was up or down - - var prevent = function() { - e.stopPropagation(); - e.preventDefault(); - e.returnValue = false; - return false; - }; - - if(!up && -delta > scrollHeight - height - scrollTop) { - - // Scrolling down, but this will take us past the bottom. - $this.scrollTop(scrollHeight); - $popover.addClass("fully-scrolled"); // Give a class for removal of scroll-related styles - return prevent(); - } else if(up && delta > scrollTop) { - - // Scrolling up, but this will take us past the top. - $this.scrollTop(0); - $popover.removeClass("fully-scrolled"); - return prevent(); - } else { - $popover.removeClass("fully-scrolled"); - } - }); - }; - - - - // ______ ______ ________ ______ _________ ________ __ __ ________ _________ ______ - // /_____/\ /_____/\ /_______/\ /_____/\/________/\/_______/\/_/\ /_/\ /_______/\ /________/\/_____/\ - // \:::_ \ \\::::_\/_\::: _ \ \\:::__\/\__.::.__\/\__.::._\/\:\ \\ \ \\::: _ \ \\__.::.__\/\::::_\/_ - // \:\ \ \ \\:\/___/\\::(_) \ \\:\ \ __ \::\ \ \::\ \ \:\ \\ \ \\::(_) \ \ \::\ \ \:\/___/\ - // \:\ \ \ \\::___\/_\:: __ \ \\:\ \/_/\ \::\ \ _\::\ \__\:\_/.:\ \\:: __ \ \ \::\ \ \::___\/_ - // \:\/.:| |\:\____/\\:.\ \ \ \\:\_\ \ \ \::\ \ /__\::\__/\\ ..::/ / \:.\ \ \ \ \::\ \ \:\____/\ - // \____/_/ \_____\/ \__\/\__\/ \_____\/ \__\/ \________\/ \___/_( \__\/\__\/ \__\/ \_____\/ - // - - // FUNCTION ---- - // unhoverFeet - - // PURPOSE ----- - // Removes the unhovered footnote content if deleteOnUnhover is true - - // IN ---------- - // Event that contains the target of the mouseout event - - var unhoverFeet = function(e) { - if(settings.deleteOnUnhover && settings.activateOnHover) { - setTimeout(function() { - // If the new element is NOT a descendant of the footnote button - var $target = $(e.target).closest(".footnote-content, .footnote-button"); - if($(".footnote-button:hover, .footnote-content:hover").length < 1) { - removePopovers(); - } - }, settings.hoverDelay); - } - }; - - - // FUNCTION ---- - // escapeKeypress - - // PURPOSE ----- - // Removes all popovers on keypress - - // IN ---------- - // Event that contains the key that was pressed - - var escapeKeypress = function(e) { - if(e.keyCode == 27) { - removePopovers(); - } - }; - - - // FUNCTION ---- - // removePopovers - - // PURPOSE ----- - // Removes/ adds appropriate classes to the footnote content and button - // After a delay (to allow for transitions) it removes the actual footnote content - - // IN ---------- - // Selector of footnotes to deactivate and timeout before deleting actual elements - - // OUT --------- - // Footnote buttons that were deactivated - - var removePopovers = function(footnotes, timeout) { - footnotes = footnotes || ".footnote-content"; - timeout = timeout || settings.popoverDeleteDelay; - - var $buttonsClosed = $(), - footnoteID, - $linkedButton, - $this; - - $(footnotes).each(function() { - $this = $(this); - footnoteID = $this.attr("data-footnote-identifier"); - $linkedButton = $(".footnote-button[data-footnote-identifier=\"" + footnoteID + "\"]"); - - if(!$linkedButton.hasClass("changing")) { - - $buttonsClosed = $buttonsClosed.add($linkedButton); - $linkedButton.removeClass("active hover-instantiated click-instantiated").addClass("changing"); - $this.removeClass("active").addClass("disapearing"); - - // Gets rid of the footnote after the timeout - setTimeout(function() { - $this.remove(); - $linkedButton.removeClass("changing"); - }, timeout); - } - }); - - return $buttonsClosed; - }; - - - - // ______ ______ ______ ______ ______ ________ _________ ________ ______ ___ __ - // /_____/\ /_____/\ /_____/\ /_____/\ /_____/\ /_______/\/________/\/_______/\/_____/\ /__/\ /__/\ - // \:::_ \ \ \::::_\/_\:::_ \ \\:::_ \ \\::::_\/_ \__.::._\/\__.::.__\/\__.::._\/\:::_ \ \\::\_\\ \ \ - // \:(_) ) )_\:\/___/\\:(_) \ \\:\ \ \ \\:\/___/\ \::\ \ \::\ \ \::\ \ \:\ \ \ \\:. `-\ \ \ - // \: __ `\ \\::___\/_\: ___\/ \:\ \ \ \\_::._\:\ _\::\ \__ \::\ \ _\::\ \__\:\ \ \ \\:. _ \ \ - // \ \ `\ \ \\:\____/\\ \ \ \:\_\ \ \ /____\:\/__\::\__/\ \::\ \ /__\::\__/\\:\_\ \ \\. \`-\ \ \ - // \_\/ \_\/ \_____\/ \_\/ \_____\/ \_____\/\________\/ \__\/ \________\/ \_____\/ \__\/ \__\/ - // - - - // FUNCTION ---- - // repositionFeet - - // PURPOSE ----- - // Positions each footnote relative to its button - - var repositionFeet = function() { - if(settings.positionContent) { - - $(".footnote-content").each(function() { - - // Element Definitions - var $this = $(this), - dataIdentifier = "data-footnote-identifier=\"" + $this.attr("data-footnote-identifier") + "\"", - $contentWrapper = $this.find(".footnote-content-wrapper"), - $button = $(".footnote-button[" + dataIdentifier + "]"); - - // Spacing Information - var roomLeft = roomCalc($button), - contentWidth = parseFloat($this.css("width")), - marginSize = parseFloat($this.css("margin-top")), - maxHeightInCSS = +($this.attr("data-bigfoot-max-height")), - totalHeightInCSS = 2*marginSize + maxHeightInCSS, - maxHeightOnScreen = 10000; - - // Position tooltip on top if: - // total space on bottom is not enough to hold footnote AND - // top room is larger than bottom room - if(roomLeft.bottomRoom < totalHeightInCSS && roomLeft.topRoom > roomLeft.bottomRoom) { - $this.css({"top": "auto", "bottom": roomLeft.bottomRoom + "px"}).addClass("top").removeClass("bottom"); - maxHeightOnScreen = roomLeft.topRoom - marginSize - 15; - $this.css({"transform-origin": (roomLeft.leftRelative*100) + "% 100%"}); - } else { - $this.css({"bottom": "auto", "top": roomLeft.topRoom + "px"}).addClass("bottom").removeClass("top"); - maxHeightOnScreen = roomLeft.bottomRoom - marginSize - 15; - $this.css({"transform-origin": (roomLeft.leftRelative*100) + "% 0%"}); - } - - // Sets the max height so that there is no footnote overflow - $this.find(".footnote-content-wrapper").css({"max-height": Math.min(maxHeightOnScreen, maxHeightInCSS) + "px"}); - - // Positions the popover - $this.css({"left": (roomLeft.leftRoom - (roomLeft.leftRelative * contentWidth)) + "px"}); - - // Position the tooltip - positionTooltip($this, roomLeft.leftRelative); - - // Give scrollable class if the content hight is larger than the container - if(parseInt($this.css("height")) < $this.find(".footnote-content-wrapper")[0].scrollHeight) { - $this.addClass("scrollable"); - } - }); - } - }; - - - // FUNCTION ---- - // positionTooltip - - // PURPOSE ----- - // Positions the tooltip at the same relative horizontal position as the button - - // IN ---------- - // Footnote popover to get the tooltip of and the relative horizontal position (as a decimal) - - var positionTooltip = function($popover, leftRelative) { - leftRelative = leftRelative || 0.5; // default to 50% - var $tooltip = $popover.find(".tooltip"); - - if($tooltip.length > 0) { - $tooltip.css({"left": leftRelative*100 + "%"}); - } - }; - - - // FUNCTION ---- - // roomCalc - - // PURPOSE ----- - // Calculates area on the top, left, bottom and right of the element - // Also calculates the relative position to the left and top of the screen - - // IN ---------- - // Element to calculate screen position of - - // OUT --------- - // Object containing room on all sides and top/ left relative positions - // All measurements are relative to the middle of the element - - var roomCalc = function($el) { - var elWidth = parseFloat($el.outerWidth()), - elHeight = parseFloat($el.outerHeight()), - w = viewportSize(), - topRoom = $el.offset().top - $(window).scrollTop() + elHeight/2, - leftRoom = $el.offset().left + elWidth/2; - - return { - topRoom : topRoom, - bottomRoom : w.height - topRoom, - leftRoom : leftRoom, - rightRoom : w.width - leftRoom, - leftRelative : leftRoom / w.width, - topRelative : topRoom / w.height - }; - }; - - - // FUNCTION ---- - // viewportSize - - // PURPOSE ----- - // Calculates the height and width of the viewport - - // OUT --------- - // Object with .width and .height properties - - var viewportSize = function() { - var test = document.createElement("div"); - - test.style.cssText = "position: fixed;top: 0;left: 0;bottom: 0;right: 0;"; - document.documentElement.insertBefore(test, document.documentElement.firstChild); - - var dims = { width: test.offsetWidth, height: test.offsetHeight }; - document.documentElement.removeChild(test); - - return dims; - }; - - - - // _______ ______ ______ ________ ___ ___ ______ ______ ________ ___ __ _________ ______ - // /_______/\ /_____/\ /_____/\ /_______/\ /___/\/__/\ /_____/\ /_____/\ /_______/\/__/\ /__/\ /________/\/_____/\ - // \::: _ \ \\:::_ \ \ \::::_\/_\::: _ \ \\::.\ \\ \ \\:::_ \ \\:::_ \ \ \__.::._\/\::\_\\ \ \\__.::.__\/\::::_\/_ - // \::(_) \/_\:(_) ) )_\:\/___/\\::(_) \ \\:: \/_) \ \\:(_) \ \\:\ \ \ \ \::\ \ \:. `-\ \ \ \::\ \ \:\/___/\ - // \:: _ \ \\: __ `\ \\::___\/_\:: __ \ \\:. __ ( ( \: ___\/ \:\ \ \ \ _\::\ \__\:. _ \ \ \::\ \ \_::._\:\ - // \::(_) \ \\ \ `\ \ \\:\____/\\:.\ \ \ \\: \ ) \ \ \ \ \ \:\_\ \ \/__\::\__/\\. \`-\ \ \ \::\ \ /____\:\ - // \_______\/ \_\/ \_\/ \_____\/ \__\/\__\/ \__\/\__\/ \_\/ \_____\/\________\/ \__\/ \__\/ \__\/ \_____\/ - // - - - // FUNCTION ---- - // addBreakpoint - - // PURPOSE ----- - // Adds a breakpoint within the HTML at which a user-defined function - // will be called. The minimum requirement is that a min/ max size is - // provided; after that point, the footnote will stop being positioned - // (i.e., to allow for bottom-fixed footnotes on small screens). - - // IN ---------- - // size: Size to break at. Can be simple (i.e., ">10px" or "<10em"), full - // media query (i.e., "(max-width: 400px)"), or a MediaQueryList object. - // deleteDelay: the delay by which to wait when closing/ reopening footnotes - // on breakpoint changes. Defaults to settings.popoverDeleteDelay. - // removeOpen: whether or not to close (and reopen) footnotes that are open - // at the time the breakpoint changes. Defaults to true. - // trueCallback: function to call when the media query is initially matched. - // will be passed the removeOpen option and a copy of the bigfoot object. - // falseCallback: function to call when the media query is initially not matched. - // The same variables are passed in. - - // OUT --------- - // Object indicating whether the breakpoint was added and, if so, the MQList object - // and listener function. - - var addBreakpoint = function(size, deleteDelay, removeOpen, - trueCallback, falseCallback) { - - // Set defaults - deleteDelay = deleteDelay || settings.popoverDeleteDelay; - if(removeOpen === null || removeOpen !== false) removeOpen = true; - - var mql, minMax, s; - - // If they passed a string representation - if(typeof(size) === "string") { - - // Repalce special strings with corresponding widths - if(size.toLowerCase() === "iphone") { - s = "<320px"; - } else if(size.toLowerCase() === "ipad") { - s = "<768px"; - } else { - s = size; - } - - // Check on the nature of the string (simple or full media query) - if(s.charAt(0) === ">") { - minMax = "min"; - } else if(s.charAt(0) === "<") { - minMax = "max"; - } else { - minMax = null; - } - - // Create the media query - var query = minMax ? "(" + minMax + "-width: " + s.substring(1) + ")" : s; - mql = window.matchMedia(query); - - } else { - - // Assumption is that a MediaQueryList object was passed. - mql = size; - } - - // If a non-MQList object is passed on the media is invalid - if(mql.media && mql.media === "invalid") return { - added: false, - mq: mql, - listener: null - }; - - // Determine whether to close/ remove popovers on the true/false callbacks - var trueDefaultPositionSetting = minMax === "min", - falseDefaultPositionSetting = minMax === "max"; - - // Create default trueCallback - trueCallback = trueCallback || - makeDefaultCallbacks( - removeOpen, deleteDelay, - trueDefaultPositionSetting, function($popover) { - $popover.addClass("fixed-bottom"); - } - ); - - // Create default falseCallback - falseCallback = falseCallback || - makeDefaultCallbacks( - removeOpen, deleteDelay, - falseDefaultPositionSetting, function() {} - ); - - // MQ Listener function - var mqListener = function(mq) { - if(mq.matches) { - trueCallback(removeOpen, bigfoot); - } else { - falseCallback(removeOpen, bigfoot); - } - }; - - // Attach listener and call it for the initial match/ non-match - mql.addListener(mqListener); - mqListener(mql); - - // Add to the breakpoints setting - settings.breakpoints[size] = { - added: true, - mq: mql, - listener: mqListener - }; - - return settings.breakpoints[size]; - - }; - - - // FUNCTION ---- - // makeDefaultCallbacks - - // PURPOSE ----- - // Creates the default callbacks to attach to the MQ events. - - // IN ---------- - // See above for the first three variables. - // callback: The function to be assigned to the "activateCallback" setting - // (called when creating new footnotes) - - // OUT --------- - // Default MQ matches/ non-matches function. - - var makeDefaultCallbacks = function(removeOpen, deleteDelay, positioningBool, callback) { - return function(removeOpen, bigfoot) { - var $closedPopovers; - - if(removeOpen) { - $closedPopovers = bigfoot.close(); - bigfoot.updateSetting("activateCallback", callback); - } - setTimeout(function() { - bigfoot.updateSetting("positionContent", positioningBool); - if(removeOpen) bigfoot.activate($closedPopovers); - }, deleteDelay); - }; - }; - - - // FUNCTION ---- - // removeBreakpoint - - // PURPOSE ----- - // Removes a previously-created breakpoint, calling the false condition - // before doing so (or, a user-provided function instead). - - // IN ---------- - // target: the media query to remove, either by passing the string used to create - // the breakpoint initially, or by passing the associated MediaQueryList object. - // callback: the (optional) function to call before removing the listener. - - // OUT --------- - // true if a media query was found and deleted, false otherwise. - - var removeBreakpoint = function(target, callback) { - var mq = null, - b, mqFount = false; - if(typeof(target) === "string") { - mqFound = settings.breakpoints[target] !== undefined; - } else { - for(b in settings.breakpoints) { - if(settings.breakpoints.hasOwnProperty(b) && settings.breakpoints[b].mq === target) { - mqFound = true; - break; - } - } - } - - if(mqFound) { - var breakpoint = settings.breakpoints[b || target]; - // Calls the non-matching callback one last time - if(callback) { - callback({matches: false}); - } else { - breakpoint.listener({matches: false}); - } - breakpoint.mq.removeListener(breakpoint.listener); - delete settings.breakpoints[b || target]; - } - - return mqFound; - }; - - - - // ______ _________ ___ ___ ______ ______ - // /_____/\ /________/\/__/\ /__/\ /_____/\ /_____/\ - // \:::_ \ \\__.::.__\/\::\ \\ \ \\::::_\/_\:::_ \ \ - // \:\ \ \ \ \::\ \ \::\/_\ .\ \\:\/___/\\:(_) ) )_ - // \:\ \ \ \ \::\ \ \:: ___::\ \\::___\/_\: __ `\ \ - // \:\_\ \ \ \::\ \ \: \ \\::\ \\:\____/\\ \ `\ \ \ - // \_____\/ \__\/ \__\/ \::\/ \_____\/ \_\/ \_\/ - // - - - // FUNCTION ---- - // updateSetting - - // PURPOSE ----- - // Updates the specified setting(s) with the value(s) you pass - - // IN ---------- - // Setting to adjust and new value for the setting (or an object - // with all setting-new value pairs) - - // OUT --------- - // Returns the old value for the setting (or an object with old settings - // for each assigned property, if more than one were set) - - var updateSetting = function(newSettings, value) { - - var oldValue; - - if(typeof(newSettings) === "string") { - - oldValue = settings[newSettings]; - settings[newSettings] = value; - - } else { - - oldValue = {}; - - for(var prop in newSettings) { - if(newSettings.hasOwnProperty(prop)) { - oldValue[prop] = settings[prop]; - settings[prop] = newSettings[prop]; - } - } - - } - - return oldValue; - }; - - - // FUNCTION ---- - // getSetting - - // PURPOSE ----- - // Returns the settings object - - var getSetting = function(setting) { - - return settings[setting]; - }; - - - - // _______ ________ ___ __ ______ ________ ___ __ _______ - // /_______/\ /_______/\/__/\ /__/\ /_____/\ /_______/\/__/\ /__/\ /______/\ - // \::: _ \ \ \__.::._\/\::\_\\ \ \\:::_ \ \ \__.::._\/\::\_\\ \ \\::::__\/__ - // \::(_) \/_ \::\ \ \:. `-\ \ \\:\ \ \ \ \::\ \ \:. `-\ \ \\:\ /____/\ - // \:: _ \ \ _\::\ \__\:. _ \ \\:\ \ \ \ _\::\ \__\:. _ \ \\:\\_ _\/ - // \::(_) \ \/__\::\__/\\. \`-\ \ \\:\/.:| |/__\::\__/\\. \`-\ \ \\:\_\ \ \ - // \_______\/\________\/ \__\/ \__\/ \____/_/\________\/ \__\/ \__\/ \_____\/ - // - - $(document).ready(function() { - - footnoteInit(); - - $(document).on("mouseenter", ".footnote-button", buttonHover); - $(document).on("touchend click", touchClick); - $(document).on("mouseout", ".hover-instantiated", unhoverFeet); - $(document).on("keyup", escapeKeypress); - $(window).on("scroll resize", repositionFeet); - }); - - - - // ______ ______ _________ __ __ ______ ___ __ - // /_____/\ /_____/\ /________/\/_/\/_/\ /_____/\ /__/\ /__/\ - // \:::_ \ \ \::::_\/_\__.::.__\/\:\ \:\ \\:::_ \ \ \::\_\\ \ \ - // \:(_) ) )_\:\/___/\ \::\ \ \:\ \:\ \\:(_) ) )_\:. `-\ \ \ - // \: __ `\ \\::___\/_ \::\ \ \:\ \:\ \\: __ `\ \\:. _ \ \ - // \ \ `\ \ \\:\____/\ \::\ \ \:\_\:\ \\ \ `\ \ \\. \`-\ \ \ - // \_\/ \_\/ \_____\/ \__\/ \_____\/ \_\/ \_\/ \__\/ \__\/ - // - - bigfoot = { - close: function(footnotes, timeout) { - return removePopovers(footnotes, timeout); - }, - activate: function(button) { - return createPopover(button); - }, - reposition: function() { - return repositionFeet(); - }, - addBreakpoint: function(size, deleteDelay, removeOpen, trueCallback, falseCallback) { - return addBreakpoint(size, deleteDelay, removeOpen, trueCallback, falseCallback); - }, - removeBreakpoint: function(target, callback) { - return removeBreakpoint(target, callback); - }, - getSetting: function(setting) { - return getSetting(setting); - }, - updateSetting: function(setting, newValue) { - return updateSetting(setting, newValue); - } - }; - - return bigfoot; - }; - -})(jQuery); \ No newline at end of file