From 9ef95e1f680d3e73dbcda4e62fa27f7e129d89b5 Mon Sep 17 00:00:00 2001 From: cacaodev Date: Fri, 23 Mar 2012 20:20:39 +0100 Subject: [PATCH 1/3] Support for decoding date type in XML 1.0, with test. --- Foundation/CPDate.j | 37 +++++++++++++++++++ Objective-J/CFPropertyList.js | 5 +++ Tests/Objective-J/CFPropertyListTest.j | 10 +++++ Tests/Objective-J/PropertyLists/XMLDate.plist | 8 ++++ 4 files changed, 60 insertions(+) create mode 100644 Tests/Objective-J/PropertyLists/XMLDate.plist diff --git a/Foundation/CPDate.j b/Foundation/CPDate.j index 3d4d12915..2bf756f9c 100644 --- a/Foundation/CPDate.j +++ b/Foundation/CPDate.j @@ -231,4 +231,41 @@ var CPDateTimeKey = @"CPDateTimeKey"; @end +// Based on 'Universal JavaScript Date.parse for ISO 8601' available at https://github.com/csnover/js-iso8601. +var numericKeys = [1, 4, 5, 6, 7, 10, 11]; +Date.parseISO8601 = function (date) +{ + var timestamp, struct, minutesOffset = 0; + + // First, check for native parsing. + timestamp = Date.parse(date); + + if (isNaN(timestamp) && (struct = /^(\d{4}|[+\-]\d{6})(?:-(\d{2})(?:-(\d{2}))?)?(?:T(\d{2}):(\d{2})(?::(\d{2})(?:\.(\d{3}))?)?(?:(Z)|([+\-])(\d{2})(?::(\d{2}))?)?)?$/.exec(date))) + { + // avoid NaN timestamps caused by “undefined” values being passed to Date.UTC + for (var i = 0, k; (k = numericKeys[i]); ++i) + { + struct[k] = +struct[k] || 0; + } + + // allow undefined days and months + struct[2] = (+struct[2] || 1) - 1; + struct[3] = +struct[3] || 1; + + if (struct[8] !== 'Z' && struct[9] !== undefined) + { + minutesOffset = struct[10] * 60 + struct[11]; + + if (struct[9] === '+') + { + minutesOffset = 0 - minutesOffset; + } + } + + return Date.UTC(struct[1], struct[2], struct[3], struct[4], struct[5] + minutesOffset, struct[6], struct[7]); + } + + return timestamp; +}; + Date.prototype.isa = CPDate; diff --git a/Objective-J/CFPropertyList.js b/Objective-J/CFPropertyList.js index cd1bbc3d2..00174387c 100644 --- a/Objective-J/CFPropertyList.js +++ b/Objective-J/CFPropertyList.js @@ -297,6 +297,7 @@ var XML_XML = "xml", PLIST_DICTIONARY = "dict", PLIST_ARRAY = "array", PLIST_STRING = "string", + PLIST_DATE = "date", PLIST_BOOLEAN_TRUE = "true", PLIST_BOOLEAN_FALSE = "false", PLIST_NUMBER_REAL = "real", @@ -596,6 +597,10 @@ CFPropertyList.propertyListFromXML = function(/*String | XMLNode*/ aStringOrXMLN object = decodeHTMLComponent(FIRST_CHILD(XMLNode) ? TEXT_CONTENT(XMLNode) : ""); break; + + case PLIST_DATE: var timestamp = Date.parseISO8601(TEXT_CONTENT(XMLNode)); + object = isNaN(timestamp) ? new Date() : new Date(timestamp); + break; case PLIST_BOOLEAN_TRUE: object = YES; break; diff --git a/Tests/Objective-J/CFPropertyListTest.j b/Tests/Objective-J/CFPropertyListTest.j index 25882ecad..9534a81f2 100644 --- a/Tests/Objective-J/CFPropertyListTest.j +++ b/Tests/Objective-J/CFPropertyListTest.j @@ -14,4 +14,14 @@ var FILE = require("file"), }); } +- (void)testDateDeserialization +{ + var path = FILE.join(FILE.dirname(module.path), "PropertyLists/XMLDate.plist"), + object = CFPropertyList.readPropertyListFromFile(path), + date = [object objectForKey:@"date"]; + + [self assert:[CPDate class] equals:[date class]]; + [self assert:[[CPDate alloc] initWithString:"2012-01-01 10:00:00 +0100"] equals:date]; +} + @end diff --git a/Tests/Objective-J/PropertyLists/XMLDate.plist b/Tests/Objective-J/PropertyLists/XMLDate.plist new file mode 100644 index 000000000..64cb0a85c --- /dev/null +++ b/Tests/Objective-J/PropertyLists/XMLDate.plist @@ -0,0 +1,8 @@ + + + + + date + 2012-01-01T09:00:00Z + + From c321084990cbc5b688f6cde60b45e97acfdf6019 Mon Sep 17 00:00:00 2001 From: Aparajita Fishman Date: Sat, 24 Mar 2012 17:57:13 -0700 Subject: [PATCH 2/3] Whitespace --- Foundation/CPDate.j | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Foundation/CPDate.j b/Foundation/CPDate.j index 2bf756f9c..febad01e9 100644 --- a/Foundation/CPDate.j +++ b/Foundation/CPDate.j @@ -233,10 +233,11 @@ var CPDateTimeKey = @"CPDateTimeKey"; // Based on 'Universal JavaScript Date.parse for ISO 8601' available at https://github.com/csnover/js-iso8601. var numericKeys = [1, 4, 5, 6, 7, 10, 11]; + Date.parseISO8601 = function (date) { var timestamp, struct, minutesOffset = 0; - + // First, check for native parsing. timestamp = Date.parse(date); From 96a038559e7cda2bbcb5957517e4871441ece129 Mon Sep 17 00:00:00 2001 From: Aparajita Fishman Date: Sat, 24 Mar 2012 20:56:31 -0700 Subject: [PATCH 3/3] CPPopover fixes - Removed animationStyle for now. - Made sure that popoverDidClose is not called until animation is finished. - Don't create a new attached window unless: there isn't one; the popover behavior has changed; the current attached window is still visible. - Don't call popoverWillShow if there is not content view controller. - Removed unused _shown instance variable. - Removed redundant !_attachedWindow checks followed by _attachedWindow message that returns a BOOL. - Documentation tweaks. - Fixed up some demo issues. --- AppKit/CPOutlineView.j | 2 +- AppKit/CPPopover.j | 85 +++++------- AppKit/_CPAttachedWindow.j | 176 +++++++++++++------------ Tests/Manual/CPPopover/AppController.j | 48 +++---- Tests/Manual/CPPopover/main.j | 6 + Tools/nib2cib/NSPopover.j | 11 +- 6 files changed, 153 insertions(+), 175 deletions(-) diff --git a/AppKit/CPOutlineView.j b/AppKit/CPOutlineView.j index 2ffbb530b..deee5c52b 100644 --- a/AppKit/CPOutlineView.j +++ b/AppKit/CPOutlineView.j @@ -992,7 +992,7 @@ var CPOutlineViewCoalesceSelectionNotificationStateOff = 0, _disclosureControlData = nil; _disclosureControlQueue = []; - // fIXME: really? + // FIXME: really? [self reloadData]; } diff --git a/AppKit/CPPopover.j b/AppKit/CPPopover.j index ce1a632cb..3629b7603 100644 --- a/AppKit/CPPopover.j +++ b/AppKit/CPPopover.j @@ -35,9 +35,6 @@ CPPopoverBehaviorApplicationDefined = 0; CPPopoverBehaviorTransient = 1; CPPopoverBehaviorSemitransient = 2; -CPPopoverAnimationStyleLion = 0; -CPPopoverAnimationStyleIOS = 1; - var CPPopoverDelegate_popover_willShow_ = 1 << 0, CPPopoverDelegate_popover_didShow_ = 1 << 1, CPPopoverDelegate_popover_shouldClose_ = 1 << 2, @@ -67,13 +64,11 @@ var CPPopoverDelegate_popover_willShow_ = 1 << 0, @outlet id _delegate @accessors(getter=delegate); BOOL _animates @accessors(property=animates); - int _animationStyle; - BOOL _shown @accessors(getter=shown); int _appearance @accessors(property=appearance); int _behavior @accessors(getter=behavior); - BOOL _needsCompute; _CPAttachedWindow _attachedWindow; + BOOL _needsNewAttachedWindow; int _implementedDelegateMethods; } @@ -90,12 +85,10 @@ var CPPopoverDelegate_popover_willShow_ = 1 << 0, { if (self = [super init]) { - _animates = YES; - _animationStyle = CPPopoverAnimationStyleLion; - _appearance = CPPopoverAppearanceMinimal; - _behavior = CPPopoverBehaviorApplicationDefined; - _needsCompute = YES; - _shown = NO; + _animates = YES; + _appearance = CPPopoverAppearanceMinimal; + _behavior = CPPopoverBehaviorApplicationDefined; + _needsNewAttachedWindow = YES; } return self; @@ -112,7 +105,7 @@ var CPPopoverDelegate_popover_willShow_ = 1 << 0, */ - (CGRect)positioningRect { - if (!_attachedWindow || ![_attachedWindow isVisible]) + if (![_attachedWindow isVisible]) return nil; return [_attachedWindow frame]; } @@ -122,7 +115,7 @@ var CPPopoverDelegate_popover_willShow_ = 1 << 0, */ - (void)setPositioningRect:(CGRect)aRect { - if (!_attachedWindow || ![_attachedWindow isVisible]) + if (![_attachedWindow isVisible]) return; [_attachedWindow setFrame:aRect]; } @@ -134,7 +127,7 @@ var CPPopoverDelegate_popover_willShow_ = 1 << 0, */ - (CGSize)contentSize { - if (!_attachedWindow || ![_attachedWindow isVisible]) + if (![_attachedWindow isVisible]) return nil; return [[_contentViewController view] frameSize]; } @@ -156,15 +149,13 @@ var CPPopoverDelegate_popover_willShow_ = 1 << 0, */ - (BOOL)shown { - if (!_attachedWindow) - return NO; return [_attachedWindow isVisible]; } /*! Set the behaviour of the CPPopover. It can be: -- \c CPPopoverBehaviorTransient: the popover will be close if another control outside the popover become the responder +- \c CPPopoverBehaviorTransient: the popover will close if another control outside the popover becomes the responder - \c CPPopoverBehaviorApplicationDefined: (DEFAULT) the application is responsible for closing the popover @param aBehaviour the desired behaviour @@ -175,31 +166,9 @@ Set the behaviour of the CPPopover. It can be: return; _behavior = aBehaviour; - _needsCompute = YES; + _needsNewAttachedWindow = YES; } -/*! - Returns the current animation style. -*/ -- (int)animationStyle -{ - return _animationStyle; -} - -/*! -Set the animation style of the CPPopover. It can be: - -- \c CPPopoverAnimationStyleLion: (DEFAULT) the popover will zoom open and fade out when closing -- \c CPPopoverAnimationStyleIOS: the popover appears instantly when opening and fades out when closing - -@param style the desired animation style -*/ -- (void)setAnimationStyle:(int)style -{ - _animationStyle = style; -} - - - (void)setDelegate:(id)aDelegate { if (_delegate === aDelegate) @@ -236,21 +205,21 @@ Set the animation style of the CPPopover. It can be: */ - (void)showRelativeToRect:(CGRect)positioningRect ofView:(CPView)positioningView preferredEdge:(CPRectEdge)preferredEdge { - if (_implementedDelegateMethods & CPPopoverDelegate_popover_willShow_) - [_delegate popoverWillShow:self]; - if (!_contentViewController) [CPException raise:CPInternalInconsistencyException reason:@"contentViewController must not be nil"]; - if (_needsCompute || !_attachedWindow) + if (_implementedDelegateMethods & CPPopoverDelegate_popover_willShow_) + [_delegate popoverWillShow:self]; + + if (!_attachedWindow || _needsNewAttachedWindow || [_attachedWindow isVisible]) { var styleMask = (_behavior == CPPopoverBehaviorTransient) ? CPClosableOnBlurWindowMask : nil; _attachedWindow = [[_CPAttachedWindow alloc] initWithContentRect:CGRectMakeZero() styleMask:styleMask]; + _needsNewAttachedWindow = NO; } [_attachedWindow setAppearance:_appearance]; [_attachedWindow setAnimates:_animates]; - [_attachedWindow setAnimationStyle:_animationStyle]; [_attachedWindow setDelegate:self]; [_attachedWindow setMovableByWindowBackground:NO]; [_attachedWindow setFrame:[_attachedWindow frameRectForContentRect:[[_contentViewController view] frame]]]; @@ -281,8 +250,8 @@ Set the animation style of the CPPopover. It can be: [_attachedWindow close]; - if (_implementedDelegateMethods & CPPopoverDelegate_popover_didClose_) - [_delegate popoverDidClose:self]; + // popoverDidClose will be sent from attachedWindowDidClose, since + // the attached window will close asynchronously when animating. } @@ -308,14 +277,22 @@ Set the animation style of the CPPopover. It can be: { [self close]; - // we return NO, because we want the CPPopover to compute - // if the attached can be close in order to send delegate messages + // We return NO, because we want the CPPopover to determine + // if the attached window can be closed and to give us a chance + // to send delegate messages. return NO; } +/*! @ignore */ +- (void)attachedWindowDidClose:(_CPAttachedWindow)anAttachedWindow +{ + if (_implementedDelegateMethods & CPPopoverDelegate_popover_didClose_) + [_delegate popoverDidClose:self]; +} + @end -var CPPopoverNeedsComputeKey = @"CPPopoverNeedsComputeKey", +var CPPopoverNeedsNewAttachedWindowKey = @"CPPopoverNeedsNewAttachedWindowKey", CPPopoverAppearanceKey = @"CPPopoverAppearanceKey", CPPopoverAnimatesKey = @"CPPopoverAnimatesKey", CPPopoverContentViewControllerKey = @"CPPopoverContentViewControllerKey", @@ -330,7 +307,7 @@ var CPPopoverNeedsComputeKey = @"CPPopoverNeedsComputeKey", if (self) { - _needsCompute = [aCoder decodeIntForKey:CPPopoverNeedsComputeKey]; + _needsNewAttachedWindow = [aCoder decodeBoolForKey:CPPopoverNeedsNewAttachedWindowKey]; _appearance = [aCoder decodeIntForKey:CPPopoverAppearanceKey]; _animates = [aCoder decodeBoolForKey:CPPopoverAnimatesKey]; _contentViewController = [aCoder decodeObjectForKey:CPPopoverContentViewControllerKey]; @@ -344,9 +321,9 @@ var CPPopoverNeedsComputeKey = @"CPPopoverNeedsComputeKey", { [super encodeWithCoder:aCoder]; - [aCoder encodeBool:_needsCompute forKey:CPPopoverNeedsComputeKey]; + [aCoder encodeBool:_needsNewAttachedWindow forKey:CPPopoverNeedsNewAttachedWindowKey]; [aCoder encodeInt:_appearance forKey:CPPopoverAppearanceKey]; - [aCoder encodeObject:_animates forKey:CPPopoverAnimatesKey]; + [aCoder encodeBool:_animates forKey:CPPopoverAnimatesKey]; [aCoder encodeObject:_contentViewController forKey:CPPopoverContentViewControllerKey]; [aCoder encodeObject:_delegate forKey:CPPopoverDelegateKey]; [aCoder encodeInt:_behavior forKey:CPPopoverBehaviorKey]; diff --git a/AppKit/_CPAttachedWindow.j b/AppKit/_CPAttachedWindow.j index 6919c6dd4..2ed4247b0 100644 --- a/AppKit/_CPAttachedWindow.j +++ b/AppKit/_CPAttachedWindow.j @@ -38,33 +38,32 @@ var _CPAttachedWindow_attachedWindowShouldClose_ = 1 << 0, @ignore This is a simple attached window like the one that pops up - when you double click on a meeting in iCal + when you double click on a meeting in iCal. */ @implementation _CPAttachedWindow : CPWindow { BOOL _animates @accessors(property=animates); - int _animationStyle @accessors(property=animationStyle); id _targetView @accessors(property=targetView); int _appearance @accessors(getter=appearance); BOOL _closeOnBlur; - BOOL _isClosed; + BOOL _isClosing; BOOL _browserAnimates; BOOL _shouldPerformAnimation; CPButton _closeButton; CPInteger _implementedDelegateMethods; } -/*! - override default windowView class loader - - @param aStyleMask the window mask - @return the windowView class -*/ #pragma mark - #pragma mark Class methods +/*! + Overrides the default windowView class loader. + + @param aStyleMask the window mask + @return the windowView class +*/ + (Class)_windowViewClassForStyleMask:(unsigned)aStyleMask { return _CPAttachedWindowView; @@ -75,7 +74,7 @@ var _CPAttachedWindow_attachedWindowShouldClose_ = 1 << 0, #pragma mark Initialization /*! - Create and init a _CPAttachedWindow with given size of and view + Create and init a _CPAttachedWindow with the given size and view. @param aSize the size of the attached window @param aView the target view @@ -87,12 +86,12 @@ var _CPAttachedWindow_attachedWindowShouldClose_ = 1 << 0, } /*! - Create and init a _CPAttachedWindow with given size of and view + Create and init a _CPAttachedWindow with given the size, view and style mask. @param aSize the size of the attached window @param aView the target view - @return ready to use _CPAttachedWindow @param styleMask the window style mask (combine CPClosableWindowMask and CPClosableOnBlurWindowMask) + @return ready to use _CPAttachedWindow */ + (id)attachedWindowWithSize:(CGSize)aSize forView:(CPView)aView styleMask:(int)aMask { @@ -104,7 +103,7 @@ var _CPAttachedWindow_attachedWindowShouldClose_ = 1 << 0, } /*! - Create and init a _CPAttachedWindow with given frame + Create and init a _CPAttachedWindow with given the given frame. @param aFrame the frame of the attached window @return ready to use _CPAttachedWindow @@ -116,7 +115,7 @@ var _CPAttachedWindow_attachedWindowShouldClose_ = 1 << 0, } /*! - Create and init a _CPAttachedWindow with given frame + Create and init a _CPAttachedWindow with the given frame and style mask. @param aFrame the frame of the attached window @param styleMask the window style mask (combine CPClosableWindowMask and CPClosableOnBlurWindowMask) @@ -127,11 +126,10 @@ var _CPAttachedWindow_attachedWindowShouldClose_ = 1 << 0, if (self = [super initWithContentRect:aFrame styleMask:aStyleMask]) { _animates = YES; - _animationStyle = CPPopoverAnimationStyleLion; _closeOnBlur = (aStyleMask & CPClosableOnBlurWindowMask); - _isClosed = NO; + _isClosing = NO; _browserAnimates = [self browserSupportsAnimation]; - _shouldPerformAnimation = _animates; + _shouldPerformAnimation = YES; [self setLevel:CPStatusWindowLevel]; [self setMovableByWindowBackground:YES]; @@ -175,14 +173,13 @@ var _CPAttachedWindow_attachedWindowShouldClose_ = 1 << 0, #pragma mark Observer /*! - Update the _CPAttachedWindow frame if a resize event is observed - + Update the _CPAttachedWindow frame if a resize event is observed. */ - (void)observeValueForKeyPath:(CPString)aPath ofObject:(id)anObject change:(CPDictionary)theChange context:(void)aContext { if ([aPath isEqual:@"frame"]) { - // @TODO: not recompute everything, just compute the move offset + // TODO: don't recompute everything, just compute the move offset var g = [_windowView preferredEdge]; [self positionRelativeToView:_targetView preferredEdge:g]; @@ -216,8 +213,7 @@ var _CPAttachedWindow_attachedWindowShouldClose_ = 1 << 0, origin = [aView frameOrigin], lastView; - // if somebody succeed to use the conversion function of CPView - // to get this working, please do. + // FIXME: make this work with the conversion function of CPView while (currentView = [currentView superview]) { origin.x += [currentView frameOrigin].x; @@ -375,7 +371,8 @@ var _CPAttachedWindow_attachedWindowShouldClose_ = 1 << 0, } /*! - Position the _CPAttachedWindow to a given point + Position the _CPAttachedWindow relative to a given rect, + automatically calculating the edge. @param aPoint the point where the _CPAttachedWindow will be attached */ @@ -385,7 +382,7 @@ var _CPAttachedWindow_attachedWindowShouldClose_ = 1 << 0, } /*! - Position the _CPAttachedWindow to a given point + Position the _CPAttachedWindow relative to a given rect's edge. @param aPoint the point where the _CPAttachedWindow will be attached @param anEdge the prefered edge @@ -442,11 +439,12 @@ var _CPAttachedWindow_attachedWindowShouldClose_ = 1 << 0, #pragma mark Overrides /*! - Called when the window is loowing focus and close the window if CPClosableOnBlurWindowMask is setted + Called when the window is losing focus. + Close the window if CPClosableOnBlurWindowMask is set. */ - (void)resignMainWindow { - if (_closeOnBlur && !_isClosed) + if (_closeOnBlur && !_isClosing) { if (!_delegate || ((_implementedDelegateMethods & _CPAttachedWindow_attachedWindowShouldClose_) && [_delegate attachedWindowShouldClose:self])) @@ -455,7 +453,8 @@ var _CPAttachedWindow_attachedWindowShouldClose_ = 1 << 0, } /*! - Order front the window as usual and add listener for CPWindowDidMoveNotification + When the window appears, show animation if necessary. + Also take this opportunity to keep track of window moves. @param sender the sender of the action */ @@ -465,98 +464,101 @@ var _CPAttachedWindow_attachedWindowShouldClose_ = 1 << 0, if (_animates && _browserAnimates && _shouldPerformAnimation) { - if (_animationStyle === CPPopoverAnimationStyleLion) + var transformOrigin = "50% 100%", + frame = [self frame], + preferredEdge = [_windowView preferredEdge], + posX; + + switch (preferredEdge) { - var transformOrigin = "50% 100%", - frame = [self frame], - preferredEdge = [_windowView preferredEdge], - posX; + case CPMaxYEdge: + case CPMinYEdge: + posX = 50 + (([_windowView arrowOffsetX] * 100) / frame.size.width); + transformOrigin = posX + "% " + (preferredEdge === CPMaxYEdge ? "0%" : "100%"); + break; - switch (preferredEdge) - { - case CPMaxYEdge: - case CPMinYEdge: - posX = 50 + (([_windowView arrowOffsetX] * 100) / frame.size.width); - transformOrigin = posX + "% " + (preferredEdge === CPMaxYEdge ? "0%" : "100%"); - break; - - case CPMinXEdge: - case CPMaxXEdge: - posY = 50 + (([_windowView arrowOffsetY] * 100) / frame.size.height); - transformOrigin = (preferredEdge === CPMaxXEdge ? "0% " : "100% ") + posY + "%"; // 100 50 - break; - } - - // This is the initial transform - [self setCSS3Property:@"Transform" value:@"scale(0)"]; - [self setCSS3Property:@"TransformOrigin" value:transformOrigin]; - [self setCSS3Property:@"TransitionDuration" value:"0"]; - - window.setTimeout(function() - { - if (_animationStyle === CPPopoverAnimationStyleLion) - { - // We are watching opacity, so this triggers the next transition - _DOMElement.style.opacity = 1; - _DOMElement.style.height = frame.size.height + @"px"; - _DOMElement.style.width = frame.size.width + @"px"; - - // Set up the pop-out transition - [self setCSS3Property:@"Transform" value:@"scale(1.1)"]; - [self setCSS3Property:@"TransitionDuration" value:@"200ms"]; - [self setCSS3Property:@"TransitionTimingFunction" value:@"ease-in"]; - - var transitionEndFunction = function() - { - _DOMElement.removeEventListener("webkitTransitionEnd", transitionEndFunction, YES); - - // Now set up the pop-in to normal size transition - [self setCSS3Property:@"Transform" value:@"scale(1)"]; - [self setCSS3Property:@"TransitionDuration" value:@"50ms"]; - [self setCSS3Property:@"TransitionTimingFunction" value:@"linear"]; - }; - - _DOMElement.addEventListener("webkitTransitionEnd", transitionEndFunction, YES); - } - }, 0); + case CPMinXEdge: + case CPMaxXEdge: + posY = 50 + (([_windowView arrowOffsetY] * 100) / frame.size.height); + transformOrigin = (preferredEdge === CPMaxXEdge ? "0% " : "100% ") + posY + "%"; + break; } - else + + // This is the initial transform. We start scaled to zero and watch for opacity changes. + [self setCSS3Property:@"Transform" value:@"scale(0)"]; + [self setCSS3Property:@"TransformOrigin" value:transformOrigin]; + [self setCSS3Property:@"Transition" value:"opacity 0 linear"]; + + window.setTimeout(function() + { + // We are watching opacity, so this triggers the next transition _DOMElement.style.opacity = 1; + _DOMElement.style.height = frame.size.height + @"px"; + _DOMElement.style.width = frame.size.width + @"px"; + + // Set up the pop-out transition + [self setCSS3Property:@"Transform" value:@"scale(1.1)"]; + [self setCSS3Property:@"Transition" value:@"-webkit-transform 200ms ease-in"]; + + var transitionEndFunction = function() + { + _DOMElement.removeEventListener("webkitTransitionEnd", 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"]; + }; + + _DOMElement.addEventListener("webkitTransitionEnd", transitionEndFunction, YES); + }, 0); + } + else + { + [self setCSS3Property:@"Transition" value:@""]; + _DOMElement.style.opacity = 1; } [[CPNotificationCenter defaultCenter] addObserver:self selector:@selector(_attachedWindowDidMove:) name:CPWindowDidMoveNotification object:self]; _shouldPerformAnimation = NO; - _isClosed = NO; + _isClosing = NO; } /*! - Close the window with animation + Animate window closing. */ - (void)close { - // set a close flag to avoid infinite loop - _isClosed = YES; + // set a flag to avoid an infinite loop in resignMainWindow + _isClosing = YES; if (_animates && _browserAnimates) { + // Tell the element to fade out when the opacity changes [self setCSS3Property:@"Transition" value:@"opacity 250ms linear"]; _DOMElement.style.opacity = 0; var transitionEndFunction = function() { - [super close]; _DOMElement.removeEventListener("webkitTransitionEnd", transitionEndFunction, YES); + [self _close]; }; _DOMElement.addEventListener("webkitTransitionEnd", transitionEndFunction, YES); } else - [super close]; + { + [self _close]; + } +} +- (void)_close +{ + [super close]; [_targetView removeObserver:self forKeyPath:@"frame"]; - _shouldPerformAnimation = _animates; + _shouldPerformAnimation = YES; if (_implementedDelegateMethods & _CPAttachedWindow_attachedWindowDidClose_) [_delegate attachedWindowDidClose:self]; diff --git a/Tests/Manual/CPPopover/AppController.j b/Tests/Manual/CPPopover/AppController.j index 47907b48e..b4b894667 100644 --- a/Tests/Manual/CPPopover/AppController.j +++ b/Tests/Manual/CPPopover/AppController.j @@ -106,12 +106,7 @@ [buttonAnimation addItemWithTitle:"No animation"]; [contentView addSubview:buttonAnimation]; - buttonAnimationStyle = [[CPPopUpButton alloc] initWithFrame:CGRectMake(570, 10, 130, 24)]; - [buttonAnimationStyle addItemWithTitle:"Lion"]; - [buttonAnimationStyle addItemWithTitle:"iOS"]; - [contentView addSubview:buttonAnimationStyle]; - - buttonBehaviour = [[CPPopUpButton alloc] initWithFrame:CGRectMake(710, 10, 130, 24)]; + buttonBehaviour = [[CPPopUpButton alloc] initWithFrame:CGRectMake(570, 10, 130, 24)]; [buttonBehaviour addItemWithTitle:"Transient"]; [buttonBehaviour addItemWithTitle:"Not managed"]; [contentView addSubview:buttonBehaviour]; @@ -165,34 +160,32 @@ - (CPPopover)popoverWithAppearance:(int)appearance { - if (popover) + if (!popover || [buttonBehaviour title] === @"Not managed") { - [appearanceLabel setStringValue:[buttonEdge title]]; - return popover; + popover = [CPPopover new]; + + var controller = [[CPViewController alloc] init], + view = [[CPView alloc] initWithFrame:CGRectMake(0.0, 0.0, 320, 300)]; + + appearanceLabel = [CPTextField labelWithTitle:[buttonEdge title]]; + [appearanceLabel setFont:[CPFont boldSystemFontOfSize:30.0]]; + [appearanceLabel setFrameOrigin:CGPointMake(0, 70)]; + [appearanceLabel setValue:CGSizeMake(0.0, 1.0) forThemeAttribute:@"text-shadow-offset"]; + [appearanceLabel setFrameSize:CPSizeMake([view frame].size.width, 50)]; + [appearanceLabel setAlignment:CPCenterTextAlignment]; + [view addSubview:appearanceLabel]; + + [controller setView:view]; + [popover setContentViewController:controller]; + [popover setDelegate:self]; } - popover = [CPPopover new]; - - var controller = [[CPViewController alloc] init], - view = [[CPView alloc] initWithFrame:CGRectMake(0.0, 0.0, 320, 300)]; - - appearanceLabel = [CPTextField labelWithTitle:[buttonEdge title]]; - [appearanceLabel setFont:[CPFont boldSystemFontOfSize:30.0]]; - [appearanceLabel setFrameOrigin:CGPointMake(0, 70)]; - [appearanceLabel setValue:(appearance === CPPopoverAppearanceHUD) ? [CPColor colorWithHexString:@"333"] : [CPColor colorWithHexString:@"fff"] forThemeAttribute:@"text-shadow-color"]; - [appearanceLabel setValue:CGSizeMake(0.0, 1.0) forThemeAttribute:@"text-shadow-offset"]; [appearanceLabel setTextColor:(appearance === CPPopoverAppearanceHUD) ? [CPColor whiteColor] : [CPColor colorWithHexString:@"444"]]; - [appearanceLabel setFrameSize:CPSizeMake([view frame].size.width, 50)]; - [appearanceLabel setAlignment:CPCenterTextAlignment]; - [view addSubview:appearanceLabel]; - - [controller setView:view]; - [popover setContentViewController:controller]; + [appearanceLabel setValue:(appearance === CPPopoverAppearanceHUD) ? [CPColor colorWithHexString:@"333"] : [CPColor colorWithHexString:@"fff"] forThemeAttribute:@"text-shadow-color"]; + [appearanceLabel setStringValue:[buttonEdge title]]; [popover setAnimates:([buttonAnimation title] === @"With animation")]; - [popover setAnimationStyle:[buttonAnimationStyle title] === @"Lion" ? CPPopoverAnimationStyleLion : CPPopoverAnimationStyleIOS]; [popover setBehaviour:([buttonBehaviour title] === @"Transient") ? CPPopoverBehaviorTransient : CPPopoverBehaviorApplicationDefined]; [popover setAppearance:appearance]; - [popover setDelegate:self]; return popover; } @@ -212,6 +205,7 @@ - (void)popoverWillClose:(CPPopover)aPopover { + CPLog.info("popover " + aPopover + " will close"); } diff --git a/Tests/Manual/CPPopover/main.j b/Tests/Manual/CPPopover/main.j index ff9216569..0c961eabd 100644 --- a/Tests/Manual/CPPopover/main.j +++ b/Tests/Manual/CPPopover/main.j @@ -12,7 +12,13 @@ @import "AppController.j" +function formatter(aString, aLevel, aTitle) +{ + return aString; +} + function main(args, namedArgs) { + CPLogRegister(CPLogConsole, null, formatter); CPApplicationMain(args, namedArgs); } diff --git a/Tools/nib2cib/NSPopover.j b/Tools/nib2cib/NSPopover.j index 3a965da27..1622cc88a 100644 --- a/Tools/nib2cib/NSPopover.j +++ b/Tools/nib2cib/NSPopover.j @@ -30,12 +30,11 @@ self = [super NS_initWithCoder:aCoder]; if (self) - { - _needsCompute = YES; - _shown = NO; - _behavior = [aCoder decodeIntForKey:@"NSBehavior"]; - _appearance = [aCoder decodeIntForKey:@"NSAppearance"]; - _animates = [aCoder decodeBoolForKey:@"NSAnimates"]; + { + _needsNewAttachedWindow = YES; + _behavior = [aCoder decodeIntForKey:@"NSBehavior"]; + _appearance = [aCoder decodeIntForKey:@"NSAppearance"]; + _animates = [aCoder decodeBoolForKey:@"NSAnimates"]; } return self;