Fixed: attachment support was missing in CPTextView (#2872)

This commit is contained in:
daboe01
2019-12-19 09:08:33 +01:00
committed by Martin Carlberg
parent 2d96b06d4c
commit 9e289574ff
8 changed files with 202 additions and 123 deletions
+1
View File
@@ -46,6 +46,7 @@ CPImagesPboardType = @"CPImagesPboardType";
CPVideosPboardType = @"CPVideosPboardType";
CPRTFPboardType = @"CPRTFPboardType";
_CPSmartPboardType = @"_CPSmartPboardType";
_CPASPboardType = @"_CPASPboardType";
UTF8PboardType = @"public.utf8-plain-text";
+5 -1
View File
@@ -179,7 +179,11 @@ CPKernAttributeName = @"CPKernAttributeName";
{
var pasteboard = [CPPasteboard generalPasteboard],
dataForPasting = [pasteboard stringForType:CPRTFPboardType],
stringForPasting = [pasteboard stringForType:CPStringPboardType];
stringForPasting = [pasteboard stringForType:CPStringPboardType],
attributedStringData = [pasteboard stringForType:_CPASPboardType];
if ([self isRichText] && attributedStringData)
return [CPKeyedUnarchiver unarchiveObjectWithData:[CPData dataWithRawString:attributedStringData]];
if (dataForPasting || [stringForPasting hasPrefix:"{\\rtf1\\ansi"])
stringForPasting = [[_CPRTFParser new] parseRTF:dataForPasting ? dataForPasting : stringForPasting];
+51 -24
View File
@@ -259,6 +259,9 @@ _oncontextmenuhandler = function () { return false; };
{
if (_lineFragments[i]._isInvalid)
{
while (i > 0 && !_lineFragments[i - 1]._isLast)
i--;
startIndex = _lineFragments[i]._range.location;
removeRange.location = i;
removeRange.length = l - i;
@@ -361,7 +364,7 @@ _oncontextmenuhandler = function () { return false; };
if (ABS(rangeOffset) !== ABS(newLength - oldLength))
return NO;
var verticalOffset = _lineFragments[targetLine]._fragmentRect.origin.y - _lineFragmentsForRescue[startLineForDOMRemoval]._fragmentRect.origin.y,
var verticalOffset = CGRectGetMaxY(_lineFragments[targetLine]._fragmentRect) - CGRectGetMaxY(_lineFragmentsForRescue[startLineForDOMRemoval]._fragmentRect),
l = _lineFragmentsForRescue.length,
newTargetLine = startLineForDOMRemoval + removalSkip;
@@ -661,12 +664,10 @@ _oncontextmenuhandler = function () { return false; };
{
var j = i;
while (--j > 0 && !_lineFragments[j]._isLast)
{
// body intentionally left empty
}
while (j > 0 && !_lineFragments[j - 1]._isLast)
j--;
return _lineFragments[j + 1];
return _lineFragments[j];
}
}
@@ -676,13 +677,16 @@ _oncontextmenuhandler = function () { return false; };
{
var l = _lineFragments.length;
if (location >= CPMaxRange(_lineFragments[l - 1]._range))
return _lineFragments[l - 1];
for (var i = 0; i < l; i++)
{
if (CPLocationInRange(location, _lineFragments[i]._range))
{
var j = i;
while (!_lineFragments[j]._isLast)
while (j < l && !_lineFragments[j]._isLast)
j++;
return _lineFragments[j];
@@ -925,15 +929,14 @@ _oncontextmenuhandler = function () { return false; };
var correctedRect = CGRectCreateCopy(frames[j]);
correctedRect.size.height -= frames[j]._descent;
correctedRect.origin.y -= frames[j]._descent;
if (!rect)
rect = CGRectCreateCopy(correctedRect);
else
rect = CGRectUnion(rect, correctedRect);
if (_isNewlineCharacter([[_textStorage string] characterAtIndex:MAX(0, CPMaxRange(selectedCharRange) - 1)]))
{
rect.size.width = containerSize.width - rect.origin.x;
}
}
}
@@ -1095,7 +1098,6 @@ var _objectsInRange = function(aList, aRange)
span = document.createElement("span");
span.oncontextmenu = span.onmousedown = span.onselectstart = _oncontextmenuhandler;
// span.contentEditable = true; // this unfortunately does not work to make native pasting work on safari
style = span.style;
style.position = "absolute";
@@ -1138,7 +1140,6 @@ var _objectsInRange = function(aList, aRange)
else if (CPFeatureIsCompatible(CPJavaScriptTextContentFeature))
span.textContent = aString;
//<!> FIXME aString.replace(/&/g,'&amp;')
return span;
#else
return nil;
@@ -1167,16 +1168,29 @@ var _objectsInRange = function(aList, aRange)
effectiveRange = attributes ? CPIntersectionRange(aRange, effectiveRange) : aRange;
var string = [textStorage._string substringWithRange:effectiveRange],
font = [textStorage font] || [CPFont systemFontOfSize:12.0],
underline = [attributes objectForKey:CPUnderlineStyleAttributeName] || CPUnderlineStyleNone ;
underline = [attributes objectForKey:CPUnderlineStyleAttributeName] || CPUnderlineStyleNone;
if ([attributes containsKey:CPFontAttributeName])
font = [attributes objectForKey:CPFontAttributeName];
// this is an attachment -> create a run for it
if (string === _CPAttachmentCharacterAsString)
{
if (![attributes objectForKey:_CPAttachmentInvisible])
{
var view = [attributes objectForKey:_CPAttachmentView],
viewCopy = [CPKeyedUnarchiver unarchiveObjectWithData:[CPKeyedArchiver archivedDataWithRootObject:view]],
elem = viewCopy._DOMElement,
run = {_range:CPMakeRangeCopy(effectiveRange), color:nil, font:nil, elem:elem, string:nil, view:viewCopy};
var color = [attributes objectForKey:CPForegroundColorAttributeName],
run = {_range:CPMakeRangeCopy(effectiveRange), color:color, font:font, elem:nil, string:string, underline:underline};
_runs.push(run);
}
}
else
{
var color = [attributes objectForKey:CPForegroundColorAttributeName],
font = [attributes objectForKey:CPFontAttributeName] || [textStorage font] || [CPFont systemFontOfSize:12.0],
run = {_range:CPMakeRangeCopy(effectiveRange), color:color, font:font, elem:nil, string:string};
_runs.push(run);
_runs.push(run);
}
if (!CPMaxRange(effectiveRange))
break;
@@ -1248,7 +1262,12 @@ var _objectsInRange = function(aList, aRange)
for (var i = 0; i < l; i++)
{
if (_runs[i].elem && _runs[i].DOMactive)
_textContainer._textView._DOMElement.removeChild(_runs[i].elem);
{
if (_runs[i].view)
[_runs[i].view removeFromSuperview];
else
_textContainer._textView._DOMElement.removeChild(_runs[i].elem);
}
_runs[i].elem = nil;
_runs[i].DOMactive = NO;
@@ -1266,9 +1285,7 @@ var _objectsInRange = function(aList, aRange)
var run = runs[i];
if (!run.elem && CPRectIntersectsRect([_textContainer._textView exposedRect], _fragmentRect))
{
run.elem=[self createDOMElementWithText:run.string andFont:run.font andColor:run.color andUnderline:run.underline];
}
run.elem = [self createDOMElementWithText:run.string andFont:run.font andColor:run.color andUnderline:run.underline];
if (run.DOMactive && !run.DOMpatched)
continue;
@@ -1285,14 +1302,21 @@ var _objectsInRange = function(aList, aRange)
run.elem.style.left = (orig.x) + "px";
run.elem.style.top = (orig.y) + "px";
if (run.view)
[run.view setFrameOrigin:orig];
if (!run.DOMactive)
_textContainer._textView._DOMElement.appendChild(run.elem);
{
if (run.view)
[self._textContainer._textView addSubview:run.view];
else
_textContainer._textView._DOMElement.appendChild(run.elem);
}
run.DOMactive = YES;
}
run.DOMpatched = NO;
}
}
@@ -1344,6 +1368,9 @@ var _objectsInRange = function(aList, aRange)
if (verticalOffset && _runs[i].elem)
{
if (_runs[i].view)
_runs[i].view._frame.origin.y += verticalOffset;
_runs[i].elem.top = (_runs[i].elem.top + verticalOffset) + 'px';
_runs[i].DOMpatched = YES;
}
+15 -1
View File
@@ -42,6 +42,11 @@ CPTextStorageDidProcessEditingNotification = @"CPTextStorageDidProcessEditingNot
@end
CPAttachmentCharacter = 65532; // "\ufffc";
_CPAttachmentCharacterAsString = String.fromCharCode(CPAttachmentCharacter);
_CPAttachmentView = "_CPAttachmentView";
_CPAttachmentInvisible = "_CPAttachmentInvisible";
var CPTextStorageDelegate_textStorageWillProcessEditing_ = 1 << 1,
CPTextStorageDelegate_textStorageDidProcessEditing_ = 1 << 2;
@@ -257,6 +262,15 @@ var CPTextStorageDelegate_textStorageWillProcessEditing_ = 1 << 1,
return [super attributedSubstringFromRange:aRange];
}
+ (id)attributedStringWithAttachment:(CPView)someView
{
var result = [[self alloc] initWithString:_CPAttachmentCharacterAsString];
[result setAttributes:@{_CPAttachmentView:someView} range:CPMakeRange(0, 1)];
return result;
}
@end
@@ -300,4 +314,4 @@ var CPTextStorageDelegate_textStorageWillProcessEditing_ = 1 << 1,
[super encodeWithCoder:aCoder];
}
@end
@end
+61 -50
View File
@@ -454,10 +454,11 @@ var kDelegateRespondsTo_textShouldBeginEditing
stringForPasting = [[self textStorage] attributedSubstringFromRange:CPMakeRangeCopy(selectedRange)],
richData = [_CPRTFProducer produceRTF:stringForPasting documentAttributes:@{}];
[pasteboard declareTypes:[CPStringPboardType, CPRTFPboardType] owner:nil];
[pasteboard setString:stringForPasting._string forType:CPStringPboardType];
[pasteboard declareTypes:[CPStringPboardType, CPRTFPboardType, _CPSmartPboardType, _CPASPboardType] owner:nil];
[pasteboard setString:[stringForPasting._string stringByReplacingOccurrencesOfString:_CPAttachmentCharacterAsString withString:''] forType:CPStringPboardType];
[pasteboard setString:richData forType:CPRTFPboardType];
[pasteboard setString:_previousSelectionGranularity + '' forType:_CPSmartPboardType];
[pasteboard setString:[[CPKeyedArchiver archivedDataWithRootObject:stringForPasting] rawString] forType:_CPASPboardType];
}
- (void)_pasteString:(id)stringForPasting
@@ -1093,6 +1094,17 @@ Sets the selection to a range of characters in response to user action.
return YES;
}
- (void)_hideRange:(CPRange)rangeToHide inDragPlaceholderString:(CPTextView)placeholderString
{
if (!rangeToHide.length)
return;
[placeholderString addAttribute:CPForegroundColorAttributeName
value:[CPColor colorWithRed:1 green:1 blue:1 alpha:0] // invisibleInk
range:rangeToHide];
[placeholderString addAttribute:_CPAttachmentInvisible value:YES range:rangeToHide];
}
#pragma mark -
#pragma mark Mouse Events
@@ -1112,31 +1124,35 @@ Sets the selection to a range of characters in response to user action.
// dragging the selection
if ([self selectionGranularity] == CPSelectByCharacter && CPLocationInRange(_startTrackingLocation, _selectionRange))
{
var lineBeginningIndex = [_layoutManager _firstLineFragmentForLineFromLocation:_selectionRange.location]._range.location,
placeholderRange = _MakeRangeFromAbs(lineBeginningIndex, CPMaxRange(_selectionRange)),
var visibleRange = [_layoutManager glyphRangeForBoundingRect:_exposedRect inTextContainer:_textContainer],
firstFragment = [_layoutManager _firstLineFragmentForLineFromLocation:_selectionRange.location],
lastFragment = [_layoutManager _lastLineFragmentForLineFromLocation:CPMaxRange(_selectionRange)],
lineBeginningIndex = firstFragment._range.location,
lineEndIndex = CPMaxRange(lastFragment._range),
placeholderRange = CPIntersectionRange(_MakeRangeFromAbs(lineBeginningIndex, lineEndIndex), visibleRange),
placeholderString = [_textStorage attributedSubstringFromRange:placeholderRange],
placeholderFrame = CGRectIntersection([_layoutManager boundingRectForGlyphRange:placeholderRange inTextContainer:_textContainer], _frame),
rangeToHide = CPMakeRange(0, _selectionRange.location - lineBeginningIndex),
rangeToHideLHS = CPMakeRange(0, _selectionRange.location - lineBeginningIndex),
rangeToHideRHS = _MakeRangeFromAbs(CPMaxRange(_selectionRange) - lineBeginningIndex, lineEndIndex - 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];
// hide the left/right parts of the first/last lines of the selection that are not included
[self _hideRange:rangeToHideLHS inDragPlaceholderString:placeholderString];
[self _hideRange:rangeToHideRHS inDragPlaceholderString:placeholderString];
_movingSelection = CPMakeRange(_startTrackingLocation, 0);
dragPlaceholder = [[CPTextView alloc] initWithFrame:placeholderFrame];
dragPlaceholder = [[CPTextView alloc] initWithFrame:_frame];
[dragPlaceholder._textStorage replaceCharactersInRange:CPMakeRange(0, 0) withAttributedString: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, CPStringPboardType] owner:nil];
[draggingPasteboard setString:richData forType:CPRTFPboardType];
[draggingPasteboard declareTypes:[_CPASPboardType, CPStringPboardType] owner:nil];
[draggingPasteboard setString:[[CPKeyedArchiver archivedDataWithRootObject:stringForPasting] rawString] forType:_CPASPboardType];
// this is necessary because the drag will not work without data of kind CPStringPboardType
[draggingPasteboard setString:stringForPasting._string forType:CPStringPboardType];
[self dragView:dragPlaceholder
@@ -2155,38 +2171,23 @@ Sets the selection to a range of characters in response to user action.
return (_selectionRange.length === 0 && [self _isFocused] && !_placeholderString);
}
- (void)updateInsertionPointStateAndRestartTimer:(BOOL)flag
- (CPRect)_getCaretRect
{
var caretRect,
numberOfGlyphs = [_layoutManager numberOfCharacters];
var numberOfGlyphs = [_layoutManager numberOfCharacters];
if (_selectionRange.length)
[_caret setVisibility:NO];
if (_selectionRange.location >= numberOfGlyphs) // cursor is "behind" the last chacacter
if (!numberOfGlyphs)
{
caretRect = [_layoutManager boundingRectForGlyphRange:CPMakeRange(MAX(0,_selectionRange.location - 1), 1) inTextContainer:_textContainer];
if (!numberOfGlyphs)
{
var font = [_typingAttributes objectForKey:CPFontAttributeName] || [self font];
caretRect.size.height = [font size];
caretRect.origin.y = ([font ascender] - [font descender]) * 0.5 + _textContainerOrigin.y;
}
caretRect.origin.x += caretRect.size.width;
if (_selectionRange.location > 0 && [[_textStorage string] characterAtIndex:_selectionRange.location - 1] === '\n')
{
caretRect.origin.y += caretRect.size.height;
caretRect.origin.x = 0;
}
var font = [_typingAttributes objectForKey:CPFontAttributeName] || [self font];
return CGRectMake(1, ([font ascender] - [font descender]) * 0.5 + _textContainerOrigin.y, 1, [font size]);
}
else
caretRect = [_layoutManager boundingRectForGlyphRange:CPMakeRange(_selectionRange.location, 1) inTextContainer:_textContainer];
var loc = (_selectionRange.location === numberOfGlyphs && numberOfGlyphs > 0) ? _selectionRange.location - 1 : _selectionRange.location,
// cursor is at a newline character -> jump to next line
if (_selectionRange.location == numberOfGlyphs && _isNewlineCharacter([[_textStorage string] characterAtIndex:_selectionRange.location - 1]))
return CGRectCreateCopy([_layoutManager extraLineFragmentRect]);
var caretRect = [_layoutManager boundingRectForGlyphRange:CPMakeRange(_selectionRange.location, 1) inTextContainer:_textContainer];
var loc = (_selectionRange.location == numberOfGlyphs) ? _selectionRange.location - 1 : _selectionRange.location,
caretOffset = [_layoutManager _characterOffsetAtLocation:loc],
oldYPosition = CGRectGetMaxY(caretRect),
caretDescend = [_layoutManager _descentAtLocation:loc];
@@ -2196,14 +2197,24 @@ Sets the selection to a range of characters in response to user action.
caretRect.origin.y += caretOffset;
caretRect.size.height = oldYPosition - caretRect.origin.y;
}
if (caretDescend < 0)
caretRect.size.height -= caretDescend;
if (_selectionRange.location == numberOfGlyphs)
caretRect.origin.x += caretRect.size.width;
caretRect.origin.x += _textContainerOrigin.x;
caretRect.origin.y += _textContainerOrigin.y;
caretRect.size.width = 1;
[_caret setRect:caretRect];
return caretRect;
}
- (void)updateInsertionPointStateAndRestartTimer:(BOOL)flag
{
if (_selectionRange.length)
[_caret setVisibility:NO];
[_caret setRect:[self _getCaretRect]];
if (flag)
[_caret startBlinking];
@@ -2215,6 +2226,10 @@ Sets the selection to a range of characters in response to user action.
location = [self _characterIndexFromRawPoint:CGPointCreateCopy(point)];
_movingSelection = CPMakeRange(location, 0);
if (CPLocationInRange(location, _selectionRange))
return;
[_caret _drawCaretAtLocation:_movingSelection.location];
[_caret setVisibility:YES];
}
@@ -2227,7 +2242,7 @@ Sets the selection to a range of characters in response to user action.
var location = [self convertPoint:[aSender draggingLocation] fromView:nil],
pasteboard = [aSender draggingPasteboard];
if ([pasteboard availableTypeFromArray:[CPRTFPboardType, CPStringPboardType]])
if ([pasteboard availableTypeFromArray:[_CPASPboardType]])
{
[_caret setVisibility:NO];
@@ -2244,15 +2259,10 @@ Sets the selection to a range of characters in response to user action.
[self _deleteForRange:_selectionRange];
[self setSelectedRange:_movingSelection];
var dataForPasting = [pasteboard stringForType:CPRTFPboardType] || [pasteboard stringForType:CPStringPboardType];
var stringForPasting = [CPKeyedUnarchiver unarchiveObjectWithData:[CPData dataWithRawString:[pasteboard stringForType:_CPASPboardType]]];
// setTimeout is to a work around a transaction issue with the undomanager
setTimeout(function(){
if ([dataForPasting hasPrefix:"{\\rtf"])
[self insertText:[[_CPRTFParser new] parseRTF:dataForPasting]];
else
[self insertText:dataForPasting];
[self insertText:stringForPasting];
}, 0);
}
@@ -2525,6 +2535,7 @@ var CPTextViewAllowsUndoKey = @"CPTextViewAllowsUndoKey",
style.whiteSpace = "pre";
style.backgroundColor = "black";
_caretDOM.style.width = "1px";
_caretDOM.style.zIndex = 10001;
_textView = aView;
_textView._DOMElement.appendChild(_caretDOM);
}
+44 -16
View File
@@ -199,13 +199,11 @@ var CPSystemTypesetterFactory,
[_layoutManager setLocation:CGPointMake(myX, _lineBase) forStartOfGlyphRange:lineRange];
[_layoutManager _setAdvancements:advancements forGlyphRange:lineRange];
if (!sameLine) //fix the _lineFragments when fontsizes differ
{
var l = _lineFragments.length;
//fix the _lineFragments when fontsizes differ
var l = _lineFragments.length;
for (var i = 0 ; i < l ; i++)
[_lineFragments[i] _adjustForHeight:_lineHeight];
}
for (var i = 0 ; i < l ; i++)
[_lineFragments[i] _adjustForHeight:_lineHeight];
if (!lineCount) // do not rescue on first line
return NO;
@@ -245,6 +243,7 @@ var CPSystemTypesetterFactory,
wrapWidth = 0,
isNewline = NO,
isTabStop = NO,
isAttachment = NO,
isWordWrapped = NO,
numberOfGlyphs= [_textStorage length],
leading,
@@ -322,6 +321,34 @@ var CPSystemTypesetterFactory,
switch (currentCharCode) // faster than sending actionForControlCharacterAtIndex: called for each char.
{
case CPAttachmentCharacter:
{
var attributes = [_textStorage attributesAtIndex:glyphIndex effectiveRange:nil],
view = [attributes objectForKey:_CPAttachmentView],
viewSize = view ? view._frame.size : CGSizeMake(0, 0);
rangeWidth = prevRangeWidth + viewSize.width; // undo sizing of dummy character
isAttachment = YES;
wrapRange = CPMakeRange(lineRange.location, lineRange.length - 1); // wrap before image
// prevent crash when image is larger than text container
if (viewSize.width > containerSizeWidth)
wrapRange.length++;
wrapWidth = rangeWidth;
wrapRange._height = _lineHeight;
wrapRange._base = _lineBase;
if (viewSize.height > _lineBase)
_lineBase = viewSize.height;
if (viewSize.height > _lineHeight)
_lineHeight = viewSize.height - descent + leading;
ascent = viewSize.height;
break;
}
case 9: // '\t'
{
var nextTab = [self textTabForWidth:rangeWidth + lineOrigin.x writingDirection:0];
@@ -346,7 +373,6 @@ var CPSystemTypesetterFactory,
}
advancements.push({width: rangeWidth - prevRangeWidth, height: ascent, descent: descent});
prevRangeWidth = _lineWidth = rangeWidth;
if (lineOrigin.x + rangeWidth > containerSizeWidth)
@@ -364,16 +390,13 @@ var CPSystemTypesetterFactory,
glyphIndex = CPMaxRange(lineRange) - 1; // start the line starts directly at current character
}
if (isNewline || isTabStop)
if (isNewline || isTabStop || isAttachment)
{
if ([self _flushRange:lineRange lineOrigin:lineOrigin currentContainer:_currentTextContainer advancements:advancements lineCount:numLines sameLine:!isNewline])
return;
if (isTabStop)
{
if (isTabStop || isAttachment)
lineOrigin.x += rangeWidth;
isTabStop = NO;
}
if (isNewline)
{
@@ -404,6 +427,9 @@ var CPSystemTypesetterFactory,
_lineBase = ascent;
}
isTabStop = NO;
isAttachment = NO;
isWordWrapped = NO;
_lineWidth = 0;
advancements = [];
currentAnchor = 0;
@@ -412,18 +438,20 @@ var CPSystemTypesetterFactory,
measuringRange = CPMakeRange(glyphIndex + 1, 0);
wrapRange = CPMakeRange(0, 0);
wrapWidth = 0;
isWordWrapped = NO;
}
}
// this is to "flush" the remaining characters
if (lineRange.length)
{
[self _flushRange:lineRange lineOrigin:lineOrigin currentContainer:_currentTextContainer advancements:advancements lineCount:numLines sameLine:NO];
}
var rect = CGRectMake(0, lineOrigin.y, containerSizeWidth, [_layoutManager._lineFragments lastObject]._usedRect.size.height - descent);
var rect = CGRectMake(1, lineOrigin.y - descent, containerSizeWidth, currentFontLineHeight);
[_layoutManager setExtraLineFragmentRect:rect usedRect:rect textContainer:_currentTextContainer];
var fragment = [_layoutManager._lineFragments lastObject];
if (fragment)
fragment._isLast = YES;
}
@end
-6
View File
@@ -28,12 +28,6 @@
[[theWindow contentView] addSubview:textView];
var button = [[CPButton alloc] initWithFrame:CGRectMake(400,10,75,25)];
[button setTitle:@"Underline"];
[button setTarget:textView];
[button setAction:@selector(underline:)];
[[theWindow contentView] addSubview:button];
delegateSpy = spy(self);
}
+25 -25
View File
@@ -101,36 +101,36 @@
item = [mainMenu insertItemWithTitle:@"Format" action:nil keyEquivalent:nil atIndex:0];
var formatMenu = [[CPMenu alloc] initWithTitle:@"Format Menu"];
[formatMenu addItemWithTitle:@"Font panel" action:@selector(orderFrontFontPanel:) keyEquivalent:@"f"];
[formatMenu addItemWithTitle:@"Underline" action:@selector(underline:) keyEquivalent:@"u"];
[mainMenu setSubmenu:formatMenu forItem:item];
//
// var centeredParagraph=[CPParagraphStyle new];
// [centeredParagraph setAlignment: CPCenterTextAlignment];
// [_textView insertText:[[CPAttributedString alloc] initWithString:@"Fusce\n"
// attributes:[CPDictionary dictionaryWithObjects:[centeredParagraph, [CPFont boldFontWithName:"Arial" size:18], [CPColor redColor]]
// forKeys:[CPParagraphStyleAttributeName, CPFontAttributeName, CPForegroundColorAttributeName]]]];
//
// [_textView insertText: [[CPAttributedString alloc] initWithString:@"lectus neque cr as eget lectus neque cr as eget lectus cr as eget lectus"
// attributes:[CPDictionary dictionaryWithObjects:[ [CPFont fontWithName:"Arial" size:12]] forKeys: [CPFontAttributeName]]]];
//
// [_textView insertText:[[CPAttributedString alloc] initWithString:@" proin, this is text in boldface "
// attributes:[CPDictionary dictionaryWithObjects:[ [CPFont boldFontWithName:"Arial" size:12]] forKeys: [CPFontAttributeName]]]];
// [_textView insertText:[[CPAttributedString alloc] initWithString:@"111111 neque cr as eget lectus neque cr as eget lectus cr as eget lectus"
// attributes:[CPDictionary dictionaryWithObjects:[ [CPFont fontWithName:"Arial" size:12.0]] forKeys: [CPFontAttributeName]]]];
//
[_textView insertText:"123"];
var tempImageView = [[CPImageView alloc] initWithFrame:CGRectMake(0, 0, 32, 32)];
[tempImageView setImage:[[CPImage alloc] initWithContentsOfFile:@"Resources/spinner.gif" size:CGSizeMake(32, 32)]]
[_textView insertText:[CPTextStorage attributedStringWithAttachment:tempImageView]];
[_textView insertText:" 456 "];
var tempButton = [[CPButton alloc] initWithFrame:CGRectMake(0, 0, 64, 28)]
[_textView insertText:[CPTextStorage attributedStringWithAttachment:tempButton]];
// var centeredParagraph=[CPParagraphStyle new];
// [centeredParagraph setAlignment: CPCenterTextAlignment];
// [_textView insertText:[[CPAttributedString alloc] initWithString:@"Fusce\n"
// attributes:[CPDictionary dictionaryWithObjects:[centeredParagraph, [CPFont boldFontWithName:"Arial" size:18], [CPColor redColor]]
// forKeys:[CPParagraphStyleAttributeName, CPFontAttributeName, CPForegroundColorAttributeName]]]];
[theWindow orderFront:self];
[CPMenu setMenuBarVisible:YES];
}
//
// - (void) makeRTF:sender
// {
// [_textView2 setString: [_CPRTFProducer produceRTF:[_textView textStorage] documentAttributes: @{}] ];
// var tc = [_CPRTFParser new];
// var mystr=[tc parseRTF:[_textView2 stringValue]];
// [_textView selectAll: self];
// [_textView insertText: mystr];
//
// }
- (void) makeRTF:sender
{
[_textView2 setString: [_CPRTFProducer produceRTF:[_textView textStorage] documentAttributes: @{}] ];
var tc = [_CPRTFParser new];
var mystr=[tc parseRTF:[_textView2 stringValue]];
[_textView selectAll: self];
[_textView insertText: mystr];
}
@end