Stop the selection of text within rt tags (furigana)

I love incorporating ruby annotation to include furigana above Japanese characters:

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

However, when attempting to select 漢字 and copy it in Safari or Chrome, the copied text appears as:

漢
かん
字

Unfortunately, I am unable to access the word's definition using OS X's dictionary tool.

Is there a way to prevent the selection of the furigana?

rt { -webkit-user-select: none; }
doesn't seem to do the trick.

Answer №1

If you encase them within a single <ruby> tag, like this:

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

You will be able to choose only the characters 漢字 without selecting the furigana.


UPDATE:

For text with a mix of kanji and kana like 間に合わせる, you can either:

  1. Utilize empty <rt> tags, as shown here:

    <ruby>
        <rb>間</rb><rt>ま</rt>
        <rb>に</rb><rt></rt>
        <rb>合</rb><rt>あ</rt>
        <rb>わせる</rb><r‌​t></rt>
    </ruby>
    
  2. Create some javascript that utilizes the Clipboard events* †:

    • HTML:

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

      $(document).on('copy', function (e) {
          e.preventDefault(); // manually set the clipboard data later
      
          // prevent selection of <rt> elements
          $('rt').css('visibility', 'hidden');
      
         // copy text from selection
          e.originalEvent.clipboardData.setData('text', window.getSelection().toString());
      
          // restore visibility
          $('rt').css('visibility', 'visible');
      });
      

Check out this demo page: http://jsfiddle.net/vJK3e/1/

* Tested successfully on Safari 6.0.3
† May require newer browser versions
‡ Added the css line rt::selection { display: none; } to prevent visually selecting the furigana text

Answer №2

Here is how you can achieve the same result using vanilla JavaScript:

// Conceal furigana before copying and reveal them afterwards
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');
  }
});

It is worth mentioning that adding .replace(/\n/g, '') after window.getSelection().toString() will eliminate any remaining new lines. Additionally, using .replace(' ', '') can be helpful in removing extra spaces if necessary. Consider these options based on your specific needs.

Answer №3

Expanding on the solution provided by Rox Dorentus and incorporating jpc-ae's Javascript conversion, a revised algorithm is presented here to enhance functionality without the need to manipulate the display style of <rt> elements, which could be considered delicate.

