ArnoldSmith86 / virtualtabletop

a virtual surface in the browser on which you can play board, dice and card games
https://virtualtabletop.io
GNU General Public License v3.0
168 stars 31 forks source link

Make Complex Objects Easier to Use #1605

Open 96LawDawg opened 1 year ago

96LawDawg commented 1 year ago

Something like the following could possibly be made to work:

{
  "func": "SET",
  "collection": [ "widgetID" ],
  "property": "cardDefaults.color",
  "value": "#00767a"
}

Would be nice if it could work for other complex objects such as CSS as well. Although that one might be harder. For something like

"css": {
    "default": {
      "background": "white",
      "font-size": "25px"
    }
  }

would the property be css.default.background or something else?

ArnoldSmith86 commented 1 year ago

css.default.background sounds right to me. And we should make ${PROPERTY css.default.background OF widgetID} work as well and make GET support the same syntax.

RaphaelAlvez commented 1 year ago

Sometimes we suggest something that seems to obvious but we just didn't think before.

Yes this would perfect to have

ArnoldSmith86 commented 1 year ago

For the first example:

Agree?

96LawDawg commented 1 year ago
  • If the widget has a property called cardDefaults.color, it should SET/GET that one. Even if it also has a property cardDefaults.

Yes. Never used periods in my property names, but a specific property name has priority over a nested object name.

  • If it has a property cardDefaults which is not an object, it should SET/GET the property cardDefaults.color instead.

Not sure about this one. Probably yes for the same reason as above and if you convert it to an object through the SET, you might screw up a bunch of other things.

  • If it has a property cardDefaults which is an object but doesn't have key color, a SET should create that key (and a GET return null or whatever it normally returns).

Yes.

RaphaelAlvez commented 1 year ago

For the first example:

  • If the widget has a property called cardDefaults.color, it should SET/GET that one. Even if it also has a property cardDefaults.
  • If it has a property cardDefaults which is not an object, it should SET/GET the property cardDefaults.color instead.
  • If it has a property cardDefaults which is an object but doesn't have key color, a SET should create that key (and a GET return null or whatever it normally returns).

Agree?

In general I think it should behave exactly like in JS no matter if it is undefined or not.

ArnoldSmith86 commented 1 year ago

But people might have used dots in their properties. So we would break those.

RaphaelAlvez commented 1 year ago

But people might have used dots in their properties. So we would break those.

We can decide they shouldn't

ArnoldSmith86 commented 1 year ago

Not retroactively.

RaphaelAlvez commented 1 year ago

Not retroactively.

File updater?

ArnoldSmith86 commented 1 year ago

For example in css you use .scoreboard .totalsLine as a key. Can't file updater that..

ArnoldSmith86 commented 1 year ago

That would be ${PROPERTY css..scoreboard .totalsLine OF widgetID}. Sounds non-trivial to resolve that.

ArnoldSmith86 commented 1 year ago

For the ${PROPERTY...} syntax we can enforce whatever we want because it doesn't allow a . in there atm.

For GET and SET, we could do something like this (introducing subproperty (or nestedproperty?) instead of using property):

{
  "func": "SET",
  "collection": [ "widgetID" ],
  "subproperty": "cardDefaults.color",
  "value": "#00767a"
}
mousewax commented 1 year ago

Would sub/nestedproperty allow more than one level of depth like we use in CSS?

Maybe introduce it along side of property?

{
  "func": "SET",
  "collection": [ "widgetID" ],
  "property": "cardDefaults",
  "subproperty": ".color",
  "value": "#00767a"
}

or

{
  "func": "SET",
  "collection": [ "widgetID" ],
  "property": "cardTypes",
  "subproperty": "Card1.color",
  "value": "#00767a"
}
ArnoldSmith86 commented 1 year ago

Is it even possible to edit css[".scoreboard .totalsLine"].color using routines atm?

ArnoldSmith86 commented 1 year ago

Or maybe

{
  "func": "SET",
  "collection": [ "widgetID" ],
  "property": "cardTypes",
  "subproperty": [ "Card1", "color" ],
  "value": "#00767a"
}

