Regular expression to convert html class to attribute - javascript

Is there any way to use regular expression alone or with help of javascript to do the following
from
<div class="type-c red blue">
to
<div type="c" class="red blue">

This isn't the solution. Just offers some insights on text parsing this problem without regex. As the OP did mention a possible non-regex solution. Also this answer was posted during a very long comment session, and as such requirements changed.
This solution (in like fashion of #DakotaMethvin's) also attempts to solve it without regex, and as well, resides on a more exact pattern match with class="type-. As such the following code will indeed break (logically) if that's not the match.
However in light of FanCheung's more recent comment [type-x] not always the first class entry, I'm only posting this answer because I already started on posting it.
function replaceIt( s, sentinel ) {
// sentinel: e.g. class="type-
if (sentinel) {
}
else sentinel = 'class="type-';
return s.replaceAll(sentinel , function( match, offset ) {
// get the position of the whitespace after "type-c"
nextSpace = s.indexOf(" ", offset);
// extract the "type" up until and excluding the "next space"
typeVar = s.substring( offset + sentinel.length, nextSpace);
// get the position of the 2nd double quote char
nextDoubleQuote = s.indexOf("\"", nextSpace);
// extract the new "class" names e.g. red blue
newClass = s.substring( nextSpace + 1, nextDoubleQuote);
// create the replacement string. Also something must be done with the leftover chars; prepend them with 'data-source'.
replacement = 'type="' + typeVar + '" class="' + newClass +'" data-source="';
// debugging code
console.log( match + ": " + offset + ": " + typeVar + ": " + newClass);
return replacement;
});
}
console.log( replaceIt( '<div class="type-c red blue">') );
But as noted on recent developments on what I noted on The entire before "class" string will have to be tokenized. So this solution only works if "type-" is the 1st class.

You don't even need regular expressions.
(Okay, you do, but only to find the x value in type-x. Proof here.)
You can use a mix of attribute selectors, the data-* attribute standard, and the Element.setAttribute() method.
Here's an example.
function doChange() {
// Find all divs with a 'type-x' class
let myDivs = document.querySelectorAll('div[class*="type-"]');
myDivs.forEach(curDiv => {
// Get the specific 'x' for the type
let curType = /(?<=type-)[A-Za-z\-]+/.exec(curDiv.classList.toString())[0];
// Set the 'data-type' attribute
curDiv.setAttribute('data-type', curType);
// Remove the 'type-x' class
curDiv.classList.toggle('type-' + curType);
// Write the 'classList' and 'data-type' attributes for show
curDiv.innerText = 'classList: ' + curDiv.classList
+ '; data-type: ' + curDiv.getAttribute('data-type') + ';';
});
}
<div class="type-a red blue">classList: type-a red blue; data-type: undefined;</div>
<div class="red type-b blue">classList: red type-b blue; data-type: undefined;</div>
<div class="red blue type-c">classList: red blue type-c; data-type: undefined;</div>
<button onclick="doChange()">Click Me</button>

This regular expression will match what you describe, regardless of the position of "type-xxx" in class attribute
/class="([^"]*)type-(\w+)([^"]*)"/g
Combining with a string replace
let value = '<div class="type-a b">test</div><div class="a type-b">test 2</div>';
value.replace(/class="([^"]*)type-(\w+)([^"]*)"/g, 'type="$2" class="$1$3"');
this will yield the result
<div type="a" class="b">test</div><div type="b" class="a">test 2</div>

Related

Converting HTML to JavaScript string in PhpStorm

I'd like to convert some html easily into concatenated JS strings in PhpStorm.
From:
<div class="spa-shell-head">
<div class="spa-shell-head-logo"></div>
<div class="spa-shell-head-acct"></div>
<div class="spa-shell-head-search"></div>
</div>
To:
var main_html = ''
+ '<div class="spa-shell-head">'
+ ' <div class="spa-shell-head-logo"></div>'
+ ' <div class="spa-shell-head-acct"></div>'
+ ' <div class="spa-shell-head-search"></div>'
+ '</div>';
Ideally into the other direction as well. Is there any chance to achieve this? With a plugin? I could imagine that a macro with some regex could do it. Is it possbile?
Same question for other IDE can be found here. Or here.
Using only PHPStorm, you can use the Extra Actions plugin:
Select all your lines
Split the selection into lines (ctrl + shift + L)
Go to the beginning of the line (home)
Add a plus sign and a quote
Go to the end of the line (end)
Add a quote
Rather than converting HTML to a JS string, you should really create your elements in JS and then insert them into the DOM. This would give you much more control, not create such a difficult to maintain/read code, cause less problems, and be much faster to boot:
var outerDiv = document.createElement("div"); // Create a div
outerDiv.className = "spa-shell-head"; // Give it a class
var innerDivLogo = document.createElement("div");
innerDivLogo.className = "spa-shell-head-logo";
var innerDivAcct = document.createElement("div");
innerDivAcct.className = "spa-shell-head-acct";
var innerDivSearch = document.createElement("div");
innerDivSearch.className = "spa-shell-head-search";
outerDiv.appendChild(innerDivLogo); // Append into original div
outerDiv.appendChild(innerDivAcct);
outerDiv.appendChild(innerDivSearch);
document.body.appendChild(outerDiv); // Add to page
The above creates the following:
https://jsfiddle.net/yfeLbhe4/

Refering to a HTML ID with mutliple variables

So, I am trying to create a game with blocks in the level being send from the server.
I have loop cycling through the blocks each time it recieves an update from the server. It will then if the block is solid, append the block to the html document if it is not already existing.
if(blocks[blockCount].solid === true){
if($("#" + blocks[blockCount].posX.toString() + "," + blocks[blockCount].posY.toString()).length > 0){
alert("Block already exists");
}else{
$("body").append("<div style='height: " + blockSize + "px;width: " + blockSize + "px;background-color: blue;position: absolute;display: inline;margin-left: " + blocks[blockCount].posX * blockSize + "px;margin-top: " + blocks[blockCount].posY * blockSize + "px;' id='" + blocks[blockCount].posX.toString() + "," + blocks[blockCount].posY.toString() + "'> </div>");
}
}
blocks[blockCount].posX and Y should both equal to 4. But for some reason they keep being created, the if statement does for some reason not work. Can you please explain me why? or post the correct code. Thanks a lot for your help. :)
I learned here: How to check if element exists in the visible DOM?
that the jquery .length would allow me to see if the element already existed.
You can't have a , in an ID (or class for that matter) [see comment, you can, but why make life hard for yourself] - because a , is used as a separator in CSS .. i.e
#id1,div would select an element with id="id1" AND any div
you're creating elements with id's like "123,456" - which as a CSS selector would be #123,456
solution: try using _ instead of ,
also, I'm not sure if an id is allowed to begin with numbers, but don't quite me on that, if not, just prepend your id's with x or whatever
note: the HTML5 spec allows ID's to begin with numbers, however, that too does not work in CSS selectors (for CSS at least, not tested with jQuery or querySelector[All] )
you'll end up with id's like x123_456 - which is OK
Since , has a special meaning in CSS, you'd have to escape in in your selector. To write a CSS selector targeting an element with id="foo,bar", you have to write #foo\,bar. In jQuery selector allow you to do the same, but you need to remember about JS syntax and write $("#foo\\,bar") to achieve what you want (the first backslash is to escape the second one in JS string).
Also, as Jaromanda X pointed out, IDs can't start with numbers so you'll have to prepend it with a letter.
To sum up, your code may look like this:
if(blocks[blockCount].solid === true){
if($("#x" + blocks[blockCount].posX.toString() + "\\," + blocks[blockCount].posY.toString()).length > 0){
alert("Block already exists");
} else {
$("body").append("<div style='height: " + blockSize + "px;width: " + blockSize + "px;background-color: blue;position: absolute;display: inline;margin-left: " + blocks[blockCount].posX * blockSize + "px;margin-top: " + blocks[blockCount].posY * blockSize + "px;' id='x" + blocks[blockCount].posX.toString() + "," + blocks[blockCount].posY.toString() + "'> </div>");
}
}

Regex dont find if inside element?

I think I need a regular expression (javascript) that can only find a string if it is NOT inside an element. IE if I wanted to find the string "Hello" but not in the div "popup"
<div class="popup">optional content Hello world and more</div>
--No Match--
<div>This is more content Hello and welcome</div>
--Match--
Can someone point me in right direction, negative lookahead?
ok should mention how im getting it :) The find already has a reg ex to "hopefully" ignore searching inside html tags but this needs to work on top of it.
var find = "((?![^<]*>) " + data[i].GlossaryWord.trim() + " )";
var replace = " <a class=\"gobig tooltip\" " + "title=\"" + data[i].GlossaryDescription + "\">" + data[i].GlossaryWord.trim().toLowerCase() + "</a> ";
var elementContent = elementContent.replace(new RegExp(find, 'gi'), replace);
Maybe easier to use CSS selectors. Something like:
document.body.querySelectorAll('div:not(.classy)')

