metro4
Version:
The front-end framework for Build responsive, mobile-first projects on the web with the first front-end component library in Metro Style
547 lines (464 loc) • 16.7 kB
JavaScript
var $ = jQuery;
if (typeof jQuery === 'undefined') {
throw new Error('Metro 4 requires jQuery!');
}
if ('MutationObserver' in window === false) {
throw new Error('Metro 4 requires MutationObserver!');
}
var meta_init = $("meta[name='metro4:init']").attr("content");
var meta_locale = $("meta[name='metro4:locale']").attr("content");
var meta_week_start = $("meta[name='metro4:week_start']").attr("content");
var meta_date_format = $("meta[name='metro4:date_format']").attr("content");
var meta_date_format_input = $("meta[name='metro4:date_format_input']").attr("content");
var meta_animation_duration = $("meta[name='metro4:animation_duration']").attr("content");
var meta_callback_timeout = $("meta[name='metro4:callback_timeout']").attr("content");
var meta_timeout = $("meta[name='metro4:timeout']").attr("content");
var meta_scroll_multiple = $("meta[name='metro4:scroll_multiple']").attr("content");
var meta_cloak = $("meta[name='metro4:cloak']").attr("content"); //default or fade
var meta_cloak_duration = $("meta[name='metro4:cloak_duration']").attr("content"); //100
if (window.METRO_INIT === undefined) {
window.METRO_INIT = meta_init !== undefined ? JSON.parse(meta_init) : true;
}
if (window.METRO_DEBUG === undefined) {window.METRO_DEBUG = true;}
if (window.METRO_WEEK_START === undefined) {
window.METRO_WEEK_START = meta_week_start !== undefined ? parseInt(meta_week_start) : 0;
}
if (window.METRO_DATE_FORMAT === undefined) {
window.METRO_DATE_FORMAT = meta_date_format !== undefined ? meta_date_format : "%Y-%m-%d";
}
if (window.METRO_DATE_FORMAT_INPUT === undefined) {
window.METRO_DATE_FORMAT_INPUT = meta_date_format_input !== undefined ? meta_date_format_input : "%Y-%m-%d";
}
if (window.METRO_LOCALE === undefined) {
window.METRO_LOCALE = meta_locale !== undefined ? meta_locale : 'en-US';
}
if (window.METRO_ANIMATION_DURATION === undefined) {
window.METRO_ANIMATION_DURATION = meta_animation_duration !== undefined ? parseInt(meta_animation_duration) : 300;
}
if (window.METRO_CALLBACK_TIMEOUT === undefined) {
window.METRO_CALLBACK_TIMEOUT = meta_callback_timeout !== undefined ? parseInt(meta_callback_timeout) : 500;
}
if (window.METRO_TIMEOUT === undefined) {
window.METRO_TIMEOUT = meta_timeout !== undefined ? parseInt(meta_timeout) : 2000;
}
if (window.METRO_SCROLL_MULTIPLE === undefined) {
window.METRO_SCROLL_MULTIPLE = meta_scroll_multiple !== undefined ? parseInt(meta_scroll_multiple) : 20;
}
if (window.METRO_CLOAK_REMOVE === undefined) {
window.METRO_CLOAK_REMOVE = meta_cloak !== undefined ? (""+meta_cloak).toLowerCase() : "fade";
}
if (window.METRO_CLOAK_DURATION === undefined) {
window.METRO_CLOAK_DURATION = meta_cloak_duration !== undefined ? parseInt(meta_cloak_duration) : 500;
}
if (window.METRO_HOTKEYS_FILTER_CONTENT_EDITABLE === undefined) {window.METRO_HOTKEYS_FILTER_CONTENT_EDITABLE = true;}
if (window.METRO_HOTKEYS_FILTER_INPUT_ACCEPTING_ELEMENTS === undefined) {window.METRO_HOTKEYS_FILTER_INPUT_ACCEPTING_ELEMENTS = true;}
if (window.METRO_HOTKEYS_FILTER_TEXT_INPUTS === undefined) {window.METRO_HOTKEYS_FILTER_TEXT_INPUTS = true;}
if (window.METRO_HOTKEYS_BUBBLE_UP === undefined) {window.METRO_HOTKEYS_BUBBLE_UP = false;}
if (window.METRO_THROWS === undefined) {window.METRO_THROWS = true;}
window.METRO_MEDIA = [];
if ( typeof Object.create !== 'function' ) {
Object.create = function (o) {
function F() {}
F.prototype = o;
return new F();
};
}
if (typeof Object.values !== 'function') {
Object.values = function(obj) {
return Object.keys(obj).map(function(e) {
return obj[e]
});
}
}
if (typeof window.setImmediate !== 'function') {
window.setImmediate = function(fn){
return setTimeout(fn, 0);
}
}
var isTouch = (('ontouchstart' in window) || (navigator.MaxTouchPoints > 0) || (navigator.msMaxTouchPoints > 0));
var Metro = {
version: "@@version",
versionFull: "@@version.@@build @@status",
isTouchable: isTouch,
fullScreenEnabled: document.fullscreenEnabled,
sheet: null,
controlsPosition: {
INSIDE: "inside",
OUTSIDE: "outside"
},
groupMode: {
ONE: "one",
MULTI: "multi"
},
aspectRatio: {
HD: "hd",
SD: "sd",
CINEMA: "cinema"
},
fullScreenMode: {
WINDOW: "window",
DESKTOP: "desktop"
},
position: {
TOP: "top",
BOTTOM: "bottom",
LEFT: "left",
RIGHT: "right",
TOP_RIGHT: "top-right",
TOP_LEFT: "top-left",
BOTTOM_LEFT: "bottom-left",
BOTTOM_RIGHT: "bottom-right",
LEFT_BOTTOM: "left-bottom",
LEFT_TOP: "left-top",
RIGHT_TOP: "right-top",
RIGHT_BOTTOM: "right-bottom"
},
popoverEvents: {
CLICK: "click",
HOVER: "hover",
FOCUS: "focus"
},
stepperView: {
SQUARE: "square",
CYCLE: "cycle",
DIAMOND: "diamond"
},
listView: {
LIST: "list",
CONTENT: "content",
ICONS: "icons",
ICONS_MEDIUM: "icons-medium",
ICONS_LARGE: "icons-large",
TILES: "tiles",
TABLE: "table"
},
events: {
click: 'click.metro',
start: isTouch ? 'touchstart.metro' : 'mousedown.metro',
stop: isTouch ? 'touchend.metro' : 'mouseup.metro',
move: isTouch ? 'touchmove.metro' : 'mousemove.metro',
enter: isTouch ? 'touchstart.metro' : 'mouseenter.metro',
leave: 'mouseleave.metro',
focus: 'focus.metro',
blur: 'blur.metro',
resize: 'resize.metro',
keyup: 'keyup.metro',
keydown: 'keydown.metro',
keypress: 'keypress.metro',
dblclick: 'dblclick.metro',
input: 'input.metro',
change: 'change.metro',
cut: 'cut.metro',
paste: 'paste.metro',
scroll: 'scroll.metro',
scrollStart: 'scrollstart.metro',
scrollStop: 'scrollstop.metro',
mousewheel: 'mousewheel.metro',
inputchange: "change.metro input.metro propertychange.metro cut.metro paste.metro copy.metro",
dragstart: "dragstart.metro",
dragend: "dragend.metro",
dragenter: "dragenter.metro",
dragover: "dragover.metro",
dragleave: "dragleave.metro",
drop: 'drop.metro',
drag: 'drag.metro'
},
keyCode: {
BACKSPACE: 8,
TAB: 9,
ENTER: 13,
SHIFT: 16,
CTRL: 17,
ALT: 18,
BREAK: 19,
CAPS: 20,
ESCAPE: 27,
SPACE: 32,
PAGEUP: 33,
PAGEDOWN: 34,
END: 35,
HOME: 36,
LEFT_ARROW: 37,
UP_ARROW: 38,
RIGHT_ARROW: 39,
DOWN_ARROW: 40,
COMMA: 188
},
media_queries: {
FS: "(min-width: 0px)",
XS: "(min-width: 360px)",
SM: "(min-width: 576px)",
MD: "(min-width: 768px)",
LG: "(min-width: 992px)",
XL: "(min-width: 1200px)",
XXL: "(min-width: 1452px)"
},
media_sizes: {
FS: 0,
XS: 360,
SM: 576,
LD: 640,
MD: 768,
LG: 992,
XL: 1200,
XXL: 1452
},
media_mode: {
FS: "fs",
XS: "xs",
SM: "sm",
MD: "md",
LG: "lg",
XL: "xl",
XXL: "xxl"
},
media_modes: ["fs","xs","sm","md","lg","xl","xxl"],
actions: {
REMOVE: 1,
HIDE: 2
},
hotkeys: [],
about: function(f){
console.log("Metro 4 - v" + (f === true ? this.versionFull : this.version));
},
aboutDlg: function(f){
alert("Metro 4 - v" + (f === true ? this.versionFull : this.version));
},
ver: function(f){
return (f === true ? this.versionFull : this.version);
},
observe: function(){
'use strict';
var observer, observerCallback;
var observerConfig = {
childList: true,
attributes: true,
subtree: true
};
observerCallback = function(mutations){
mutations.map(function(mutation){
if (mutation.type === 'attributes' && mutation.attributeName !== "data-role") {
var element = $(mutation.target);
var mc = element.data('metroComponent');
if (mc !== undefined) {
$.each(mc, function(){
'use strict';
var plug = element.data(this);
if (plug) plug.changeAttribute(mutation.attributeName);
});
}
} else
if (mutation.type === 'childList' && mutation.addedNodes.length > 0) {
var i, obj, widgets = {}, plugins = {};
var nodes = mutation.addedNodes;
for(i = 0; i < nodes.length; i++) {
var node = mutation.addedNodes[i];
if (node.tagName === 'SCRIPT' || node.tagName === 'STYLE') {
continue ;
}
obj = $(mutation.addedNodes[i]);
plugins = obj.find("[data-role]");
if (obj.data('role') !== undefined) {
widgets = $.merge(plugins, obj);
} else {
widgets = plugins;
}
if (widgets.length) {
Metro.initWidgets(widgets);
}
}
} else {
//console.log(mutation);
}
});
};
observer = new MutationObserver(observerCallback);
observer.observe($("html")[0], observerConfig);
},
init: function(){
var widgets = $("[data-role]");
var hotkeys = $("[data-hotkey]");
var html = $("html");
if (isTouch === true) {
html.addClass("metro-touch-device");
} else {
html.addClass("metro-no-touch-device");
}
this.sheet = Utils.newCssSheet();
window.METRO_MEDIA = [];
$.each(Metro.media_queries, function(key, query){
if (Utils.media(query)) {
METRO_MEDIA.push(Metro.media_mode[key]);
}
});
this.observe();
this.initHotkeys(hotkeys);
this.initWidgets(widgets);
this.about(true);
if (METRO_CLOAK_REMOVE !== "fade") {
$(".m4-cloak").removeClass("m4-cloak");
} else {
$(".m4-cloak").animate({
opacity: 1
}, METRO_CLOAK_REMOVE, function(){
$(".m4-cloak").removeClass("m4-cloak");
})
}
return this;
},
initHotkeys: function(hotkeys){
$.each(hotkeys, function(){
'use strict';
var element = $(this);
var hotkey = element.data('hotkey') ? element.data('hotkey').toLowerCase() : false;
if (hotkey === false) {
return;
}
if (element.data('hotKeyBonded') === true ) {
return;
}
Metro.hotkeys.push(hotkey);
$(document).on(Metro.events.keyup, null, hotkey, function(e){
if (element === undefined) return;
if (element[0].tagName === 'A' &&
element.attr('href') !== undefined &&
element.attr('href').trim() !== '' &&
element.attr('href').trim() !== '#') {
document.location.href = element.attr('href');
} else {
element.click();
}
return METRO_HOTKEYS_BUBBLE_UP;
});
element.data('hotKeyBonded', true);
});
},
initWidgets: function(widgets) {
var that = this;
$.each(widgets, function () {
'use strict';
var $this = $(this), w = this;
var roles = $this.data('role').split(/\s*,\s*/);
roles.map(function (func) {
if ($.fn[func] !== undefined && $this.attr("data-role-"+func) === undefined) {
$.fn[func].call($this);
$this.attr("data-role-"+func, true);
var mc = $this.data('metroComponent');
if (mc === undefined) {
mc = [func];
} else {
mc.push(func);
}
$this.data('metroComponent', mc);
}
});
});
},
plugin: function(name, object){
'use strict';
$.fn[name] = function( options ) {
return this.each(function() {
$.data( this, name, Object.create(object).init(options, this ));
});
};
},
destroyPlugin: function(element, name){
var p, mc;
element = Utils.isJQueryObject(element) ? element[0] : element;
p = $(element).data(name);
if (!Utils.isValue(p)) {
throw new Error("Component can not be destroyed: the element is not a Metro 4 component.");
}
if (!Utils.isFunc(p['destroy'])) {
throw new Error("Component can not be destroyed: method destroy not found.");
}
p['destroy']();
mc = $(element).data("metroComponent");
Utils.arrayDelete(mc, name);
$(element).data("metroComponent", mc);
$.removeData(element, name);
$(element).removeAttr("data-role-"+name);
},
destroyPluginAll: function(element){
element = Utils.isJQueryObject(element) ? element[0] : element;
var mc = $(element).data("metroComponent");
if (mc !== undefined && mc.length > 0) $.each(mc, function(){
'use strict';
Metro.destroyPlugin(element, this);
});
},
initPlugin: function(element, name){
element = $(element);
try {
if ($.fn[name] !== undefined && element.attr("data-role-"+name) === undefined) {
$.fn[name].call(element);
element.attr("data-role-"+name, true);
var mc = element.data('metroComponent');
if (mc === undefined) {
mc = [name];
} else {
mc.push(name);
}
element.data('metroComponent', mc);
}
} catch (e) {
console.log(e.message, e.stack);
}
},
reinitPlugin: function(element, name){
this.destroyPlugin(element, name);
this.initPlugin(element, name);
},
reinitPluginAll: function(element){
var mc = $(element).data("metroComponent");
if (mc !== undefined && mc.length > 0) $.each(mc, function(){
'use strict';
Metro.reinitPlugin(element, this);
});
},
noop: function(){},
noop_true: function(){return true;},
noop_false: function(){return false;},
stop: function(e){
e.stopPropagation();
e.preventDefault();
},
requestFullScreen: function(element){
if (element.mozRequestFullScreen) {
element.mozRequestFullScreen();
} else if (element.webkitRequestFullScreen) {
element.webkitRequestFullScreen();
} else if (element.msRequestFullscreen) {
element.msRequestFullscreen();
} else {
element.requestFullscreen();
}
},
exitFullScreen: function(){
if (document.mozCancelFullScreen) {
document.mozCancelFullScreen();
}
else if (document.webkitCancelFullScreen) {
document.webkitCancelFullScreen();
}
else if (document.msExitFullscreen) {
document.msExitFullscreen();
} else {
document.exitFullscreen();
}
},
inFullScreen: function(){
var fsm = (document.fullscreenElement || document.webkitFullscreenElement || document.mozFullScreenElement || document.msFullscreenElement);
return fsm !== undefined;
}
};
window['Metro'] = Metro;
$(window).on(Metro.events.resize, function(){
window.METRO_MEDIA = [];
$.each(Metro.media_queries, function(key, query){
if (Utils.media(query)) {
METRO_MEDIA.push(Metro.media_mode[key]);
}
});
});
;