mirror of
https://github.com/gyurix1968/guacamole-client.git
synced 2025-09-07 05:31:22 +00:00
GUACAMOLE-55: Move clipboard handling to own module. Represent clipboard contents with ClipboardData type.
This commit is contained in:
@@ -22,6 +22,7 @@
|
|||||||
*/
|
*/
|
||||||
angular.module('client', [
|
angular.module('client', [
|
||||||
'auth',
|
'auth',
|
||||||
|
'clipboard',
|
||||||
'element',
|
'element',
|
||||||
'history',
|
'history',
|
||||||
'navigation',
|
'navigation',
|
||||||
|
@@ -410,9 +410,9 @@ angular.module('client').directive('guacClient', [function guacClient() {
|
|||||||
};
|
};
|
||||||
|
|
||||||
// Update remote clipboard if local clipboard changes
|
// Update remote clipboard if local clipboard changes
|
||||||
$scope.$on('guacClipboard', function onClipboard(event, mimetype, data) {
|
$scope.$on('guacClipboard', function onClipboard(event, data) {
|
||||||
if (client) {
|
if (client) {
|
||||||
client.setClipboard(data);
|
ManagedClient.setClipboard($scope.client, data);
|
||||||
$scope.client.clipboardData = data;
|
$scope.client.clipboardData = data;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
@@ -26,6 +26,7 @@ angular.module('client').factory('ManagedClient', ['$rootScope', '$injector',
|
|||||||
// Required types
|
// Required types
|
||||||
var ClientProperties = $injector.get('ClientProperties');
|
var ClientProperties = $injector.get('ClientProperties');
|
||||||
var ClientIdentifier = $injector.get('ClientIdentifier');
|
var ClientIdentifier = $injector.get('ClientIdentifier');
|
||||||
|
var ClipboardData = $injector.get('ClipboardData');
|
||||||
var ManagedClientState = $injector.get('ManagedClientState');
|
var ManagedClientState = $injector.get('ManagedClientState');
|
||||||
var ManagedDisplay = $injector.get('ManagedDisplay');
|
var ManagedDisplay = $injector.get('ManagedDisplay');
|
||||||
var ManagedFilesystem = $injector.get('ManagedFilesystem');
|
var ManagedFilesystem = $injector.get('ManagedFilesystem');
|
||||||
@@ -37,7 +38,6 @@ angular.module('client').factory('ManagedClient', ['$rootScope', '$injector',
|
|||||||
var $rootScope = $injector.get('$rootScope');
|
var $rootScope = $injector.get('$rootScope');
|
||||||
var $window = $injector.get('$window');
|
var $window = $injector.get('$window');
|
||||||
var authenticationService = $injector.get('authenticationService');
|
var authenticationService = $injector.get('authenticationService');
|
||||||
var clipboardService = $injector.get('clipboardService');
|
|
||||||
var connectionGroupService = $injector.get('connectionGroupService');
|
var connectionGroupService = $injector.get('connectionGroupService');
|
||||||
var connectionService = $injector.get('connectionService');
|
var connectionService = $injector.get('connectionService');
|
||||||
var tunnelService = $injector.get('tunnelService');
|
var tunnelService = $injector.get('tunnelService');
|
||||||
@@ -100,9 +100,12 @@ angular.module('client').factory('ManagedClient', ['$rootScope', '$injector',
|
|||||||
/**
|
/**
|
||||||
* The current clipboard contents.
|
* The current clipboard contents.
|
||||||
*
|
*
|
||||||
* @type String
|
* @type ClipboardData
|
||||||
*/
|
*/
|
||||||
this.clipboardData = template.clipboardData || '';
|
this.clipboardData = template.clipboardData || new ClipboardData({
|
||||||
|
type : 'text/plain',
|
||||||
|
data : ''
|
||||||
|
});
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* All uploaded files. As files are uploaded, their progress can be
|
* All uploaded files. As files are uploaded, their progress can be
|
||||||
@@ -385,7 +388,7 @@ angular.module('client').factory('ManagedClient', ['$rootScope', '$injector',
|
|||||||
|
|
||||||
// Send any clipboard data already provided
|
// Send any clipboard data already provided
|
||||||
if (managedClient.clipboardData)
|
if (managedClient.clipboardData)
|
||||||
client.setClipboard(managedClient.clipboardData);
|
ManagedClient.setClipboard(managedClient, managedClient.clipboardData);
|
||||||
|
|
||||||
// Begin streaming audio input if possible
|
// Begin streaming audio input if possible
|
||||||
requestAudioStream(client);
|
requestAudioStream(client);
|
||||||
@@ -421,28 +424,43 @@ angular.module('client').factory('ManagedClient', ['$rootScope', '$injector',
|
|||||||
// Handle any received clipboard data
|
// Handle any received clipboard data
|
||||||
client.onclipboard = function clientClipboardReceived(stream, mimetype) {
|
client.onclipboard = function clientClipboardReceived(stream, mimetype) {
|
||||||
|
|
||||||
// Only text/plain is supported for now
|
var reader;
|
||||||
if (mimetype !== "text/plain") {
|
|
||||||
stream.sendAck("Only text/plain supported", Guacamole.Status.Code.UNSUPPORTED);
|
// If the received data is text, read it as a simple string
|
||||||
return;
|
if (/^text\//.exec(mimetype)) {
|
||||||
|
|
||||||
|
reader = new Guacamole.StringReader(stream);
|
||||||
|
|
||||||
|
// Assemble received data into a single string
|
||||||
|
var data = '';
|
||||||
|
reader.ontext = function textReceived(text) {
|
||||||
|
data += text;
|
||||||
|
};
|
||||||
|
|
||||||
|
// Set clipboard contents once stream is finished
|
||||||
|
reader.onend = function textComplete() {
|
||||||
|
$rootScope.$apply(function updateClipboard() {
|
||||||
|
managedClient.clipboardData = new ClipboardData({
|
||||||
|
type : mimetype,
|
||||||
|
data : data
|
||||||
|
});
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
var reader = new Guacamole.StringReader(stream);
|
// Otherwise read the clipboard data as a Blob
|
||||||
var data = "";
|
else {
|
||||||
|
reader = new Guacamole.BlobReader(stream, mimetype);
|
||||||
// Append any received data to buffer
|
reader.onend = function blobComplete() {
|
||||||
reader.ontext = function clipboard_text_received(text) {
|
$rootScope.$apply(function updateClipboard() {
|
||||||
data += text;
|
managedClient.clipboardData = new ClipboardData({
|
||||||
stream.sendAck("Received", Guacamole.Status.Code.SUCCESS);
|
type : mimetype,
|
||||||
};
|
data : reader.getBlob()
|
||||||
|
});
|
||||||
// Update state when done
|
});
|
||||||
reader.onend = function clipboard_text_end() {
|
};
|
||||||
$rootScope.$apply(function updateClipboard() {
|
}
|
||||||
managedClient.clipboardData = data;
|
|
||||||
clipboardService.setLocalClipboard(data);
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -527,6 +545,46 @@ angular.module('client').factory('ManagedClient', ['$rootScope', '$injector',
|
|||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sends the given clipboard data over the given Guacamole client, setting
|
||||||
|
* the contents of the remote clipboard to the data provided.
|
||||||
|
*
|
||||||
|
* @param {ManagedClient} managedClient
|
||||||
|
* The ManagedClient over which the given clipboard data is to be sent.
|
||||||
|
*
|
||||||
|
* @param {ClipboardData} data
|
||||||
|
* The clipboard data to send.
|
||||||
|
*/
|
||||||
|
ManagedClient.setClipboard = function setClipboard(managedClient, data) {
|
||||||
|
|
||||||
|
var writer;
|
||||||
|
|
||||||
|
// Create stream with proper mimetype
|
||||||
|
var stream = managedClient.client.createClipboardStream(data.type);
|
||||||
|
|
||||||
|
// Send data as a string if it is stored as a string
|
||||||
|
if (typeof data.data === 'string') {
|
||||||
|
writer = new Guacamole.StringWriter(stream);
|
||||||
|
writer.sendText(data.data);
|
||||||
|
writer.sendEnd();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Otherwise, assume the data is a File/Blob
|
||||||
|
else {
|
||||||
|
|
||||||
|
// Write File/Blob asynchronously
|
||||||
|
writer = new Guacamole.BlobWriter(stream);
|
||||||
|
writer.oncomplete = function clipboardSent() {
|
||||||
|
writer.sendEnd();
|
||||||
|
};
|
||||||
|
|
||||||
|
// Begin sending data
|
||||||
|
writer.sendBlob(data.data);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
return ManagedClient;
|
return ManagedClient;
|
||||||
|
|
||||||
}]);
|
}]);
|
23
guacamole/src/main/webapp/app/clipboard/clipboardModule.js
Normal file
23
guacamole/src/main/webapp/app/clipboard/clipboardModule.js
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
/*
|
||||||
|
* Licensed to the Apache Software Foundation (ASF) under one
|
||||||
|
* or more contributor license agreements. See the NOTICE file
|
||||||
|
* distributed with this work for additional information
|
||||||
|
* regarding copyright ownership. The ASF licenses this file
|
||||||
|
* to you under the Apache License, Version 2.0 (the
|
||||||
|
* "License"); you may not use this file except in compliance
|
||||||
|
* with the License. You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing,
|
||||||
|
* software distributed under the License is distributed on an
|
||||||
|
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||||
|
* KIND, either express or implied. See the License for the
|
||||||
|
* specific language governing permissions and limitations
|
||||||
|
* under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The module for code used to manipulate/observe the clipboard.
|
||||||
|
*/
|
||||||
|
angular.module('clipboard', []);
|
@@ -27,7 +27,11 @@
|
|||||||
* "data" attribute, changes to clipboard data will be broadcast on the scope
|
* "data" attribute, changes to clipboard data will be broadcast on the scope
|
||||||
* via "guacClipboard" events.
|
* via "guacClipboard" events.
|
||||||
*/
|
*/
|
||||||
angular.module('client').directive('guacClipboard', [function guacClipboard() {
|
angular.module('clipboard').directive('guacClipboard', ['$injector',
|
||||||
|
function guacClipboard($injector) {
|
||||||
|
|
||||||
|
// Required types
|
||||||
|
var ClipboardData = $injector.get('ClipboardData');
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Configuration object for the guacClipboard directive.
|
* Configuration object for the guacClipboard directive.
|
||||||
@@ -37,7 +41,7 @@ angular.module('client').directive('guacClipboard', [function guacClipboard() {
|
|||||||
var config = {
|
var config = {
|
||||||
restrict : 'E',
|
restrict : 'E',
|
||||||
replace : true,
|
replace : true,
|
||||||
templateUrl : 'app/client/templates/guacClipboard.html'
|
templateUrl : 'app/clipboard/templates/guacClipboard.html'
|
||||||
};
|
};
|
||||||
|
|
||||||
// Scope properties exposed by the guacClipboard directive
|
// Scope properties exposed by the guacClipboard directive
|
||||||
@@ -51,7 +55,7 @@ angular.module('client').directive('guacClipboard', [function guacClipboard() {
|
|||||||
* field. Changes to this value will be rendered within the field and,
|
* field. Changes to this value will be rendered within the field and,
|
||||||
* if possible, will be pushed to the local clipboard.
|
* if possible, will be pushed to the local clipboard.
|
||||||
*
|
*
|
||||||
* @type String|Blob
|
* @type ClipboardData
|
||||||
*/
|
*/
|
||||||
data : '='
|
data : '='
|
||||||
|
|
||||||
@@ -81,17 +85,42 @@ angular.module('client').directive('guacClipboard', [function guacClipboard() {
|
|||||||
* contents received while those keys were pressed. All keys not
|
* contents received while those keys were pressed. All keys not
|
||||||
* currently pressed will not have entries within this map.
|
* currently pressed will not have entries within this map.
|
||||||
*
|
*
|
||||||
* @type Object.<Number, String>
|
* @type Object.<Number, Blob>
|
||||||
*/
|
*/
|
||||||
var clipboardDataFromKey = {};
|
var clipboardDataFromKey = {};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The URL of the image is currently stored within the clipboard. If
|
* The FileReader to use to read File or Blob data received from the
|
||||||
* the clipboard currently contains text, this will be null.
|
* clipboard.
|
||||||
*
|
*
|
||||||
* @type String
|
* @type FileReader
|
||||||
*/
|
*/
|
||||||
$scope.imageURL = null;
|
var reader = new FileReader();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Properties which contain the current clipboard contents. Each
|
||||||
|
* property is mutually exclusive, and will only contain data if the
|
||||||
|
* clipboard contents are of a particular type.
|
||||||
|
*/
|
||||||
|
$scope.content = {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The text contents of the clipboard. If the clipboard contents
|
||||||
|
* is not text, this will be null.
|
||||||
|
*
|
||||||
|
* @type String
|
||||||
|
*/
|
||||||
|
text : null,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The URL of the image is currently stored within the clipboard. If
|
||||||
|
* the clipboard currently contains text, this will be null.
|
||||||
|
*
|
||||||
|
* @type String
|
||||||
|
*/
|
||||||
|
imageURL : null
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
// Intercept paste events, handling image data specifically
|
// Intercept paste events, handling image data specifically
|
||||||
$element[0].addEventListener('paste', function dataPasted(e) {
|
$element[0].addEventListener('paste', function dataPasted(e) {
|
||||||
@@ -103,9 +132,15 @@ angular.module('client').directive('guacClipboard', [function guacClipboard() {
|
|||||||
// If the item is an image, attempt to read that image
|
// If the item is an image, attempt to read that image
|
||||||
if (items[i].kind === 'file' && /^image\//.exec(items[i].type)) {
|
if (items[i].kind === 'file' && /^image\//.exec(items[i].type)) {
|
||||||
|
|
||||||
|
// Retrieven contents as a File
|
||||||
|
var file = items[i].getAsFile();
|
||||||
|
|
||||||
// Set clipboard data to contents
|
// Set clipboard data to contents
|
||||||
$scope.$apply(function setClipboardData() {
|
$scope.$apply(function setClipboardData() {
|
||||||
$scope.data = items[i].getAsFile();
|
$scope.data = new ClipboardData({
|
||||||
|
type : file.type,
|
||||||
|
data : file
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
// Do not paste
|
// Do not paste
|
||||||
@@ -127,7 +162,7 @@ angular.module('client').directive('guacClipboard', [function guacClipboard() {
|
|||||||
* otherwise.
|
* otherwise.
|
||||||
*/
|
*/
|
||||||
$scope.isImage = function isImage() {
|
$scope.isImage = function isImage() {
|
||||||
return !!$scope.imageURL;
|
return !!$scope.content.imageURL;
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -149,10 +184,25 @@ angular.module('client').directive('guacClipboard', [function guacClipboard() {
|
|||||||
$scope.resetClipboard = function resetClipboard() {
|
$scope.resetClipboard = function resetClipboard() {
|
||||||
|
|
||||||
// Reset to blank
|
// Reset to blank
|
||||||
$scope.data = '';
|
$scope.data = new ClipboardData({
|
||||||
|
type : 'text/plain',
|
||||||
|
data : ''
|
||||||
|
});
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// Keep data in sync with changes to text
|
||||||
|
$scope.$watch('content.text', function textChanged(text) {
|
||||||
|
|
||||||
|
if (text) {
|
||||||
|
$scope.data = new ClipboardData({
|
||||||
|
type : $scope.data.type,
|
||||||
|
data : text
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
// Watch clipboard for new data, associating it with any pressed keys
|
// Watch clipboard for new data, associating it with any pressed keys
|
||||||
$scope.$watch('data', function clipboardChanged(data) {
|
$scope.$watch('data', function clipboardChanged(data) {
|
||||||
|
|
||||||
@@ -160,21 +210,35 @@ angular.module('client').directive('guacClipboard', [function guacClipboard() {
|
|||||||
for (var keysym in keysCurrentlyPressed)
|
for (var keysym in keysCurrentlyPressed)
|
||||||
clipboardDataFromKey[keysym] = data;
|
clipboardDataFromKey[keysym] = data;
|
||||||
|
|
||||||
// Revoke old image URL, if any
|
// Stop any current read process
|
||||||
if ($scope.imageURL) {
|
reader.abort();
|
||||||
URL.revokeObjectURL($scope.imageURL);
|
|
||||||
$scope.imageURL = null;
|
// If the clipboard data is a string, render it as text
|
||||||
|
if (typeof data.data === 'string') {
|
||||||
|
$scope.content.text = data.data;
|
||||||
|
$scope.content.imageURL = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
// If the copied data was an image, display it as such
|
// Render Blob/File contents based on mimetype
|
||||||
if (data instanceof Blob) {
|
else if (data.data instanceof Blob) {
|
||||||
$scope.imageURL = URL.createObjectURL(data);
|
|
||||||
$rootScope.$broadcast('guacClipboard', data.type, data);
|
// If the copied data was an image, display it as such
|
||||||
|
if (/^image\//.exec(data.type)) {
|
||||||
|
reader.onload = function updateImageURL() {
|
||||||
|
$scope.$apply(function imageURLLoaded() {
|
||||||
|
$scope.content.text = null;
|
||||||
|
$scope.content.imageURL = reader.result;
|
||||||
|
});
|
||||||
|
};
|
||||||
|
reader.readAsDataURL(data.data);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Ignore other data types
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Otherwise, the data is simply text
|
// Notify of change
|
||||||
else
|
$rootScope.$broadcast('guacClipboard', data);
|
||||||
$rootScope.$broadcast('guacClipboard', 'text/plain', data);
|
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
@@ -20,7 +20,7 @@
|
|||||||
/**
|
/**
|
||||||
* A service for accessing local clipboard data.
|
* A service for accessing local clipboard data.
|
||||||
*/
|
*/
|
||||||
angular.module('client').factory('clipboardService', ['$injector',
|
angular.module('clipboard').factory('clipboardService', ['$injector',
|
||||||
function clipboardService($injector) {
|
function clipboardService($injector) {
|
||||||
|
|
||||||
// Get required services
|
// Get required services
|
||||||
@@ -58,14 +58,14 @@ angular.module('client').factory('clipboardService', ['$injector',
|
|||||||
/**
|
/**
|
||||||
* Sets the local clipboard, if possible, to the given text.
|
* Sets the local clipboard, if possible, to the given text.
|
||||||
*
|
*
|
||||||
* @param {String} text
|
* @param {ClipboardData} data
|
||||||
* The text to which the local clipboard should be set.
|
* The data to assign to the local clipboard should be set.
|
||||||
*
|
*
|
||||||
* @return {Promise}
|
* @return {Promise}
|
||||||
* A promise that will resolve if setting the clipboard was successful,
|
* A promise that will resolve if setting the clipboard was successful,
|
||||||
* and will reject if it failed.
|
* and will reject if it failed.
|
||||||
*/
|
*/
|
||||||
service.setLocalClipboard = function setLocalClipboard(text) {
|
service.setLocalClipboard = function setLocalClipboard(data) {
|
||||||
|
|
||||||
var deferred = $q.defer();
|
var deferred = $q.defer();
|
||||||
|
|
||||||
@@ -73,9 +73,29 @@ angular.module('client').factory('clipboardService', ['$injector',
|
|||||||
var originalElement = document.activeElement;
|
var originalElement = document.activeElement;
|
||||||
|
|
||||||
// Copy the given value into the clipboard DOM element
|
// Copy the given value into the clipboard DOM element
|
||||||
clipboardContent.value = text;
|
clipboardContent.value = 'X';
|
||||||
clipboardContent.select();
|
clipboardContent.select();
|
||||||
|
|
||||||
|
// Override copied contents of clipboard with the provided value
|
||||||
|
clipboardContent.oncopy = function overrideContent(e) {
|
||||||
|
|
||||||
|
// Override the contents of the clipboard
|
||||||
|
e.preventDefault();
|
||||||
|
|
||||||
|
// Remove anything already present within the clipboard
|
||||||
|
var items = e.clipboardData.items;
|
||||||
|
items.clear();
|
||||||
|
|
||||||
|
// If the provided data is a string, add it as such
|
||||||
|
if (typeof data.data === 'string')
|
||||||
|
items.add(data.data, data.type);
|
||||||
|
|
||||||
|
// Otherwise, add as a File
|
||||||
|
else
|
||||||
|
items.add(new File([data.data], 'data', { type : data.type }));
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
// Attempt to copy data from clipboard element into local clipboard
|
// Attempt to copy data from clipboard element into local clipboard
|
||||||
if (document.execCommand('copy'))
|
if (document.execCommand('copy'))
|
||||||
deferred.resolve();
|
deferred.resolve();
|
||||||
@@ -93,7 +113,7 @@ angular.module('client').factory('clipboardService', ['$injector',
|
|||||||
/**
|
/**
|
||||||
* Get the current value of the local clipboard.
|
* Get the current value of the local clipboard.
|
||||||
*
|
*
|
||||||
* @return {Promise}
|
* @return {Promise.<ClipboardData>}
|
||||||
* A promise that will resolve with the contents of the local clipboard
|
* A promise that will resolve with the contents of the local clipboard
|
||||||
* if getting the clipboard was successful, and will reject if it
|
* if getting the clipboard was successful, and will reject if it
|
||||||
* failed.
|
* failed.
|
||||||
@@ -114,9 +134,14 @@ angular.module('client').factory('clipboardService', ['$injector',
|
|||||||
clipboardContent.focus();
|
clipboardContent.focus();
|
||||||
clipboardContent.select();
|
clipboardContent.select();
|
||||||
|
|
||||||
|
// FIXME: Only handling text data
|
||||||
|
|
||||||
// Attempt paste local clipboard into clipboard DOM element
|
// Attempt paste local clipboard into clipboard DOM element
|
||||||
if (document.activeElement === clipboardContent && document.execCommand('paste'))
|
if (document.activeElement === clipboardContent && document.execCommand('paste'))
|
||||||
deferred.resolve(clipboardContent.value);
|
deferred.resolve(new ClipboardData({
|
||||||
|
type : 'text/plain',
|
||||||
|
data : clipboardContent.value
|
||||||
|
}));
|
||||||
else
|
else
|
||||||
deferred.reject();
|
deferred.reject();
|
||||||
|
|
@@ -1,9 +1,9 @@
|
|||||||
<div class="clipboard">
|
<div class="clipboard">
|
||||||
<div ng-if="isText()" class="text-clipboard">
|
<div ng-if="isText()" class="text-clipboard">
|
||||||
<textarea ng-model="data" rows="10" cols="40"></textarea>
|
<textarea ng-model="content.text" rows="10" cols="40"></textarea>
|
||||||
</div>
|
</div>
|
||||||
<div ng-if="isImage()" class="image-clipboard">
|
<div ng-if="isImage()" class="image-clipboard">
|
||||||
<button ng-click="resetClipboard()" class="reset-button">Clear</button>
|
<button ng-click="resetClipboard()" class="reset-button">Clear</button>
|
||||||
<img ng-src="{{imageURL}}">
|
<img ng-src="{{content.imageURL}}">
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
@@ -0,0 +1,59 @@
|
|||||||
|
/*
|
||||||
|
* Licensed to the Apache Software Foundation (ASF) under one
|
||||||
|
* or more contributor license agreements. See the NOTICE file
|
||||||
|
* distributed with this work for additional information
|
||||||
|
* regarding copyright ownership. The ASF licenses this file
|
||||||
|
* to you under the Apache License, Version 2.0 (the
|
||||||
|
* "License"); you may not use this file except in compliance
|
||||||
|
* with the License. You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing,
|
||||||
|
* software distributed under the License is distributed on an
|
||||||
|
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||||
|
* KIND, either express or implied. See the License for the
|
||||||
|
* specific language governing permissions and limitations
|
||||||
|
* under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Provides the ClipboardData class used for interchange between the
|
||||||
|
* guacClipboard directive, clipboardService service, etc.
|
||||||
|
*/
|
||||||
|
angular.module('clipboard').factory('ClipboardData', [function defineClipboardData() {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Arbitrary data which can be contained by the clipboard.
|
||||||
|
*
|
||||||
|
* @constructor
|
||||||
|
* @param {ClipboardData|Object} [template={}]
|
||||||
|
* The object whose properties should be copied within the new
|
||||||
|
* ClipboardData.
|
||||||
|
*/
|
||||||
|
var ClipboardData = function ClipboardData(template) {
|
||||||
|
|
||||||
|
// Use empty object by default
|
||||||
|
template = template || {};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The mimetype of the data currently stored within the clipboard.
|
||||||
|
*
|
||||||
|
* @type String
|
||||||
|
*/
|
||||||
|
this.type = template.type || 'text/plain';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The data currently stored within the clipboard. Depending on the
|
||||||
|
* nature of the stored data, this may be either a String, a Blob, or a
|
||||||
|
* File.
|
||||||
|
*
|
||||||
|
* @type String|Blob|File
|
||||||
|
*/
|
||||||
|
this.data = template.data || '';
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
return ClipboardData;
|
||||||
|
|
||||||
|
}]);
|
Reference in New Issue
Block a user