javascript - Trello如何访问用户的剪贴板?

  显示原文与译文双语对照的内容

当你徘徊在一张卡片 Trello和按 Ctrl + C, 这张卡片的url复制到剪贴板。 他们怎么做的?

据我所知,没有涉及 Flash 电影。 已经安装 Flashblock web,Firefox 网络选项卡显示没有加载 Flash 电影。 ( 这是通常的方法,例如 ZeroClipboard 。)

他们如何实现这种魔力?

( 现在我想到了一个顿悟: 你不能选择文本在页面上,所以我认为他们有一个无形的元素,他们通过javascript代码,创建一个文本选择和 Ctrl + C 触发浏览器的默认行为,复制的无形的文本节点值)。

时间:

披露:我写的代码Trello使用;下面的代码是实际的源代码Trello用来完成剪贴板的诀窍。


我们实际上不"访问剪贴板"用户,而不是我们帮助用户通过选择一些有用的东西,当他们按 Ctrl C +

听起来像你搞懂了,我们利用这一事实当你想打击 Ctrl + C, 你必须先按 Ctrl键。 Ctrl键被按下时,突然出现一个文本区域,其中包含文本我们想最终在剪贴板上,并选择所有文本,所以选择时都是集 C 关键是打击。 ( 然后,当对象 Ctrl键出现时,我们隐藏文本文本)

具体来说,Trello执行以下操作:


TrelloClipboard = new class
 constructor: ->
 @value =""

 $(document).keydown (e) =>
 # Only do this if there's something to be put on the clipboard, and it
 # looks like they're starting a copy shortcut
 if!@value ||!(e.ctrlKey || e.metaKey)
 return

 if $(e.target).is("input:visible,textarea:visible")
 return

 # Abort if it looks like they've selected some text (maybe they're trying
 # to copy out a bit of the description or something)
 if window.getSelection?()?.toString()
 return

 if document.selection?.createRange().text
 return

 _.defer =>
 $clipboardContainer = $("#clipboard-container")
 $clipboardContainer.empty().show()
 $("<textarea id='clipboard'></textarea>")
. val(@value)
. appendTo($clipboardContainer)
. focus()
. select()

 $(document).keyup (e) ->
 if $(e.target).is("#clipboard")
 $("#clipboard-container").empty().hide()

 set: (@value) ->

在DOM中我们得到了


<div id="clipboard-container"><textarea id="clipboard"></textarea></div>

剪贴板内容的CSS:


#clipboard-container {
 position: fixed;
 left: 0px;
 top: 0px;
 width: 0px;
 height: 0px;
 z-index: 100;
 display: none;
 opacity: 0;
}
#clipboard {
 width: 1px;
 height: 1px; 
 padding: 0px;
}

。和css使它所以你不能看到当它出现在文本区域。 但是它可以从"可见"复制。

当你在一张卡片上停留时,它就会调用


TrelloClipboard.set(cardUrl)

。所以那么剪贴板 helper 就知道该怎么选择当 Ctrl 键已经按下。

我实际上建立 Chrome 扩展,确实就是这个,和所有web页面。 源代码是上的。

我发现三个 Bug 有trello方法,我知道,因为我自己面对它们:)

副本在以下情况下不起作用:

  1. 如果你已经有 Ctrl压然后悬停链接,点击 C, 复制不工作。
  2. 如果光标位于页面中其他文本字段中,则该副本无法工作。
  3. 如果你的光标位于地址栏中,则副本无法工作。

我解决了 #1 总是有一个隐藏的跨度,而不是创建一个当用户点击 Ctrl/Cmd

我解决了 #2 暂时清理zero-length选择,节省脱字符号的位置,复制和恢复插入符号的位置。

我还没有找到 #3的修复:( 有关信息,请检查我的GitHub项目中的打开问题) 。

借助( 雨衣链接到github的 ) 代码,我设法得到一个运行的版本,使用纯javascript访问剪贴板。


