Modifying the CSS of highlighted text with the help of JavaScript

I am currently working on a JavaScript bookmarklet that will function as a highlighter, changing the background color of selected text on a webpage to yellow when the bookmarklet is clicked.

The code I have for retrieving the selected text is functioning correctly and returning the desired string:

function getSelectedText() {
    var selection = '';
    if (window.getSelection) {
        selection = window.getSelection();
    } else if (document.getSelection) {
        selection = document.getSelection();
    } else if (document.selection) {
        selection = document.selection.createRange().text;
    }
    return selection;
}

However, I am facing issues with a similar function that aims to change the CSS properties of the selected text using jQuery:

function applyHighlightToSelectedText() {
    var selectedText;
    if (window.getSelection) {
        selectedText = window.getSelection();
    } else if (document.getSelection) {
        selectedText = document.getSelection();
    } else if (document.selection) {
        selectedText = document.selection.createRange().text;
    }
    $(selectedText).css({'background-color' : 'yellow', 'font-weight' : 'bolder'});
}

Any suggestions on how to resolve this issue?

Answer №1

If you're looking to change the background color easily, one method is to utilize the execCommand() function, which includes a command specifically for altering background colors in most up-to-date web browsers.

The code snippet below should effectively handle your request, even with selections that span across multiple elements. For non-Internet Explorer browsers, it activates designMode, sets a background color, and then deactivates designMode.

UPDATE:

This issue has been resolved in Internet Explorer 9.

function makeEditableAndHighlight(color) {
    var range, sel = window.getSelection();
    if (sel.rangeCount && sel.getRangeAt) {
        range = sel.getRangeAt(0);
    }
    document.designMode = "on";
    if (range) {
        sel.removeAllRanges();
        sel.addRange(range);
    }
    // Utilize HiliteColor as some browsers might apply BackColor to the entire block
    if (!document.execCommand("HiliteColor", false, color)) {
        document.execCommand("BackColor", false, color);
    }
    document.designMode = "off";
}

function highlight(color) {
    var range, sel;
    if (window.getSelection) {
       // For IE9 and other browsers
        try {
            if (!document.execCommand("BackColor", false, color)) {
                makeEditableAndHighlight(color);
            }
        } catch (ex) {
            makeEditableAndHighlight(color);
        }
    } else if (document.selection && document.selection.createRange) {
        // For older versions of Internet Explorer (8 and below)
        range = document.selection.createRange();
        range.execCommand("BackColor", false, color);
    }
}

Answer №2

Here's a basic demonstration of how it might operate. As mentioned by Zack, it's important to consider scenarios where the selection crosses multiple elements. This code snippet is not meant for direct implementation, but rather as a starting point for generating ideas. Tested in the Chrome browser.

let selectedText = window.getSelection();
let textContent = selectedText.toString();
let parentElement = $(selectedText.focusNode.parentElement);
let oldContent = parentElement.html();
let newContent = oldContent.replace(textContent, "<span class='highlight'>" + textContent + "</span>");
parentElement.html(newContent);

Answer №3

In order to ensure that the highlighted section remains permanent, it is necessary to enclose the selection within a fresh DOM element (such as span) and then apply style attributes to it. I am not certain if jQuery has the capability to accomplish this task for you. It is important to remember that selections may cross over element boundaries, resulting in the need to introduce numerous new elements in the general scenario.

Answer №4

Check out an example I created at http://www.jsfiddle.net/hbwEE/3/

This example does not consider selections that span multiple elements. (Internet Explorer will work but might mess up the HTML structure a bit.)

Answer №5

For Mozilla Firefox, the ::-moz-selection pseudo-class can be utilized.
When working with Webkit browsers, opt for the ::selection pseudo-class.

Answer №6

I appreciate Tim's solution for its efficiency and cleanliness, although it does limit the possibility of interacting with highlights.

Directly adding inline elements around text can be disruptive to the flow and cause complications in more intricate scenarios,

Instead, I propose a unique workaround that

  1. determines the precise layout of each line of selected text (regardless of their position),
  2. then places colored, semi-transparent inline-block elements at the end of the document body.

An illustration of this approach can be seen in this chrome extension.

This tool utilizes the API provided by this library to obtain the exact layout of each selected line.

Answer №7

If you're looking to add custom highlights to your webpage, the CSS Custom Highlight API is the way to go. This API allows you to mark specific ranges in JavaScript with a named highlight style, and then define the appearance of that highlight using CSS. The result is a persistent highlight effect that resembles text selection.

For example:

<style>
  div::highlight(foo) {
    background-color: green;
  }
</style>
<div id="highlighted">This is highlighted text</div>
<script>
  let r = new Range();
  r.setStart(highlighted, 0);
  r.setEnd(highlighted, 1);
  let h = new Highlight(r);
  CSS.highlights.set('foo', h);
</script>

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

Creating JavaScript classes based on JSON schemas

