If we run toggle class and remove a class that is between two other classes, the remaining classes have no space between them. Example:

elt.className = 'this that another';
toggleClass(elt., 'that');
alert(elt.className);

New class name wil be 'thisanother'.

Support from Acquia helps fund testing for Drupal Acquia logo

Comments

nedjo’s picture

Title: toggleClass() in drupal.js problem--removes needed spaces » removeClass() in drupal.js problem--removes needed spaces

The issue I guess is in removeClass. We use a regular expression that removes the class and any space before or after it. This handles the case that the class is the only one set, that it is at the end, or that it is at the beginning, but not if it is in the middle and one of the enclosing spaces needs to be kept.

Would we do better to handle all our class setting using arrays? We could e.g. split the existing names into an array and then use splice to remove elements.

nedjo’s picture

Assigned: Unassigned » nedjo
Status: Active » Needs review
FileSize
1.83 KB

Here's a patch that uses arrays to handle class names. We introduce a new Array method, indexOf, that works in a parallel way to the String object's indexOf method: it searches the array for a particular value, returning the index if found and -1 if not.

addClass and removeClass then convert the node.className into an array and call indexOf, adding or removing elements accordingly.

markus_petrux’s picture

Extending a builtin javascript object could conflict with 3rd party libraries, which is very difficult to debug when that happens.

Maybe you could implement the same feature using a standalone function?

moshe weitzman’s picture

perhaps a prefixing the new method with drupal_ would suffice?

markus_petrux’s picture

Maybe, but still, something unexpected may happen when extending builtin javascript objects.

This is an example (related to a bug in MSIE):
http://drupal.org/node/47557

I think it's equally easy to create a standalone function that takes an array as its first argument and whatever else it may need. Javascript arguments are passed by reference so this shouldn't be a restriction.

Javascript doesn't have namespaces so when there are chances to mix several libraries (which may happen with Drupal, f.e. with prototype.js or the Yahoo! library, etc.), prefixing global objects with something unique (say drupal_) would be a good idea, however.

nedjo’s picture

Okay, here's a version with a standalone function rather than prototyping the Array object.

Steven’s picture

Why do you use the lambda-like function assignment instead of a normal declaration? Don't you need to declare the variable with 'var' then?

I'd prefer the normal function syntax.

nedjo’s picture

Thanks for pointing this out, just a bad edit on my part from my previous patch. Here it is with a normal declaration.

nedjo’s picture

Status: Needs review » Needs work

This patch raises errors if there is no className set. We need to test for node.className before acting on it. I'll work on fixing this.

nedjo’s picture

Title: removeClass() in drupal.js problem--removes needed spaces » removeClass() in drupal.js removes needed spaces
Status: Needs work » Needs review
FileSize
633 bytes

I'm still kinda partial to treating classes as arrays, but here's a much smaller patch.

Instead of refactoring our approach, we change removeClass to test separately for classes with a space before and a space after, so that two spaces won't be removed.

drumm’s picture

Status: Needs review » Needs work

Lets say we have class="my-class-with-lots-of-words" and we attempt to remove 'my-class.' I that a chunk of the class name would be removed since there is no test for end of word. There is a way to match end of word in many regexp varients, usually '>' or '\>.'

nedjo’s picture

Status: Needs work » Needs review
FileSize
654 bytes

Good point. Regular expressions have never been my strong point (which probably begs the question, why am I submitting a regex patch? ;) ). Anyway, \b seems to be the Javascript regex word boundary match. Here's a patch that tests for beginning/end of string or word boundary.

Dries’s picture

See also #64639.

kkaefer’s picture

Title: removeClass() in drupal.js removes needed spaces » Another patch
Component: other » javascript
FileSize
582 bytes

Here is a new patch (which is also different from the one I posted at http://drupal.org/node/64639).

It works with word boundaries and does also handle classes with dashes inside correctly.

kkaefer’s picture

Title: Another patch » removeClass() in drupal.js removes needed spaces

(sorry, didn't know that changing the title affects the whole issue now)

Dries’s picture

I suggest that we document this change/requirement with a code comment.

If Nedjo can confirm that this patch solves his problem, we can commit it to CVS.

nedjo’s picture

FileSize
772 bytes

On my basic testing this fixes the issue.

Why do we need special handling for dashes (-) ? Are they interpreted as word boundaries?

Here's how I tested the patch (no patching of files required): copy the attached into a 'page' or 'story' node, set input type as PHP. It loads drupal.js, redefines the removeClass() function, and then runs a test, setting a three-part class name and removing the middle part.

Konstantin, can you add a one-line code comment explaining the filtering?

Dries’s picture

With some documentation, this patch looks ready to go. Thanks Nedjo for testing.

kkaefer’s picture

FileSize
667 bytes

Again a new patch. I figured out, that my previous patch was way too complex (it worked though) because we can achieve that much simpler. It actually doesn't matter if there is more than one space between two classes so we can safely punch in just another space to be sure that there *is* whitespace. That also solves the word boundary problem because yes, a dash is a word boundary in regex. In my previous patch, that was solved with a lookahead which makes sure that there is no dash directly following. In the new patch however, this isn't needed.

Nedjo: You should've added another class calles 'one' and remove that class without word boundaries. Because then, it also would have removed *every* 'one' in every class.

Dries’s picture

The code looks clean and elegant, but I can't make sense of the code comment. Not without reading up on this issue anyway. I suggest we work on the code comment some more. Thanks! :)

kkaefer’s picture

FileSize
656 bytes

Another code comment

nedjo’s picture

Status: Needs review » Reviewed & tested by the community

Looks good to go.

Dries’s picture

Sorry but the code comment is not entirely clear yet. It explains what is going on, but not why.

kkaefer’s picture

FileSize
714 bytes

Added the reason for the change to the code comment.

Dries’s picture

Status: Reviewed & tested by the community » Fixed

Excellent. Comitted to CVS HEAD. Thanks for the persistence Konstantin.

Gerhard Killesreiter’s picture

also to 4.7.

Anonymous’s picture

Status: Fixed » Closed (fixed)