您的位置:首页 > Web前端 > JavaScript

剪贴板自定义类型跨浏览器支持

2017-01-03 14:11 323 查看

引子

在编辑器开发中, 遇到了需要设置内容到剪贴板和获取并剪贴板内容的情况. 有关以下问题

跨浏览器获取Clipboard

从剪贴板中获取不同类型数据

可以参考 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 call
var 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
and
URL
. 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
). 自定义类型数据的主要使用场景是:

同一个端不同笔记间(同一个编辑器, 不同实例)相互拷贝粘贴

不同端的编辑器(不同编辑器, 不同实例)相互拷贝粘贴, 如从PC端中的编辑器拷贝, 粘贴到Web浏览器的编辑器中

但 Windows Edge 浏览器的剪贴板又不支持自定义类型数据, 于是琢磨着如何应对 Windows Edge 浏览器.

在 Windows Edge 下
try ... catch ...
设置内容到剪贴板, 如果不能设置到剪贴板, 则不设置.

无论在 Webkit 内核浏览器还是 Windows Edge 中, 都能统一处理设置到剪贴板.

第一种解决方案肯定不太好, 而第二种方案又该如何实现呢?

思路

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);

});


以上方案能够解决以下场景

同一个端不同笔记间(同一个编辑器, 不同实例)相互拷贝粘贴

无法解决以下场景

不同端的编辑器(不同编辑器, 不同实例)相互拷贝粘贴, 如从PC端中的编辑器拷贝, 粘贴到Web浏览器的编辑器中

参考

THE DEFINITIVE GUIDE TO COPYING AND PASTING IN JAVASCRIPT

Clipboard API and events - Mandatory data types
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
相关文章推荐