0

I am new to webDevelopment. I have string which has some text.Now I want to highlight some words from that text file . So, Here I am using this logic

$scope.highlightHTML = function (content,startoffset,endoffset,color) {
          var className = 'mark';
          console.log(content.substring(startoffset, endoffset));
          return content.replace(content.substring(startoffset, endoffset), '<span class="' + className + '">$&</span>');
}

Now this is working fine. But Now what happens is when first word gets highlighted and then when It tries to highlight the second word then the strings offsets are getting changed because of this replacing . It takes tag as well so, now offsets are getting changed. now when I highlight some text then next time it should not take offsets of start and end offset of the span tag . SO, How can I do this ?

Its like , "Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industry's standard dummy text ever since the 1500s, when an unknown printer took a galley of type and scrambled it to make a type specimen book. It has survived not only five centuries, but also the leap into electronic typesetting, remaining essentially unchanged"

I have this string. Now, I want to highlight when an unknown printer took a galley of Now, for this I use substring because I get the start and end from back-end itself. I replace only that string with mark tag.

Now The problem is after this immediately,If I want to highlight but also the leap into electronic typesetting, Then the offset which I got from the backend will not be useful because while replacing the first string I added span tag, so it is taking the span tag offsets as well. So, Its not getting me the exact string by providing the offsets as well. It gives me some another string because offsets has changed. Now, whil highlighting the offsets should not get changed by adding the span tag.

Ajax call -

jsonDataArray.forEach(function (item) {
                  responseData = $scope.highlightHTML(responseData,item.startOffset,item.endOffset,item.color);
                  $rootScope.data.htmlDocument = responseData.replace(/\n/g, "</br>");;
                });
