/** * @preserve Sticky Anything 2.22 | (c) WebFactory Ltd | GPL2 Licensed */ console.error( "PLEASE NOTE: this is just a notification that the Sticky Menu (or Anything!) plugin is now working in Debug Mode." ); console.error( "Even though this mode will not impact any functionality, do NOT use this mode in production environments!" ); (function ($) { $.fn.stickThis = function (options) { var settings = $.extend( { // Default top: 0, minscreenwidth: 0, maxscreenwidth: 99999, zindex: 1, legacymode: false, dynamicmode: false, debugmode: false, pushup: "", adminbar: false, }, options ); var numElements = $(this).length; var numPushElements = $(settings.pushup).length; if (numPushElements < 1) { // There are no elements on the page with the called selector for the Push-up Element. if (settings.debugmode == true && settings.pushup) { console.error( 'STICKY ANYTHING DEBUG: There are no elements with the selector/class/ID you selected for the Push-up element ("' + settings.pushup + '").' ); } // Resetting it to NOTHING. settings.pushup = ""; } else if (numPushElements > 1) { // You can't use more than one element to push up the sticky element. // Make sure that you use a selector that applies to only ONE SINGLE element on the page. // Want to find out quickly where all the elements are that you targeted? Uncomment the next line to debug. // $(settings.pushup).css('border','solid 3px #ff0000'); if (settings.debugmode == true) { console.error( "STICKY ANYTHING DEBUG: There are " + numPushElements + ' elements on the page with the selector/class/ID you selected for the push-up element ("' + settings.pushup + '"). You can select only ONE element to push the sticky element up.' ); } // Resetting it to NOTHING. settings.pushup = ""; } if (numElements < 1) { // There are no elements on the page with the called selector. if (settings.debugmode == true) { console.error( 'STICKY ANYTHING DEBUG: There are no elements with the selector/class/ID you selected for the sticky element ("' + this.selector + '").' ); } } else if (numElements > 1) { // This is not going to work either. You can't make more than one element sticky. They will only get in eachother's way. // Make sure that you use a selector that applies to only ONE SINGLE element on the page. // Want to find out quickly where all the elements are that you targeted? Uncomment the next line to debug. // $(this).css('border','solid 3px #00ff00'); if (settings.debugmode == true) { console.error( "STICKY ANYTHING DEBUG: There There are " + numPushElements + ' elements with the selector/class/ID you selected for the sticky element ("' + this.selector + '"). You can only make ONE element sticky.' ); } } else { if (settings.legacymode == true) { // LEGACY MODE $(this) .addClass("sticky-element-original") .addClass("element-is-not-sticky"); if (settings.dynamicmode != true) { // Create a clone of the menu, right next to original (in the DOM) on initial page load createClone(settings.top, settings.zindex, settings.adminbar); } checkElement = setInterval(function () { stickItLegacy( settings.top, settings.minscreenwidth, settings.maxscreenwidth, settings.zindex, settings.pushup, settings.dynamicmode, settings.adminbar ); }, 10); } else { // MODERN MODE $(this) .addClass("sticky-element-original") .addClass("element-is-not-sticky"); orgAssignedStyles = cssStyles($(this)); // All original element styles, assigned by CSS. orgInlineStyles = $(".sticky-element-original").attr("style"); if (orgInlineStyles == null) { orgInlineStyles = ""; } createPlaceholder(); checkElement = setInterval(function () { stickIt( settings.top, settings.minscreenwidth, settings.maxscreenwidth, settings.zindex, settings.pushup, settings.adminbar, orgAssignedStyles, orgInlineStyles ); }, 10); } } return this; }; // The new StickIt function function stickIt( stickyTop, minwidth, maxwidth, stickyZindex, pushup, adminbar, originalAssignedStyles, originalInlineStyles ) { // We need to check the position of the ACTIVE element. // This is the original one when it's not sticky, but when it's sticky, it's the placeholder. $listenerElement = $(".sticky-element-active"); var orgElementPos = $listenerElement.offset(); orgElementTop = orgElementPos.top; if (pushup) { var pushElementPos = $(pushup).offset(); pushElementTop = pushElementPos.top; } // Calculating actual viewport width var e = window, a = "inner"; if (!("innerWidth" in window)) { a = "client"; e = document.documentElement || document.body; } viewport = e[a + "Width"]; if (adminbar && $("body").hasClass("admin-bar") && viewport > 600) { // below 600, the adminbar is not fixed adminBarHeight = $("#wpadminbar").height(); } else { adminBarHeight = 0; } if ( $(window).scrollTop() >= orgElementTop - stickyTop - adminBarHeight && viewport >= minwidth && viewport <= maxwidth ) { // We've scrolled PAST the original position; this is where we need to make the element sticky. // Placeholder element should always have same left position as original element (see comment below). // The sticky element will NOT have a TOP or the LEFT margin. This is because the left/top reference point of the original // element does not consider the margin. So, we're checking the left/top point of the actual original element and then // use that position for the sticky element. // LEFT POSITION coordsOrgElement = $listenerElement.offset(); leftOrgElement = coordsOrgElement.left; // This is the position REGARDLESS of the margin. // WIDTH/HEIGHT // The placeholder needs to have the width and height of the original element, WITHOUT the margins but WITH the padding and borders // Whatever margins the original has, the placeholder needs to have that too. widthPlaceholder = $listenerElement[0].getBoundingClientRect().width; if (!widthPlaceholder) { widthPlaceholder = $listenerElement.css("width"); // FALLBACK for subpixels } heightPlaceholder = $listenerElement[0].getBoundingClientRect().height; if (!heightPlaceholder) { heightPlaceholder = $listenerElement.css("height"); // FALLBACK for subpixels } // WIDTH/HEIGHT OF STICKY ELEMENT // The original element though, needs to have the inner width and height of the original (non-sticky) element // No padding, no borders, because that will be applied later anyway, regardless of box-sizing widthSticky = $(".sticky-element-original").css("width"); if (widthSticky == "0px") { widthSticky = $(".sticky-element-original")[0].getBoundingClientRect() .width; } heightSticky = $(".sticky-element-original").height(); // PADDING // If padding is percentages, convert to pixels when it becomes sticky // Just a leftover from the old method. We will not use padding for the placeholder paddingOrgElement = [ $(".sticky-element-original").css("padding-top"), $(".sticky-element-original").css("padding-right"), $(".sticky-element-original").css("padding-bottom"), $(".sticky-element-original").css("padding-left"), ]; paddingSticky = paddingOrgElement[0] + " " + paddingOrgElement[1] + " " + paddingOrgElement[2] + " " + paddingOrgElement[3]; // MARGIN marginOrgElement = [ $listenerElement.css("margin-top"), $listenerElement.css("margin-right"), $listenerElement.css("margin-bottom"), $listenerElement.css("margin-left"), ]; marginPlaceholder = marginOrgElement[0] + " " + marginOrgElement[1] + " " + marginOrgElement[2] + " " + marginOrgElement[3]; // OTHER ELEMENTS // if original has float, display, etc., we need to assign that to the placeholder // Though not as important as the width/height/margin/padding assignedStyles = ""; for (var importantStyle in originalAssignedStyles) { if (originalAssignedStyles[importantStyle] == "inline") { assignedStyles += importantStyle + ":inline-block; "; } else { assignedStyles += importantStyle + ":" + originalAssignedStyles[importantStyle] + "; "; } } // Fixes bug where height of original element returns zero // Is this still needed for the post-2.0 mode?? elementHeight = 0; if (heightPlaceholder < 1) { elementHeight = $(".sticky-element-cloned").outerHeight(); } else { elementHeight = $(".sticky-element-original").outerHeight(); } // If scrolled position = pushup-element (top coordinate) - space between top and element - element height - admin bar // In other words, if the pushup element hits the bottom of the sticky element if ( pushup && $(window).scrollTop() > pushElementTop - stickyTop - elementHeight - adminBarHeight ) { stickyTopMargin = pushElementTop - stickyTop - elementHeight - $(window).scrollTop(); } else { stickyTopMargin = adminBarHeight; } assignedStyles += "width:" + widthPlaceholder + "px; height:" + heightPlaceholder + "px; margin:" + marginPlaceholder + ";"; $(".sticky-element-original") .removeClass("sticky-element-active") .removeClass("element-is-not-sticky") .addClass("element-is-sticky") .css( "cssText", originalInlineStyles + "margin-top: " + stickyTopMargin + "px !important; margin-left: 0 !important" ) .css("position", "fixed") .css("left", leftOrgElement + "px") .css("top", stickyTop + "px") .css("width", widthSticky) .css("padding", paddingSticky) .css("z-index", stickyZindex); if (!$(".sticky-element-placeholder").hasClass("sticky-element-active")) { $(".sticky-element-placeholder") .addClass("sticky-element-active") .attr("style", assignedStyles); } } else { // not scrolled past the menu; only show the original element. $(".sticky-element-original") .addClass("sticky-element-active") .removeClass("element-is-sticky") .addClass("element-is-not-sticky") .attr("style", originalInlineStyles); if ($(".sticky-element-placeholder").hasClass("sticky-element-active")) { $(".sticky-element-placeholder") .removeClass("sticky-element-active") .removeAttr("style") .css("width", "0") .css("height", "0") .css("margin", "0") .css("padding", "0"); } } } function createPlaceholder() { $(".sticky-element-original") .addClass("sticky-element-active") .before( '
' ); } // Helper function: get the important CSS rules from an element function cssStyles(el) { o = {}; o["display"] = el.css("display"); o["float"] = el.css("float"); o["flex"] = el.css("flex"); o["box-sizing"] = el.css("box-sizing"); o["clear"] = el.css("clear"); o["overflow"] = el.css("overflow"); o["transform"] = el.css("transform"); // For some reason, this original loop doesn't work with some themes/plugins. // importantStyles = ['display','float','flex','box-sizing','clear','overflow','transform']; // for(var styleProp in importantStyles) { // o[importantStyles[styleProp]] = el.css(importantStyles[styleProp]); // } return o; } // The old StickIt function function stickItLegacy( stickyTop, minwidth, maxwidth, stickyZindex, pushup, dynamic, adminbar ) { var orgElementPos = $(".sticky-element-original").offset(); orgElementTop = orgElementPos.top; if (pushup) { var pushElementPos = $(pushup).offset(); pushElementTop = pushElementPos.top; } // Calculating actual viewport width var e = window, a = "inner"; if (!("innerWidth" in window)) { a = "client"; e = document.documentElement || document.body; } viewport = e[a + "Width"]; if (adminbar && $("body").hasClass("admin-bar") && viewport > 600) { adminBarHeight = $("#wpadminbar").height(); } else { adminBarHeight = 0; } if ( $(window).scrollTop() >= orgElementTop - stickyTop - adminBarHeight && viewport >= minwidth && viewport <= maxwidth ) { // scrolled past the original position; now only show the cloned, sticky element. // Cloned element should always have same left position and width as original element. orgElement = $(".sticky-element-original"); coordsOrgElement = orgElement.offset(); leftOrgElement = coordsOrgElement.left; widthOrgElement = orgElement[0].getBoundingClientRect().width; if (!widthOrgElement) { widthOrgElement = orgElement.css("width"); // FALLBACK for subpixels } heightOrgElement = orgElement.outerHeight(); // If padding is percentages, convert to pixels paddingOrgElement = [ orgElement.css("padding-top"), orgElement.css("padding-right"), orgElement.css("padding-bottom"), orgElement.css("padding-left"), ]; paddingCloned = paddingOrgElement[0] + " " + paddingOrgElement[1] + " " + paddingOrgElement[2] + " " + paddingOrgElement[3]; if (dynamic == true && $(".sticky-element-cloned").length < 1) { // DYNAMIC MODE: if there is no clone present, create it right now createClone(stickyTop, stickyZindex); } // Fixes bug where height of original element returns zero elementHeight = 0; if (heightOrgElement < 1) { elementHeight = $(".sticky-element-cloned").outerHeight(); } else { elementHeight = $(".sticky-element-original").outerHeight(); } // If scrolled position = pushup-element (top coordinate) - space between top and element - element height - admin bar // In other words, if the pushup element hits the bottom of the sticky element if ( pushup && $(window).scrollTop() > pushElementTop - stickyTop - elementHeight - adminBarHeight ) { stickyTopMargin = pushElementTop - stickyTop - elementHeight - $(window).scrollTop(); } else { stickyTopMargin = adminBarHeight; } $(".sticky-element-cloned") .css("left", leftOrgElement + "px") .css("top", stickyTop + "px") .css("width", widthOrgElement) .css("margin-top", stickyTopMargin) .css("padding", paddingCloned) .show(); $(".sticky-element-original").css("visibility", "hidden"); } else { // not scrolled past the menu; only show the original menu. if (dynamic == true) { $(".sticky-element-cloned").remove(); } else { $(".sticky-element-cloned").hide(); } $(".sticky-element-original").css("visibility", "visible"); } } function createClone(cloneTop, cloneZindex) { $(".sticky-element-original") .clone() .insertAfter($(".sticky-element-original")) .addClass("sticky-element-cloned") .removeClass("element-is-not-sticky") .addClass("element-is-sticky") .css("position", "fixed") .css("top", cloneTop + "px") .css("margin-left", "0") .css("z-index", cloneZindex) .removeClass("sticky-element-original") .hide(); } })(jQuery);