首页 文章

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

提问于
浏览
903

将鼠标悬停在Trello中的卡片上并按Ctrl C时,此卡片的URL将复制到剪贴板 . 他们如何做到这一点?

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

他们如何实现这种魔力?

(此刻我认为我有一个顿悟:你不能在页面上选择文本,所以我假设他们有一个不可见的元素,他们通过JavaScript代码创建文本选择,Ctrl C触发浏览器's default behaviour, copying that invisible node'的文本值 . )

5 回答

  • 19

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

    有一个readonly输入元素,以编程方式聚焦,工具提示“按CTRL-C复制” . 当您点击该快捷方式时,输入内容将有效地进入剪贴板 . 非常好 :)

  • 77

    Daniel LeCheminant 's code didn'在将它从CoffeeScript转换为JavaScript(js2coffee)之后为我工作 . 它继续轰炸 _.defer() 线 .

    我认为这与jQuery延迟有关,所以我将其更改为 $.Deferred() 并将其更改为'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' .

    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;
    
    })());
    
  • 7

    我实际上构建了a Chrome extension,它正是这样做的,并且适用于所有网页 . 源代码是on GitHub .

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

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

    • 如果您已按下Ctrl键,然后将鼠标悬停在链接上并点击C,则副本不起作用 .

    • 如果光标位于页面中的其他文本字段中,则副本不起作用 .

    • 如果光标位于地址栏中,则副本不起作用 .

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

    我通过暂时清除零长度选择,保存插入位置,执行复制和恢复插入位置来解决#2 .

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

  • 5

    在雨衣(link to 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/

  • 1520

    Disclosure: I wrote the code that Trello uses;下面的代码是Trello用来完成剪贴板技巧的实际源代码 .


    我们实际上并不是"access the user's clipboard",而是通过在按下Ctrl C时选择有用的东西来帮助用户 .

    听起来你已经弄清楚了;我们利用了这样一个事实:当你想要按Ctrl C时,你必须先按Ctrl键 . 当按下Ctrl键时,我们弹出一个textarea,其中包含我们想要在剪贴板上结束的文本,并选择其中的所有文本,因此当C键被命中时,所有选择都会被设置 . (然后我们在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 ...但是它“可见”足以复制 .

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

    TrelloClipboard.set(cardUrl)
    

    ...因此,当按下Ctrl键时,剪贴板助手知道要选择什么 .

相关问题