mikit-framework
Version:
A web framework for professional developers and designers alike.
1,961 lines (1,626 loc) • 47.5 kB
JavaScript
/*
Mikit. CSS & JS Framework
Version 1.0
http://mikit.missra.com/
Copyright (c) 2017, Mikit.
License: MIT
*/
if (typeof jQuery === 'undefined') {
throw new Error('Mikit\'s requires jQuery')
};
(function ($) {
var version = $.fn.jquery.split('.');
if (version[0] == 1 && version[1] < 8) {
throw new Error('Mikit\'s requires at least jQuery v1.8');
}
})(jQuery);
(function () {
// Inherits
Function.prototype.inherits = function (parent) {
var F = function () {};
F.prototype = parent.prototype;
var f = new F();
for (var prop in this.prototype) f[prop] = this.prototype[prop];
this.prototype = f;
this.prototype.super = parent.prototype;
};
// Core Class
var Mikit = function (element, options) {
options = (typeof options === 'object') ? options : {};
this.$element = $(element);
this.opts = $.extend(true, this.defaults, $.fn[this.namespace].options, this.$element.data(), options);
this.$target = (typeof this.opts.target === 'string') ? $(this.opts.target) : null;
};
// Core Functionality
Mikit.prototype = {
getInstance: function () {
return this.$element.data('fn.' + this.namespace);
},
hasTarget: function () {
return !(this.$target === null);
},
callback: function (type) {
var args = [].slice.call(arguments).splice(1);
// on element callback
if (this.$element) {
args = this._fireCallback($._data(this.$element[0], 'events'), type, this.namespace, args);
}
// on target callback
if (this.$target) {
args = this._fireCallback($._data(this.$target[0], 'events'), type, this.namespace, args);
}
// opts callback
if (this.opts && this.opts.callbacks && $.isFunction(this.opts.callbacks[type])) {
return this.opts.callbacks[type].apply(this, args);
}
return args;
},
_fireCallback: function (events, type, eventNamespace, args) {
if (events && typeof events[type] !== 'undefined') {
var len = events[type].length;
for (var i = 0; i < len; i++) {
var namespace = events[type][i].namespace;
if (namespace === eventNamespace) {
var value = events[type][i].handler.apply(this, args);
}
}
}
return (typeof value === 'undefined') ? args : value;
}
};
// Scope
window.Mikit = Mikit;
})();
/**
* @library Mikit Plugin
* @author Mikit
*/
(function (Mikit) {
Mikit.Plugin = {
create: function (classname, pluginname) {
pluginname = (typeof pluginname === 'undefined') ? classname.toLowerCase() : pluginname;
$.fn[pluginname] = function (method, options) {
var args = Array.prototype.slice.call(arguments, 1);
var name = 'fn.' + pluginname;
var val = [];
this.each(function () {
var $this = $(this),
data = $this.data(name);
options = (typeof method === 'object') ? method : options;
if (!data) {
// Initialization
$this.data(name, {});
$this.data(name, (data = new Mikit[classname](this, options)));
}
// Call methods
if (typeof method === 'string') {
if ($.isFunction(data[method])) {
var methodVal = data[method].apply(data, args);
if (methodVal !== undefined) {
val.push(methodVal);
}
} else {
$.error('No such method "' + method + '" for ' + classname);
}
}
});
return (val.length === 0 || val.length === 1) ? ((val.length === 0) ? this : val[0]) : val;
};
$.fn[pluginname].options = {};
return this;
},
autoload: function (pluginname) {
var arr = pluginname.split(',');
var len = arr.length;
for (var i = 0; i < len; i++) {
var name = arr[i].toLowerCase().split(',').map(function (s) {
return s.trim()
}).join(',');
this.autoloadQueue.push(name);
}
return this;
},
autoloadQueue: [],
startAutoload: function () {
if (!window.MutationObserver || this.autoloadQueue.length === 0) {
return;
}
var self = this;
var observer = new MutationObserver(function (mutations) {
mutations.forEach(function (mutation) {
var newNodes = mutation.addedNodes;
if (newNodes.length === 0 || (newNodes.length === 1 && newNodes.nodeType === 3)) {
return;
}
self.startAutoloadOnce();
});
});
// pass in the target node, as well as the observer options
observer.observe(document, {
subtree: true,
childList: true
});
},
startAutoloadOnce: function () {
var self = this;
var $nodes = $('[data-component]').not('[data-loaded]');
$nodes.each(function () {
var $el = $(this);
var pluginname = $el.data('component');
if (self.autoloadQueue.indexOf(pluginname) !== -1) {
$el.attr('data-loaded', true);
$el[pluginname]();
}
});
},
watch: function () {
Mikit.Plugin.startAutoloadOnce();
Mikit.Plugin.startAutoload();
}
};
$(window).on('load', function () {
Mikit.Plugin.watch();
});
}(Mikit));
/**
* @library Mikit Animation
* @author Mikit
*/
(function (Mikit) {
Mikit.Animation = function (element, effect, callback) {
this.namespace = 'animation';
this.defaults = {};
// Parent Constructor
Mikit.apply(this, arguments);
// Initialization
this.effect = effect;
this.completeCallback = (typeof callback === 'undefined') ? false : callback;
this.prefixes = ['', '-moz-', '-o-animation-', '-webkit-'];
this.queue = [];
this.start();
};
Mikit.Animation.prototype = {
start: function () {
if (this.isSlideEffect()) {
this.setElementHeight();
}
this.addToQueue();
this.clean();
this.animate();
},
addToQueue: function () {
this.queue.push(this.effect);
},
setElementHeight: function () {
this.$element.height(this.$element.height());
},
removeElementHeight: function () {
this.$element.css('height', '');
},
isSlideEffect: function () {
return (this.effect === 'slideDown' || this.effect === 'slideUp');
},
isHideableEffect: function () {
var effects = ['fadeOut', 'slideUp', 'flipOut', 'zoomOut', 'slideOutUp', 'slideOutRight', 'slideOutLeft'];
return ($.inArray(this.effect, effects) !== -1);
},
isToggleEffect: function () {
return (this.effect === 'show' || this.effect === 'hide');
},
storeHideClasses: function () {
if (this.$element.hasClass('mi-hide-sm')) {
this.$element.data('hide-sm-class', true);
} else if (this.$element.hasClass('mi-hide-md')) {
this.$element.data('hide-md-class', true);
}
},
revertHideClasses: function () {
if (this.$element.data('hide-sm-class')) {
this.$element.addClass('mi-hide-sm').removeData('hide-sm-class');
} else if (this.$element.data('hide-md-class')) {
this.$element.addClass('mi-hide-md').removeData('hide-md-class');
} else this.$element.addClass('mi-hide');
},
removeHideClass: function () {
if (this.$element.data('hide-sm-class')) {
this.$element.removeClass('mi-hide-sm');
} else if (this.$element.data('hide-md-class')) {
this.$element.removeClass('mi-hide-md');
} else {
this.$element.removeClass('mi-hide');
}
},
animate: function () {
this.storeHideClasses();
if (this.isToggleEffect()) {
return this.makeSimpleEffects();
}
this.$element.addClass('mi-animated');
this.$element.addClass(this.queue[0]);
this.removeHideClass();
var _callback = (this.queue.length > 1) ? null : this.completeCallback;
this.complete('AnimationEnd', $.proxy(this.makeComplete, this), _callback);
},
makeSimpleEffects: function () {
if (this.effect === 'show') {
this.removeHideClass();
} else if (this.effect === 'hide') {
this.revertHideClasses();
}
if (typeof this.completeCallback === 'function') {
this.completeCallback(this);
}
},
makeComplete: function () {
if (this.$element.hasClass(this.queue[0])) {
this.clean();
this.queue.shift();
if (this.queue.length) this.animate();
}
},
complete: function (type, make, callback) {
var event = type.toLowerCase() + ' webkit' + type + ' o' + type + ' MS' + type;
this.$element.one(event, $.proxy(function () {
if (typeof make === 'function') {
make();
}
if (this.isHideableEffect()) {
this.revertHideClasses();
}
if (this.isSlideEffect()) {
this.removeElementHeight();
}
if (typeof callback === 'function') {
callback(this);
}
this.$element.off(event);
}, this));
},
clean: function () {
this.$element.removeClass('mi-animated').removeClass(this.queue[0]);
}
};
// Inheritance
Mikit.Animation.inherits(Mikit);
}(Mikit));
// Plugin
(function ($) {
$.fn.animation = function (effect, callback) {
var name = 'fn.animation';
return this.each(function () {
var $this = $(this),
data = $this.data(name);
$this.data(name, {});
$this.data(name, (data = new Mikit.Animation(this, effect, callback)));
});
};
$.fn.animation.options = {};
})(jQuery);
/**
* @library Mikit Detect
* @author Mikit
*/
(function (Mikit) {
Mikit.Detect = function () {};
Mikit.Detect.prototype = {
isMobile: function () {
return /(iPhone|iPod|BlackBerry|Android)/.test(navigator.userAgent);
},
isDesktop: function () {
return !/(iPhone|iPod|iPad|BlackBerry|Android)/.test(navigator.userAgent);
},
isMobileScreen: function () {
return ($(window).width() <= 768);
},
isTabletScreen: function () {
return ($(window).width() >= 768 && $(window).width() <= 1024);
},
isDesktopScreen: function () {
return ($(window).width() > 1024);
}
};
}(Mikit));
/**
* @library Mikit FormData
* @author Mikit
*/
(function (Mikit) {
Mikit.FormData = function (app) {
this.opts = app.opts;
};
Mikit.FormData.prototype = {
set: function (data) {
this.data = data;
},
get: function (formdata) {
this.formdata = formdata;
if (this.opts.appendForms) this.appendForms();
if (this.opts.appendFields) this.appendFields();
return this.data;
},
appendFields: function () {
var $fields = $(this.opts.appendFields);
if ($fields.length === 0) {
return;
}
var self = this;
var str = '';
if (this.formdata) {
$fields.each(function () {
self.data.append($(this).attr('name'), $(this).val());
});
} else {
$fields.each(function () {
str += '&' + $(this).attr('name') + '=' + $(this).val();
});
this.data = (this.data === '') ? str.replace(/^&/, '') : this.data + str;
}
},
appendForms: function () {
var $forms = $(this.opts.appendForms);
if ($forms.length === 0) {
return;
}
if (this.formdata) {
var self = this;
var formsData = $(this.opts.appendForms).serializeArray();
$.each(formsData, function (i, s) {
self.data.append(s.name, s.value);
});
} else {
var str = $forms.serialize();
this.data = (this.data === '') ? str : this.data + '&' + str;
}
}
};
}(Mikit));
/**
* @library Mikit Response
* @author Mikit
*/
(function (Mikit) {
Mikit.Response = function (app) {};
Mikit.Response.prototype = {
parse: function (str) {
if (str === '') {
return false;
}
var obj = {};
try {
obj = JSON.parse(str);
} catch (e) {
return false;
}
if (obj[0] !== undefined) {
for (var item in obj) {
this.parseItem(obj[item]);
}
} else {
this.parseItem(obj);
}
return obj;
},
parseItem: function (item) {
if (item.type === 'value') {
$.each(item.data, $.proxy(function (key, val) {
val = (val === null || val === false) ? 0 : val;
val = (val === true) ? 1 : val;
$(key).val(val);
}, this));
} else if (item.type === 'html') {
$.each(item.data, $.proxy(function (key, val) {
val = (val === null || val === false) ? '' : val;
$(key).html(this.stripslashes(val));
}, this));
} else if (item.type === 'addClass') {
$.each(item.data, function (key, val) {
$(key).addClass(val);
});
} else if (item.type === 'removeClass') {
$.each(item.data, function (key, val) {
$(key).removeClass(val);
});
} else if (item.type === 'command') {
$.each(item.data, function (key, val) {
$(val)[key]();
});
} else if (item.type === 'animation') {
$.each(item.data, function (key, data) {
data.opts = (typeof data.opts === 'undefined') ? {} : data.opts;
$(key).animation(data.name, data.opts);
});
} else if (item.type === 'location') {
top.location.href = item.data;
} else if (item.type === 'notify') {
$.notify(item.data);
}
return item;
},
stripslashes: function (str) {
return (str + '').replace(/\0/g, '0').replace(/\\([\\'"])/g, '$1');
}
};
}(Mikit));
/**
* @library Mikit Utils
* @author Mikit
*/
(function (Mikit) {
Mikit.Utils = function () {};
Mikit.Utils.prototype = {
disableBodyScroll: function () {
var $body = $('body');
var windowWidth = window.innerWidth;
if (!windowWidth) {
var documentElementRect = document.documentElement.getBoundingClientRect();
windowWidth = documentElementRect.right - Math.abs(documentElementRect.left);
}
var isOverflowing = document.body.clientWidth < windowWidth;
var scrollbarWidth = this.measureScrollbar();
$body.css('overflow', 'hidden');
if (isOverflowing) {
$body.css('padding-right', scrollbarWidth);
}
},
measureScrollbar: function () {
var $body = $('body');
var scrollDiv = document.createElement('div');
scrollDiv.className = 'mi-scrollbar-measure';
$body.append(scrollDiv);
var scrollbarWidth = scrollDiv.offsetWidth - scrollDiv.clientWidth;
$body[0].removeChild(scrollDiv);
return scrollbarWidth;
},
enableBodyScroll: function () {
$('body').css({
'overflow': '',
'padding-right': ''
});
}
};
}(Mikit));
/**
* @library Mikit Message
* @author Mikit
*/
(function (Mikit) {
Mikit.Message = function (element, options) {
this.namespace = 'message';
this.defaults = {
closeSelector: '.mi-close',
closeEvent: 'click',
animationOpen: 'fadeIn',
animationClose: 'fadeOut',
callbacks: ['open', 'opened', 'close', 'closed']
};
// Parent Constructor
Mikit.apply(this, arguments);
// Initialization
this.start();
};
// Functionality
Mikit.Message.prototype = {
start: function () {
this.$close = this.$element.find(this.opts.closeSelector);
this.$close.on(this.opts.closeEvent + '.' + this.namespace, $.proxy(this.close, this));
this.$element.addClass('mi-open');
},
stop: function () {
this.$close.off('.' + this.namespace);
this.$element.removeClass('mi-open');
},
open: function (e) {
if (e) {
e.preventDefault();
}
if (!this.isOpened()) {
this.callback('open');
this.$element.animation(this.opts.animationOpen, $.proxy(this.onOpened, this));
}
},
isOpened: function () {
return this.$element.hasClass('mi-open');
},
onOpened: function () {
this.callback('opened');
this.$element.addClass('mi-open');
},
close: function (e) {
if (e) {
e.preventDefault();
}
if (this.isOpened()) {
this.callback('close');
this.$element.animation(this.opts.animationClose, $.proxy(this.onClosed, this));
}
},
onClosed: function () {
this.callback('closed');
this.$element.removeClass('mi-open');
}
};
// Inheritance
Mikit.Message.inherits(Mikit);
// Plugin
Mikit.Plugin.create('Message');
Mikit.Plugin.autoload('Message');
}(Mikit));
/**
* @library Mikit Sticky
* @author Mikit
*/
(function (Mikit) {
Mikit.Sticky = function (element, options) {
this.namespace = 'sticky';
this.defaults = {
classname: 'mi-fixed',
offset: 0, // pixels
callbacks: ['fixed', 'unfixed']
};
// Parent Constructor
Mikit.apply(this, arguments);
// Initialization
this.start();
};
// Functionality
Mikit.Sticky.prototype = {
start: function () {
this.offsetTop = this.getOffsetTop();
this.load();
$(window).scroll($.proxy(this.load, this));
},
getOffsetTop: function () {
return this.$element.offset().top;
},
load: function () {
return (this.isFix()) ? this.fixed() : this.unfixed();
},
isFix: function () {
return ($(window).scrollTop() > (this.offsetTop + this.opts.offset));
},
fixed: function () {
this.$element.addClass(this.opts.classname).css('top', this.opts.offset + 'px');
this.callback('fixed');
},
unfixed: function () {
this.$element.removeClass(this.opts.classname).css('top', '');
this.callback('unfixed');
}
};
// Inheritance
Mikit.Sticky.inherits(Mikit);
// Plugin
Mikit.Plugin.create('Sticky');
Mikit.Plugin.autoload('Sticky');
}(Mikit));
/**
* @library Mikit Toggleme
* @author Mikit
*/
(function (Mikit) {
Mikit.Toggleme = function (element, options) {
this.namespace = 'toggleme';
this.defaults = {
toggleEvent: 'click',
target: null,
text: '',
animationOpen: 'slideDown',
animationClose: 'slideUp',
callbacks: ['open', 'opened', 'close', 'closed']
};
// Parent Constructor
Mikit.apply(this, arguments);
// Initialization
this.start();
};
// Functionality
Mikit.Toggleme.prototype = {
start: function () {
if (!this.hasTarget()) return;
this.$element.on(this.opts.toggleEvent + '.' + this.namespace, $.proxy(this.toggle, this));
},
stop: function () {
this.$element.off('.' + this.namespace);
this.revertText();
},
toggle: function (e) {
if (this.isOpened()) this.close(e);
else this.open(e);
},
open: function (e) {
if (e) e.preventDefault();
if (!this.isOpened()) {
this.storeText();
this.callback('open');
this.$target.animation('slideDown', $.proxy(this.onOpened, this));
// changes the text of $element with a less delay to smooth
setTimeout($.proxy(this.replaceText, this), 100);
}
},
close: function (e) {
if (e) e.preventDefault();
if (this.isOpened()) {
this.callback('close');
this.$target.animation('slideUp', $.proxy(this.onClosed, this));
}
},
isOpened: function () {
return (this.$target.hasClass('mi-open'));
},
onOpened: function () {
this.$target.addClass('mi-open');
this.callback('opened');
},
onClosed: function () {
this.$target.removeClass('mi-open');
this.revertText();
this.callback('closed');
},
storeText: function () {
this.$element.data('replacement-text', this.$element.html());
},
revertText: function () {
var text = this.$element.data('replacement-text');
if (text) this.$element.html(text);
this.$element.removeData('replacement-text');
},
replaceText: function () {
if (this.opts.text !== '') {
this.$element.html(this.opts.text);
}
}
};
// Inheritance
Mikit.Toggleme.inherits(Mikit);
// Plugin
Mikit.Plugin.create('Toggleme');
Mikit.Plugin.autoload('Toggleme');
}(Mikit));
/**
* @library Mikit Offcanvas
* @author Mikit
*/
(function (Mikit) {
Mikit.Offcanvas = function (element, options) {
this.namespace = 'offcanvas';
this.defaults = {
target: null, // selector
push: true, // boolean
width: '250px', // string
direction: 'left', // string: left or right
toggleEvent: 'click',
clickOutside: true, // boolean
animationOpen: 'slideInLeft',
animationClose: 'slideOutLeft',
callbacks: ['open', 'opened', 'close', 'closed']
};
// Parent Constructor
Mikit.apply(this, arguments);
// Services
this.utils = new Mikit.Utils();
this.detect = new Mikit.Detect();
// Initialization
this.start();
};
// Functionality
Mikit.Offcanvas.prototype = {
start: function () {
if (!this.hasTarget()) return;
this.buildTargetWidth();
this.buildAnimationDirection();
this.$close = this.getCloseLink();
this.$element.on(this.opts.toggleEvent + '.' + this.namespace, $.proxy(this.toggle, this));
this.$target.addClass('mi-offcanvas');
},
stop: function () {
this.closeAll();
this.$element.off('.' + this.namespace);
this.$close.off('.' + this.namespace);
$(document).off('.' + this.namespace);
},
toggle: function (e) {
if (this.isOpened()) this.close(e);
else this.open(e);
},
buildTargetWidth: function () {
this.opts.width = ($(window).width() < parseInt(this.opts.width)) ? '100%' : this.opts.width;
},
buildAnimationDirection: function () {
if (this.opts.direction === 'right') {
this.opts.animationOpen = 'slideInRight';
this.opts.animationClose = 'slideOutRight';
}
},
getCloseLink: function () {
return this.$target.find('.mi-close');
},
open: function (e) {
if (e) e.preventDefault();
if (!this.isOpened()) {
this.closeAll();
this.callback('open');
this.$target.addClass('mi-offcanvas-' + this.opts.direction);
this.$target.css('width', this.opts.width);
this.pushBody();
this.$target.animation(this.opts.animationOpen, $.proxy(this.onOpened, this));
}
},
closeAll: function () {
var $elms = $(document).find('.offcanvas');
if ($elms.length !== 0) {
$elms.each(function () {
var $el = $(this);
if ($el.hasClass('mi-open')) {
$el.css('width', '').animation('hide');
$el.removeClass('mi-open mi-offcanvas-left mi-offcanvas-right');
}
});
$(document).off('.' + this.namespace);
$('body').css('left', '');
}
},
close: function (e) {
if (e) {
var $el = $(e.target);
var isTag = ($el[0].tagName === 'A' || $el[0].tagName === 'BUTTON');
if (isTag && $el.closest('.mi-offcanvas').length !== 0 && !$el.hasClass('mi-close')) {
return;
}
e.preventDefault();
}
if (this.isOpened()) {
this.utils.enableBodyScroll();
this.callback('close');
this.pullBody();
this.$target.animation(this.opts.animationClose, $.proxy(this.onClosed, this));
}
},
isOpened: function () {
return (this.$target.hasClass('mi-open'));
},
onOpened: function () {
if (this.opts.clickOutside) $(document).on('click.' + this.namespace, $.proxy(this.close, this));
if (this.detect.isMobileScreen()) $('html').addClass('mi-no-scroll');
$(document).on('keyup.' + this.namespace, $.proxy(this.handleKeyboard, this));
this.$close.on('click.' + this.namespace, $.proxy(this.close, this));
this.utils.disableBodyScroll();
this.$target.addClass('mi-open');
this.callback('opened');
},
onClosed: function () {
if (this.detect.isMobileScreen()) $('html').removeClass('mi-no-scroll');
this.$target.css('width', '').removeClass('mi-offcanvas-' + this.opts.direction);
this.$close.off('.' + this.namespace);
$(document).off('.' + this.namespace);
this.$target.removeClass('mi-open');
this.callback('closed');
},
handleKeyboard: function (e) {
if (e.which === 27) this.close();
},
pullBody: function () {
if (this.opts.push) {
$('body').animate({
left: 0
}, 350, function () {
$(this).removeClass('mi-offcanvas-push-body');
});
}
},
pushBody: function () {
if (this.opts.push) {
var properties = (this.opts.direction === 'left') ? {
'left': this.opts.width
} : {
'left': '-' + this.opts.width
};
$('body').addClass('mi-offcanvas-push-body').animate(properties, 200);
}
}
};
// Inheritance
Mikit.Offcanvas.inherits(Mikit);
// Plugin
Mikit.Plugin.create('Offcanvas');
Mikit.Plugin.autoload('Offcanvas');
}(Mikit));
/**
* @library Mikit Collapse
* @author Mikit
*/
(function (Mikit) {
Mikit.Collapse = function (element, options) {
this.namespace = 'collapse';
this.defaults = {
target: null,
toggle: true,
active: false, // string (hash = tab id selector)
toggleClass: 'mi-collapse-toggle',
boxClass: 'mi-collapse-box',
callbacks: ['open', 'opened', 'close', 'closed'],
// private
hashes: [],
currentHash: false,
currentItem: false
};
// Parent Constructor
Mikit.apply(this, arguments);
// Initialization
this.start();
};
// Functionality
Mikit.Collapse.prototype = {
start: function () {
// items
this.$items = this.getItems();
this.$items.each($.proxy(this.loadItems, this));
// boxes
this.$boxes = this.getBoxes();
// active
this.setActiveItem();
},
getItems: function () {
return this.$element.find('.' + this.opts.toggleClass);
},
getBoxes: function () {
return this.$element.find('.' + this.opts.boxClass);
},
loadItems: function (i, el) {
var item = this.getItem(el);
// set item identificator
item.$el.attr('rel', item.hash);
// active
if (!$(item.hash).hasClass('mi-hide')) {
this.opts.currentItem = item;
this.opts.active = item.hash;
item.$el.addClass('mi-active');
}
// event
item.$el.on('click.collapse', $.proxy(this.toggle, this));
},
setActiveItem: function () {
if (this.opts.active !== false) {
this.opts.currentItem = this.getItemBy(this.opts.active);
this.opts.active = this.opts.currentItem.hash;
}
if (this.opts.currentItem !== false) {
this.addActive(this.opts.currentItem);
this.opts.currentItem.$box.removeClass('mi-hide');
}
},
addActive: function (item) {
item.$box.removeClass('mi-hide').addClass('mi-open');
item.$el.addClass('mi-active');
if (item.$caret !== false) item.$caret.removeClass('mi-down').addClass('mi-up');
if (item.$parent !== false) item.$parent.addClass('mi-active');
this.opts.currentItem = item;
},
removeActive: function (item) {
item.$box.removeClass('mi-open');
item.$el.removeClass('mi-active');
if (item.$caret !== false) item.$caret.addClass('mi-down').removeClass('mi-up');
if (item.$parent !== false) item.$parent.removeClass('mi-active');
this.opts.currentItem = false;
},
toggle: function (e) {
if (e) e.preventDefault();
var target = $(e.target).closest('.' + this.opts.toggleClass).get(0) || e.target;
var item = this.getItem(target);
if (this.isOpened(item.hash)) this.close(item.hash);
else this.open(e)
},
openAll: function () {
this.$items.addClass('mi-active');
this.$boxes.addClass('mi-open').removeClass('mi-hide');
},
open: function (e, push) {
if (typeof e === 'undefined') return;
if (typeof e === 'object') e.preventDefault();
var target = $(e.target).closest('.' + this.opts.toggleClass).get(0) || e.target;
var item = (typeof e === 'object') ? this.getItem(target) : this.getItemBy(e);
if (item.$box.hasClass('mi-open')) {
return;
}
if (this.opts.toggle) this.closeAll();
this.callback('open', item);
this.addActive(item);
item.$box.animation('slideDown', $.proxy(this.onOpened, this));
},
onOpened: function () {
this.callback('opened', this.opts.currentItem);
},
closeAll: function () {
this.$items.removeClass('mi-active').closest('li').removeClass('mi-active');
this.$boxes.removeClass('mi-open').addClass('mi-hide');
},
close: function (num) {
var item = this.getItemBy(num);
this.callback('close', item);
this.opts.currentItem = item;
item.$box.animation('slideUp', $.proxy(this.onClosed, this));
},
onClosed: function () {
var item = this.opts.currentItem;
this.removeActive(item);
this.callback('closed', item);
},
isOpened: function (hash) {
return $(hash).hasClass('mi-open');
},
getItem: function (element) {
var item = {};
item.$el = $(element);
item.hash = item.$el.attr('href');
item.$box = $(item.hash);
var $parent = item.$el.parent();
item.$parent = ($parent[0].tagName === 'LI') ? $parent : false;
var $caret = item.$el.find('.mi-caret');
item.$caret = ($caret.length !== 0) ? $caret : false;
return item;
},
getItemBy: function (num) {
var element = (typeof num === 'number') ? this.$items.eq(num - 1) : this.$element.find('[rel="' + num + '"]');
return this.getItem(element);
}
};
// Inheritance
Mikit.Collapse.inherits(Mikit);
// Plugin
Mikit.Plugin.create('Collapse');
Mikit.Plugin.autoload('Collapse');
}(Mikit));
/**
* @library Mikit Dropdown
* @author Mikit
*/
(function (Mikit) {
Mikit.Dropdown = function (element, options) {
this.namespace = 'dropdown';
this.defaults = {
target: null,
toggleEvent: 'click',
height: false, // integer
width: false, // integer
animationOpen: 'slideDown',
animationClose: 'slideUp',
caretUp: false,
callbacks: ['open', 'opened', 'close', 'closed']
};
// Parent Constructor
Mikit.apply(this, arguments);
// Services
this.utils = new Mikit.Utils();
this.detect = new Mikit.Detect();
// Initialization
this.start();
};
// Functionality
Mikit.Dropdown.prototype = {
start: function () {
this.buildClose();
this.buildCaret();
if (this.detect.isMobile()) this.buildMobileAnimation();
this.$target.addClass('mi-hide');
this.$element.on(this.opts.toggleEvent + '.' + this.namespace, $.proxy(this.toggle, this));
},
stop: function () {
this.$element.off('.' + this.namespace);
this.$target.removeClass('mi-open').addClass('mi-hide');
this.disableEvents();
},
buildMobileAnimation: function () {
this.opts.animationOpen = 'fadeIn';
this.opts.animationClose = 'fadeOut';
},
buildClose: function () {
this.$close = this.$target.find('.mi-close');
},
buildCaret: function () {
this.$caret = this.getCaret();
this.buildCaretPosition();
},
buildCaretPosition: function () {
var height = this.$element.offset().top + this.$element.innerHeight() + this.$target.innerHeight();
if ($(document).height() > height) {
return;
}
this.opts.caretUp = true;
this.$caret.addClass('mi-up');
},
getCaret: function () {
return this.$element.find('.mi-caret');
},
toggleCaretOpen: function () {
if (this.opts.caretUp) this.$caret.removeClass('mi-up').addClass('mi-down');
else this.$caret.removeClass('mi-down').addClass('mi-up');
},
toggleCaretClose: function () {
if (this.opts.caretUp) this.$caret.removeClass('mi-down').addClass('mi-up');
else this.$caret.removeClass('mi-up').addClass('mi-down');
},
toggle: function (e) {
if (this.isOpened()) this.close(e);
else this.open(e);
},
open: function (e) {
if (e) e.preventDefault();
this.callback('open');
$('.mi-dropdown').removeClass('mi-open').addClass('mi-hide');
if (this.opts.height) this.$target.css('min-height', this.opts.height + 'px');
if (this.opts.width) this.$target.width(this.opts.width);
this.setPosition();
this.toggleCaretOpen();
this.$target.animation(this.opts.animationOpen, $.proxy(this.onOpened, this));
},
close: function (e) {
if (!this.isOpened()) {
return;
}
if (e) {
if (this.shouldNotBeClosed(e.target)) {
return;
}
e.preventDefault();
}
this.utils.enableBodyScroll();
this.callback('close');
this.toggleCaretClose();
this.$target.animation(this.opts.animationClose, $.proxy(this.onClosed, this));
},
onClosed: function () {
this.$target.removeClass('mi-open');
this.disableEvents();
this.callback('closed');
},
onOpened: function () {
this.$target.addClass('mi-open');
this.enableEvents();
this.callback('opened');
},
isOpened: function () {
return (this.$target.hasClass('mi-open'));
},
enableEvents: function () {
if (this.detect.isDesktop()) {
this.$target.on('mouseover.' + this.namespace, $.proxy(this.utils.disableBodyScroll, this.utils)).on('mouseout.' + this.namespace, $.proxy(this.utils.enableBodyScroll, this.utils));
}
$(document).on('scroll.' + this.namespace, $.proxy(this.setPosition, this));
$(window).on('resize.' + this.namespace, $.proxy(this.setPosition, this));
$(document).on('click.' + this.namespace + ' touchstart.' + this.namespace, $.proxy(this.close, this));
$(document).on('keydown.' + this.namespace, $.proxy(this.handleKeyboard, this));
this.$target.find('[data-action="dropdown-close"]').on('click.' + this.namespace, $.proxy(this.close, this));
},
disableEvents: function () {
this.$target.off('.' + this.namespace);
$(document).off('.' + this.namespace);
$(window).off('.' + this.namespace);
},
handleKeyboard: function (e) {
if (e.which === 27) this.close(e);
},
shouldNotBeClosed: function (el) {
if ($(el).attr('data-action') === 'dropdown-close' || el === this.$close[0]) {
return false;
} else if ($(el).closest('.mi-dropdown').length === 0) {
return false;
}
return true;
},
isNavigationFixed: function () {
return (this.$element.closest('.mi-fixed').length !== 0);
},
getPlacement: function (height) {
//return ( ( $(document).scrollTop() + $(window).height() ) < height ) ? 'top' : 'bottom';
return ( $(document).height() < height ) ? 'top' : 'bottom';
},
getOffset: function (position) {
return (this.isNavigationFixed()) ? this.$element.position() : this.$element.offset();
},
getPosition: function () {
return (this.isNavigationFixed()) ? 'fixed' : 'absolute';
},
setPosition: function () {
if (this.detect.isMobile()) {
this.$target.addClass('mi-dropdown-mobile');
return;
}
var position = this.getPosition();
var coords = this.getOffset(position);
var height = this.$target.innerHeight();
var width = this.$target.innerWidth();
var placement = this.getPlacement(coords.top + height + this.$element.innerHeight());
var leftFix = ($(window).width() < (coords.left + width)) ? (width - this.$element.innerWidth()) : 0;
var top, left = coords.left - leftFix;
if (placement === 'bottom') {
if (!this.isOpened()) this.$caret.removeClass('mi-up').addClass('mi-down');
this.opts.caretUp = false;
top = coords.top + this.$element.outerHeight() + 1;
} else {
this.opts.animationOpen = 'show';
this.opts.animationClose = 'hide';
if (!this.isOpened()) this.$caret.addClass('mi-up').removeClass('mi-down');
this.opts.caretUp = true;
top = coords.top - height - 1;
}
this.$target.css({
position: position,
top: top + 'px',
left: left + 'px'
});
}
};
// Inheritance
Mikit.Dropdown.inherits(Mikit);
// Plugin
Mikit.Plugin.create('Dropdown');
Mikit.Plugin.autoload('Dropdown');
}(Mikit));
/**
* @library Mikit Tab
* @author Mikit
*/
(function (Mikit) {
Mikit.Tab = function (element, options) {
this.namespace = 'tab';
this.defaults = {
equals: false,
active: false, // string (hash = tab id selector)
live: false, // class selector
hash: true, //boolean
callbacks: ['init', 'next', 'prev', 'open', 'opened', 'close', 'closed']
};
// Parent Constructor
Mikit.apply(this, arguments);
// Initialization
this.start();
};
// Functionality
Mikit.Tab.prototype = {
start: function () {
if (this.opts.live !== false) this.buildLiveTab();
this.tabCollection = [];
this.hashesCollection = [];
this.currentHash = [];
this.currentItem = false;
// items
this.$items = this.getItems();
this.$items.each($.proxy(this.loadItems, this));
// tab
this.$tab = this.getTab();
// location hash
this.currentHash = this.getLocationHash();
// close all
this.closeAll();
// active & height
this.setActiveItem();
this.setItemHeight();
// callback
this.callback('init');
},
getTab: function () {
return $(this.tabCollection).map(function () {
return this.toArray();
});
},
getItems: function () {
return this.$element.find('a');
},
loadItems: function (i, el) {
var item = this.getItem(el);
// set item identificator
item.$el.attr('rel', item.hash);
// collect item
this.collectItem(item);
// active
if (item.$parent.hasClass('mi-active')) {
this.currentItem = item;
this.opts.active = item.hash;
}
// event
item.$el.on('click.tab', $.proxy(this.open, this));
},
collectItem: function (item) {
this.tabCollection.push(item.$tab);
this.hashesCollection.push(item.hash);
},
buildLiveTab: function () {
var $layers = $(this.opts.live);
if ($layers.length === 0) {
return;
}
this.$liveTabList = $('<ul />');
$layers.each($.proxy(this.buildLiveItem, this));
this.$element.html('').append(this.$liveTabList);
},
buildLiveItem: function (i, tab) {
var $tab = $(tab);
var $li = $('<li />');
var $a = $('<a />');
var index = i + 1;
$tab.attr('id', this.getLiveItemId($tab, index));
var hash = '#' + $tab.attr('id');
var title = this.getLiveItemTitle($tab);
$a.attr('href', hash).attr('rel', hash).text(title);
$li.append($a);
this.$liveTabList.append($li);
},
getLiveItemId: function ($tab, index) {
return (typeof $tab.attr('id') === 'undefined') ? this.opts.live.replace('.', '') + index : $tab.attr('id');
},
getLiveItemTitle: function ($tab) {
return (typeof $tab.attr('data-title') === 'undefined') ? $tab.attr('id') : $tab.attr('data-title');
},
setActiveItem: function () {
if (this.currentHash) {
this.currentItem = this.getItemBy(this.currentHash);
this.opts.active = this.currentHash;
} else if (this.opts.active === false) {
this.currentItem = this.getItem(this.$items.first());
this.opts.active = this.currentItem.hash;
}
this.addActive(this.currentItem);
},
addActive: function (item) {
item.$parent.addClass('mi-active');
item.$tab.removeClass('mi-hide').addClass('mi-open');
this.currentItem = item;
},
removeActive: function (item) {
item.$parent.removeClass('mi-active');
item.$tab.addClass('mi-hide').removeClass('mi-open');
this.currentItem = false;
},
next: function (e) {
if (e) e.preventDefault();
var item = this.getItem(this.fetchElement('next'));
this.open(item.hash);
this.callback('next', item);
},
prev: function (e) {
if (e) e.preventDefault();
var item = this.getItem(this.fetchElement('prev'));
this.open(item.hash);
this.callback('prev', item);
},
fetchElement: function (type) {
var element;
if (this.currentItem !== false) {
// prev or next
element = this.currentItem.$parent[type]().find('a');
if (element.length === 0) {
return;
}
} else {
// first
element = this.$items[0];
}
return element;
},
open: function (e, push) {
if (typeof e === 'undefined') return;
if (typeof e === 'object') e.preventDefault();
var item = (typeof e === 'object') ? this.getItem(e.target) : this.getItemBy(e);
this.closeAll();
this.callback('open', item);
this.addActive(item);
// push state (doesn't need to push at the start)
this.pushStateOpen(push, item);
this.callback('opened', item);
},
pushStateOpen: function (push, item) {
if (push !== false && this.opts.hash !== false) {
history.pushState(false, false, item.hash);
}
},
close: function (num) {
var item = this.getItemBy(num);
if (!item.$parent.hasClass('mi-active')) {
return;
}
this.callback('close', item);
this.removeActive(item);
this.pushStateClose();
this.callback('closed', item);
},
pushStateClose: function () {
if (this.opts.hash !== false) {
history.pushState(false, false, ' ');
}
},
closeAll: function () {
this.$tab.removeClass('mi-open').addClass('mi-hide');
this.$items.parent().removeClass('mi-active');
},
getItem: function (element) {
var item = {};
item.$el = $(element);
item.hash = item.$el.attr('href');
item.$parent = item.$el.parent();
item.$tab = $(item.hash);
return item;
},
getItemBy: function (num) {
var element = (typeof num === 'number') ? this.$items.eq(num - 1) : this.$element.find('[rel="' + num + '"]');
return this.getItem(element);
},
getLocationHash: function () {
if (this.opts.hash === false) {
return false;
}
return (this.isHash()) ? top.location.hash : false;
},
isHash: function () {
return !(top.location.hash === '' || $.inArray(top.location.hash, this.hashesCollection) === -1);
},
setItemHeight: function () {
if (this.opts.equals) {
var minHeight = this.getItemMaxHeight() + 'px';
this.$tab.css('min-height', minHeight);
}
},
getItemMaxHeight: function () {
var max = 0;
this.$tab.each(function () {
var h = $(this).height();
max = h > max ? h : max;
});
return max;
}
};
// Inheritance
Mikit.Tab.inherits(Mikit);
// Plugin
Mikit.Plugin.create('Tab');
Mikit.Plugin.autoload('Tab');
}(Mikit));
/**
* @library Mikit Modal
* @author Mikit
*/
(function ($) {
$.modalcurrent = null;
$.modalwindow = function (options) {
var opts = $.extend({}, options, {
show: true
});
var $element = $('<span />');
$element.modal(opts);
};
})(jQuery);
(function (Mikit) {
Mikit.Modal = function (element, options) {
this.namespace = 'modal';
this.defaults = {
target: null,
show: false,
url: false,
header: false,
width: '600px', // string
height: false, // or string
maxHeight: false,
position: 'center', // top or center
overlay: true,
appendForms: false,
appendFields: false,
animationOpen: 'show',
animationClose: 'hide',
callbacks: ['open', 'opened', 'close', 'closed']
};
// Parent Constructor
Mikit.apply(this, arguments);
// Services
this.utils = new Mikit.Utils();
this.detect = new Mikit.Detect();
// Initialization
this.start();
};
// Functionality
Mikit.Modal.prototype = {
start: function () {
if (!this.hasTarget()) {
return;
}
if (this.opts.show) this.load();
else this.$element.on('click.' + this.namespace, $.proxy(this.load, this));
},
buildModal: function () {
this.$modal = this.$target.find('.mi-modal');
this.$header = this.$target.find('.mi-modal-header');
this.$close = this.$target.find('.mi-close');
this.$body = this.$target.find('.mi-modal-body');
},
buildOverlay: function () {
if (this.opts.overlay === false) {
return;
}
if ($('#mi-modal-overlay').length !== 0) {
this.$overlay = $('#mi-modal-overlay');
} else {
this.$overlay = $('<div id="mi-modal-overlay">').addClass('mi-hide');
$('body').prepend(this.$overlay);
}
this.$overlay.addClass('mi-overlay');
},
buildHeader: function () {
if (this.opts.header) this.$header.html(this.opts.header);
},
load: function (e) {
this.buildModal();
this.buildOverlay();
this.buildHeader();
if (this.opts.url) this.buildContent();
else this.open(e);
},
open: function (e) {
if (e) e.preventDefault();
if (this.isOpened()) {
return;
}
if (this.detect.isMobile()) this.opts.width = '96%';
if (this.opts.overlay) this.$overlay.removeClass('mi-hide');
this.$target.removeClass('mi-hide');
this.$modal.removeClass('mi-hide');
this.enableEvents();
this.findActions();
this.resize();
$(window).on('resize.' + this.namespace, $.proxy(this.resize, this));
if (this.detect.isDesktop()) this.utils.disableBodyScroll();
// enter
this.$modal.find('input[type=text],input[type=url],input[type=email]').on('keydown.' + this.namespace, $.proxy(this.handleEnter, this));
this.callback('open');
this.$modal.animation(this.opts.animationOpen, $.proxy(this.onOpened, this));
},
close: function (e) {
if (!this.$modal || !this.isOpened()) {
return;
}
if (e) {
if (this.shouldNotBeClosed(e.target)) {
return;
}
e.preventDefault();
}
this.callback('close');
this.disableEvents();
this.$modal.animation(this.opts.animationClose, $.proxy(this.onClosed, this));
if (this.opts.overlay) this.$overlay.animation(this.opts.animationClose);
},
onOpened: function () {
this.$modal.addClass('mi-open');
this.callback('opened');
$.modalcurrent = this;
},
onClosed: function () {
this.callback('closed');
this.$target.addClass('mi-hide');
this.$modal.removeClass('mi-open');
if (this.detect.isDesktop()) this.utils.enableBodyScroll();
this.$body.css('height', '');
$.modalcurrent = null;
},
isOpened: function () {
return (this.$modal.hasClass('mi-open'));
},
getData: function () {
var formdata = new Mikit.FormData(this);
formdata.set('');
return formdata.get();
},
buildContent: function () {
$.ajax({
url: this.opts.url + '?' + new Date().getTime(),
cache: false,
type: 'post',
data: this.getData(),
success: $.proxy(function (data) {
this.$body.html(data);
this.open();
}, this)
});
},
buildWidth: function () {
var width = this.opts.width;
var top = '2%';
var bottom = '2%';
var percent = width.match(/%$/);
if ((parseInt(this.opts.width) > $(window).width()) && !percent) {
width = '96%';
} else if (!percent) {
top = '16px';
bottom = '16px';
}
this.$modal.css({
'width': width,
'margin-top': top,
'margin-bottom': bottom
});
},
buildPosition: function () {
if (this.opts.position !== 'center') {
return;
}
var windowHeight = $(window).height();
var height = this.$modal.outerHeight();
var top = (windowHeight / 2 - height / 2) + 'px';
if (this.detect.isMobile()) top = '2%';
else if (height > windowHeight) top = '16px';
this.$modal.css('margin-top', top);
},
buildHeight: function () {
var windowHeight = $(window).height();
if (this.opts.maxHeight) {
var padding = parseInt(this.$body.css('padding-top')) + parseInt(this.$body.css('padding-bottom'));
var margin = parseInt(this.$modal.css('margin-top')) + parseInt(this.$modal.css('margin-bottom'));
var height = windowHeight - this.$header.innerHeight() - padding - margin;
this.$body.height(height);
} else if (this.opts.height !== false) {
this.$body.css('height', this.opts.height);
}
var modalHeight = this.$modal.outerHeight();
if (modalHeight > windowHeight) {
this.opts.animationOpen = 'show';
this.opts.animationClose = 'hide';
}
},
resize: function () {
this.buildWidth();
this.buildPosition();
this.buildHeight();
},
enableEvents: function () {
this.$close.on('click.' + this.namespace, $.proxy(this.close, this));
$(document).on('keyup.' + this.namespace, $.proxy(this.handleEscape, this));
this.$target.on('click.' + this.namespace, $.proxy(this.close, this));
},
disableEvents: function () {
this.$close.off('.' + this.namespace);
$(document).off('.' + this.namespace);
this.$target.off('.' + this.namespace);
$(window).off('.' + this.namespace);
},
findActions: function () {
this.$body.find('[data-action="modal-close"]').on('mousedown.' + this.namespace, $.proxy(this.close, this));
},
setHeader: function (header) {
this.$header.html(header);
},
setContent: function (content) {
this.$body.html(content);
},
setWidth: function (width) {
this.opts.width = width;
this.resize();
},
getModal: function () {
return this.$modal;
},
getBody: function () {
return this.$body;
},
getHeader: function () {
return this.$header;
},
handleEnter: function (e) {
if (e.which === 13) {
e.preventDefault();
this.close(false);
}
},
handleEscape: function (e) {
return (e.which === 27) ? this.close(false) : true;
},
shouldNotBeClosed: function (el) {
if ($(el).attr('data-action') === 'modal-close' || el === this.$close[0]) {
return false;
} else if ($(el).closest('.mi-modal').length === 0) {
return false;
}
return true;
}
};
// Inheritance
Mikit.Modal.inherits(Mikit);
// Plugin
Mikit.Plugin.create('Modal');
Mikit.Plugin.autoload('Modal');
}(Mikit));