Highlight a part of string which has html entities as text : angularJs - html

I have :
$scope.text = "<b>TESTNAME</b>"; (This can be any string. This is to specify that there can be html tags written as text in the string.)
The bold tags are part of text and need to be displayed as text only and not HTML.
Now suppose someone enters a search string(for eg.. anyone can enter any string) :
$scope.searchTerm = "NAME";
Then i want that $scope.text gets modified such that i see <b>TESTNAME</b> but with the substring of "NAME" highlighted.
My highlight function does :
$scope.text = $scope.text.replace(new RegExp("(" + $scope.searchTerm + ")","gi"), "<span class='highlighted'>\$1</span>");
and in the HTML I had to write :
<span ng-bing-html="text"></span>
However, the issue now arises is that, the <b> and </b> also get rendered in the HTML form and bold the string in between.
How can this be handled?
EDIT
In order to avoid the b tags from rendering as HTML, I modified the angular brackets to their HTML counterparts using this :
$scope.text = $scope.text.replace(/&/g, '&').replace(/</g, '<').replace(/>/g, '>');
after using the first replace function mentioned above. Now when the $scope.text is rendered using ng-bing-html, the b tags are only rendered as text.
However, now the span tags added are also rendered as text as angular brackets have been replaced globally.
EDIT
Another way to deal with the problem was that i replaced the angular tags before adding the span tags to highlight the text. So my highlight function was :
$scope.text = $scope.text.replace(/&/g, '&').replace(/</g, '<').replace(/>/g, '>');
$scope.searchTerm = $scope.searchTerm.replace(/&/g, '&').replace(/</g, '<').replace(/>/g, '>');
$scope.text = $scope.text.replace(new RegExp("(" + $scope.searchTerm + ")","gi"), "<span class='highlighted'>\$1</span>");
However, the issue with this is that if the user searches for the string lt or gt,then due to the replacements done for < and >, the highlight spans are added to these too and the net result is not as expected.

Please check working example: DEMO
Controller:
var app = angular.module('plunker', ["ngSanitize"]);
app.controller('MainCtrl', function($scope) {
$scope.searchTerm = "NAME";
$scope.content = "TESTNAME";
$scope.matchClass = 'bold';
var re = new RegExp($scope.searchTerm, 'g');
$scope.content = $scope.content.replace(re, '<span class="' + $scope.matchClass + '">' + $scope.searchTerm + '</span>');
});
HTML
<body ng-controller="MainCtrl">
<p ng-bind-html="content"></p>
</body>
CSS
.bold {
font-weight: bold;
}

Edit: new solution:
$scope.text = $scope.text.replace(new RegExp("(" + $scope.searchTerm + ")","gi"), "long-random-string-one$1long-random-string-two");
// Any encoding goes here
$scope.text = $scope.text.replace("long-random-string-one", "<span class='highlighted'>").replace("long-random-string-two", "</span>")
The idea is to insert two strings that won't be changed by the encoding, and are unique enough that they are extremely unlikely to be present in the text you are searching. Replace them with GUIDs if you want.

Related

How to define style attribute when html is in double quotes (as String)

My question is very straight forward. I am trying to put style attribute in a html which is in string format. Through a method i am passing html code in string format. And later i am suppose to add a css in that depending on the situation.
I tried:
"<div style='background-color: red'>'Some data'</div>" // didnt help
"<div style="background-color: red;">'Some data'</div>" // didnt help
In the end:
if(somethingMatches){
data = data.replace('something', "<mark style='background-color: red;'>" + 'something' + "</mark>")
}
Is there some way that i can pull it off...
This is one of the way:
var data = document.body.innerHTML;
data = data.replace(/something/g, "<mark style='background-color: red;'>" + 'something' + "</mark>");
document.body.innerHTML = data;
my name is something<br>
something is going on
If you want to replace all matching words then you should use Regular expression in JavaScript

Trouble Adding Array output to an Dynamically Generated HTML String in GAS Google Script

