You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
273 lines
9.8 KiB
273 lines
9.8 KiB
(function( $ ) {
|
|
var flip = function($dom, callback) {
|
|
$dom.data("flipped", true);
|
|
|
|
var rotateAxis = "rotate" + $dom.data("axis");
|
|
$dom.find($dom.data("front")).css({
|
|
transform: rotateAxis + ($dom.data("reverse") ? "(-180deg)" : "(180deg)"),
|
|
"z-index": "0"
|
|
});
|
|
|
|
$dom.find($dom.data("back")).css({
|
|
transform: rotateAxis + "(0deg)",
|
|
"z-index": "1"
|
|
});
|
|
|
|
//Providing a nicely wrapped up callback because transform is essentially async
|
|
$dom.one(whichTransitionEvent(), function(){
|
|
$(this).trigger('flip:done');
|
|
if (callback !== undefined){
|
|
callback.call(this);
|
|
}
|
|
});
|
|
};
|
|
|
|
var unflip = function($dom, callback) {
|
|
$dom.data("flipped", false);
|
|
|
|
var rotateAxis = "rotate" + $dom.data("axis");
|
|
$dom.find($dom.data("front")).css({
|
|
transform: rotateAxis + "(0deg)",
|
|
"z-index": "1"
|
|
});
|
|
|
|
$dom.find($dom.data("back")).css({
|
|
transform: rotateAxis + ($dom.data("reverse") ? "(180deg)" : "(-180deg)"),
|
|
"z-index": "0"
|
|
});
|
|
|
|
//Providing a nicely wrapped up callback because transform is essentially async
|
|
$dom.one(whichTransitionEvent(), function(){
|
|
$(this).trigger('flip:done');
|
|
if (callback !== undefined){
|
|
callback.call(this);
|
|
}
|
|
});
|
|
};
|
|
// Function from David Walsh: http://davidwalsh.name/css-animation-callback licensed with http://opensource.org/licenses/MIT
|
|
var whichTransitionEvent = function(){
|
|
var t,
|
|
el = document.createElement("fakeelement"),
|
|
transitions = {
|
|
"transition" : "transitionend",
|
|
"OTransition" : "oTransitionEnd",
|
|
"MozTransition" : "transitionend",
|
|
"WebkitTransition": "webkitTransitionEnd"
|
|
};
|
|
|
|
for (t in transitions){
|
|
if (el.style[t] !== undefined){
|
|
return transitions[t];
|
|
}
|
|
}
|
|
};
|
|
$.fn.flip = function(options, callback) {
|
|
if (typeof options == 'function'){
|
|
//This allows flip to be called for setup with only a callback (default settings)
|
|
callback = options;
|
|
}
|
|
this.each(function(){
|
|
var $dom = $(this);
|
|
|
|
if (options !== undefined && (typeof(options) == "boolean" || typeof(options) == "string")) { // Force flip the DOM
|
|
if (options == "toggle"){
|
|
options = !$dom.data("flipped");
|
|
}
|
|
if (options) {
|
|
flip($dom,callback);
|
|
} else {
|
|
unflip($dom,callback);
|
|
}
|
|
// //Providing a nicely wrapped up callback because transform is essentially async
|
|
// $(this).one(whichTransitionEvent(), function(){
|
|
// $(this).trigger('flip:done');
|
|
// if (callback !== undefined){
|
|
// callback.call(this);
|
|
// }
|
|
// });
|
|
} else if (!$dom.data("initiated")){ //Init flipable DOM
|
|
$dom.data("initiated", true);
|
|
|
|
var settings = $.extend({
|
|
axis: "y",
|
|
reverse: false,
|
|
trigger: "click",
|
|
speed: 500,
|
|
forceHeight: false,
|
|
forceWidth: false,
|
|
autoSize: true,
|
|
front: 'auto',
|
|
back: 'auto'
|
|
}, options );
|
|
|
|
//By defualt we first check for the old front and back selectors for backward compatibility
|
|
//if they arent there we fall back to auto selecting the first and second div
|
|
if (settings.front == "auto"){
|
|
settings.front = ($dom.find('.front').length > 0)? '.front' : 'div:first-child';
|
|
}else if (settings.front == "autostrict"){
|
|
settings.front = 'div:first-child';
|
|
}
|
|
if (settings.back == "auto"){
|
|
//Note, we must use the old 'div:first-child + div' for IE compatibility
|
|
settings.back = ($dom.find('.back').length > 0)? '.back' : 'div:first-child + div';
|
|
}else if (settings.back == "autostrict"){
|
|
settings.back = 'div:first-child + div';
|
|
}
|
|
// save reverse and axis css to DOM for performing flip
|
|
$dom.data("reverse", settings.reverse);
|
|
$dom.data("axis", settings.axis);
|
|
$dom.data("front", settings.front);
|
|
$dom.data("back", settings.back);
|
|
|
|
var rotateAxis = "rotate" + (settings.axis.toLowerCase() == "x" ? "x" : "y"),
|
|
perspective = $dom["outer" + (rotateAxis == "rotatex" ? "Height" : "Width")]() * 2;
|
|
|
|
$dom.find($dom.data("back")).css({
|
|
transform: rotateAxis + "(" + (settings.reverse? "180deg" : "-180deg") + ")"
|
|
});
|
|
|
|
$dom.css({
|
|
perspective: perspective,
|
|
position: "relative"
|
|
});
|
|
|
|
var speedInSec = settings.speed / 1000 || 0.5;
|
|
var faces = $dom.find(settings.front).add(settings.back, $dom);
|
|
if (settings.forceHeight) {faces.outerHeight($dom.height());} else if (settings.autoSize) {faces.css({'height': '100%'});}
|
|
if (settings.forceWidth) {faces.outerWidth($dom.width());} else if (settings.autoSize) {faces.css({'width': '100%'});}
|
|
faces.css({
|
|
"backface-visibility": "hidden",
|
|
"transform-style": "preserve-3d",
|
|
position: "absolute",
|
|
"z-index": "1"
|
|
});
|
|
faces.find('*').css({
|
|
"backface-visibility": "hidden"
|
|
});
|
|
$dom.find($dom.data("back")).css({
|
|
transform: rotateAxis + "(" + (settings.reverse? "180deg" : "-180deg") + ")",
|
|
"z-index": "0"
|
|
});
|
|
|
|
// Back face always visible on Chrome #39
|
|
if ((window.chrome || (window.Intl && Intl.v8BreakIterator)) && 'CSS' in window){
|
|
//Blink Engine, add preserve-3d to $dom
|
|
$dom.css({"-webkit-transform-style": "preserve-3d"});
|
|
}
|
|
// /#39
|
|
|
|
// not forcing width/height may cause an initial flip to show up on
|
|
// page load when we apply the style to reverse the backface...
|
|
// To prevent this we first apply the basic styles and then give the
|
|
// browser a moment to apply them. Only afterwards do we add the transition.
|
|
setTimeout(function(){
|
|
// By now the browser should have applied the styles, so the transition
|
|
// will only affect subsequent flips.
|
|
faces.css({
|
|
transition: "all " + speedInSec + "s ease-out"
|
|
});
|
|
if (callback !== undefined){
|
|
callback.call(this);
|
|
}
|
|
//While this used to work with a setTimeout of zero, at some point that became
|
|
//unstable and the initial flip returned. The reason for this is unknown but we
|
|
//will temporarily use a short delay of 20 to mitigate this issue.
|
|
}, 20);
|
|
|
|
if (settings.trigger.toLowerCase() == "click") {
|
|
$dom.on($.fn.tap ? "tap" : "click", function(event) {
|
|
if (!event) {event = window.event;}
|
|
if ($dom.find($(event.target).closest('button, a, input[type="submit"]')).length) {
|
|
return;
|
|
}
|
|
|
|
if ($dom.data("flipped")) {
|
|
unflip($dom);
|
|
} else {
|
|
flip($dom);
|
|
}
|
|
});
|
|
}
|
|
else if (settings.trigger.toLowerCase() == "hover") {
|
|
var performFlip = function() {
|
|
$dom.unbind('mouseleave', performUnflip);
|
|
|
|
flip($dom);
|
|
|
|
setTimeout(function() {
|
|
$dom.bind('mouseleave', performUnflip);
|
|
if (!$dom.is(":hover")) {
|
|
unflip($dom);
|
|
}
|
|
}, (settings.speed + 150));
|
|
};
|
|
|
|
var performUnflip = function() {
|
|
unflip($dom);
|
|
};
|
|
|
|
$dom.mouseenter(performFlip);
|
|
$dom.mouseleave(performUnflip);
|
|
}
|
|
}else{
|
|
//The element has been initiated, all we have to do is change applicable settings
|
|
if (options && (options.axis !== undefined || options.reverse !== undefined)){
|
|
changeSettings.call(this,options,function(){
|
|
$dom.trigger('flip:change');
|
|
if (callback !== undefined){
|
|
callback.call(this);
|
|
}
|
|
});
|
|
}
|
|
}
|
|
});
|
|
|
|
return this;
|
|
};
|
|
var changeSettings = function(options,callback){
|
|
var changeNeeded = false;
|
|
if (options.axis !== undefined && $(this).data("axis") != options.axis.toLowerCase()){
|
|
$(this).data("axis", options.axis.toLowerCase());
|
|
changeNeeded = true;
|
|
}
|
|
if (options.reverse !== undefined && $(this).data("reverse") != options.reverse){
|
|
$(this).data("reverse", options.reverse);
|
|
changeNeeded = true;
|
|
}
|
|
if (changeNeeded){
|
|
var faces = $(this).find($(this).data("front")).add($(this).data("back"), $(this));
|
|
var savedTrans = faces.css("transition");
|
|
faces.css({
|
|
transition: "none"
|
|
});
|
|
//Only setting the axis if it needs to be
|
|
|
|
//options.axis = options.axis.toLowerCase();
|
|
//$(this).data("axis", options.axis);
|
|
|
|
//This sets up the first flip in the new direction automatically
|
|
var rotateAxis = "rotate" + $(this).data("axis");
|
|
if ($(this).data("flipped")){
|
|
$(this).find($(this).data("front")).css({
|
|
transform: rotateAxis + ($(this).data("reverse") ? "(-180deg)" : "(180deg)"),
|
|
"z-index": "0"
|
|
});
|
|
}else{
|
|
$(this).find($(this).data("back")).css({
|
|
transform: rotateAxis + "(" + ($(this).data("reverse")? "180deg" : "-180deg") + ")",
|
|
"z-index": "0"
|
|
});
|
|
}
|
|
//Providing a nicely wrapped up callback because transform is essentially async
|
|
setTimeout(function(){
|
|
faces.css({
|
|
transition: savedTrans
|
|
});
|
|
callback.call(this);
|
|
}.bind(this),0);
|
|
}else{
|
|
//If we didnt have to set the axis we can just call back.
|
|
setTimeout(callback.bind(this), 0);
|
|
}
|
|
};
|
|
}( jQuery )); |