diff --git a/AppKit/CPTextView/CPLayoutManager.j b/AppKit/CPTextView/CPLayoutManager.j index 99d403be3..54591368e 100644 --- a/AppKit/CPTextView/CPLayoutManager.j +++ b/AppKit/CPTextView/CPLayoutManager.j @@ -164,7 +164,7 @@ _oncontextmenuhandler = function () { return false; }; if (![self numberOfGlyphs]) return CGRectMake(0, 0, 1, 12); // crude hack to give a cursor in an empty doc. - if (CPMaxRange(aRange) >= [self numberOfGlyphs]) + if (CPMaxRange(aRange) > [self numberOfGlyphs]) aRange = CPMakeRange([self numberOfGlyphs] - 1, 1); var fragments = _objectsInRange(_lineFragments, aRange), @@ -1370,4 +1370,4 @@ var _objectsInRange = function(aList, aRange) "\n\t_attributes="+[_attributes description]; } -@end \ No newline at end of file +@end diff --git a/AppKit/CPTextView/CPTextView.j b/AppKit/CPTextView/CPTextView.j index 7080aa297..e082cb8d7 100644 --- a/AppKit/CPTextView/CPTextView.j +++ b/AppKit/CPTextView/CPTextView.j @@ -153,6 +153,7 @@ var kDelegateRespondsTo_textShouldBeginEditing CPTimer _scrollingTimer; BOOL _scrollingDownward; + CPRange _movingSelection; int _stickyXLocation; @@ -203,7 +204,7 @@ var kDelegateRespondsTo_textShouldBeginEditing _typingAttributes = [[CPDictionary alloc] initWithObjects:[_font, _textColor] forKeys:[CPFontAttributeName, CPForegroundColorAttributeName]]; } - [self registerForDraggedTypes:[CPColorDragType]]; + [self registerForDraggedTypes:[CPColorDragType, CPRTFPboardType]]; return self; } @@ -899,6 +900,28 @@ var kDelegateRespondsTo_textShouldBeginEditing }, 500); } +- (CGPoint)_characterIndexFromRawPoint:(CGPoint)point +{ + var fraction = [], + point = [self convertPoint:point fromView:nil]; + + // convert to container coordinate + point.x -= _textContainerOrigin.x; + point.y -= _textContainerOrigin.y; + + var index = [_layoutManager glyphIndexForPoint:point inTextContainer:_textContainer fractionOfDistanceThroughGlyph:fraction]; + + if (index === CPNotFound) + index = [_layoutManager numberOfCharacters]; + else if (fraction[0] > 0.5) + index++; + + return index; +} +- (CGPoint)_characterIndexFromEvent:(CPEvent)event +{ + return [self _characterIndexFromRawPoint:[event locationInWindow]]; +} #pragma mark - #pragma mark Mouse Events @@ -906,28 +929,53 @@ var kDelegateRespondsTo_textShouldBeginEditing - (void)mouseDown:(CPEvent)event { [_CPNativeInputManager cancelCurrentInputSessionIfNeeded]; - - var fraction = [], - point = [self convertPoint:[event locationInWindow] fromView:nil], - granularities = [CPNotFound, CPSelectByCharacter, CPSelectByWord, CPSelectByParagraph]; - [_caret setVisibility:NO]; - - // convert to container coordinate - point.x -= _textContainerOrigin.x; - point.y -= _textContainerOrigin.y; - - _startTrackingLocation = [_layoutManager glyphIndexForPoint:point inTextContainer:_textContainer fractionOfDistanceThroughGlyph:fraction]; - - if (_startTrackingLocation === CPNotFound) - _startTrackingLocation = [_layoutManager numberOfCharacters]; - else if (fraction[0] > 0.5) - _startTrackingLocation++; - + + _startTrackingLocation = [self _characterIndexFromEvent:event]; + + var granularities = [CPNotFound, CPSelectByCharacter, CPSelectByWord, CPSelectByParagraph]; [self setSelectionGranularity:granularities[[event clickCount]]]; - + + if ([self selectionGranularity] == CPSelectByCharacter && CPLocationInRange(_startTrackingLocation, _selectionRange)) + { + var lineBeginningIndex = [_layoutManager _firstLineFragmentForLineFromLocation:_selectionRange.location]._range.location, + placeholderRange = _MakeRangeFromAbs(lineBeginningIndex, CPMaxRange(_selectionRange)), + placeholderString = [_textStorage attributedSubstringFromRange:placeholderRange], + placeholderFrame = CGRectIntersection([_layoutManager boundingRectForGlyphRange:placeholderRange inTextContainer:_textContainer], _frame), + rangeToHide = CPMakeRange(0, _selectionRange.location - lineBeginningIndex), + dragPlaceholder; + + // hide the left part of the first line of the selection that is not included + [placeholderString addAttribute:CPForegroundColorAttributeName + value:[CPColor colorWithRed:1 green:1 blue:1 alpha:0] + range:rangeToHide]; + + _movingSelection = CPMakeRange(_startTrackingLocation, 0); + + dragPlaceholder = [[CPTextView alloc] initWithFrame:placeholderFrame]; + [dragPlaceholder insertText:placeholderString]; + [dragPlaceholder setBackgroundColor:[CPColor colorWithRed:1 green:1 blue:1 alpha:0]]; + [dragPlaceholder setAlphaValue:0.5]; + + var stringForPasting = [_textStorage attributedSubstringFromRange:CPMakeRangeCopy(_selectionRange)], + richData = [_CPRTFProducer produceRTF:stringForPasting documentAttributes:@{}], + draggingPasteboard = [CPPasteboard pasteboardWithName:CPDragPboard]; + [draggingPasteboard declareTypes:[CPRTFPboardType] owner:nil]; + [draggingPasteboard setString:richData forType:CPRTFPboardType]; + + [self dragView:dragPlaceholder + at:placeholderFrame.origin + offset:nil + event:event + pasteboard:draggingPasteboard + source:self + slideBack:YES]; + + return; + } + var setRange = CPMakeRange(_startTrackingLocation, 0); - + if ([event modifierFlags] & CPShiftKeyMask) setRange = _MakeRangeFromAbs(_startTrackingLocation < _MidRange(_selectionRange) ? CPMaxRange(_selectionRange) : _selectionRange.location, _startTrackingLocation); else @@ -943,22 +991,11 @@ var kDelegateRespondsTo_textShouldBeginEditing - (void)mouseDragged:(CPEvent)event { - var fraction = [], - point = [self convertPoint:[event locationInWindow] fromView:nil]; - - // convert to container coordinate - point.x -= _textContainerOrigin.x; - point.y -= _textContainerOrigin.y; - + if (_movingSelection) + return; + var oldRange = [self selectedRange], - index = [_layoutManager glyphIndexForPoint:point - inTextContainer:_textContainer - fractionOfDistanceThroughGlyph:fraction]; - - if (index === CPNotFound) - index = _scrollingDownward ? CPMaxRange(oldRange) : oldRange.location; - else if (fraction[0] > 0.5) - index++; + index = [self _characterIndexFromEvent:event]; if (index > oldRange.location) _scrollingDownward = YES; @@ -977,7 +1014,9 @@ var kDelegateRespondsTo_textShouldBeginEditing - (void)mouseUp:(CPEvent)event { - /* will post CPTextViewDidChangeSelectionNotification */ + _movingSelection = nil; + + // will post CPTextViewDidChangeSelectionNotification _previousSelectionGranularity = [self selectionGranularity]; [self setSelectionGranularity:CPSelectByCharacter]; [self setSelectedRange:[self selectedRange] affinity:0 stillSelecting:NO]; @@ -1965,6 +2004,15 @@ var kDelegateRespondsTo_textShouldBeginEditing [_caret startBlinking]; } +- (void)draggingUpdated:(CPDraggingInfo)info +{ + var point = [info draggingLocation], + location = [self _characterIndexFromRawPoint:point]; + + _movingSelection = CPMakeRange(location, 0); + [_caret _drawCaretAtLocation:_movingSelection.location]; + [_caret setVisibility:YES]; +} #pragma mark - #pragma mark Dragging operation @@ -1973,11 +2021,33 @@ var kDelegateRespondsTo_textShouldBeginEditing { var location = [self convertPoint:[aSender draggingLocation] fromView:nil], pasteboard = [aSender draggingPasteboard]; + + if ([pasteboard availableTypeFromArray:[CPRTFPboardType]]) + { + [_caret setVisibility:NO]; + + if (CPLocationInRange(_movingSelection.location, _selectionRange)) + { + [self setSelectedRange:_movingSelection]; + _movingSelection = nil; + return; + } - if (![pasteboard availableTypeFromArray:[CPColorDragType]]) - return NO; + if (_movingSelection.location > CPMaxRange(_selectionRange)) + _movingSelection.location -= _selectionRange.length; - [self setTextColor:[CPKeyedUnarchiver unarchiveObjectWithData:[pasteboard dataForType:CPColorDragType]] range:_selectionRange]; + [self _deleteForRange:_selectionRange]; + [self setSelectedRange:_movingSelection]; + + var dataForPasting = [pasteboard stringForType:CPRTFPboardType]; + // setTimeout is to a work around a transaction issue with the undomanager + setTimeout(function(){ + [self insertText:[[_CPRTFParser new] parseRTF:dataForPasting]]; + }, 0); + } + + if ([pasteboard availableTypeFromArray:[CPColorDragType]]) + [self setTextColor:[CPKeyedUnarchiver unarchiveObjectWithData:[pasteboard dataForType:CPColorDragType]] range:_selectionRange]; } @end @@ -2254,6 +2324,12 @@ var CPTextViewAllowsUndoKey = @"CPTextViewAllowsUndoKey", _caretTimer = nil; } } + +- (void)_drawCaretAtLocation:(int)aLoc +{ + var rect = [_textView._layoutManager boundingRectForGlyphRange:CPMakeRange(aLoc, 1) inTextContainer:_textView._textContainer]; + [self setRect:rect]; +} @end @@ -2639,6 +2715,7 @@ var _CPCopyPlaceholder = '-'; -(void) _setRegularExpression:(JSObject)re toFontTrait:(CPFontTrait)aTrait { + var match; while (match = re.exec(_string)) { var attribs = [[self attributesAtIndex:match.index effectiveRange:nil] copy], @@ -2650,6 +2727,7 @@ var _CPCopyPlaceholder = '-'; -(void) _replaceEveryOccurenceOfRegularExpression:(JSObject)re withString:(CPString)aString { + var match; while (match = re.exec(_string)) [self replaceCharactersInRange:CPMakeRange(match.index, match[0].length) withString:aString]; } @@ -2663,6 +2741,7 @@ var _CPCopyPlaceholder = '-'; [self _replaceEveryOccurenceOfRegularExpression:/</i withString:'<']; [self _replaceEveryOccurenceOfRegularExpression:/>/i withString:'>']; [self _replaceEveryOccurenceOfRegularExpression:/&/i withString:'&']; + [self _replaceEveryOccurenceOfRegularExpression:/ /i withString:' ']; return self; } diff --git a/AppKit/CPTextView/_CPRTFParser.j b/AppKit/CPTextView/_CPRTFParser.j index a94081c8d..f1f94db99 100644 --- a/AppKit/CPTextView/_CPRTFParser.j +++ b/AppKit/CPTextView/_CPRTFParser.j @@ -514,6 +514,9 @@ var kRgsymRtf = { return [self _applyPropChange:sym parameter:param]; case kRTFParserType_char: + if((param + '') !== 'NaN' && (param + '').length) + _currentParseIndex -= (param + '').length; + return [self _checkChar:sym parameter:param]; case kRTFParserType_dest: @@ -785,4 +788,4 @@ var kRgsymRtf = { return _result; } -@end \ No newline at end of file +@end diff --git a/AppKit/CPView.j b/AppKit/CPView.j index cadcdf356..33d1bac60 100644 --- a/AppKit/CPView.j +++ b/AppKit/CPView.j @@ -416,7 +416,7 @@ var CPViewHighDPIDrawingEnabled = YES; */ - (void)setToolTip:(CPString)aToolTip { - if (_toolTip == aToolTip) + if (_toolTip === aToolTip) return; if (aToolTip && ![aToolTip isKindOfClass:CPString]) @@ -574,7 +574,7 @@ var CPViewHighDPIDrawingEnabled = YES; [[self window] _dirtyKeyViewLoop]; // If this is already one of our subviews, remove it. - if (aSubview._superview == self) + if (aSubview._superview === self) { var index = [_subviews indexOfObjectIdenticalTo:aSubview]; @@ -863,7 +863,7 @@ var CPViewHighDPIDrawingEnabled = YES; do { - if (view == aView) + if (view === aView) return YES; } while(view = [view superview]) @@ -978,7 +978,7 @@ var CPViewHighDPIDrawingEnabled = YES; - (CPView)viewWithTag:(CPInteger)aTag { - if ([self tag] == aTag) + if ([self tag] === aTag) return self; var index = 0, @@ -1030,7 +1030,7 @@ var CPViewHighDPIDrawingEnabled = YES; [[self superview] viewFrameChanged:[[CPNotification alloc] initWithName:CPViewFrameDidChangeNotification object:self userInfo:nil]]; if (!_inhibitUpdateTrackingAreas) - [self _updateTrackingAreas]; + [self _updateTrackingAreasWithRecursion:YES]; } /*! @@ -1103,7 +1103,7 @@ var CPViewHighDPIDrawingEnabled = YES; #endif if (!_inhibitUpdateTrackingAreas && !_inhibitFrameAndBoundsChangedNotifications) - [self _updateTrackingAreas]; + [self _updateTrackingAreasWithRecursion:YES]; } /*! @@ -1257,7 +1257,7 @@ var CPViewHighDPIDrawingEnabled = YES; [[self superview] viewFrameChanged:[[CPNotification alloc] initWithName:CPViewFrameDidChangeNotification object:self userInfo:nil]]; if (!_inhibitUpdateTrackingAreas && !_inhibitFrameAndBoundsChangedNotifications) - [self _updateTrackingAreas]; + [self _updateTrackingAreasWithRecursion:!_autoresizesSubviews]; } /*! @@ -1306,7 +1306,7 @@ var CPViewHighDPIDrawingEnabled = YES; [[self superview] viewBoundsChanged:[[CPNotification alloc] initWithName:CPViewBoundsDidChangeNotification object:self userInfo:nil]]; if (!_inhibitUpdateTrackingAreas) - [self _updateTrackingAreas]; + [self _updateTrackingAreasWithRecursion:YES]; } /*! @@ -1374,7 +1374,7 @@ var CPViewHighDPIDrawingEnabled = YES; [[self superview] viewBoundsChanged:[[CPNotification alloc] initWithName:CPViewBoundsDidChangeNotification object:self userInfo:nil]]; if (!_inhibitUpdateTrackingAreas && !_inhibitFrameAndBoundsChangedNotifications) - [self _updateTrackingAreas]; + [self _updateTrackingAreasWithRecursion:YES]; } /*! @@ -1418,7 +1418,7 @@ var CPViewHighDPIDrawingEnabled = YES; [[self superview] viewBoundsChanged:[[CPNotification alloc] initWithName:CPViewBoundsDidChangeNotification object:self userInfo:nil]]; if (!_inhibitUpdateTrackingAreas && !_inhibitFrameAndBoundsChangedNotifications) - [self _updateTrackingAreas]; + [self _updateTrackingAreasWithRecursion:YES]; } @@ -1430,7 +1430,7 @@ var CPViewHighDPIDrawingEnabled = YES; { var mask = [self autoresizingMask]; - if (mask == CPViewNotSizable) + if (mask === CPViewNotSizable) return; var frame = _superview._frame, @@ -1611,7 +1611,7 @@ var CPViewHighDPIDrawingEnabled = YES; { do { - if (self == view) + if (self === view) { [_window makeFirstResponder:[self nextValidKeyView]]; break; @@ -1737,7 +1737,7 @@ var CPViewHighDPIDrawingEnabled = YES; */ - (void)setAlphaValue:(float)anAlphaValue { - if (_opacity == anAlphaValue) + if (_opacity === anAlphaValue) return; _opacity = anAlphaValue; @@ -1936,10 +1936,10 @@ var CPViewHighDPIDrawingEnabled = YES; */ - (void)setBackgroundColor:(CPColor)aColor { - if (_backgroundColor == aColor) + if (_backgroundColor === aColor) return; - if (aColor == [CPNull null]) + if (aColor === [CPNull null]) aColor = nil; _backgroundColor = aColor; @@ -1982,7 +1982,7 @@ var CPViewHighDPIDrawingEnabled = YES; var image = slices[i], size = [image size]; - if (!size || (size.width == 0 && size.height == 0)) + if (!size || (size.width === 0 && size.height === 0)) size = nil; _DOMImageSizes[i] = size; @@ -2037,10 +2037,12 @@ var CPViewHighDPIDrawingEnabled = YES; CPDOMDisplayServerSetStyleSize(_DOMImageParts[0], size.width, size.height); } else + { _DOMElement.style.background = colorCSS; if (patternImage) CPDOMDisplayServerSetStyleBackgroundSize(_DOMElement, [patternImage size].width + "px", [patternImage size].height + "px"); + } } else { @@ -2074,7 +2076,7 @@ var CPViewHighDPIDrawingEnabled = YES; partIndex++; } - if (_backgroundType == BackgroundNinePartImage) + if (_backgroundType === BackgroundNinePartImage) { var left = _DOMImageSizes[0] ? _DOMImageSizes[0].width : 0, right = _DOMImageSizes[2] ? _DOMImageSizes[2].width : 0, @@ -2135,7 +2137,7 @@ var CPViewHighDPIDrawingEnabled = YES; CPDOMDisplayServerSetStyleRightBottom(_DOMImageParts[partIndex], NULL, 0.0, 0.0); } } - else if (_backgroundType == BackgroundVerticalThreePartImage) + else if (_backgroundType === BackgroundVerticalThreePartImage) { var top = _DOMImageSizes[0] ? _DOMImageSizes[0].height : 0, bottom = _DOMImageSizes[2] ? _DOMImageSizes[2].height : 0; @@ -2167,7 +2169,7 @@ var CPViewHighDPIDrawingEnabled = YES; CPDOMDisplayServerSetStyleSize(_DOMImageParts[partIndex], frameSize.width, bottom); } } - else if (_backgroundType == BackgroundHorizontalThreePartImage) + else if (_backgroundType === BackgroundHorizontalThreePartImage) { var left = _DOMImageSizes[0] ? _DOMImageSizes[0].width : 0, right = _DOMImageSizes[2] ? _DOMImageSizes[2].width : 0; @@ -3129,7 +3131,7 @@ setBoundsOrigin: */ - (void)setLayer:(CALayer)aLayer { - if (_layer == aLayer) + if (_layer === aLayer) return; if (_layer) @@ -3590,21 +3592,21 @@ setBoundsOrigin: [_trackingAreas removeObjectIdenticalTo:trackingArea]; } -- (void)_updateTrackingAreas +- (void)_updateTrackingAreasWithRecursion:(BOOL)shouldCallRecursively { _inhibitUpdateTrackingAreas = YES; - [self _recursivelyUpdateTrackingAreas]; - - _inhibitUpdateTrackingAreas = NO; -} - -- (void)_recursivelyUpdateTrackingAreas -{ [self _updateTrackingAreasForOwners:[self _calcTrackingAreaOwners]]; - for (var i = 0; i < _subviews.length; i++) - [_subviews[i] _recursivelyUpdateTrackingAreas]; + if (shouldCallRecursively) + { + // Now, call _updateTrackingAreasWithRecursion on subviews + + for (var i = 0; i < _subviews.length; i++) + [_subviews[i] _updateTrackingAreasWithRecursion:YES]; + } + + _inhibitUpdateTrackingAreas = NO; } - (CPArray)_calcTrackingAreaOwners diff --git a/AppKit/CPWindow/CPWindow.j b/AppKit/CPWindow/CPWindow.j index 380b2b149..fd1a0b469 100644 --- a/AppKit/CPWindow/CPWindow.j +++ b/AppKit/CPWindow/CPWindow.j @@ -4098,6 +4098,9 @@ var interpolate = function(fromValue, toValue, progress) [overlappingTrackingAreas addObject:aTrackingArea]; } + if (overlappingTrackingAreas.length === 0) + return; + var frontmostTrackingArea = overlappingTrackingAreas[0], frontmostView = [frontmostTrackingArea view];