TO DO - Uize.Widget.V2
- Contents
- 1. Implement Next Generation Localization
- 2. Implement New Binding Features
- 3. Possible New Tree-inherited Properties
This is a TO DO document for the Uize.Widget.V2
module.
1. Implement Next Generation Localization
1.1. Locale Strings as State Properties
All locale strings should be represented as state properties.
1.1.1. Type for Locale String State Properties
The values of these locale string state properties can be either string type (in the simple case) or function type (in the case of strings accepting inputs).
1.1.2. Binding Locale Strings to HTML
Represented as state properties, locale strings can be bound to the HTML using the same binding techniques used for binding other state properties.
for locale strings that don't accept inputs, the string state properties can be bound directly to the HTML | |
for locale strings that accept inputs, derived properties can be created that accept state properties inputs and the locale string itself as determinants, and the value of the derived property can be bound to the HTML |
1.1.3. Namespacing of Locale String State Properties
In order to prevent state properties that represent locale strings from competing with other state properties, a naming convention can be used to put them in their own unique namespace.
For example, all locale string state properties could be put under a namespace prefix such as "$", "str_", "loc_", etc.
1.1.4. A Single Locale Strings State Property
As an alternative to representing individual locale strings as separate state property, one could use a single object state property to represent all locale strings.
In order for this to be viable, it would be necessary to support more granular changed events and binding of properties of state property object values to HTML.
1.2. The locale State Property
There should be a locale
state property, whose value should affect the loading a locale strings module for the class.
1.2.1. Locale and Locale Strings Module
Whenever the value of the locale
state property changes, a locale stirngs module should be loaded if necessary (i.e. not already loaded), and the values of the locale strings from the module should be used to set the corresponding locale string state properties on the instance.
The locale
state property should be a tree-inherited property, so that a locale change on a widget is propagated to all its child widgets, which are set by default to inherit the value of the property from the parent. Optionally, any widget can choose to not inherit the parent's value and explicitly set their own.
1.2.2. Locale and Theme
Whenever the value of the locale
state property changes, an optional locale-specific theme CSS module can be loaded.
1.3. Locale String Modules
Locale string modules are organized into a specific folder under a widget's namespace folder by convention, and named according to a convention that incorporates the locale code.
1.3.1. Locale String Modules as Implicit Dependencies
In order to improve the user experience when the UI is rendered, locale string modules can be injected as implicit dependencies by the module system, based upon an environment setting for locale.
This will support both the dynamic loading of locale string modules as dependencies of the widget modules that need them, as well as packaging of the locale string modules along with the widget modules that use them.
1.3.2. Specifying Strings for Variant Selection
EXAMPLE - ICU MESSAGE FORMAT
{gender_of_host, select, female { {num_guests, plural, offset:1 =0 {{host} does not give a party.} =1 {{host} invites {guest} to her party.} =2 {{host} invites {guest} and one other person to her party.} other {{host} invites {guest} and # other people to her party.} } } male { {num_guests, plural, offset:1 =0 {{host} does not give a party.} =1 {{host} invites {guest} to his party.} =2 {{host} invites {guest} and one other person to his party.} other {{host} invites {guest} and # other people to his party.} } } other { {num_guests, plural, offset:1 =0 {{host} does not give a party.} =1 {{host} invites {guest} to their party.} =2 {{host} invites {guest} and one other person to their party.} other {{host} invites {guest} and # other people to their party.} } } }
UIZE FORMAT
invitation host.gender == 'female' num_guests == 0: {host} does not give a party. num_guests == 1: {host} invites {guest} to her party. num_guests == 2: invites {guest} and one other person to her party. else: {host} invites {guest} and {num_guests - 1} other people to her party. host.gender == 'male' num_guests == 0: {host} does not give a party. num_guests == 1: {host} invites {guest} to his party. num_guests == 2: invites {guest} and one other person to his party. else: {host} invites {guest} and {num_guests - 1} other people to his party. else num_guests == 0: {host} does not give a party. num_guests == 1: {host} invites {guest} to their party. num_guests == 2: invites {guest} and one other person to their party. else: {host} invites {guest} and {num_guests - 1} other people to their party.
UIZE FORMAT - ALTERNATE
invitation host.gender == 'female' && num_guests == 0: {host} does not give a party. host.gender == 'female' && num_guests == 1: {host} invites {guest} to her party. host.gender == 'female' && num_guests == 2: invites {guest} and one other person to her party. host.gender == 'female': {host} invites {guest} and {num_guests - 1} other people to her party. host.gender == 'male' && num_guests == 0: {host} does not give a party. host.gender == 'male' && num_guests == 1: {host} invites {guest} to his party. host.gender == 'male' && num_guests == 2: invites {guest} and one other person to his party. host.gender == 'male': {host} invites {guest} and {num_guests - 1} other people to his party. num_guests == 0: {host} does not give a party. num_guests == 1: {host} invites {guest} to their party. num_guests == 2: invites {guest} and one other person to their party. else: {host} invites {guest} and {num_guests - 1} other people to their party.
consider supporting string resources scoped to a conditionalization block (the goal is to allow very flexible construction, with the ability to locally have translated variants of parts / portions of the ultimate translation, but to have those sub-parts still be "in the clear" and outside of programmatic / scripting code) |
2. Implement New Binding Features
2.1. Add Feature for Declaring UI Updaters
Add a class feature that allows uiUpdates to be declared.
uiUpdaters:[ { properties:['width','height','scale'], updater:function () { } }, function (width,height,scale) { } ]
2.2. Add Feature for Declaring Child State Bindings
A way to declare one or more bindings of state properties to child widget state properties.
support one-directional or bi-directional bindings | |
support optional value transformation (in both directions) |
2.3. Add Feature for Declaring UI Wirer
Provide a way to declare the UI wirer for a widget and switch away from old wireUi
approach.
EXAMPLE
_superclass.subclass ({ uiWirer:function (m) { // wiring logic here } });
When the wireUi
method of the Uize.Widget.V2
base class is executed, it will iterate through all the declared UI wirers for the class, from the shallowest base class to the deepest subclass, passing the reference to the instance as the single argument to the wirer functions.
This approach has the following benefits...
2.3.1. No More Safety Wrapping
The code inside the UI wirer function would not need to be wrapped inside a if (m.isWired)
safety check, since this would be taken care of by the wireUI
implementation in the base class.
2.3.2. No More Calling Superclass Wirer
The UI wirer function would not need to call the UI wirer for the superclass, since this would be taken care of by the wireUI
implementation in the base class.
An added benefit of the UI wirer declarative approach is that it would enforce the additive subclassing pattern, so every wirer would count on the fact that the wirers for all shallower classes along the inheritance chain have already been executed by the time that the UI wirer for the current subclass is executed.
2.3.3. Passing the Instance Reference
As an enhancement, the instance reference is passed to the wirer functions as the first argument.
This means that the value of this
doesn't need to be captured with an additional statement to assign it to a local variable, thereby reducing code size and making coding easier.
EXAMPLE
_superclass.subclass ({ uiWirer:function (m) { // wiring logic here } });
The wirer functions would still be called with the instance as context, so the old approach would still be supported as well...
STILL SUPPORTED
_superclass.subclass ({ uiWirer:function () { var m = this; // wiring logic here } });
2.3.4. Old vs New Comparison
OLD APPROACH...
_superclass.subclass ({ wireUi:function () { var m = this; if (!m.isWired) { // wiring logic here _superclass.doMy (m,'wireUi'); } } });
NEW APPROACH...
_superclass.subclass ({ uiWirer:function (m) { // wiring logic here } });
2.4. Consolidating Node and Child Bindings
Is there an elegant way to consolidate bindings for DOM nodes and child widgets, such that...
an implementation could escalate from node to child widget without having to rewrite binding logic | |
two different templates for the same widget could implement something as node or widget, and everything would still work | |
binding could be written in the same way and in the same sections for either nodes or child widgets |
In order for this to work, node IDs and child widget names would need to share the same namespace, which is not something that has previously been required. Also, certain types of DOM node bindings, such as style bindings and innerHTML bindings would not be application to child widget bindings. Only child widget state property and DOM node attribute bindings could be treated as equivalent.
2.4.1. Child Widget Equivalent of Style Object Bindings
Perhaps bindings to the style object could be treated as bindings on the style of a child widget's root node, but this could be quite complicated for rendering of HTML, since the HTML generation for a child widget is opaque to the template for a widget and cannot be easily co-compiled.
Perhaps a more reasonable approach would be to treat bindings to the style object of a child widget as bindings to a style
state property that is implemented in the Uize.Widget.V2
base class and that is bound to the style object of the widget's root node. Then, bindings to a child widget's style object would be propagated through the style
state property of the child widget to its root node's style
property.
3. Possible New Tree-inherited Properties
theme |
|
locale |