31 @protocol CPTextViewDelegate <CPTextDelegate>
33 - (BOOL)textView:(
CPTextView)aTextView doCommandBySelector:(
SEL)aSelector;
34 - (BOOL)textView:(
CPTextView)aTextView shouldChangeTextInRange:(CPRange)affectedCharRange replacementString:(
CPString)replacementString;
36 - (CPRange)textView:(
CPTextView)aTextView willChangeSelectionFromCharacterRange:(CPRange)oldSelectedCharRange toCharacterRange:(CPRange)newSelectedCharRange;
38 - (void)textViewDidChangeTypingAttributes:(
CPNotification)aNotification;
42 _MakeRangeFromAbs =
function(a1, a2)
47 _MidRange =
function(a1)
49 return Math.floor((
CPMaxRange(a1) + a1.location) / 2);
52 function _isWhitespaceCharacter(chr)
54 return (chr ===
'\n' || chr ===
'\r' || chr ===
' ' || chr ===
'\t');
57 _characterTripletFromStringAtIndex =
function(string, index)
60 string =
string._string;
62 var tripletRange = _MakeRangeFromAbs(MAX(0, index - 1), MIN(
string.length, index + 2));
64 return [string substringWithRange:tripletRange];
67 _regexMatchesStringAtIndex=
function(regex, string, index)
69 var triplet = _characterTripletFromStringAtIndex(
string, index);
71 return regex.exec(triplet) !== null;
78 @
typedef CPSelectionGranularity
79 CPSelectByCharacter = 0;
99 BOOL _isHorizontallyResizable;
100 BOOL _isVerticallyResizable;
102 CGPoint _textContainerOrigin;
105 CGSize _textContainerInset;
112 CPRange _selectionRange;
113 CPSelectionGranularity _selectionGranularity;
115 CPSelectionGranularity _previousSelectionGranularity;
116 CPSelectionGranularity _copySelectionGranularity;
122 unsigned _delegateRespondsToSelectorMask;
124 int _startTrackingLocation;
129 BOOL _scrollingDownward;
130 CPRange _movingSelection;
132 int _stickyXLocation;
134 CPArray _selectionSpans;
143 + (Class)_binderClassForBinding:(
CPString)aBinding
146 return [_CPTextViewValueBinder class];
148 return [
super _binderClassForBinding:aBinding];
152 #pragma mark Class methods 161 #pragma mark Init methods 165 if (
self = [super initWithFrame:aFrame])
175 _usesFontPanel = YES;
179 forKey:CPBackgroundColorAttributeName];
193 - (id)initWithFrame:(CGRect)aFrame
203 _DOMElement.style.cursor =
"text";
207 _textContainerInset = CGSizeMake(2, 0);
208 _textContainerOrigin = CGPointMake(_bounds.origin.x, _bounds.origin.y);
210 _selectionGranularity = CPSelectByCharacter;
212 _minSize = CGSizeCreateCopy(_frame.size);
213 _maxSize = CGSizeMake(_frame.size.width, 1e7);
215 _isVerticallyResizable = YES;
216 _isHorizontallyResizable = NO;
221 _caret = [[_CPCaret alloc] initWithTextView:self];
222 [_caret setRect:CGRectMake(0, 0, 1, 11)]
224 var pboardTypes = [CPStringPboardType, CPColorDragType];
232 - (void)_setObserveWindowKeyNotifications:(BOOL)shouldObserve
246 - (void)_removeObservers
251 [
super _removeObservers];
252 [
self _setObserveWindowKeyNotifications:NO];
255 - (void)_addObservers
260 [
super _addObservers];
261 [
self _setObserveWindowKeyNotifications:YES];
262 [
self _startObservingClipView];
264 - (void)_startObservingClipView
266 if (!_observedClipView)
271 [_observedClipView setPostsFrameChangedNotifications:YES];
272 [_observedClipView setPostsBoundsChangedNotifications:YES];
274 [defaultCenter addObserver:self
275 selector:@selector(superviewFrameChanged:)
276 name:CPViewFrameDidChangeNotification
277 object:_observedClipView];
279 [defaultCenter addObserver:self
280 selector:@selector(superviewBoundsChanged:)
281 name:CPViewBoundsDidChangeNotification
282 object:_observedClipView];
290 if ([superview isKindOfClass:[
CPClipView class]])
291 _exposedRect = [superview bounds];
293 _exposedRect = [
self bounds];
316 - (void)viewWillMoveToSuperview:(
CPView)aView
319 _observedClipView = aView;
321 [
self _stopObservingClipView];
326 - (void)_stopObservingClipView
328 if (!_observedClipView)
333 [defaultCenter removeObserver:self
334 name:CPViewFrameDidChangeNotification
335 object:_observedClipView];
337 [defaultCenter removeObserver:self
338 name:CPViewBoundsDidChangeNotification
339 object:_observedClipView];
341 _observedClipView = nil;
346 if (![[
self window] isKeyWindow])
352 if ([
self _isFocused])
353 [
self _becomeFirstResponder];
357 #pragma mark Copy and paste methods 359 - (void)copy:(
id)sender
361 _copySelectionGranularity = _previousSelectionGranularity;
370 richData = [_CPRTFProducer produceRTF:stringForPasting documentAttributes:@{}];
372 [pasteboard declareTypes:[CPStringPboardType, CPRTFPboardType] owner:nil];
373 [pasteboard setString:stringForPasting._string forType:CPStringPboardType];
374 [pasteboard setString:richData forType:CPRTFPboardType];
377 - (void)_pasteString:(
id)stringForPasting
379 if (!stringForPasting)
382 if (_copySelectionGranularity > 0 && _selectionRange.location > 0)
384 if (!_isWhitespaceCharacter([[_textStorage
string] characterAtIndex:_selectionRange.location - 1]) &&
385 _selectionRange.location != [_layoutManager numberOfCharacters])
393 var peekStr = stringForPasting,
396 if (![stringForPasting isKindOfClass:[
CPString class]])
397 peekStr = stringForPasting._string;
399 while (_isWhitespaceCharacter([peekStr characterAtIndex:i]))
404 if ([stringForPasting isKindOfClass:[CPString
class]])
405 stringForPasting = [stringForPasting stringByReplacingCharactersInRange:CPMakeRange(0, i) withString:''];
407 [stringForPasting replaceCharactersInRange:CPMakeRange(0, i) withString:''];
413 if (_copySelectionGranularity > 0)
415 if (!_isWhitespaceCharacter([[_textStorage
string] characterAtIndex:
CPMaxRange(_selectionRange)]) &&
416 !_isNewlineCharacter([[_textStorage
string] characterAtIndex:MAX(0, _selectionRange.location - 1)]) &&
417 _selectionRange.location != [_layoutManager numberOfCharacters])
423 - (void)pasteAsPlainText:(
id)sender
425 if (![sender isKindOfClass:_CPNativeInputManager] && [[
CPApp currentEvent] type] !=
CPAppKitDefined)
428 [
self _pasteString:[
self _plainStringForPasting]];
431 - (void)paste:(
id)sender
433 if (![sender isKindOfClass:_CPNativeInputManager] && [[
CPApp currentEvent] type] !=
CPAppKitDefined)
436 [
self _pasteString:[
self _stringForPasting]];
440 #pragma mark Responders method 447 - (void)_becomeFirstResponder
459 [
self _becomeFirstResponder];
466 [
self _reverseSetBinding];
467 [_caret stopBlinking];
469 [_CPNativeInputManager cancelCurrentInputSessionIfNeeded];
476 #pragma mark Delegate methods 481 - (void)setDelegate:(
id <CPTextViewDelegate>)aDelegate
483 if (aDelegate === _delegate)
486 _delegateRespondsToSelectorMask = 0;
487 _delegate = aDelegate;
491 if ([_delegate respondsToSelector:
@selector(textDidChange:)])
494 if ([_delegate respondsToSelector:
@selector(textViewDidChangeSelection:)])
497 if ([_delegate respondsToSelector:
@selector(textViewDidChangeTypingAttributes:)])
500 if ([_delegate respondsToSelector:
@selector(textView:doCommandBySelector:)])
503 if ([_delegate respondsToSelector:
@selector(textShouldBeginEditing:)])
506 if ([_delegate respondsToSelector:
@selector(textView:willChangeSelectionFromCharacterRange:toCharacterRange:)])
509 if ([_delegate respondsToSelector:
@selector(textView:shouldChangeTextInRange:replacementString:)])
512 if ([_delegate respondsToSelector:
@selector(textView:shouldChangeTypingAttributes:toAttributes:)])
519 #pragma mark Key window methods 534 - (BOOL)_isFirstResponder
546 #pragma mark Undo redo methods 548 - (void)undo:(
id)sender
554 - (void)redo:(
id)sender
562 #pragma mark Accessors 566 return _textStorage._string;
571 if (_placeholderString)
574 return [
self isRichText]? _textStorage : _textStorage._string;
576 - (void)setObjectValue:(
id)aValue
578 if (_placeholderString)
590 - (void)setString:(
id)aString
594 [_textStorage replaceCharactersInRange:CPMakeRange(0, [_layoutManager numberOfCharacters]) withAttributedString:aString];
598 [_textStorage replaceCharactersInRange:CPMakeRange(0, [_layoutManager numberOfCharacters]) withString:aString];
601 if (
CPMaxRange(_selectionRange) > [_layoutManager numberOfCharacters])
602 [
self setSelectedRange:
CPMakeRange([_layoutManager numberOfCharacters], 0)];
605 [_layoutManager _validateLayoutAndGlyphs];
612 return [_textStorage string];
617 _textContainer = aContainer;
618 _layoutManager = [_textContainer layoutManager];
619 _textStorage = [_layoutManager textStorage];
620 [_textStorage setFont:[
self font]];
621 [_textStorage setForegroundColor:_textColor];
626 - (void)setTextContainerInset:(CGSize)aSize
628 _textContainerInset = aSize;
634 _textContainerOrigin.x = _bounds.origin.x;
635 _textContainerOrigin.x += _textContainerInset.width;
637 _textContainerOrigin.y = _bounds.origin.y;
638 _textContainerOrigin.y += _textContainerInset.height;
641 - (void)doCommandBySelector:(
SEL)aSelector
643 if (![
self _sendDelegateDoCommandBySelector:aSelector])
644 [
super doCommandBySelector:aSelector];
655 - (BOOL)shouldChangeTextInRange:(CPRange)aRange replacementString:(
CPString)aString
660 return [
self _sendDelegateTextShouldBeginEditing] && [
self _sendDelegateShouldChangeTextInRange:aRange replacementString:aString];
665 #pragma mark Insert characters methods 667 - (void)_fixupReplaceForRange:(CPRange)aRange
670 [_layoutManager _validateLayoutAndGlyphs];
676 - (void)_replaceCharactersInRange:(CPRange)aRange withAttributedString:(
CPString)aString selectionRange:(CPRange)selectionRange
679 _replaceCharactersInRange:CPMakeRange(aRange.location, [aString
length])
680 withAttributedString:[_textStorage attributedSubstringFromRange:CPMakeRangeCopy(aRange)]
681 selectionRange:CPMakeRangeCopy(_selectionRange)];
683 [_textStorage replaceCharactersInRange:aRange withAttributedString:aString];
684 [
self _fixupReplaceForRange:selectionRange];
689 var isAttributed = [aString
isKindOfClass:CPAttributedString],
690 string = isAttributed ? [aString
string]:aString;
701 [undoManager setActionName:@"Replace/insert text"];
703 [[undoManager prepareWithInvocationTarget:self]
704 _replaceCharactersInRange:CPMakeRange(_selectionRange.location, [aString
length])
705 withAttributedString:[_textStorage attributedSubstringFromRange:CPMakeRangeCopy(_selectionRange)]
706 selectionRange:CPMakeRangeCopy(_selectionRange)];
708 [
self willChangeValueForKey:@"objectValue"];
709 [_textStorage replaceCharactersInRange:CPMakeRangeCopy(_selectionRange) withAttributedString:aString];
710 [
self didChangeValueForKey:@"objectValue"];
711 [
self _continuouslyReverseSetBinding];
713 [
self _setSelectedRange:CPMakeRange(_selectionRange.location + [
string length], 0) affinity:0 stillSelecting:NO overwriteTypingAttributes:NO];
714 _startTrackingLocation = _selectionRange.location;
717 [_layoutManager _validateLayoutAndGlyphs];
720 _stickyXLocation = MAX(0, _caret._rect.origin.x - 1);
724 #pragma mark Drawing methods 726 - (void)drawInsertionPointInRect:(CGRect)aRect color:(
CPColor)aColor turnedOn:(BOOL)flag
728 [_caret setRect:aRect];
729 [_caret setVisibility:flag stop:NO];
739 - (void)drawRect:(CGRect)aRect
742 var range = [_layoutManager glyphRangeForBoundingRect:aRect inTextContainer:_textContainer];
744 for (var i = 0; i < [_selectionSpans count]; i++)
745 [_selectionSpans[i] removeFromTextView];
747 _selectionSpans = [];
749 if (_selectionRange.length)
751 var rects = [_layoutManager rectArrayForCharacterRange:_selectionRange
752 withinSelectedCharacterRange:_selectionRange
753 inTextContainer:_textContainer
755 effectiveSelectionColor = [
self _isFocused] ? [_selectedTextAttributes objectForKey:CPBackgroundColorAttributeName] : [
CPColor _selectedTextBackgroundColorUnfocussed],
756 lengthRect = rects.length;
758 for (var i = 0; i < lengthRect; i++)
760 rects[i].origin.x += _textContainerOrigin.x;
761 rects[i].origin.y += _textContainerOrigin.y;
763 var newSpan = [[_CPSelectionBox alloc] initWithTextView:self rect:rects[i] color:effectiveSelectionColor];
764 [_selectionSpans addObject:newSpan];
769 [_layoutManager drawGlyphsForGlyphRange:range atPoint:_textContainerOrigin];
777 [_caret setVisibility:NO];
783 #pragma mark Select methods 785 - (void)selectAll:(
id)sender
789 [_caret stopBlinking];
790 [
self setSelectedRange:CPMakeRange(0, [_layoutManager numberOfCharacters])];
794 - (void)setSelectedRange:(CPRange)range
796 [_CPNativeInputManager cancelCurrentInputSessionIfNeeded];
800 - (void)setSelectedRange:(CPRange)range affinity:(CPSelectionAffinity)affinity stillSelecting:(BOOL)selecting
802 [
self _setSelectedRange:range affinity:affinity stillSelecting:selecting overwriteTypingAttributes:YES];
805 - (void)_setSelectedRange:(CPRange)range affinity:(CPSelectionAffinity)affinity stillSelecting:(BOOL)selecting overwriteTypingAttributes:(BOOL)doOverwrite
807 var maxRange =
CPMakeRange(0, [_layoutManager numberOfCharacters]);
811 if (!selecting && [
self _delegateRespondsToWillChangeSelectionFromCharacterRangeToCharacterRange])
813 _selectionRange = [
self _sendDelegateWillChangeSelectionFromCharacterRange:_selectionRange toCharacterRange:range];
821 if (_selectionRange.length)
822 [_layoutManager invalidateDisplayForGlyphRange:_selectionRange];
828 if ([
self _isFirstResponder])
831 if (doOverwrite && _placeholderString === nil)
832 [
self setTypingAttributes:[_textStorage attributesAtIndex:CPMaxRange(range) effectiveRange:nil]];
840 if (!selecting && _selectionRange.length > 0)
841 [_CPNativeInputManager focusForClipboardOfTextView:self];
845 - (CGPoint)_cumulativeOffset
849 element =
self._DOMElement;
853 top += element.offsetTop || 0;
854 left += element.offsetLeft || 0;
855 element = element.offsetParent;
859 return CGPointMake(left, top);
865 - (void)_activateNativeInputElement:(DOMElemet)aNativeField
873 var placeholderString = [[
CPAttributedString alloc] initWithString:aNativeField.innerHTML attributes:attributes];
876 var caretOrigin = [_layoutManager boundingRectForGlyphRange:CPMakeRange(MAX(0, _selectionRange.location - 1), 1) inTextContainer:_textContainer].origin;
877 caretOrigin.y += [_layoutManager _characterOffsetAtLocation:MAX(0, _selectionRange.location - 1)];
879 var cumulativeOffset = [
self _cumulativeOffset];
883 aNativeField.style.left = (caretOrigin.x + cumulativeOffset.x) +
"px";
884 aNativeField.style.top = (caretOrigin.y + cumulativeOffset.y) +
"px";
885 aNativeField.style.font = [[_typingAttributes objectForKey:CPFontAttributeName] cssString];
886 aNativeField.style.color = [[_typingAttributes objectForKey:CPForegroundColorAttributeName] cssString];
889 [_caret setVisibility:NO];
894 return [_selectionRange];
898 #pragma mark Keyboard events 903 [[_window platformWindow] _propagateCurrentDOMEvent:YES];
905 if (![_CPNativeInputManager isNativeInputFieldActive] && [event charactersIgnoringModifiers].charCodeAt(0) != 229)
906 [
self interpretKeyEvents:[event]];
908 [_caret setPermanentlyVisible:YES];
915 setTimeout(
function() {
916 [_caret setPermanentlyVisible:NO];
920 - (CGPoint)_characterIndexFromRawPoint:(CGPoint)point
926 point.x -= _textContainerOrigin.x;
927 point.y -= _textContainerOrigin.y;
929 var index = [_layoutManager glyphIndexForPoint:point inTextContainer:_textContainer fractionOfDistanceThroughGlyph:fraction];
932 index = [_layoutManager numberOfCharacters];
933 else if (fraction[0] > 0.5)
938 - (CGPoint)_characterIndexFromEvent:(
CPEvent)
event 949 #pragma mark Mouse Events 956 [_CPNativeInputManager cancelCurrentInputSessionIfNeeded];
957 [_caret setVisibility:NO];
959 _startTrackingLocation = [
self _characterIndexFromEvent:event];
961 var granularities = [CPNotFound, CPSelectByCharacter, CPSelectByWord, CPSelectByParagraph];
967 var lineBeginningIndex = [_layoutManager _firstLineFragmentForLineFromLocation:_selectionRange.location]._range.location,
968 placeholderRange = _MakeRangeFromAbs(lineBeginningIndex,
CPMaxRange(_selectionRange)),
969 placeholderString = [_textStorage attributedSubstringFromRange:placeholderRange],
970 placeholderFrame = CGRectIntersection([_layoutManager boundingRectForGlyphRange:placeholderRange inTextContainer:_textContainer], _frame),
971 rangeToHide =
CPMakeRange(0, _selectionRange.location - lineBeginningIndex),
975 [placeholderString addAttribute:CPForegroundColorAttributeName
979 _movingSelection =
CPMakeRange(_startTrackingLocation, 0);
981 dragPlaceholder = [[
CPTextView alloc] initWithFrame:placeholderFrame];
982 [dragPlaceholder._textStorage replaceCharactersInRange:CPMakeRange(0, 0) withAttributedString:placeholderString];
985 [dragPlaceholder setAlphaValue:0.5];
987 var stringForPasting = [_textStorage attributedSubstringFromRange:CPMakeRangeCopy(_selectionRange)],
988 richData = [_CPRTFProducer produceRTF:stringForPasting documentAttributes:@{}],
990 [draggingPasteboard declareTypes:[CPRTFPboardType, CPStringPboardType] owner:nil];
991 [draggingPasteboard setString:richData forType:CPRTFPboardType];
992 [draggingPasteboard setString:stringForPasting._string forType:CPStringPboardType];
995 at:placeholderFrame.origin
1005 var setRange =
CPMakeRange(_startTrackingLocation, 0);
1008 setRange = _MakeRangeFromAbs(_startTrackingLocation < _MidRange(_selectionRange) ?
CPMaxRange(_selectionRange) : _selectionRange.location, _startTrackingLocation);
1015 - (void)_supportScrolling:(
CPTimer)aTimer
1025 if (_movingSelection)
1029 index = [
self _characterIndexFromEvent:event];
1031 if (index > oldRange.location)
1032 _scrollingDownward = YES;
1035 _scrollingDownward = NO;
1048 _movingSelection = nil;
1055 var point = [_layoutManager locationForGlyphAtIndex:[
self selectedRange].location];
1056 _stickyXLocation = point.x;
1057 _startTrackingLocation = _selectionRange.location;
1059 if (_scrollingTimer)
1061 [_scrollingTimer invalidate];
1062 _scrollingTimer = nil;
1066 - (void)moveDown:(
id)sender
1072 nglyphs = [_layoutManager numberOfCharacters],
1074 rectSource = [_layoutManager boundingRectForGlyphRange:CPMakeRange(sindex, 1) inTextContainer:_textContainer],
1075 rectEnd = nglyphs ? [_layoutManager boundingRectForGlyphRange:CPMakeRange(nglyphs - 1, 1) inTextContainer:_textContainer] : rectSource,
1076 point = rectSource.origin;
1078 if (_stickyXLocation)
1079 point.x = _stickyXLocation;
1082 point.y += 2 + rectSource.size.height;
1084 var dindex = point.y >= CGRectGetMaxY(rectEnd) ? nglyphs : [_layoutManager glyphIndexForPoint:point inTextContainer:_textContainer fractionOfDistanceThroughGlyph:fraction],
1085 oldStickyLoc = _stickyXLocation;
1087 if (fraction[0] > 0.5)
1090 [
self _establishSelection:CPMakeRange(dindex, 0) byExtending:NO];
1091 _stickyXLocation = oldStickyLoc;
1096 - (void)moveDownAndModifySelection:(
id)sender
1101 var oldStartTrackingLocation = _startTrackingLocation;
1103 [
self _performSelectionFixupForRange:CPMakeRange(_selectionRange.location < _startTrackingLocation ? _selectionRange.location : CPMaxRange(_selectionRange), 0)];
1105 _startTrackingLocation = oldStartTrackingLocation;
1106 [
self _performSelectionFixupForRange:_MakeRangeFromAbs(_startTrackingLocation, (_selectionRange.location < _startTrackingLocation ? _selectionRange.location : CPMaxRange(_selectionRange)))];
1109 - (void)moveUp:(
id)sender
1119 var rectSource = [_layoutManager boundingRectForGlyphRange:CPMakeRange(dindex, 1) inTextContainer:_textContainer];
1121 if (!(dindex === [_layoutManager numberOfCharacters] && _isNewlineCharacter([[_textStorage
string] characterAtIndex:dindex - 1])))
1122 dindex = [_layoutManager glyphIndexForPoint:CGPointMake(0, rectSource.origin.y + 1) inTextContainer:_textContainer fractionOfDistanceThroughGlyph:nil];
1128 rectSource = [_layoutManager boundingRectForGlyphRange:CPMakeRange(dindex - 1, 1) inTextContainer:_textContainer];
1129 dindex = [_layoutManager glyphIndexForPoint:CGPointMake(_stickyXLocation, rectSource.origin.y + 1) inTextContainer:_textContainer fractionOfDistanceThroughGlyph:fraction];
1131 if (fraction[0] > 0.5)
1134 var oldStickyLoc = _stickyXLocation;
1135 [
self _establishSelection:CPMakeRange(dindex,0) byExtending:NO];
1136 _stickyXLocation = oldStickyLoc;
1141 - (void)moveUpAndModifySelection:(
id)sender
1146 var oldStartTrackingLocation = _startTrackingLocation;
1148 [
self _performSelectionFixupForRange:CPMakeRange(_selectionRange.location < _startTrackingLocation ? _selectionRange.location : CPMaxRange(_selectionRange), 0)];
1150 _startTrackingLocation = oldStartTrackingLocation;
1151 [
self _performSelectionFixupForRange:_MakeRangeFromAbs(_startTrackingLocation, (_selectionRange.location < _startTrackingLocation ? _selectionRange.location : CPMaxRange(_selectionRange)))];
1154 - (void)_performSelectionFixupForRange:(CPRange)aSel
1156 aSel.location = MAX(0, aSel.location);
1158 if (
CPMaxRange(aSel) > [_layoutManager numberOfCharacters])
1159 aSel =
CPMakeRange([_layoutManager numberOfCharacters], 0);
1163 var point = [_layoutManager locationForGlyphAtIndex:aSel.location];
1165 _stickyXLocation = point.x;
1168 - (void)_establishSelection:(CPSelection)aSel byExtending:(BOOL)flag
1173 [
self _performSelectionFixupForRange:aSel];
1174 _startTrackingLocation = _selectionRange.location;
1177 - (unsigned)_calculateMoveSelectionFromRange:(CPRange)aRange intoDirection:(integer)move granularity:(CPSelectionGranularity)granularity
1179 var inWord = [
self _isCharacterAtIndex:(move > 0 ? CPMaxRange(aRange) : aRange.location) + move granularity:granularity],
1183 return move > 0 ?
CPMaxRange(inWord? aSel:bSel) : (inWord? aSel:bSel).location;
1186 - (void)_moveSelectionIntoDirection:(integer)move granularity:(CPSelectionGranularity)granularity
1188 var pos = [
self _calculateMoveSelectionFromRange:_selectionRange intoDirection:move granularity:granularity];
1190 [
self _performSelectionFixupForRange:CPMakeRange(pos, 0)];
1191 _startTrackingLocation = _selectionRange.location;
1194 - (void)_extendSelectionIntoDirection:(integer)move granularity:(CPSelectionGranularity)granularity
1198 if (granularity !== CPSelectByCharacter)
1200 var pos = [
self _calculateMoveSelectionFromRange:CPMakeRange(aSel.location < _startTrackingLocation ? aSel.location : CPMaxRange(aSel), 0)
1202 granularity:granularity];
1207 aSel =
CPMakeRange((aSel.location < _startTrackingLocation? aSel.location :
CPMaxRange(aSel)) + move, 0);
1209 aSel = _MakeRangeFromAbs(_startTrackingLocation, aSel.location);
1210 [
self _performSelectionFixupForRange:aSel];
1213 - (void)moveLeftAndModifySelection:(
id)sender
1216 [
self _extendSelectionIntoDirection:-1 granularity:CPSelectByCharacter];
1219 - (void)moveBackward:(
id)sender
1224 - (void)moveBackwardAndModifySelection:(
id)sender
1229 - (void)moveRightAndModifySelection:(
id)sender
1232 [
self _extendSelectionIntoDirection:1 granularity:CPSelectByCharacter];
1235 - (void)moveLeft:(
id)sender
1238 [
self _establishSelection:CPMakeRange(_selectionRange.location - (_selectionRange.length ? 0 : 1), 0) byExtending:NO];
1241 - (void)moveToEndOfParagraph:(
id)sender
1246 if (!_isNewlineCharacter([[_textStorage
string] characterAtIndex:_selectionRange.location]))
1247 [
self _moveSelectionIntoDirection:1 granularity:CPSelectByParagraph];
1249 if (_isNewlineCharacter([[_textStorage
string] characterAtIndex:MAX(0, _selectionRange.location - 1)]))
1253 - (void)moveToEndOfParagraphAndModifySelection:(
id)sender
1256 [
self _extendSelectionIntoDirection:1 granularity:CPSelectByParagraph];
1259 - (void)moveParagraphForwardAndModifySelection:(
id)sender
1262 [
self _extendSelectionIntoDirection:1 granularity:CPSelectByParagraph];
1265 - (void)moveParagraphForward:(
id)sender
1268 [
self _moveSelectionIntoDirection:1 granularity:CPSelectByParagraph];
1271 - (void)moveWordBackwardAndModifySelection:(
id)sender
1276 - (void)moveWordBackward:(
id)sender
1281 - (void)moveWordForwardAndModifySelection:(
id)sender
1286 - (void)moveWordForward:(
id)sender
1291 - (void)moveToBeginningOfDocument:(
id)sender
1294 [
self _establishSelection:CPMakeRange(0, 0) byExtending:NO];
1297 - (void)moveToBeginningOfDocumentAndModifySelection:(
id)sender
1300 [
self _establishSelection:CPMakeRange(0, 0) byExtending:YES];
1303 - (void)moveToEndOfDocument:(
id)sender
1306 [
self _establishSelection:CPMakeRange([_layoutManager numberOfCharacters], 0) byExtending:NO];
1309 - (void)moveToEndOfDocumentAndModifySelection:(
id)sender
1312 [
self _establishSelection:CPMakeRange([_layoutManager numberOfCharacters], 0) byExtending:YES];
1315 - (void)moveWordRight:(
id)sender
1318 [
self _moveSelectionIntoDirection:1 granularity:CPSelectByWord];
1321 - (void)moveToBeginningOfParagraph:(
id)sender
1326 if (!_isNewlineCharacter([[_textStorage
string] characterAtIndex:MAX(0, _selectionRange.location - 1)]))
1327 [
self _moveSelectionIntoDirection:-1 granularity:CPSelectByParagraph];
1330 - (void)moveToBeginningOfParagraphAndModifySelection:(
id)sender
1333 [
self _extendSelectionIntoDirection:-1 granularity:CPSelectByParagraph];
1336 - (void)moveParagraphBackward:(
id)sender
1339 [
self _moveSelectionIntoDirection:-1 granularity:CPSelectByParagraph];
1342 - (void)moveParagraphBackwardAndModifySelection:(
id)sender
1345 [
self _extendSelectionIntoDirection:-1 granularity:CPSelectByParagraph];
1348 - (void)moveWordRightAndModifySelection:(
id)sender
1351 [
self _extendSelectionIntoDirection:+1 granularity:CPSelectByWord];
1354 - (void)deleteToEndOfParagraph:(
id)sender
1363 - (void)deleteToBeginningOfParagraph:(
id)sender
1372 - (void)deleteToBeginningOfLine:(
id)sender
1381 - (void)deleteToEndOfLine:(
id)sender
1390 - (void)deleteWordBackward:(
id)sender
1399 - (void)deleteWordForward:(
id)sender
1408 - (void)moveToLeftEndOfLine:(
id)sender byExtending:(BOOL)flag
1413 var nglyphs = [_layoutManager numberOfCharacters],
1414 loc = nglyphs == _selectionRange.location ? MAX(0, _selectionRange.location - 1) : _selectionRange.location,
1415 fragment = [_layoutManager _firstLineFragmentForLineFromLocation:loc];
1418 [
self _establishSelection:CPMakeRange(fragment._range.location, 0) byExtending:flag];
1421 - (void)moveToLeftEndOfLine:(
id)sender
1426 - (void)moveToLeftEndOfLineAndModifySelection:(
id)sender
1431 - (void)moveToRightEndOfLine:(
id)sender byExtending:(BOOL)flag
1436 var fragment = [_layoutManager _lastLineFragmentForLineFromLocation:_selectionRange.location];
1441 var nglyphs = [_layoutManager numberOfCharacters],
1442 loc = nglyphs ==
CPMaxRange(fragment._range) ? nglyphs : MAX(0,
CPMaxRange(fragment._range) - 1);
1444 [
self _establishSelection:CPMakeRange(loc, 0) byExtending:flag];
1447 - (void)moveToRightEndOfLine:(
id)sender
1452 - (void)moveToRightEndOfLineAndModifySelection:(
id)sender
1457 - (void)moveWordLeftAndModifySelection:(
id)sender
1460 [
self _extendSelectionIntoDirection:-1 granularity:CPSelectByWord];
1463 - (void)moveWordLeft:(
id)sender
1466 [
self _moveSelectionIntoDirection:-1 granularity:CPSelectByWord]
1469 - (void)moveRight:(
id)sender
1472 [
self _establishSelection:CPMakeRange(CPMaxRange(_selectionRange) + (_selectionRange.length ? 0 : 1), 0) byExtending:NO];
1475 - (void)_deleteForRange:(CPRange)changedRange
1477 if (![
self shouldChangeTextInRange:changedRange replacementString:
@""])
1482 [[[_window undoManager] prepareWithInvocationTarget:self] _replaceCharactersInRange:CPMakeRange(changedRange.location, 0)
1483 withAttributedString:[_textStorage attributedSubstringFromRange:CPMakeRangeCopy(changedRange)]
1484 selectionRange:CPMakeRangeCopy(_selectionRange)];
1485 [
self willChangeValueForKey:@"objectValue"];
1486 [_textStorage deleteCharactersInRange:CPMakeRangeCopy(changedRange)];
1487 [
self didChangeValueForKey:@"objectValue"];
1488 [
self _continuouslyReverseSetBinding];
1492 [_layoutManager _validateLayoutAndGlyphs];
1494 _stickyXLocation = _caret._rect.origin.x;
1497 - (void)cancelOperation:(
id)sender
1499 [_CPNativeInputManager cancelCurrentInputSessionIfNeeded];
1502 - (void)deleteBackward:(
id)sender ignoreSmart:(BOOL)ignoreFlag
1506 if (
CPEmptyRange(_selectionRange) && _selectionRange.location > 0)
1507 changedRange =
CPMakeRange(_selectionRange.location - 1, 1);
1509 changedRange = _selectionRange;
1512 if (!ignoreFlag && _copySelectionGranularity > 0 &&
1513 changedRange.location > 0 && _isWhitespaceCharacter([[_textStorage
string] characterAtIndex:_selectionRange.location - 1]) &&
1514 changedRange.location < [[
self string] length] && _isWhitespaceCharacter([[_textStorage
string] characterAtIndex:
CPMaxRange(changedRange)]))
1515 changedRange.length++;
1517 [
self _deleteForRange:changedRange];
1518 _startTrackingLocation = _selectionRange.location;
1521 - (void)deleteBackward:(
id)sender
1523 _copySelectionGranularity = _previousSelectionGranularity;
1524 [
self deleteBackward:self ignoreSmart:_selectionRange.length > 0? NO:YES];
1527 - (void)deleteForward:(
id)sender
1531 if (
CPEmptyRange(_selectionRange) && _selectionRange.location < [_layoutManager numberOfCharacters])
1532 changedRange =
CPMakeRange(_selectionRange.location, 1);
1534 changedRange = _selectionRange;
1536 [
self _deleteForRange:changedRange];
1539 - (void)cut:(
id)sender
1550 - (void)insertLineBreak:(
id)sender
1555 - (void)insertTab:(
id)sender
1560 - (void)insertTabIgnoringFieldEditor:(
id)sender
1565 - (void)insertNewlineIgnoringFieldEditor:(
id)sender
1570 - (void)insertNewline:(
id)sender
1575 - (void)_enrichEssentialTypingAttributes:(
CPDictionary)attributes
1578 [attributes setObject:[
self font] forKey:CPFontAttributeName];
1581 [attributes setObject:[
self textColor] forKey:CPForegroundColorAttributeName];
1589 if ([
self _delegateRespondsToShouldChangeTypingAttributesToAttributes])
1591 _typingAttributes = [
self _sendDelegateShouldChangeTypingAttributes:_typingAttributes toAttributes:attributes];
1595 _typingAttributes = [attributes
copy];
1597 [
self _enrichEssentialTypingAttributes:_typingAttributes];
1609 var attributes = [[_textStorage attributesAtIndex:CPMaxRange(_selectionRange) effectiveRange:nil] copy];
1611 [
self _enrichEssentialTypingAttributes:attributes];
1616 - (void)delete:(
id)sender
1623 #pragma mark Font methods 1634 var length = [_layoutManager numberOfCharacters];
1638 [_textStorage addAttribute:CPFontAttributeName value:_font range:CPMakeRange(0, length)];
1639 [_textStorage setFont:_font];
1644 - (void)setFont:(
CPFont)font range:(CPRange)range
1649 [_textStorage setFont:_font];
1652 var currentAttributes = [_textStorage attributesAtIndex:range.location effectiveRange:nil] || _typingAttributes;
1655 setFont:[currentAttributes objectForKey:CPFontAttributeName] || [
self font]
1656 range:CPMakeRangeCopy(range)];
1658 [_textStorage addAttribute:CPFontAttributeName value:font range:CPMakeRangeCopy(range)];
1659 [_layoutManager _validateLayoutAndGlyphs];
1662 - (void)changeFont:(
id)sender
1664 var currRange =
CPMakeRange(_selectionRange.location, 0),
1670 [undoManager beginUndoGrouping];
1678 attributes = [_textStorage attributesAtIndex:CPMaxRange(currRange)
1679 longestEffectiveRange:currRange
1680 inRange:_selectionRange];
1683 [
self setFont:[sender convertFont:oldFont]
range:currRange];
1688 [_typingAttributes setObject:[sender selectedFont] forKey:CPFontAttributeName];
1693 var length = [_textStorage length];
1695 oldFont = [
self font];
1696 [
self setFont:[sender convertFont:oldFont]
range:CPMakeRange(0, length)];
1700 [undoManager endUndoGrouping];
1702 [_layoutManager _validateLayoutAndGlyphs];
1710 #pragma mark Color methods 1712 - (void)changeColor:(
id)sender
1719 _textColor = [aColor copy];
1720 [
self setTextColor:aColor
range:CPMakeRange(0, [_layoutManager numberOfCharacters])];
1721 [_typingAttributes setObject:_textColor forKey:CPForegroundColorAttributeName];
1724 - (void)setTextColor:(
CPColor)aColor range:(CPRange)range
1726 var currentAttributes = [_textStorage attributesAtIndex:range.location effectiveRange:nil] || _typingAttributes;
1729 setTextColor:[currentAttributes objectForKey:CPForegroundColorAttributeName] || _textColor
1730 range:CPMakeRangeCopy(range)];
1735 [_textStorage addAttribute:CPForegroundColorAttributeName value:aColor range:CPMakeRangeCopy(range)];
1737 [_textStorage removeAttribute:CPForegroundColorAttributeName range:CPMakeRangeCopy(range)];
1740 [_typingAttributes setObject:aColor forKey:CPForegroundColorAttributeName];
1742 [_layoutManager textStorage:_textStorage edited:0 range:CPMakeRangeCopy(range) changeInLength:0 invalidatedRange:CPMakeRangeCopy(range)];
1745 - (void)underline:(
id)sender
1747 if (![
self shouldChangeTextInRange:_selectionRange replacementString:nil])
1752 var attrib = [_textStorage attributesAtIndex:_selectionRange.location effectiveRange:nil];
1755 [_textStorage removeAttribute:CPUnderlineStyleAttributeName range:_selectionRange];
1757 [_textStorage addAttribute:CPUnderlineStyleAttributeName value:[
CPNumber numberWithInt:1]
range:CPMakeRangeCopy(_selectionRange)];
1767 [_layoutManager textStorage:_textStorage edited:0 range:CPMakeRangeCopy(_selectionRange) changeInLength:0 invalidatedRange:CPMakeRangeCopy(_selectionRange)];
1780 - (void)replaceCharactersInRange:(CPRange)aRange withString:(
CPString)aString
1782 [_textStorage replaceCharactersInRange:aRange withString:aString];
1785 - (void)setConstrainedFrameSize:(CGSize)desiredSize
1795 - (void)setFrameSize:(CGSize)aSize
1799 desiredSize = CGSizeCreateCopy(aSize),
1800 rect = CGRectUnion([_layoutManager boundingRectForGlyphRange:
CPMakeRange(0, 1) inTextContainer:_textContainer],
1801 [_layoutManager boundingRectForGlyphRange:
CPMakeRange(MAX(0, [_layoutManager numberOfCharacters] - 2), 1) inTextContainer:_textContainer]),
1802 myClipviewSize = nil;
1807 if ([_layoutManager extraLineFragmentTextContainer] === _textContainer)
1808 rect = CGRectUnion(rect, [_layoutManager extraLineFragmentRect]);
1810 if (_isHorizontallyResizable)
1812 rect = [_layoutManager boundingRectForGlyphRange:CPMakeRange(0, MAX(0, [_layoutManager numberOfCharacters] - 1)) inTextContainer:_textContainer];
1814 desiredSize.width = rect.size.width + 2 * _textContainerInset.width;
1816 if (desiredSize.width <
minSize.width)
1817 desiredSize.width =
minSize.width;
1818 else if (desiredSize.width >
maxSize.width)
1819 desiredSize.width =
maxSize.width;
1822 if (_isVerticallyResizable)
1824 desiredSize.height = rect.size.height + 2 * _textContainerInset.height;
1826 if (desiredSize.height <
minSize.height)
1827 desiredSize.height =
minSize.height;
1828 else if (desiredSize.height >
maxSize.height)
1829 desiredSize.height =
maxSize.height;
1834 if (desiredSize.width < myClipviewSize.width)
1835 desiredSize.width = myClipviewSize.width;
1836 if (desiredSize.height < myClipviewSize.height)
1837 desiredSize.height = myClipviewSize.height;
1843 - (void)scrollRangeToVisible:(CPRange)aRange
1849 if (aRange.location >= [_layoutManager numberOfCharacters])
1850 rect = [_layoutManager extraLineFragmentRect];
1852 rect = [_layoutManager lineFragmentRectForGlyphAtIndex:aRange.location effectiveRange:nil];
1856 rect = [_layoutManager boundingRectForGlyphRange:aRange inTextContainer:_textContainer];
1859 rect.origin.x += _textContainerOrigin.x;
1860 rect.origin.y += _textContainerOrigin.y;
1865 - (BOOL)_isCharacterAtIndex:(
unsigned)index granularity:(CPSelectionGranularity)granularity
1869 switch (granularity)
1872 characterSet = [[
self class] _wordBoundaryRegex];
1876 characterSet = [[
self class] _paragraphBoundaryRegex];
1882 return _regexMatchesStringAtIndex(characterSet, [_textStorage
string], index);
1885 + (JSObject)_wordBoundaryRegex
1887 return new RegExp(
"(^[0-9][\\.,])|(^.[^-\\.,+#'\"!§$%&/\\(<\\[\\]>\\)=?`´*\\s{}\\|¶])",
"m");
1890 + (JSObject)_paragraphBoundaryRegex
1892 return new RegExp(
"^.[^\\n\\r]",
"m");
1895 + (JSObject)_whitespaceRegex
1898 return new RegExp(
"^.[ \\t]+",
"m");
1901 - (CPRange)_characterRangeForIndex:(
unsigned)index asDefinedByRegex:(JSObject)regex
1903 return [
self _characterRangeForIndex:index asDefinedByLRegex:regex andRRegex:regex]
1906 - (CPRange)_characterRangeForIndex:(
unsigned)index asDefinedByLRegex:(JSObject)lregex andRRegex:(JSObject)rregex
1909 numberOfCharacters = [_layoutManager numberOfCharacters],
1910 string = [_textStorage string];
1913 for (var searchIndex = index - 1; searchIndex >= 0 && _regexMatchesStringAtIndex(lregex,
string, searchIndex); searchIndex--)
1914 wordRange.location = searchIndex;
1917 searchIndex = index + 1;
1919 while (searchIndex < numberOfCharacters && _regexMatchesStringAtIndex(rregex,
string, searchIndex))
1922 return _MakeRangeFromAbs(wordRange.location, MIN(MAX(0, numberOfCharacters), searchIndex));
1925 - (CPRange)selectionRangeForProposedRange:(CPRange)proposedRange granularity:(CPSelectionGranularity)granularity
1927 var textStorageLength = [_layoutManager numberOfCharacters];
1929 if (textStorageLength == 0)
1932 if (proposedRange.location >= textStorageLength)
1933 proposedRange =
CPMakeRange(textStorageLength, 0);
1935 if (
CPMaxRange(proposedRange) > textStorageLength)
1936 proposedRange.length = textStorageLength - proposedRange.location;
1938 var
string = [_textStorage string],
1941 lloc = proposedRange.location,
1944 switch (granularity)
1947 lregex = _isWhitespaceCharacter([
string characterAtIndex:lloc])? [[
self class] _whitespaceRegex] : [[
self class] _wordBoundaryRegex];
1948 rregex = _isWhitespaceCharacter([
string characterAtIndex:
CPMaxRange(proposedRange)])? [[
self class] _whitespaceRegex] : [[
self class] _wordBoundaryRegex];
1951 lregex = rregex = [[
self class] _paragraphBoundaryRegex];
1954 if (lloc > 0 && _isNewlineCharacter([
string characterAtIndex:lloc]) &&
1955 !_isNewlineCharacter([
string characterAtIndex:lloc - 1]))
1958 if (rloc > 0 && _isNewlineCharacter([
string characterAtIndex:rloc]))
1963 return proposedRange;
1966 var granularRange = [
self _characterRangeForIndex:lloc
1967 asDefinedByLRegex:lregex
1970 if (proposedRange.length == 0 && _isNewlineCharacter([
string characterAtIndex:proposedRange.location]))
1971 return _MakeRangeFromAbs(_isNewlineCharacter([
string characterAtIndex:lloc])? proposedRange.location : granularRange.location, proposedRange.location + 1);
1973 if (proposedRange.length)
1974 granularRange =
CPUnionRange(granularRange, [
self _characterRangeForIndex:rloc
1975 asDefinedByLRegex:lregex
1980 granularRange.length++;
1982 return granularRange;
1987 return (_selectionRange.length === 0 && [
self _isFocused]);
1990 - (void)updateInsertionPointStateAndRestartTimer:(BOOL)flag
1993 numberOfGlyphs = [_layoutManager numberOfCharacters];
1995 if (_selectionRange.length)
1996 [_caret setVisibility:NO];
1998 if (_selectionRange.location >= numberOfGlyphs)
2000 caretRect = [_layoutManager boundingRectForGlyphRange:CPMakeRange(MAX(0,_selectionRange.location - 1), 1) inTextContainer:_textContainer];
2002 if (!numberOfGlyphs)
2004 var font = [_typingAttributes objectForKey:CPFontAttributeName] || [
self font];
2006 caretRect.
size.height = [font size];
2007 caretRect.origin.y = ([font ascender] - [font descender]) * 0.5 + _textContainerOrigin.y;
2010 caretRect.origin.x += caretRect.size.width;
2012 if (_selectionRange.location > 0 && [[_textStorage
string] characterAtIndex:_selectionRange.location - 1] ===
'\n')
2014 caretRect.origin.y += caretRect.size.height;
2015 caretRect.origin.x = 0;
2019 caretRect = [_layoutManager boundingRectForGlyphRange:CPMakeRange(_selectionRange.location, 1) inTextContainer:_textContainer];
2021 var loc = (_selectionRange.location === numberOfGlyphs && numberOfGlyphs > 0) ? _selectionRange.location - 1 : _selectionRange.location,
2022 caretOffset = [_layoutManager _characterOffsetAtLocation:loc],
2023 oldYPosition = CGRectGetMaxY(caretRect),
2024 caretDescend = [_layoutManager _descentAtLocation:loc];
2026 if (caretOffset > 0)
2028 caretRect.origin.y += caretOffset;
2029 caretRect.size.height = oldYPosition - caretRect.origin.y;
2031 if (caretDescend < 0)
2032 caretRect.size.height -= caretDescend;
2034 caretRect.origin.x += _textContainerOrigin.x;
2035 caretRect.origin.y += _textContainerOrigin.y;
2036 caretRect.size.width = 1;
2038 [_caret setRect:caretRect];
2041 [_caret startBlinking];
2047 location = [
self _characterIndexFromRawPoint:CGPointCreateCopy(point)];
2050 [_caret _drawCaretAtLocation:_movingSelection.location];
2051 [_caret setVisibility:YES];
2055 #pragma mark Dragging operation 2064 [_caret setVisibility:NO];
2069 _movingSelection = nil;
2073 if (_movingSelection.location >
CPMaxRange(_selectionRange))
2074 _movingSelection.location -= _selectionRange.length;
2076 [
self _deleteForRange:_selectionRange];
2079 var dataForPasting = [pasteboard stringForType:CPRTFPboardType] || [pasteboard stringForType:CPStringPboardType];
2082 setTimeout(
function(){
2084 if ([dataForPasting hasPrefix:
"{\\rtf"])
2085 [
self insertText:[[_CPRTFParser
new] parseRTF:dataForPasting]];
2101 return [
super isEditable] && !_placeholderString;
2104 - (void)_setPlaceholderString:(
CPString)aString
2106 if (_placeholderString === aString)
2109 _placeholderString = aString;
2114 - (void)_continuouslyReverseSetBinding
2116 var binderClass = [[
self class] _binderClassForBinding:CPAttributedStringBinding] ||
2117 [[
self class] _binderClassForBinding:CPValueBinding],
2118 theBinding = [binderClass getBinding:CPAttributedStringBinding forObject:self] || [binderClass getBinding:CPValueBinding forObject:self];
2120 if ([theBinding continuouslyUpdatesValue])
2121 [theBinding reverseSetValueFor:@"objectValue"];
2124 - (void)_reverseSetBinding
2126 var binderClass = [[
self class] _binderClassForBinding:CPAttributedStringBinding] ||
2127 [[
self class] _binderClassForBinding:CPValueBinding],
2128 theBinding = [binderClass getBinding:CPAttributedStringBinding forObject:self] || [binderClass getBinding:CPValueBinding forObject:self];
2130 [theBinding reverseSetValueFor:@"objectValue"];
2138 - (BOOL)_delegateRespondsToShouldChangeTypingAttributesToAttributes
2143 - (BOOL)_delegateRespondsToWillChangeSelectionFromCharacterRangeToCharacterRange
2148 - (BOOL)_sendDelegateDoCommandBySelector:(
SEL)aSelector
2153 return [_delegate textView:self doCommandBySelector:aSelector];
2156 - (BOOL)_sendDelegateTextShouldBeginEditing
2161 return [_delegate textShouldBeginEditing:self];
2164 - (BOOL)_sendDelegateShouldChangeTextInRange:(CPRange)aRange replacementString:(
CPString)aString
2169 return [_delegate textView:self shouldChangeTextInRange:aRange replacementString:aString];
2177 return [_delegate textView:self shouldChangeTypingAttributes:typingAttributes toAttributes:attributes];
2180 - (CPRange)_sendDelegateWillChangeSelectionFromCharacterRange:(CPRange)selectionRange toCharacterRange:(CPRange)range
2185 return [_delegate textView:self willChangeSelectionFromCharacterRange:selectionRange toCharacterRange:range];
2213 enumerator = [selectedTextAttributes keyEnumerator],
2216 while (key = [enumerator nextObject])
2217 [_selectedTextAttributes setObject:[selectedTextAttributes valueForKey:key] forKey:key];
2222 [
self setAllowsUndo:[aCoder decodeBoolForKey:CPTextViewAllowsUndoKey]];
2223 [
self setUsesFontPanel:[aCoder decodeBoolForKey:CPTextViewUsesFontPanelKey]];
2225 [
self setDelegate:[aCoder decodeObjectForKey:CPTextViewDelegateKey]];
2227 var container = [aCoder decodeObjectForKey:CPTextViewContainerKey];
2228 [container setTextView:self];
2230 _typingAttributes = [[_textStorage attributesAtIndex:0 effectiveRange:nil] copy];
2233 [_typingAttributes setObject:[
CPColor blackColor] forKey:CPForegroundColorAttributeName];
2235 _textColor = [_typingAttributes valueForKey:CPForegroundColorAttributeName];
2236 [
self setFont:[_typingAttributes valueForKey:CPFontAttributeName]];
2248 [aCoder encodeObject:_delegate forKey:CPTextViewDelegateKey];
2249 [aCoder encodeObject:_textContainer forKey:CPTextViewContainerKey];
2250 [aCoder encodeObject:_insertionPointColor forKey:CPTextViewInsertionPointColorKey];
2251 [aCoder encodeObject:_selectedTextAttributes forKey:CPTextViewSelectedTextAttributesKey];
2252 [aCoder encodeBool:_allowsUndo forKey:CPTextViewAllowsUndoKey];
2253 [aCoder encodeBool:_usesFontPanel forKey:CPTextViewUsesFontPanelKey];
2259 @implementation _CPSelectionBox :
CPObject 2261 DOMElement _selectionBoxDOM;
2267 - (id)initWithTextView:(
CPTextView)aTextView rect:(CGRect)aRect color:(
CPColor)aColor
2269 if (
self = [super
init])
2271 _textView = aTextView;
2276 _textView._DOMElement.appendChild(_selectionBoxDOM);
2282 - (void)removeFromTextView
2284 _textView._DOMElement.removeChild(_selectionBoxDOM);
2291 _selectionBoxDOM = document.createElement(
"span");
2292 _selectionBoxDOM.style.position =
"absolute";
2293 _selectionBoxDOM.style.visibility =
"visible";
2294 _selectionBoxDOM.style.padding =
"0px";
2295 _selectionBoxDOM.style.margin =
"0px";
2296 _selectionBoxDOM.style.whiteSpace =
"pre";
2299 _selectionBoxDOM.style.width = (_rect.size.width) +
"px";
2300 _selectionBoxDOM.style.left = (_rect.origin.x) +
"px";
2301 _selectionBoxDOM.style.top = (_rect.origin.y) +
"px";
2302 _selectionBoxDOM.style.height = (_rect.size.height) +
"px";
2303 _selectionBoxDOM.style.zIndex = -1000;
2304 _selectionBoxDOM.oncontextmenu = _selectionBoxDOM.onmousedown = _selectionBoxDOM.onselectstart =
function () {
return false; };
2312 @implementation _CPCaret :
CPObject 2315 BOOL _permanentlyVisible;
2319 DOMElement _caretDOM;
2322 - (void)setRect:(CGRect)aRect
2324 _rect = CGRectCreateCopy(aRect);
2327 _caretDOM.style.left = (aRect.origin.x) +
"px";
2328 _caretDOM.style.top = (aRect.origin.y) +
"px";
2329 _caretDOM.style.height = (aRect.size.height) +
"px";
2335 if (
self = [super
init])
2342 _caretDOM = document.createElement(
"span");
2343 style = _caretDOM.style;
2344 style.position =
"absolute";
2345 style.visibility =
"visible";
2346 style.padding =
"0px";
2347 style.margin =
"0px";
2348 style.whiteSpace =
"pre";
2349 style.backgroundColor =
"black";
2350 _caretDOM.style.width =
"1px";
2352 _textView._DOMElement.appendChild(_caretDOM);
2360 - (void)setVisibility:(BOOL)visibilityFlag
stop:(BOOL)stopFlag
2364 _caretDOM.style.visibility = visibilityFlag ?
"visible" :
"hidden";
2367 if (!visibilityFlag && stopFlag)
2368 [
self stopBlinking];
2371 - (void)setVisibility:(BOOL)visibilityFlag
2373 [
self setVisibility:visibilityFlag stop:YES];
2376 - (void)_blinkCaret:(
CPTimer)aTimer
2378 _drawCaret = (!_drawCaret) || _permanentlyVisible;
2379 [_textView setNeedsDisplayInRect:_rect];
2382 - (void)startBlinking
2394 return [_caretTimer isValid];
2397 - (void)stopBlinking
2403 [_caretTimer invalidate];
2408 - (void)_drawCaretAtLocation:(
int)aLoc
2410 var rect = [_textView._layoutManager boundingRectForGlyphRange:CPMakeRange(aLoc, 1) inTextContainer:_textView._textContainer];
2412 if (aLoc >= [_textView._layoutManager numberOfCharacters])
2413 rect.origin.x = CGRectGetMaxX(rect)
2415 [
self setRect:rect];
2421 var _CPNativeInputField,
2422 _CPNativeInputFieldKeyDownCalled,
2423 _CPNativeInputFieldKeyUpCalled,
2424 _CPNativeInputFieldKeyPressedCalled,
2425 _CPNativeInputFieldActive;
2427 var _CPCopyPlaceholder =
'-';
2428 @implementation _CPNativeInputManager :
CPObject 2433 + (BOOL)isNativeInputFieldActive
2435 return _CPNativeInputFieldActive;
2438 + (void)cancelCurrentNativeInputSession
2442 _CPNativeInputField.innerHTML =
'';
2445 [
self _endInputSessionWithString:_CPNativeInputField.innerHTML];
2448 + (void)cancelCurrentInputSessionIfNeeded
2450 if (!_CPNativeInputFieldActive)
2453 [
self cancelCurrentNativeInputSession];
2456 + (void)_endInputSessionWithString:(
CPString)aStr
2458 _CPNativeInputFieldActive = NO;
2460 var currentFirstResponder = [[CPApp keyWindow] firstResponder],
2463 [currentFirstResponder setSelectedRange:placeholderRange];
2464 [currentFirstResponder insertText:aStr];
2465 _CPNativeInputField.innerHTML =
'';
2468 [
self hideInputElement];
2469 [currentFirstResponder updateInsertionPointStateAndRestartTimer:YES];
2475 _CPNativeInputField = document.createElement(
"div");
2476 _CPNativeInputField.contentEditable = YES;
2477 _CPNativeInputField.style.width =
"64px";
2478 _CPNativeInputField.style.zIndex = 10000;
2479 _CPNativeInputField.style.position =
"absolute";
2480 _CPNativeInputField.style.visibility =
"visible";
2481 _CPNativeInputField.style.padding =
"0px";
2482 _CPNativeInputField.style.margin =
"0px";
2483 _CPNativeInputField.style.whiteSpace =
"pre";
2484 _CPNativeInputField.style.outline =
"0px solid transparent";
2486 document.body.appendChild(_CPNativeInputField);
2488 _CPNativeInputField.addEventListener(
"keyup",
function(e)
2490 _CPNativeInputFieldKeyUpCalled = YES;
2494 if (e.which < 27 || e.which == 91 || e.which == 93)
2497 _CPNativeInputField.innerHTML =
'';
2499 if (_CPNativeInputField.innerHTML.length == 0 || _CPNativeInputField.innerHTML.length > 2)
2500 [self cancelCurrentInputSessionIfNeeded];
2505 var currentFirstResponder = [[
CPApp keyWindow] firstResponder];
2507 if (![currentFirstResponder respondsToSelector:
@selector(_activateNativeInputElement:)])
2510 var charCode = _CPNativeInputField.innerHTML.charCodeAt(0);
2513 if (charCode == 229 || charCode == 197)
2515 [currentFirstResponder insertText:_CPNativeInputField.innerHTML];
2516 _CPNativeInputField.innerHTML =
'';
2521 if (!_CPNativeInputFieldActive && _CPNativeInputFieldKeyPressedCalled == NO && _CPNativeInputField.innerHTML.length && _CPNativeInputField.innerHTML != _CPCopyPlaceholder && _CPNativeInputField.innerHTML.length < 3)
2523 _CPNativeInputFieldActive = YES;
2524 [currentFirstResponder _activateNativeInputElement:_CPNativeInputField];
2528 if (_CPNativeInputFieldActive)
2529 [
self _endInputSessionWithString:_CPNativeInputField.innerHTML];
2532 if (_CPNativeInputFieldKeyPressedCalled)
2533 _CPNativeInputField.innerHTML =
'';
2536 _CPNativeInputFieldKeyDownCalled = NO;
2541 _CPNativeInputField.addEventListener(
"keydown",
function(e)
2544 if (_CPNativeInputFieldKeyDownCalled)
2547 _CPNativeInputFieldKeyDownCalled = YES;
2548 _CPNativeInputFieldKeyUpCalled = NO;
2549 _CPNativeInputFieldKeyPressedCalled = NO;
2550 var currentFirstResponder = [[CPApp keyWindow] firstResponder];
2554 _CPNativeInputFieldKeyPressedCalled = YES;
2556 if (![currentFirstResponder respondsToSelector:
@selector(_activateNativeInputElement:)])
2561 setTimeout(
function(){
2562 _CPNativeInputFieldKeyDownCalled = NO;
2564 if (!_CPNativeInputFieldActive && _CPNativeInputFieldKeyUpCalled == NO && _CPNativeInputField.innerHTML.length && _CPNativeInputField.innerHTML != _CPCopyPlaceholder && _CPNativeInputField.innerHTML.length < 3 && !e.repeat)
2566 _CPNativeInputFieldActive = YES;
2567 [currentFirstResponder _activateNativeInputElement:_CPNativeInputField];
2569 else if (!_CPNativeInputFieldActive)
2570 [
self hideInputElement];
2576 _CPNativeInputField.addEventListener(
"keypress",
function(e)
2578 _CPNativeInputFieldKeyUpCalled = YES;
2579 _CPNativeInputFieldKeyPressedCalled = YES;
2584 _CPNativeInputField.onpaste =
function(e)
2586 var nativeClipboard = (e.originalEvent || e).clipboardData,
2589 currentFirstResponder = [[
CPApp keyWindow] firstResponder],
2592 if ([currentFirstResponder respondsToSelector:
@selector(
isRichText)] && ![currentFirstResponder isRichText])
2596 if ((richtext = nativeClipboard.getData(
'text/rtf')) && !(!!
window.event.shiftKey) && !isPlain)
2601 setTimeout(
function(){
2602 [currentFirstResponder insertText:[[_CPRTFParser new] parseRTF:richtext]]
2610 var data = e.clipboardData.getData(
'text/plain'),
2611 cappString = [pasteboard stringForType:CPStringPboardType];
2613 if (cappString != data)
2615 [pasteboard declareTypes:[CPStringPboardType] owner:nil];
2616 [pasteboard setString:data forType:CPStringPboardType];
2619 setTimeout(
function(){
2620 [currentFirstResponder paste:self];
2628 _CPNativeInputField.oncopy =
function(e)
2632 currentFirstResponder = [[CPApp keyWindow] firstResponder];
2634 [currentFirstResponder copy:self];
2636 var stringForPasting = [pasteboard stringForType:CPStringPboardType];
2637 e.clipboardData.setData(
'text/plain', stringForPasting);
2642 _CPNativeInputField.oncut =
function(e)
2646 currentFirstResponder = [[CPApp keyWindow] firstResponder];
2649 setTimeout(
function(){
2650 [currentFirstResponder cut:self];
2654 [currentFirstResponder copy:self];
2656 var stringForPasting = [pasteboard stringForType:CPStringPboardType];
2658 e.clipboardData.setData(
'text/plain', stringForPasting);
2666 + (void)focusForTextView:(
CPTextView)currentFirstResponder
2668 if (![currentFirstResponder respondsToSelector:
@selector(_activateNativeInputElement:)])
2671 [
self hideInputElement];
2674 _CPNativeInputField.focus();
2679 + (void)focusForClipboardOfTextView:(
CPTextView)textview
2683 if (!_CPNativeInputFieldActive && _CPNativeInputField.innerHTML.length == 0)
2684 _CPNativeInputField.innerHTML = _CPCopyPlaceholder;
2686 [
self focusForTextView:textview];
2689 if (document.body.createTextRange)
2691 var range = document.body.createTextRange();
2693 range.moveToElementText(_CPNativeInputField);
2696 else if (
window.getSelection)
2698 var selection =
window.getSelection(),
2699 range = document.createRange();
2701 range.selectNodeContents(_CPNativeInputField);
2702 selection.removeAllRanges();
2703 selection.addRange(range);
2709 + (void)hideInputElement
2713 _CPNativeInputField.style.top =
"-10000px";
2714 _CPNativeInputField.style.left =
"-10000px";
2720 @implementation _CPTextViewValueBinder : _CPTextFieldValueBinder
2725 - (void)setPlaceholderValue:(
id)aValue withMarker:(
CPString)aMarker forBinding:(
CPString)aBinding
2727 [_source _setPlaceholderString:aValue];
2730 - (void)setValue:(
id)aValue forBinding:(
CPString)aBinding
2732 if (aValue === nil || (aValue.isa && [aValue isMemberOfClass:
CPNull]))
2733 [_source _setPlaceholderString:[
self _placeholderForMarker:
CPNullMarker]];
2735 [_source _setPlaceholderString:nil];
2737 [_source setObjectValue:aValue];
2758 - (void)setAllowsUndo:(BOOL)aValue
2760 _allowsUndo = aValue;
2768 return _isHorizontallyResizable;
2774 - (void)setHorizontallyResizable:(BOOL)aValue
2776 _isHorizontallyResizable = aValue;
2784 return _isVerticallyResizable;
2790 - (void)setVerticallyResizable:(BOOL)aValue
2792 _isVerticallyResizable = aValue;
2800 return _usesFontPanel;
2806 - (void)setUsesFontPanel:(BOOL)aValue
2808 _usesFontPanel = aValue;
2816 return _textContainerOrigin;
2830 - (void)setMinSize:(CGSize)aValue
2846 - (void)setMaxSize:(CGSize)aValue
2856 return _textContainerInset;
2862 - (void)setTextContainerInset:(CGSize)aValue
2864 _textContainerInset = aValue;
2872 return _insertionPointColor;
2880 _insertionPointColor = aValue;
2896 _textColor = aValue;
2904 return _selectedTextAttributes;
2912 _selectedTextAttributes = aValue;
2920 return _typingAttributes;
2928 _typingAttributes = aValue;
2936 return _layoutManager;
2944 return _selectionRange;
2952 return _selectionGranularity;
2958 - (void)setSelectionGranularity:(CPSelectionGranularity)aValue
2960 _selectionGranularity = aValue;
2968 return _textContainer;
2976 _textContainer = aValue;
2984 return _textStorage;
void setFrameSize:(CGSize aSize)
void encodeWithCoder:(CPCoder aCoder)
CPPasteboard draggingPasteboard()
BOOL becomeFirstResponder()
void mouseDragged:(CPEvent event)
void dragView:at:offset:event:pasteboard:source:slideBack:(CPView aView, [at] CGPoint aLocation, [offset] CGSize mouseOffset, [event] CPEvent anEvent, [pasteboard] CPPasteboard aPasteboard, [source] id aSourceObject, [slideBack] BOOL slideBack)
var CPTextViewUsesFontPanelKey
function CPUnionRange(lhsRange, rhsRange)
var kDelegateRespondsTo_textView_willChangeSelectionFromCharacterRange_toCharacterRange
void scrollRangeToVisible:(CPRange aRange)
void addAttribute:value:range:(CPString anAttribute, [value] id aValue, [range] CPRange aRange)
An object representation of nil.
var kDelegateRespondsTo_textView_shouldChangeTextInRange_replacementString
CPFont systemFontOfSize:(CGSize aSize)
id initWithFrame:textContainer:(CGRect aFrame, [textContainer] CPTextContainer aContainer)
void setAllowsUndo:(BOOL aValue)
void moveToRightEndOfLineAndModifySelection:(id sender)
var CPTextViewTextStorageKey
void moveToRightEndOfLine:byExtending:(id sender, [byExtending] BOOL flag)
The main run loop for the application.
var kDelegateRespondsTo_textView_didChangeTypingAttributes
void addObserver:selector:name:object:(id anObserver, [selector] SEL aSelector, [name] CPString aNotificationName, [object] id anObject)
void performSelector:target:argument:order:modes:(SEL aSelector, [target] id aTarget, [argument] id anArgument, [order] int anOrder, [modes] CPArray modes)
CPResponder firstResponder()
CGPoint locationInWindow()
void setInsertionPointColor:(CPColor aValue)
void moveToEndOfParagraphAndModifySelection:(id sender)
void postNotificationName:object:(CPString aNotificationName, [object] id anObject)
CPForegroundColorAttributeName
id initWithContainerSize:(CGSize aSize)
Unarchives objects created using CPKeyedArchiver.
CPColor backgroundColor()
CPTextContainer textContainer()
CPNotificationCenter defaultCenter()
A mutable key-value pair collection.
CPRunLoop currentRunLoop()
void setSelectedRange:(CPRange range)
void setUsesFontPanel:(BOOL aValue)
id initWithCoder:(CPCoder aCoder)
CPAttributedString attributedSubstringFromRange:(CPRange aRange)
var kDelegateRespondsTo_textShouldBeginEditing
A mutable character string with attributes.
CPDictionary typingAttributes()
void setDelegate:(id< CPTextViewDelegate > aDelegate)
var CPTextViewInsertionPointColorKey
void viewWillMoveToSuperview:(CPView aView)
FrameUpdater prototype stop
CPTextStorage textStorage()
var CPTextViewSelectedTextAttributesKey
BOOL becomeFirstResponder()
id initWithName:object:userInfo:(CPString aNotificationName, [object] id anObject, [userInfo] CPDictionary aUserInfo)
function CPEmptyRange(aRange)
void setSelectionGranularity:(CPSelectionGranularity aValue)
function CPMaxRange(aRange)
An immutable string (collection of characters).
CGPoint convertPoint:fromView:(CGPoint aPoint, [fromView] CPView aView)
CPUndoManager undoManager()
id objectForKey:(id aKey)
if(CPFeatureIsCompatible(CPHTMLCanvasFeature))
void moveDown:(id sender)
CPColor insertionPointColor()
var kDelegateRespondsTo_textView_shouldChangeTypingAttributes_toAttributes
void invalidateTextContainerOrigin()
BOOL isVerticallyResizable()
CPColor colorWithRed:green:blue:alpha:(float red, [green] float green, [blue] float blue, [alpha] float alpha)
CPSelectionGranularity selectionGranularity()
void setNeedsDisplay:(BOOL aFlag)
CPBackgroundColorAttributeName
var CPTextViewDelegateKey
function CPIntersectionRange(lhsRange, rhsRange)
CPLayoutManager layoutManager()
CPSelectionGranularity selectionGranularity()
CPFontManager sharedFontManager()
A notification that can be posted to a CPNotificationCenter.
CPTimer scheduledTimerWithTimeInterval:target:selector:userInfo:repeats:(CPTimeInterval seconds, [target] id aTarget, [selector] SEL aSelector, [userInfo] id userInfo, [repeats] BOOL shouldRepeat)
void insertLineBreak:(id sender)
void setSelectable:(BOOL flag)
BOOL isKindOfClass:(Class aClass)
CPUnderlineStyleAttributeName
BOOL acceptsFirstResponder()
CGPoint draggingLocation()
void setTypingAttributes:(CPDictionary attributes)
BOOL isHorizontallyResizable()
function CPMakeRangeCopy(aRange)
void moveWordRight:(id sender)
void setTextColor:range:(CPColor aColor, [range] CPRange range)
void moveToLeftEndOfLine:byExtending:(id sender, [byExtending] BOOL flag)
CPTextStorage textStorage()
A timer object that can send a message after the given time interval.
Defines methods for use when archiving & restoring (enc/decoding).
CPColor selectedTextBackgroundColor()
void setFont:(CPFont font)
CPDictionary selectedTextAttributes()
id numberWithInt:(int anInt)
void setSelectedRange:affinity:stillSelecting:(CPRange range, [affinity] CPSelectionAffinity affinity, [stillSelecting] BOOL selecting)
id unarchiveObjectWithData:(CPData aData)
void insertText:(CPString aString)
Sends messages (CPNotification) between objects.
function CPLocationInRange(aLocation, aRange)
void drawRect:(CGRect aRect)
id prepareWithInvocationTarget:(id aTarget)
void setBackgroundColor:(CPColor aColor)
var kDelegateRespondsTo_textView_textDidChange
void setTextView:(CPTextView aTextView)
void moveToLeftEndOfLineAndModifySelection:(id sender)
BOOL needsPanelToBecomeKey()
void setFrameSize:(CGSize aSize)
void removeObserver:name:object:(id anObserver, [name] CPString aNotificationName, [object] id anObject)
var kDelegateRespondsTo_textView_doCommandBySelector
CPRange selectionRangeForProposedRange:granularity:(CPRange proposedRange, [granularity] CPSelectionGranularity granularity)
CPAttributedStringBinding
var CPTextViewLayoutManagerKey
void moveToBeginningOfParagraphAndModifySelection:(id sender)
void deleteBackward:ignoreSmart:(id sender, [ignoreSmart] BOOL ignoreFlag)
BOOL resignFirstResponder()
function CPBrowserIsEngine(anEngine)
void moveLeft:(id sender)
void moveWordLeftAndModifySelection:(id sender)
void drawInsertionPointInRect:color:turnedOn:(CGRect aRect, [color] CPColor aColor, [turnedOn] BOOL flag)
void moveWordLeft:(id sender)
void setSelectedFont:isMultiple:(CPFont aFont, [isMultiple] BOOL aFlag)
BOOL shouldDrawInsertionPoint()
A bridged object to native Javascript numbers.
BOOL scrollRectToVisible:(CGRect aRect)
void moveWordRightAndModifySelection:(id sender)
id< CPTextViewDelegate > _delegate accessors(property=delegate)
void updateInsertionPointStateAndRestartTimer:(BOOL flag)
void deleteBackward:(id sender)
id initWithObjects:forKeys:(CPArray objects, [forKeys] CPArray keyArray)
void setEditable:(BOOL flag)
void moveLeftAndModifySelection:(id sender)
CPSelectionAffinity selectionAffinity()
CPRange function CPMakeRange(location, length)
CGSize textContainerInset()
void insertTab:(id sender)
void setFont:range:(CPFont font, [range] CPRange range)
id pasteboardWithName:(CPString aName)
void setString:(id aString)
void registerForDraggedTypes:(CPArray pasteboardTypes)
void setRichText:(BOOL aValue)
CPDictionary typingAttributes()
var CPTextViewContainerKey
id dictionaryWithObject:forKey:(id anObject, [forKey] id aKey)
var kDelegateRespondsTo_textView_didChangeSelection
var CPTextViewAllowsUndoKey
FrameUpdater prototype description
CGPoint textContainerOrigin()