I am trying to automate my businesses blog. I want to create a dynamic html string to use as a wordpress blog description. I am pulling text data from email body's in my gmail account to use as information. I parse the email body using the first function below.
I have everything working properly except for the for loop (in the second code block) creating the description of the post. I have searched for hours and tried dozens of different techniques but I cant figure it out for the life of me.
Here is how I am reading the text values into an array:
function getMatches(string, regex, index) {
index || (index = 1); // default to the first capturing group
var matches = [];
var match;
while (match = regex.exec(string)) {
matches.push(match[index]);
}
return matches;
}
This is how I am trying to dynamically output the text arrays to create a basic HTML blogpost description (which I pass to xmlrpc to post):
var1 = getMatches(string, regex expression, 1);
var2 = getMatches(string, regex expression, 1);
var3 = getMatches(string, regex expression, 1);
var3 = getMatches(string, regex expression, 1);
var fulldesc = "<center>";
var text = "";
for (var k=0; k<var1.length; k++) {
text = "<u><b>Var 1:</u></b> " + var1[k] + ", <u><b>Var 2:</u></b> " + var2[k] + ", <u><b>Var 3:</u></b> " + var3[k] + ", <u><b>Var 4:</u></b> " + var4[k] + ", <br><br>";
fulldesc += text;
}
fulldesc += "</center>";
Lastly here is the blog post description code (using GAS XMLRPC library):
var fullBlog = "<b><u>Headline:</u> " + sub + "</b><br><br>" + fulldesc + "<br><br>General Description: " + desc;
var blogPost = {
post_type: 'post',
post_status: 'publish', // Set to draft or publish
title: 'Ticker: ' + sub, //sub is from gmail subject and works fine
categories: cat, //cat is defined elsewhere and works fine
date_created_gmt: pubdate2, //defined elsewhere (not working but thats another topic)
mt_allow_comments: 'closed',
description: fullBlog
};
request.addParam(blogPost);
If there's only one value in the var1,2,3,4 arrays all works as it should. But any more than 1 value and I get no output at all from the "fulldesc" var. All other text variables work as they should and the blog still gets posted (just minus some very important information). I'm pretty sure the problem lies in my for loop which adds the HTML description to text var.
Any suggestions would be greatly appreciated, I'm burned out trying to get the answer! I am a self taught programmer (just from reading this forum) so please go easy on me if I missed something stupid :)
Figured it out: It wasnt the html/text loop at all. My blogpost title had to be a variable or text, but not both.
Not working:
title: 'Ticker: ' + sub, //sub is from gmail subject and works fine
Working:
var test = 'Ticker: ' + sub;
//
title:test,

Parse html code and set <span> tag

<div id=bar>
Hey, <b>how</b> are <span><u><b>you</b>?</u></span>
</div>
I need to parse this code and set a span tag in a determined position identified by a start and an end.
An example is: START: 15 - END: 16
(note, "start" and "end" are set from the simple string "Hey, how are you?")
<div id=bar>
Hey, <b>how</b> are <span><u><b>y<span id=someid>ou</span></b>?</u></span>
</div>
My idea is to parse the node "bar", getting its html code, and with a complex OOP algoritm set the span tag, but...it's hard and long to do. (everything in JS)
Is there a good programming language to semplify my work?
I think I get what you are trying to do. Try this out:
var text = $("#bar").text(); //jQuery gives you the text...strips the html tags
var html = $("#bar").html(); //jQuery gives you the html and text here
text = $.trim(text); //remove any whitespace from start and end
var original = text.substr(14, 2); //Get the substring you want
var updated = "<span id='someid'>" + original + "</span>";
html = html.replace(original, updated); //replace
$("#bar").html(html); //set new html
JsFiddle here: http://jsfiddle.net/bbcLm97o/2/

Loop Through HTML Elements and Nodes

I'm working on an HTML page highlighter project but ran into problems when a search term is a name of an HTML tag metadata or a class/ID name; eg if search terms are "media OR class OR content" then my find and replace would do this:
<link href="/css/DocHighlighter.css" <span style='background-color:yellow;font-weight:bold;'>media</span>="all" rel="stylesheet" type="text/css">
<div <span style='background-color:yellow;font-weight:bold;'>class</span>="container">
I'm using Lucene for highlighting and my current code (sort of):
InputStreamReader xmlReader = new INputStreamReader(xmlConn.getInputStream(), "UTF-8");
if (searchTerms!=null && searchTerms!="") {
QueryScorer qryScore = new QueryScorer(qp.parse(searchTerms));
Highlighter hl = new Highlighter(new SimpleHTMLFormatter(hlStart, hlEnd), qryScore);
}
if (xmlReader!=null) {
BufferedReader br = new BufferedReader(xmlReader);
String inputLine;
while((inputLine = br.readLine())!=null) {
String tmp = inputLine.trim();
StringReader strReader = new stringReader(tmp);
HTMLStripCharFilter htm = HTMLStripCharFilter(strReader.markSupported() ? strReader : new BufferedReader(strReader));
String tHL = hl.getBestFragment(analyzer, "", htm);
tmp = (tHL==null ? tmp : tHL);
}
xmlDoc+=tmp;
}
bufferedReader.close()
As you can see (if you understand Lucene highlighting) this does an indiscriminate find/replace. Since my document will be HTML and the search terms are dictated by users there is no way for me to parse on certain elements or tags. Also, since the find/replace basically loops and appends the HTML to a string (the return type of the method) I have to keep all HTML tags and values in place and order. I've tried using Jsoup to loop through the page but handles the HTML tag as one big result. I also tried tag soup to remove the broken HTML caused by the problem but it doesn't work correctly. Does anyone know how to basically loop though the elements and node (data value) of html?
I've been having the most luck with this
StringBuilder sb = new StringBuilder();
sb.append("<?xml version=\"1.0\" enconding=\"UTF-8\"?><!DOCTYPE html>");
Document doc = Jsoup.parse(txt.getResult());
Element elements = doc.getAllElements();
for (Element e : elements) {
if (!(e.tagName().equalsIgnoreCase("#root"))) {
sb.append("<" + e.tagName() + e.attributes() + ">" + e.ownText() + "\n");
}// end if
}// end for
return sb;
The one snag I still get is the nesting isn't always "repaired" properly but still semi close. I'm working more on this.

