remove CSS all classes from element except one

384 views
Skip to first unread message

cbolson

unread,
Feb 13, 2010, 11:19:40 AM2/13/10
to MooTools Users
Hi,
Can anyone suggest how I can remove all the css classes from an array
of elements except for one specific one (if it is set)?
I guess I could use erase('class') and then add the base class back in
however not all the elements have the base class.
Alternatively there is removeClass(_class name_) but the problem there
is that I don't know what classes the elements might have so I can't
get them by name. (Note - I DO know the name of the base class that
must not be removed)

I have set up a mooshell test here but to be honest it contains little
code as I haven't got a semi-solution to show:
http://mootools.net/shell/w4fc5/

Thanks as always for any suggstions or solutions :)

Chris

Sanford Whiteman

unread,
Feb 13, 2010, 12:10:16 PM2/13/10
to cbolson

cbolson

unread,
Feb 13, 2010, 12:27:20 PM2/13/10
to MooTools Users
Thanks for that :)
I am actually using something along those lines I was just hoping that
there might be a "cleverer" way to do it (ie not remove then add
again) :)

Chris

On 13 feb, 18:10, Sanford Whiteman <sa...@cypressintegrated.com>
wrote:
> http://mootools.net/shell/w4fc5/1/
>
> -- S.

ken

unread,
Feb 14, 2010, 2:55:16 AM2/14/10
to MooTools Users

Sanford Whiteman

unread,
Feb 14, 2010, 4:04:46 PM2/14/10
to ken
> the mootools way

You forgot the "don't add base_class if it wasn't originally there"
part of the spec.

Anyway, this way is just a function around the same basic logic... not
really reaching the "cleverer" mark. :)

-- S.

Dimitar Christoff

unread,
Feb 14, 2010, 5:32:10 PM2/14/10
to mootool...@googlegroups.com
> Anyway, this way is just a function around the same basic logic... not
> really reaching the "cleverer" mark. :)

the 'clever' i could think of without involving garden gnomes was this:

Element.implement({
removeClassesExcept: function(klass) {
return this.hasClass(klass) ? this.set("class", klass) : this.erase("class");
}
});

http://mootools.net/shell/Wpqum/1/ - tested in FF 2.5 and IE7. back to
gardening now...

regards,
--
Dimitar Christoff <chri...@gmail.com> - http://fragged.org/

Roman Land

unread,
Feb 14, 2010, 6:09:15 PM2/14/10
to mootool...@googlegroups.com
(mooshell is down)

how about this over engineered solution:


var leaveOnlyThisClass = function(el, cl){
    el.set('class', el.get('class').split(' ').filter(function(c){return c == this },cl)[0]);
};

usage:
leaveOnlyThisClass($('divid'),'leave-only-me');
--
---
"Make everything as simple as possible, but not simpler."

- Albert Einstein

hazlema

unread,
Feb 15, 2010, 1:08:32 PM2/15/10
to MooTools Users
Yes, But the question was from an array of controls:

http://mootools.net/shell/hv3Yv/

Array.implement({
removeClassesExcept: function(klass) {
this.map(function(ele, ndx) {
return ele.hasClass(klass) ? ele.set("class", klass) :
ele.erase("class");
});
}
});

On Feb 14, 6:09 pm, Roman Land <roman.l...@gmail.com> wrote:
> (mooshell is down)
>
> how about this over engineered solution:
>
> var leaveOnlyThisClass = function(el, cl){
>     el.set('class', el.get('class').split(' ').filter(function(c){return c
> == this },cl)[0]);
>
> };
>
> usage:
> leaveOnlyThisClass($('divid'),'leave-only-me');
>

> On Mon, Feb 15, 2010 at 12:32 AM, Dimitar Christoff <christ...@gmail.com>wrote:
>
>
>
> > > Anyway, this way is just a function around the same basic logic... not
> > > really reaching the "cleverer" mark. :)
>
> > the 'clever' i could think of  without involving garden gnomes was this:
>
> > Element.implement({
> >    removeClassesExcept: function(klass) {
> >        return this.hasClass(klass) ? this.set("class", klass) :
> > this.erase("class");
> >    }
> > });
>

