mirror of
https://github.com/Jermolene/TiddlyWiki5
synced 2026-08-20 09:48:53 +00:00
Fix button widget selection state with setTitle (#9951)
Make the button widget apply selectedClass correctly when the state is addressed with setTitle instead of set. Issue #9949, the button could not be rendered at all * Guard the setField read in isSelected(), which dereferenced the result of getTiddler() directly. A missing state tiddler threw a TypeError, and that tiddler is normally only created by the first click Issue #9950, every button of a set reported itself as selected * Rewrite isSelected() as an if/else. The nested ternary mixed `||` with `?:`, so the setTitle branch returned a fallback value instead of a comparison * Watch the setTitle state tiddler in refresh(), so the selected class follows the state as it already does for set Documentation and tests * Document that setField takes preference over setIndex. That has always been the behaviour, it was never written down * Document that selectedClass and default apply to setTitle as well as to set * Add wiki based test cases for the set, setTitle, setField and setIndex selection paths. Six of the seven fail against v5.4.1, the one that passes uses set, which was never broken Fixes #9949 Fixes #9950
This commit is contained in:
@@ -151,10 +151,24 @@ ButtonWidget.prototype.getBoundingClientRect = function() {
|
||||
};
|
||||
|
||||
ButtonWidget.prototype.isSelected = function() {
|
||||
return this.setTitle ? (this.setField ? this.wiki.getTiddler(this.setTitle).getFieldString(this.setField) === this.setTo :
|
||||
(this.setIndex ? this.wiki.extractTiddlerDataItem(this.setTitle,this.setIndex) === this.setTo :
|
||||
this.wiki.getTiddlerText(this.setTitle))) || this.defaultSetValue || this.getVariable("currentTiddler") :
|
||||
this.wiki.getTextReference(this.set,this.defaultSetValue,this.getVariable("currentTiddler")) === this.setTo;
|
||||
var currentValue;
|
||||
if(this.setTitle) {
|
||||
if(this.setField) {
|
||||
// The state tiddler usually does not exist until the button is first clicked
|
||||
var tiddler = this.wiki.getTiddler(this.setTitle);
|
||||
currentValue = tiddler ? tiddler.getFieldString(this.setField) : undefined;
|
||||
} else if(this.setIndex) {
|
||||
currentValue = this.wiki.extractTiddlerDataItem(this.setTitle,this.setIndex);
|
||||
} else {
|
||||
currentValue = this.wiki.getTiddlerText(this.setTitle);
|
||||
}
|
||||
if(!currentValue) {
|
||||
currentValue = this.defaultSetValue || this.getVariable("currentTiddler");
|
||||
}
|
||||
} else {
|
||||
currentValue = this.wiki.getTextReference(this.set,this.defaultSetValue,this.getVariable("currentTiddler"));
|
||||
}
|
||||
return currentValue === this.setTo;
|
||||
};
|
||||
|
||||
ButtonWidget.prototype.isPoppedUp = function() {
|
||||
@@ -267,7 +281,7 @@ Selectively refreshes the widget if needed. Returns true if the widget or any of
|
||||
*/
|
||||
ButtonWidget.prototype.refresh = function(changedTiddlers) {
|
||||
var changedAttributes = this.computeAttributes();
|
||||
if(changedAttributes.tooltip || changedAttributes.actions || changedAttributes.to || changedAttributes.message || changedAttributes.param || changedAttributes.set || changedAttributes.setTo || changedAttributes.popup || changedAttributes.hover || changedAttributes.selectedClass || changedAttributes.style || changedAttributes.dragFilter || changedAttributes.dragTiddler || (this.set && changedTiddlers[this.set]) || (this.popup && changedTiddlers[this.popup]) || (this.popupTitle && changedTiddlers[this.popupTitle]) || changedAttributes.popupAbsCoords || changedAttributes.setTitle || changedAttributes.setField || changedAttributes.setIndex || changedAttributes.popupTitle || changedAttributes.disabled || changedAttributes["default"]) {
|
||||
if(changedAttributes.tooltip || changedAttributes.actions || changedAttributes.to || changedAttributes.message || changedAttributes.param || changedAttributes.set || changedAttributes.setTo || changedAttributes.popup || changedAttributes.hover || changedAttributes.selectedClass || changedAttributes.style || changedAttributes.dragFilter || changedAttributes.dragTiddler || (this.set && changedTiddlers[this.set]) || (this.setTitle && changedTiddlers[this.setTitle]) || (this.popup && changedTiddlers[this.popup]) || (this.popupTitle && changedTiddlers[this.popupTitle]) || changedAttributes.popupAbsCoords || changedAttributes.setTitle || changedAttributes.setField || changedAttributes.setIndex || changedAttributes.popupTitle || changedAttributes.disabled || changedAttributes["default"]) {
|
||||
this.refreshSelf();
|
||||
return true;
|
||||
} else {
|
||||
|
||||
@@ -0,0 +1,12 @@
|
||||
title: ButtonSelection/DefaultSelection
|
||||
description: The default attribute selects a setTitle button while the state tiddler is missing
|
||||
type: text/vnd.tiddlywiki-multiple
|
||||
tags: [[$:/tags/wiki-test-spec]]
|
||||
|
||||
title: Output
|
||||
|
||||
<$button setTitle="$:/state/demo" setTo="Alpha" default="Beta" selectedClass="sel">Alpha</$button><$button setTitle="$:/state/demo" setTo="Beta" default="Beta" selectedClass="sel">Beta</$button>
|
||||
+
|
||||
title: ExpectedResult
|
||||
|
||||
<p><button aria-checked="false" class="">Alpha</button><button aria-checked="true" class=" sel">Beta</button></p>
|
||||
@@ -0,0 +1,12 @@
|
||||
title: ButtonSelection/MissingStateTiddler
|
||||
description: A setField button renders when its state tiddler does not exist
|
||||
type: text/vnd.tiddlywiki-multiple
|
||||
tags: [[$:/tags/wiki-test-spec]]
|
||||
|
||||
title: Output
|
||||
|
||||
<$button setTitle="$:/state/demo" setField="selection" setTo="Alpha" selectedClass="sel">Alpha</$button>
|
||||
+
|
||||
title: ExpectedResult
|
||||
|
||||
<p><button aria-checked="false" class="">Alpha</button></p>
|
||||
@@ -0,0 +1,15 @@
|
||||
title: ButtonSelection/SetFieldSelection
|
||||
description: Only the setField button whose setTo matches the state field is selected
|
||||
type: text/vnd.tiddlywiki-multiple
|
||||
tags: [[$:/tags/wiki-test-spec]]
|
||||
|
||||
title: $:/state/demo
|
||||
selection: Beta
|
||||
+
|
||||
title: Output
|
||||
|
||||
<$button setTitle="$:/state/demo" setField="selection" setTo="Alpha" selectedClass="sel">Alpha</$button><$button setTitle="$:/state/demo" setField="selection" setTo="Beta" selectedClass="sel">Beta</$button>
|
||||
+
|
||||
title: ExpectedResult
|
||||
|
||||
<p><button aria-checked="false" class="">Alpha</button><button aria-checked="true" class=" sel">Beta</button></p>
|
||||
@@ -0,0 +1,17 @@
|
||||
title: ButtonSelection/SetIndexSelection
|
||||
description: Only the setIndex button whose setTo matches the state index is selected
|
||||
type: text/vnd.tiddlywiki-multiple
|
||||
tags: [[$:/tags/wiki-test-spec]]
|
||||
|
||||
title: $:/state/demo
|
||||
type: application/json
|
||||
|
||||
{"selection": "Beta"}
|
||||
+
|
||||
title: Output
|
||||
|
||||
<$button setTitle="$:/state/demo" setIndex="selection" setTo="Alpha" selectedClass="sel">Alpha</$button><$button setTitle="$:/state/demo" setIndex="selection" setTo="Beta" selectedClass="sel">Beta</$button>
|
||||
+
|
||||
title: ExpectedResult
|
||||
|
||||
<p><button aria-checked="false" class="">Alpha</button><button aria-checked="true" class=" sel">Beta</button></p>
|
||||
@@ -0,0 +1,16 @@
|
||||
title: ButtonSelection/SetSelection
|
||||
description: Only the set button whose setTo matches the state is selected
|
||||
type: text/vnd.tiddlywiki-multiple
|
||||
tags: [[$:/tags/wiki-test-spec]]
|
||||
|
||||
title: $:/state/demo
|
||||
|
||||
Alpha
|
||||
+
|
||||
title: Output
|
||||
|
||||
<$button set="$:/state/demo" setTo="Alpha" selectedClass="sel">Alpha</$button><$button set="$:/state/demo" setTo="Beta" selectedClass="sel">Beta</$button>
|
||||
+
|
||||
title: ExpectedResult
|
||||
|
||||
<p><button aria-checked="true" class=" sel">Alpha</button><button aria-checked="false" class="">Beta</button></p>
|
||||
@@ -0,0 +1,20 @@
|
||||
title: ButtonSelection/SetTitleRefresh
|
||||
description: The setTitle selection follows the state tiddler when it changes
|
||||
type: text/vnd.tiddlywiki-multiple
|
||||
tags: [[$:/tags/wiki-test-spec]]
|
||||
|
||||
title: $:/state/demo
|
||||
|
||||
Alpha
|
||||
+
|
||||
title: Output
|
||||
|
||||
<$button setTitle="$:/state/demo" setTo="Alpha" selectedClass="sel">Alpha</$button><$button setTitle="$:/state/demo" setTo="Beta" selectedClass="sel">Beta</$button>
|
||||
+
|
||||
title: Actions
|
||||
|
||||
<$action-setfield $tiddler="$:/state/demo" text="Beta"/>
|
||||
+
|
||||
title: ExpectedResult
|
||||
|
||||
<p><button aria-checked="false" class="">Alpha</button><button aria-checked="true" class=" sel">Beta</button></p>
|
||||
@@ -0,0 +1,16 @@
|
||||
title: ButtonSelection/SetTitleSelection
|
||||
description: Only the setTitle button whose setTo matches the state is selected
|
||||
type: text/vnd.tiddlywiki-multiple
|
||||
tags: [[$:/tags/wiki-test-spec]]
|
||||
|
||||
title: $:/state/demo
|
||||
|
||||
Alpha
|
||||
+
|
||||
title: Output
|
||||
|
||||
<$button setTitle="$:/state/demo" setTo="Alpha" selectedClass="sel">Alpha</$button><$button setTitle="$:/state/demo" setTo="Beta" selectedClass="sel">Beta</$button>
|
||||
+
|
||||
title: ExpectedResult
|
||||
|
||||
<p><button aria-checked="true" class=" sel">Alpha</button><button aria-checked="false" class="">Beta</button></p>
|
||||
@@ -0,0 +1,26 @@
|
||||
change-category: widget
|
||||
change-type: bugfix
|
||||
created: 20260727171657000
|
||||
description: The button widget applies selectedClass when the state is addressed with setTitle
|
||||
github-contributors: pmario
|
||||
github-links: https://github.com/TiddlyWiki/TiddlyWiki5/pull/9951
|
||||
release: 5.5.0
|
||||
tags: $:/tags/ChangeNote
|
||||
title: $:/changenotes/5.5.0/#9951
|
||||
type: text/vnd.tiddlywiki
|
||||
|
||||
* Buttons sharing a state tiddler through `setTitle` highlight the selected one. Only the button whose `setTo` matches the state gets the `selectedClass`
|
||||
* The highlight follows the state as it changes
|
||||
* `default` picks the highlighted button while the state tiddler is still missing
|
||||
* The state is the tiddler text. Use `setField` or `setIndex` to address a field or an index instead
|
||||
|
||||
```
|
||||
<div class="tc-tab-buttons">
|
||||
<$button setTitle="$:/state/tab" setTo="Alpha" default="Alpha" selectedClass="tc-tab-selected">Alpha</$button>
|
||||
<$button setTitle="$:/state/tab" setTo="Beta" default="Alpha" selectedClass="tc-tab-selected">Beta</$button>
|
||||
</div>
|
||||
```
|
||||
|
||||
The ButtonWidget documentation gained two missing rules. `setField` takes preference over `setIndex`. `selectedClass` and `default` apply to `setTitle`, not only to `set`.
|
||||
|
||||
Fixed issues: [[#9949|https://github.com/TiddlyWiki/TiddlyWiki5/issues/9949]] and [[#9950|https://github.com/TiddlyWiki/TiddlyWiki5/issues/9950]]
|
||||
@@ -30,12 +30,12 @@ The content of the `<$button>` widget is displayed within the button.
|
||||
|param |The optional parameter to the message |
|
||||
|set |A TextReference to which a new value will be assigned |
|
||||
|setTitle |A title to which a new value will be assigned, ''without'' TextReference. Gets preferred over <<.attr set>> |
|
||||
|setField |A ''field name'' to which the new value will be assigned, if the attribute <<.attr setTitle>> is present. Defaults to the ''text'' field |
|
||||
|setIndex |An ''index'' to which the new value will be assigned, if the attribute <<.attr setTitle>> is present |
|
||||
|setField |A ''field name'' to which the new value will be assigned, if the attribute <<.attr setTitle>> is present. Defaults to the ''text'' field. Takes preference over <<.attr setIndex>> |
|
||||
|setIndex |An ''index'' to which the new value will be assigned, if the attribute <<.attr setTitle>> is present. Ignored if <<.attr setField>> is also present |
|
||||
|setTo |The new value to assign to the TextReference identified in the `set` attribute or the text field / the field specified through <<.attr setField>> / the index specified through <<.attr setIndex>> of the title given through <<.attr setTitle>> |
|
||||
|selectedClass |An optional additional CSS class to be assigned if the popup is triggered or the tiddler specified in <<.attr set>> already has the value specified in <<.attr setTo>> |
|
||||
|selectedClass |An optional additional CSS class to be assigned if the popup is triggered or the state identified by <<.attr set>> or <<.attr setTitle>> already has the value specified in <<.attr setTo>> |
|
||||
|selectedAria |<<.from-version "5.4.0">> An ARIA attribute to be set to `true` or `false` when <<.attr selectedClass>> is defined. Allowed values are `aria-checked` (default), `aria-selected` and `aria-pressed` |
|
||||
|default |Default value if <<.attr set>> tiddler is missing for testing against <<.attr setTo>> to determine <<.attr selectedClass>> |
|
||||
|default |Default value if the state identified by <<.attr set>> or <<.attr setTitle>> is missing for testing against <<.attr setTo>> to determine <<.attr selectedClass>> |
|
||||
|popup |Title of a state tiddler for a popup that is toggled when the button is clicked. See PopupMechanism for details |
|
||||
|popupTitle |Title of a state tiddler for a popup that is toggled when the button is clicked. In difference to the <<.attr popup>> attribute, ''no'' TextReference is used. See PopupMechanism for details |
|
||||
|popupAbsCoords |<<.from-version "5.2.4">> If set to ''yes'' writes absolute coordinates to the tiddler referenced by the <<.attr popup>>. If set to ''no'' (the default) uses relative coordinates. See [[Coordinate Systems]] for details |
|
||||
|
||||
Reference in New Issue
Block a user