Setting textformat to mulitple parts of a string

I'm having an issue with applying textformat to various parts of a string:
feedBackText = "This is <b>bold</b>, and this is some more text, and <b>this is bold too</b>. But this is not bold. This is <b>bold</b>!";
feedbackTextField.htmlText = feedBackText;
var startBoldPos:int = 0;
var closeBoldPos:int = 0;
var i:uint = 0;
while(true) {
startBoldPos = feedBackText.indexOf("<b>", startBoldPos);
closeBoldPos = feedBackText.indexOf("</b>", startBoldPos);
if(startBoldPos > 0) {
i++;
// Here is the main trouble:
feedbackTextField.setTextFormat(_boldFormat, startBoldPos-((7)*i), closeBoldPos-((10)*i));
trace("i is: " + i);
trace("Feedbacktext: " + feedBackText);
trace("Start bold: " + startBoldPos);
trace("End bold: " + closeBoldPos + "\n");
} else {
// This works as expected
feedbackTextField.setTextFormat(_boldFormat, startBoldPos, closeBoldPos-3);
// trace("Feedbacktext: " + feedBackText);
// trace("Start bold: " + startBoldPos);
// trace("End bold: " + closeBoldPos + "\n");
}
if(startBoldPos == -1) break;
startBoldPos = closeBoldPos;
}
I'm trying to play around with the index of where the setTextFormat should be assigned, but it doesn't seem to align with startBoldPos and endBoldPos. Even if the traces are showing the correct numbers of where to place setTextFormat it in the string.
Any ideas would be apppreciated!
Regards,
Hans Magnus
I tested your code and it works as expected. I don't fully understand what you trying to do, so here some general remarks:
You can set some formatting without setTextFormat only with htmlText. After assigning text with html tags textField text will be already partly formatted.
setTextFormat works with text property, so start and end index calculated depend on text without html tags. In your case it will be: This is bold, and this is some more text, and this is bold too. But this is not bold. This is bold!
And tracing your code step by step:
1) Setting text with to htmlText property in TextField. After this TextField contained:
This is bold, and this is some more text, and this is bold too. But this is not bold. This is bold!
2) Loop starts. First iteration:
startBoldPos-((7)*i) = 1
closeBoldPos-((10)*i) = 5
TextField: This is bold, and this is some more text, and this is bold too. But this is not bold. This is bold!
3) Second iteration:
startBoldPos-((7)*i) = 39
closeBoldPos-((10)*i) = 52
TextField: This is bold, and this is some more text, and this is bold too. But this is not bold. This is bold!
4) Third iteration:
startBoldPos-((7)*i) = 87
closeBoldPos-((10)*i) = 85
Nothing changed bacause endPosition < startPosition.
5) Fourth iteration:
startBoldPos = -1
closeBoldPos-3 = 12
TextField: This is bold, and this is some more text, and this is bold too. But this is not bold. This is bold!
And final result on screenshot:
UPDATE (formatting without setTextFormat method):
...
[Embed(source="GOTHIC.TTF", fontName="Gothic", embedAsCFF="false", advancedAntiAliasing="true")]
private var gothicFont:Class;
[Embed(source="GOTHICB.TTF", fontName="Gothic", embedAsCFF="false", advancedAntiAliasing="true", fontWeight="bold")]
private var gothicFontBold:Class;
...
var feedBackText:String = "This is <b>bold</b>, and this is some more text, and <b>this is bold too</b>. But this is not bold. This is <b>bold</b>!";
var feedbackTextField:TextField = new TextField();
feedbackTextField.defaultTextFormat = new TextFormat("Gothic", 14);
feedbackTextField.embedFonts = true;
feedbackTextField.width = 500;
feedbackTextField.htmlText = feedBackText;
And result (with embed font as you see):