? That would make dots in names way easier to handle.

And for ${PROPERTY ...} we simply don't support dots in key names at all so ${PROPERTY a.b.c} would always index object a and a.b.

mousewax commented 1 year ago

I feel like this should just be rolled into property proper. Similar to to how inheritFrom can take either, but this looks like a list even though it's traversing an object.

{
  "func": "SET",
  "collection": [ "widgetID" ],
  "property": ["cardTypes", "Card1", "color"],
  "value": "#00767a"
}
ArnoldSmith86 commented 1 year ago

but this looks like a list even though it's traversing an object

Yeah, seeing that, you might expect that it would set the value to each of the properties cardTypes, Card1 and color.

Edit: I still kinda like it though.

mousewax commented 1 year ago

Replace the commas with periods and no spaces and I think it would be fine.

{
  "func": "SET",
  "collection": [ "widgetID" ],
  "property": ["cardTypes"."Card1"."color"],
  "value": "#00767a"
}

(I wanted to suggest arrows and no square brackets but I think those might suggest something else and I'd like it to be consistent.)

  "property": "cardTypes"->"Card1"->"color",
robartsd commented 1 year ago

Replace the commas with periods and no spaces and I think it would be fine.

{
  "func": "SET",
  "collection": [ "widgetID" ],
  "property": ["cardTypes"."Card1"."color"],
  "value": "#00767a"
}

(I wanted to suggest arrows and no square brackets but I think those might suggest something else and I'd like it to be consistent.)

  "property": "cardTypes"->"Card1"->"color",

Although I like the syntax, these aren't valid JSON; so we'd have to change the parser completely.

robartsd commented 1 year ago

Or maybe

{
  "func": "SET",
  "collection": [ "widgetID" ],
  "property": "cardTypes",
  "subproperty": [ "Card1", "color" ],
  "value": "#00767a"
}

? That would make dots in names way easier to handle.

And for ${PROPERTY ...} we simply don't support dots in key names at all so ${PROPERTY a.b.c} would always index object a and a.b.

This would work. If we extend GET and SET, it will always be possible to handle difficult keys.

What about square bracket notation in strings? ${PROPERTY css['.scoreboard .totalsLine']['color']}?

robartsd commented 1 year ago

Somewhat related #139

mousewax commented 1 year ago

I am on board with square bracket notation!

robartsd commented 1 year ago

Currently variables can be indexed 1 level (var foo.bar and var foo.$bar work but not var foo.bar.1). Properties and widgets can be selected with variables (but not by indexed values within variables: ${PROPERTY $foo OF $bar} works but not ${PROPERTY $foo.$bar OF $widget.0}).

I'm thinking that variable indexing should be processed recursively with both dot and bracket notation allowed interchangeably (var foo.$bar['some index'] or var foo['some index'].$bar). Dot style index notation could be allowed within square bracket indexes var myVar[$foo.bar]; but nested brackets would not be allowed (var myVar[$foo[bar]] would not work).

For properties, I think square bracket indexing should refer to indexing of the property and Dot style indexing should only be allowed on variables. {PROPERTY $foo.$bar[1]} would resolve variable $bar, use it to retrieve an indexed value of variable $foo, use the the value retrieved from $foo as a property name, then retrieve index 1 of the widget property. An alternative would be to allow dot style indexing of property indexes, but require square brackets to retrieve the property name from a variable index {PROPERTY [$foo.$bar].1}.

96LawDawg commented 1 year ago

Well, if that is possible, that would be a reason to hold off on #1608 and its awkward structure.

robartsd commented 1 year ago

Well, if that is possible, that would be a reason to hold off on #1608 and its awkward structure.

GET still has the advantage of retrieving properties from a collection of widgets (and returning an aggregated value or array).

robartsd commented 1 year ago

I'm also not sure what should happen on the left hand side if an intermediate index in undefined (on the right hand side as soon as as the value at an index is encountered, undefined is returned).

ArnoldSmith86 commented 1 year ago

This is actually only partly resolved.