mirror of
https://github.com/Jermolene/TiddlyWiki5
synced 2026-08-07 19:38:54 +00:00
Align fakedom tagname with HTML spec (#9843)
* Fakedom: uppercase tagName for HTML elements per DOM spec Browsers uppercase tagName for HTML elements. Other namespaces (SVG, MathML, XML) preserve case. Fakedom now matches, so widget code can use the natural `node.tagName === "OPTGROUP"` form in both environments. https://dom.spec.whatwg.org/#dom-element-tagname * Tests: cover fakedom tagName spec compliance Three specs pin the DOM contract for tagName: uppercase for HTML elements, case preservation for other namespaces, and non-mutating reads. Includes the OPTGROUP predicate the select widget will rely on once it can drop its defensive .toUpperCase() call. https://dom.spec.whatwg.org/#dom-element-tagname * Fakedom: empty or null namespace creates a no-namespace element Per DOM spec, createElementNS("") and createElementNS(null) have to produce elements with no namespace. Fakedom previously defaults both to HTML, which made tagName incorrectly uppercase non-HTML elements. createElement without arguments still defaults to HTML. https://dom.spec.whatwg.org/#dom-document-createelementns * Add ChangeNote
This commit is contained in:
@@ -115,7 +115,9 @@ var TW_Element = function(tag, namespace) {
|
||||
this.children = [];
|
||||
this._style = {}; // Internal style object
|
||||
this.style = new TW_Style(this); // Proxy for style management
|
||||
this.namespaceURI = namespace || "http://www.w3.org/1999/xhtml";
|
||||
// createElementNS with empty-string or null normalises to null (no namespace) per spec.
|
||||
// https://dom.spec.whatwg.org/#dom-document-createelementns
|
||||
this.namespaceURI = namespace !== undefined ? (namespace || null) : "http://www.w3.org/1999/xhtml";
|
||||
};
|
||||
|
||||
|
||||
@@ -206,7 +208,16 @@ TW_Element.prototype.addEventListener = function(type,listener,useCapture) {
|
||||
|
||||
Object.defineProperty(TW_Element.prototype, "tagName", {
|
||||
get: function() {
|
||||
return this.tag || "";
|
||||
if(!this.tag) {
|
||||
return "";
|
||||
}
|
||||
// HTML elements report uppercase tagName per DOM spec. Other namespaces
|
||||
// preserve case. Fakedom only models HTML documents.
|
||||
// https://dom.spec.whatwg.org/#dom-element-tagname
|
||||
if(this.namespaceURI === "http://www.w3.org/1999/xhtml") {
|
||||
return this.tag.toUpperCase();
|
||||
}
|
||||
return this.tag;
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
@@ -19,6 +19,56 @@ describe("fakedom tests", function() {
|
||||
expect($tw.fakeDocument.createTextNode("text").TEXT_NODE).toBe(3);
|
||||
});
|
||||
|
||||
// Per DOM spec, tagName returns the HTML-uppercased qualified name for HTML
|
||||
// elements. Other namespaces preserve case.
|
||||
// https://dom.spec.whatwg.org/#dom-element-tagname
|
||||
var HTML_NS = "http://www.w3.org/1999/xhtml";
|
||||
var SVG_NS = "http://www.w3.org/2000/svg";
|
||||
|
||||
it("tagName uppercases for HTML namespace", function() {
|
||||
// Default namespace is HTML
|
||||
expect($tw.fakeDocument.createElement("div").tagName).toBe("DIV");
|
||||
// The exact predicate the select widget relies on (#9839)
|
||||
expect($tw.fakeDocument.createElement("optgroup").tagName === "OPTGROUP").toBe(true);
|
||||
// Already-uppercase input stays uppercase
|
||||
expect($tw.fakeDocument.createElement("OPTGROUP").tagName).toBe("OPTGROUP");
|
||||
// Mixed-case input is normalised
|
||||
expect($tw.fakeDocument.createElement("Div").tagName).toBe("DIV");
|
||||
// Hyphenated custom-element names uppercase whole tag, hyphens survive
|
||||
expect($tw.fakeDocument.createElement("my-button").tagName).toBe("MY-BUTTON");
|
||||
// Empty tag returns empty string
|
||||
expect($tw.fakeDocument.createElement("").tagName).toBe("");
|
||||
// Explicit HTML namespace via createElementNS uppercases the same way
|
||||
expect($tw.fakeDocument.createElementNS(HTML_NS,"Div").tagName).toBe("DIV");
|
||||
});
|
||||
|
||||
it("tagName preserves case for non-HTML namespaces", function() {
|
||||
// SVG: lowercase preserved
|
||||
expect($tw.fakeDocument.createElementNS(SVG_NS,"circle").tagName).toBe("circle");
|
||||
// SVG: camelCase preserved (linearGradient is the canonical example)
|
||||
expect($tw.fakeDocument.createElementNS(SVG_NS,"linearGradient").tagName).toBe("linearGradient");
|
||||
// SVG: already-uppercase input is also preserved (NOT lowercased)
|
||||
expect($tw.fakeDocument.createElementNS(SVG_NS,"DIV").tagName).toBe("DIV");
|
||||
// Empty namespace string is "no namespace", not HTML. Case preserved.
|
||||
expect($tw.fakeDocument.createElementNS("","div").tagName).toBe("div");
|
||||
});
|
||||
|
||||
it("tagName reflects current state without mutating it", function() {
|
||||
// Reading tagName must not overwrite the internal `tag` field
|
||||
var el = $tw.fakeDocument.createElement("div");
|
||||
expect(el.tagName).toBe("DIV");
|
||||
expect(el.tag).toBe("div");
|
||||
// Idempotent: two reads return identical values
|
||||
var first = el.tagName, second = el.tagName;
|
||||
expect(first).toBe(second);
|
||||
// Dynamic namespace change is reflected. The getter must read current
|
||||
// state, not a value cached at construction time.
|
||||
var dynamic = $tw.fakeDocument.createElement("foo");
|
||||
expect(dynamic.tagName).toBe("FOO");
|
||||
dynamic.namespaceURI = SVG_NS;
|
||||
expect(dynamic.tagName).toBe("foo");
|
||||
});
|
||||
|
||||
// Real CSSStyleDeclaration returns undefined for Symbol property keys.
|
||||
// Without a guard, the TW_Style Proxy throws on Symbol access. This bites
|
||||
// in practice when Jasmine pretty-prints fakedom elements on failure.
|
||||
|
||||
@@ -0,0 +1,13 @@
|
||||
change-category: internal
|
||||
change-type: bugfix
|
||||
created: 20260711014241000
|
||||
description: fakedom tagName is uppercase for HTML elements, matching the DOM spec
|
||||
github-contributors: pmario
|
||||
github-links: https://github.com/TiddlyWiki/TiddlyWiki5/pull/9843
|
||||
release: 5.5.0
|
||||
tags: $:/tags/ChangeNote
|
||||
title: $:/changenotes/5.5.0/#9843
|
||||
type: text/vnd.tiddlywiki
|
||||
|
||||
* `$tw.fakeDocument` elements now report `tagName` in uppercase for HTML elements, matching the DOM specification and real browsers; code that compares fakedom `tagName` against lowercase strings must be updated
|
||||
* Creating an element with an empty or null namespace now produces a plain element without a namespace
|
||||
Reference in New Issue
Block a user