Preventing text in rt tags (furigana) from being selected
Asked Answered
B

4

11

I use ruby annotation to add furigana to Japanese text:

<ruby><rb>漢</rb><rt>かん</rt></ruby><ruby><rb>字</rb><rt>じ</rt></ruby>

When I try selecting 漢字 and copying it in Safari or Chrome, the clipboard looks like this:

漢
かん
字

I can't look up the word from OS X's dictionary either.

Is there some way to prevent the furigana from being selected? rt { -webkit-user-select: none; } doesn't seem to work.

Bili answered 18/11, 2012 at 7:46 Comment(1)
See the latest CSS to disable user-select: #827282Bingaman
E
5

It appears that if you wrap them inside one <ruby> element, like this:

<ruby>
  <rb>漢</rb><rt>かん</rt>
  <rb>字</rb><rt>じ</rt>
</ruby>

Then it'll be possible to select 漢字 without the furiganas selected.


UPDATE:

For kanji-kana mixed text like 間に合わせる, you can either:

  1. Use empty <rt> element, like this:

    <ruby>
        <rb>間</rb><rt>ま</rt>
        <rb>に</rb><rt></rt>
        <rb>合</rb><rt>あ</rt>
        <rb>わせる</rb><r‌​t></rt>
    </ruby>
    
  2. Write some javascript, making use of the Clipboard events* †:

    • HTML:

      <ruby>
        <rb>間</rb><rt>ま</rt>
      </ruby>
      に
      <ruby>
        <rb>合</rb><rt>あ</rt>
      </ruby>
      わせる
      
    • Javascript:

      $(document).on('copy', function (e) {
          e.preventDefault(); // the clipboard data will be set manually later
      
          // hide <rt> elements so that they won't be selected
          $('rt').css('visibility', 'hidden');
      
          // copy text from selection
          e.originalEvent.clipboardData.setData('text', window.getSelection().toString());
      
          // restore visibility
          $('rt').css('visibility', 'visible');
      });
      

Here's a demo page: http://jsfiddle.net/vJK3e/1/

* Tested OK on Safari 6.0.3
† Might require newer browser versions
‡ I add the line of css code rt::selection { display: none; } to prevent the furigana text from beed (visually) selected

Emplacement answered 30/3, 2013 at 13:13 Comment(4)
There's always words like 間に合わせる though.Bili
@LauriRanta There's a trick (using empty <rt> tags) like this: <ruby><rb>間</rb><rt>ま</rt><rb>に</rb><rt></rt><rb>合</rb><rt>あ</rt><rb>わせる</rb><rt></rt></ruby>. The html code might not look quite semantic though...Goodell
@LauriRanta I've updated my answer and added a javascript solution. Hope it could help.Goodell
If you select the second paragraph including the ま furigana (even though it doesn't appear selected), the clipboard doesn't include 間. It still doesn't work with OS X's dictionary (words like 見る would be better for testing that). And words are still split on multiple lines in the clipboard, but if clipboards wouldn't normally contain newlines, you could add .replace(/\n/g, '') after window.getSelection().toString().Bili
B
3

Here's the vanilla javascript way of doing it:

// hide furigana before sending and reenable after
document.addEventListener('copy', function (e) {
  e.preventDefault();
  var furis = document.getElementsByTagName('rt');
  for (var i = 0; i < furis.length; i++) {
    furis[i].style.display = 'none';
  }
  e.clipboardData.setData('text', window.getSelection().toString());
  for (var i = 0; i < furis.length; i++) {
    furis[i].style.removeProperty('display');
  }
});

As noted above, adding .replace(/\n/g, '') after window.getSelection().toString() will remove any new lines that are somehow still hanging around. .replace(' ', '') might be useful too if you don't want the user to end up with extra spaces either. These may or may not be desirable for your use case.

Bracer answered 5/12, 2015 at 23:55 Comment(0)
A
1

Building on Rox Dorentus's accepted answer (and with reference to jpc-ae's helpful Javascript conversion), here is an improvement on the algorithm that doesn't involve hacking the display style of the <rt> elements, which feels fragile to me.

Instead, we build an array of references to all the nodes in the selection, filter for any with the tag <rb>, and return their innerText. I also provide a commented-out alternative in case no <rb> tags are used to wrap up the kanji.

document.addEventListener('copy', function (e) {
  var nodesInRange = getRangeSelectedNodes(window.getSelection().getRangeAt(0));

  /* Takes all <rb> within the selected range, ie. for <ruby><rb>振</rb><rt>ふ</rt></ruby> */
  var payload = nodesInRange.filter((node) => node.nodeName === "RB").map((rb) => rb.innerText).join("");

  /* Alternative for when <rb> isn't used: take all textNodes within <ruby> elements, ie. for <ruby>振<rt>ふ</rt></ruby> */
  // var payload = nodesInRange.filter((node) => node.parentNode.nodeName === "RUBY").map((textNode) => textNode.textContent ).join("");

  e.clipboardData.setData('text/plain', payload);
  e.preventDefault();


  /* Utility function for getting an array of references to all the nodes in the selection area,
   * from: https://mcmap.net/q/689468/-js-get-array-of-all-selected-nodes-in-contenteditable-div */
  function getRangeSelectedNodes(range) {
    var node = range.startContainer;
    var endNode = range.endContainer;
    if (node == endNode) return [node];
    var rangeNodes = [];
    while (node && node != endNode) rangeNodes.push(node = nextNode(node));
    node = range.startContainer;
    while (node && node != range.commonAncestorContainer) {
      rangeNodes.unshift(node);
      node = node.parentNode;
    }
    return rangeNodes;

    function nextNode(node) {
      if (node.hasChildNodes()) return node.firstChild;
      else {
        while (node && !node.nextSibling) node = node.parentNode;
        if (!node) return null;
        return node.nextSibling;
      }
    }
  }

});
Akela answered 18/3, 2017 at 23:32 Comment(0)
U
0

You can achieve this with CSS by using the user-select property. You can try it below:

rt {
  -webkit-touch-callout: none; /* iOS Safari */
    -webkit-user-select: none; /* Safari */
     -khtml-user-select: none; /* Konqueror HTML */
       -moz-user-select: none; /* Old versions of Firefox */
        -ms-user-select: none; /* Internet Explorer/Edge */
            user-select: none; /* Non-prefixed version, currently supported by Chrome, Edge, Opera and Firefox */
}
<ruby><rb>漢</rb><rt>かん</rt></ruby><ruby><rb>字</rb><rt>じ</rt></ruby>

You can check the Can I Use information for browser compatibility.

Unfolded answered 21/8, 2022 at 3:56 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.