I have been writing a lot of jQuery plugins lately, but I don't really know if what I am doing is any good. Here is one of my most recent plugins. It allows the user to add a data attribute to any class and load a full page view window (which is written to the body on render) to e.g. open a menu on mobile or read large pieces of text without taking up the entire page (scrolling on a product page for example):
(function ($) {
var jelm = $('.js-full-page-view');
var methods = {
init: function () {
jelm.each(function () {
var id = $(this).attr('id'),
title = ($(this).data('caFullPageTitle')) ? $(this).data('caFullPageTitle') : '',
content = (!$(this).data('caSingle')) ? $(this).html() : '',
action_container = ($(this).data('caActionContainer')) ? $(this).data('caActionContainer') : '',
indented_content = ($(this).data('caNoIndentedContent')) ? '' : 'full-page-view--indented-content',
bottom_action_container = '';
if ($(this).data('caBottomActionContainer')) {
bottom_action_container = '<div class="full-page-view--footer-bar">' + $(this).data('caBottomActionContainer') + '</div>';
}
$('body').append(
'<div class="full-page-view js-full-page-view" id="fp_' + id
+ '"><div class="full-page-view--main-bar"><div class="full-page-view--action-container"><button class="full-page-view--action js-full-page-view-close"><svg class="icon-svg alt-flip"><use xlink:href="#icon-arrow"></use></svg></button></div><div class="full-page-view--title">' + title
+ '</div><div class="full-page-view--action-container">' + action_container + '</div></div><div class="full-page-view--scroll-pane full-page-view--content ' + indented_content + '">' + content
+ '</div>' + bottom_action_container + '</div>');
});
methods.bind();
},
bind: function () {
$('.js-full-page-view-open').on('click', function () {
var open_elm = ($(this).data('caTarget')) ? $("#" + $(this).data('caTarget')) : $(this).closest('.js-full-page-view');
if (methods.responsive_check(open_elm)) {
methods.open('#fp_' + open_elm.attr('id'));
}
});
$('.js-full-page-view-close').on('click', function () {
var close_elm = ($(this).data('caTarget')) ? $(this).data('caTarget') : $(this).closest('.js-full-page-view');
methods.close('#' + close_elm.attr('id'));
});
},
close: function (selector) {
$(selector).removeClass('active').ceScrollLock('body', 'rm');
if (methods.single_check('#' + selector.substring(4))) {
var focus = $(selector + ' .full-page-view--content');
var content = $(focus).html();
$('#' + selector.substring(4) + ' .full-page-view--content-placeholder').append(content);
focus.empty();
}
},
open: function (selector) {
$(selector).addClass('active');
setTimeout(function() {$(selector).ceScrollLock('body', 'add');}, 200);
if (methods.single_check('#' + selector.substring(4))) {
var focus = $('#' + selector.substring(4) + ' .full-page-view--content-placeholder');
var content = $(focus).html();
$(selector + ' .full-page-view--content').append(content);
focus.empty();
}
},
responsive_check: function (selector) {
return $.fn.getRealWidth() <= $(selector).data('caResponsiveMax');
},
responsive_resize: function () {
$('.js-full-page-view.active').each(function() {
if (!methods.responsive_check('#' + $(this).attr('id').substring(3))) {
methods.close('#' + $(this).attr('id'));
}
});
},
single_check: function (elem) {
return !!$(elem).data('caSingle');
}
};
$.fn.ceFullPageView = function (method) {
return $(this).each(function (i, elm) {
var errors = {};
if (methods[method]) {
return methods[method].apply(this, Array.prototype.slice.call(arguments, 1));
} else if (typeof method === 'object' || !method) {
return methods.init.apply(this, arguments);
} else {
$.error('fullpageview: method ' + method + ' does not exist');
}
});
};
if ($(document).ready()) {
$('.js-full-page-view').ceFullPageView();
$('.js-full-page-view-open').on('click', function () {
$(this).ceFullPageView('bind');
});
$('.js-full-page-view-close').on('click', function () {
$(this).ceFullPageView('bind');
});
$(window).resize(function () {
$(this).ceFullPageView('responsive_resize');
});
}
})(jQuery);
And the supportive functions
(function (_, $) {
var methods = {
rm: function () {
$('body').removeClass('is-non-scrollable-fixed');
},
add: function() {
$('body').addClass('is-non-scrollable-fixed');
}
};
$.fn.ceScrollLock = function (selector, method) {
return methods[method].apply(this, arguments);
};
$.fn.ceIsIE = function (userAgent) {
userAgent = userAgent || navigator.userAgent;
return userAgent.indexOf("MSIE ") > -1 || userAgent.indexOf("Trident/") > -1 || userAgent.indexOf("Edge/") > -1;
};
$.fn.getRealWidth = function () {
var outer = $('<div>').css({visibility: 'hidden', width: 100, overflow: 'scroll'}).appendTo('body'),
widthWithScroll = $('<div>').css({width: '100%'}).appendTo(outer).outerWidth();
outer.remove();
var scrollBarWidth = 100 - widthWithScroll;
if ($.fn.ceIsIE) {
return window.innerWidth || document.documentElement.clientWidth || document.body.clientWidth;
}
if ($('.is-non-scrollable-fixed').length) {
return $('body').width();
} else {
return $('body').width() + scrollBarWidth;
}
};
})(jQuery);
And the HTML:
<div class="js-full-page-view" data-ca-single="true" data-ca-responsive-max="667" data-ca-full-page-title="{sl 'filter'}" id="full_page_product_filter">
<div class="full-page-view--content-placeholder">
Any HTML content
<div>
</div>
Let me know what you think.
jQuery
) while the function definition expects two two parameters (I.e._, $
). Is underscore or old ash required for it to work? I don’t actually see_
used within the function... \$\endgroup\$