在编辑器开发中, 遇到了需要设置内容到剪贴板和获取并剪贴板内容的情况. 有关以下问题
可以参考 THE DEFINITIVE GUIDE TO COPYING AND PASTING IN JAVASCRIPT
下面分享以下在 THE DEFINITIVE GUIDE TO COPYING AND PASTING IN JAVASCRIPT 基础上如何实现跨浏览器支持自定义类型.
从 THE DEFINITIVE GUIDE TO COPYING AND PASTING IN JAVASCRIPT 一文我们可以了解
到clipboardData.setData(type, value)
API 中 type
在不同浏览器中的支持情况:
- Chrome and Safari: They support any content type on the clipboardData, including custom types. So, we can call
clipboardData.setData('application/lucidObjects', serializedObjects)
for pasting, and then callvar serialized = clipboardData.getData('application/lucidObjects')
- Firefox: It currently only allows access to the data types described above. You can set custom types on copy, but when pasting, only the white-listed types are passed through.
- Internet Explorer: In true IE fashion, it supports just two data types:
Text
andURL
. Oh, and if you set one, you can’t set the other (it gets nulled out). There is a hack, however, that also allows us to indirectly get and set HTML.
Windows Edge 浏览器的情况与 FireFox
类似 ( Windows Edge 浏览器2016年才发布, THE DEFINITIVE GUIDE TO COPYING AND PASTING IN JAVASCRIPT 一文写于 2014 年, 故没有提到 Windows Edge ).
在编辑器(仅支持 Webkit 内核浏览器和 Windows Edge )中, 除了设置text/plain
, text/html
到剪贴板外, 还会用到挺多自定义类型的数据 (如 text/yne-table-json
, text/yne-json
). 自定义类型数据的主要使用场景是:
但 Windows Edge 浏览器的剪贴板又不支持自定义类型数据, 于是琢磨着如何应对 Windows Edge 浏览器.
try ... catch ...
设置内容到剪贴板, 如果不能设置到剪贴板, 则不设置.第一种解决方案肯定不太好, 而第二种方案又该如何实现呢?
在 Clipboard API and events - Mandatory data types 可以发现, 剪贴板支持读取的数据类型:
- text/plain
- text/uri-list
- text/csv
- text/css
- text/html
- application/xhtml+xml
- image/png
- image/jpg, image/jpeg
- image/gif
- image/svg+xml
- application/xml, text/xml
- application/javascript
- application/json
- application/octet-stream
剪贴板支持写入的数据类型
- text/plain
- text/uri-list
- text/csv
- text/html
- image/svg+xml
- application/xml, text/xml
- application/json
无论读取还是写入剪贴板, 都支持写入类型.
能否将自定义类型数据 JSON 序列化后写入标准写入类型中的一种呢? 要读取时,也可以
从剪贴板中读取该标准写入类型, JSON 处理后再提取出自定义类型.
后来实验成功, 以下是参考代码:
DataTransfer.js
/**
*
* @see https://www.lucidchart.com/techblog/2014/12/02/definitive-guide-copying-pasting-javascript
* @see https://w3c.github.io/clipboard-apis/#mandatory-data-types
*
* @author fudesign2008
* @date 2016-12-29
*/
define(function (require) {
var _ = require('underscore'),
Class = require('jtk/core/Class'),
L = require('jtk/core/L'),
USER_AGENT = require('../util/userAgent'),
ONLY_SUPPORT_STANDARD_TYPES = USER_AGENT.isEdge(),
REGISTERED_TYPES = {
/**
* @type {Boolean} is standard type or not
* @see https://w3c.github.io/clipboard-apis/#mandatory-data-types
*/
'text/html': true,
'text/plain': true,
'text/uri-list': true,
'text/yne-image-json': false,
'text/yne-json': false,
'text/yne-note-id': false,
'text/yne-table-json': false,
},
ALT_STANDARD_TYPE = 'application/json',
DataTransfer;
DataTransfer = Class.extend({
/**
* @param {Event} options.event
*/
initialize: function (options) {
var that = this,
event = options.event,
rawEvent = event.originalEvent || event;
that._dataTransfer = rawEvent.dataTransfer;
},
_getCustomData: function (type) {
var that = this,
dataStr,
dataObj;
if (!that._altData) {
dataStr = that._dataTransfer.getData(ALT_STANDARD_TYPE);
try {
dataObj = JSON.parse(dataStr);
that._altData = dataObj;
} catch (ex) {
L.error(ex);
that._altData = {};
}
}
return that._altData[type];
},
/**
* @param {String} type
* @return {Any}
*/
getData: function (type) {
var that = this,
dataTransfer = that._dataTransfer,
isStardard,
value;
if (ONLY_SUPPORT_STANDARD_TYPES) {
isStardard = REGISTERED_TYPES[type];
if (isStardard === true) {
value = dataTransfer.getData(type);
L.log('get standard type', type, value);
} else if (isStardard === false) {
value = that._getCustomData(type);
L.log('get custom type', type, value);
} else {
L.error('type should be registered!', type);
}
return value;
} else {
return dataTransfer.getData(type);
}
},
/**
* @param {Object} data
*/
setDataMap: function (dataMap) {
var dataTransfer = this._dataTransfer,
setData = function (value, type) {
L.log('set data to data transfer', type, value);
try {
dataTransfer.setData(type, value);
} catch (ex) {
L.error(ex);
}
},
customData = {},
customCounter = 0,
str;
if (ONLY_SUPPORT_STANDARD_TYPES) {
_.each(dataMap, function (value, type) {
var isStardard = REGISTERED_TYPES[type];
if (isStardard === true) {
setData(value, type);
} else if (isStardard === false){
L.log('set custom type', type);
customData[type] = value;
customCounter++;
} else {
L.error('type should be registered!', type);
}
});
if (customCounter > 0) {
try {
str = JSON.stringify(customData);
setData(str, ALT_STANDARD_TYPE);
} catch (ex) {
L.error(ex);
}
}
} else {
_.each(dataMap, setData);
}
}
});
return DataTransfer;
});
ClipboardData.js
/**
*
* @see https://www.lucidchart.com/techblog/2014/12/02/definitive-guide-copying-pasting-javascript
* @see https://w3c.github.io/clipboard-apis/#mandatory-data-types
*
* @author fudesign2008
* @date 2016-12-29
*/
define(function (require) {
var DataTransfer = require('./DataTransfer'),
ClipboardData = DataTransfer.extend({
/**
* @param {Event} options.event
* @override
*/
initialize: function (options) {
var that = this,
event = options.event,
rawEvent = event.originalEvent || event;
that._dataTransfer = rawEvent.clipboardData;
}
});
return ClipboardData;
});
无论在 Webkit 内核浏览器和 Windows Edge 浏览器都能如此使用:
var ClipboardData = require('./ClipboardData');
$(el).on('copy', function (event) {
var clipboardData = new ClipboardData({
event: event
});
clipboardData.setDataMap({
'text/plain': 'plain xxxx',
'text/html': 'html xxxx',
'yne-json': 'xxxx',
'yne-table-json': 'yyyy'
});
}).on('paste', function (event) {
var clipboardData = new ClipboardData({
event: event
}),
html = clipboardData.get('text/html'),
yneTableJSON = clipboardData.get('yne-table-json');
console.log('clipboard data text/html', html);
console.log('clipboard data yne-table-json', yneTableJSON);
});
以上方案能够解决以下场景
无法解决以下场景