I have a JSON file containing information and data related to my work, presented in the following format: { "Employees":[ { "id": 1, "fullName": "Test Test" } ], "Infos":[ { "id": 1, ...

Determine whether a URL has already been encoded using the encodeURI function

Attempting to accomplish this task in VBScript/JScript to prevent re-encoding. Is it necessary to check for the presence of "%" ? Are there other purposes for "%" in URLs? Thank you. Edit: Oh, perhaps the original encoding method wasn't encodeURI ...

The default locale for momentJS is set to zh-tw and I'm having trouble changing it

Currently, I am incorporating the momentJS library into my Angular application by pulling it from a CDN: <script src="https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.10.3/moment.min.js"></script> Although the default locale should be Engli ...

Connect event handler to the document to fetch data from the firebase API using the useEffect hook

Simple Explanation: My main objective is to achieve something similar to the example link provided, but with an asynchronous call to Firebase for each useEffect where the list content is populated by Firebase objects. https://codesandbox.io/s/usage-pxfy7 ...

Do not delete blank notes upon saving

Issue: When multiple notes are created simultaneously, and the same text is entered in the first note and saved, the blank remaining notes are not removed upon page reload or refresh. How can I ensure that empty notes are deleted and only notes with conten ...

Leveraging JQuery in Master Pages

I am attempting to integrate JQuery into my Master Page. Despite not receiving any errors, the JQuery does not seem to be functioning properly. Specifically, I am trying to implement the Table Sorter function. MasterFile: <head runat="server"> ...

Cross-origin resource sharing problem encountered in Firefox and Internet Explorer, while functioning properly in Chrome

I am encountering CORS errors in Firefox and IE, but everything is functioning properly in Chrome. The two requests causing the issue are A general call to Facebook which works in Chrome and Firefox, but fails in IE 11. I am making a request to verify t ...

I am having trouble running my JavaScript code outside of JSFiddle

It's strange how my code functions perfectly in JSFiddle, but when I attempt to use it outside of JSFiddle, it fails to work. Can anyone provide a solution or insight into what might be causing this issue? Feel free to check out the JSFiddle code here ...

From SketchUp to Canvas

I've been trying to figure out how to display a 3D model created in SketchUp on a web page. After discovering three.js and exporting the model to a .dae file for use with ColladaLoader, I still can't get it to appear on my canvas. (I'm using ...

Understanding the Camera's View in Three.js

I am currently developing a game using html5 and THREE.js, where I have implemented a camera that rotates with the euler order of 'YXZ'. This setup allows the camera to rotate up, down, left, and right – simulating a first person view experien ...

What are the steps to preview a video using AngularJS?

I have a unique feature in my Angular.js application that allows users to upload various types of files, including documents, images, and videos. While I have successfully implemented the functionality to upload any type of file, I am now looking to find ...

Exploring the characteristics of $scope elements generated by the $resource factory service within AngularJS

I need to access attributes of an object that originates from a $resource factory service (REST API). services.js: myApp.factory('userService', ['$resource', 'backendUrl', function($resource, backendUrl) { return $resource ...

Electron's start script leads to project failure

Despite extensively searching the internet for a solution, I have yet to find a definitive answer that actually works. My last resort was downloading the example from Electron's website and directly inserting the scripts into my project. However, whe ...

What could be causing the custom Angular filter to not return the expected results?

I have been working on a custom filter called "occursToday" for an array of "event" objects. This filter is supposed to return events that have a startDate matching the current date. However, when I test the filter, no events are displayed despite expectin ...

Is there a way to enhance the height of Bootstrap combobox items? Can this be achieved?

Is it possible to improve the height of Bootstrap combobox item? How can I achieve that?https://i.sstatic.net/MkGFd.jpg 1 2 3 4 ...

Is there a way to transform a string array into JSON using jQuery?

When working with Django, the view that returns a JSON object contains the following code: def searchTourDBEsp_view(request): print 'llamamos search ESP' dataTourEsp = TourEsp.objects.raw('SELECT * FROM appMain_tour where idTour=1&a ...

What steps can I take to ensure that the information in my Cart remains consistent over time?

I recently built a NextJS application integrating the ShopifyBuy SDK. My implementation successfully fetches products from the store and displays them to users. Users can navigate to product pages and add items to their cart. However, I encountered an iss ...

SailsJS failing to detect changes in local JSON file

https://i.stack.imgur.com/RG13Y.png This sailsjs application does not utilize any database. Instead, it relies on multiple JSON files located in the data folder within the root directory. The controller accesses this data as follows: req.session.categori ...

axios interceptor - delay the request until the cookie API call is completed, and proceed only after that

Struggling to make axios wait for an additional call in the interceptor to finish. Using NuxtJS as a frontend SPA with Laravel 8 API. After trying various approaches for about 4 days, none seem to be effective. TARGET Require axios REQUEST interceptor t ...

Is it possible to retrieve the values of #select1 and #select2 before initiating the AJAX request?

I am presented with the following snippet of HTML code: <select id="choice1"> <option value="0">Option 0</option> <option value="1">Option 1</option> <option value="2">Option 2</option> <option value="3 ...