ganesh kaspate
  • 1
  • 9
  • 41
  • 88
  • 1
    Similar to [this](https://stackoverflow.com/questions/3294576/javascript-highlight-substring-keeping-original-case-but-searching-in-case-inse) – Jyme Mar 22 '18 at 04:31
  • Actually , Its not the same – ganesh kaspate Mar 22 '18 at 04:33
  • 1
    Can you post your input, current output and what's you expected ? – Jyme Mar 22 '18 at 04:52
  • @ThanatManeenutplease see the updated question – ganesh kaspate Mar 22 '18 at 05:22
  • One option is you to store the original text and check the position of the string on the original text rather than on the updated one. – Eddie Mar 23 '18 at 08:21
  • You mean I should store that original Text in one variable and then position on the this one and should highlight the new text, But it will still give same issue because I want to show the user new one with highlighted – ganesh kaspate Mar 23 '18 at 08:31

3 Answers3

1

You can achieve this by using the length of the string using below logic.

I'm adding span to 'simply dummy', 'and typesetting', 'Ipsum has been' in your text.

what i have done is after the text has been updated after the function call, i am adding the difference between the initial text length and updated text length to the offeset which calling the function again which gives me the exact offsets of the words.

Please let me know whether its works for you.

Updated ajax :

var initialLength = responseData.length;
var updatedLength = 0;
jsonDataArray.forEach(function(item, index) {
  if (index == 0)
    responseData = $scope.highlightHTML(responseData, parseInt(item.startOffset), parseInt(item.endOffset), item.color);
  else
    $scope.highlightHTML(responseData, parseInt(item.startOffset) + (updatedLength - initialLength), parseInt(item.endOffset) + (updatedLength - initialLength), item.color);
    updatedLength = responseData.length;
    $rootScope.data.htmlDocument = responseData.replace(/\n/g, "</br>");;
});

$(document).ready(function() {
  var text = "Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industry's standard dummy text ever since the 1500s, when an unknown printer took a galley of type and scrambled it to make a type specimen book. It has survived not only five centuries, but also the leap into electronic typesetting, remaining essentially unchanged";
  var initialLength = text.length;
  var updatedLength = 0;
  var startoffset1 = 15;
  var endoffset1 = 27;
  var startoffset2 = 49;
  var endoffset2 = 64;
  var startoffset3 = 81;
  var endoffset3 = 95;
  console.log(text.substring(startoffset1, endoffset1));
  console.log(text.substring(startoffset2, endoffset2));
  console.log(text.substring(startoffset3, endoffset3));
  text = highlightHTML(text, startoffset1, endoffset1, 'green');
  updatedLength = text.length;
  text = highlightHTML(text, startoffset2 + (updatedLength - initialLength), endoffset2 + (updatedLength - initialLength), 'green');
  updatedLength = text.length;
  text = highlightHTML(text, startoffset3 + (updatedLength - initialLength), endoffset3 + (updatedLength - initialLength), 'green');
  console.log(text);
});

function highlightHTML(content, startoffset, endoffset, color) {
  var className = 'mark';
  console.log('Inside Function: ' + content.substring(startoffset, endoffset));
  return content.replace(content.substring(startoffset, endoffset), '<span class="' + className + '">$&</span>');
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
Makarand Patil
  • 1,001
  • 1
  • 8
  • 15
0

Can you keep the original content to the global variable ?

So you don't need to worry about offset changed by added span tag.

updated code

var responseData;
function readFile() {
    responseData = 'Lorem ipsum dolor sit amet, consectetur .....'
}

var highlightNeeded = []

jsonDataArray.forEach(function (item) {
    var actualText = responseData.substring(item.startOffset, item.endOffset)
    highlightNeeded.push(highlightNeeded)
});

// call this after foreach finished 
var tmpData = $scope.highlightHTML(responseData, highlightNeeded, item.color);
$rootScope.data.htmlDocument = tmpData.replace(/\n/g, "</br>");;

$scope.highlightHTML = function (content, listOfText, color) {
    var className = 'mark';
    listOfText.forEach(function (text) {
        var regex = new RegExp(text, 'gi')
        content.replace(regex, '<span class="' + className + '">$&</span>');
    })
}
Jyme
  • 332
  • 2
  • 13
  • can you tell me when I am going to show then I want to show the highlighted file – ganesh kaspate Mar 23 '18 at 06:24
  • One thing content means whole file or the one which I want to highlight – ganesh kaspate Mar 23 '18 at 06:26
  • You can apply my updated code, the idea is to find what text is from the offset and keep it in array, after finished all of that you can use regex to highlight all the text you needed – Jyme Mar 23 '18 at 09:00
0

Sometimes it's cool to keep it cryptic and concise for no reasons...It can still be less cryptic at end!

So here my version using the html <mark> and <wbr> tags.

There is not so much need to melt non related functions from my view, it loose all the versatility/portability.

let ߐ = document.body
function check(_ૐ){
ߐ.innerHTML=ߐ.innerHTML.replace(_ૐ,"<mark>"+_ૐ+"</mark>")
}

check("when an unknown printer took a galley of")
Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industry's standard dummy text ever since the 1500s, when an unknown printer took a galley of type and scrambled it to make a type specimen book. It has survived not only five centuries, but also the leap into electronic typesetting, remaining essentially unchanged

The mark tag suits very well for highlighting,as it is made for that, there is some special wizardry with the wbr.

wbr: On UTF-8 encoded pages, behaves like the U+200B ZERO-WIDTH SPACE code point. In particular, it behaves like a Unicode bidi BN code point, meaning it has no effect on bidi-ordering: 123,456 displays, when not broken on two lines, 123,456 and not 456,123.

For the same reason, the element does not introduce a hyphen at the line break point. To make a hyphen appear only at the end of a line, use the soft hyphen character entity (­) instead.

https://developer.mozilla.org/en-US/docs/Web/HTML/Element/wbr

Here the marking will disappear after 8s, without breaking the text.

let ߐ = document.body
function check(_ૐ){
ߐ.innerHTML=ߐ.innerHTML.replace(_ૐ,"<mark>"+_ૐ+"</mark>")
window.setTimeout(Ώ,8000)}
function Ώ(){
ߐ.innerHTML=ߐ.innerHTML.replace("mark","wbr")}

check("when an unknown printer took a galley of")
Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industry's standard dummy text ever since the 1500s, when an unknown printer took a galley of type and scrambled it to make a type specimen book. It has survived not only five centuries, but also the leap into electronic typesetting, remaining essentially unchanged

Source: https://codepen.io/Nico_KraZhtest/pen/mEjBdj

For you exact enquiry, it can then look like this:

jsonDataArray.forEach(function (item) {
                  responseData = $scope.highlightHTML(responseData,item.startOffset,item.endOffset,item.color);
                  $rootScope.data.htmlDocument = responseData.replace("when an unknown printer took a galley of","<mark>"+"when an unknown printer took a galley of"+"</mark>")
                });

Or, more nicely:

let search = "when an unknown printer took a galley of"
jsonDataArray.forEach(function (item, search) {
                  responseData = $scope.highlightHTML(responseData,item.startOffset,item.endOffset,item.color)
                  $rootScope.data.htmlDocument = responseData.replace(search,"<mark>"+search+"</mark>")
                })
NVRM
  • 11,480
  • 1
  • 88
  • 87