<!DOCTYPE html>
<html>
<head>
<script data-require="jquery@2.1.3" data-semver="2.1.3" src="http://code.jquery.com/jquery-2.1.3.min.js"></script>
<script data-require="angular.js@1.5.8" data-semver="1.5.8" src="https://code.angularjs.org/1.5.8/angular.js"></script>
<link rel="stylesheet" href="style.css" />
<script src="script.js"></script>
</head>
<body ng-app="plunker">
<div ng-controller="MainCtrl">
<div>
<pt-input-event-detector model="model" ng-model="model.text" events="events" set-event="setEvent(event, text)" on-change="updateModel(model)"></pt-input-event-detector>
</div>
<h1> {{model.text}}</h1>
<table cellspacing="0" cellpadding="0" ng-if="model.events.length">
<thead>
<tr>
<th colspan="2">Keyup</th>
<th colspan="2">Keydown</th>
<th colspan="2">Paste</th>
</tr>
<tr>
<th>Detected</th>
<th>Key</th>
<th>Detected</th>
<th>Key</th>
<th>Detected</th>
<th>Text</th>
</tr>
</thead>
<tbody>
<tr ng-repeat="event in model.events">
<td>{{event.keyup.detected}}</td>
<td>{{event.keyup.text}}</td>
<td>{{event.keydown.detected}}</td>
<td>{{event.keydown.text}}</td>
<td>{{event.paste.detected}}</td>
<td>{{event.paste.text}}</td>
</tr>
</tbody>
</table>
</div>
</body>
</html>
// Code goes here
var app = angular.module('plunker', []);
app.controller('MainCtrl', function($scope) {
var EVENTS = ['paste', 'keyup', 'keydown'];
$scope.model = {
text: '',
events: []
};
$scope.setEvent = function(event, text) {
var eventList = {};
for ( var i in EVENTS ) {
var detected = false;
var val = '';
if (EVENTS[i] === event) {
detected = true;
val = text;
}
eventList[EVENTS[i]] = {
detected: detected,
text: val
};
}
$scope.model.events.push(eventList);
}
});
app.directive('ptInputEventDetector', function($compile) {
return {
restrict: 'E',
template: `<div class="position-relative">
<input type="text" placeholder="Paste text here" ng-model="_model.text" ng-trim="false" ng-change="onTextUpdate(_model)"/>
<button type="button" ng-if="!listenerActive" ng-click="launchEventListener()">Enable</button>
</div>`,
replace: true,
scope: {
onChange : "&?",
model: '=',
events: '=',
setEvent: '&'
},
link: function(scope, element, attrs, ngModel) {
var input = element.find('input');
scope.listenerActive = false;
scope._model = { text: '' };
scope.launchEventListener = launchEventListener;
scope.onTextUpdate = function(_model) {
var textUpdate = _model.text;
scope.model.text = textUpdate;
scope.onChange({ model: scope.model });
killEventListener();
compileDirective();
}
function compileDirective() {
$compile(input)(scope);
}
var isMeta = false;
function setText(event, text, type, key) {
event.preventDefault();
scope._model.text = text;
scope.onTextUpdate(scope._model);
scope.setEvent({event: type, text: text || key});
}
function handlePaste(event) {
isMeta = false;
var clipboardText = event.originalEvent.clipboardData.getData('text');
setText(event, event, 'paste');
}
function handleKeyup(event) {
if (event.metaKey || event.ctrlKey) {
isMeta = false;
scope.setEvent({event: 'keyup', text: event.key});
}
}
function handleKeydown(event) {
let key = event.which || event.keyCode;
if(key == 8 || key == 46) {
setText(event, '', 'keydown', event.key);
} else {
if (event.metaKey || event.ctrlKey) {
isMeta = true;
scope.setEvent({event: 'keydown', text: event.key});
} else if (!isMeta && isVisibleKey(key)) {
setText(event, String.fromCharCode(key), 'keydown');
}
}
}
function isVisibleKey(keyCode) {
return (keyCode >= 48 && keyCode <= 90) || (keyCode >= 106 && keyCode <= 111) || (keyCode >= 186 && keyCode <= 192) || (keyCode >= 219 && keyCode <= 222);
}
function launchEventListener() {
if(!scope.listenerActive) {
input.bind('paste.test', handlePaste);
input.bind('keyup.test', handleKeyup);
input.bind('keydown.test', handleKeydown);
scope.listenerActive = true;
scope._model.text = 'Enter Text';
input[0].focus();
}
}
function killEventListener() {
if(scope.listenerActive) {
input.unbind('paste.test');
input.unbind('keyup.test');
input.unbind('keydown.test');
scope.listenerActive = false;
}
}
launchEventListener();
}
}
});
/* Styles go here */
div {
margin: 10px;
}
input, button {
border: 1px solid #000;
border-radius: 2px;
font-size: 24px;
}
table tr th,
table tr td {
border: #ccc 1px solid;
padding: 5px;
margin: 0;
}