amazeui
Version:
Sleek, intuitive, and powerful front-end framework for faster and easier web development.
608 lines (499 loc) • 15.9 kB
JavaScript
;
var $ = require('jquery');
if (typeof $ === 'undefined') {
throw new Error('Amaze UI 2.x requires jQuery :-(\n' +
'\u7231\u4e0a\u4e00\u5339\u91ce\u9a6c\uff0c\u53ef\u4f60' +
'\u7684\u5bb6\u91cc\u6ca1\u6709\u8349\u539f\u2026');
}
var UI = $.AMUI || {};
var $win = $(window);
var doc = window.document;
var $html = $('html');
UI.VERSION = '{{VERSION}}';
UI.support = {};
UI.support.transition = (function() {
var transitionEnd = (function() {
// https://developer.mozilla.org/en-US/docs/Web/Events/transitionend#Browser_compatibility
var element = doc.body || doc.documentElement;
var transEndEventNames = {
WebkitTransition: 'webkitTransitionEnd',
MozTransition: 'transitionend',
OTransition: 'oTransitionEnd otransitionend',
transition: 'transitionend'
};
for (var name in transEndEventNames) {
if (element.style[name] !== undefined) {
return transEndEventNames[name];
}
}
})();
return transitionEnd && {end: transitionEnd};
})();
UI.support.animation = (function() {
var animationEnd = (function() {
var element = doc.body || doc.documentElement;
var animEndEventNames = {
WebkitAnimation: 'webkitAnimationEnd',
MozAnimation: 'animationend',
OAnimation: 'oAnimationEnd oanimationend',
animation: 'animationend'
};
for (var name in animEndEventNames) {
if (element.style[name] !== undefined) {
return animEndEventNames[name];
}
}
})();
return animationEnd && {end: animationEnd};
})();
/* eslint-disable dot-notation */
UI.support.touch = (
('ontouchstart' in window &&
navigator.userAgent.toLowerCase().match(/mobile|tablet/)) ||
(window.DocumentTouch && document instanceof window.DocumentTouch) ||
(window.navigator['msPointerEnabled'] &&
window.navigator['msMaxTouchPoints'] > 0) || // IE 10
(window.navigator['pointerEnabled'] &&
window.navigator['maxTouchPoints'] > 0) || // IE >=11
false);
/* eslint-enable dot-notation */
// https://developer.mozilla.org/zh-CN/docs/DOM/MutationObserver
UI.support.mutationobserver = (window.MutationObserver ||
window.WebKitMutationObserver || null);
// https://github.com/Modernizr/Modernizr/blob/924c7611c170ef2dc502582e5079507aff61e388/feature-detects/forms/validation.js#L20
UI.support.formValidation = (typeof document.createElement('form').
checkValidity === 'function');
UI.utils = {};
/**
* Debounce function
*
* @param {function} func Function to be debounced
* @param {number} wait Function execution threshold in milliseconds
* @param {bool} immediate Whether the function should be called at
* the beginning of the delay instead of the
* end. Default is false.
* @description Executes a function when it stops being invoked for n seconds
* @see _.debounce() http://underscorejs.org
*/
UI.utils.debounce = function(func, wait, immediate) {
var timeout;
return function() {
var context = this;
var args = arguments;
var later = function() {
timeout = null;
if (!immediate) {
func.apply(context, args);
}
};
var callNow = immediate && !timeout;
clearTimeout(timeout);
timeout = setTimeout(later, wait);
if (callNow) {
func.apply(context, args);
}
};
};
UI.utils.isInView = function(element, options) {
var $element = $(element);
var visible = !!($element.width() || $element.height()) &&
$element.css('display') !== 'none';
if (!visible) {
return false;
}
var windowLeft = $win.scrollLeft();
var windowTop = $win.scrollTop();
var offset = $element.offset();
var left = offset.left;
var top = offset.top;
options = $.extend({topOffset: 0, leftOffset: 0}, options);
return (top + $element.height() >= windowTop &&
top - options.topOffset <= windowTop + $win.height() &&
left + $element.width() >= windowLeft &&
left - options.leftOffset <= windowLeft + $win.width());
};
UI.utils.parseOptions = UI.utils.options = function(string) {
if ($.isPlainObject(string)) {
return string;
}
var start = (string ? string.indexOf('{') : -1);
var options = {};
if (start != -1) {
try {
options = (new Function('',
'var json = ' + string.substr(start) +
'; return JSON.parse(JSON.stringify(json));'))();
} catch (e) {
}
}
return options;
};
UI.utils.generateGUID = function(namespace) {
var uid = namespace + '-' || 'am-';
do {
uid += Math.random().toString(36).substring(2, 7);
} while (document.getElementById(uid));
return uid;
};
// @see https://davidwalsh.name/get-absolute-url
UI.utils.getAbsoluteUrl = (function() {
var a;
return function(url) {
if (!a) {
a = document.createElement('a');
}
a.href = url;
return a.href;
};
})();
/**
* Plugin AMUI Component to jQuery
*
* @param {String} name - plugin name
* @param {Function} Component - plugin constructor
* @param {Object} [pluginOption]
* @param {String} pluginOption.dataOptions
* @param {Function} pluginOption.methodCall - custom method call
* @param {Function} pluginOption.before
* @param {Function} pluginOption.after
* @since v2.4.1
*/
UI.plugin = function UIPlugin(name, Component, pluginOption) {
var old = $.fn[name];
pluginOption = pluginOption || {};
$.fn[name] = function(option) {
var allArgs = Array.prototype.slice.call(arguments, 0);
var args = allArgs.slice(1);
var propReturn;
var $set = this.each(function() {
var $this = $(this);
var dataName = 'amui.' + name;
var dataOptionsName = pluginOption.dataOptions || ('data-am-' + name);
var instance = $this.data(dataName);
var options = $.extend({},
UI.utils.parseOptions($this.attr(dataOptionsName)),
typeof option === 'object' && option);
if (!instance && option === 'destroy') {
return;
}
if (!instance) {
$this.data(dataName, (instance = new Component(this, options)));
}
// custom method call
if (pluginOption.methodCall) {
pluginOption.methodCall.call($this, allArgs, instance);
} else {
// before method call
pluginOption.before &&
pluginOption.before.call($this, allArgs, instance);
if (typeof option === 'string') {
propReturn = typeof instance[option] === 'function' ?
instance[option].apply(instance, args) : instance[option];
}
// after method call
pluginOption.after && pluginOption.after.call($this, allArgs, instance);
}
});
return (propReturn === undefined) ? $set : propReturn;
};
$.fn[name].Constructor = Component;
// no conflict
$.fn[name].noConflict = function() {
$.fn[name] = old;
return this;
};
UI[name] = Component;
};
// http://blog.alexmaccaw.com/css-transitions
$.fn.emulateTransitionEnd = function(duration) {
var called = false;
var $el = this;
$(this).one(UI.support.transition.end, function() {
called = true;
});
var callback = function() {
if (!called) {
$($el).trigger(UI.support.transition.end);
}
$el.transitionEndTimmer = undefined;
};
this.transitionEndTimmer = setTimeout(callback, duration);
return this;
};
$.fn.redraw = function() {
return this.each(function() {
/* eslint-disable */
var redraw = this.offsetHeight;
/* eslint-enable */
});
};
$.fn.transitionEnd = function(callback) {
var endEvent = UI.support.transition.end;
var dom = this;
function fireCallBack(e) {
callback.call(this, e);
endEvent && dom.off(endEvent, fireCallBack);
}
if (callback && endEvent) {
dom.on(endEvent, fireCallBack);
}
return this;
};
$.fn.removeClassRegEx = function() {
return this.each(function(regex) {
var classes = $(this).attr('class');
if (!classes || !regex) {
return false;
}
var classArray = [];
classes = classes.split(' ');
for (var i = 0, len = classes.length; i < len; i++) {
if (!classes[i].match(regex)) {
classArray.push(classes[i]);
}
}
$(this).attr('class', classArray.join(' '));
});
};
//
$.fn.alterClass = function(removals, additions) {
var self = this;
if (removals.indexOf('*') === -1) {
// Use native jQuery methods if there is no wildcard matching
self.removeClass(removals);
return !additions ? self : self.addClass(additions);
}
var classPattern = new RegExp('\\s' +
removals.
replace(/\*/g, '[A-Za-z0-9-_]+').
split(' ').
join('\\s|\\s') +
'\\s', 'g');
self.each(function(i, it) {
var cn = ' ' + it.className + ' ';
while (classPattern.test(cn)) {
cn = cn.replace(classPattern, ' ');
}
it.className = $.trim(cn);
});
return !additions ? self : self.addClass(additions);
};
// handle multiple browsers for requestAnimationFrame()
// http://www.paulirish.com/2011/requestanimationframe-for-smart-animating/
// https://github.com/gnarf/jquery-requestAnimationFrame
UI.utils.rAF = (function() {
return window.requestAnimationFrame ||
window.webkitRequestAnimationFrame ||
window.mozRequestAnimationFrame ||
window.oRequestAnimationFrame ||
// if all else fails, use setTimeout
function(callback) {
return window.setTimeout(callback, 1000 / 60); // shoot for 60 fps
};
})();
// handle multiple browsers for cancelAnimationFrame()
UI.utils.cancelAF = (function() {
return window.cancelAnimationFrame ||
window.webkitCancelAnimationFrame ||
window.mozCancelAnimationFrame ||
window.oCancelAnimationFrame ||
function(id) {
window.clearTimeout(id);
};
})();
// via http://davidwalsh.name/detect-scrollbar-width
UI.utils.measureScrollbar = function() {
if (document.body.clientWidth >= window.innerWidth) {
return 0;
}
// if ($html.width() >= window.innerWidth) return;
// var scrollbarWidth = window.innerWidth - $html.width();
var $measure = $('<div ' +
'style="width: 100px;height: 100px;overflow: scroll;' +
'position: absolute;top: -9999px;"></div>');
$(document.body).append($measure);
var scrollbarWidth = $measure[0].offsetWidth - $measure[0].clientWidth;
$measure.remove();
return scrollbarWidth;
};
UI.utils.imageLoader = function($image, callback) {
function loaded() {
callback($image[0]);
}
function bindLoad() {
this.one('load', loaded);
if (/MSIE (\d+\.\d+);/.test(navigator.userAgent)) {
var src = this.attr('src');
var param = src.match(/\?/) ? '&' : '?';
param += 'random=' + (new Date()).getTime();
this.attr('src', src + param);
}
}
if (!$image.attr('src')) {
loaded();
return;
}
if ($image[0].complete || $image[0].readyState === 4) {
loaded();
} else {
bindLoad.call($image);
}
};
/**
* @see https://github.com/cho45/micro-template.js
* (c) cho45 http://cho45.github.com/mit-license
*/
UI.template = function(id, data) {
var me = UI.template;
if (!me.cache[id]) {
me.cache[id] = (function() {
var name = id;
var string = /^[\w\-]+$/.test(id) ?
me.get(id) : (name = 'template(string)', id); // no warnings
var line = 1;
/* eslint-disable max-len, quotes */
var body = ('try { ' + (me.variable ?
'var ' + me.variable + ' = this.stash;' : 'with (this.stash) { ') +
"this.ret += '" +
string.
replace(/<%/g, '\x11').replace(/%>/g, '\x13'). // if you want other tag, just edit this line
replace(/'(?![^\x11\x13]+?\x13)/g, '\\x27').
replace(/^\s*|\s*$/g, '').
replace(/\n/g, function() {
return "';\nthis.line = " + (++line) + "; this.ret += '\\n";
}).
replace(/\x11-(.+?)\x13/g, "' + ($1) + '").
replace(/\x11=(.+?)\x13/g, "' + this.escapeHTML($1) + '").
replace(/\x11(.+?)\x13/g, "'; $1; this.ret += '") +
"'; " + (me.variable ? "" : "}") + "return this.ret;" +
"} catch (e) { throw 'TemplateError: ' + e + ' (on " + name +
"' + ' line ' + this.line + ')'; } " +
"//@ sourceURL=" + name + "\n" // source map
).replace(/this\.ret \+= '';/g, '');
/* eslint-enable max-len, quotes */
var func = new Function(body);
var map = {
'&': '&',
'<': '<',
'>': '>',
'\x22': '"',
'\x27': '''
};
var escapeHTML = function(string) {
return ('' + string).replace(/[&<>\'\"]/g, function(_) {
return map[_];
});
};
return function(stash) {
return func.call(me.context = {
escapeHTML: escapeHTML,
line: 1,
ret: '',
stash: stash
});
};
})();
}
return data ? me.cache[id](data) : me.cache[id];
};
UI.template.cache = {};
UI.template.get = function(id) {
if (id) {
var element = document.getElementById(id);
return element && element.innerHTML || '';
}
};
// Dom mutation watchers
UI.DOMWatchers = [];
UI.DOMReady = false;
UI.ready = function(callback) {
UI.DOMWatchers.push(callback);
if (UI.DOMReady) {
// console.log('Ready call');
callback(document);
}
};
UI.DOMObserve = function(elements, options, callback) {
var Observer = UI.support.mutationobserver;
if (!Observer) {
return;
}
options = $.isPlainObject(options) ?
options : {childList: true, subtree: true};
callback = typeof callback === 'function' && callback || function() {
};
$(elements).each(function() {
var element = this;
var $element = $(element);
if ($element.data('am.observer')) {
return;
}
try {
var observer = new Observer(UI.utils.debounce(
function(mutations, instance) {
callback.call(element, mutations, instance);
// trigger this event manually if MutationObserver not supported
$element.trigger('changed.dom.amui');
}, 50));
observer.observe(element, options);
$element.data('am.observer', observer);
} catch (e) {
}
});
};
$.fn.DOMObserve = function(options, callback) {
return this.each(function() {
/* eslint-disable new-cap */
UI.DOMObserve(this, options, callback);
/* eslint-enable new-cap */
});
};
if (UI.support.touch) {
$html.addClass('am-touch');
}
$(document).on('changed.dom.amui', function(e) {
var element = e.target;
// TODO: just call changed element's watcher
// every watcher callback should have a key
// use like this: <div data-am-observe='key1, key2'>
// get keys via $(element).data('amObserve')
// call functions store with these keys
$.each(UI.DOMWatchers, function(i, watcher) {
watcher(element);
});
});
$(function() {
var $body = $(document.body);
UI.DOMReady = true;
// Run default init
$.each(UI.DOMWatchers, function(i, watcher) {
watcher(document);
});
// watches DOM
/* eslint-disable new-cap */
UI.DOMObserve('[data-am-observe]');
/* eslint-enable */
$html.removeClass('no-js').addClass('js');
UI.support.animation && $html.addClass('cssanimations');
// iOS standalone mode
if (window.navigator.standalone) {
$html.addClass('am-standalone');
}
$('.am-topbar-fixed-top').length &&
$body.addClass('am-with-topbar-fixed-top');
$('.am-topbar-fixed-bottom').length &&
$body.addClass('am-with-topbar-fixed-bottom');
// Remove responsive classes in .am-layout
var $layout = $('.am-layout');
$layout.find('[class*="md-block-grid"]').alterClass('md-block-grid-*');
$layout.find('[class*="lg-block-grid"]').alterClass('lg-block-grid');
// widgets not in .am-layout
$('[data-am-widget]').each(function() {
var $widget = $(this);
// console.log($widget.parents('.am-layout').length)
if ($widget.parents('.am-layout').length === 0) {
$widget.addClass('am-no-layout');
}
});
});
module.exports = UI;