META-INF.resources.bower_components.outlayer.item.js Maven / Gradle / Ivy
/**
* Outlayer Item
*/
( function (window, factory) {
// universal module definition
/* jshint strict: false */
/* globals define, module, require */
if (typeof define == 'function' && define.amd) {
// AMD - RequireJS
define([
'ev-emitter/ev-emitter',
'get-size/get-size'
],
factory
);
} else if (typeof module == 'object' && module.exports) {
// CommonJS - Browserify, Webpack
module.exports = factory(
require('ev-emitter'),
require('get-size')
);
} else {
// browser global
window.Outlayer = {};
window.Outlayer.Item = factory(
window.EvEmitter,
window.getSize
);
}
}(window, function factory(EvEmitter, getSize) {
'use strict';
// ----- helpers ----- //
function isEmptyObj(obj) {
for (var prop in obj) {
return false;
}
prop = null;
return true;
}
// -------------------------- CSS3 support -------------------------- //
var docElemStyle = document.documentElement.style;
var transitionProperty = typeof docElemStyle.transition == 'string' ?
'transition' : 'WebkitTransition';
var transformProperty = typeof docElemStyle.transform == 'string' ?
'transform' : 'WebkitTransform';
var transitionEndEvent = {
WebkitTransition: 'webkitTransitionEnd',
transition: 'transitionend'
}[transitionProperty];
// cache all vendor properties that could have vendor prefix
var vendorProperties = {
transform: transformProperty,
transition: transitionProperty,
transitionDuration: transitionProperty + 'Duration',
transitionProperty: transitionProperty + 'Property',
transitionDelay: transitionProperty + 'Delay'
};
// -------------------------- Item -------------------------- //
function Item(element, layout) {
if (!element) {
return;
}
this.element = element;
// parent layout class, i.e. Masonry, Isotope, or Packery
this.layout = layout;
this.position = {
x: 0,
y: 0
};
this._create();
}
// inherit EvEmitter
var proto = Item.prototype = Object.create(EvEmitter.prototype);
proto.constructor = Item;
proto._create = function () {
// transition objects
this._transn = {
ingProperties: {},
clean: {},
onEnd: {}
};
this.css({
position: 'absolute'
});
};
// trigger specified handler for event type
proto.handleEvent = function (event) {
var method = 'on' + event.type;
if (this[method]) {
this[method](event);
}
};
proto.getSize = function () {
this.size = getSize(this.element);
};
/**
* apply CSS styles to element
* @param {Object} style
*/
proto.css = function (style) {
var elemStyle = this.element.style;
for (var prop in style) {
// use vendor property if available
var supportedProp = vendorProperties[prop] || prop;
elemStyle[supportedProp] = style[prop];
}
};
// measure position, and sets it
proto.getPosition = function () {
var style = getComputedStyle(this.element);
var isOriginLeft = this.layout._getOption('originLeft');
var isOriginTop = this.layout._getOption('originTop');
var xValue = style[isOriginLeft ? 'left' : 'right'];
var yValue = style[isOriginTop ? 'top' : 'bottom'];
var x = parseFloat(xValue);
var y = parseFloat(yValue);
// convert percent to pixels
var layoutSize = this.layout.size;
if (xValue.indexOf('%') != -1) {
x = ( x / 100 ) * layoutSize.width;
}
if (yValue.indexOf('%') != -1) {
y = ( y / 100 ) * layoutSize.height;
}
// clean up 'auto' or other non-integer values
x = isNaN(x) ? 0 : x;
y = isNaN(y) ? 0 : y;
// remove padding from measurement
x -= isOriginLeft ? layoutSize.paddingLeft : layoutSize.paddingRight;
y -= isOriginTop ? layoutSize.paddingTop : layoutSize.paddingBottom;
this.position.x = x;
this.position.y = y;
};
// set settled position, apply padding
proto.layoutPosition = function () {
var layoutSize = this.layout.size;
var style = {};
var isOriginLeft = this.layout._getOption('originLeft');
var isOriginTop = this.layout._getOption('originTop');
// x
var xPadding = isOriginLeft ? 'paddingLeft' : 'paddingRight';
var xProperty = isOriginLeft ? 'left' : 'right';
var xResetProperty = isOriginLeft ? 'right' : 'left';
var x = this.position.x + layoutSize[xPadding];
// set in percentage or pixels
style[xProperty] = this.getXValue(x);
// reset other property
style[xResetProperty] = '';
// y
var yPadding = isOriginTop ? 'paddingTop' : 'paddingBottom';
var yProperty = isOriginTop ? 'top' : 'bottom';
var yResetProperty = isOriginTop ? 'bottom' : 'top';
var y = this.position.y + layoutSize[yPadding];
// set in percentage or pixels
style[yProperty] = this.getYValue(y);
// reset other property
style[yResetProperty] = '';
this.css(style);
this.emitEvent('layout', [this]);
};
proto.getXValue = function (x) {
var isHorizontal = this.layout._getOption('horizontal');
return this.layout.options.percentPosition && !isHorizontal ?
( ( x / this.layout.size.width ) * 100 ) + '%' : x + 'px';
};
proto.getYValue = function (y) {
var isHorizontal = this.layout._getOption('horizontal');
return this.layout.options.percentPosition && isHorizontal ?
( ( y / this.layout.size.height ) * 100 ) + '%' : y + 'px';
};
proto._transitionTo = function (x, y) {
this.getPosition();
// get current x & y from top/left
var curX = this.position.x;
var curY = this.position.y;
var didNotMove = x == this.position.x && y == this.position.y;
// save end position
this.setPosition(x, y);
// if did not move and not transitioning, just go to layout
if (didNotMove && !this.isTransitioning) {
this.layoutPosition();
return;
}
var transX = x - curX;
var transY = y - curY;
var transitionStyle = {};
transitionStyle.transform = this.getTranslate(transX, transY);
this.transition({
to: transitionStyle,
onTransitionEnd: {
transform: this.layoutPosition
},
isCleaning: true
});
};
proto.getTranslate = function (x, y) {
// flip cooridinates if origin on right or bottom
var isOriginLeft = this.layout._getOption('originLeft');
var isOriginTop = this.layout._getOption('originTop');
x = isOriginLeft ? x : -x;
y = isOriginTop ? y : -y;
return 'translate3d(' + x + 'px, ' + y + 'px, 0)';
};
// non transition + transform support
proto.goTo = function (x, y) {
this.setPosition(x, y);
this.layoutPosition();
};
proto.moveTo = proto._transitionTo;
proto.setPosition = function (x, y) {
this.position.x = parseFloat(x);
this.position.y = parseFloat(y);
};
// ----- transition ----- //
/**
* @param {Object} style - CSS
* @param {Function} onTransitionEnd
*/
// non transition, just trigger callback
proto._nonTransition = function (args) {
this.css(args.to);
if (args.isCleaning) {
this._removeStyles(args.to);
}
for (var prop in args.onTransitionEnd) {
args.onTransitionEnd[prop].call(this);
}
};
/**
* proper transition
* @param {Object} args - arguments
* @param {Object} to - style to transition to
* @param {Object} from - style to start transition from
* @param {Boolean} isCleaning - removes transition styles after transition
* @param {Function} onTransitionEnd - callback
*/
proto.transition = function (args) {
// redirect to nonTransition if no transition duration
if (!parseFloat(this.layout.options.transitionDuration)) {
this._nonTransition(args);
return;
}
var _transition = this._transn;
// keep track of onTransitionEnd callback by css property
for (var prop in args.onTransitionEnd) {
_transition.onEnd[prop] = args.onTransitionEnd[prop];
}
// keep track of properties that are transitioning
for (prop in args.to) {
_transition.ingProperties[prop] = true;
// keep track of properties to clean up when transition is done
if (args.isCleaning) {
_transition.clean[prop] = true;
}
}
// set from styles
if (args.from) {
this.css(args.from);
// force redraw. http://blog.alexmaccaw.com/css-transitions
var h = this.element.offsetHeight;
// hack for JSHint to hush about unused var
h = null;
}
// enable transition
this.enableTransition(args.to);
// set styles that are transitioning
this.css(args.to);
this.isTransitioning = true;
};
// dash before all cap letters, including first for
// WebkitTransform => -webkit-transform
function toDashedAll(str) {
return str.replace(/([A-Z])/g, function ($1) {
return '-' + $1.toLowerCase();
});
}
var transitionProps = 'opacity,' + toDashedAll(transformProperty);
proto.enableTransition = function (/* style */) {
// HACK changing transitionProperty during a transition
// will cause transition to jump
if (this.isTransitioning) {
return;
}
// make `transition: foo, bar, baz` from style object
// HACK un-comment this when enableTransition can work
// while a transition is happening
// var transitionValues = [];
// for ( var prop in style ) {
// // dash-ify camelCased properties like WebkitTransition
// prop = vendorProperties[ prop ] || prop;
// transitionValues.push( toDashedAll( prop ) );
// }
// munge number to millisecond, to match stagger
var duration = this.layout.options.transitionDuration;
duration = typeof duration == 'number' ? duration + 'ms' : duration;
// enable transition styles
this.css({
transitionProperty: transitionProps,
transitionDuration: duration,
transitionDelay: this.staggerDelay || 0
});
// listen for transition end event
this.element.addEventListener(transitionEndEvent, this, false);
};
// ----- events ----- //
proto.onwebkitTransitionEnd = function (event) {
this.ontransitionend(event);
};
proto.onotransitionend = function (event) {
this.ontransitionend(event);
};
// properties that I munge to make my life easier
var dashedVendorProperties = {
'-webkit-transform': 'transform'
};
proto.ontransitionend = function (event) {
// disregard bubbled events from children
if (event.target !== this.element) {
return;
}
var _transition = this._transn;
// get property name of transitioned property, convert to prefix-free
var propertyName = dashedVendorProperties[event.propertyName] || event.propertyName;
// remove property that has completed transitioning
delete _transition.ingProperties[propertyName];
// check if any properties are still transitioning
if (isEmptyObj(_transition.ingProperties)) {
// all properties have completed transitioning
this.disableTransition();
}
// clean style
if (propertyName in _transition.clean) {
// clean up style
this.element.style[event.propertyName] = '';
delete _transition.clean[propertyName];
}
// trigger onTransitionEnd callback
if (propertyName in _transition.onEnd) {
var onTransitionEnd = _transition.onEnd[propertyName];
onTransitionEnd.call(this);
delete _transition.onEnd[propertyName];
}
this.emitEvent('transitionEnd', [this]);
};
proto.disableTransition = function () {
this.removeTransitionStyles();
this.element.removeEventListener(transitionEndEvent, this, false);
this.isTransitioning = false;
};
/**
* removes style property from element
* @param {Object} style
**/
proto._removeStyles = function (style) {
// clean up transition styles
var cleanStyle = {};
for (var prop in style) {
cleanStyle[prop] = '';
}
this.css(cleanStyle);
};
var cleanTransitionStyle = {
transitionProperty: '',
transitionDuration: '',
transitionDelay: ''
};
proto.removeTransitionStyles = function () {
// remove transition
this.css(cleanTransitionStyle);
};
// ----- stagger ----- //
proto.stagger = function (delay) {
delay = isNaN(delay) ? 0 : delay;
this.staggerDelay = delay + 'ms';
};
// ----- show/hide/remove ----- //
// remove element from DOM
proto.removeElem = function () {
this.element.parentNode.removeChild(this.element);
// remove display: none
this.css({display: ''});
this.emitEvent('remove', [this]);
};
proto.remove = function () {
// just remove element if no transition support or no transition
if (!transitionProperty || !parseFloat(this.layout.options.transitionDuration)) {
this.removeElem();
return;
}
// start transition
this.once('transitionEnd', function () {
this.removeElem();
});
this.hide();
};
proto.reveal = function () {
delete this.isHidden;
// remove display: none
this.css({display: ''});
var options = this.layout.options;
var onTransitionEnd = {};
var transitionEndProperty = this.getHideRevealTransitionEndProperty('visibleStyle');
onTransitionEnd[transitionEndProperty] = this.onRevealTransitionEnd;
this.transition({
from: options.hiddenStyle,
to: options.visibleStyle,
isCleaning: true,
onTransitionEnd: onTransitionEnd
});
};
proto.onRevealTransitionEnd = function () {
// check if still visible
// during transition, item may have been hidden
if (!this.isHidden) {
this.emitEvent('reveal');
}
};
/**
* get style property use for hide/reveal transition end
* @param {String} styleProperty - hiddenStyle/visibleStyle
* @returns {String}
*/
proto.getHideRevealTransitionEndProperty = function (styleProperty) {
var optionStyle = this.layout.options[styleProperty];
// use opacity
if (optionStyle.opacity) {
return 'opacity';
}
// get first property
for (var prop in optionStyle) {
return prop;
}
};
proto.hide = function () {
// set flag
this.isHidden = true;
// remove display: none
this.css({display: ''});
var options = this.layout.options;
var onTransitionEnd = {};
var transitionEndProperty = this.getHideRevealTransitionEndProperty('hiddenStyle');
onTransitionEnd[transitionEndProperty] = this.onHideTransitionEnd;
this.transition({
from: options.visibleStyle,
to: options.hiddenStyle,
// keep hidden stuff hidden
isCleaning: true,
onTransitionEnd: onTransitionEnd
});
};
proto.onHideTransitionEnd = function () {
// check if still hidden
// during transition, item may have been un-hidden
if (this.isHidden) {
this.css({display: 'none'});
this.emitEvent('hide');
}
};
proto.destroy = function () {
this.css({
position: '',
left: '',
right: '',
top: '',
bottom: '',
transition: '',
transform: ''
});
};
return Item;
}));
© 2015 - 2025 Weber Informatics LLC | Privacy Policy