From a687aefbe9e97922c3b99c713a6a4df165d81d40 Mon Sep 17 00:00:00 2001
From: Saq Imtiaz
Date: Tue, 29 Oct 2024 12:59:04 +0100
Subject: [PATCH] Extends element widget with support for CSS custom properties
(#8699)
* Extend element widget with support for CSS custom properties.
* chore: added tests
* chore: code style
* docs: added documentation for support for CSS custom properties
* docs: added documentation for support for CSS custom properties
---
core/modules/utils/fakedom.js | 70 +++++++++++++------
core/modules/widgets/widget.js | 5 ++
.../widgets/ElementWidgetStyleAttributes2.tid | 15 ++++
.../tiddlers/wikitext/HTML in WikiText.tid | 16 ++---
4 files changed, 76 insertions(+), 30 deletions(-)
create mode 100644 editions/test/tiddlers/tests/data/widgets/ElementWidgetStyleAttributes2.tid
diff --git a/core/modules/utils/fakedom.js b/core/modules/utils/fakedom.js
index fb28465fe..66f2314e2 100755
--- a/core/modules/utils/fakedom.js
+++ b/core/modules/utils/fakedom.js
@@ -56,36 +56,64 @@ Object.defineProperty(TW_TextNode.prototype, "formattedTextContent", {
}
});
-var TW_Element = function(tag,namespace) {
+var TW_Style = function(el) {
+ // Define the internal style object
+ var styleObject = {
+ // Method to get the entire style object
+ get: function() {
+ return el._style;
+ },
+ // Method to set styles using a string (e.g. "color:red; background-color:blue;")
+ set: function(str) {
+ var self = this;
+ str = str || "";
+ $tw.utils.each(str.split(";"),function(declaration) {
+ var parts = declaration.split(":"),
+ name = $tw.utils.trim(parts[0]),
+ value = $tw.utils.trim(parts[1]);
+ if(name && value) {
+ el._style[$tw.utils.convertStyleNameToPropertyName(name)] = value;
+ }
+ });
+ },
+ // Method to set a specific property without transforming the property name, such as a custom property
+ setProperty: function(name, value) {
+ el._style[name] = value;
+ }
+ };
+
+ // Return a Proxy to handle direct access to individual style properties
+ return new Proxy(styleObject, {
+ get: function(target, property) {
+ // If the property exists on styleObject, return it (get, set, setProperty methods)
+ if (property in target) {
+ return target[property];
+ }
+ // Otherwise, return the corresponding property from _style
+ return el._style[$tw.utils.convertStyleNameToPropertyName(property)] || "";
+ },
+ set: function(target, property, value) {
+ // Set the property in _style
+ el._style[$tw.utils.convertStyleNameToPropertyName(property)] = value;
+ return true;
+ }
+ });
+};
+
+var TW_Element = function(tag, namespace) {
bumpSequenceNumber(this);
this.isTiddlyWikiFakeDom = true;
this.tag = tag;
this.attributes = {};
this.isRaw = false;
this.children = [];
- this._style = {};
+ this._style = {}; // Internal style object
+ this.style = new TW_Style(this); // Proxy for style management
this.namespaceURI = namespace || "http://www.w3.org/1999/xhtml";
};
-Object.setPrototypeOf(TW_Element.prototype,TW_Node.prototype);
-Object.defineProperty(TW_Element.prototype, "style", {
- get: function() {
- return this._style;
- },
- set: function(str) {
- var self = this;
- str = str || "";
- $tw.utils.each(str.split(";"),function(declaration) {
- var parts = declaration.split(":"),
- name = $tw.utils.trim(parts[0]),
- value = $tw.utils.trim(parts[1]);
- if(name && value) {
- self._style[$tw.utils.convertStyleNameToPropertyName(name)] = value;
- }
- });
- }
-});
+Object.setPrototypeOf(TW_Element.prototype,TW_Node.prototype);
Object.defineProperty(TW_Element.prototype, "nodeType", {
get: function() {
@@ -105,7 +133,7 @@ TW_Element.prototype.setAttribute = function(name,value) {
throw "Cannot setAttribute on a raw TW_Element";
}
if(name === "style") {
- this.style = value;
+ this.style.set(value);
} else {
this.attributes[name] = value + "";
}
diff --git a/core/modules/widgets/widget.js b/core/modules/widgets/widget.js
index b73294654..14e90ba2d 100755
--- a/core/modules/widgets/widget.js
+++ b/core/modules/widgets/widget.js
@@ -428,6 +428,11 @@ Widget.prototype.assignAttributes = function(domNode,options) {
destPrefix = options.destPrefix || "",
EVENT_ATTRIBUTE_PREFIX = "on";
var assignAttribute = function(name,value) {
+ // Process any CSS custom properties
+ if(name.substr(0,2) === "--" && name.length > 2) {
+ domNode.style.setProperty(name,value);
+ return;
+ }
// Process any style attributes before considering sourcePrefix and destPrefix
if(name.substr(0,6) === "style." && name.length > 6) {
domNode.style[$tw.utils.unHyphenateCss(name.substr(6))] = value;
diff --git a/editions/test/tiddlers/tests/data/widgets/ElementWidgetStyleAttributes2.tid b/editions/test/tiddlers/tests/data/widgets/ElementWidgetStyleAttributes2.tid
new file mode 100644
index 000000000..6b6a2f953
--- /dev/null
+++ b/editions/test/tiddlers/tests/data/widgets/ElementWidgetStyleAttributes2.tid
@@ -0,0 +1,15 @@
+title: Widgets/ElementWidgetCSSCustomProps
+description: Element widget should support CSS custom properties
+type: text/vnd.tiddlywiki-multiple
+tags: [[$:/tags/wiki-test-spec]]
+
+title: Output
+
+\whitespace trim
+
+TiddlyWiki
+
++
+title: ExpectedResult
+
+TiddlyWiki
\ No newline at end of file
diff --git a/editions/tw5.com/tiddlers/wikitext/HTML in WikiText.tid b/editions/tw5.com/tiddlers/wikitext/HTML in WikiText.tid
index b28b471b8..5f1618791 100644
--- a/editions/tw5.com/tiddlers/wikitext/HTML in WikiText.tid
+++ b/editions/tw5.com/tiddlers/wikitext/HTML in WikiText.tid
@@ -1,6 +1,6 @@
caption: HTML
created: 20131205160816081
-modified: 20230615060119987
+modified: 20241025073517909
tags: WikiText
title: HTML in WikiText
type: text/vnd.tiddlywiki
@@ -68,13 +68,13 @@ In an extension of conventional HTML syntax, attributes of elements and widgets
!! Style Attributes
-<<.from-version "5.2.2">> TiddlyWiki supports the usual HTML ''style'' attribute for assigning CSS styles to elements:
+TiddlyWiki supports the usual HTML ''style'' attribute for assigning CSS styles to elements:
```
Hello
```
-In an extension to HTML, TiddlyWiki also supports accessing individual CSS styles as independent attributes. For example:
+<<.from-version "5.2.2">> In an extension to HTML, TiddlyWiki also supports accessing individual CSS styles as independent attributes. For example:
```
Hello
@@ -86,10 +86,8 @@ The advantage of this syntax is that it simplifies assigning computed values to
Hello
```
+<<.from-version "5.3.6">> TiddlyWiki also supports setting [[CSS custom properties|https://developer.mozilla.org/en-US/docs/Web/CSS/Using_CSS_custom_properties]] as independent attributes. For example:
-
-
-
-
-
-
+```
+Hello
+```