I need a code review for my first jQuery plugin. It seems like a lot of code and I want to hear something about my plugin code structure and more.
;
(function($) {
'use strict';
$.fn.mpopup = function(options) {
//Default settings
var defaults = {
overlayClass: 'mpopup-overlay',
overlayColor: '#000',
overlayOpacity: 0.7,
overlayFadeSpeed: 500,
popupFadeSpeed: 500,
closePopup: '.close-popup',
trigger: '.open-mpopup',
effect: 'fadeUp'
};
//Settings
var settings = $.extend({}, defaults, options);
//Variables
var popup = this,
windowWidth = $(window).width(),
windowHeight = $(window).height(),
popupBlockHeight = popup.outerHeight(),
popupBlockWidth = popup.outerWidth(),
bodyElement = $('body'),
trigger = $(settings.trigger),
popupHorizontalPosition = (windowWidth - popupBlockWidth) / 2,
closeFlag = false,
transitionEffectVal = 100,
indent = (settings.indent) ? settings.indent : windowHeight / 6, // windowHeight / 6 for better look on resize
isShortPopup,
popupVerticalPosition,
onResize,
newPopupVerticalPosition,
documentHeight,
overlay = $('<div />')
.attr('class', settings.overlayClass)
.css({
'top': '0',
'bottom': '0',
'left': '0',
'right': '0',
'position': 'fixed',
'z-index': 9998,
'display': 'none'
});
//Hex to RGB with opactiy
function hex2rgb(hex, opacity) {
var h = hex.replace('#', '');
h = h.match(new RegExp('(.{' + h.length / 3 + '})', 'g'));
for (var i = 0; i < h.length; i++)
h[i] = parseInt(h[i].length == 1 ? h[i] + h[i] : h[i], 16);
if (typeof opacity != 'undefined') h.push(opacity);
return 'rgba(' + h.join(',') + ')';
}
var rgbaValue = hex2rgb(settings.overlayColor, settings.overlayOpacity);
// Custom event for callback functions
$.each(settings, function(key, value) {
if (typeof value === 'function') {
popup.on(key + '.mpopup', function() {
value(popup);
})
}
});
//Append popup into overlay block
function appendPopup() {
overlay.css('background', rgbaValue).appendTo(bodyElement).append(popup);
popup.css({
'position': 'relative',
'z-index': 9999
});
}
//Show popup
function triggerCall() {
if (popup.length > 0) {
appendPopup();
trigger.click(function(e) {
e.preventDefault();
onResize = false;
closeFlag = false;
popup.trigger('beforeCreated.mpopup');
shortPopup();
longPopup();
doEffect();
popup.trigger('created.mpopup');
});
resizePopup();
} else {
console.log('Pop-up is undefined');
}
}
// Close popup
function close() {
var svgCloseElem = $(settings.closePopup).find('*');
overlay.click(function(e) {
closeFlag = true;
if ($(e.target).is(settings.closePopup) ||
$(e.target).is(svgCloseElem) || // for svg elements
$(e.target).is(overlay)) {
overlay.css('overflow-y', 'hidden');
// Remove overflow-y and padding-right styles from body
documentHeight = $('html, body').height();
if (documentHeight > windowHeight) {
bodyElement.css({
'overflow-y': '',
'padding-right': ''
});
}
doEffect();
}
popup.trigger('afterClose.mpopup');
});
// Close popup when clicking the esc keyboard button
$(document).keyup(function(e) {
if (e.which == '27') {
overlay.removeClass('show-popup');
popup.removeClass('show-popup');
popup.trigger('afterClose.mpopup');
}
});
}
// If popup block height LESS than window height
function shortPopup() {
if (popupBlockHeight < windowHeight) {
isShortPopup = true;
popupVerticalPosition = (windowHeight - popupBlockHeight) / 2;
newPopupVerticalPosition = popupVerticalPosition + transitionEffectVal;
popup.css({
'left': popupHorizontalPosition,
'margin': 0,
'top': (settings.effect === 'fadeUp' && !onResize) ? newPopupVerticalPosition : popupVerticalPosition
})
}
}
// If popup block height BIGGER or EQUAL to window height
function longPopup() {
if (popupBlockHeight >= windowHeight) {
isShortPopup = false;
popupVerticalPosition = indent;
// Remove body scroll and add right padding equal to Scrollbar size
documentHeight = $('html, body').height();
if (documentHeight > windowHeight) {
var horizontalScrollWidth = window.innerWidth - document.documentElement.clientWidth;
bodyElement.css({
'overflow-y': 'hidden',
'padding-right': horizontalScrollWidth
});
}
overlay.css('overflow-y', 'scroll');
newPopupVerticalPosition = indent + transitionEffectVal;
popup.css({
'left': popupHorizontalPosition,
'top': 0,
'margin-top': (settings.effect === 'fadeUp' && !onResize) ? newPopupVerticalPosition : popupVerticalPosition,
'margin-bottom': popupVerticalPosition
})
}
}
//Show and close effects
function doEffect() {
switch (settings.effect) {
case 'fade':
if (!closeFlag)
overlay.fadeIn(settings.overlayFadeSpeed).find(popup).fadeIn(settings.popupFadeSpeed);
else
overlay.fadeOut(settings.overlayFadeSpeed).find(popup).fadeOut(settings.popupFadeSpeed);
break;
case 'fadeUp':
if (!closeFlag) {
if (isShortPopup) {
popup.animate({
'top': '-=' + transitionEffectVal
}, settings.popupFadeSpeed);
} else {
popup.animate({
'margin-top': '-=' + transitionEffectVal
}, settings.popupFadeSpeed);
}
overlay.fadeIn({
queue: false,
duration: settings.overlayFadeSpeed
}).find(popup).fadeIn({
queue: false,
duration: settings.popupFadeSpeed
});
} else {
if (isShortPopup) {
popup.animate({
'top': '+=' + transitionEffectVal
}, settings.popupFadeSpeed);
} else {
popup.animate({
'margin-top': '+=' + transitionEffectVal
}, settings.popupFadeSpeed);
}
overlay.fadeOut({
queue: false,
duration: settings.overlayFadeSpeed
}).find(popup).fadeOut({
queue: false,
duration: settings.popupFadeSpeed
});
}
break;
default:
console.log('No effect');
}
}
// Popup on mobile devices
function resizePopup() {
$(window).resize(function() {
onResize = true;
windowWidth = $(window).width();
windowHeight = $(window).height();
popupBlockWidth = popup.outerWidth();
popupHorizontalPosition = (windowWidth - popupBlockWidth) / 2;
if (popupBlockHeight < windowHeight) {
popupVerticalPosition = (windowHeight - popupBlockHeight) / 2;
} else {
popupVerticalPosition = windowHeight / 6;
}
if (popup.css('display') === 'block') {
shortPopup();
longPopup();
}
popup.trigger('onResize.mpopup');
});
}
function init() {
triggerCall();
close();
}
init();
return this;
}
}(jQuery));