On Monday, August 7, 2023 at 12:04:12 AM UTC-5, JJ wrote:
On Sat, 5 Aug 2023 05:55:08 -0700 (PDT), luserdroog wrote:
On Thursday, August 3, 2023 at 10:04:58 AM UTC-5, luserdroog wrote:
I want to make a control that looks like a checkbox but cycles through
4 states: { blank, checkmark, X-mark, questionmark }. What's the best
way to build such a thing. I'm thinking it wouldn't be too hard to make >> a web component that just controls a span and flips through
{ " ", "&#x...whatevers", ... "?" } strings.
Is there an existing element that's closer, like an <option> I guess?
Thanks Michael and Arno. Here's my idea for the interface a little more fleshed out:
<click-box cycle
states="empty checkmark xmark questionmark"
empty=""
checkmark="&x#..."
xmark="&x#..."
questionmark="?"></click-box>
Specifying the "cycle" attribute selects the (currently only) behavior
of cycling through states. The .value attribute/property of the
component will be reported as one of the strings from the "states" attribute. If a state value itself is defined as an attribute then the value of that attribute will be used as the label for visual display, otherwise the value string will be used as the label.
This seems like it covers what I need, allowing extension without too
much YAGNI, and I can stick one in a <template> and then clone that
around where I need it, I think. Maybe it should also offer a .textContent output.
That would be a custom input interface element. e.g.
https://jsbin.com/dixapihuto/1/edit?html,css,js,output
Very nice. I took a slight peek while ironing out the creases in mine.
I haven't quite figured out the next tweak where I want to convert
the value to/from a string by doing a map/reverse-map through the
label strings. Like, if this "clickbox" is a cell in a table I want to easily convert the table contents to/from a CSV text file. And for this type of
cell it should read and write the unicode checkmark character and
internally recognize/store the value as "checkmark".
click.html:
<html>
<body>
<click-box cycle
states="empty checkmark xmark questionmark"
empty=""
checkmark="✓"
xmark="✖"
questionmark="?"></click-box>
</body>
<script src="click.js"></script>
</html>
click.js:
const clickBoxTemplate = document.createElement( "template" ); clickBoxTemplate.innerHTML = `
<style>
input{
text-align: center;
cursor: default;
}
</style>
<input id="box" type="text" readonly>
`;
function max( x, y ){
return y > x ? y : x;
}
class ClickBox extends HTMLElement {
constructor() {
super();
this.attachShadow( {mode:"open"} );
this.shadowRoot.appendChild( clickBoxTemplate.content.cloneNode(true) );
if( this.hasAttribute( "cycle" ) ){
this._states =
( this.hasAttribute("states") ?
this.getAttribute("states") : "empty true false" ).split( " " );
console.log( this._states );
this._stateNumber = 0;
this._state = this._states[ this._stateNumber ];
let box = this.shadowRoot.querySelector("#box");
let size = this._states.
map(x=>this.hasAttribute(x)?this.getAttribute(x):x).
map(x=>x.length).
reduce( max );
console.log( size );
box.setAttribute( "size", size );
}
}
increment() {
this._stateNumber = (this._stateNumber + 1) % this._states.length;
this._state = this._states[ this._stateNumber ];
}
draw() {
let box = this.shadowRoot.querySelector("#box");
console.log( box );
this.value = this._state;
console.log( this.value );
box.toggleAttribute( "readonly" );
if( this.hasAttribute( this.value ) ){
box.value = this.getAttribute( this.value );
} else {
box.value = this.value;
}
box.toggleAttribute( "readonly" );
box.blur();
}
click( event ){
event.preventDefault();
this.increment();
this.draw();
return;
}
connectedCallback() {
this.shadowRoot.querySelector("#box").addEventListener( "click", (e)=>this.click(e) );
}
disconnectedCallback() {
this.shadowRoot.querySelector("#box").removeEventListener();
}
}
window.customElements.define( "click-box", ClickBox );
--- SoupGate-Win32 v1.05
* Origin: fsxNet Usenet Gateway (21:1/5)