victorsoares96 / epubjs-react-native

ePub.js Reader for React Native

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

highlight text dynamically with span Id

rashidwiizb opened this issue · comments

My EPUB CFI range looks like this: epubcfi(/6/4!/4,/4/2/2[_idTextSpan0001]/1:0 for each element. So, if I have dynamically assigned span IDs like _idTextSpan0001 or _idTextSpan0002, or whatever, I want the CFI range to contain that span ID, and I want to highlight that element. or curresponding elemt with cfirange contains that spanid

Could you provide me with a use case for what you want to do? Are you trying to start a book with notes already added to it?

I've been working on a feature to highlight text in a book reading app. Initially, I used a search function to find text dynamically from a JSON file and then highlight it. Now, I want to streamline this process by directly highlighting text that contains specific IDs provided in the JSON.

[
{
"id": "_idTextSpan0001",
"lines": "هَذِهِ\n\n...يَدي اليَمينُ"
},
{
"id": "_idTextSpan0002",
"lines": "!وَهَذِهِ اليَسارُ"
},
...
]

Instead of searching, I want to use these IDs to highlight text directly. This approach will simplify the process and make it more efficient.

Got it, you want to highlight a text based on an id... I have been working on improvements in version 1.4.0 beta related to annotations, as soon as possible I will check the feasibility of your order!

Okay, so currently, there is no way to retrieve the contents or text of each page and highlight the text using span IDs or reference IDs.

Once I was trying to get the cfi of each element

of the book, I will try to recover this script to pass it to you. I believe he will help you.

I hope as soon as possible i will get the script because currently i am working on it.

I believe this will help you, use the latest available beta version of the library:

import * as React from 'react';
import { SafeAreaView, useWindowDimensions } from 'react-native';
import { Reader, ReaderProvider } from '@epubjs-react-native/core';
import { useFileSystem } from '@epubjs-react-native/expo-file-system';

export function JavascriptInjection() {
  const { width, height } = useWindowDimensions();
  return (
    <SafeAreaView>
      <ReaderProvider>
        <Reader
          src="https://s3.amazonaws.com/moby-dick/OPS/package.opf"
          width={width}
          height={height * 0.85}
          fileSystem={useFileSystem}
          injectedJavascript={`
            function highlightTextByTagId(tagId) {
              return Promise.all(book.spine.spineItems.map((item) => {
                return item.load(book.load.bind(book)).then(() => {
                  const element = item.document.getElementById('c001p0005');

                  if (!element) return null;

                  const cfi = item.cfiFromElement(element).split(')')[0].concat(',/1:0,/1:').concat(element.textContent.length).concat(')') ;
                  rendition.annotations.add('highlight', cfi);

                  console.log({
                    cfi,
                    text: element.textContent,
                    elements,
                  });

                  item.unload();
                  return Promise.resolve();
                });
              }));
            }

            highlightTextByTagId('c001p0005');
          `}
        />
      </ReaderProvider>
    </SafeAreaView>
  );
}

This script will look for an element within the book that has a certain tag and will mark the text using cfi

the text associated with the id is the one in the image below:
image

The above script works and highlights the text element according to the corresponding span id, but some text elements with span ids don't work.
injectedJavascript={function highlightTextByTagId(tagId) { return Promise.all(book.spine.spineItems.map((item) => { return item.load(book.load.bind(book)).then(() => { const element = item.document.getElementById(tagId); if (!element) return null; const cfi = item.cfiFromElement(element).split(')')[0].concat(',/1:0,/1:').concat(element.textContent.length).concat(')'); rendition.annotations.add('highlight', cfi); console.log({ text: element.textContent, element, }); item.unload(); return Promise.resolve(); }); })); } highlightTextByTagId('_idTextSpan0001');}

Here, I am using span id _idTextSpan0001, and this doesn't highlight the corresponding element, but span id _idTextSpan0002 works.

{
"page": "2",
"startDelay": 3000,
"endDelay": 6000,
"data": [
{
"begin": "0.000",
"end": "1.960",
"language": "arb",
"lines": "هَذِهِ\n\n...يَدي اليَمينُ",
"id": "_idTextSpan0001",
"page": "2"
},
{
"begin": "1.960",
"end": "3.800",
"language": "arb",
"lines": "!وَهَذِهِ اليَسارُ",
"id": "_idTextSpan0002",
"page": "2"
},
{
"begin": "3.800",
"end": "4.280",
"language": "arb",
"lines": "..لا..لا",
"id": "_idTextSpan0003",
"page": "2"
},
{
"begin": "4.280",
"end": "4.720",
"language": "arb",
"lines": "؟؟",
"id": "_idTextSpan0004",
"page": "2"
},
{
"begin": "4.720",
"end": "6.160",
"language": "arb",
"lines": "..هَذِهِ اليَسارُ",
"id": "_idTextSpan0005",
"page": "2"
},
{
"begin": "6.160",
"end": "6.520",
"language": "arb",
"lines": "..وَهَذِهِ اليَمينُ",
"id": "_idTextSpan0006",
"page": "2"
}
],
"isAudio": true
}

Actually, this issue does not appear to be related to the book element; all text is highlighted using the above JSON span ids in the web application using the react-reader library.

Screenshot_1712561597

Also instaed of doing annotation can i do custome style for each span? I attach the book page html below

image

Did any of the ids containing the
tag work?

Yes some span with spanid containe br tag

At the moment it is not possible to change the style of a section or a specific element dynamically, annotations such as underline or highlight are svg elements attached to the book

I don't know how react-reader works very well but I think it allows you to manipulate the rendition directly... you can try to do the same thing here either using the injectJavascript method from the example above

debug the highlightTextBySpanId function and check if it can find the id _idTextSpan0001 in the html document

also try adding:

rendition.views().forEach(view => view.pane ? view.pane.render() : null);

this method will render the active view, maybe this will solve your problem with this id

So there is no way to inject a script to change color of text on corresponding element with spanid?

My opf file is : https://kutubiapp-blobdb.s3.ap-south-1.amazonaws.com/unzip/65d75f3e8a403d7e14b4fd74/OEBPS/content.opf

Actually the above script got the cfi range of span which contain br tag. But highlight is not work

Screenshot_1712647010

and the element outerhtml is:

Screenshot_1712647286

okay, i'll take a look

try this:

import * as React from 'react';
import { SafeAreaView, useWindowDimensions } from 'react-native';
import { Reader, ReaderProvider } from '@epubjs-react-native/core';
import { useFileSystem } from '@epubjs-react-native/expo-file-system';
import { Header } from './Header';

export function JavascriptInjection() {
  const { width, height } = useWindowDimensions();
  return (
    <SafeAreaView>
      <ReaderProvider>
        <Header />

        <Reader
          src="https://kutubiapp-blobdb.s3.ap-south-1.amazonaws.com/unzip/65d75f3e8a403d7e14b4fd74/OEBPS/content.opf"
          width={width}
          height={height * 0.85}
          fileSystem={useFileSystem}
          initialLocation="epubcfi(/6/4!/4/4/2/2[_idTextSpan0001]/1:0)"
          injectedJavascript={`
            function highlightTextByTagId(tagId) {
              return Promise.all(book.spine.spineItems.map((item) => {
                return item.load(book.load.bind(book)).then(() => {
                  const element = item.document.getElementById(tagId);

                  if (!element) return null;

                  const range = item.document.createRange();
                  range.selectNodeContents(element);

                  let textOffset = element.textContent.length;
                  if (element.childNodes.length > 1) {
                    const lastChildNode = element.childNodes[element.childNodes.length - 1];
                    textOffset = lastChildNode.textContent.length;
                  }

                  const cfi = item.cfiFromElement(element).split(')')[0].concat(',/1:0,/').concat(range.endOffset).concat(':').concat(textOffset).concat(')');
                  rendition.annotations.add('highlight', cfi);

                  item.unload();
                  return Promise.resolve();
                });
              }));
            }

            highlightTextByTagId('_idTextSpan0001');
          `}
          onWebViewMessage={(message) => console.log(message)}
        />
      </ReaderProvider>
    </SafeAreaView>
  );
}

image

Thank you, this works fine. However, I want to confirm whether I can move my application to production with this beta version "@epubjs-react-native/core": "1.4.0-beta.45". Will the injectJavaScript or any other property be deprecated or removed in future versions?

This props not will be removed

Do you know why i got this error while opening book?

domain undefineed
error code: 1
WARN Encountered an error loading page {"canGoBack": false, "canGoForward": false, "code": -1, "description": "net::ERR_ACCESS_DENIED", "loading": false, "target": 5927, "title": "", "url": "file:///data/user/0/com.alrajhieducation.kutubiapp/filesindex.html"}

Screenshot_1712921643