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.
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:
Use empty <rt>
element, like this:
<ruby>
<rb>間</rb><rt>ま</rt>
<rb>に</rb><rt></rt>
<rb>合</rb><rt>あ</rt>
<rb>わせる</rb><rt></rt>
</ruby>
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
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.
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: http://stackoverflow.com/a/7784176/5951226 */
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;
}
}
}
});
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With