> >http://mootools.net/shell/Wpqum/1/- tested in FF 2.5 and IE7. back to
> > gardening now...
>
> > regards,
> > --
> > Dimitar Christoff <christ...@gmail.com> -http://fragged.org/

Sanford Whiteman

unread,
Feb 15, 2010, 1:55:06 PM2/15/10
to hazlema
> Yes, But the question was from an array of controls:

When you implement on Element, you automatically implement on Elements
arrays. There is no need to implement on the generic Array.

Element.implement({
removeClassesExcept: function(klass) {
...
}
});

$('remove').addEvent('click', function() {
$$('li').removeClassesExcept('base_class'); // works
});

-- S.

Roman Land

unread,
Feb 15, 2010, 2:03:27 PM2/15/10
to mootool...@googlegroups.com
Or with my version:

Element.Implement({
     'removeClassesExcept': function(baseClass){
          this.set('class', this.get('class').split(' ').filter(function(c){return c == this },baseClass)[0]);
     }
})

Sanford Whiteman

unread,
Feb 19, 2010, 4:42:22 PM2/19/10
to cbolson
Hey Chris,

I was just looking at this thread again and wondered what the
particulars were that necessitated a JS solution for this. Depending
on the environment, could the "clever" solution have been CSS-only?

http://mootools.net/shell/XdL9T/6/

Not saying this would apply, but I'm wondering what would make it an
inapplicable approach. All other things being equal, CSS would be my
first take.

-- S.

cbolson

unread,
Feb 20, 2010, 3:59:46 AM2/20/10
to MooTools Users
Hi,
The reason is that the classes are added via javascript (mootools)
according to user actions.
In basic terms this is used on a large list of <li> (delegation is
used ;) ) some of which can be clicked and others not (they are
dates).
The "clickable" dates always need to remain clickable but, as the user
clicks them classes are added/removed according to what is being done.
The class "clickable" doesn't actually have any styling at all (the
other classes that need to be removed do)

The problem is that the "classes" that are being added are not within
the codes control so there is no way (I imagine that they could be
stored in someway as they are added but this may be more complicated
that is actually needed).
So, the problem is that the "clickable" class must always be applied
and the code should just remove the other classes.

In the end I stayed with the simple
"el.erase('class').addClass('base_class')" code, I was just hoping
that there would be some hidden mootools function something like this:
removeClasses('!=clickable')
The suggestions made here in this thread are basically this.

Thanks for thinking about it :)

Chris

On 19 feb, 22:42, Sanford Whiteman <sa...@cypressintegrated.com>
wrote:

Sanford Whiteman

unread,
Feb 20, 2010, 7:40:53 PM2/20/10
to cbolson
OK, how often are you going to be running the function that strips the
classes from a collection of els? How large is the usual collection?

-- Sandy


------------------------------------
Sanford Whiteman, Chief Technologist
Broadleaf Systems, a division of
Cypress Integrated Systems, Inc.
e-mail: sa...@cypressintegrated.com
------------------------------------

Yann Leretaille

unread,
Feb 20, 2010, 10:03:01 PM2/20/10
to mootool...@googlegroups.com
Why not use RegExp?

Element.implement({
    removeClassesExcept: function(klass) {
        return this.set("class",new RegExp(klass).exec(this.get("class")));
    }
});

If the RegExp /klass/ matches class, class is "klass", otherwise it's null.
Yann

Dimitar Christoff

unread,
Feb 21, 2010, 6:28:21 PM2/21/10
to mootool...@googlegroups.com
> Why not use RegExp?
>
speed. this will be slower.

Yann Leretaille

unread,
Feb 21, 2010, 8:45:06 PM2/21/10
to mootool...@googlegroups.com

On Mon, Feb 22, 2010 at 00:28, Dimitar Christoff <chri...@gmail.com> wrote:
> Why not use RegExp?
>
speed. this will be slower.

