I've got this bit of jQuery with some javascript and RegEx mixed in:
$(function() {
var regExp = new RegExp("\\b(" + "hashtag" + ")\\b", "gm");
var boxLink = "<a class='taglink' onClick='tagBox()'>$1</a>"
var html = $('body').html();
$('body').html(html.replace(regExp, boxLink));
});
function tagBox() {
alert("It works!")
};
Basically it applies $1 to everywhere that the word "hashtag" appears. Tagbox just brings up an alert that says it works. Simple enough. The change I'd like to make is one so that it won't jet select the word "hashtag", but all words with "#" symbols before them.
How can I accomplish this and work it into the script above?
Thanks in advance!
First of all, $('body').html(html) is a really bad idea. You'll recreate the DOM, and any event listeners previously bound to nodes within the old structure will no longer function. Traversing the DOM node by node is a better idea. Something like this should do the trick:
// Douglas Crockford's WalkTheDOM
function walkTheDOM(node, func) {
func(node);
node = node.firstChild;
while (node) {
walkTheDOM(node, func);
node = node.nextSibling;
}
}
function esc(text) {
return text.replace(/[&<>"'`]/g, function (chr) {
return '&#' + chr.charCodeAt(0) + ';'
})
}
walkTheDOM(document.body, function (node) {
if (node.nodeType === 3) {
var html = ''
// The even indexes contain the hashtags; the odd indexes contain
// the text that appears between one hashtag and the next.
//
// > 'This post is tagged #javascript and #jquery'.split(/(#\w+)/)
// ["This post is tagged ", "#javascript", " and ", "#jquery", ""]
//
// Text must be escaped before being inserted via `.html()`.
$.each(node.textContent.split(/(#\w+)/), function (idx, text) {
html += idx % 2 ? esc(text) : '<a class="taglink">' + esc(text) + '</a>'
})
$(node).parent().html(html)
}
})
This code is untested, and no doubt has some bugs, but hopefully I've convinced you that this problem is more difficult than it may have appeared at first.
Try something like this
var regExp = new RegExp("(#\w+)", "gm");
If you want to select a word without #, move it in front of the (
Related
I have a nicely functioning full calendar script. I have some filters for it, which basically have the following form:
$("input[name='event_filter_select']:checked").each(function () {
// I specified data-type attribute in HTML checkboxes to differentiate
// between risks and tags.
// Saving each type separately
if ($(this).data('type') == 'risk') {
risks.push($(this).val());
} else if ($(this).data('type') == 'tag') {
tagss.push($(this).val());
}
});
However the else if statement should check if the checked value 'tag' is contained within the result set, not be the only value of the result set (as implied by the ==).
Now I can only filter results that have the checked tag-value only. But i want to filter those, which have the tag-value amongst many others.
I figure this is to be done with match(/'tag'/) but i cannot figure out for the life of me how to put that into an if-statement.
Would be really glad if someone could lead me in the right direction.
I would simply do:
...
if ($(this).data('type') == 'risk') {
risks.push($(this).val());
} else if ($(this).data('type').test(/^tag/) {
tagss.push($(this).val());
}
...
This works if the 'tag' must be at the beginning of the string.
If the 'tag' can be everywhere in the string, you can use test(/tag/).
If your data is a string, example: tag filter1 filter2 filter3, you could use the indexOf-function (manual)
Code:
if ($(this).data('type').indexOf("risk") != -1))
//Action here.
indexOf returns -1 if the text isn't found.
You can use:
var re = new RegExp('\\b' + word + '\\b', 'i');
or if you wish to have the word hard-coded in (e.g., in the example, the word test):
var re = /\btest\b/i
Example showing the matches below:
var input = document.querySelector('input');
var div = document.querySelector('div');
var re;
var match;
input.addEventListener('keyup', function() {
match = input.value.trim();
re = new RegExp('\\b' + match + '\\b', 'i');
if($('div').data('type').match(re))
div.innerHTML = 'Matched the word: ' + '<strong>' + match + '</strong>';
else div.innerHTML = 'Did not match the word: ' + '<strong>' + match + '</strong>';
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
Word to match:<input></input><br>
Output:
<div data-type='tag tags test'></div>
With the above regular expression incorporated into your code, it should look something like this:
else if ($(this).data('type').match(/\btag\b/i) { //true for data-type that has `tag` in it.
tagss.push($(this).val());
}
Try with this condition.
/\btag\b/.test($(this).data('type'))
User enter chat messages, which gets rendered directly to the page using Mustache templates. Obviously, HTML should be escaped to prevent HTML injection, but then again links should be rendered as <a href='...'>.
There are different approaches I've tried to use {{{ ... }}} to return the unescaped HTML content, which means the link would get rendered and I need to take care of HTML escaping myself. Is there a safe way of doing that without relying on a half-baked solution I write myself?
jQuery.text() would be great, but I guess it will render the <a> again as text.
What else can I do here?
If you don't want to write your own escaping or parsing solution there is a jQuery plugin to handle links called Linkify. You could simply escape messages and then parse them client-side.
Example of how it works:
var text = "<div>Test<br>Test<br>Test http://stackoverflow.com</div>";
$('div').text(text);
// Before: <div>Test<br>Test<br>Test http://stackoverflow.com</div>
$('div').linkify();
// After: lt;div>Test<br>Test<br>Test http://stackoverflow.com</div>
Just an idea: You could build your own escaping function
escape : function () {
return function(val, render) {
var $s = $(val);
var $elements = $s.find("*").not("a"); //add other white-listed elements seperated by comma
for (var i = $elements.length - 1; i >= 0; i--) {
var e = $elements[i];
$(e).replaceWith(e.innerHTML);
}
return $s.html();
}
}
You can call the function by
{{#escape}}{{{YOUR_TEXT}}}{{/escape}}
I have not tested this. This solution needs jQuery. The code above is based on this solution: https://stackoverflow.com/a/27764431/1479486
try inserting first in .text() and then use regexp for render the link with .html(). Here you can see a vanilla example:
var a="see formula a<b>c in http://test.com or https://x.com?p=3";
var hold=document.createElement('div');
hold.textContent=a;
hold.innerHTML=hold.innerHTML.replace(
/(https?:\/\/[-$A-Za-z0-9%_?&.~+\/=]+)/g,
'$1'
);
window.addEventListener('load',function(){
document.body.appendChild(hold);
});
For a more acurate regexp you can see here
If you end up going down the regex route the following filter and regex was the most aggressive one i found for picking up all kinds of urls that your users will try to type.
Heres a regexr to play around with it: http://regexr.com/3bjk9
(function () {
'use strict';
angular
.module('core.filters')
.filter('urlToA', urlToA);
// --------------------
function urlToA () {
return function (string, noClick) {
var urlPattern = /((?:(http|https|Http|Https|rtsp|Rtsp):\/\/(?:(?:[a-zA-Z0-9\$\-\_\.\+\!\*\'\(\)\,\;\?\&\=]|(?:\%[a-fA-F0-9]{2})){1,64}(?:\:(?:[a-zA-Z0-9\$\-\_\.\+\!\*\'\(\)\,\;\?\&\=]|(?:\%[a-fA-F0-9]{2})){1,25})?\#)?)?((?:(?:[a-zA-Z0-9][a-zA-Z0-9\-]{0,64}\.)+(?:(?:aero|arpa|asia|a[cdefgilmnoqrstuwxz])|(?:biz|b[abdefghijmnorstvwyz])|(?:cat|com|coop|c[acdfghiklmnoruvxyz])|d[ejkmoz]|(?:edu|e[cegrstu])|f[ijkmor]|(?:gov|g[abdefghilmnpqrstuwy])|h[kmnrtu]|(?:info|int|i[delmnoqrst])|(?:jobs|j[emop])|k[eghimnrwyz]|l[abcikrstuvy]|(?:mil|mobi|museum|m[acdghklmnopqrstuvwxyz])|(?:name|net|n[acefgilopruz])|(?:org|om)|(?:pro|p[aefghklmnrstwy])|qa|r[eouw]|s[abcdeghijklmnortuvyz]|(?:tel|travel|t[cdfghjklmnoprtvwz])|u[agkmsyz]|v[aceginu]|w[fs]|y[etu]|z[amw]))|(?:(?:25[0-5]|2[0-4][0-9]|[0-1][0-9]{2}|[1-9][0-9]|[1-9])\.(?:25[0-5]|2[0-4][0-9]|[0-1][0-9]{2}|[1-9][0-9]|[1-9]|0)\.(?:25[0-5]|2[0-4][0-9]|[0-1][0-9]{2}|[1-9][0-9]|[1-9]|0)\.(?:25[0-5]|2[0-4][0-9]|[0-1][0-9]{2}|[1-9][0-9]|[0-9])))(?:\:\d{1,5})?)(\/(?:(?:[a-zA-Z0-9\;\/\?\:\#\&\=\#\~\-\.\+\!\*\'\(\)\,\_])|(?:\%[a-fA-F0-9]{2}))*)?(?:\b|$)/gi; // jshint ignore:line
return string ? string.replace(urlPattern, replace) : string;
function replace (url) {
var httpUrl = url.indexOf('http') === -1 ? 'http://' + url : url;
if (noClick) {
return '<a>' + url + '</a>';
} else {
return '' + url + '';
}
}
};
}
})();
I'm trying to turn some text into html, but I'm having trouble building a table. Each cell is surrounded by brackets [].
I've already got the rows set:
<tr>[blue][red][yellow][purple][white]</tr>
Now I need to replace turn each cell into a <td>.
This would work fine:
.replace(/\[(.*?)\]/g,'<td>$1</td>')
but I don't want to happen in other parts of the document, just when it's in between tags.
This makes sense to me, but just doesn't work:
.replace(/(<tr>.*?)\[(.*?)\](.*?\<\/tr\>)/g,'$1<td>$2</td>$3')
here is a full code if you want to try it:
alert('<tr>[blue][red][yellow][purple][white]</tr>'.replace(/(<tr>.*?)\[(.*?)\](.*?\<\/tr\>)/g,'$1<td>$2</td>$3'));
it outputs:
<tr><td>blue</td>[red][yellow][purple][white]</tr>
expected output:
<tr><td>blue</td><td>red</td><td>yellow</td><td>purple</td><td>white</td></tr>
You can do this easily in two steps:
var str = "<div>[do not replace]</div><table><tr>[blue][red][yellow][purple][white]</tr></table>";
str = str.replace(/(<tr[\s\S]*?>)([\s\S]*?)(<\/tr>)/g, function(m, start, contents, end) {
return start + contents.replace(/\[([\s\S]*?)\]/g, "<td>$1</td>") + end;
});
alert(str);
Note that I replaced what should have been . with [\s\S] to simulate the s regex option that JS unfortunately lacks.
A way that use a split/join in the replacement function:
var str = '<tr>[blue][red][yellow][purple][white]</tr>';
var res = str.replace(/<tr>(?:\[[^\]]*\])+<\/tr>/g,
function (m) {
return '<tr><td>'
+ m.substring(5, m.length-6).split('][').join('</td><td>')
+ '</td><tr>';
});
console.log(res);
So over the past few days I have been searching for a solution that will allow me to insert a character (Specifically, the dollar sign) at the beginning of each line within a div. This is so that I can type the the commands in the back end with out the dollar sign and have it inserted automatically.
Currently, the backend of the site is using WordPress with the custom shortcode [command]. When the site is loaded the commands are returned as such:
<div id="command">
First Command<br />
Second Command<br />
Last Command<br />
</div>
I have tried to use JavaScript to replace '<br />' tag with '<br />$' however it doesn't replace all of them.
Any help is appreciated.
Cheers,
Joe
For multiple same ids:
$(function() {
var textNodes = $("[id^=command]");
$.each(textNodes, function(index, value) {
var nodes = $(this).contents().filter(function() {
return this.nodeType === 3;
});
$.each(nodes,function(index, value) {
if(index!=nodes.length-1) $(this).before("$");
});
});
});
Example : DEMO
$(function() {
var textNodes = $("#command").contents().filter(function() {
return this.nodeType === 3;
})
$.each(textNodes,function(index, value) {
if(index!=textNodes.length-1) $(this).before("$");
});
});
Output:
$ First Command
$ Second Command
$ Last Command
DEMO
Try replacing with regular expressions. It is possible that some breaks don't contain a slash or a space and I think this is why you might have missed some.
var str = str.replace(/<br\s*\/?>/ig, "<br />$");
The parameter g makes sure all occurrences are replaced in the string. The parameter i makes the search not case sensitive.
This should work for you
var textLines = ($('#command').html()).split('<br>');
var newLines = $.map(textLines,function(line){
return '$' + line;
});
$('#command').html(newLines.join('<br>'))
output
$ First Command
$ Second Command
$ Last Command
$
I'm trying to use JavaScript to replace target text with a hyperlinked version of the target text. Generally speaking, this is the function in question:
function replace_text_in_editor(target_text, target_type, target_slug) {
//if target_text was "Google", then the replacement_text might be "Google
var replacement_text = get_replacement_text(target_text, target_type, target_slug);
if(typeof replacement_text != undefined && replacement_text != '') {
var content = '';
content = jQuery( "#content" ).val();
content = content.replace(target_text,replacement_text)
if(content != '') {
jQuery( "#content" ).val(content);
}
}
}
I've tried a couple permutations of the following line, which I'd like to alert to only replace text that's not already hyperlinked.
var regex = "/" + target_text + "/";
content = content.replace(regex,replacement_text);
Example attempt:
var regex = "/^(<a.*?>)" + target_text + "^(<\/a>)/";
Can someone please correct me with a regex showing how I should be doing this? No need to explain what the regex does step by step, as I can infer that from the design. Thank you!
I think you want this but I'm not sure that I compeletly understand.
If you use RE to find the text you can assign it to group $1 by putting () around it (in this case "Google").
Then when you go to replace it you build the expression with that group assignment id $1
\<a href="$1\.com"\>$1\<\/a\>