social-likes-nojq/gh-pages/tamia/tamia/tamia.js

364 lines
9.8 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

// Tâmia © 2013 Artem Sapegin http://sapegin.me
// https://github.com/sapegin/tamia
// JS core
// jQuery and Modernizr arent required but very useful
/*jshint newcap:false*/
/*global DEBUG:true, Modernizr:false, console:false*/
/**
* Debug mode.
*
* You can use DEBUG global variable in your scripts to hide some code from minified production version of JavaScript.
*
* To make it work add to your Gruntfile:
*
* uglify: {
* options: {
* compress: {
* global_defs: {
* DEBUG: !!grunt.option('debug')
* }
* }
* },
* ...
* }
*
* Then if you run `grunt --debug` DEBUG variable will be true and false if you run just `grunt`.
*/
if (typeof window.DEBUG === 'undefined') window.DEBUG = true;
;(function(window, jQuery, Modernizr, undefined) {
'use strict';
// IE8+
if (!document.querySelectorAll) return;
// Namespace
var tamia = window.tamia = {};
if (DEBUG) {
// Debug logger
var addBadge = function(args, name) {
// Color console badge
// Based on https://github.com/jbail/lumberjack
var ua = navigator.userAgent.toLowerCase();
if (ua.indexOf('chrome') !== -1 || ua.indexOf('firefox') !== -1) {
var format = '%c %s %c ' + args.shift();
args.unshift(format, 'background:#aa759f; color:#fff', name, 'background:inherit; color:inherit');
}
else {
args[0] = name + ': ' + args[0];
}
return args;
};
var logger = function() {
var args = Array.prototype.slice.call(arguments);
var func = args.shift();
console[func].apply(console, addBadge(args, 'Tâmia'));
};
var log = tamia.log = logger.bind(null, 'log');
var warn = tamia.warn = logger.bind(null, 'warn');
// Check optional dependencies
if (!jQuery) warn('jQuery not found.');
if (!jQuery.Transitions) warn('jQuery Transition Events plugin (tamia/vendor/transition-events.js) not found.');
if (!Modernizr) warn('Modernizr not found.');
// Check required Modernizr features
$.each([
'csstransitions',
'cssgradients',
'flexbox',
'touch',
], function(idx, feature) {
if (!(feature in Modernizr)) warn('Modernizr should be built with "' + feature + '" feautre.');
});
}
var _containersCache;
var _components = {};
var _initializedAttribute = '_tamia-yep';
function _getContainers(parent) {
return (parent || document).querySelectorAll('[data-component]');
}
/**
* Initialize components.
*
* @param {Object} components Initializers for each component.
*
* Examples:
*
* <div data-component="pony"></div>
*
* tamia.initComponents({
* // New style component
* pony: Pony, // class Pony extends Component {...}
* // Plain initializer
* pony: function(elem) {
* // $(elem) === <div data-component="pony">
* },
* // Initialize jQuery plugins (plain initializer)
* jquerypony: function(elem) {
* $(elem).pluginmethod({option1: 'val1', options2: 'val2'});
* $(elem).pluginmethod2();
* },
* // Initialize jQuery plugins (shortcut)
* jquerypony: {
* pluginmethod: {option1: 'val1', options2: 'val2'},
* pluginmethod2: ['attr1', 'attr2', 'attr3'],
* pluginmethod3: null
* }
* }
*
* Caveats:
*
* 1. To initialize components inside container that was hidden or inside dynamically created container use
* init.tamia event: `$('.js-container').trigger('init.tamia');`
* 2. No components will be initialized twice. Its safe to trigger init.tamia event multiple times: only new nodes
* or nodes that was hidden before will be affected.
*/
tamia.initComponents = function(components, parent) {
var containers;
if (parent === undefined) {
containers = _containersCache || (_containersCache = _getContainers());
}
else {
// Init all components inside DOM node
containers = _getContainers(parent);
components = _components;
}
// Init components
for (var containerIdx = 0, containerCnt = containers.length; containerIdx < containerCnt; containerIdx++) {
var container = containers[containerIdx];
var componentName = container.getAttribute('data-component');
var component = components[componentName];
if (!component || container.hasAttribute(_initializedAttribute)) continue;
var initialized = true;
if ('__tamia_cmpnt__' in component) {
// New style component
initialized = (new component(container)).initializable;
}
else if (typeof component === 'function') {
// Old style component
initialized = component(container);
}
else if (jQuery) {
// jQuery plugins shortcut
for (var method in component) {
var params = component[method];
var elem = jQuery(container);
if (DEBUG && !jQuery.isFunction(elem[method])) warn('jQuery method "%s" not found (used in "%s" component).', method, componentName);
if (jQuery.isArray(params)) {
elem[method].apply(elem, params);
}
else {
elem[method](params);
}
}
}
if (initialized !== false) {
container.setAttribute(_initializedAttribute, 'yes');
}
}
// Add new components to all components array
for (var name in components) {
_components[name] = components[name];
}
};
if (jQuery) {
var _doc = jQuery(document);
var _hiddenClass = 'is-hidden';
var _transitionClass = 'is-transit';
var _appearedEvent = 'appeared.tamia';
var _disappearedEvent = 'disappeared.tamia';
var _fallbackTimeout = 1000;
/**
* Registers Tâmia events (eventname.tamia) on document.
*
* Example:
*
* // Registers enable.tamia event.
* tamia.registerEvents({
* enable: function(elem) {
* }
* });
*
* @param {Object} handlers Handlers list.
*/
tamia.registerEvents = function(handlers) {
var events = $.map(handlers, _tamiaze).join(' ');
_doc.on(events, function(event) {
if (DEBUG) log('Event "%s":', event.type, event.target);
handlers[event.type](event.target);
});
};
var _tamiaze = function (handler, name) {
return name + '.tamia';
};
/**
* Events
*/
var _handlers = {};
/**
* Init components inside any jQuery node.
*
* Examples:
*
* $(document).trigger('init.tamia');
* $('.js-container').trigger('init.tamia');
*/
_handlers.init = function(elem) {
tamia.initComponents(undefined, elem);
};
/**
* Show element with CSS transition.
*
* appeared.tamia event will be fired the moment transition ends.
*
* Example:
*
* .dialog
* transition: opacity .5s ease-in-out
* ...
* &.is-hidden
* opacity: 0
*
* <div class="dialog is-hidden js-dialog">...</div>
*
* $('.js-dialog').trigger('appear.tamia');
*/
_handlers.appear = function(elem) {
elem = $(elem);
if (Modernizr && Modernizr.csstransitions) {
if (elem.hasClass(_transitionClass) && !elem.hasClass(_hiddenClass)) return;
elem.addClass(_transitionClass);
setTimeout(function() {
elem.removeClass(_hiddenClass);
elem.afterTransition(function() {
elem.removeClass(_transitionClass);
elem.trigger(_appearedEvent);
});
}, 0);
}
else {
elem.removeClass(_hiddenClass);
elem.trigger(_appearedEvent);
}
};
/**
* Hide element with CSS transition.
*
* disappeared.tamia event will be fired the moment transition ends.
*
* Opposite of `appear.tamia` event.
*/
_handlers.disappear = function(elem) {
elem = $(elem);
if (Modernizr && Modernizr.csstransitions) {
if (elem.hasClass(_transitionClass) && elem.hasClass(_hiddenClass)) return;
elem.addClass(_transitionClass);
elem.addClass(_hiddenClass);
elem.afterTransition(function() {
elem.removeClass(_transitionClass);
elem.trigger(_disappearedEvent);
});
}
else {
elem.addClass(_hiddenClass);
elem.trigger(_disappearedEvent);
}
};
/**
* Toggles elements visibility with CSS transition.
*
* See `appear.tamia` event for details.
*/
_handlers.toggle = function(elem) {
elem = $(elem);
if (elem.hasClass(_hiddenClass)) {
_handlers.appear(elem);
}
else {
_handlers.disappear(elem);
}
};
tamia.registerEvents(_handlers);
/**
* Controls.
*
* Fires jQuery event to specified element on click at this element.
*
* @param data-fire Event name.
* @param [data-target] Target element selector.
* @param [data-closest] Target element selector: search only through element ancestors.
* @param [data-attrs] Comma separated attributes list.
*
* Either of data-target or data-closest is required.
*
* Example:
*
* <span data-fire="slider-next" data-target=".portfolio" data-attrs="1,2,3">Next</span>
* <!-- $('.portfolio').trigger('slider-next', [1, 2, 3]); -->
*/
_doc.on('click', '[data-fire]', function(event) {
var elem = jQuery(event.currentTarget);
var data = elem.data();
if (DEBUG) if (!data.target && !data.closest) return log('You should define either data-target or data-closest on', elem[0]);
var target = data.target && jQuery(data.target) || elem.closest(data.closest);
if (DEBUG) if (!target.length) return log('Target element %s not found for', data.target || data.closest, elem[0]);
var attrs = data.attrs;
if (DEBUG) log('Fire "%s" with attrs [%s] on', data.fire, attrs || '', target);
target.trigger(data.fire, attrs ? attrs.split(/[;, ]/) : undefined);
event.preventDefault();
});
/**
* Grid helper.
*
* Example:
*
* <div data-component="grid"></div>
*/
if (DEBUG) tamia.initComponents({
grid: function(elem) {
elem = $(elem);
elem
.addClass('g-row')
.html(
new Array((elem.data('columns') || 12) + 1).join('<b class="g-debug-col" style="height:'+document.documentElement.scrollHeight+'px"></b>')
)
;
}
});
}
}(window, window.jQuery, window.Modernizr));