I'm not sure about this. hasClass require string-operation anyway and with RegExp, you can directly set the correct class without further comparing.
I made a small benchmark comparing different methods posted here:
  • Method1 (my method):
    • return this.set('class',new RegExp(klass).exec(this.get('class')));
  • Method2 (Roman):
    • return this.set('class', this.get('class').split(' ').filter(function(c){return c == this },klass)[0]);
  • Method3 (hazlema):
    •  return this.hasClass(klass) ? this.set("class", klass) : this.erase("class");
    Results (time per operation):
    • Method1: 0.000265s
    • Method2: 0.000297s
    • Method3: 0.000279s
    Looks like if my method is slightly faster...

    benchmark: http://mootools.net/shell/uDHj4/

    Yann

    Sanford Whiteman

    unread,
    Feb 22, 2010, 12:47:52 AM2/22/10
    to Yann Leretaille
    > - Method1: 0.000265s
    > - Method2: 0.000297s
    > - Method3: 0.000279s

    > Looks like if my method is slightly faster...

    Mmm, something is wrong with your benchmark.

    Comparing your regex

    [f1] t.set('class',new RegExp('base_class').exec(t.get('class')));

    with the straightforward

    [f2] t.hasClass('base_class') ? t.set('class','base_class') :
    t.erase('class');

    averaging over 10 runs of 1000 function calls each, the regex approach
    is markedly slower.

    [f1]:

    .016 when base_class is present on the element
    .012 when base_class is not present

    [f2]:

    .007 when base_class is present
    .004 when base_class is not present

    You can eke out more performance by compiling the RegEx, but the basic
    approach still beats it out significantly, 50-100% faster depending on
    whether the target class is present.

    [f1-compiled]:

    .011 when base_class is present on the element
    .008 when base_class is not present

    See http://mootools.net/shell/B8pPc/7/.

    - S.

    Dimitar Christoff

    unread,
    Feb 22, 2010, 10:20:03 AM2/22/10
    to mootool...@googlegroups.com
    even through your benchmark:

    time1: 0.000329
    time2: 0.00022600000000000002
    time3: 0.0001933333333333333

    i am using FF 3.5.8(?)

    even with advances in regex performance for webkit, hasClass uses
    contains which uses indexOf... indexOf > regex, at least for now.

    Yann Leretaille

    unread,
    Feb 22, 2010, 11:45:26 AM2/22/10
    to mootool...@googlegroups.com
    I understand your point. Actually, benchmarking seems particualry difficult for this one.
    I created a mooshell wich creates a list with 1000 Elements, wich have 0-3 classes, with or without base_class.
    The list ist cloned for each benchmark and i ran each methos is runned 10 times.
    Here are the results:

    • Method1 (my method):
      • return this.set('class',new RegExp(klass).exec(this.get('class')));
    • Method1a (my method, precompiled RegExp )
      • regexp=new RegExp(klass)
      • this.each(function(e) { e.set('class',regexp.exec(e.get('class'))) });
    • Method2 (Roman):
      • return this.set('class', this.get('class').split(' ').filter(function(c){return c == this },klass)[0]);
    • Method3 (hazlema):
      •  return this.hasClass(klass) ? this.set("class", klass) : this.erase("class");

    Results (1000 items):
    • time1:   0.0000340
    • time1a: 0.0000216
    • time2:   0.0000306
    • time3:   0.0000234
    It seems to depend on how much items you have what the fastet method is. The strange thing is that i tried it with 1,50,10,100,500,1000 items and now Method1a is always faster! Perhaps Firefox is caching the RegExp...

    http://mootools.net/shell/J7ySB/

    Yann

    Barry van Oudtshoorn

    unread,
    Feb 22, 2010, 7:37:35 PM2/22/10
    to mootool...@googlegroups.com
    This might be to do with TraceMonkey being en-/disabled on one of the
    testing machines... As far as I know, it's disabled by default in 64bit
    Linux, and perhaps in some other builds.

    Barry

    On 22/02/10 23:20, Dimitar Christoff wrote:
    > even through your benchmark:
    >
    > time1: 0.000329
    > time2: 0.00022600000000000002
    > time3: 0.0001933333333333333
    >
    > i am using FF 3.5.8(?)
    >
    > even with advances in regex performance for webkit, hasClass uses
    > contains which uses indexOf... indexOf> regex, at least for now.
    >


    --
    Not sent from my Apple πPhone.

    Sanford Whiteman

    unread,
    Feb 22, 2010, 8:13:32 PM2/22/10
    to Barry van Oudtshoorn
    > This might be to do with TraceMonkey being en-/disabled on one of the
    > testing machines... As far as I know, it's disabled by default in 64bit
    > Linux, and perhaps in some other builds.

    A promising idea, but I just tested on 3.5.7 with TM off and TM on and
    the non-regex fn cleanly beats out both compiled and uncompiled
    regexes -- regardless of whether JIT is enabled.

    -- S.

    Yann Leretaille

    unread,
    Feb 23, 2010, 10:08:40 AM2/23/10
    to mootool...@googlegroups.com
    could somebody test this one with 100,100 & 10 Elements?

    My results:
    n
    FF 3.6, Linux, 64Bit FF 2.5.8,WinXP, 32Bit
    1000
    time1::: 0.000033
    time1a: 0.000020
    time2::: 0.000030
    time3::: 0.000024
    time1::: 0.000055
    time1a: 0.000036
    time2::: 0.000048
    time3::: 0.000038
    100
    time1::: 0.000045
    time1a: 0.000027
    time2::: 0.000040
    time3::: 0.000032
    time1::: 0.000058
    time1a: 0.000037
    time2::: 0.000051
    time3::: 0.000040
    10
    time1::: 0.000052
    time1a: 0.000026
    time2::: 0.000045
    time3::: 0.000042
    time1::: 0.000077
    time1a: 0.000046
    time2::: 0.000072
    time3::: 0.000059



    http://mootools.net/shell/J7ySB/

    rasmusfl0e

    unread,
    Feb 23, 2010, 11:34:43 AM2/23/10
    to MooTools Users
    dude - would you like to borrow the "var" keyword? :P

    anyways... if you want performance avoid extra function calls when
    they aren't needed. all of the above could be done much simpler - the
    following example uses only 1 hasClass call:

    Element.implement({
    removeAllClassExcept: function(klass) {
    this.className = this.hasClass(klass) ? klass : '';
    return this;
    }
    });

    and it shows in the benchmark: http://mootools.net/shell/J7ySB/1/


    On Feb 23, 4:08 pm, Yann Leretaille <yleretai...@googlemail.com>
    wrote:


    > could somebody test this one with 100,100 & 10 Elements?
    >
    > My results:
    > n
    > FF 3.6, Linux, 64Bit FF 2.5.8,WinXP, 32Bit
    > 1000
    > time1::: 0.000033

    > *time1a: 0.000020*
    > time2::: 0.000030
    > time3::: 0.000024time1::: 0.000055
    > *time1a: 0.000036*


    > time2::: 0.000048
    > time3::: 0.000038
    > 100
    > time1::: 0.000045

    > *time1a: 0.000027*
    > time2::: 0.000040
    > time3::: 0.000032time1::: 0.000058
    > *time1a: 0.000037*


    > time2::: 0.000051
    > time3::: 0.000040
    > 10
    > time1::: 0.000052

    > *time1a: 0.000026*
    > time2::: 0.000045
    > time3::: 0.000042**time1::: 0.000077
    > *time1a: 0.000046*


    > time2::: 0.000072
    > time3::: 0.000059
    >
    > http://mootools.net/shell/J7ySB/
    >
    > On Mon, Feb 22, 2010 at 17:45, Yann Leretaille

    > <yleretai...@googlemail.com>wrote:


    >
    > > I understand your point. Actually, benchmarking seems particualry difficult
    > > for this one.
    > > I created a mooshell wich creates a list with 1000 Elements, wich have 0-3
    > > classes, with or without base_class.
    > > The list ist cloned for each benchmark and i ran each methos is runned 10
    > > times.
    > > Here are the results:
    >

    > >    - Method1 (my method):
    > >       - return this.set('class',new RegExp(klass).exec(this.get('class')))
    > >       ;
    >
    > >    - Method1a (my method, *precompiled RegExp* )
    > >       - regexp=new RegExp(klass)
    > >       - this.each(function(e) { e.set('class',regexp.exec(e.get('class')))
    > >       });
    >
    > >    - Method2 (Roman):
    > >       - return this.set('class', this.get('class').split(' ').filter(


    > >       function(c){return c == this },klass)[0]);

    > >    - Method3 (hazlema):
    > >    -  return this.hasClass(klass) ? this.set("class", klass) : this.erase(


    > >       "class");
    >
    > > Results (1000 items):
    >

    > >    - time1:   0.0000340
    > >    - *time1a: 0.0000216*
    > >    - time2:   0.0000306
    > >    - time3:   0.0000234

    Message has been deleted

    אריה גלזר

    unread,
    Feb 23, 2010, 10:35:32 AM2/23/10
    to mootool...@googlegroups.com
    FF 3.6 Windows 764bit:
    1000:
    time1::: 0.0000394
    time1a: 0.000024199999999999995 - fastets
    time2::: 0.0000338
    time3::: 0.000024800000000000003

    100:
    time1::: 0.00005440000000000003
    time1a: 0.00003120000000000002
    time2::: 0.000049800000000000025
    time3::: 0.00003960000000000003

    10:
    time1::: 0.00006180000000000004
    time1a: 0.00003120000000000002 - most likely to be used. same as 100
    time2::: 0.000052200000000000036
    time3::: 0.00004640000000000004
    -----------
    אריה גלזר
    052-5348-561
    5561

    Thierry bela nanga

    unread,
    Feb 23, 2010, 11:16:43 AM2/23/10
    to mootool...@googlegroups.com
    from the mooshell,

    Win Vista64 FF3.6

    time1::: 0.000049600000000000006
    time1a: 0.0000284
    time2::: 0.000044399999999999995
    time3::: 0.0000348
    --
    http://tbela99.blogspot.com/

    fax : (+33) 08 26 51 94 51

    Thierry bela nanga

    unread,
    Feb 23, 2010, 11:24:23 AM2/23/10
    to mootool...@googlegroups.com
    10 items

    time1::: 0.00006680000000000005
    time1a: 0.00003260000000000003
    time2::: 0.00006320000000000005
    time3::: 0.000052400000000000034


    100  items

    time1::: 0.00004920000000000003
    time1a: 0.000029000000000000014
    time2::: 0.00004500000000000003
    time3::: 0.000038400000000000025

    1000 items

    time1::: 0.000045
    time1a: 0.0000262
    time2::: 0.000042000000000000004
    time3::: 0.0000318

    Yann Leretaille

    unread,
    Feb 23, 2010, 4:51:46 PM2/23/10
    to mootool...@googlegroups.com
    anyways... if you want performance avoid extra function calls when
    they aren't needed. all of the above could be done much simpler - the
    following example uses only 1 hasClass call:

    Element.implement({
       removeAllClassExcept: function(klass) {
           this.className = this.hasClass(klass) ? klass : '';
           return this;
       }
    });


    I already wondered why always using set/get for class. It's good if you want to keep the moo style, but bad for performance in this case. The "Precompiled RexExp"-version is damn fast with className:
    (1000 items, almost the same for 100&10)
    time1::: 0.000040 <= RegExp+set/get, my method
    time1a: 0.000026  <=precompiled RegExp+set/get
    time1b: 0.000007  <=precompiled RegExp+className (yeah, thats one zero more ;) )
    time2::: 0.000040 <= get/set+Array.filter, Roman
    time3::: 0.000031   <= hasClass?:+get/set/erease, hazlema
    time4::: 0.000020 <= hasClass?:+className, rasmusfl0e

    http://mootools.net/shell/bmfGu/

    I didn't expected RegExp to be faster, but actually it is in this case ;-)
    Just wonder why Sanford got other results...perhaps because className was empty most time in his test...
    Thanks for all which did the benchmark and contributed, such tests/benchmarks are really interesting.

    Yann

    Sanford Whiteman

    unread,
    Feb 23, 2010, 6:52:55 PM2/23/10
    to Yann Leretaille
    But your benchmark still isn't balanced. For example, fn [1b] is using
    more pure JS/DOM functions and is implemented on Array, while fn [4]
    is using Moo overhead and is implemented on Element.

    The most apt competitor to your className.RegExp is className.indexOf.
    I adjusted fn [4] accordingly. I think you'll see that [4] wins out at
    n=10000, 1000, 100 and is about the same at n=10 (I don't think n=10
    is appropriate to test, since there is no "smoothing" effect in a
    benchmark that small).

    http://mootools.net/shell/bmfGu/3/

    -- S.


    Yann Leretaille

    unread,
    Feb 23, 2010, 10:00:01 PM2/23/10
    to mootool...@googlegroups.com
    But your benchmark still isn't balanced. For example, fn [1b] is using
    more  pure  JS/DOM functions and is implemented on Array, while fn [4]
    is using Moo overhead and is implemented on Element.
    Really? [4] used className, so i wanted to see how big the change was when using className in [1a] too (and for pure JS i think i should replace the ".each", but this wont make a big difference i think). Actually using pure JS for "contains" makes [4] 30x times faster than before, while hasClass does the same:

        hasClass: function(className){
            return this.className.contains(className, ' ');
        },

        contains: function(item, from){
            return this.indexOf(item, from) != -1;
        },
    Anyway its a question of milliseconds and i don't think it will ever matter in productive enviroment. So what is the best method to programm such a type of functions? The moo way or pureJS way?
    Moo code is more portable&durable but in some situations it could be a performance killer. In this case RegExp+moo's get/set is still faster then all other methods using moo code whenever its possible, mainly because it needs less of it. I think it will always be a compromise between speed and the ease&usefullness of moo, unless somebody writes a moo2pureJS compiler. (Would be a nice experiment, though).

    Well, enough benchmarking for today, i hope i didn't annoyed anybody by blowing up this thread with all this stuff.
    Yann

    Sanford Whiteman

    unread,
    Feb 23, 2010, 10:35:36 PM2/23/10
    to Yann Leretaille
    It isn't shocking that running hasClass()»contains()»indexOf() and
    set() is marginally slower than running only exec() (on a preexisting
    regex)»direct property set. Not that it isn't mildly interesting, just
    not anything actionable IMO.

    It would be shocking if just indexOf()»direct property set were slower
    than exec()»direct property set. But it isn't: it's 2-3x faster.

    So the only conclusion here is that "Moo wrappers add overhead that
    might, in quantity, cause some methods to fall behind otherwise clunky
    JS." But don't we know that already from peeking at Core?

    Anyway, _my_ feeling is that this would be better done with stylesheet
    scripting until I hear deeper requirements. And the stylesheet
    scripting will beat everyone else's a--. :P

    -- S.

    Yann Leretaille

    unread,
    Feb 23, 2010, 11:07:51 PM2/23/10
    to mootool...@googlegroups.com
    Full Ack! :D

    rasmusfl0e

    unread,
    Feb 24, 2010, 11:29:50 AM2/24/10
    to MooTools Users
    The way you've used RegExp will also match partial matches; you look
    for "rump" and get a match on "scrump"... not good. False positives.

    @Yann: The contains method you listed is the Array method - not String
    one which looks like this:

    contains: function(string, separator){
    return (separator) ? (separator + this + separator).indexOf(separator
    + string + separator) > -1 : this.indexOf(string) > -1;
    }

    Combining that code with the className property you'd get:

    removeAllClassExcept: function(klass) {
    this.className = ((' ' + this.className + ' ').indexOf(' ' + klass
    + ' ')>-1) ? klass : '';
    return this;
    }

    http://mootools.net/shell/bmfGu/3/

    On Feb 24, 4:00 am, Yann Leretaille <yleretai...@googlemail.com>

    Reply all
    Reply to author
    Forward
    0 new messages