What is the method to allow a div to display on top of specific text?

I am currently developing an application with VueJS that generates a tooltip over user-selected text. The goal is to position the tooltip directly above the selected text, utilizing Tippy.js for its creation.

Check out the code snippet below:

const giphy = require('giphy-api')('Insert API key here');

export default {
  data () {
    return {
      
    }
  },

  mounted() {
    const template = document.querySelector('#template');
    const initialText = template.textContent;
    
    let that = this;

    const tip = tippy('.tip', {
      animation: 'shift-toward',
      arrow: true,
      html: '#template',
      trigger: 'click',
      onShow() {
        
        // `this` inside callbacks refers to the popper element
        const content = this.querySelector('.tippy-content');
        
        if(tip.loading || content.innerHTML !== initialText) 
          return;
        
        tip.loading = true;

        var self = that;
        
        $('#app').mouseup(function() {
          let selection = self.getSelected();

          if (selection != "") {

            giphy.translate(`${selection}`)
            .then(function (response) {
              // Assigning the url from response object to the url
              const url = response.data.images.fixed_width_small.url;
              content.innerHTML = `<img width="100" height="100" src="${url}">`
              tip.loading = false
            })
            .catch(function(error){
              content.innerHTML = 'Loading failed'
              tip.loading = false
            });

          }
        });
      },

      onHidden() {
        const content = this.querySelector('.tippy-content');
        content.innerHTML = initialText;
      }
    })

  },

  methods: {
    // Function to get the selected text
    getSelected() {
      let selectedText = "", selection;
      
      if (window.getSelection) {
        selectedText = "" + window.getSelection();
      } 
      else if ( (selection = document.selection) && selection.type == "Text") {
        selectedText = selection.createRange().text;
      }
      return selectedText;
    }

  }
#app {
  font-family: 'Avenir', Helvetica, Arial, sans-serif;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  text-align: center;
  color: #2c3e50;
  margin-top: 250px;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.16/vue.min.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id="app">
    <div class="tip">
      <h1>Fifa World Cup 2018</h1>
      <h4 style="margin-top:40px;">Winner is France</h4>
      <span style="margin-top:10px;">Runner up is Croatia</span>
    </div>

    <div>
      <div id="template" style="display: none">
        Loading tooltip...
      </div>
    </div>

  </div>

The div with id="template" serves as the foundation for the tooltip. Currently, I have only achieved positioning it at the center of the text-containing div. Any tips on how to ensure the tooltip displays exactly above the selected text? Assistance would be greatly appreciated.

Answer №1

  1. add event listener for the `mouseup` event on the application

  2. inside the event handler, use

    window.getSelection().getRangeAt(0).getBoundingClientRect()
    to obtain the bounding rectangle of the selected text

  3. provide the bounding rectangle of the selected text as a "virtual element" to tippy, refer to the documentation: (search for "virtual element")

An example using vanilla JavaScript for the first 2 steps:

let p = document.querySelector('p');
let div = document.querySelector('div');

document.documentElement.addEventListener('mouseup', () => {
    console.log(p);
    let selection = getSelection();
    console.log(selection);
    if (!selection.isCollapsed && selection.rangeCount > 0) {
        let range = selection.getRangeAt(0);
        console.log(range);
        let rangeRect = range.getBoundingClientRect();
        console.log(rangeRect);
        console.log(div);
        div.style.top = rangeRect.top+'px';
        div.style.left = rangeRect.left+'px';
        div.style.width = rangeRect.width+'px';
        div.style.height = rangeRect.height+'px';
    } else {
        div.style.top = 0;
        div.style.left = 0;
        div.style.width = 0;
        div.style.height = 0;
    }
});
body {
    padding: 20px;
    position: relative;
}

div {
    border: 2px red solid;
    position: absolute;
    pointer-events: none;
    top: -999px;
    left: -999px;
}

p {
    width: 500px;
}
<div></div>
<h1> try selecting some of the text below </h1>
<p>
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.
</p>

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

Step-by-step guide to implementing dynamic field autocomplete using AJAX techniques

Seeking assistance in merging ajax autocomplete with dynamic field input. The autocomplete feature is currently working on the first field, but when adding another field, the autocomplete stops functioning. Any help would be greatly appreciated. Here is t ...

The TemplateDoesNotExist error persists despite the accurate path configuration

Take a look and provide assistance Despite entering the correct path in the code, it keeps displaying an error message saying the template doesn't exist. ...

How to efficiently iterate through an array in Nuxt using a v-for directive and effectively display the data

I am struggling with looping through nested data from a JSON file on my e-commerce website. Despite trying several methods, I have not been successful in achieving this. async fetch() { this.post = await fetch( `http://test.com/api.php?id=${this. ...

Javascript - Issue: Route.post() is in need of a callback function, however it received an [object Promise] instead

I'm encountering an issue with one of my express routes. The error message I am receiving is as follows: Error: Route.post() requires a callback function but got a [object Promise] This error seems to be related to the last line in controllerFunction ...

The functionality of Google Maps code is limited on Android devices because the map feature is not available

After updating the Google Maps embed code to be responsive for mobile devices, I discovered that the map still won't display on Android or iPhone. The following is the modified code. Can anyone assist me in resolving this issue so that the map can sho ...

Utilizing request-promise for intertwined asynchronous requests

Currently, I am utilizing the Visual Studio Online API to retrieve branch statistics by repository. To achieve this, I have incorporated nested asynchronous calls. My choice of resolving GET requests is through using request-promise. The challenge I am en ...

Vue.js: In a third-party library, the reference to "this" is coming back as "undefined"

My third-party script contains code in the following format ( function initialMethod(scope, factory) { // 'scope' is undefined when used in Vue // but it works fine in React and Angular } (this, function function1(param1) { ...

Implementing Jquery to Identify the Matching Indices of Two Arrays

I need to find the indices of similar values in array1 and array2, and then save them in a variable named stored_index. array1 = ["50","51","52","53","54","55","56","57","58","59"]; array2 = ["59","55","51"]; The desired result for stored_index is: sto ...

When reducing the page size, the Bootstrap columns are colliding with

While resizing the screen, I noticed that these images are overlapping each other. I haven't made any changes to the css for container-fluid or row. <div class="container-fluid bg-grey"> <div class="row center"> <div class= ...

Receiving undefined when trying to access an array within the state in React

When I use console.log(this.state.animal_names), the output is >(2) [Array(2), Array(2)] Upon expanding, I see 0: (2) ["dogNames", Array(53)] 1: (2) ["catNames", Array(100)] However, when I attempt to access them like this: desiredAnimal = "dogNames ...

The function is activated once

Upon clicking a text block, a textarea should appear in its place. However, after the first click, the code fails to trigger correctly, resulting in no action. Despite this issue, there are no errors reported in the console. var blockInfo; var textare ...

Maintaining TextBox State in ASP.Net Through Postbacks

Can anyone help me figure out how to maintain the control state that has been modified in Javascript? I am working with two TextBoxes, one DropDownList, and a button (all Runat=Server) in C# ASP.net 2010 Express. The first textbox accepts any user in ...

Is AngularJS known for its ability to bind variables across different components effortlessly

In the beginning of my Angular controller, I use Promises to download JSON data and then store it in variables: app.controller('mainController', ['$scope', '$http', '$q', function($scope, $http, $q) { var req1 = $ ...

Altering the hues of a see-through gradient to enhance a text using Javascript

On my Anki flashcards, I've implemented a stylish transparent gradient for text using CSS: background: -webkit-linear-gradient(-45deg, #cccccc, #ffffff); -webkit-background-clip: text; -webkit-text-fill-color: transparent; Currently, this is specifi ...

Identifying movement towards <a name="latest-topics"></a>

I am trying to identify an event where a URL navigates to a specific anchor: <a name="latest-topics"></a> http://someserver.com/index.html#latest-topics Afterward, I want to utilize an event like onfocus, onclick, etc. <a onclick="doSome ...

What is the best method for extracting data from a form using javascript?

Hello everyone! I've been trying to figure out how to retrieve information from a form using JavaScript, and I came across the method involving object forms. However, I'm running into an issue where the object is coming back as undefined. Can any ...

Convert an entire HTML page into a PDF file by generating it with JSPdf

I've included all necessary js files on my aspx page to generate a pdf file of my table data. However, the generated pdf comes out blank. I want to ensure that all table data is included in the pdf. Does anyone have a solution for this? <script src ...

Develop fresh JavaScript code using JavaScript

Is it possible to dynamically create a new row in an HTML table by clicking on a button? Each row contains multiple input fields. <script type="text/javascript> row = 2; specific_row_id = new Array(); $(document).ready(function() { $(".change_1 ...

Encountering an error when attempting to reach a JSON endpoint using Javascript and X-Auth-Token

I'm attempting to retrieve data from a JSON endpoint using JavaScript and X-Auth-Token, but I am continuously encountering errors. The data is from a sports API, and despite diligently following all the instructions in the documentation and checking m ...

Timeout set to run indefinitely

Looking at the code snippet below, it seems to be running at a frame rate of 60 frames per second. If any button is clicked, the variable isjump will be set to true and the following code will start executing. The goal here is to exit the jump() function a ...