i'm trying to make some code that'll loop over html forum data and replace some brackets.
i'm basically trying to turn
<br><br>
<br>
<img src="blah"></img>
to
[br][br]
[br]
[img src="blah"][/img]
and avoid changing text like
:<
<("<) <(")> (>")>
I'm using javascript and a regex pattern for now. I was able to find a regex for something between two tags, but not two tags around a string. What would be the best way to do this?
There's probably a far more elegant way to do this - but this is basically how I did it in the early 2000's (slight update to more modern JS with const/let etc)
const input = `<br><br>
<br>
<img src="blah"></img>`;
const body = document.createElement('body');
body.innerHTML = input;
function square(obj) {
let out = '';
let el;
while(el = obj.firstChild) {
if (el.nodeType == 3) {
out += el.nodeValue;
} else {
out += `[${el.nodeName}]`;
out += square(el);
if (!["BR"].includes(el.nodeName)) {
out += `[/${el.nodeName}]`;
}
}
el.remove();
}
return out;
}
console.log(square(body));
Related
I have variable containing some text.Basically I am trying to do toggle(hide/show) in html using c#.I want to pass this variable to javascript function that is performing hide and show .
Here is my code:
static void Main(string[] args)
{
string res = null;
string toggle = null;
res += "<div style=\"display: none;\">This is the content that is dynamically being collapsed.</div>";
toggle += "<html><head>";
toggle += "<script type=\"text/javascript\"></script><script> function toggle2(showDetails) {var ele =document.getElementById(showDetails);if(ele.style.display == \"block\") {ele.style.display = \"none\";}else {ele.style.display = \"block\";}}</script>";
toggle += "</head>";
toggle += "<body>";
toggle += "collapse";
toggle += "</body>";
toggle += "</html>";
FileStream log = new FileStream(#"E:\report2.html", FileMode.Create);
using (StreamWriter w = new StreamWriter(log, Encoding.UTF8))
{
w.WriteLine(toggle);
}
}
On clicking collapse,it should display the content of variable res.Where am I doing wrong?
Thanks in advance
You've got multiple issues:
The "quotes" inside your string are messing with the href="quotes"
Your JavaScript function is incorrect
The general approach is unusual/ very error-prone
Nitpicking: Don't use += and null
First, those quotes
Take a look at your file report2.html in your favourite text editor and you'll probably see this:
<a href="javascript:toggle2('<div style="display: none;">This is the content that is dynamically being collapsed.</div>')">
StackOverflow's code colouring helps here - notice that display:none; is black. This is because it's essentially seeing just href="javascript:toggle2('<div style="
A simple fix is to double-escape those quotes in your res string:
<div style=\\\"display: none;\\\">This is the content..
..but yikes. This kind of thing is really not recommended unless you have to!
Second, the function
I (and many others!) really dislike JavaScript inside a string like this - it promotes bad code formatting, for starters. Let's undo that and make it pretty:
function toggle2(showDetails) {
var ele =document.getElementById(showDetails);
if(ele.style.display == "block") {
ele.style.display = "none";
}else {
ele.style.display = "block";
}
}
That's better! So, firstly, showDetails is not an ID of an element - it's a full string of content. Pass an ID instead:
function toggle2(elementID) {
var ele =document.getElementById(elementID);
if(ele.style.display == "block") {
ele.style.display = "none";
}else {
ele.style.display = "block";
}
}
This way you can instead use, e.g:
toggle+="<div id='collapsibleDiv'>"+res+"</div>";
toggle+="<div onmousedown=\"toggle2('collapsibleDiv');\">Click me!</div>";
instead. A bonus here is that it doesn't need to deal with those quotes in res.
Null and +=
Right at the start you've got this:
string res=null;
res+="...";
It's safer to just use string res=".."; instead as adding a null to anything is bad practice. Some programming languages will straight crash on you.
I'm using the below code for wrapping long text, entered by users in a text area for commenting:
function addNewlines(comments) {
var result = '';
while ($.trim(comments).length > 0) {
result += comments.substring(0,70) + '\n';
comments = comments.substring(70);
}
return result;
}
The problem is shown in the below screen shot. Any ideas on how to solve it? Can we use lastindexof(" ") method to get the last space in a substring to solve this issue logically? Can anyone tweak this little code to make it right?
I believe wrapping a text by CSS is a better solution however there is a link here which may be helpful wrap-text-in-javascript
by the way i remember there is a JQuery plugin for wrapping text google it too.
Try word-wrap: break-word in CSS.
The word-wrap property is well supported by browsers (even IE 5.5+).
More info here: https://developer.mozilla.org/en-US/docs/CSS/word-wrap
Sample usage: FIDDLE
Try one of these:
word-wrap:no-wrap;
word-wrap: break-word
It might solve your problem
The ones above only work 99% of the time. This is the only one that works for me 100%:
http://locutus.io/php/strings/wordwrap/
Hi just apply some css on text area like
style="word-wrap: break-word;"
I use this css code for displaying in Torch browser and it works
I've tried word-wrap:break-word;overflow:ellipsis;....etc, but didn't work.
#xxx{
width: 750px;
word-break: break-word;
}
After looking for the perfect solution using regex and other implementations. I decided to right my own. It is not perfect however worked nice for my case, maybe it does not work properly when you have all your text in Upper case.
function breakTextNicely(text, limit, breakpoints) {
var parts = text.split(' ');
var lines = [];
text = parts[0];
parts.shift();
while (parts.length > 0) {
var newText = `${text} ${parts[0]}`;
if (newText.length > limit) {
lines.push(`${text}\n`);
breakpoints--;
if (breakpoints === 0) {
lines.push(parts.join(' '));
break;
} else {
text = parts[0];
}
} else {
text = newText;
}
parts.shift();
}
if (lines.length === 0) {
return text;
} else {
return lines.join('');
}
}
var mytext = 'this is my long text that you can break into multiple line sizes';
console.log( breakTextNicely(mytext, 20, 3) );
I had the same issue, I solved it using the below function.
function wordWrap(message, lineSize, breakPoint){
let wordsArr = message.split(" "),
wordsLen = wordsArr.length,
finalMsg = "",
linesArr = [""],
currLine = 0;
for(let i=0; i< wordsLen; i++){
if(linesArr[currLine].length + wordsArr[i].length > lineSize){
currLine +=1;
linesArr[currLine] = wordsArr[i] + " ";
} else {
linesArr[currLine] += wordsArr[i] + " ";
}
}
let linesLen = linesArr.length;
for(let i=0; i<linesLen; i++){
finalMsg += linesArr[i] + breakPoint;
}
return finalMsg.trim();
}
Hope this helps.
i'm trying to make my own markdown-able textarea like Stackoverflow has done. The goal is to allow people to type **blah blah** in a textarea and have the output in a div be <span style="font-weight:bold;">blah blah</span>.
I'm having trouble with the javascript to find and replace to the **asterisks with the HTML.
here's a jsfiddle which has gotten the party started: http://jsfiddle.net/trpeters1/2LAL4/14/
here's the JS on that just to show you where I'm at:
$(document.body).on('click', 'button', function() {
var val=$('textarea').val();
var bolded=val.replace(/\**[A-z][0-9]**/gi, '<span style="font-weight:bold;">"'+val+'" </span>');
$('div').html(bolded);
});
and the HTML...
<textarea></textarea>
<div></div><button type="button">Markdownify</button>
any thoughts would be greatly appreciated!
thanks,
tim
The other answers fail when a char is immediately before or after the asterisks.
This works like markdown should:
function bold(text){
var bold = /\*\*(.*?)\*\*/gm;
var html = text.replace(bold, '<strong>$1</strong>');
return html;
}
var result = bold('normal**bold**normal **b** n.');
document.getElementById("output").innerHTML = result;
div { color: #aaa; }
strong { color: #000; }
<div id="output"></div>
None of the provided answers works in all cases. For example, the other solutions wont work if we have a space next to the double star, ie:
This will ** not ** be bold
So I wrote this:
function markuptext(text,identifier,htmltag)
{
var array = text.split(identifier);
var previous = "";
var previous_i;
for (i = 0; i < array.length; i++) {
if (i % 2)
{
//odd number
}
else if (i!=0)
{
previous_i = eval(i-1);
array[previous_i] = "<"+htmltag+">"+previous+"</"+htmltag+">";
}
previous = array[i];
}
var newtext = "";
for (i = 0; i < array.length; i++) {
newtext += array[i];
}
return newtext;
}
Just call it like this:
thetext = markuptext(thetext,"**","strong");
and it will work in all cases. Of course, you can also use it with other identifiers/html-tags as you like
(the stackoverflow preview should have this too).
Choose the perfect regex that will fit your needs.
If you don't want styling to span through new line and also using ([^*<\n]+) makes sure at least one character is in between styles or else ** without a character in-between will result will become invisible.
function format_text(text){
return text.replace(/(?:\*)([^*<\n]+)(?:\*)/g, "<strong>$1</strong>")
.replace(/(?:_)([^_<\n]+)(?:_)/g, "<i>$1</i>")
.replace(/(?:~)([^~<\n]+)(?:~)/g, "<s>$1</s>")
.replace(/(?:```)([^```<\n]+)(?:```)/g, "<tt>$1</tt>")
}
•The downside to the above code is that, you can't nest styles i.e *_Bold and italic_*
To allow nested styles use this 👇
format_text(text){
return text.replace(/(?:\*)(?:(?!\s))((?:(?!\*|\n).)+)(?:\*)/g,'<b>$1</b>')
.replace(/(?:_)(?:(?!\s))((?:(?!\n|_).)+)(?:_)/g,'<i>$1</i>')
.replace(/(?:~)(?:(?!\s))((?:(?!\n|~).)+)(?:~)/g,'<s>$1</s>')
.replace(/(?:--)(?:(?!\s))((?:(?!\n|--).)+)(?:--)/g,'<u>$1</u>')
.replace(/(?:```)(?:(?!\s))((?:(?!\n|```).)+)(?:```)/g,'<tt>$1</tt>');
// extra:
// --For underlined text--
// ```Monospace font```
}
👆 If you want your style to span through new line, then remove \n from the regex. Also if your new line is html break tag, you can replace \n with <br>
Thank me later!
Why create from scratch? With so many open source editors out there, you should pick a code base you like & go from there.
http://oscargodson.github.com/EpicEditor/
http://markitup.jaysalvat.com/home/
custom component in react who receives bold like boolean
{(() => {
const splitText = theText.split('**');
return (
<TextByScale>
{splitText.map((text, i) => (
<TextByScale bold={!!(i % 2)}>{text}</TextByScale>
))}
</TextByScale>
);
})()}
If you are using jQuery, replace this:
$(document.body).on('click', 'button', function() {
with this:
$("button").click(function () {
The following regular expression will find your asterisk-wrapped text:
/\x2a\x2a[A-z0-9]+\x2a\x2a/
I updated your fiddle as an example: http://jsfiddle.net/2LAL4/30/
Your regex is broken, for one thing. You probably want something more like:
/\*\*[A-z0-9]+\*\*/gi
The * is a special character in regular expressions. If you want to match against a literal *, then you need to escape it with \.
For instance: http://jsfiddle.net/2LAL4/22/
However, even with this change there's still a fair ways to go before you get to where you really want to be. For instance, your example will not work if the text area contains a mix of bold and non-bold text.
I am using a 'contenteditable' <div/> and enabling PASTE.
It is amazing the amount of markup code that gets pasted in from a clipboard copy from Microsoft Word. I am battling this, and have gotten about 1/2 way there using Prototypes' stripTags() function (which unfortunately does not seem to enable me to keep some tags).
However, even after that, I wind up with a mind-blowing amount of unneeded markup code.
So my question is, is there some function (using JavaScript), or approach I can use that will clean up the majority of this unneeded markup?
Here is the function I wound up writing that does the job fairly well (as far as I can tell anyway).
I am certainly open for improvement suggestions if anyone has any. Thanks.
function cleanWordPaste( in_word_text ) {
var tmp = document.createElement("DIV");
tmp.innerHTML = in_word_text;
var newString = tmp.textContent||tmp.innerText;
// this next piece converts line breaks into break tags
// and removes the seemingly endless crap code
newString = newString.replace(/\n\n/g, "<br />").replace(/.*<!--.*-->/g,"");
// this next piece removes any break tags (up to 10) at beginning
for ( i=0; i<10; i++ ) {
if ( newString.substr(0,6)=="<br />" ) {
newString = newString.replace("<br />", "");
}
}
return newString;
}
Hope this is helpful to some of you.
You can either use the full CKEditor which cleans on paste, or look at the source.
I am using this:
$(body_doc).find('body').bind('paste',function(e){
var rte = $(this);
_activeRTEData = $(rte).html();
beginLen = $.trim($(rte).html()).length;
setTimeout(function(){
var text = $(rte).html();
var newLen = $.trim(text).length;
//identify the first char that changed to determine caret location
caret = 0;
for(i=0;i < newLen; i++){
if(_activeRTEData[i] != text[i]){
caret = i-1;
break;
}
}
var origText = text.slice(0,caret);
var newText = text.slice(caret, newLen - beginLen + caret + 4);
var tailText = text.slice(newLen - beginLen + caret + 4, newLen);
var newText = newText.replace(/(.*(?:endif-->))|([ ]?<[^>]*>[ ]?)|( )|([^}]*})/g,'');
newText = newText.replace(/[·]/g,'');
$(rte).html(origText + newText + tailText);
$(rte).contents().last().focus();
},100);
});
body_doc is the editable iframe, if you are using an editable div you could drop out the .find('body') part. Basically it detects a paste event, checks the location cleans the new text and then places the cleaned text back where it was pasted. (Sounds confusing... but it's not really as bad as it sounds.
The setTimeout is needed because you can't grab the text until it is actually pasted into the element, paste events fire as soon as the paste begins.
How about having a "paste as plain text" button which displays a <textarea>, allowing the user to paste the text in there? that way, all tags will be stripped for you. That's what I do with my CMS; I gave up trying to clean up Word's mess.
You can do it with regex
Remove head tag
Remove script tags
Remove styles tag
let clipboardData = event.clipboardData || window.clipboardData;
let pastedText = clipboardData.getData('text/html');
pastedText = pastedText.replace(/\<head[^>]*\>([^]*)\<\/head/g, '');
pastedText = pastedText.replace(/\<script[^>]*\>([^]*)\<\/script/g, '');
pastedText = pastedText.replace(/\<style[^>]*\>([^]*)\<\/style/g, '');
// pastedText = pastedText.replace(/<(?!(\/\s*)?(b|i|u)[>,\s])([^>])*>/g, '');
here the sample : https://stackblitz.com/edit/angular-u9vprc
I did something like that long ago, where i totally cleaned up the stuff in a rich text editor and converted font tags to styles, brs to p's, etc, to keep it consistant between browsers and prevent certain ugly things from getting in via paste. I took my recursive function and ripped out most of it except for the core logic, this might be a good starting point ("result" is an object that accumulates the result, which probably takes a second pass to convert to a string), if that is what you need:
var cleanDom = function(result, n) {
var nn = n.nodeName;
if(nn=="#text") {
var text = n.nodeValue;
}
else {
if(nn=="A" && n.href)
...;
else if(nn=="IMG" & n.src) {
....
}
else if(nn=="DIV") {
if(n.className=="indent")
...
}
else if(nn=="FONT") {
}
else if(nn=="BR") {
}
if(!UNSUPPORTED_ELEMENTS[nn]) {
if(n.childNodes.length > 0)
for(var i=0; i<n.childNodes.length; i++)
cleanDom(result, n.childNodes[i]);
}
}
}
This works great to remove any comments from HTML text, including those from Word:
function CleanWordPastedHTML(sTextHTML) {
var sStartComment = "<!--", sEndComment = "-->";
while (true) {
var iStart = sTextHTML.indexOf(sStartComment);
if (iStart == -1) break;
var iEnd = sTextHTML.indexOf(sEndComment, iStart);
if (iEnd == -1) break;
sTextHTML = sTextHTML.substring(0, iStart) + sTextHTML.substring(iEnd + sEndComment.length);
}
return sTextHTML;
}
Had a similar issue with line-breaks being counted as characters and I had to remove them.
$(document).ready(function(){
$(".section-overview textarea").bind({
paste : function(){
setTimeout(function(){
//textarea
var text = $(".section-overview textarea").val();
// look for any "\n" occurences and replace them
var newString = text.replace(/\n/g, '');
// print new string
$(".section-overview textarea").val(newString);
},100);
}
});
});
Could you paste to a hidden textarea, copy from same textarea, and paste to your target?
Hate to say it, but I eventually gave up making TinyMCE handle Word crap the way I want. Now I just have an email sent to me every time a user's input contains certain HTML (look for <span lang="en-US"> for example) and I correct it manually.
I was wondering if it is possible to use JavaScript to add a <div> tag around a word in an HTML page.
I have a JS search that searches a set of HTML files and returns a list of files that contain the keyword. I'd like to be able to dynamically add a <div class="highlight"> around the keyword so it stands out.
If an alternate search is performed, the original <div>'s will need to be removed and new ones added. Does anyone know if this is even possible?
Any tips or suggestions would be really appreciated.
Cheers,
Laurie.
In general you will need to parse the html code in order to ensure that you are only highlighting keywords and not invisible text or code (such as alt text attributes for images or actual markup). If you do as Jesse Hallett suggested:
$('body').html($('body').html().replace(/(pretzel)/gi, '<b>$1</b>'));
You will run into problems with certain keywords and documents. For example:
<html>
<head><title>A history of tables and tableware</title></head>
<body>
<p>The table has a fantastic history. Consider the following:</p>
<table><tr><td>Year</td><td>Number of tables made</td></tr>
<tr><td>1999</td><td>12</td></tr>
<tr><td>2009</td><td>14</td></tr>
</table>
<img src="/images/a_grand_table.jpg" alt="A grand table from designer John Tableius">
</body>
</html>
This relatively simple document might be found by searching for the word "table", but if you just replace text with wrapped text you could end up with this:
<<span class="highlight">table</span>><tr><td>Year</td><td>Number of <span class="highlight">table</span>s made</td></tr>
and this:
<img src="/images/a_grand_<span class="highlight">table</span>.jpg" alt="A grand <span class="highlight">table</span> from designer John <span class="highlight">Table</span>ius">
This means you need parsed HTML. And parsing HTML is tricky. But if you can assume a certain quality control over the html documents (i.e. no open-angle-brackets without closing angle brackets, etc) then you should be able to scan the text looking for non-tag, non-attribute data that can be further-marked-up.
Here is some Javascript which can do that:
function highlight(word, text) {
var result = '';
//char currentChar;
var csc; // current search char
var wordPos = 0;
var textPos = 0;
var partialMatch = ''; // container for partial match
var inTag = false;
// iterate over the characters in the array
// if we find an HTML element, ignore the element and its attributes.
// otherwise try to match the characters to the characters in the word
// if we find a match append the highlight text, then the word, then the close-highlight
// otherwise, just append whatever we find.
for (textPos = 0; textPos < text.length; textPos++) {
csc = text.charAt(textPos);
if (csc == '<') {
inTag = true;
result += partialMatch;
partialMatch = '';
wordPos = 0;
}
if (inTag) {
result += csc ;
} else {
var currentChar = word.charAt(wordPos);
if (csc == currentChar && textPos + (word.length - wordPos) <= text.length) {
// we are matching the current word
partialMatch += csc;
wordPos++;
if (wordPos == word.length) {
// we've matched the whole word
result += '<span class="highlight">';
result += partialMatch;
result += '</span>';
wordPos = 0;
partialMatch = '';
}
} else if (wordPos > 0) {
// we thought we had a match, but we don't, so append the partial match and move on
result += partialMatch;
result += csc;
partialMatch = '';
wordPos = 0;
} else {
result += csc;
}
}
if (inTag && csc == '>') {
inTag = false;
}
}
return result;
}
Wrapping is pretty easy with jQuery:
$('span').wrap('<div class="highlight"></div>'); // wraps spans in a b tag
Then, to remove, something like this:
$('div.highlight').each(function(){ $(this).after( $(this).text() ); }).remove();
Sounds like you will have to do some string splitting, though, so wrap may not work unless you want to pre-wrap all your words with some tag (ie. span).
The DOM API does not provide a super easy way to do this. As far as I know the best solution is to read text into JavaScript, use replace to make the changes that you want, and write the entire content back. You can do this either one HTML node at a time, or modify the whole <body> at once.
Here is how that might work in jQuery:
$('body').html($('body').html().replace(/(pretzel)/gi, '<b>$1</b>'));
couldn't you just write a selector as such to wrap it all?
$("* :contains('foo')").wrap("<div class='bar'></div>");
adam wrote the code above to do the removal:
$('div.bar').each(function(){ $(this).after( $(this).text() ); }).remove();
edit: on second thought, the first statement returns an element which would wrap the element with the div tag and not the sole word. maybe a regex replace would be a better solution here.