Dynamically changing innerText's start without eval()

I have some code (several batches) that look like this:
1 <div id="backgrounds" class="centery">Backgrounds
2 <div id="bk1" class="attr">Background 1
3 <div class="container">
4 <!-- Lots more HTML here /-->
5 </div>
6 </div>
7 </div>
I have a JS function I wrote (changefirstCharacters) that will return the script to change line 2 to read:
2 <div id="bk1" class="attr">Some text I specify
But because I want this to only execute when an event listener fires, it only outputs the code, rather than evaluating it. As a result, my event listener contains a line like this:
eval(changeFirstCharacters('bk1', "'" + document.getElementById('background1').value + "'"));
Where background1 is a select box.
How can I re-write changeFirstCharacters to not need eval, but still work only when called?
changeFirstCharacters() code
function changeFirstCharacters(id, newText) {
return 'document.getElementById(\"' + id + '\").innerHTML = ' + newText + ' \+ document.getElementById(\"' + id + '\").innerHTML.substr(' + document.getElementById(id).innerText.length + ', document.getElementById(\"' + id + '\").innerHTML.length \-' + document.getElementById(id).innerText.length + ')';
}
I don't see what's so dynamic about that statement. The only reason we need eval is when code is dynamically generated, but neither newText nor id changes the produced code. Therefore, the following ought to work:
document.getElementById(id).innerHTML = newText +
document.getElementById(id).innerHTML.substr(document.getElementById(id).innerText.length,
document.getElementById(id).innerHTML.length - document.getElementById(id).innerText.length);
Called by (without adding quotes around the second argument):
changeFirstCharacters('bk1', document.getElementById('background1').value)
Also that first code calls getElementById(id) five times, which is not only a performance hit, it's rather ugly. You might want to rewrite it as:
var el = document.getElementById(id);
el.innerHTML = newText + el.innerHTML.substr(el.innerText.length,
el.innerHTML.length - el.innerText.length);

