mirror of
https://github.com/Jermolene/TiddlyWiki5
synced 2026-06-03 19:22:27 +00:00
Fix RSOD when $tw.utils.addClass receives a class string with whitespace
PR #9251 replaced the manual setAttribute("class", ...) implementation of $tw.utils.addClass/removeClass/toggleClass with direct Element.classList calls. Unlike setAttribute, classList.add/remove/toggle throws InvalidCharacterError on any token containing whitespace, so callers that pass a whole class string (e.g. modal.js passing tiddler.fields.class) now crash. Manual repro on tw5-com: open SampleWizard, set the `class` field to "aaa bbb", Done, open popup -> OK -> open nested popup -> RSOD. Fix: split the className argument on whitespace in deprecated.js and feed individual tokens to classList. A small splitClasses() helper keeps the three functions symmetrical. Adds adversarial regression tests in test-utils.js covering: - ASCII whitespace variants (space, tab, CR, LF, mixed runs, padding) - Unicode whitespace (U+00A0 non-breaking space) - de-duplication across single and multiple calls - remove/toggle no-op on missing tokens - toggle with status undefined / true / false - silent no-op for whitespace-only / empty / non-string / null input - silent no-op when the element has no classList
This commit is contained in:
@@ -43,16 +43,24 @@ exports.domMatchesSelector = (node,selector) => node.matches(selector);
|
||||
|
||||
exports.hasClass = (el,className) => el.classList && el.classList.contains(className);
|
||||
|
||||
// classList.add/remove/toggle reject whitespace, but the legacy API accepts "aaa bbb".
|
||||
function splitClasses(className) {
|
||||
return (typeof className === "string" && className.match(/\S+/g)) || [];
|
||||
}
|
||||
|
||||
exports.addClass = function(el,className) {
|
||||
el.classList && className && el.classList.add(className);
|
||||
if(!el.classList) return;
|
||||
splitClasses(className).forEach(function(c) { el.classList.add(c); });
|
||||
};
|
||||
|
||||
exports.removeClass = function(el,className) {
|
||||
el.classList && className && el.classList.remove(className);
|
||||
if(!el.classList) return;
|
||||
splitClasses(className).forEach(function(c) { el.classList.remove(c); });
|
||||
};
|
||||
|
||||
exports.toggleClass = function(el,className,status) {
|
||||
el.classList && className && el.classList.toggle(className, status);
|
||||
if(!el.classList) return;
|
||||
splitClasses(className).forEach(function(c) { el.classList.toggle(c,status); });
|
||||
};
|
||||
|
||||
exports.getLocationPath = () => window.location.origin + window.location.pathname;
|
||||
Reference in New Issue
Block a user