剪贴板自定义类型跨浏览器支持
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:
Textand
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 JAVASCRIPTClipboard API and events - Mandatory data types
相关文章推荐
- net控件中数据导到Excel的格式 首先,我们了解一下excel从web页面上导出的原理。当我们把这些数据发送到客户端时,我们想让客户端程序(浏览器)以excel的格式读取它,所以把mime类型设为:application/vnd.ms-excel,当excel读取文件时会以每个cell的格式呈现数据,如果cell没有规定的格式,则excel会以默认的格式去呈现该cell的数据。这样就给我们提供了自定义数据格式的空间,当然我们必须使用excel支持的格式。下面就列出常用的一些格式: 1) 文本
- 9-2 支持自定义数据类型的托拽(Supporting Custom Drag Types)
- explicit和implicit属于转换运算符,如用这两者可以让我们自定义的类型支持相互交换。
- Jquery tablesorter addParser 支持多浏览器,多列同时排序,自定义排序
- js设置剪贴板数据 event.clipboardData.setData("text/plain",value);不起作用,并非所有的浏览器都支持,限制了
- 浅谈浏览器插件检测 和自定义协议的支持
- Oracle不支持在select语句中调用自定义函数时使用自定义类型作参数?
- Android 浏览网页:WebView 嵌入浏览器(浏览历史返回、自定义加载失败界面、支持缩放、获取标题栏)
- android 默认浏览器 无法下载,此手机不支持此内容(自定义文件or APK文件看过了)
- notepad++支持自定义文件类型
- 黄聪:wordpress前台自定义用户,调用wp_editor上传附件提示【抱歉,出于安全的考虑,不支持此文件类型】错误。
- 黑莓浏览器通过BES服务器访问Tomcat服务器上的Word文档,报错,不支持的媒体类型:application/vnd.ms-wsworld
- SQLite3支持自定义数据类型
- xml不支持自定义的css模式(浏览器问题)
- 使Firefox浏览器支持ocx类型的插件
- [转]浅谈浏览器插件检测 和自定义协议的支持
- 工作学习笔记——C#自定义类型剪贴板操作、自定义鼠标光标定位问题
- 发布首款支持Shift/Ctrl多选的国产日历控件,界面仿Twitter风格,支持中文日期类型,支持SImpleDateFormat格式,支持change等自定义事件,全中文注释和API,欢迎支持
- jQuery 1.9不支持$.browser 怎么判断浏览器类型和版本
- Axure文本框控件的11种类型和支持的浏览器类型