check if a string in the address bar matches an li id

I need to check if my address has any words that matches word in my li id:
<ul>
<li id="filter-myId" class="noSelected">Text</li>
</ul>
url address example to check:
http://www_link.com/D=.myId
But on the window address bar it'd only display "myId" without "filter-", so I guess I need to check if whatever is after "filter-" matches a string which appears on the windows address. If so, the li would get a class "selected"
Help?
I'd suggest, though currently untested, something along the lines of:
var string = document.location.href.split('=')[1];
if ($('li[id*="' + string + '"]').length){
$('li[id*="' + string + '"]').addClass('selected');
}
To restrict the search to those li elements that have the filter- prefix:
var string = document.location.href.split('=')[1];
if ($('li[id^="filter-"][id*="' + string + '"]').length){
$('li[id^="filter-"][id*="' + string + '"]').addClass('selected');
}
References:
Attribute-contains ([attribute*="value"]) selector.
Attribute-starts-with ([attribute^="value"]) selector.
You'll need to parse the URL somehow. I'm leaving that part out, but assuming it is placed in an object called url.
Javascript
if (elem = document.getElementById('filter-' + url['D'])) {
// exists
elem.className += ' selected';
}
jQuery
elem = $('#filter-' + url['D']);
if (elem.length) {
// exists
elem.addClass('selected');
}

Categories

Resources