diff --git a/AppKit/CPPasteboard.j b/AppKit/CPPasteboard.j index 2f1b4e9db..c821aee41 100644 --- a/AppKit/CPPasteboard.j +++ b/AppKit/CPPasteboard.j @@ -128,7 +128,10 @@ var CPPasteboards = nil, _changeCount = 0; if (supportsNativePasteboard) + { _nativePasteboard = window.cpPasteboardWithName(aName); + [self _synchronizePasteboard]; + } } return self; @@ -177,6 +180,12 @@ var CPPasteboards = nil, @return the pasteboard's change count */ - (unsigned)declareTypes:(CPArray)types owner:(id)anOwner +{ + [self _declareTypes:types owner:anOwner updateNativePasteboard:YES]; +} + +/*! @ignore */ +- (unsigned)_declareTypes:(CPArray)types owner:(id)anOwner updateNativePasteboard:(BOOL)shouldUpdate { [_types setArray:types]; @@ -188,15 +197,15 @@ var CPPasteboards = nil, while (count--) [_owners setObject:anOwner forKey:_types[count]]; - if (_nativePasteboard) + if (_nativePasteboard && shouldUpdate) { var nativeTypes = [types copy]; if ([types containsObject:CPStringPboardType]) nativeTypes.push(UTF8PboardType); _nativePasteboard.declareTypes_(nativeTypes); + _changeCount = _nativePasteboard.changeCount(); } - return ++_changeCount; } @@ -255,6 +264,7 @@ var CPPasteboards = nil, */ - (CPArray)types { + [self _synchronizePasteboard]; return _types; } @@ -283,16 +293,46 @@ var CPPasteboards = nil, if (owner) { - [owner pasteboard:self provideDataForType:aType]; - - ++_changeCount; - + [owner pasteboard:self provideDataForType:aType]; return [_provided objectForKey:aType]; } + if (aType === CPStringPboardType) + return [self dataForType:UTF8PboardType]; + return nil; } +- (void)_synchronizePasteboard +{ + if (_nativePasteboard && _nativePasteboard.changeCount() > _changeCount) + { + var nativeTypes = [_nativePasteboard.types() copy]; + if ([nativeTypes containsObject:UTF8PboardType]) + nativeTypes.push(CPStringPboardType); + + [self _declareTypes:nativeTypes owner:self updateNativePasteboard:NO]; + + _changeCount = _nativePasteboard.changeCount(); + } +} + +/*! @ignore + method provided for integration with native pasteboard +*/ +- (void)pasteboard:(CPPasteboard)aPasteboard provideDataForType:(CPString)aType +{ + if (aType === CPStringPboardType) + { + var string = _nativePasteboard.stringForType_(UTF8PboardType); + + [self setString:string forType:CPStringPboardType]; + [self setString:string forType:UTF8PboardType]; + } + else + [self setString:_nativePasteboard.stringForType_(aType) forType:aType]; +} + /*! Returns the property list for the specified data type @param aType the requested data type diff --git a/AppKit/CPTextField.j b/AppKit/CPTextField.j index 05e3da2ec..ef77ea021 100644 --- a/AppKit/CPTextField.j +++ b/AppKit/CPTextField.j @@ -789,11 +789,129 @@ CPTextFieldStatePlaceholder = CPThemeState("placeholder"); #endif } +- (void)copy:(id)sender +{ + var selectedRange = [self selectedRange]; + + if (selectedRange.length < 1) + return; + + var pasteboard = [CPPasteboard generalPasteboard], + stringValue = [self stringValue], + stringForPasting = [stringValue substringWithRange:selectedRange]; + + [pasteboard declareTypes:[CPStringPboardType] owner:nil]; + [pasteboard setString:stringForPasting forType:CPStringPboardType]; +} + +- (void)cut:(id)sender +{ + [self copy:sender]; + [self deleteBackwards:sender]; +} + +- (void)paste:(id)sender +{ + var pasteboard = [CPPasteboard generalPasteboard]; + + if (![[pasteboard types] containsObject:CPStringPboardType]) + return; + + [self deleteBackwards:sender]; + + var selectedRange = [self selectedRange], + stringValue = [self stringValue], + pasteString = [pasteboard stringForType:CPStringPboardType], + newValue = [stringValue stringByReplacingCharactersInRange:selectedRange withString:pasteString]; + + [self setStringValue:newValue]; + [self setSelectedRange:CPMakeRange(selectedRange.location+pasteString.length, 0)]; +} + +- (CPRange)selectedRange +{ + if ([[self window] firstResponder] !== self) + return CPMakeRange(0, 0); + + // we wrap this in try catch because firefox will throw an exception in certain instances + try + { + var inputElement = [self _inputElement], + selectionStart = inputElement.selectionStart, + selectionEnd = inputElement.selectionEnd; + + if ([selectionStart isKindOfClass:CPNumber]) + return CPMakeRange(selectionStart, selectionEnd - selectionStart); + + // browsers which don't support selectionStart/selectionEnd (aka IE). + var theDocument = inputElement.ownerDocument || inputElement.document, + selectionRange = theDocument.selection.createRange(), + range = inputElement.createTextRange(); + + if (range.inRange(selectionRange)) + { + range.setEndPoint('EndToStart', selectionRange); + return CPMakeRange(range.text.length, selectionRange.text.length); + } + } + catch (e) + { + // fall through to the return + } + + return CGMakeRange(0, 0); +} + +- (void)setSelectedRange:(CPRange)aRange +{ + if (![[self window] firstResponder] === self) + return; + + var inputElement = [self _inputElement]; + + try + { + if ([inputElement.selectionStart isKindOfClass:CPNumber]) + { + inputElement.selectionStart = aRange.location; + inputElement.selectionEnd = CPMaxRange(aRange); + } + else + { + // browsers which don't support selectionStart/selectionEnd (aka IE). + var theDocument = inputElement.ownerDocument || inputElement.document, + existingRange = theDocument.selection.createRange(), + range = inputElement.createTextRange(); + + if (range.inRange(existingRange)) + { + range.collapse(true); + range.move('character', aRange.location); + range.moveEnd('character', aRange.length); + range.select(); + } + } + } + catch (e) + { + } +} + - (void)selectAll:(id)sender { [self selectText:sender]; } +- (void)deleteBackwards:(id)sender +{ + var selectedRange = [self selectedRange], + stringValue = [self stringValue], + newValue = [stringValue stringByReplacingCharactersInRange:selectedRange withString:""]; + + [self setStringValue:newValue]; + [self setSelectedRange:CPMakeRange(selectedRange.location, 0)]; +} + #pragma mark Setting the Delegate - (void)setDelegate:(id)aDelegate