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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/17527870/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-10-27 08:40:14  来源:igfitidea点击:

How does Trello access the user's clipboard?

javascriptcoffeescriptclipboardtrello

提问by Boldewyn

When you hover over a card in Trelloand press Ctrl+C, the URL of this card is copied to the clipboard. How do they do this?

当您将鼠标悬停在Trello 中的卡片上并按Ctrl+ 时C,此卡片的 URL 将复制到剪贴板。他们怎么做到的?

As far as I can tell, there is no Flash movie involved. I've got Flashblockinstalled, and the Firefox network tab shows no Flash movie loaded. (That's the usual method, for example, by ZeroClipboard.)

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

How do they achieve this magic?

他们是如何实现这种魔力的?

(Right at this moment I think I had an epiphany: You cannot select text on the page, so I assume they have an invisible element, where they create a text selection via JavaScript code, and Ctrl+Ctriggers the browser's default behaviour, copying that invisible node's text value.)

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

回答by Daniel LeCheminant

Disclosure:I wrote the code that Trello uses; the code below is the actual source code Trello uses to accomplish the clipboard trick.

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



We don't actually "access the user's clipboard", instead we help the user out a bit by selecting something useful when they press Ctrl+C.

我们实际上并没有“访问用户的剪贴板”,而是通过在用户按下Ctrl+时选择一些有用的东西来帮助用户C

Sounds like you've figured it out; we take advantage of the fact that when you want to hit Ctrl+C, you have to hit the Ctrlkey first. When the Ctrlkey is pressed, we pop in a textarea that contains the text we want to end up on the clipboard, and select all the text in it, so the selection is all set when the Ckey is hit. (Then we hide the textarea when the Ctrlkey comes up)

听起来你已经想通了;我们利用了这样一个事实,即当您想按Ctrl+ 时C,您必须先按一下Ctrl键。当Ctrl按键被按下时,我们弹出一个包含我们想要在剪贴板上结束的文本的文本区域,并选择其中的所有文本,因此当C按下该键时选择全部设置。(然后我们在Ctrlkey出现时隐藏textarea )

Specifically, Trello does this:

具体来说,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) ->

In the DOM we've got

在 DOM 中,我们有

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

CSS for the clipboard stuff:

剪贴板内容的 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;
}

... and the CSS makes it so you can't actually see the textarea when it pops in ... but it's "visible" enough to copy from.

... CSS 使您在弹出时实际上看不到 textarea ......但它“可见”足以复制。

When you hover over a card, it calls

当您将鼠标悬停在卡片上时,它会调用

TrelloClipboard.set(cardUrl)

... so then the clipboard helper knows what to select when the Ctrlkey is pressed.

...所以剪贴板助手知道Ctrl按下键时要选择什么。

回答by Dhruv Vemula

I actually built a Chrome extensionthat does exactly this, and for all web pages. The source code is on GitHub.

我实际上构建了一个 Chrome 扩展程序,它完全可以做到这一点,并且适用于所有网页。源代码在 GitHub 上

I find three bugs with Trello's approach, which I know because I've faced them myself :)

我发现 Trello 的方法存在三个错误,我知道这是因为我自己也遇到过:)

The copy doesn't work in these scenarios:

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

  1. If you already have Ctrlpressed and then hover a link and hit C, the copy doesn't work.
  2. If your cursor is in some other text field in the page, the copy doesn't work.
  3. If your cursor is in the address bar, the copy doesn't work.
  1. 如果您已经Ctrl按下然后将鼠标悬停在一个链接上并点击C,则该副本将不起作用。
  2. 如果您的光标位于页面中的某个其他文本字段中,则副本不起作用。
  3. 如果您的光标在地址栏中,则副本不起作用。

I solved #1 by always having a hidden span, rather than creating one when user hits Ctrl/Cmd.

我通过总是有一个隐藏的跨度来解决 #1,而不是在用户点击Ctrl/时创建一个Cmd

I solved #2 by temporarily clearing the zero-length selection, saving the caret position, doing the copy and restoring the caret position.

我通过临时清除零长度选择、保存插入符号位置、进行复制和恢复插入符号位置来解决 #2。

I haven't found a fix for #3 yet :) (For information, check the open issue in my GitHub project).

我还没有找到 #3 的修复程序:)(有关信息,请查看我的 GitHub 项目中的未解决问题)。

回答by Felix

With the help of raincoat's (link to GitHub) code, I managed to get a running version accessing the clipboard with plain JavaScript.

在raincoat(指向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");

The only problem is, that this version only works with Chrome. The Trello platform supports all browsers. What I am missing?

唯一的问题是,此版本仅适用于 Chrome。Trello 平台支持所有浏览器。我缺少什么?

Sovled thanks to VadimIvanov.

感谢 VadimIvanov。

See a working example: http://jsfiddle.net/AGEf7/

查看一个工作示例:http: //jsfiddle.net/AGEf7/

回答by TugboatCaptain

Daniel LeCheminant's code didn't work for me after converting it from CoffeeScript to JavaScript (js2coffee). It kept bombing out on the _.defer()line.

Daniel LeCheminant 的代码在将其从 CoffeeScript 转换为 JavaScript ( js2coffee)后对我不起作用。它一直在线上轰炸_.defer()

I assumed this was something to do with jQuery deferreds, so I changed it to $.Deferred()and it's working now. I tested it in Internet Explorer 11, Firefox 35, and Chrome 39 with jQuery 2.1.1. The usage is the same as described in Daniel's post.

我认为这与 jQuery 延迟有关,所以我将其更改为$.Deferred()现在可以使用了。我在 Internet Explorer 11、Firefox 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;

})());

回答by Boris Brdari?

Something very similar can be seen on http://goo.glwhen you shorten the URL.

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

There is a readonly input element that gets programmatically focused, with tooltip press CTRL-Cto copy.

有一个只读输入元素,它以编程方式聚焦,工具提示按下CTRL-C复制。

When you hit that shortcut, the input content effectively gets into the clipboard. Really nice :)

当您点击该快捷方式时,输入内容会有效地进入剪贴板。非常好 :)