diff --git a/Source/ASDisplayNode+Layout.mm b/Source/ASDisplayNode+Layout.mm index dd0a2e2adf..bdf3d74a6f 100644 --- a/Source/ASDisplayNode+Layout.mm +++ b/Source/ASDisplayNode+Layout.mm @@ -61,6 +61,10 @@ return [self layoutThatFits:constrainedSize parentSize:constrainedSize.max]; } +- (CGSize)measure:(CGSize)constrainedSize { + return [self layoutThatFits:ASSizeRangeMake(CGSizeZero, constrainedSize)].size; +} + - (ASLayout *)layoutThatFits:(ASSizeRange)constrainedSize parentSize:(CGSize)parentSize { ASDN::MutexLocker l(__instanceLock__); diff --git a/Source/ASDisplayNode+Subclasses.h b/Source/ASDisplayNode+Subclasses.h index ead690f93c..5a47aa787a 100644 --- a/Source/ASDisplayNode+Subclasses.h +++ b/Source/ASDisplayNode+Subclasses.h @@ -186,6 +186,7 @@ NS_ASSUME_NONNULL_BEGIN * @note This method should not be called directly outside of ASDisplayNode; use -layoutThatFits: or -calculatedLayout instead. */ - (ASLayout *)calculateLayoutThatFits:(ASSizeRange)constrainedSize; +- (CGSize)calculateSizeThatFits:(CGSize)contrainedSize; /** * ASDisplayNode's implementation of -layoutThatFits:parentSize: calls this method to resolve the node's size diff --git a/Source/ASDisplayNode.h b/Source/ASDisplayNode.h index b0ea2791b8..7426ec3a8f 100644 --- a/Source/ASDisplayNode.h +++ b/Source/ASDisplayNode.h @@ -793,6 +793,7 @@ extern NSInteger const ASDefaultDrawingPriority; * @see [ASDisplayNode(Subclassing) calculateLayoutThatFits:] */ - (ASLayout *)layoutThatFits:(ASSizeRange)constrainedSize; +- (CGSize)measure:(CGSize)constrainedSize; @end diff --git a/Source/ASDisplayNodeExtras.h b/Source/ASDisplayNodeExtras.h index ba0a38172c..ee58f32aac 100644 --- a/Source/ASDisplayNodeExtras.h +++ b/Source/ASDisplayNodeExtras.h @@ -35,7 +35,13 @@ #endif /// For deallocation of objects on the main thread across multiple run loops. +#ifdef __cplusplus +extern "C" { +#endif extern void ASPerformMainThreadDeallocation(id _Nullable __strong * _Nonnull objectPtr); +#ifdef __cplusplus +} +#endif // Because inline methods can't be extern'd and need to be part of the translation unit of code // that compiles with them to actually inline, we both declare and define these in the header. diff --git a/Source/ASEditableTextNode.h b/Source/ASEditableTextNode.h index 31dbfe7d03..39f864c139 100644 --- a/Source/ASEditableTextNode.h +++ b/Source/ASEditableTextNode.h @@ -139,6 +139,8 @@ NS_ASSUME_NONNULL_BEGIN @property(nonatomic, readwrite, assign) BOOL enablesReturnKeyAutomatically; // default is NO (when YES, will automatically disable return key when text widget has zero-length contents, and will automatically enable when text widget has non-zero-length contents) @property(nonatomic, readwrite, assign, getter=isSecureTextEntry) BOOL secureTextEntry; // default is NO +- (void)dropAutocorrection; + @end @interface ASEditableTextNode (Unavailable) @@ -206,6 +208,7 @@ NS_ASSUME_NONNULL_BEGIN */ - (void)editableTextNodeDidFinishEditing:(ASEditableTextNode *)editableTextNode; +- (BOOL)editableTextNodeShouldPaste:(ASEditableTextNode *)editableTextNode; @end diff --git a/Source/ASEditableTextNode.mm b/Source/ASEditableTextNode.mm index 2e63d6b3b4..2791d35a0b 100644 --- a/Source/ASEditableTextNode.mm +++ b/Source/ASEditableTextNode.mm @@ -80,6 +80,8 @@ BOOL _shouldBlockPanGesture; } +@property (nonatomic, copy) bool (^shouldPaste)(); + @end @implementation ASPanningOverriddenUITextView @@ -103,6 +105,30 @@ [super setContentSize:contentSize]; } +- (BOOL)canPerformAction:(SEL)action withSender:(id)sender +{ + if (action == @selector(paste:)) + return true; + + if (action == @selector(toggleUnderline:)) { + return false; + } + + return [super canPerformAction:action withSender:sender]; +} + +- (id)targetForAction:(SEL)action withSender:(id)__unused sender +{ + return [super targetForAction:action withSender:sender]; +} + +- (void)paste:(id)sender +{ + if (_shouldPaste == nil || _shouldPaste()) { + [super paste:sender]; + } +} + #endif - (BOOL)gestureRecognizerShouldBegin:(UIGestureRecognizer *)gestureRecognizer @@ -120,7 +146,7 @@ @end #pragma mark - -@interface ASEditableTextNode () +@interface ASEditableTextNode () { @private // Configuration. @@ -227,7 +253,18 @@ configureTextView(_placeholderTextKitComponents.textView); // Create and configure our text view. - _textKitComponents.textView = [[ASPanningOverriddenUITextView alloc] initWithFrame:CGRectZero textContainer:_textKitComponents.textContainer]; + ASPanningOverriddenUITextView *textView = [[ASPanningOverriddenUITextView alloc] initWithFrame:CGRectZero textContainer:_textKitComponents.textContainer]; + __weak ASEditableTextNode *weakSelf = self; + textView.shouldPaste = ^bool{ + __strong ASEditableTextNode *strongSelf = weakSelf; + if (strongSelf != nil) { + if ([strongSelf->_delegate respondsToSelector:@selector(editableTextNodeShouldPaste:)]) { + return [strongSelf->_delegate editableTextNodeShouldPaste:self]; + } + } + return true; + }; + _textKitComponents.textView = textView; _textKitComponents.textView.scrollEnabled = _scrollEnabled; _textKitComponents.textView.delegate = self; #if TARGET_OS_IOS @@ -241,6 +278,32 @@ // once view is loaded, setters set directly on view _textInputTraits = nil; + + UITapGestureRecognizer *tapRecognizer = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(tapGesture:)]; + tapRecognizer.cancelsTouchesInView = false; + tapRecognizer.delaysTouchesBegan = false; + tapRecognizer.delaysTouchesEnded = false; + tapRecognizer.delegate = self; + [self.view addGestureRecognizer:tapRecognizer]; +} + +- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldRecognizeSimultaneouslyWithGestureRecognizer:(UIGestureRecognizer *)otherGestureRecognizer { + return true; +} + +- (void)tapGesture:(UITapGestureRecognizer *)recognizer { + static Class promptClass = nil; + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + promptClass = NSClassFromString([[NSString alloc] initWithFormat:@"%@AutocorrectInlinePrompt", @"UI"]); + }); + + if (recognizer.state == UIGestureRecognizerStateEnded) { + UIView *result = [self hitTest:[recognizer locationInView:self.view] withEvent:nil]; + if (result != nil && [result class] == promptClass) { + [self dropAutocorrection]; + } + } } - (CGSize)calculateSizeThatFits:(CGSize)constrainedSize @@ -456,6 +519,15 @@ } } +- (void)dropAutocorrection { + _isPreservingSelection = YES; // Used in -textViewDidChangeSelection: to avoid informing our delegate about our preservation. + + [_textKitComponents.textView.inputDelegate textWillChange:_textKitComponents.textView]; + [_textKitComponents.textView.inputDelegate textDidChange:_textKitComponents.textView]; + + _isPreservingSelection = NO; +} + #pragma mark - Core - (void)_updateDisplayingPlaceholder { diff --git a/Source/ASImageNode+AnimatedImage.mm b/Source/ASImageNode+AnimatedImage.mm index 8443779945..be5cb84ded 100644 --- a/Source/ASImageNode+AnimatedImage.mm +++ b/Source/ASImageNode+AnimatedImage.mm @@ -15,6 +15,8 @@ // http://www.apache.org/licenses/LICENSE-2.0 // +#ifndef MINIMAL_ASDK + #import #import @@ -150,7 +152,6 @@ NSString *const ASAnimatedImageDefaultRunLoopMode = NSRunLoopCommonModes; [(ASNetworkImageNode *)self _locked_setDefaultImage:coverImage]; } else if (_displayLink == nil || _displayLink.paused == YES) { [self _locked_setImage:coverImage]; -#ifndef MINIMAL_ASDK } #endif } @@ -395,3 +396,5 @@ NSString *const ASAnimatedImageDefaultRunLoopMode = NSRunLoopCommonModes; } @end + +#endif diff --git a/Source/ASImageNode.h b/Source/ASImageNode.h index 5d3e09718c..1b0210d15e 100644 --- a/Source/ASImageNode.h +++ b/Source/ASImageNode.h @@ -20,7 +20,9 @@ NS_ASSUME_NONNULL_BEGIN +#ifndef MINIMAL_ASDK @protocol ASAnimatedImageProtocol; +#endif /** * Image modification block. Use to transform an image before display. @@ -143,6 +145,7 @@ typedef UIImage * _Nullable (^asimagenode_modification_block_t)(UIImage *image); @end +#ifndef MINIMAL_ASDK @interface ASImageNode (AnimatedImage) /** @@ -183,6 +186,7 @@ typedef UIImage * _Nullable (^asimagenode_modification_block_t)(UIImage *image); - (void)animatedImageSet:(id )newAnimatedImage previousAnimatedImage:(id )previousAnimatedImage; @end +#endif @interface ASImageNode (Unavailable) diff --git a/Source/ASImageNode.mm b/Source/ASImageNode.mm index b38f5e156b..a93cca7235 100644 --- a/Source/ASImageNode.mm +++ b/Source/ASImageNode.mm @@ -190,7 +190,9 @@ typedef void (^ASImageNodeDrawParametersBlock)(ASWeakMapEntry *entry); _cropRect = CGRectMake(0.5, 0.5, 0, 0); _cropDisplayBounds = CGRectNull; _placeholderColor = ASDisplayNodeDefaultPlaceholderColor(); +#ifndef MINIMAL_ASDK _animatedImageRunLoopMode = ASAnimatedImageDefaultRunLoopMode; +#endif return self; } @@ -198,7 +200,9 @@ typedef void (^ASImageNodeDrawParametersBlock)(ASWeakMapEntry *entry); - (void)dealloc { // Invalidate all components around animated images +#ifndef MINIMAL_ASDK [self invalidateAnimatedImage]; +#endif } #pragma mark - Placeholder diff --git a/Source/Private/ASImageNode+AnimatedImagePrivate.h b/Source/Private/ASImageNode+AnimatedImagePrivate.h index bd2a4d3099..32bd12a0ae 100644 --- a/Source/Private/ASImageNode+AnimatedImagePrivate.h +++ b/Source/Private/ASImageNode+AnimatedImagePrivate.h @@ -21,6 +21,7 @@ extern NSString *const ASAnimatedImageDefaultRunLoopMode; @interface ASImageNode () { +#ifndef MINIMAL_ASDK ASDN::Mutex _displayLinkLock; id _animatedImage; BOOL _animatedImagePaused; @@ -31,21 +32,24 @@ extern NSString *const ASAnimatedImageDefaultRunLoopMode; //accessed on main thread only CFTimeInterval _playHead; NSUInteger _playedLoops; +#endif } @property (nonatomic, assign) CFTimeInterval lastDisplayLinkFire; @end +#ifndef MINIMAL_ASDK @interface ASImageNode (AnimatedImagePrivate) - (void)_locked_setAnimatedImage:(id )animatedImage; @end - @interface ASImageNode (AnimatedImageInvalidation) - (void)invalidateAnimatedImage; @end + +#endif diff --git a/Source/Private/_ASHierarchyChangeSet.h b/Source/Private/_ASHierarchyChangeSet.h index 7eb263d794..19acdd2a71 100644 --- a/Source/Private/_ASHierarchyChangeSet.h +++ b/Source/Private/_ASHierarchyChangeSet.h @@ -15,6 +15,8 @@ // http://www.apache.org/licenses/LICENSE-2.0 // +#ifndef MINIMAL_ASDK + #import #import #import @@ -217,3 +219,5 @@ NSString *NSStringFromASHierarchyChangeType(_ASHierarchyChangeType changeType); @end NS_ASSUME_NONNULL_END + +#endif diff --git a/Source/Private/_ASHierarchyChangeSet.mm b/Source/Private/_ASHierarchyChangeSet.mm index 77ad5d959d..b5a88b071c 100644 --- a/Source/Private/_ASHierarchyChangeSet.mm +++ b/Source/Private/_ASHierarchyChangeSet.mm @@ -15,6 +15,8 @@ // http://www.apache.org/licenses/LICENSE-2.0 // +#ifndef MINIMAL_ASDK + #import #import #import @@ -1007,3 +1009,5 @@ NSString *NSStringFromASHierarchyChangeType(_ASHierarchyChangeType changeType) } @end + +#endif