955 Stimmen

Wie greift Trello auf die Zwischenablage des Benutzers zu?

Wenn Sie in Trello über eine Karte fahren und Strg+C drücken, wird die URL dieser Karte in die Zwischenablage kopiert. Wie machen sie das?

So weit ich sehen kann, ist hier kein Flash-Film beteiligt. Ich habe Flashblock installiert und das Firefox-Netzwerktab zeigt keinen geladenen Flash-Film. (Das ist die übliche Methode, z.B. von ZeroClipboard.)

Wie erreichen sie diese Magie?

(Gerade in diesem Moment denke ich, dass ich eine Erkenntnis hatte: Sie können keinen Text auf der Seite auswählen, also nehme ich an, dass sie ein unsichtbares Element haben, wo sie durch JavaScript-Code eine Textauswahl erstellen, und Strg+C löst das Standardverhalten des Browsers aus, indem sie den Textwert dieses unsichtbaren Knotens kopieren.)

1562voto

Daniel LeCheminant Punkte 49305

Offenlegung: Ich habe den Code geschrieben, den Trello verwendet; der nachfolgende Code ist der tatsächliche Quellcode, den Trello verwendet, um den Zwischenspeichertrick zu bewerkstelligen.


Wir haben eigentlich keinen "Zugriff auf die Zwischenablage des Benutzers", sondern wir helfen dem Benutzer ein wenig, indem wir etwas Nützliches auswählen, wenn sie Strg+C drücken.

Es klingt so, als ob du es herausgefunden hast; wir nutzen die Tatsache aus, dass du den Strg-Taste zuerst drücken musst, wenn du Strg+C drücken möchtest. Wenn die Strg-Taste gedrückt wird, fügen wir ein Textfeld ein, das den Text enthält, den wir auf der Zwischenablage haben möchten, und wählen den gesamten Text darin aus, damit die Auswahl bereit ist, wenn die C-Taste gedrückt wird. (Dann verstecken wir das Textfeld, wenn die Strg-Taste losgelassen wird.)

Genau genommen macht Trello dies:

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

    $(document).keydown (e) =>
      # Dies nur machen, wenn etwas auf die Zwischenablage gelegt werden soll und es aussieht, als würden sie eine Kopier-Verknüpfung starten
      if !@value || !(e.ctrlKey || e.metaKey)
        return

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

      # Abbrechen, wenn es so aussieht, als ob sie etwas Text ausgewählt haben (vielleicht versuchen sie, einen Teil der Beschreibung oder so zu kopieren)
      if window.getSelection?()?.toString()
        return

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

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

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

  set: (@value) ->

Im DOM haben wir:

CSS für den Zwischenablage-Kram:

#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;
}

... und das CSS sorgt dafür, dass du das Textfeld tatsächlich nicht sehen kannst, wenn es auftaucht ... aber es ist "genug sichtbar", um daraus zu kopieren.

Wenn du über eine Karte schwebst, wird aufgerufen

TrelloClipboard.set(cardUrl)

... dann weiß der Zwischenablagenhelfer, was ausgewählt werden soll, wenn die Strg-Taste gedrückt wird.

83voto

Dhruv Vemula Punkte 952

Ich habe tatsächlich eine Chrome-Erweiterung erstellt, die genau das tut, und zwar für alle Webseiten. Der Quellcode befindet sich auf GitHub.

Ich finde drei Fehler im Ansatz von Trello, die ich kenne, weil ich sie selbst erlebt habe :)

Das Kopieren funktioniert in folgenden Szenarien nicht:

  1. Wenn Sie bereits die Taste Strg gedrückt halten und dann auf einen Link zeigen und C drücken, funktioniert das Kopieren nicht.
  2. Wenn sich Ihr Cursor in einem anderen Textfeld auf der Seite befindet, funktioniert das Kopieren nicht.
  3. Wenn sich Ihr Cursor in der Adressleiste befindet, funktioniert das Kopieren nicht.

Ich habe Problem #1 gelöst, indem ich immer einen versteckten Span erstellt habe, anstatt einen zu erstellen, wenn der Benutzer Strg/Cmd drückt.

Problem #2 habe ich gelöst, indem ich die Auswahl der Länge Null vorübergehend gelöscht, die Caret-Position gespeichert, das Kopieren durchgeführt und die Caret-Position wiederhergestellt habe.

Ich habe noch keine Lösung für Problem #3 gefunden :) (Für weitere Informationen überprüfen Sie das offene Problem in meinem GitHub-Projekt).

23voto

Felix Punkte 977

Mit Hilfe des Codes von raincoat auf GitHub konnte ich eine laufende Version erstellen, die auf die Zwischenablage mit reinem JavaScript zugreift.

function TrelloClipboard() {
    var ich = 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(ich.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");

Sieh dir ein funktionierendes Beispiel an: http://jsfiddle.net/AGEf7/

7voto

TugboatCaptain Punkte 3824

Daniel LeCheminants Code hat bei mir nicht funktioniert, nachdem ich es von CoffeeScript nach JavaScript konvertiert habe (js2coffee). Es gab immer einen Abbruch in der _.defer() Zeile.

Ich nahm an, dass dies mit jQuery Deferreds zu tun hatte, also änderte ich es in $.Deferred() und jetzt funktioniert es. Ich habe es in Internet Explorer 11, Firefox 35 und Chrome 39 mit jQuery 2.1.1 getestet. Die Verwendung ist die gleiche wie in Daniels Beitrag beschrieben.

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 $("").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;

})());

5voto

Boris Brdarić Punkte 4614

Etwas Ähnliches kann man sehen unter http://goo.gl, wenn man die URL verkürzt.

Es gibt ein schreibgeschütztes Eingabefeld, das programmgesteuert fokussiert wird, mit dem Tooltip drücken Strg+C zum Kopieren.

Wenn man diese Tastenkombination verwendet, wird der Inhalt des Eingabefelds tatsächlich in die Zwischenablage kopiert. Wirklich nett :)

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X