From 0781a4153e087a44d6c27f4fdb6fe772b3d10854 Mon Sep 17 00:00:00 2001 From: Alexander Ljungberg Date: Thu, 13 Dec 2012 14:04:36 +0000 Subject: [PATCH] Fixed: popoverDidShow in Firefox. New: popover animation support in Firefox, Opera and IE10. Before this fix, popoverDidShow: would not be sent to popover delegates when the app ran in Firefox due to Firefox now recognising the -webkit-transition property, but not the webkitTransitionEnd event. Also, before this fix popover animation was only implemented for Webkit based browsers. This fix resolves that issue and in addition adds full support for animated popovers in all browsers that support CSS transitions. The fix also improves Cappuccino's general support for CSS3 animations. --- AppKit/CPCompatibility.j | 87 +++++++++++++++++++++++++++++++++++++- AppKit/_CPAttachedWindow.j | 35 ++++++--------- 2 files changed, 100 insertions(+), 22 deletions(-) diff --git a/AppKit/CPCompatibility.j b/AppKit/CPCompatibility.j index 8dd1686d5..8a0e3c023 100644 --- a/AppKit/CPCompatibility.j +++ b/AppKit/CPCompatibility.j @@ -83,7 +83,8 @@ CPCanvasParentDrawErrorsOnMovementBug = 1 << 0; var USER_AGENT = "", PLATFORM_ENGINE = CPUnknownBrowserEngine, PLATFORM_FEATURES = 0, - PLATFORM_BUGS = 0; + PLATFORM_BUGS = 0, + PLATFORM_STYLE_JS_PROPERTIES = {}; // default these features to true @@ -273,3 +274,87 @@ else CPUndoKeyEquivalentModifierMask = CPControlKeyMask; CPRedoKeyEquivalentModifierMask = CPControlKeyMask; } + +/*! + Return the properly prefixed JS property for the given name. E.g. in a webkit browser, + CPBrowserStyleProperty('transition') -> WebkitTransition + + While technically not a style property, style related event handler names are also supported. + CPBrowserStyleProperty('transitionend') -> 'webkitTransitionEnd' + + CSS is only available in platform(dom), so don't rely too heavily on it. +*/ +function CPBrowserStyleProperty(aProperty) +{ + var lowerProperty = aProperty.toLowerCase(); + + if (PLATFORM_STYLE_JS_PROPERTIES[lowerProperty] === undefined) + { + var r = nil; + +#if PLATFORM(DOM) + var testElement = document.createElement('div'); + + switch (lowerProperty) + { + case 'transitionend': + var candidates = { + 'WebkitTransition' : 'webkitTransitionEnd', + 'MozTransition' : 'transitionend', + 'OTransition' : 'oTransitionEnd', + 'msTransition' : 'MSTransitionEnd', + 'transition' : 'transitionend' + }; + + r = candidates[PLATFORM_STYLE_JS_PROPERTIES['transition']] || nil; + break; + default: + var prefixes = ["Webkit", "Moz", "O", "ms"], + capProperty = [aProperty capitalizedString]; + + for (var i = 0; i < prefixes.length; i++) + { + if (prefixes[i] + capProperty in testElement.style) + { + r = prefixes[i] + capProperty; + break; + } + } + + if (!r && lowerProperty in testElement.style) + r = lowerProperty; + + break; + } +#endif + + PLATFORM_STYLE_JS_PROPERTIES[lowerProperty] = r; + } + + return PLATFORM_STYLE_JS_PROPERTIES[lowerProperty]; +} + +function CPBrowserCSSProperty(aProperty) +{ + var browserProperty = CPBrowserStyleProperty(aProperty); + + if (!browserProperty) + return nil; + + var prefixes = { + 'Webkit': '-webkit-', + 'Moz': '-moz-', + 'O': '-o-', + 'ms': '-ms-' + }; + + for (var prefix in prefixes) + { + if (browserProperty.substring(0, prefix.length) == prefix) + { + return prefixes[prefix] + browserProperty.substring(prefix.length).toLowerCase(); + } + } + + return browserProperty.toLowerCase(); +} diff --git a/AppKit/_CPAttachedWindow.j b/AppKit/_CPAttachedWindow.j index 2ac249dfa..52c0d81f4 100644 --- a/AppKit/_CPAttachedWindow.j +++ b/AppKit/_CPAttachedWindow.j @@ -134,7 +134,7 @@ var _CPAttachedWindow_attachedWindowShouldClose_ = 1 << 0, [self setMovableByWindowBackground:YES]; [self setHasShadow:NO]; - [self setCSS3Property:@"TransitionProperty" value:@"-webkit-transform, opacity"]; + [self setCSS3Property:@"TransitionProperty" value:CPBrowserCSSProperty('transform') + @", opacity"]; [_windowView setNeedsDisplay:YES]; } @@ -350,25 +350,18 @@ var _CPAttachedWindow_attachedWindowShouldClose_ = 1 << 0, } /*! @ignore */ -- (void)setCSS3Property:(CPString)property value:(CPString)value +- (void)setCSS3Property:(CPString)aProperty value:(CPString)value { - _DOMElement.style['webkit' + property] = value; + var browserProperty = CPBrowserStyleProperty(aProperty); - // Support other browsers here eventually + if (browserProperty) + _DOMElement.style[browserProperty] = value; } /*! @ignore */ - (BOOL)browserSupportsAnimation { - return typeof(_DOMElement.style.webkitTransition) !== "undefined"; - - /* - No others browsers supported yet. - - typeof(_DOMElement.style.MozTransition) !== "undefined" || - typeof(_DOMElement.style.MsTransition) !== "undefined" || - typeof(_DOMElement.style.OTransition) !== "undefined"; - */ + return CPBrowserStyleProperty('transition') && CPBrowserStyleProperty('transitionend'); } #pragma mark - @@ -452,28 +445,28 @@ var _CPAttachedWindow_attachedWindowShouldClose_ = 1 << 0, // Set up the pop-out transition [self setCSS3Property:@"Transform" value:@"scale(1.1)"]; - [self setCSS3Property:@"Transition" value:@"-webkit-transform 200ms ease-in"]; + [self setCSS3Property:@"Transition" value:CPBrowserCSSProperty('transform') + @" 200ms ease-in"]; var transitionEndFunction = function() { - _DOMElement.removeEventListener("webkitTransitionEnd", transitionEndFunction, YES); + _DOMElement.removeEventListener(CPBrowserStyleProperty('transitionend'), transitionEndFunction, YES); // Now set up the pop-in to normal size transition. // Because we are watching the -webkit-transform, it will occur now. [self setCSS3Property:@"Transform" value:@"scale(1)"]; - [self setCSS3Property:@"Transition" value:@"-webkit-transform 50ms linear"]; + [self setCSS3Property:@"Transition" value:CPBrowserCSSProperty('transform') + @" 50ms linear"]; var transitionCompleteFunction = function() { - _DOMElement.removeEventListener("webkitTransitionEnd", transitionCompleteFunction, YES); + _DOMElement.removeEventListener(CPBrowserStyleProperty('transitionend'), transitionCompleteFunction, YES); if (_implementedDelegateMethods & _CPAttachedWindow_attachedWindowDidShow_) [_delegate attachedWindowDidShow:self]; } - _DOMElement.addEventListener("webkitTransitionEnd", transitionCompleteFunction, YES); + _DOMElement.addEventListener(CPBrowserStyleProperty('transitionend'), transitionCompleteFunction, YES); }; - _DOMElement.addEventListener("webkitTransitionEnd", transitionEndFunction, YES); + _DOMElement.addEventListener(CPBrowserStyleProperty('transitionend'), transitionEndFunction, YES); }, 0); } else @@ -506,11 +499,11 @@ var _CPAttachedWindow_attachedWindowShouldClose_ = 1 << 0, var transitionEndFunction = function() { - _DOMElement.removeEventListener("webkitTransitionEnd", transitionEndFunction, YES); + _DOMElement.removeEventListener(CPBrowserStyleProperty("transitionend"), transitionEndFunction, YES); [self _close]; }; - _DOMElement.addEventListener("webkitTransitionEnd", transitionEndFunction, YES); + _DOMElement.addEventListener(CPBrowserStyleProperty("transitionend"), transitionEndFunction, YES); } else {