├── .bowerrc ├── .gitignore ├── bower.json ├── .jshintrc ├── demo ├── flip-with-swipebox │ ├── style.css │ └── index.html ├── index.html └── index2.html ├── LICENSE ├── package.json ├── Gruntfile.js ├── dist ├── jquery.flip.min.js ├── jquery.flip.min.js.map └── jquery.flip.js ├── README.md └── src └── flip.js /.bowerrc: -------------------------------------------------------------------------------- 1 | { 2 | "directory": "bower_components" 3 | } 4 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | /node_modules/ 2 | /bower_components/ 3 | npm-debug.log 4 | -------------------------------------------------------------------------------- /bower.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "flip", 3 | "version": "1.0.11", 4 | "dependencies": {}, 5 | "devDependencies": { 6 | "jquery": "~2.1.1" 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /.jshintrc: -------------------------------------------------------------------------------- 1 | { 2 | "boss": true, 3 | "curly": true, 4 | "eqeqeq": false, 5 | "eqnull": true, 6 | "es3": true, 7 | "expr": true, 8 | "immed": true, 9 | "noarg": true, 10 | "onevar": true, 11 | "quotmark": false, 12 | "trailing": true, 13 | "undef": true, 14 | "unused": true, 15 | "newcap": false, 16 | "browser": true, 17 | "shadow": true, 18 | "devel": true, 19 | 20 | "globals": { 21 | "jQuery": false 22 | } 23 | } -------------------------------------------------------------------------------- /demo/flip-with-swipebox/style.css: -------------------------------------------------------------------------------- 1 | html, body, div, ul { 2 | box-sizing: border-box; 3 | } 4 | 5 | html, body { 6 | margin: 0; 7 | padding: 0; 8 | } 9 | 10 | .card { 11 | width: 320px; 12 | height: 460px; 13 | padding: 30px; 14 | margin: 0 auto; 15 | } 16 | 17 | .card a.thumb { 18 | float: left; 19 | width: 100px; 20 | height: 60px; 21 | margin: 0 5px 10px 0; 22 | } 23 | 24 | .card a.thumb img { 25 | max-width: 100%; 26 | max-height: 100%; 27 | } 28 | 29 | .front, .back { 30 | width: 100%; 31 | height: 80%; 32 | padding: 15px; 33 | background-color: white; 34 | border-radius: 5px; 35 | box-shadow: 0px 1px 6px rgba(0,0,0, 0.4); 36 | } -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2014 Nattawat Nonsung 4 | 2015 Jemar Jones, Nattawat Nonsung and Stijn de Witt 5 | 6 | Permission is hereby granted, free of charge, to any person obtaining a copy of 7 | this software and associated documentation files (the "Software"), to deal in 8 | the Software without restriction, including without limitation the rights to 9 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of 10 | the Software, and to permit persons to whom the Software is furnished to do so, 11 | subject to the following conditions: 12 | 13 | The above copyright notice and this permission notice shall be included in all 14 | copies or substantial portions of the Software. 15 | 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS 18 | FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 19 | COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 20 | IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 21 | CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 22 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "flip", 3 | "version": "1.0.11", 4 | "description": "jQuery Plugin - 3d Flip Content", 5 | "keywords": [ 6 | "jquery-plugin" 7 | ], 8 | "homepage": "https://github.com/nnattawat/flip", 9 | "bugs": "https://github.com/nnattawat/flip/issues", 10 | "author": { 11 | "name": "Nattawat Nonsung", 12 | "email": "armmer1@gmail.com", 13 | "url": "https://github.com/nnattawat" 14 | }, 15 | "contributors": [ 16 | { 17 | "name": "Carlos Fagiani Junior", 18 | "email": "fagianijunior@gmail.com", 19 | "url": "https://github.com/fagianijunior" 20 | }, 21 | { 22 | "name": "Jemar Jones", 23 | "email": "jemarkjones@gmail.com", 24 | "url": "http://JKJones.me/" 25 | }, 26 | { 27 | "name": "Stijn de Witt", 28 | "email": "StijnDeWitt@hotmail.com", 29 | "url": "http://StijnDeWitt.com" 30 | } 31 | ], 32 | "repository": { 33 | "type": "git", 34 | "url": "https://github.com/nnattawat/flip.git" 35 | }, 36 | "licenses": [ 37 | { 38 | "type": "MIT" 39 | } 40 | ], 41 | "devDependencies": { 42 | "grunt-contrib-concat": "~0.3.0", 43 | "grunt-contrib-uglify": "~0.2.7", 44 | "grunt-contrib-watch": "~0.5.3", 45 | "grunt-contrib-clean": "~0.5.0", 46 | "grunt-contrib-connect": "~0.5.0", 47 | "time-grunt": "~0.2.3", 48 | "load-grunt-tasks": "~0.2.0", 49 | "grunt": "~0.4.2", 50 | "grunt-contrib-jshint": "~0.11.2" 51 | }, 52 | "scripts": { 53 | "test": "grunt test" 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /Gruntfile.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | module.exports = function (grunt) { 4 | // Load all grunt tasks 5 | require('load-grunt-tasks')(grunt); 6 | // Show elapsed time at the end 7 | require('time-grunt')(grunt); 8 | 9 | // Project configuration. 10 | grunt.initConfig({ 11 | // Metadata. 12 | pkg: grunt.file.readJSON('package.json'), 13 | banner: '/*! <%= pkg.name %> - v<%= pkg.version %> - ' + 14 | '<%= grunt.template.today("yyyy-mm-dd") %>\n' + 15 | '<%= pkg.homepage ? "* " + pkg.homepage + "\\n" : "" %>' + 16 | '* Copyright (c) <%= grunt.template.today("yyyy") %> <%= pkg.author.name %>;' + 17 | ' Licensed MIT */\n', 18 | // Task configuration. 19 | clean: { 20 | files: ['dist'] 21 | }, 22 | jshint: { 23 | options : { 24 | jshintrc : '.jshintrc' 25 | }, 26 | all: [ 'src/<%= pkg.name %>.js' ] 27 | }, 28 | concat: { 29 | options: { 30 | banner: '<%= banner %>', 31 | stripBanners: true 32 | }, 33 | dist: { 34 | src: ['src/<%= pkg.name %>.js'], 35 | dest: 'dist/jquery.<%= pkg.name %>.js' 36 | } 37 | }, 38 | uglify: { 39 | options: { 40 | sourceMap: 'dist/jquery.<%= pkg.name %>.min.js.map', 41 | sourceMappingURL : 'jquery.<%= pkg.name %>.min.js.map', 42 | banner: '<%= banner %>' 43 | }, 44 | dist: { 45 | src: '<%= concat.dist.src %>', 46 | dest: 'dist/jquery.<%= pkg.name %>.min.js' 47 | } 48 | }, 49 | connect: { 50 | server: { 51 | options: { 52 | hostname: '*', 53 | port: 9000 54 | } 55 | } 56 | } 57 | }); 58 | 59 | // Default task. 60 | grunt.registerTask('default', ['connect', 'clean', 'jshint', 'concat', 'uglify']); 61 | }; 62 | -------------------------------------------------------------------------------- /demo/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 |
4 | 5 | 6 | 7 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 | When a Swipebox is used on 28 | a card animated with Flip, the Swipebox fails, as can be seen in this demo when 29 | we use version 1.0.1 of Flip. If we apply the patch the issue is fixed.
30 |Click on the thumbnails. A Swipebox should open.
31 | 32 |The problem is caused by Flip disabling the bubbling of click 36 | events on any links that are contained inside the element to be flipped, 37 | as can be seen in lines 80-82 of the 38 | source code.
39 |This code was written to prevent the card from flipping when buttons and 40 | links on the card are pressed. However, preventing event bubling is 41 | dangerous.
42 |The better solution is to ignore those events that you are not interested in.
43 |bower install flip55 | 56 | ### Usage 57 | In your web page: 58 | 59 | ```html 60 | 61 |
90 | npm install 91 | bower install 92 |93 | 94 | And run grunt command to create files in /dist folder. 95 |
grunt96 | -------------------------------------------------------------------------------- /src/flip.js: -------------------------------------------------------------------------------- 1 | (function( $ ) { 2 | var flip = function($dom) { 3 | $dom.data("flipped", true); 4 | 5 | var rotateAxis = "rotate" + $dom.data("axis"); 6 | $dom.find($dom.data("front")).css({ 7 | transform: rotateAxis + ($dom.data("reverse") ? "(-180deg)" : "(180deg)"), 8 | "z-index": "0" 9 | }); 10 | 11 | $dom.find($dom.data("back")).css({ 12 | transform: rotateAxis + "(0deg)", 13 | "z-index": "1" 14 | }); 15 | }; 16 | 17 | var unflip = function($dom) { 18 | $dom.data("flipped", false); 19 | 20 | var rotateAxis = "rotate" + $dom.data("axis"); 21 | $dom.find($dom.data("front")).css({ 22 | transform: rotateAxis + "(0deg)", 23 | "z-index": "1" 24 | }); 25 | 26 | $dom.find($dom.data("back")).css({ 27 | transform: rotateAxis + ($dom.data("reverse") ? "(180deg)" : "(-180deg)"), 28 | "z-index": "0" 29 | }); 30 | }; 31 | // Function from David Walsh: http://davidwalsh.name/css-animation-callback licensed with http://opensource.org/licenses/MIT 32 | var whichTransitionEvent = function(){ 33 | var t, 34 | el = document.createElement("fakeelement"), 35 | transitions = { 36 | "transition" : "transitionend", 37 | "OTransition" : "oTransitionEnd", 38 | "MozTransition" : "transitionend", 39 | "WebkitTransition": "webkitTransitionEnd" 40 | }; 41 | 42 | for (t in transitions){ 43 | if (el.style[t] !== undefined){ 44 | return transitions[t]; 45 | } 46 | } 47 | }; 48 | $.fn.flip = function(options, callback) { 49 | if (typeof options == 'function'){ 50 | //This allows flip to be called for setup with only a callback (default settings) 51 | callback = options; 52 | } 53 | this.each(function(){ 54 | var $dom = $(this); 55 | 56 | if (options !== undefined && (typeof(options) == "boolean" || typeof(options) == "string")) { // Force flip the DOM 57 | if (options == "toggle"){ 58 | options = !$dom.data("flipped"); 59 | } 60 | if (options) { 61 | flip($dom); 62 | } else { 63 | unflip($dom); 64 | } 65 | //Providing a nicely wrapped up callback because transform is essentially async 66 | if (callback !== undefined){ 67 | $(this).one(whichTransitionEvent(), callback); 68 | } 69 | } else if (!$dom.data("initiated")){ //Init flipable DOM 70 | $dom.data("initiated", true); 71 | 72 | var settings = $.extend({ 73 | axis: "y", 74 | reverse: false, 75 | trigger: "click", 76 | speed: 500, 77 | forceHeight: false, 78 | forceWidth: false, 79 | autoSize: true, 80 | front: 'auto', 81 | back: 'auto' 82 | }, options ); 83 | 84 | //By defualt we first check for the old front and back selectors for backward compatibility 85 | //if they arent there we fall back to auto selecting the first and second div 86 | if (settings.front == "auto"){ 87 | settings.front = ($dom.find('.front').length > 0)? '.front' : 'div:first-child'; 88 | }else if (settings.front == "autostrict"){ 89 | settings.front = 'div:first-child'; 90 | } 91 | if (settings.back == "auto"){ 92 | //Note, we must use the old 'div:first-child + div' for IE compatibility 93 | settings.back = ($dom.find('.back').length > 0)? '.back' : 'div:first-child + div'; 94 | }else if (settings.back == "autostrict"){ 95 | settings.back = 'div:first-child + div'; 96 | } 97 | // save reverse and axis css to DOM for performing flip 98 | $dom.data("reverse", settings.reverse); 99 | $dom.data("axis", settings.axis); 100 | $dom.data("front", settings.front); 101 | $dom.data("back", settings.back); 102 | 103 | var rotateAxis = "rotate" + (settings.axis.toLowerCase() == "x" ? "x" : "y"), 104 | perspective = $dom["outer" + (rotateAxis == "rotatex" ? "Height" : "Width")]() * 2; 105 | 106 | $dom.find($dom.data("back")).css({ 107 | transform: rotateAxis + "(" + (settings.reverse? "180deg" : "-180deg") + ")" 108 | }); 109 | 110 | $dom.css({ 111 | perspective: perspective, 112 | position: "relative" 113 | }); 114 | 115 | var speedInSec = settings.speed / 1000 || 0.5; 116 | var faces = $dom.find(settings.front).add(settings.back, $dom); 117 | if (settings.forceHeight) {faces.outerHeight($dom.height());} else if (settings.autoSize) {faces.css({'height': '100%'});} 118 | if (settings.forceWidth) {faces.outerWidth($dom.width());} else if (settings.autoSize) {faces.css({'width': '100%'});} 119 | faces.css({ 120 | "backface-visibility": "hidden", 121 | "transform-style": "preserve-3d", 122 | position: "absolute", 123 | "z-index": "1" 124 | }); 125 | $dom.find($dom.data("back")).css({ 126 | transform: rotateAxis + "(" + (settings.reverse? "180deg" : "-180deg") + ")", 127 | "z-index": "0" 128 | }); 129 | // not forcing width/height may cause an initial flip to show up on 130 | // page load when we apply the style to reverse the backface... 131 | // To prevent this we first apply the basic styles and then give the 132 | // browser a moment to apply them. Only afterwards do we add the transition. 133 | setTimeout(function(){ 134 | // By now the browser should have applied the styles, so the transition 135 | // will only affect subsequent flips. 136 | faces.css({ 137 | transition: "all " + speedInSec + "s ease-out" 138 | }); 139 | if (callback !== undefined){ 140 | callback.call(this); 141 | } 142 | //While this used to work with a setTimeout of zero, at some point that became 143 | //unstable and the initial flip returned. The reason for this is unknown but we 144 | //will temporarily use a short delay of 20 to mitigate this issue. 145 | }, 20); 146 | 147 | if (settings.trigger.toLowerCase() == "click") { 148 | $dom.on($.fn.tap ? "tap" : "click", function(event) { 149 | if( !event ) event = window.event; 150 | if ($dom.find($(event.target).closest('button, a, input[type="submit"]')).length) { 151 | return; 152 | } 153 | 154 | if ($dom.data("flipped")) { 155 | unflip($dom); 156 | } else { 157 | flip($dom); 158 | } 159 | }); 160 | } 161 | else if (settings.trigger.toLowerCase() == "hover") { 162 | var performFlip = function() { 163 | $dom.unbind('mouseleave', performUnflip); 164 | 165 | flip($dom); 166 | 167 | setTimeout(function() { 168 | $dom.bind('mouseleave', performUnflip); 169 | if (!$dom.is(":hover")) { 170 | unflip($dom); 171 | } 172 | }, (settings.speed + 150)); 173 | }; 174 | 175 | var performUnflip = function() { 176 | unflip($dom); 177 | }; 178 | 179 | $dom.mouseenter(performFlip); 180 | $dom.mouseleave(performUnflip); 181 | } 182 | }else{ 183 | //The element has been initiated, all we have to do is change applicable settings 184 | if (options.axis !== undefined){ 185 | setAxis.call(this,options.axis,callback); 186 | } 187 | } 188 | }); 189 | 190 | return this; 191 | }; 192 | var setAxis = function(axis,callback){ 193 | if ($(this).data("axis") != axis.toLowerCase()){ 194 | var faces = $(this).find($(this).data("front")).add($(this).data("back"), $(this)); 195 | var savedTrans = faces.css("transition"); 196 | faces.css({ 197 | transition: "none" 198 | }); 199 | //Only setting the axis if it needs to be 200 | 201 | axis = axis.toLowerCase(); 202 | $(this).data("axis", axis); 203 | 204 | //This sets up the first flip in the new direction automatically 205 | var rotateAxis = "rotate" + axis; 206 | if ($(this).data("flipped")){ 207 | $(this).find($(this).data("front")).css({ 208 | transform: rotateAxis + ($(this).data("reverse") ? "(-180deg)" : "(180deg)"), 209 | "z-index": "0" 210 | }); 211 | }else{ 212 | $(this).find($(this).data("back")).css({ 213 | transform: rotateAxis + "(" + ($(this).data("reverse")? "180deg" : "-180deg") + ")", 214 | "z-index": "0" 215 | }); 216 | } 217 | //Providing a nicely wrapped up callback because transform is essentially async 218 | setTimeout(function(){ 219 | faces.css({ 220 | transition: savedTrans 221 | }); 222 | if (callback !== undefined){ 223 | callback.call(this); 224 | } 225 | },0); 226 | }else{ 227 | //If we didnt have to set the axis we can just call back. 228 | if (callback !== undefined){ 229 | setTimeout(callback.bind(this), 0); 230 | } 231 | } 232 | }; 233 | }( jQuery )); -------------------------------------------------------------------------------- /dist/jquery.flip.js: -------------------------------------------------------------------------------- 1 | /*! flip - v1.0.11 - 2015-07-13 2 | * https://github.com/nnattawat/flip 3 | * Copyright (c) 2015 Nattawat Nonsung; Licensed MIT */ 4 | (function( $ ) { 5 | var flip = function($dom) { 6 | $dom.data("flipped", true); 7 | 8 | var rotateAxis = "rotate" + $dom.data("axis"); 9 | $dom.find($dom.data("front")).css({ 10 | transform: rotateAxis + ($dom.data("reverse") ? "(-180deg)" : "(180deg)"), 11 | "z-index": "0" 12 | }); 13 | 14 | $dom.find($dom.data("back")).css({ 15 | transform: rotateAxis + "(0deg)", 16 | "z-index": "1" 17 | }); 18 | }; 19 | 20 | var unflip = function($dom) { 21 | $dom.data("flipped", false); 22 | 23 | var rotateAxis = "rotate" + $dom.data("axis"); 24 | $dom.find($dom.data("front")).css({ 25 | transform: rotateAxis + "(0deg)", 26 | "z-index": "1" 27 | }); 28 | 29 | $dom.find($dom.data("back")).css({ 30 | transform: rotateAxis + ($dom.data("reverse") ? "(180deg)" : "(-180deg)"), 31 | "z-index": "0" 32 | }); 33 | }; 34 | // Function from David Walsh: http://davidwalsh.name/css-animation-callback licensed with http://opensource.org/licenses/MIT 35 | var whichTransitionEvent = function(){ 36 | var t, 37 | el = document.createElement("fakeelement"), 38 | transitions = { 39 | "transition" : "transitionend", 40 | "OTransition" : "oTransitionEnd", 41 | "MozTransition" : "transitionend", 42 | "WebkitTransition": "webkitTransitionEnd" 43 | }; 44 | 45 | for (t in transitions){ 46 | if (el.style[t] !== undefined){ 47 | return transitions[t]; 48 | } 49 | } 50 | }; 51 | $.fn.flip = function(options, callback) { 52 | if (typeof options == 'function'){ 53 | //This allows flip to be called for setup with only a callback (default settings) 54 | callback = options; 55 | } 56 | this.each(function(){ 57 | var $dom = $(this); 58 | 59 | if (options !== undefined && (typeof(options) == "boolean" || typeof(options) == "string")) { // Force flip the DOM 60 | if (options == "toggle"){ 61 | options = !$dom.data("flipped"); 62 | } 63 | if (options) { 64 | flip($dom); 65 | } else { 66 | unflip($dom); 67 | } 68 | //Providing a nicely wrapped up callback because transform is essentially async 69 | if (callback !== undefined){ 70 | $(this).one(whichTransitionEvent(), function(){ 71 | callback.call(this); 72 | }); 73 | } 74 | } else if (!$dom.data("initiated")){ //Init flipable DOM 75 | $dom.data("initiated", true); 76 | 77 | var settings = $.extend({ 78 | axis: "y", 79 | reverse: false, 80 | trigger: "click", 81 | speed: 500, 82 | forceHeight: false, 83 | forceWidth: false, 84 | autoSize: true, 85 | front: 'auto', 86 | back: 'auto' 87 | }, options ); 88 | 89 | //By defualt we first check for the old front and back selectors for backward compatibility 90 | //if they arent there we fall back to auto selecting the first and second div 91 | if (settings.front == "auto"){ 92 | settings.front = ($dom.find('.front').length > 0)? '.front' : 'div:first-child'; 93 | }else if (settings.front == "autostrict"){ 94 | settings.front = 'div:first-child'; 95 | } 96 | if (settings.back == "auto"){ 97 | //Note, we must use the old 'div:first-child + div' for IE compatibility 98 | settings.back = ($dom.find('.back').length > 0)? '.back' : 'div:first-child + div'; 99 | }else if (settings.back == "autostrict"){ 100 | settings.back = 'div:first-child + div'; 101 | } 102 | // save reverse and axis css to DOM for performing flip 103 | $dom.data("reverse", settings.reverse); 104 | $dom.data("axis", settings.axis); 105 | $dom.data("front", settings.front); 106 | $dom.data("back", settings.back); 107 | 108 | var rotateAxis = "rotate" + (settings.axis.toLowerCase() == "x" ? "x" : "y"), 109 | perspective = $dom["outer" + (rotateAxis == "rotatex" ? "Height" : "Width")]() * 2; 110 | 111 | $dom.find($dom.data("back")).css({ 112 | transform: rotateAxis + "(" + (settings.reverse? "180deg" : "-180deg") + ")" 113 | }); 114 | 115 | $dom.css({ 116 | perspective: perspective, 117 | position: "relative" 118 | }); 119 | 120 | var speedInSec = settings.speed / 1000 || 0.5; 121 | var faces = $dom.find(settings.front).add(settings.back, $dom); 122 | if (settings.forceHeight) {faces.outerHeight($dom.height());} else if (settings.autoSize) {faces.css({'height': '100%'});} 123 | if (settings.forceWidth) {faces.outerWidth($dom.width());} else if (settings.autoSize) {faces.css({'width': '100%'});} 124 | faces.css({ 125 | "backface-visibility": "hidden", 126 | "transform-style": "preserve-3d", 127 | position: "absolute", 128 | "z-index": "1" 129 | }); 130 | $dom.find($dom.data("back")).css({ 131 | transform: rotateAxis + "(" + (settings.reverse? "180deg" : "-180deg") + ")", 132 | "z-index": "0" 133 | }); 134 | // not forcing width/height may cause an initial flip to show up on 135 | // page load when we apply the style to reverse the backface... 136 | // To prevent this we first apply the basic styles and then give the 137 | // browser a moment to apply them. Only afterwards do we add the transition. 138 | setTimeout(function(){ 139 | // By now the browser should have applied the styles, so the transition 140 | // will only affect subsequent flips. 141 | faces.css({ 142 | transition: "all " + speedInSec + "s ease-out" 143 | }); 144 | if (callback !== undefined){ 145 | callback.call(this); 146 | } 147 | //While this used to work with a setTimeout of zero, at some point that became 148 | //unstable and the initial flip returned. The reason for this is unknown but we 149 | //will temporarily use a short delay of 20 to mitigate this issue. 150 | }, 20); 151 | 152 | if (settings.trigger.toLowerCase() == "click") { 153 | $dom.on($.fn.tap ? "tap" : "click", function() { 154 | if ($dom.find($(event.target).closest('button, a, input[type="submit"]')).length) { 155 | return; 156 | } 157 | 158 | if ($dom.data("flipped")) { 159 | unflip($dom); 160 | } else { 161 | flip($dom); 162 | } 163 | }); 164 | } 165 | else if (settings.trigger.toLowerCase() == "hover") { 166 | var performFlip = function() { 167 | $dom.unbind('mouseleave', performUnflip); 168 | 169 | flip($dom); 170 | 171 | setTimeout(function() { 172 | $dom.bind('mouseleave', performUnflip); 173 | if (!$dom.is(":hover")) { 174 | unflip($dom); 175 | } 176 | }, (settings.speed + 150)); 177 | }; 178 | 179 | var performUnflip = function() { 180 | unflip($dom); 181 | }; 182 | 183 | $dom.mouseenter(performFlip); 184 | $dom.mouseleave(performUnflip); 185 | } 186 | }else{ 187 | //The element has been initiated, all we have to do is change applicable settings 188 | if (options.axis !== undefined){ 189 | setAxis.call(this,options.axis,callback); 190 | } 191 | } 192 | }); 193 | 194 | return this; 195 | }; 196 | var setAxis = function(axis,callback){ 197 | if ($(this).data("axis") != axis.toLowerCase()){ 198 | var faces = $(this).find($(this).data("front")).add($(this).data("back"), $(this)); 199 | var savedTrans = faces.css("transition"); 200 | faces.css({ 201 | transition: "none" 202 | }); 203 | //Only setting the axis if it needs to be 204 | 205 | axis = axis.toLowerCase(); 206 | $(this).data("axis", axis); 207 | 208 | //This sets up the first flip in the new direction automatically 209 | var rotateAxis = "rotate" + axis; 210 | if ($(this).data("flipped")){ 211 | $(this).find($(this).data("front")).css({ 212 | transform: rotateAxis + ($(this).data("reverse") ? "(-180deg)" : "(180deg)"), 213 | "z-index": "0" 214 | }); 215 | }else{ 216 | $(this).find($(this).data("back")).css({ 217 | transform: rotateAxis + "(" + ($(this).data("reverse")? "180deg" : "-180deg") + ")", 218 | "z-index": "0" 219 | }); 220 | } 221 | //Providing a nicely wrapped up callback because transform is essentially async 222 | setTimeout(function(){ 223 | faces.css({ 224 | transition: savedTrans 225 | }); 226 | if (callback !== undefined){ 227 | callback.call(this); 228 | } 229 | },0); 230 | }else{ 231 | //If we didnt have to set the axis we can just call back. 232 | if (callback !== undefined){ 233 | setTimeout(callback.bind(this), 0); 234 | } 235 | } 236 | }; 237 | }( jQuery )); --------------------------------------------------------------------------------