Instead of directly modifying styles, this approach involves constructing an array containing references to all nodes in the selection, filtering for those tagged as <rb>, and extracting their textual content using innerText. Additionally, an alternative method is outlined as a fallback when <rb> tags are not utilized to envelop the kanji characters.

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

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

  /* Alternative method if no <rb> tags are used: captures all textNodes within <ruby> elements e.g., 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();

  /* Helper function for fetching an array of node references within 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;
      }
    }
  }

});

Answer №4

To alter the selection behavior of text using CSS, utilize the user-select property. Implement the following code snippet:

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>

For details on browser compatibility, refer to the information available at Can I Use.

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

What is the reason that prototypes are not passed down through inheritance?

Can anyone shed light on why Validator.js is structured the way it is initialized (as shown in the first code snippet) and the reason behind the inability to call the validate method (as demonstrated in the second snippet)? I am currently experimenting wi ...

Accessing the AppContext in Next.js within the _document file is the

My challenge with using next js is the occurrence of Content-Security-Policy issues due to the inline styles it utilizes. If 'unsafe-inline' is not added to the style-src, you will encounter the error message 'Refused to apply inline style ...

Angular Link function encounters scope undefined issue

I've been struggling with this issue for some time now. Imagine I have the directive and controller setup as shown below: angular.module('LiveAPP.artist',[]) .controller('artistCtrl', ['$scope', '$http', ' ...

The click interactions of SVG elements are altered when switching between <img> and <object> elements

I currently have 4 SVG buttons featured in the main menu of my personal website. https://i.stack.imgur.com/gA7En.png /----------------------------------------------------------------------------------------------------------------------------------/ Upo ...

What is the reason for not allowing return statements in the ternary operator?

Imagine you have a basic form and you want to determine if the form has been modified. If it has changed, you want to submit it; otherwise, you want to prevent form submission. To tackle this, instead of using an if-else statement, I decided to go for a te ...

AngularJS Cascading Dropdowns for Enhanced User Experience

There is a merchant with multiple branches. When I select a merchant, I want another dropdown list to display the data from merchant.branches. The following code does not seem to be fixing the issue: <label>Merchant:</label> <select ng-if= ...

Incorporating a personalized image to create custom icons on the Material UI bottom navigation bar

Is it possible to replace the default icon with a custom image in material ui's BottomNavigation component? I'm curious if Material UI supports this feature. If you'd like to take a closer look, here is the link to the codesandbox. ...

Unable to view any output in the console while attempting to troubleshoot a login functionality

My current setup involves using Node.js with Express and Pug templates. I have encountered an issue with a login function that is not functioning as expected. In order to troubleshoot the problem, I attempted to log the credentials (email and password) to ...

Utilizing React JS: Displaying or Concealing Specific Components Based on the URL Path

Is there a way to dynamically change the navbar items based on the URL without having separate navbar components for each side? My current navbar design features 3 links on the left side and 3 links on the right, but I want to display only one side at a ti ...

Tips for managing the output of an asynchronous function in TypeScript

The casesService function deals with handling an HTTP request and response to return a single object. However, due to its asynchronous nature, it currently returns an empty object (this.caseBook). My goal is for it to only return the object once it has b ...

Guide to incorporating HTML within React JSX following the completion of a function that yields an HTML tag

I am currently working on a function that is triggered upon submitting a Form. This function dynamically generates a paragraph based on the response received from an Axios POST request. I am facing some difficulty trying to figure out the best way to inje ...

Encountering a Next.js Strapi error. TypeError: Fetch request unsuccessful

An error occurred during module build: UnhandledSchemeError: The plugin does not support reading from "node:assert" URIs (Unhandled scheme). Webpack natively supports "data:" and "file:" URIs. You might require an extra plugin to handle "node:" URIs. ...

Durandal attempts to retrieve a view located within the viewmodel directory

Having an issue with durandal's compose binding as it is looking for views under app/viewmodels instead of app/views The ViewModel code: define(["fields/fieldClosures"], function (fields) { var ctor = function(opt) { this.value = opt.valu ...

Separate the string by commas, excluding any commas that are within quotation marks - javascript

While similar questions have been asked in this forum before, my specific requirement differs slightly. Apologies if this causes any confusion. The string I am working with is as follows - myString = " "123","ABC", "ABC,DEF", "GHI" " My goal is to spli ...

Using Vanilla JavaScript and VueJS to smoothly scroll back to the top of a div when a button is clicked

I have a VueJS-based app that features a multistep form with a next button. You can check out the functioning of the app here: My current challenge is ensuring that once the user clicks the next button, the top of the following question becomes visible. I ...

Adjusting jQuery Button Width with input type of "button"

Currently, I am working with jQuery Mobile to develop a straightforward Golf Score Card App. To calculate the total at the end of a form submission, I've implemented the following code. <input id="total" type="text" name="total" value="" readonly= ...

The nodemailer module in Node.js encountered an issue while trying to send an email, resulting

Looking to confirm registration, I want to send an email from my server (kimsufi). To accomplish this, I am utilizing nodemailer which can be found at https://github.com/andris9/Nodemailer Encountering the following error: Error occurred Sendmail exited ...

Is there a skilled coder available to troubleshoot this carousel's HTML code?

Hello, I am struggling with the code snippet below that uses Bootstrap to create a carousel. The next and previous buttons are not working properly. <div id="testimonial-carousel" class="carousel slide" data-ride="carousel&qu ...

Choose Your Price - Price Grids

I need to incorporate two sets of pricing columns into a website. The first set is for regular car cleaning prices, while the second set is for larger cars with slightly higher prices. My idea is to have two buttons at the top – one for regular cars and ...

Reduce the noise from different versions by utilizing package-lock.json

There may not be a clear-cut answer, but I'm curious to hear how others handle the issue of package-lock.json causing problems when committing to their node repository. Many opinions lean towards committing package-lock.json - ensuring consistent dep ...