does anyone know of a good regular expression to remove events from html.
For example the string:
"<h1 onmouseover="top.location='http://www.google.com">Large Text</h1>
Becomes
"<h1>Large Text</h1>
So HTML tags are preserved but events like onmouseover, onmouseout, onclick, etc. are removed.
Thanks in Advance!
How about:
data.replace(/ on\w+="[^"]*"/g, '');
Edit from the comments:
This is intended to be run on your markup as a one time thing. If you're trying to remove events dynamically during the execution of the page, that's a slightly different story. A javascript library like jQuery makes it extremely easy, though:
$('*').unbind();
Edit:
Restricting this to only within tags is a lot harder. I'm not confident it can be done with a single regex expression. However, this should get you by if no one can come up with one:
var matched;
do
{
matched = false;
data = data.replace(/(<[^>]+)( on\w+="[^"]*")+/g,
function(match, goodPart)
{
matched = true;
return goodPart;
});
} while(matched);
Edit:
I surrender at writing a single regex for this. There must be some way to check the context of a match without actually capturing the beginning of the tag in your match, but my RegEx-fu is not strong enough. This is the most elegant solution I'm going to come up with:
data = data.replace(/<[^>]+/g, function(match)
{
return match.replace(/ on\w+="[^"]*"/g, '');
});
Here's a pure JS way to do it:
function clean(html) {
function stripHTML(){
html = html.slice(0, strip) + html.slice(j);
j = strip;
strip = false;
}
function isValidTagChar(str) {
return str.match(/[a-z?\\\/!]/i);
}
var strip = false; //keeps track of index to strip from
var lastQuote = false; //keeps track of whether or not we're inside quotes and what type of quotes
for(var i=0; i<html.length; i++){
if(html[i] === "<" && html[i+1] && isValidTagChar(html[i+1])) {
i++;
//Enter element
for(var j=i; j<html.length; j++){
if(!lastQuote && html[j] === ">"){
if(strip) {
stripHTML();
}
i = j;
break;
}
if(lastQuote === html[j]){
lastQuote = false;
continue;
}
if(!lastQuote && html[j-1] === "=" && (html[j] === "'" || html[j] === '"')){
lastQuote = html[j];
}
//Find on statements
if(!lastQuote && html[j-2] === " " && html[j-1] === "o" && html[j] === "n"){
strip = j-2;
}
if(strip && html[j] === " " && !lastQuote){
stripHTML();
}
}
}
}
return html;
}
Related
I'm no professional and after research, I wasn't able to find a solution.
I have a JavaScript source code for a SharePoint list to implement the InstantListFilter (https://archive.codeplex.com/?p=instantlistfilter) which works!
But I would like to update the source code so that the filter is NOT case sensitive. I was able to replace the the filter word (val) to uppercase (val = val.toUpperCase()). But I have no idea how to get the list-text to uppercase.
$("table.ms-listviewtable").children("tbody").each(function() {
$(this).children("tr").each(function() {
var mismatch = false;
$(this).children("td").each(function(colIndex) {
if (mismatch) return;
if (filterValues[colIndex]) {
var val = filterValues[colIndex];
// replace double quote character with 2 instances of itself
val = val.replace(/"/g, String.fromCharCode(34) + String.fromCharCode(34));
val = val.toUpperCase(); //my adaption, working for the filter word
$(this).val = $(this).val().toUpperCase(); //not working for the list-text
// verifies the filter word.
if ($(this).is(":not(:contains('" + val + "'))")) {
mismatch = true;
}
}
});
if (mismatch) {
$(this).hide();
} else {
$(this).show();
}
});
});
Does anybody have a solution?
Would be happy with a short reply!
The solution you are trying will also modify the input value to upper case, i'm not sure you want that? Maybe you could assign the input value to a var and see if it contains the text with String.indexOf()
...
val = val.toUpperCase(); //my adaption, working for the filter word
var inputVal = $(this).val().toUpperCase();
// indexOf = -1 means that inputVal does not contain val
if (inputVal.indexOf(val) === -1) {
mismatch = true;
}
...
thanks for reply!!!
I got it:
var inputVal = $(this).text().toUpperCase();
//alert(inputVal);
// verifies the filter word.
// indexOf = -1 means that inputVal does not contain val
if (inputVal.indexOf(val.toUpperCase()) === -1) {
mismatch = true;
}
I want to extract text out of an arbitrary block of HTML. Naive attempt:
$('<div><p>Some</p>Inner<div>Text</div></div>').text()
This gives SomeInnerText, but I want Some Inner Text
What is a better way to extract text out of HTML, while maintaining some concept of the visual structure with which the HTML would be rendered?
In the example above, new lines between block elements would be great & spaces could be a sort of "flattened" output.
Use a regular expression to inject spaces before closing tags:
$('<div><p>Some</p>Inner<div>Text</div></div>'.replace(/</g, ' <')).text();
Fiddle: http://jsfiddle.net/mattdlockyer/uau6S/
You can insert ' ' into your script:
$('<div><p>Some </p>Inner <div>Text</div></div>').text();
Well, you can extend jQuery to do that:
$.fn.textRespectingBlocks = function() {
return this.map(function() {
var $this = $(this);
var display = $this.css('display');
var isBlock = display !== 'none' && display !== 'inline' && display !== 'inline-block' && display !== 'inline-flex' && display !== 'inline-table';
var childText = Array.prototype.map.call(this.childNodes, function(node) {
if (node.nodeType === 1) {
return $(node).textRespectingBlocks();
}
if (node.nodeType === 3) {
return node.nodeValue;
}
return '';
}).join('');
return isBlock ? ' ' + childText + ' ' : childText;
}).get().join('');
};
Do a .replace(/^\s+|\s+$|\s(?=\s)/g, '') on the result, if you like.
Simply adding the spaces yourself will do the trick. However, due to the variations in the way that html is parsed by different browsers, this may result in variations of white space across browsers.
$('<div> <p>Some</p> Inner <div>Text</div></div>').text()
I'm using js to read an xml file elements and replace some nodes name with another by replacing part of the string, but when running my app nothing happening, that's my code:
$('#dummy').load('cafe.xml',function() {
initialize();
})
function initialize(){
ct=$('menu').children().length;
for(cati==0;cati<=ct-1;cati++)
{
cats[cati]=$('menu').children().eq(cati).prop('nodeName');
// modifing the whitespaces and special characters
var realname = cats[cati];
if(realname.indexOf(".") != -1){
realname.replace(/\./g,' ');
}
if(realname.indexOf("1") != -1){
realname.replace(/\1/g,'\'');
}
if(realname.indexOf("2") != -1){
realname.replace(/\2/g,'&');
}
if(realname.indexOf(":") != -1){
realname.replace(/\:/g,'(');
}
if(realname.indexOf("!") != -1){
realname.replace(/\!/g,')');
}
if(realname.indexOf("0") != -1){
realname.replace(/\0/g,'/');
}
}
replace doesn't change the original string. Try with something like
realname = realname.replace(/.../g, "...");
Anyway, I'd ditch all those if, that are kind of useless given what you're doing.
I'm creating a DSL based on JSON and JavaScript and I have a requirement to let key values be specified 'raw' and not enclosed in string delimiters. A quick example that hopefully explains this:
{myKey:custom_function('arg1'), myKey2:custom_function("another arg1")}
should become
{myKey:"custom_function('arg1')", myKey2:"custom_function(\"another arg1\")"}
This is because at the time of parsing the JSON object, custom_function will not exist. I need to be able to parse the JSON without evaluating any of the values, then only expand values one by one as I iterate the keys.
What regular expression or other method can I use to turn that 1st snippet into the 2nd one?
I'm assuming a simpler solution will cover 90% of cases but that writing a bullet-proof implementation would take a lot of effort. Based on the research I did into JavaScript's regular expression support (apparantly no lookbehind capability) I'm assuming it will require something more than just 1 or 2 lines of regex patterns.
Also, this is for a node application so any tricks that it has for this will be helpful too.
EDIT:
This question seems to be getting some downvotes, but I've left it up anyway for the benefit of future googlers / my own reference. It's a perfectly valid question about what method / technique would work best for this kind of problem, and there could easily be other node/js newcomers who face a similar problem.
Final answer: Regex just isn't suited to a task as complex as this. Any similarly complex solutions I found online (e.g. removing code comments) all resorted to a mainly custom, iterative approach, only using regex sparingly, so a similar approach ended up being not too painless in this situation.
So in the end the 'best' method I could find didn't involve very much regex or any specialized libraries from node or elsewhere suited to the problem.
Finally, for the benefit of future googlers who might have a similar problem, I've published my solution at https://gist.github.com/2590689 and copied below:
//clothe a hub file that has 'naked' expressions
//e.g. turn {key:$('body p')} into {key:"$('body p')"}
function clothe(contents){
closers = /[\}\]\)\/"']/
openers = /[\{\[\(\/"']/
closing = {
"{": "}",
"[": "]",
"(": ")",
"/": "/",
'"': '"',
"'": "'"
}
contents = contents.split("");
var beforeKey = true;
var inKey = false;
var beforeValue = false;
var inValue = false;
var inArray = false;
var delimiterStack = [];
function inDelimited(){
return delimiterStack.length > 0;
}
function toggleDelimiter(d){
if(openers.exec(d) && !closers.exec(d)){
pushDelimiter(d);
}else if(openers.exec(d) && closers.exec(d)){
if(topDelimiter()){
if(topDelimiter()==d){
popDelimiterIfValid(d);
}else{
pushDelimiter(d);
}
}else{
pushDelimiter(d);
}
}else if(closers.exec(d)){
popDelimiterIfValid(d);
}
}
function topDelimiter(){
if(delimiterStack.length>=0){
return delimiterStack[delimiterStack.length-1];
}else{
return undefined;
}
}
function pushDelimiter(d){
delimiterStack.push(d);
}
function popDelimiterIfValid(d){
if(delimiterStack.length>0)
if(closing[delimiterStack[delimiterStack.length-1]]==d)
delimiterStack.pop(d);
}
function rTrimmedRightBound(rightBound){
while(rightBound>0){
if(!/\s/g.exec(contents[--rightBound])){
return rightBound+1;
}
}
}
for(var i=0; i<contents.length; i++){
function delimiterCheck(c){
if(c=='"'){
toggleDelimiter('"');
contents.splice(i, 0, '\\');
i++;
}else if(openers.exec(c) || closers.exec(c)){
toggleDelimiter(c)
}
}
if(beforeKey){
if(/[a-zA-Z0-9$_!]/.exec(contents[i])){
beforeKey = false;
inKey = true;
}
}else if(inKey){
if(contents[i]==":"){
inKey = false;
beforeValue = true;
}
}else if(beforeValue){
if(/[a-zA-Z0-9$_!'"\(\/]/.exec(contents[i])){
contents.splice(i, 0, '"');
i++;
beforeValue = false;
inValue = true;
delimiterCheck(contents[i]);
}else if(/\{/.exec(contents[i])){
beforeKey = true;
beforeValue = false;
}else if(/\[/.exec(contents[i])){
beforeValue = false;
inArray = true;
}
}else if(inArray && !inValue){
if(/[a-zA-Z0-9$_!'"\(\/]/.exec(contents[i])){
contents.splice(i, 0, '"');
i++;
beforeValue = false;
inValue = true;
delimiterCheck(contents[i]);
}
}else if(inValue){
if(!inDelimited() && /[\},\]]/.exec(contents[i])){
contents.splice(rTrimmedRightBound(i), 0, '"');
i++;
inValue = false;
if(/\]/.exec(contents[i])){
inArray = false;
}
beforeKey = !inArray;
}else{
delimiterCheck(contents[i]);
}
}
}
return contents.join("");
}
Is there a way to make this code more simplified?
<input type="text" id="tags" />
var splittext = document.getElementById('tags').value.split(' ');
if (document.getElementById('tags').value.split(' ').length < 2 || splittext[1] == '') {
alert("Two tags required.");
}
is there another way to make
splittext[1] == ''
be like
document.getElementById('tags').value.split(' ').something[1]
to avoid using the line
var splittext = document.getElementById('tags').value.split(' ')
The purpose of this is when a user inputs one tag and made a space after it, the split detects 2 values which i would like to avoid the space being counted as another tag because that would be like, uhm, cheating.
Trim first, and split on any number of white space characters:
if (document.getElementById('tags').value.trim( ).split(/\s+/).length < 2) {
alert("Two tags required.");
}
You will need to create the String.trim function if you want to support some versions of IE though... but it's a useful function to have. Put this in a utility js file, or just at the top of your js:
if(typeof String.prototype.trim !== 'function') {
String.prototype.trim = function() {
return this.replace(/^\s+|\s+$/g, '');
}
}
You should change your code to this to avoid making multiple calls to the same dom element(you are splitting the same thing twice)
var splittext = document.getElementById('tags').value.split(' ');
if (splittext.length < 2 || splittext[1] == '') {
alert("Two tags required.");
}
This is the whole point of using variables, to avoid calling the same function(with the same results) multiple times.
Something like this should do the trick:
var elem=document.getElementById('tags').value;
if(elem.indexOf(' ')>-1 && elem.split(' ').length>=2) {
alert('Worked!');
} else if(!elem || elem.indexOf(' ')<0) {
alert('Two tags required.');
}
yeah :
var g= document.getElementById('tags').value.split(/[ ]+/)
if (g.length==2) // ok.....
http://jsbin.com/ovibef/edit#javascript,html