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

当您将鼠标hover在Trello中的卡片上并按Ctrl + C时 ,此卡片的URL将被复制到剪贴板。 他们如何做到这一点?

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

他们如何实现这个魔法?

(在这一刻,我想我有一个顿悟:你不能select页面上的文本,所以我假设他们有一个不可见的元素,他们通过JavaScript代码创build一个文本select, Ctrl + C触发浏览器的默认行为,复制那个看不见的节点的文本值。)

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


我们实际上并不是“访问用户的剪贴板”,而是通过按Ctrl + C来select一些有用的东西来帮助用户。

听起来你已经知道了; 我们利用这个事实,即当你想按Ctrl + C时 ,你必须先按下Ctrl键。 当按下Ctrl键时,我们popup一个包含我们想要在剪贴板上结束的文本的textarea,并select其中的所有文本,所以当C键被击中时,所有的select都被设置。 (然后当Ctrl键出现时我们隐藏textarea)

具体来说,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这样做,所以你不能真正看到textarea时,它popup…但它是“可见的”足以复制。

当你将鼠标hover在卡上时,它会调用

 TrelloClipboard.set(cardUrl) 

…所以然后剪贴板助手知道按下Ctrl键时要select什么。

我实际上构build了一个Chrome扩展 ,完成了这一切,并为所有的网页。 源代码在GitHub上 。

我发现Trello的方法有三个错误,我知道是因为我自己面对过他们:)

该副本在这些情况下不起作用:

  1. 如果您已经按下Ctrl键,然后hover一个链接并点击C ,副本不起作用。
  2. 如果您的光标位于页面的其他文本字段中,则复制不起作用。
  3. 如果您的光标在地址栏中,则复制不起作用。

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

我通过暂时清除零长度选项,保存插入位置,复制和恢复插入位置来解决#2问题。

我还没有find#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 keyDownMonitor = 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', keyDownMonitor) document.addEventListener('keyup', keyUpMonitor) } TrelloClipboard.prototype.setValue = function (value) { this.value = value; } var clip = new TrelloClipboard(); clip.setValue("test"); 

唯一的问题是,这个版本只适用于Chrome。 Trello平台支持所有浏览器。 我错过了什么?

非常感谢VadimIvanov。

看到一个工作的例子: http : //jsfiddle.net/AGEf7/

Daniel LeCheminant的代码在将它从CoffeeScript转换为JavaScript( js2coffee )之后并不适用于我。 它不断在_.defer()行上轰炸。

我认为这是与jQuery延期有关,所以我将其更改为$.Deferred() ,现在它正在工作。 我使用jQuery 2.1.1在Internet Explorer 11,Firefox 35和Chrome 39中testing了它。 用法与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; })()); 

缩短url时,可以在http://goo.gl上看到非常相似的内容。;

有一个readonlyinput元素,获取以编程为中心的工具提示“按CTRL-C复制”。 当你点击该快捷方式时,input的内容就会有效地进入剪贴板。 非常好 :)