diff --git a/Examples/UIExplorer/ClipboardExample.js b/Examples/UIExplorer/ClipboardExample.js
new file mode 100644
index 000000000..bcc53dfbb
--- /dev/null
+++ b/Examples/UIExplorer/ClipboardExample.js
@@ -0,0 +1,60 @@
+/**
+ * The examples provided by Facebook are for non-commercial testing and
+ * evaluation purposes only.
+ *
+ * Facebook reserves all rights not expressly granted.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NON INFRINGEMENT. IN NO EVENT SHALL
+ * FACEBOOK BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
+ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * @flow
+ */
+'use strict';
+
+var React = require('react-native');
+var {
+ Clipboard,
+ View,
+ Text,
+} = React;
+
+var ClipboardExample = React.createClass({
+ getInitialState: function() {
+ return {
+ content: 'Content will appear here'
+ };
+ },
+
+ _setContentToClipboard:function(){
+ Clipboard.setString('Hello World');
+ Clipboard.getString(content => {
+ this.setState({content});
+ });
+ },
+
+ render() {
+ return (
+
+
+ Tap to put "Hello World" in the clipboard
+
+
+ {this.state.content}
+
+
+ );
+ }
+});
+
+exports.title = 'Clipboard';
+exports.description = 'Show Clipboard contents.';
+exports.examples = [
+ {
+ title: 'Clipboard.setString() and getString()',
+ render(): ReactElement { return ; }
+ }
+];
diff --git a/Examples/UIExplorer/UIExplorerList.android.js b/Examples/UIExplorer/UIExplorerList.android.js
index a2ff43096..36746c558 100644
--- a/Examples/UIExplorer/UIExplorerList.android.js
+++ b/Examples/UIExplorer/UIExplorerList.android.js
@@ -39,6 +39,7 @@ var COMPONENTS = [
var APIS = [
require('./AccessibilityAndroidExample.android'),
require('./BorderExample'),
+ require('./ClipboardExample'),
require('./GeolocationExample'),
require('./IntentAndroidExample.android'),
require('./LayoutEventsExample'),
diff --git a/Examples/UIExplorer/UIExplorerList.ios.js b/Examples/UIExplorer/UIExplorerList.ios.js
index 940bd79ba..61a213097 100644
--- a/Examples/UIExplorer/UIExplorerList.ios.js
+++ b/Examples/UIExplorer/UIExplorerList.ios.js
@@ -66,6 +66,7 @@ var APIS = [
require('./AsyncStorageExample'),
require('./BorderExample'),
require('./CameraRollExample.ios'),
+ require('./ClipboardExample'),
require('./GeolocationExample'),
require('./LayoutExample'),
require('./NetInfoExample'),
diff --git a/Libraries/BatchedBridge/BatchedBridgedModules/__mocks__/NativeModules.js b/Libraries/BatchedBridge/BatchedBridgedModules/__mocks__/NativeModules.js
index 113a09262..164508ddd 100644
--- a/Libraries/BatchedBridge/BatchedBridgedModules/__mocks__/NativeModules.js
+++ b/Libraries/BatchedBridge/BatchedBridgedModules/__mocks__/NativeModules.js
@@ -54,8 +54,8 @@ var NativeModules = {
AlertManager: {
alertWithArgs: jest.genMockFunction(),
},
- Pasteboard: {
- setPasteboardString: jest.genMockFunction(),
+ Clipboard: {
+ setString: jest.genMockFunction(),
},
};
diff --git a/Libraries/Components/Clipboard/Clipboard.js b/Libraries/Components/Clipboard/Clipboard.js
new file mode 100644
index 000000000..fd8461ba4
--- /dev/null
+++ b/Libraries/Components/Clipboard/Clipboard.js
@@ -0,0 +1,13 @@
+/**
+ * Copyright (c) 2015-present, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under the BSD-style license found in the
+ * LICENSE file in the root directory of this source tree. An additional grant
+ * of patent rights can be found in the PATENTS file in the same directory.
+ *
+ * @providesModule Clipboard
+ */
+'use strict';
+
+module.exports = require('NativeModules').Clipboard;
diff --git a/Libraries/react-native/react-native.js b/Libraries/react-native/react-native.js
index 9eb675a84..be3dfd26a 100644
--- a/Libraries/react-native/react-native.js
+++ b/Libraries/react-native/react-native.js
@@ -58,6 +58,7 @@ var ReactNative = {
get AsyncStorage() { return require('AsyncStorage'); },
get BackAndroid() { return require('BackAndroid'); },
get CameraRoll() { return require('CameraRoll'); },
+ get Clipboard() { return require('Clipboard'); },
get Dimensions() { return require('Dimensions'); },
get Easing() { return require('Easing'); },
get ImagePickerIOS() { return require('ImagePickerIOS'); },
diff --git a/Libraries/react-native/react-native.js.flow b/Libraries/react-native/react-native.js.flow
index 0f314456a..d6c4aac73 100644
--- a/Libraries/react-native/react-native.js.flow
+++ b/Libraries/react-native/react-native.js.flow
@@ -70,6 +70,7 @@ var ReactNative = Object.assign(Object.create(require('React')), {
AsyncStorage: require('AsyncStorage'),
BackAndroid: require('BackAndroid'),
CameraRoll: require('CameraRoll'),
+ Clipboard: require('Clipboard'),
Dimensions: require('Dimensions'),
Easing: require('Easing'),
ImagePickerIOS: require('ImagePickerIOS'),
diff --git a/React/Modules/RCTPasteboard.h b/React/Modules/RCTClipboard.h
similarity index 86%
rename from React/Modules/RCTPasteboard.h
rename to React/Modules/RCTClipboard.h
index d29a3fb1a..bc65c6239 100644
--- a/React/Modules/RCTPasteboard.h
+++ b/React/Modules/RCTClipboard.h
@@ -9,6 +9,6 @@
#import "RCTBridgeModule.h"
-@interface RCTPasteboard : NSObject
+@interface RCTClipboard : NSObject
@end
diff --git a/React/Modules/RCTPasteboard.m b/React/Modules/RCTClipboard.m
similarity index 52%
rename from React/Modules/RCTPasteboard.m
rename to React/Modules/RCTClipboard.m
index 41ad7c044..0a62f3f88 100644
--- a/React/Modules/RCTPasteboard.m
+++ b/React/Modules/RCTClipboard.m
@@ -7,11 +7,13 @@
* of patent rights can be found in the PATENTS file in the same directory.
*/
-#import "RCTPasteboard.h"
+#import "RCTClipboard.h"
+
+#import "RCTUtils.h"
#import
-@implementation RCTPasteboard
+@implementation RCTClipboard
RCT_EXPORT_MODULE()
@@ -20,9 +22,16 @@ RCT_EXPORT_MODULE()
return dispatch_get_main_queue();
}
-RCT_EXPORT_METHOD(setPasteboardString:(NSString *)string)
+RCT_EXPORT_METHOD(getString:(RCTResponseSenderBlock)callback)
{
- [[UIPasteboard generalPasteboard] setString:string];
+ UIPasteboard *clipboard = [UIPasteboard generalPasteboard];
+ callback(@[RCTNullIfNil(clipboard.string)]);
+}
+
+RCT_EXPORT_METHOD(setString:(NSString *)content)
+{
+ UIPasteboard *clipboard = [UIPasteboard generalPasteboard];
+ clipboard.string = content;
}
@end
diff --git a/React/React.xcodeproj/project.pbxproj b/React/React.xcodeproj/project.pbxproj
index 53a11ed1d..d5ea0c76d 100644
--- a/React/React.xcodeproj/project.pbxproj
+++ b/React/React.xcodeproj/project.pbxproj
@@ -38,12 +38,12 @@
13B0801D1A69489C00A75B9A /* RCTNavItemManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 13B080131A69489C00A75B9A /* RCTNavItemManager.m */; };
13B080201A69489C00A75B9A /* RCTActivityIndicatorViewManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 13B080191A69489C00A75B9A /* RCTActivityIndicatorViewManager.m */; };
13B080261A694A8400A75B9A /* RCTWrapperViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 13B080241A694A8400A75B9A /* RCTWrapperViewController.m */; };
- 13BB3D021BECD54500932C10 /* RCTImageSource.m in Sources */ = {isa = PBXBuildFile; fileRef = 13BB3D011BECD54500932C10 /* RCTImageSource.m */; };
- 13B202011BFB945300C07393 /* RCTPasteboard.m in Sources */ = {isa = PBXBuildFile; fileRef = 13B202001BFB945300C07393 /* RCTPasteboard.m */; };
13B202041BFB948C00C07393 /* RCTMapAnnotation.m in Sources */ = {isa = PBXBuildFile; fileRef = 13B202031BFB948C00C07393 /* RCTMapAnnotation.m */; };
+ 13BB3D021BECD54500932C10 /* RCTImageSource.m in Sources */ = {isa = PBXBuildFile; fileRef = 13BB3D011BECD54500932C10 /* RCTImageSource.m */; };
13C156051AB1A2840079392D /* RCTWebView.m in Sources */ = {isa = PBXBuildFile; fileRef = 13C156021AB1A2840079392D /* RCTWebView.m */; };
13C156061AB1A2840079392D /* RCTWebViewManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 13C156041AB1A2840079392D /* RCTWebViewManager.m */; };
13CC8A821B17642100940AE7 /* RCTBorderDrawing.m in Sources */ = {isa = PBXBuildFile; fileRef = 13CC8A811B17642100940AE7 /* RCTBorderDrawing.m */; };
+ 13D033631C1837FE0021DC29 /* RCTClipboard.m in Sources */ = {isa = PBXBuildFile; fileRef = 13D033621C1837FE0021DC29 /* RCTClipboard.m */; };
13E0674A1A70F434002CDEE1 /* RCTUIManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 13E067491A70F434002CDEE1 /* RCTUIManager.m */; };
13E067551A70F44B002CDEE1 /* RCTShadowView.m in Sources */ = {isa = PBXBuildFile; fileRef = 13E0674C1A70F44B002CDEE1 /* RCTShadowView.m */; };
13E067561A70F44B002CDEE1 /* RCTViewManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 13E0674E1A70F44B002CDEE1 /* RCTViewManager.m */; };
@@ -174,12 +174,10 @@
13B080191A69489C00A75B9A /* RCTActivityIndicatorViewManager.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RCTActivityIndicatorViewManager.m; sourceTree = ""; };
13B080231A694A8400A75B9A /* RCTWrapperViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RCTWrapperViewController.h; sourceTree = ""; };
13B080241A694A8400A75B9A /* RCTWrapperViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RCTWrapperViewController.m; sourceTree = ""; };
- 13BB3D001BECD54500932C10 /* RCTImageSource.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RCTImageSource.h; sourceTree = ""; };
- 13BB3D011BECD54500932C10 /* RCTImageSource.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RCTImageSource.m; sourceTree = ""; };
- 13B201FF1BFB945300C07393 /* RCTPasteboard.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RCTPasteboard.h; sourceTree = ""; };
- 13B202001BFB945300C07393 /* RCTPasteboard.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RCTPasteboard.m; sourceTree = ""; };
13B202021BFB948C00C07393 /* RCTMapAnnotation.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RCTMapAnnotation.h; sourceTree = ""; };
13B202031BFB948C00C07393 /* RCTMapAnnotation.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RCTMapAnnotation.m; sourceTree = ""; };
+ 13BB3D001BECD54500932C10 /* RCTImageSource.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RCTImageSource.h; sourceTree = ""; };
+ 13BB3D011BECD54500932C10 /* RCTImageSource.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RCTImageSource.m; sourceTree = ""; };
13C156011AB1A2840079392D /* RCTWebView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RCTWebView.h; sourceTree = ""; };
13C156021AB1A2840079392D /* RCTWebView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RCTWebView.m; sourceTree = ""; };
13C156031AB1A2840079392D /* RCTWebViewManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RCTWebViewManager.h; sourceTree = ""; };
@@ -189,6 +187,8 @@
13C325281AA63B6A0048765F /* RCTComponent.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RCTComponent.h; sourceTree = ""; };
13CC8A801B17642100940AE7 /* RCTBorderDrawing.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RCTBorderDrawing.h; sourceTree = ""; };
13CC8A811B17642100940AE7 /* RCTBorderDrawing.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RCTBorderDrawing.m; sourceTree = ""; };
+ 13D033611C1837FE0021DC29 /* RCTClipboard.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RCTClipboard.h; sourceTree = ""; };
+ 13D033621C1837FE0021DC29 /* RCTClipboard.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RCTClipboard.m; sourceTree = ""; };
13E067481A70F434002CDEE1 /* RCTUIManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RCTUIManager.h; sourceTree = ""; };
13E067491A70F434002CDEE1 /* RCTUIManager.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RCTUIManager.m; sourceTree = ""; };
13E0674B1A70F44B002CDEE1 /* RCTShadowView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RCTShadowView.h; sourceTree = ""; };
@@ -318,14 +318,14 @@
1372B7091AB030C200659ED6 /* RCTAppState.m */,
58114A4F1AAE93D500E7D092 /* RCTAsyncLocalStorage.h */,
58114A4E1AAE93D500E7D092 /* RCTAsyncLocalStorage.m */,
+ 13D033611C1837FE0021DC29 /* RCTClipboard.h */,
+ 13D033621C1837FE0021DC29 /* RCTClipboard.m */,
13A0C2851B74F71200B29F6F /* RCTDevLoadingView.h */,
13A0C2861B74F71200B29F6F /* RCTDevLoadingView.m */,
13A0C2871B74F71200B29F6F /* RCTDevMenu.h */,
13A0C2881B74F71200B29F6F /* RCTDevMenu.m */,
13B07FE91A69327A00A75B9A /* RCTExceptionsManager.h */,
13B07FEA1A69327A00A75B9A /* RCTExceptionsManager.m */,
- 13B201FF1BFB945300C07393 /* RCTPasteboard.h */,
- 13B202001BFB945300C07393 /* RCTPasteboard.m */,
13F17A831B8493E5007D4C75 /* RCTRedBox.h */,
13F17A841B8493E5007D4C75 /* RCTRedBox.m */,
000E6CE91AB0E97F000CDF4D /* RCTSourceCode.h */,
@@ -628,7 +628,6 @@
13723B501A82FD3C00F88898 /* RCTStatusBarManager.m in Sources */,
000E6CEB1AB0E980000CDF4D /* RCTSourceCode.m in Sources */,
133CAE8E1B8E5CFD00F6AD92 /* RCTDatePicker.m in Sources */,
- 13B202011BFB945300C07393 /* RCTPasteboard.m in Sources */,
14C2CA761B3AC64F00E6CBB2 /* RCTFrameUpdate.m in Sources */,
13B07FEF1A69327A00A75B9A /* RCTAlertManager.m in Sources */,
83CBBACC1A6023D300E9B192 /* RCTConvert.m in Sources */,
@@ -669,6 +668,7 @@
14C2CA781B3ACB0400E6CBB2 /* RCTBatchedBridge.m in Sources */,
13E067591A70F44B002CDEE1 /* UIView+React.m in Sources */,
14F484561AABFCE100FDF6B9 /* RCTSliderManager.m in Sources */,
+ 13D033631C1837FE0021DC29 /* RCTClipboard.m in Sources */,
14C2CA741B3AC64300E6CBB2 /* RCTModuleData.m in Sources */,
142014191B32094000CC17BA /* RCTPerformanceLogger.m in Sources */,
83CBBA981A6020BB00E9B192 /* RCTTouchHandler.m in Sources */,
diff --git a/ReactAndroid/src/main/java/com/facebook/react/modules/clipboard/ClipboardModule.java b/ReactAndroid/src/main/java/com/facebook/react/modules/clipboard/ClipboardModule.java
new file mode 100644
index 000000000..b3689f980
--- /dev/null
+++ b/ReactAndroid/src/main/java/com/facebook/react/modules/clipboard/ClipboardModule.java
@@ -0,0 +1,84 @@
+/**
+ * Copyright (c) 2015-present, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under the BSD-style license found in the
+ * LICENSE file in the root directory of this source tree. An additional grant
+ * of patent rights can be found in the PATENTS file in the same directory.
+ */
+
+package com.facebook.react.modules.clipboard;
+
+import android.annotation.SuppressLint;
+import android.content.ClipboardManager;
+import android.content.ClipData;
+import android.os.Build;
+
+import com.facebook.common.logging.FLog;
+import com.facebook.react.bridge.Callback;
+import com.facebook.react.bridge.NativeModule;
+import com.facebook.react.bridge.ReactApplicationContext;
+import com.facebook.react.bridge.ReactContext;
+import com.facebook.react.bridge.ReactContextBaseJavaModule;
+import com.facebook.react.bridge.ReactMethod;
+import com.facebook.react.common.ReactConstants;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * A module that allows JS to get/set clipboard contents.
+ */
+public class ClipboardModule extends ReactContextBaseJavaModule {
+
+ public ClipboardModule(ReactApplicationContext reactContext) {
+ super(reactContext);
+ }
+
+ @Override
+ public String getName() {
+ return "Clipboard";
+ }
+
+ private ClipboardManager getClipboardService() {
+ ReactApplicationContext reactContext = getReactApplicationContext();
+ return (ClipboardManager) reactContext.getSystemService(reactContext.CLIPBOARD_SERVICE);
+ }
+
+ @ReactMethod
+ public void getString(Callback cb) {
+ try {
+ ClipboardManager clipboard = getClipboardService();
+ ClipData clipData = clipboard.getPrimaryClip();
+ if (clipData == null) {
+ cb.invoke("");
+ return;
+ }
+ if (clipData.getItemCount() >= 1) {
+ ClipData.Item firstItem = clipboard.getPrimaryClip().getItemAt(0);
+ String text = "" + firstItem.getText();
+ cb.invoke(text);
+ } else {
+ cb.invoke("");
+ }
+ } catch(Exception e) {
+ FLog.w(ReactConstants.TAG, "Cannot get clipboard contents: " + e.getMessage());
+ }
+ }
+
+ @SuppressLint("DeprecatedMethod")
+ @ReactMethod
+ public void setString(String text) {
+ ReactApplicationContext reactContext = getReactApplicationContext();
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) {
+ ClipData clipdata = ClipData.newPlainText(null, text);
+ ClipboardManager clipboard = getClipboardService();
+ clipboard.setPrimaryClip(clipdata);
+ } else {
+ ClipboardManager clipboard = getClipboardService();
+ clipboard.setText(text);
+ }
+ }
+}
diff --git a/ReactAndroid/src/main/java/com/facebook/react/shell/MainReactPackage.java b/ReactAndroid/src/main/java/com/facebook/react/shell/MainReactPackage.java
index bf91bade6..973cfbd84 100644
--- a/ReactAndroid/src/main/java/com/facebook/react/shell/MainReactPackage.java
+++ b/ReactAndroid/src/main/java/com/facebook/react/shell/MainReactPackage.java
@@ -41,6 +41,7 @@ import com.facebook.react.views.toolbar.ReactToolbarManager;
import com.facebook.react.views.view.ReactViewManager;
import com.facebook.react.views.viewpager.ReactViewPagerManager;
import com.facebook.react.views.swiperefresh.SwipeRefreshLayoutManager;
+import com.facebook.react.modules.clipboard.ClipboardModule;
/**
* Package defining basic modules and view managers.
@@ -51,6 +52,7 @@ public class MainReactPackage implements ReactPackage {
public List createNativeModules(ReactApplicationContext reactContext) {
return Arrays.asList(
new AsyncStorageModule(reactContext),
+ new ClipboardModule(reactContext),
new FrescoModule(reactContext),
new IntentModule(reactContext),
new LocationModule(reactContext),