jquery.animate-enhanced.js 31 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958
  1. /*
  2. jquery.animate-enhanced plugin v1.10
  3. ---
  4. http://github.com/benbarnett/jQuery-Animate-Enhanced
  5. http://benbarnett.net
  6. @benpbarnett
  7. ---
  8. Copyright (c) 2013 Ben Barnett
  9. Permission is hereby granted, free of charge, to any person obtaining a copy
  10. of this software and associated documentation files (the "Software"), to deal
  11. in the Software without restriction, including without limitation the rights
  12. to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  13. copies of the Software, and to permit persons to whom the Software is
  14. furnished to do so, subject to the following conditions:
  15. The above copyright notice and this permission notice shall be included in
  16. all copies or substantial portions of the Software.
  17. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  18. IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  19. FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  20. AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  21. LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  22. OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  23. THE SOFTWARE.
  24. ---
  25. Extends jQuery.animate() to automatically use CSS3 transformations where applicable.
  26. Tested with jQuery 1.3.2+
  27. Supports -moz-transition, -webkit-transition, -o-transition, transition
  28. Targetted properties (for now):
  29. - left
  30. - top
  31. - opacity
  32. - width
  33. - height
  34. Usage (exactly the same as it would be normally):
  35. jQuery(element).animate({left: 200}, 500, function() {
  36. // callback
  37. });
  38. Changelog:
  39. 1.10 (09/04/2014):
  40. - Merging PR #153 Don't try to restore values which weren't saved
  41. 1.09 (09/04/2014):
  42. - Merging PR #154 Added support of AMD and Node.js (via browserify) environments
  43. 1.08 (16/01/2014):
  44. - Merging PR #147 Access element tag name appropriately
  45. 1.07 (06/12/2013):
  46. - Merging PR #139 Other units, beside '%' should also be kept
  47. 1.06 (06/12/2013):
  48. - Merging PR #140 Do not change a user defined display mode for elements, after show/hide
  49. 1.05 (14/08/2013):
  50. - Merging PR #124 fix for highcharts clash. Thanks @bensonc!
  51. 1.04 (14/08/2013):
  52. - Using fix from issue #69 by @rickyk586 to support percentages
  53. 1.03 (19/7/2013):
  54. - Merge PR #129 (Use originalAnimateMethod if a step callback function is provided.) /thx @lehni
  55. 1.02 (8/5/2013):
  56. - Fixing use3D default flags. It must explicitly be set to false to disable 3d now, the plugin by default will use it if available.
  57. 1.01 (8/5/2013):
  58. - Adding appropriate display value for wider range of elements (issue #121 - thanks smacky)
  59. 1.0 (8/5/2103):
  60. - Fix avoidTransforms: true behaviour for directional transitions
  61. 0.99.1 (3/4/2013):
  62. - Add Set or unset the 'disabled by default' value (PR #117)
  63. 0.99 (5/12/2012):
  64. - PR #109 Added support for list-item nodes. FadeIn on tags was omitting the list-style support. (thx @SeanCannon)
  65. 0.98 (12/11/2012):
  66. - Merging pull request #106 thx @gboysko - checking for ownerDocument before using getComputedStyle
  67. 0.97 (6/11/2012):
  68. - Merging pull request #104 thx @gavrochelegnou - .bind instead of .one
  69. 0.96a (20/08/2012):
  70. - Checking event is from dispatch target (issue #58)
  71. 0.96 (20/08/2012):
  72. - Fixes for context, all elements returned as context (issue #84)
  73. - Reset position with leaveTransforms !== true fixes (issue #93)
  74. 0.95 (20/08/2012):
  75. - If target opacity == current opacity, pass back to jquery native to get callback firing (#94)
  76. 0.94 (20/08/2012):
  77. - Addresses Firefox callback mechanisms (issue #94)
  78. - using $.one() to bind to CSS callbacks in a more generic way
  79. 0.93 (6/8/2012):
  80. - Adding other Opera 'transitionend' event (re: issue #90)
  81. 0.92 (6/8/2012):
  82. - Seperate unbinds into different threads (re: issue #91)
  83. 0.91 (2/4/2012):
  84. - Merge Pull Request #74 - Unit Management
  85. 0.90 (7/3/2012):
  86. - Adding public $.toggleDisabledByDefault() feature to disable entire plugin by default (Issue #73)
  87. 0.89 (24/1/2012):
  88. - Adding 'avoidCSSTransitions' property. Set to true to disable entire plugin. (Issue #47)
  89. 0.88 (24/1/2012):
  90. - Fix Issue #67 for HighchartsJS compatibility
  91. 0.87 (24/1/2012):
  92. - Fix Issue #66 selfCSSData.original is undefined
  93. 0.86 (9/1/2012):
  94. - Strict JS fix for undefined variable
  95. 0.85 (20/12/2011):
  96. - Merge Pull request #57 from Kronuz
  97. - Codebase cleaned and now passes jshint.
  98. - Fixed a few bugs (it now saves and restores the original css transition properties).
  99. - fadeOut() is fixed, it wasn't restoring the opacity after hiding it.
  100. 0.80 (13/09/2011):
  101. - Issue #28 - Report $(el).is(':animated') fix
  102. 0.79 (06/09/2011):
  103. - Issue #42 - Right negative position animation: please see issue notes on Github.
  104. 0.78 (02/09/2011):
  105. - Issue #18 - jQuery/$ reference joys
  106. 0.77 (02/09/2011):
  107. - Adding feature on Github issue #44 - Use 3D Transitions by default
  108. 0.76 (28/06/2011):
  109. - Fixing issue #37 - fixed stop() method (with gotoEnd == false)
  110. 0.75 (15/06/2011):
  111. - Fixing issue #35 to pass actual object back as context for callback
  112. 0.74 (28/05/2011):
  113. - Fixing issue #29 to play nice with 1.6+
  114. 0.73 (05/03/2011):
  115. - Merged Pull Request #26: Fixed issue with fadeOut() / "hide" shortcut
  116. 0.72 (05/03/2011):
  117. - Merged Pull Request #23: Added Penner equation approximations from Matthew Lein's Ceaser, and added failsafe fallbacks
  118. 0.71 (05/03/2011):
  119. - Merged Pull Request #24: Changes translation object to integers instead of strings to fix relative values bug with leaveTransforms = true
  120. 0.70 (17/03/2011):
  121. - Merged Pull Request from amlw-nyt to add bottom/right handling
  122. 0.68 (15/02/2011):
  123. - width/height fixes & queue issues resolved.
  124. 0.67 (15/02/2011):
  125. - Code cleanups & file size improvements for compression.
  126. 0.66 (15/02/2011):
  127. - Zero second fadeOut(), fadeIn() fixes
  128. 0.65 (01/02/2011):
  129. - Callbacks with queue() support refactored to support element arrays
  130. 0.64 (27/01/2011):
  131. - BUGFIX #13: .slideUp(), .slideToggle(), .slideDown() bugfixes in Webkit
  132. 0.63 (12/01/2011):
  133. - BUGFIX #11: callbacks not firing when new value == old value
  134. 0.62 (10/01/2011):
  135. - BUGFIX #11: queue is not a function issue fixed
  136. 0.61 (10/01/2011):
  137. - BUGFIX #10: Negative positions converting to positive
  138. 0.60 (06/01/2011):
  139. - Animate function rewrite in accordance with new queue system
  140. - BUGFIX #8: Left/top position values always assumed relative rather than absolute
  141. - BUGFIX #9: animation as last item in a chain - the chain is ignored?
  142. - BUGFIX: width/height CSS3 transformation with left/top working
  143. 0.55 (22/12/2010):
  144. - isEmptyObject function for <jQuery 1.4 (requires 1.3.2)
  145. 0.54a (22/12/2010):
  146. - License changed to MIT (http://www.opensource.org/licenses/mit-license.php)
  147. 0.54 (22/12/2010):
  148. - Removed silly check for 'jQuery UI' bailouts. Sorry.
  149. - Scoping issues fixed - Issue #4: $(this) should give you a reference to the selector being animated.. per jquery's core animation funciton.
  150. 0.53 (17/11/2010):
  151. - New $.translate() method to easily calculate current transformed translation
  152. - Repeater callback bug fix for leaveTransforms:true (was constantly appending properties)
  153. 0.52 (16/11/2010):
  154. - leaveTransforms: true bug fixes
  155. - 'Applying' user callback function to retain 'this' context
  156. 0.51 (08/11/2010):
  157. - Bailing out with jQuery UI. This is only so the plugin plays nice with others and is TEMPORARY.
  158. 0.50 (08/11/2010):
  159. - Support for $.fn.stop()
  160. - Fewer jQuery.fn entries to preserve namespace
  161. - All references $ converted to jQuery
  162. - jsDoc Toolkit style commenting for docs (coming soon)
  163. 0.49 (19/10/2010):
  164. - Handling of 'undefined' errors for secondary CSS objects
  165. - Support to enhance 'width' and 'height' properties (except shortcuts involving jQuery.fx.step, e.g slideToggle)
  166. - Bugfix: Positioning when using avoidTransforms: true (thanks Ralf Santbergen reports)
  167. - Bugfix: Callbacks and Scope issues
  168. 0.48 (13/10/2010):
  169. - Checks for 3d support before applying
  170. 0.47 (12/10/2010);
  171. - Compatible with .fadeIn(), .fadeOut()
  172. - Use shortcuts, no duration for jQuery default or "fast" and "slow"
  173. - Clean up callback event listeners on complete (preventing multiple callbacks)
  174. 0.46 (07/10/2010);
  175. - Compatible with .slideUp(), .slideDown(), .slideToggle()
  176. 0.45 (06/10/2010):
  177. - 'Zero' position bug fix (was originally translating by 0 zero pixels, i.e. no movement)
  178. 0.4 (05/10/2010):
  179. - Iterate over multiple elements and store transforms in jQuery.data per element
  180. - Include support for relative values (+= / -=)
  181. - Better unit sanitization
  182. - Performance tweaks
  183. - Fix for optional callback function (was required)
  184. - Applies data[translateX] and data[translateY] to elements for easy access
  185. - Added 'easeInOutQuint' easing function for CSS transitions (requires jQuery UI for JS anims)
  186. - Less need for leaveTransforms = true due to better position detections
  187. */
  188. (function (window, factory) {
  189. if (typeof define === 'function' && define.amd) {
  190. // AMD. Register as an anonymous module.
  191. define(['jquery'], function(){
  192. return factory.apply(window, arguments);
  193. });
  194. } else if (typeof module === 'object' && module.exports) {
  195. // NodeJS.
  196. module.exports = factory.call(window, require('jquery'));
  197. } else {
  198. // Browser globals
  199. factory.call(window, window.jQuery);
  200. }
  201. }(typeof global === 'object' ? global : this, function (jQuery) {
  202. var originalAnimateMethod = jQuery.fn.animate,
  203. originalStopMethod = jQuery.fn.stop;
  204. // ----------
  205. // Plugin variables
  206. // ----------
  207. var cssTransitionProperties = ['top', 'right', 'bottom', 'left', 'opacity', 'height', 'width'],
  208. directions = ['top', 'right', 'bottom', 'left'],
  209. cssPrefixes = ['-webkit-', '-moz-', '-o-', ''],
  210. pluginOptions = ['avoidTransforms', 'useTranslate3d', 'leaveTransforms'],
  211. rfxnum = /^([+-]=)?([\d+-.]+)(.*)$/,
  212. rupper = /([A-Z])/g,
  213. defaultEnhanceData = {
  214. secondary: {},
  215. meta: {
  216. top : 0,
  217. right : 0,
  218. bottom : 0,
  219. left : 0
  220. }
  221. },
  222. valUnit = 'px',
  223. DATA_KEY = 'jQe',
  224. CUBIC_BEZIER_OPEN = 'cubic-bezier(',
  225. CUBIC_BEZIER_CLOSE = ')',
  226. originalAnimatedFilter = null,
  227. pluginDisabledDefault = false;
  228. // ----------
  229. // Check if this browser supports CSS3 transitions
  230. // ----------
  231. var thisBody = document.body || document.documentElement,
  232. thisStyle = thisBody.style,
  233. transitionEndEvent = 'webkitTransitionEnd oTransitionEnd transitionend',
  234. cssTransitionsSupported = thisStyle.WebkitTransition !== undefined || thisStyle.MozTransition !== undefined || thisStyle.OTransition !== undefined || thisStyle.transition !== undefined,
  235. has3D = ('WebKitCSSMatrix' in window && 'm11' in new WebKitCSSMatrix()),
  236. use3DByDefault = has3D;
  237. // ----------
  238. // Extended :animated filter
  239. // ----------
  240. if ( jQuery.expr && jQuery.expr.filters ) {
  241. originalAnimatedFilter = jQuery.expr.filters.animated;
  242. jQuery.expr.filters.animated = function(elem) {
  243. return jQuery(elem).data('events') && jQuery(elem).data('events')[transitionEndEvent] ? true : originalAnimatedFilter.call(this, elem);
  244. };
  245. }
  246. /**
  247. @private
  248. @name _getUnit
  249. @function
  250. @description Return unit value ("px", "%", "em" for re-use correct one when translating)
  251. @param {variant} [val] Target value
  252. */
  253. function _getUnit(val){
  254. return val.match(/\D+$/);
  255. }
  256. /**
  257. @private
  258. @name _interpretValue
  259. @function
  260. @description Interpret value ("px", "+=" and "-=" sanitisation)
  261. @param {object} [element] The Element for current CSS analysis
  262. @param {variant} [val] Target value
  263. @param {string} [prop] The property we're looking at
  264. @param {boolean} [isTransform] Is this a CSS3 transform?
  265. */
  266. function _interpretValue(e, val, prop, isTransform) {
  267. // this is a nasty fix, but we check for prop == 'd' to see if we're dealing with SVG, and abort
  268. if (prop == "d") return;
  269. if (!_isValidElement(e)) return;
  270. var parts = rfxnum.exec(val),
  271. start = e.css(prop) === 'auto' ? 0 : e.css(prop),
  272. cleanCSSStart = typeof start == 'string' ? _cleanValue(start) : start,
  273. cleanTarget = typeof val == 'string' ? _cleanValue(val) : val,
  274. cleanStart = isTransform === true ? 0 : cleanCSSStart,
  275. hidden = e.is(':hidden'),
  276. translation = e.translation();
  277. if (prop == 'left') cleanStart = parseInt(cleanCSSStart, 10) + translation.x;
  278. if (prop == 'right') cleanStart = parseInt(cleanCSSStart, 10) + translation.x;
  279. if (prop == 'top') cleanStart = parseInt(cleanCSSStart, 10) + translation.y;
  280. if (prop == 'bottom') cleanStart = parseInt(cleanCSSStart, 10) + translation.y;
  281. // deal with shortcuts
  282. if (!parts && val == 'show') {
  283. cleanStart = 1;
  284. if (hidden) {
  285. elem = e[0];
  286. if (elem.style) {
  287. display = elem.style.display;
  288. // Reset the inline display of this element to learn if it is
  289. // being hidden by cascaded rules or not
  290. if (!jQuery._data(elem, 'olddisplay') && display === 'none') {
  291. display = elem.style.display = '';
  292. }
  293. // Set elements which have been overridden with display: none
  294. // in a stylesheet to whatever the default browser style is
  295. // for such an element
  296. if ( display === '' && jQuery.css(elem, 'display') === 'none' ) {
  297. jQuery._data(elem, 'olddisplay', _domElementVisibleDisplayValue(elem.tagName));
  298. }
  299. if (display === '' || display === 'none') {
  300. elem.style.display = jQuery._data(elem, 'olddisplay') || '';
  301. }
  302. }
  303. e.css('opacity', 0);
  304. }
  305. } else if (!parts && val == 'hide') {
  306. cleanStart = 0;
  307. }
  308. if (parts) {
  309. var end = parseFloat(parts[2]);
  310. // If a +=/-= token was provided, we're doing a relative animation
  311. if (parts[1]) end = ((parts[1] === '-=' ? -1 : 1) * end) + parseInt(cleanStart, 10);
  312. // check for unit as per issue #69
  313. if (parts[3] && parts[3] != 'px') end = end + parts[3];
  314. return end;
  315. } else {
  316. return cleanStart;
  317. }
  318. }
  319. /**
  320. @private
  321. @name _getTranslation
  322. @function
  323. @description Make a translate or translate3d string
  324. @param {integer} [x]
  325. @param {integer} [y]
  326. @param {boolean} [use3D] Use translate3d if available?
  327. */
  328. function _getTranslation(x, y, use3D) {
  329. return ((use3D === true || ((use3DByDefault === true && use3D !== false)) && has3D)) ? 'translate3d(' + x + 'px, ' + y + 'px, 0)' : 'translate(' + x + 'px,' + y + 'px)';
  330. }
  331. /**
  332. @private
  333. @name _applyCSSTransition
  334. @function
  335. @description Build up the CSS object
  336. @param {object} [e] Element
  337. @param {string} [property] Property we're dealing with
  338. @param {integer} [duration] Duration
  339. @param {string} [easing] Easing function
  340. @param {variant} [value] String/integer for target value
  341. @param {boolean} [isTransform] Is this a CSS transformation?
  342. @param {boolean} [isTranslatable] Is this a CSS translation?
  343. @param {boolean} [use3D] Use translate3d if available?
  344. */
  345. function _applyCSSTransition(e, property, duration, easing, value, isTransform, isTranslatable, use3D) {
  346. var eCSSData = e.data(DATA_KEY),
  347. enhanceData = eCSSData && !_isEmptyObject(eCSSData) ? eCSSData : jQuery.extend(true, {}, defaultEnhanceData),
  348. offsetPosition = value,
  349. isDirection = jQuery.inArray(property, directions) > -1;
  350. if (isDirection) {
  351. var meta = enhanceData.meta,
  352. cleanPropertyValue = _cleanValue(e.css(property)) || 0,
  353. stashedProperty = property + '_o';
  354. offsetPosition = value - cleanPropertyValue;
  355. meta[property] = offsetPosition;
  356. meta[stashedProperty] = e.css(property) == 'auto' ? 0 + offsetPosition : cleanPropertyValue + offsetPosition || 0;
  357. enhanceData.meta = meta;
  358. // fix 0 issue (transition by 0 = nothing)
  359. if (isTranslatable && offsetPosition === 0) {
  360. offsetPosition = 0 - meta[stashedProperty];
  361. meta[property] = offsetPosition;
  362. meta[stashedProperty] = 0;
  363. }
  364. }
  365. // reapply data and return
  366. return e.data(DATA_KEY, _applyCSSWithPrefix(e, enhanceData, property, duration, easing, offsetPosition, isTransform, isTranslatable, use3D));
  367. }
  368. /**
  369. @private
  370. @name _applyCSSWithPrefix
  371. @function
  372. @description Helper function to build up CSS properties using the various prefixes
  373. @param {object} [cssProperties] Current CSS object to merge with
  374. @param {string} [property]
  375. @param {integer} [duration]
  376. @param {string} [easing]
  377. @param {variant} [value]
  378. @param {boolean} [isTransform] Is this a CSS transformation?
  379. @param {boolean} [isTranslatable] Is this a CSS translation?
  380. @param {boolean} [use3D] Use translate3d if available?
  381. */
  382. function _applyCSSWithPrefix(e, cssProperties, property, duration, easing, value, isTransform, isTranslatable, use3D) {
  383. var saveOriginal = false,
  384. transform = isTransform === true && isTranslatable === true;
  385. cssProperties = cssProperties || {};
  386. if (!cssProperties.original) {
  387. cssProperties.original = {};
  388. saveOriginal = true;
  389. }
  390. cssProperties.properties = cssProperties.properties || {};
  391. cssProperties.secondary = cssProperties.secondary || {};
  392. var meta = cssProperties.meta,
  393. original = cssProperties.original,
  394. properties = cssProperties.properties,
  395. secondary = cssProperties.secondary;
  396. for (var i = cssPrefixes.length - 1; i >= 0; i--) {
  397. var tp = cssPrefixes[i] + 'transition-property',
  398. td = cssPrefixes[i] + 'transition-duration',
  399. tf = cssPrefixes[i] + 'transition-timing-function';
  400. property = (transform ? cssPrefixes[i] + 'transform' : property);
  401. if (saveOriginal) {
  402. original[tp] = e.css(tp) || '';
  403. original[td] = e.css(td) || '';
  404. original[tf] = e.css(tf) || '';
  405. }
  406. secondary[property] = transform ? _getTranslation(meta.left, meta.top, use3D) : value;
  407. properties[tp] = (properties[tp] ? properties[tp] + ',' : '') + property;
  408. properties[td] = (properties[td] ? properties[td] + ',' : '') + duration + 'ms';
  409. properties[tf] = (properties[tf] ? properties[tf] + ',' : '') + easing;
  410. }
  411. return cssProperties;
  412. }
  413. /**
  414. @private
  415. @name _isBoxShortcut
  416. @function
  417. @description Shortcut to detect if we need to step away from slideToggle, CSS accelerated transitions (to come later with fx.step support)
  418. @param {object} [prop]
  419. */
  420. function _isBoxShortcut(prop) {
  421. for (var property in prop) {
  422. if ((property == 'width' || property == 'height') && (prop[property] == 'show' || prop[property] == 'hide' || prop[property] == 'toggle')) {
  423. return true;
  424. }
  425. }
  426. return false;
  427. }
  428. /**
  429. @private
  430. @name _isEmptyObject
  431. @function
  432. @description Check if object is empty (<1.4 compatibility)
  433. @param {object} [obj]
  434. */
  435. function _isEmptyObject(obj) {
  436. for (var i in obj) {
  437. return false;
  438. }
  439. return true;
  440. }
  441. /**
  442. * Fetch most appropriate display value for element types
  443. * @see https://github.com/benbarnett/jQuery-Animate-Enhanced/issues/121
  444. * @private
  445. * @param {[type]} tagName [description]
  446. * @return {[type]} [description]
  447. */
  448. function _domElementVisibleDisplayValue(tagName) {
  449. tagName = tagName.toUpperCase();
  450. var displayValues = {
  451. 'LI' : 'list-item',
  452. 'TR' : 'table-row',
  453. 'TD' : 'table-cell',
  454. 'TH' : 'table-cell',
  455. 'CAPTION' : 'table-caption',
  456. 'COL' : 'table-column',
  457. 'COLGROUP' : 'table-column-group',
  458. 'TFOOT' : 'table-footer-group',
  459. 'THEAD' : 'table-header-group',
  460. 'TBODY' : 'table-row-group'
  461. };
  462. return typeof displayValues[tagName] == 'string' ? displayValues[tagName] : 'block';
  463. }
  464. /**
  465. @private
  466. @name _cleanValue
  467. @function
  468. @description Remove 'px' and other artifacts
  469. @param {variant} [val]
  470. */
  471. function _cleanValue(val) {
  472. return parseFloat(val.replace(_getUnit(val), ''));
  473. }
  474. function _isValidElement(element) {
  475. var allValid=true;
  476. element.each(function(index, el) {
  477. allValid = allValid && el.ownerDocument;
  478. return allValid;
  479. });
  480. return allValid;
  481. }
  482. /**
  483. @private
  484. @name _appropriateProperty
  485. @function
  486. @description Function to check if property should be handled by plugin
  487. @param {string} [prop]
  488. @param {variant} [value]
  489. */
  490. function _appropriateProperty(prop, value, element) {
  491. if (!_isValidElement(element)) {
  492. return false;
  493. }
  494. var is = jQuery.inArray(prop, cssTransitionProperties) > -1;
  495. if ((prop == 'width' || prop == 'height' || prop == 'opacity') && (parseFloat(value) === parseFloat(element.css(prop)))) is = false;
  496. return is;
  497. }
  498. jQuery.extend({
  499. /**
  500. @public
  501. @name toggle3DByDefault
  502. @function
  503. @description Toggle for plugin settings to automatically use translate3d (where available). Usage: $.toggle3DByDefault
  504. */
  505. toggle3DByDefault: function() {
  506. return use3DByDefault = !use3DByDefault;
  507. },
  508. /**
  509. @public
  510. @name toggleDisabledByDefault
  511. @function
  512. @description Toggle the plugin to be disabled by default (can be overridden per animation with avoidCSSTransitions)
  513. */
  514. toggleDisabledByDefault: function() {
  515. return pluginDisabledDefault = !pluginDisabledDefault;
  516. },
  517. /**
  518. @public
  519. @name setDisabledByDefault
  520. @function
  521. @description Set or unset the 'disabled by default' value
  522. */
  523. setDisabledByDefault: function(newValue) {
  524. return pluginDisabledDefault = newValue;
  525. }
  526. });
  527. /**
  528. @public
  529. @name translation
  530. @function
  531. @description Get current X and Y translations
  532. */
  533. jQuery.fn.translation = function() {
  534. if (!this[0]) {
  535. return null;
  536. }
  537. var elem = this[0],
  538. cStyle = window.getComputedStyle(elem, null),
  539. translation = {
  540. x: 0,
  541. y: 0
  542. };
  543. if (cStyle) {
  544. for (var i = cssPrefixes.length - 1; i >= 0; i--) {
  545. var transform = cStyle.getPropertyValue(cssPrefixes[i] + 'transform');
  546. if (transform && (/matrix/i).test(transform)) {
  547. var explodedMatrix = transform.replace(/^matrix\(/i, '').split(/, |\)$/g);
  548. translation = {
  549. x: parseInt(explodedMatrix[4], 10),
  550. y: parseInt(explodedMatrix[5], 10)
  551. };
  552. break;
  553. }
  554. }
  555. }
  556. return translation;
  557. };
  558. /**
  559. @public
  560. @name jQuery.fn.animate
  561. @function
  562. @description The enhanced jQuery.animate function
  563. @param {string} [property]
  564. @param {string} [speed]
  565. @param {string} [easing]
  566. @param {function} [callback]
  567. */
  568. jQuery.fn.animate = function(prop, speed, easing, callback) {
  569. prop = prop || {};
  570. var isTranslatable = !(typeof prop['bottom'] !== 'undefined' || typeof prop['right'] !== 'undefined'),
  571. optall = jQuery.speed(speed, easing, callback),
  572. callbackQueue = 0,
  573. propertyCallback = function() {
  574. callbackQueue--;
  575. if (callbackQueue === 0) {
  576. // we're done, trigger the user callback
  577. if (typeof optall.complete === 'function') {
  578. optall.complete.apply(this, arguments);
  579. }
  580. }
  581. },
  582. bypassPlugin = (typeof prop['avoidCSSTransitions'] !== 'undefined') ? prop['avoidCSSTransitions'] : pluginDisabledDefault;
  583. if (bypassPlugin === true || !cssTransitionsSupported || _isEmptyObject(prop) || _isBoxShortcut(prop) || optall.duration <= 0 || optall.step) {
  584. return originalAnimateMethod.apply(this, arguments);
  585. }
  586. return this[ optall.queue === true ? 'queue' : 'each' ](function() {
  587. var self = jQuery(this),
  588. opt = jQuery.extend({}, optall),
  589. cssCallback = function(e) {
  590. var selfCSSData = self.data(DATA_KEY) || { original: {} },
  591. restore = {};
  592. if (e.eventPhase != 2) // not at dispatching target (thanks @warappa issue #58)
  593. return;
  594. // convert translations to left & top for layout
  595. if (prop.leaveTransforms !== true) {
  596. for (var i = cssPrefixes.length - 1; i >= 0; i--) {
  597. restore[cssPrefixes[i] + 'transform'] = '';
  598. }
  599. if (isTranslatable && typeof selfCSSData.meta !== 'undefined') {
  600. for (var j = 0, dir; (dir = directions[j]); ++j) {
  601. var stashedProperty = selfCSSData.meta[dir + '_o'];
  602. if (stashedProperty) {
  603. restore[dir] = stashedProperty + valUnit;
  604. jQuery(this).css(dir, restore[dir]);
  605. }
  606. }
  607. }
  608. }
  609. // remove transition timing functions
  610. self.
  611. unbind(transitionEndEvent).
  612. css(selfCSSData.original).
  613. css(restore).
  614. data(DATA_KEY, null);
  615. // if we used the fadeOut shortcut make sure elements are display:none
  616. if (prop.opacity === 'hide') {
  617. elem = self[0];
  618. if (elem.style) {
  619. display = jQuery.css(elem, 'display');
  620. if (display !== 'none' && !jQuery._data(elem, 'olddisplay')) {
  621. jQuery._data(elem, 'olddisplay', display);
  622. }
  623. elem.style.display = 'none';
  624. }
  625. self.css('opacity', '');
  626. }
  627. // run the main callback function
  628. propertyCallback.call(this);
  629. },
  630. easings = {
  631. bounce: CUBIC_BEZIER_OPEN + '0.0, 0.35, .5, 1.3' + CUBIC_BEZIER_CLOSE,
  632. linear: 'linear',
  633. swing: 'ease-in-out',
  634. // Penner equation approximations from Matthew Lein's Ceaser: http://matthewlein.com/ceaser/
  635. easeInQuad: CUBIC_BEZIER_OPEN + '0.550, 0.085, 0.680, 0.530' + CUBIC_BEZIER_CLOSE,
  636. easeInCubic: CUBIC_BEZIER_OPEN + '0.550, 0.055, 0.675, 0.190' + CUBIC_BEZIER_CLOSE,
  637. easeInQuart: CUBIC_BEZIER_OPEN + '0.895, 0.030, 0.685, 0.220' + CUBIC_BEZIER_CLOSE,
  638. easeInQuint: CUBIC_BEZIER_OPEN + '0.755, 0.050, 0.855, 0.060' + CUBIC_BEZIER_CLOSE,
  639. easeInSine: CUBIC_BEZIER_OPEN + '0.470, 0.000, 0.745, 0.715' + CUBIC_BEZIER_CLOSE,
  640. easeInExpo: CUBIC_BEZIER_OPEN + '0.950, 0.050, 0.795, 0.035' + CUBIC_BEZIER_CLOSE,
  641. easeInCirc: CUBIC_BEZIER_OPEN + '0.600, 0.040, 0.980, 0.335' + CUBIC_BEZIER_CLOSE,
  642. easeInBack: CUBIC_BEZIER_OPEN + '0.600, -0.280, 0.735, 0.045' + CUBIC_BEZIER_CLOSE,
  643. easeOutQuad: CUBIC_BEZIER_OPEN + '0.250, 0.460, 0.450, 0.940' + CUBIC_BEZIER_CLOSE,
  644. easeOutCubic: CUBIC_BEZIER_OPEN + '0.215, 0.610, 0.355, 1.000' + CUBIC_BEZIER_CLOSE,
  645. easeOutQuart: CUBIC_BEZIER_OPEN + '0.165, 0.840, 0.440, 1.000' + CUBIC_BEZIER_CLOSE,
  646. easeOutQuint: CUBIC_BEZIER_OPEN + '0.230, 1.000, 0.320, 1.000' + CUBIC_BEZIER_CLOSE,
  647. easeOutSine: CUBIC_BEZIER_OPEN + '0.390, 0.575, 0.565, 1.000' + CUBIC_BEZIER_CLOSE,
  648. easeOutExpo: CUBIC_BEZIER_OPEN + '0.190, 1.000, 0.220, 1.000' + CUBIC_BEZIER_CLOSE,
  649. easeOutCirc: CUBIC_BEZIER_OPEN + '0.075, 0.820, 0.165, 1.000' + CUBIC_BEZIER_CLOSE,
  650. easeOutBack: CUBIC_BEZIER_OPEN + '0.175, 0.885, 0.320, 1.275' + CUBIC_BEZIER_CLOSE,
  651. easeInOutQuad: CUBIC_BEZIER_OPEN + '0.455, 0.030, 0.515, 0.955' + CUBIC_BEZIER_CLOSE,
  652. easeInOutCubic: CUBIC_BEZIER_OPEN + '0.645, 0.045, 0.355, 1.000' + CUBIC_BEZIER_CLOSE,
  653. easeInOutQuart: CUBIC_BEZIER_OPEN + '0.770, 0.000, 0.175, 1.000' + CUBIC_BEZIER_CLOSE,
  654. easeInOutQuint: CUBIC_BEZIER_OPEN + '0.860, 0.000, 0.070, 1.000' + CUBIC_BEZIER_CLOSE,
  655. easeInOutSine: CUBIC_BEZIER_OPEN + '0.445, 0.050, 0.550, 0.950' + CUBIC_BEZIER_CLOSE,
  656. easeInOutExpo: CUBIC_BEZIER_OPEN + '1.000, 0.000, 0.000, 1.000' + CUBIC_BEZIER_CLOSE,
  657. easeInOutCirc: CUBIC_BEZIER_OPEN + '0.785, 0.135, 0.150, 0.860' + CUBIC_BEZIER_CLOSE,
  658. easeInOutBack: CUBIC_BEZIER_OPEN + '0.680, -0.550, 0.265, 1.550' + CUBIC_BEZIER_CLOSE
  659. },
  660. domProperties = {},
  661. cssEasing = easings[opt.easing || 'swing'] ? easings[opt.easing || 'swing'] : opt.easing || 'swing';
  662. // seperate out the properties for the relevant animation functions
  663. for (var p in prop) {
  664. if (jQuery.inArray(p, pluginOptions) === -1) {
  665. var isDirection = jQuery.inArray(p, directions) > -1,
  666. cleanVal = _interpretValue(self, prop[p], p, (isDirection && prop.avoidTransforms !== true));
  667. if (/**prop.avoidTransforms !== true && **/_appropriateProperty(p, cleanVal, self)) {
  668. _applyCSSTransition(
  669. self,
  670. p,
  671. opt.duration,
  672. cssEasing,
  673. cleanVal, //isDirection && prop.avoidTransforms === true ? cleanVal + valUnit : cleanVal,
  674. isDirection && prop.avoidTransforms !== true,
  675. isTranslatable,
  676. prop.useTranslate3d);
  677. }
  678. else {
  679. domProperties[p] = prop[p];
  680. }
  681. }
  682. }
  683. self.unbind(transitionEndEvent);
  684. var selfCSSData = self.data(DATA_KEY);
  685. if (selfCSSData && !_isEmptyObject(selfCSSData) && !_isEmptyObject(selfCSSData.secondary)) {
  686. callbackQueue++;
  687. self.css(selfCSSData.properties);
  688. // store in a var to avoid any timing issues, depending on animation duration
  689. var secondary = selfCSSData.secondary;
  690. // has to be done in a timeout to ensure transition properties are set
  691. setTimeout(function() {
  692. self.bind(transitionEndEvent, cssCallback).css(secondary);
  693. });
  694. }
  695. else {
  696. // it won't get fired otherwise
  697. opt.queue = false;
  698. }
  699. // fire up DOM based animations
  700. if (!_isEmptyObject(domProperties)) {
  701. callbackQueue++;
  702. originalAnimateMethod.apply(self, [domProperties, {
  703. duration: opt.duration,
  704. easing: jQuery.easing[opt.easing] ? opt.easing : (jQuery.easing.swing ? 'swing' : 'linear'),
  705. complete: propertyCallback,
  706. queue: opt.queue
  707. }]);
  708. }
  709. // strict JS compliance
  710. return true;
  711. });
  712. };
  713. jQuery.fn.animate.defaults = {};
  714. /**
  715. @public
  716. @name jQuery.fn.stop
  717. @function
  718. @description The enhanced jQuery.stop function (resets transforms to left/top)
  719. @param {boolean} [clearQueue]
  720. @param {boolean} [gotoEnd]
  721. @param {boolean} [leaveTransforms] Leave transforms/translations as they are? Default: false (reset translations to calculated explicit left/top props)
  722. */
  723. jQuery.fn.stop = function(clearQueue, gotoEnd, leaveTransforms) {
  724. if (!cssTransitionsSupported) return originalStopMethod.apply(this, [clearQueue, gotoEnd]);
  725. // clear the queue?
  726. if (clearQueue) this.queue([]);
  727. // route to appropriate stop methods
  728. this.each(function() {
  729. var self = jQuery(this),
  730. selfCSSData = self.data(DATA_KEY);
  731. // is this a CSS transition?
  732. if (selfCSSData && !_isEmptyObject(selfCSSData)) {
  733. var i, restore = {};
  734. if (gotoEnd) {
  735. // grab end state properties
  736. restore = selfCSSData.secondary;
  737. if (!leaveTransforms && typeof selfCSSData.meta['left_o'] !== undefined || typeof selfCSSData.meta['top_o'] !== undefined) {
  738. restore['left'] = typeof selfCSSData.meta['left_o'] !== undefined ? selfCSSData.meta['left_o'] : 'auto';
  739. restore['top'] = typeof selfCSSData.meta['top_o'] !== undefined ? selfCSSData.meta['top_o'] : 'auto';
  740. // remove the transformations
  741. for (i = cssPrefixes.length - 1; i >= 0; i--) {
  742. restore[cssPrefixes[i]+'transform'] = '';
  743. }
  744. }
  745. } else if (!_isEmptyObject(selfCSSData.secondary)) {
  746. var cStyle = window.getComputedStyle(self[0], null);
  747. if (cStyle) {
  748. // grab current properties
  749. for (var prop in selfCSSData.secondary) {
  750. if(selfCSSData.secondary.hasOwnProperty(prop)) {
  751. prop = prop.replace(rupper, '-$1').toLowerCase();
  752. restore[prop] = cStyle.getPropertyValue(prop);
  753. // is this a matrix property? extract left and top and apply
  754. if (!leaveTransforms && (/matrix/i).test(restore[prop])) {
  755. var explodedMatrix = restore[prop].replace(/^matrix\(/i, '').split(/, |\)$/g);
  756. // apply the explicit left/top props
  757. restore['left'] = (parseFloat(explodedMatrix[4]) + parseFloat(self.css('left')) + valUnit) || 'auto';
  758. restore['top'] = (parseFloat(explodedMatrix[5]) + parseFloat(self.css('top')) + valUnit) || 'auto';
  759. // remove the transformations
  760. for (i = cssPrefixes.length - 1; i >= 0; i--) {
  761. restore[cssPrefixes[i]+'transform'] = '';
  762. }
  763. }
  764. }
  765. }
  766. }
  767. }
  768. // Remove transition timing functions
  769. // Moving to seperate thread (re: Animation reverts when finished in Android - issue #91)
  770. self.unbind(transitionEndEvent);
  771. self.
  772. css(selfCSSData.original).
  773. css(restore).
  774. data(DATA_KEY, null);
  775. }
  776. else {
  777. // dom transition
  778. originalStopMethod.apply(self, [clearQueue, gotoEnd]);
  779. }
  780. });
  781. return this;
  782. };
  783. }));