Skip to content

Instantly share code, notes, and snippets.

@subzey
Forked from 140bytes/LICENSE.txt
Created July 28, 2011 13:30
Show Gist options
  • Star 3 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save subzey/1111550 to your computer and use it in GitHub Desktop.
Save subzey/1111550 to your computer and use it in GitHub Desktop.
removeClassRegexp

removeClassRegexp

Function removes css class names from element class attribute.

Supports regexp as a class name (thing I wait from jQuery for years).

Preserves order, leaves no duplicate or trailing spaces in className.

Regexp-related info

Regexp should be matched fully, not partially.

/foo-.*/ will match 'foo-bar' in 'foo-bar baz'

/foo-/ will not.

^ and $ means start and end of class name chunk, not of the whole className string

i (case-independent) modifier search is supported

m (multiline) modifier has no meaning

g (global) modifier is ignored: all search behaves as global

Usage

removeClass(o, c)

o required object whose className is changed

c required class name: regexp or string (or anything that coerces to string, excepting null and undefined)

Returns: nothing

function(
a, /* (DOM element) object */
b, /* (string | regexp) class name */
c, /* - placeholder */
d, /* - placeholder */
e /* - placeholder */
){
/* For each class chunk: */
for (
/* First, create new RegExp: any amount of anything except whitespaces */
c = /\S+/g
;
/* then get className chunks from the className until exec() is exhausted and returns null */
/* Thanks to @tsaniel for getting rid of array and saving a lot of extra bytes! */
d = c.exec(a.className)
;
/* {{ empty counting expression }} */
)
d == (
/* If b is regexp ... */
/* (bypass: if b is undefined, TypeError is raised here) */
b.exec ?
/* ... apply this regexp to class name chunk, */
/* test if is an array (not null), */
/* and get the 0th item (whole captured string) */
/* Thanks to @atk for great reduce and speed-up hint! */
(b.exec(d)||0)[0]
/* pass this string to comparsion. */
:
/* If b is not regexp, just pass it to comparsion as is */
b
)
/* So we have compared the class name chunk and a mask. If regexp is matched not fully, this comparsion will fail */
/* If string or regexp matches ... */
?
/* Do nothing, this class chunk must be removed */
0
:
/* Else we need to append it to the resulting string */
e = e ? /* If e is "truthy", that is, not empty string and not undefined... */
/* append d to e */
e + ' ' + d
/* e is "" or undefined ? */
:
/* let just `e` be `d` */
d
;
/* {{ end of for loop }} */
/* Finally, assign a new value to className */
/* Assigning to property will trigger .toString() on array */
/* If `e` is undefined, `[e]` returns an empty string */
a.className = [e];
}
function(a,b,c,d,e){for(c=/\S+/g;d=c.exec(a.className);)d==(b.exec?(b.exec(d)||0)[0]:b)?0:e=e?e+' '+d:d;a.className=[e]}
DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
Version 2, December 2004
Copyright (C) 2011 subzey <subzey@immelman.ru>
Everyone is permitted to copy and distribute verbatim or modified
copies of this license document, and changing it is allowed as long
as the name is changed.
DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
0. You just DO WHAT THE FUCK YOU WANT TO.
{
"name": "removeClassRegexp",
"description": "Regular expression capable removeClass",
"keywords": [
"removeClass",
"remove",
"class",
"regexp"
]
}
<!DOCTYPE html>
<title>removeClass</title>
<div>Expected value: <pre><b>foo bar foo-1 foo-bar 42</b><br /><b>bar baz foo-bar 42</b><br /><b>foo bar baz foo-1 foo-bar</b></pre></div>
<div>Actual value: <pre><b id="ret"></b><br /><b id="ret2"></b><br /><b id="ret3"></b></pre></div>
<script>
var removeClass = function(a,b,c,d,e){for(c=/\S+/g;d=c.exec(a.className);)d==(b.exec?(b.exec(d)||0)[0]:b)?0:e=e?e+' '+d:d;a.className=[e]}
var testElement = document.createElement("div");
var testClassName = " foo \t bar baz foo-1 foo-bar 42 "; /* dirty class string :) */
testElement.className = testClassName;
/* remove class named 'baz', just all the removeClass functions does */
removeClass(testElement, 'baz')
document.getElementById("ret").innerHTML = testElement.className
testElement.className = testClassName;
/* remove all classes matches to regexp */
/* (strips 'foo' and 'foo-1', but leaves 'foo-bar' ) */
removeClass(testElement, /foo(-\d+)?/)
document.getElementById("ret2").innerHTML = testElement.className
testElement.className = testClassName;
/* coercion test */
removeClass(testElement, 42)
document.getElementById("ret3").innerHTML = testElement.className
</script>
@atk
Copy link

atk commented Jul 28, 2011

Why arrays? You can stay on string level (and still save a few bytes):

function(o,c){o.className=o.className.replace(/(\S+)\s*/g,function(f,x){return((c.exec?(c.exec(x)||0)[0]:c)==x)?'':f})}

@subzey
Copy link
Author

subzey commented Jul 28, 2011

@atk, very nice (null||0)[0] trick! Once again you suggest a great technique.

I suppose, I'll keep array: I don't think it will be easy to "normalize" spaces using .replace "eat piece-process-return". And I want to do so, as jQ's addClass does.

@subzey
Copy link
Author

subzey commented Jul 28, 2011

  • removeClass, not addClass, of course.

@atk
Copy link

atk commented Jul 28, 2011

there are two ways to do this: 1. select additional spaces and replace not with f, but with x+' ' (+trim) or 2. use a new string (written off-hand, not tested):

function(o,c,r){r='';o.className=o.className.replace(/\S+/g,function(x){(c.exec?(c.exec(x)||0)[0]:c)==x||(r+=x+' ')}),r.trim()}

@subzey
Copy link
Author

subzey commented Jul 29, 2011

@atk, it works incorrectly: var foo; foo = 42, 34; foo // 42, not 34. Also, it relies on String.prototype.trim not defined by ECMA 262-3.
Fixed and shortened: function(o,c,r){r='';o.className.replace(/\S+/g,function(x){(c.exec?(c.exec(x)||0)[0]:c)==x||(r+=(r&&' ')+x)});o.className=r}

Also, I tested both versions in node.js. Array-based one is ≈15% faster (varies). I suppose, this happens because of function call overhead.

@tsaniel
Copy link

tsaniel commented Jan 21, 2012

What about this? Save 18 bytes and maybe a little bit slower?
function(a,b,c,d,e){for(c=/\S+/g;d=c.exec(a.className);)d==(b.exec?(b.exec(d)||0)[0]:b)?0:e=e?e+' '+d:d;a.className=[e]}

@subzey
Copy link
Author

subzey commented Jan 23, 2012

@tsaniel, that's a great minification!

Curious fact is that one may also add class using e argument, not only remove. But let it be an undocumented feature.

@tsaniel
Copy link

tsaniel commented Jan 23, 2012

Interesting fact, I've never considered that. But you're right, let it be an undocumented feature.
For convenience, we may exchange their position:
function(a,b,e,d,c){for(c=/\S+/g;d=c.exec(a.className);)d==(b.exec?(b.exec(d)||0)[0]:b)?0:e=e?e+' '+d:d;a.className=[e]}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment