4

Context

The real free software (GPLv3) application (motivating this question) that I am coding is the MELT monitor on github (FWIW, I am at commit 56a83d358d3966eddb55... on February 11th, 2016). It is on Linux/x86_64/Debian, Firefox/44, JQuery-2.2.0, JqueryUI 1.11.4, clipboard.js 1.5.8....

A more open (but without code) related question was downvoted on Programmers. So I made a JsFiddle example for this very question, but that JsFiddle example is probably very wrong.

I have a (dynamically generated) HTML document with some <span>-s of class='momitemref_cl' like <span class='momitemref_cl'>this</span> etc... (the inside content of such spans is always a single word like this, actually some variable name or identifier in some DSL of mine). My goal is to have a dynamically generated menu for each such spans to enable some operations on them, in particular: hilight every occurrence of that word, and copy & select the word to the browser's and desktop's clipboard.

There are many questions here about copying to the clipboard in Javascript, such as this one. Several of them mention Zeno Rocha's clipboard.js which I am trying to use.

Code with explanation

To explain some of the JsFiddle: I am creating the JQueryUI menu with

// make a menu for the given span
function make_menu(spa) {
  console.log("make_menu spa=", spa);
  var name = $(spa).text();
  mom_menuitemcount++;
  var menuid = "menuid_" + mom_menuitemcount;
  console.log("make_menu name=", name, " menuid=", menuid);
  $maindiv.after("<ul class='mommenu_cl' id='" + menuid + "'>"
               + "<li class='ui-state-disabled'>* <i>" + name + "</i> *</li>"
    // the text inside the following <li> matters
    + "<li>Hilight</li>" + "<li>Copy</li>" + "</ul>");
  var mymenu = $('#' + menuid);
  mymenu.menu({
    select: function(ev, ui) {
      var uitem = ui.item;
      var utext = uitem.text();
      console.log("mymenu-select ev=", ev, " ui=", ui, " name=", name,
        " uitem=", uitem, " utext=", utext);
      switch (utext) {
        case "Hilight":
          $maindiv.find(".momitemref_cl").each(function(ix, el) {
            var etext = $(el).text();
            console.log("hilighting el=", el, " etext=", etext);
            if (etext == name) {
              $(el).toggleClass("momhilight_cl");
            }
          });
          break;
        case "Copy":
          //// what should go here?
          break;
      };
      setTimeout(200, destroy_menu);
    },
    position: {
      my: "left top",
      at: "bottom left",
      of: spa
    }
  });
  mom_menuitem = mymenu;
  console.log("make_menu spa=", spa, " mymenu=", mymenu);
  return mymenu;
}

In the above code, I don't know what to put in //// what should go here?; perhaps it might be something similar to:

uitem.select();
document.execCommand('Copy');

but AFAIU this don't work as expected, and I feel that clipboard operations need the user event (e.g. a mouse click or down) trigerring them.

The clipboard is initialized with

$clipboardh = new Clipboard(".momitemref_cl", {
  text: function (trig) {
    console.log("clipboard text trig=", trig);
    /// some code is missing here probably
  };
});

I guess (but I am not sure) that the /// some code is missing here probably should return the text value of the relevant span.

Questions

So I don't know how to copy the span's content to the clipboard (//// what should go here? ....) and how to put into the clipboard its text (/// some code is missing here probably....)

The full MVCE code is this JsFiddle

In other words, how to use clipboard.js from a JQueryUI menu item to copy a span's content to the browser's clipboard ??


Perhaps the entire approach is wrong, and perhaps I should use contextmenu (but then, how to customize it only for span-s of class='momitemref_cl' ?)

To make things even more complex, I actually have in MELT monitor (but not in this JsFiddle...) two CSS classes mom_itemref_cl & mom_itemval_cl that I want to behave likewise.


PS. I messed the JsFiddle when copying code here. I updated it, https://jsfiddle.net/bstarynk/g2notLd7/132/

NB. I could be satisfied with an answer working only on recent Firefox & Chrome.

4

2 に答える 2

4

コピー イベントをトリガーする要素に Clipboard.js をアタッチする必要があります。あなたの場合、これはメニュー<li>Copy</li>内の要素であり、右クリックmommenu_clすると動的に作成されます。メニュー自体を作成するときに、動的にmomitemref_clcopy に clipboard.js をアタッチできます。liメニューを破棄するときは、クリップボードも破棄する必要があります。

まず、更新されたフィドルの 87 行目のタイプミスを修正しましょう。

curmenu[0].stle.left = Math.round(ev.pageY) + 5;

次に、DOM の ready ハンドラーからクリップボードを削除します。これをmake_menu関数に移動します。

$(document).ready(function() {
  $maindiv = $('#maindiv_id');
  // no clipboard initialization here
  console.log("our document ready function");
  ...
});

次に、スクリプトの先頭で、最初に を宣言し$clipboardh、 に初期化しfalseます。後で、クリップボードが現在接続されていない場合にのみクリップボードを接続することを確認します。

/// javascript code
var $clipboardh = false;

make_menu関数で、<li>Copy</li>要素に属性を与えてclass="copy"、clipboard.js を簡単にアタッチできるようにdata-clipboard-textし、要素がクリックされたときに clipboard.js がコピーする値に設定された属性を設定します。

変数にはコピーするテキスト値が含まれているため、nameメニューは次のようになります。

$maindiv.after("<ul class='mommenu_cl' id='" + menuid + "'>" +
        "<li class='copy' data-clipboard-text='" + name + "'>Copy</li>" + 
    "</ul>");

次に、関数内のこのコードの直後に、make_menuまだアタッチされていない場合に限り、clipboard.js をアタッチします。

if ($clipboardh === false){
  console.log("creating the clipboard");
  $clipboardh = new Clipboard('.copy');

  // some optional event handlers for debugging
  $clipboardh.on('success', function(e) {
      console.info('Action:', e.action);
      console.info('Text:', e.text);
      console.info('Trigger:', e.trigger);

      e.clearSelection();
  });

  $clipboardh.on('error', function(e) {
      console.error('Action:', e.action);
      console.error('Trigger:', e.trigger);
  });
}

destroy_menu最後に、これを関数の最後に追加して、メニューを破棄するときにクリップボードを確実に破棄する必要があります。

$clipboardh.destroy();
$clipboardh = false;

ここで動作するフィドルを見つけることができます。

于 2016-02-12T14:36:52.590 に答える
3

IE 以外のクリップボードからのコピーは、編集可能な要素で行う必要があります。これを処理する最も一般的な方法は、非表示のテキストエリアを作成し、コンテンツをテキストエリアに配置してから

textArea.select();
document.execCommand('Copy');

IEの場合は、単に使用できます

if(window.clipboardData){
    window.clipboardData.setData('Text',
        uitem.innerText);
}

私はこれがどのように機能するかを説明する非常に広範な記事を書き、結果のコードを含むプロジェクトを GitHub に持っています。

http://blog.dmbcllc.com/cross-browser-javascript-copy-and-paste/

ブラウザが「成熟」するにつれて、これを行う方法は変化し続けるため、Googleを検索して得られる矛盾するアドバイスをすべて整理するのに数か月かかりました。

于 2016-02-12T13:56:41.997 に答える