function TrelloClipboard() {
 var me = this;

 var utils = {
 nodeName: function (node, name) {
 return!!(node.nodeName.toLowerCase() === name)
 }
 }
 var textareaId = 'simulate-trello-clipboard',
 containerId = textareaId + '-container',
 container, textarea

 var createTextarea = function () {
 container = document.querySelector('#' + containerId)
 if (!container) {
 container = document.createElement('div')
 container.id = containerId
 container.setAttribute('style', [, 'position: fixed;', 'left: 0px;', 'top: 0px;', 'width: 0px;', 'height: 0px;', 'z-index: 100;', 'opacity: 0;'].join(''))
 document.body.appendChild(container)
 }
 container.style.display = 'block'
 textarea = document.createElement('textarea')
 textarea.setAttribute('style', [, 'width: 1px;', 'height: 1px;', 'padding: 0px;'].join(''))
 textarea.id = textareaId
 container.innerHTML = ''
 container.appendChild(textarea)

 textarea.appendChild(document.createTextNode(me.value))
 textarea.focus()
 textarea.select()
 }

 var keyDonwMonitor = function (e) {
 var code = e.keyCode || e.which;
 if (!(e.ctrlKey || e.metaKey)) {
 return
 }
 var target = e.target
 if (utils.nodeName(target, 'textarea') || utils.nodeName(target, 'input')) {
 return
 }
 if (window.getSelection && window.getSelection() && window.getSelection().toString()) {
 return
 }
 if (document.selection && document.selection.createRange().text) {
 return
 }
 setTimeout(createTextarea, 0)
 }

 var keyUpMonitor = function (e) {
 var code = e.keyCode || e.which;
 if (e.target.id!== textareaId || code!== 67) {
 return
 }
 container.style.display = 'none'
 }

 document.addEventListener('keydown', keyDonwMonitor)
 document.addEventListener('keyup', keyUpMonitor)
}

TrelloClipboard.prototype.setValue = function (value) {
 this.value = value;
}

var clip = new TrelloClipboard();
clip.setValue("test");

唯一的问题是,这个版本只适用于 Chrome.The Trello plattform支持所有浏览器。 我缺少的东西?

VadimIvanov感谢。

请参阅一个工作示例:http://jsfiddle.net/AGEf7/

lecheminant代码在从coffeescript转换到 javascript ( js2coffee ) 后对我不起作用。 它一直在 _.defer() 线上爆炸。 我认为这与 jQuery deferreds有关,所以我把它改成 $.Deferred(),现在它工作了。 在 IE 11,FF 35,& Chrome 39,使用 jQuery 2.1.1测试。 用法与daniel的文章中描述的相同。


var TrelloClipboard;

TrelloClipboard = new ((function () {
 function _Class() {
 this.value ="";
 $(document).keydown((function (_this) {
 return function (e) {
 var _ref, _ref1;
 if (!_this.value ||!(e.ctrlKey || e.metaKey)) {
 return;
 }
 if ($(e.target).is("input:visible,textarea:visible")) {
 return;
 }
 if (typeof window.getSelection ==="function"? (_ref = window.getSelection())!= null? _ref.toString() : void 0 : void 0) {
 return;
 }
 if ((_ref1 = document.selection)!= null? _ref1.createRange().text : void 0) {
 return;
 }
 return $.Deferred(function () {
 var $clipboardContainer;
 $clipboardContainer = $("#clipboard-container");
 $clipboardContainer.empty().show();
 return $("<textarea id='clipboard'></textarea>").val(_this.value).appendTo($clipboardContainer).focus().select();
 });
 };
 })(this));
 $(document).keyup(function (e) {
 if ($(e.target).is("#clipboard")) {
 return $("#clipboard-container").empty().hide();
 }
 });
 }

 _Class.prototype.set = function (value) {
 this.value = value;
 };

 return _Class;

})());

...