Earlier this week a friend of mine on Facebook noticed something odd. Facebook recognizes when you have URLs in your clipboard:

shot1

Now - I think we can have a good discussion about whether or not this is creepy (I have some thoughts at the end!), but I was curious about how one would do this in a Cordova application. Turns out - it's quite easy. VersoSolutions has a Cordova plugin that provides both read and write access to the clipboard for Windows Phone, iOS, and Android devices: https://github.com/VersoSolutions/CordovaClipboard. Even nicer, ngCordova supports it too. So with that in mind, I built a simple demo.

The app is just one textarea and nothing more:

Simulator Screen Shot Nov 11, 2015, 2.04.07 PM

But if you copy a URL into your clipboard, the app will recognize it when your return:

Simulator Screen Shot Nov 11, 2015, 2.05.20 PM

And clicking the button will insert the text:

Simulator Screen Shot Nov 11, 2015, 2.05.26 PM

Not exactly rocket science, but you get the idea. So here's how I built it. First, the index.html page.

<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8">
    <meta name="viewport" content="initial-scale=1, maximum-scale=1, user-scalable=no, width=device-width">
    <title>CopyPasteDemo</title>

    <link href="lib/ionic/css/ionic.css" rel="stylesheet">
    <link href="css/style.css" rel="stylesheet">

    <!-- IF using Sass (run gulp sass first), then uncomment below and remove the CSS includes above
    <link href="css/ionic.app.css" rel="stylesheet">
    -->

    <!-- ionic/angularjs js -->
    <script src="lib/ionic/js/ionic.bundle.js"></script>

    <!-- cordova script (this will be a 404 during development) -->
    <script src="cordova.js"></script>

    <!-- your app's js -->
    <script src="js/app.js"></script>
  
		<script src="lib/ngCordova/dist/ng-cordova.js"></script>
	</head>
  <body ng-app="starter">

    <ion-pane ng-controller="MainCtrl">
      <ion-header-bar class="bar-stable">
        <h1 class="title">Ionic Blank Starter</h1>
      </ion-header-bar>
      <ion-content>
				
				<div class="list list-inset">
					<label class="item item-input">
						<textarea placeholder="Comments"ng-model="comments"></textarea>
					</label>
					<div ng-show="hasURL">
						<button class="button button-full button-assertive" ng-click="pasteURL()">
							You have copied a URL. Add it?
						</button>
					</div>
				</div>
						
				
				
      </ion-content>
    </ion-pane>
  </body>
</html>

There's nothing particularly interesting here outside of the button which only shows up when a URL is available. Now let's look at the code.

// Ionic Starter App

// angular.module is a global place for creating, registering and retrieving Angular modules
// 'starter' is the name of this angular module example (also set in a <body> attribute in index.html)
// the 2nd parameter is an array of 'requires'
angular.module('starter', ['ionic','ngCordova'])

.controller('MainCtrl', function($scope,$ionicPlatform,$cordovaClipboard,$interval) {

	$scope.haURL = false;
	$scope.comments = "";
	
	var theURL = "";
	
	$ionicPlatform.ready(function() {
	
		//Begin looking for stuff in the clipboard
		$interval(checkForURL, 4*1000);

	});

	var isURL = function(s) {
		//Credit: http://stackoverflow.com/a/3809435
		var expr = /https?:\/\/(www\.)?[-a-zA-Z0-9@:%._\+~#=]{2,256}\.[a-z]{2,6}\b([-a-zA-Z0-9@:%_\+.~#?&//=]*)/i;
		var regex = new RegExp(expr);
		var result = s.match(regex);
		if(result) return true;
		return false;
	};
	
	var checkForURL = function() {
		console.log('Checking the clipboard...');
		$cordovaClipboard
			.paste()
			.then(function (result) {
				console.log(result);
				if(result && isURL(result)) {
					$scope.hasURL = true;
					theURL = result;
				} else {
					$scope.hasURL = false;
				}
			}, function (e) {
				// error - do nothing cuz we don't care
			});
		
	};
	
	$scope.pasteURL = function() {
		console.log("Paste "+theURL);
		$scope.comments += theURL;		
		//remove from clippboard
		$cordovaClipboard.copy('').then(function () {
			$scope.theURL = '';
		}, function () {
			// error
		});	
		$scope.hasURL = false;
	};
		
})
.run(function($ionicPlatform) {
  $ionicPlatform.ready(function() {
    // Hide the accessory bar by default (remove this to show the accessory bar above the keyboard
    // for form inputs)
    if(window.cordova && window.cordova.plugins.Keyboard) {
      cordova.plugins.Keyboard.hideKeyboardAccessoryBar(true);
    }
    if(window.StatusBar) {
      StatusBar.styleDefault();
    }
  });
})

I begin by setting up an interval that runs every 4 seconds. That was somewhat arbitrary and actually a bit slow. Also, it runs forever and should be cleared when the user navigates away from this particular view. (If the application had more than one view of course.)

The function called every 4 seconds, checkForURL, uses the ngCordova wrapper for the clipboard plugin and simply grabs the text. If it can find any, and it is a URL, then we enable the button.

The pasteURL function simply handles adding the URL and clearing the clipboard. Finally, it hides the button.

You can find the complete source here: https://github.com/cfjedimaster/Cordova-Examples/tree/master/copypaste/www.

So... let's spend a minute or so talking about the privacy aspects of this. As I mentioned earlier, my friend was surprised by this and a bit put off as he didn't even know Facebook was doing this. I can certainly see that point. I kind of figure that if the operating system itself allows for apps to read the clipboard than it must be "Ok", but I wonder how many people know this? Obviously it would be trivial to take that clipboard content and Ajax it up to a server. For "research" purposes of course. What do you think?