UIZE JavaScript Framework

TO DO - Uize.Class

This is a TO DO document for the Uize.Class module.

1. The bind Instance Method

Would provide a convenient way to bind the instance as a context to an instance method and arguments.

INSTEAD OF...

setTimeout (function () {m.hideMenu ()},0);

USE...

setTimeout (m.bind ('hideMenu'),0);

IMPLEMENTATION

var _bind = Uize.nop.bind || function (_context) {
  var
    _args = [].slice.call (arguments,1),
    _function = this
  ;
  return function () {
    return _function.apply (_context,_args.concat (Uize.copyList (arguments)));
  };
};

_class.prototype.bind = function (_method) {
  var
    _context = this,
    _args = arguments
  ;
  _args = _args.length > 1 && [].slice.call (_args,1);
  if (typeof _function == 'string')
    _function = _context [_function]
  ;
  return _args ? _bind.apply (_function,[_context].concat (_args)) : _bind.call (_function,_context);
};

1.1. Impact

Would add about 336 bytes to the size of the Uize.Class module.

The main benefits would be a more elegant semantic for certain situations, and a tiny reduction in code size across the codebase. The savings would only balance out the added weight at large application scale, so the penalty is experienced mostly for smaller apps. Furthermore, most of the benefits would accrue to widget class modules in situations that will be avoided in future by more declarative binding logic. Finally, future versions of JavaScript will bring a bind method for all functions (already present in most modern browsers), and fat arrow syntax would also help in such situations.

In conclusion, besides being kind of neat, there's negative value in adding this feature at this time.

2. Virtual Events

Similar to the system of virtual DOM events.

Virtual events can be parameterized. When multiple handlers are wired for the same virtual event, the setup for the event is shared amongst all handlers.

2.1. Representing Conditions as Virtual Events

2.1.1. The whenever Virtual Event

EXAMPLES

myWidget.wire (
  Uize.Class.virtualEvent ('whenever','theme => theme == "bottle"'),
  function () {
    // do stuff whenever condition is met
  }
);

myWidget.wire (
  Uize.Class.virtualEvent ('whenever',function (theme) {return theme == 'bottle'}),
  function () {
    // do stuff whenever condition is met
  }
);

myWidget.wire (
  'whenever("theme => theme == \'bottle\'")',
  function () {
    // do stuff whenever condition is met
  }
);

2.2. The next Virtual Event

EXAMPLES

myWidget.wire (
  'next("Click")',
  function () {
    // do something for only the very next click
  }
);

myWidget.onNext(
  'Click',
  function () {
    // do something for only the very next click
  }
);

3. Properties Expressions

SYNTAX

propertiesExpressionFUNC = Uize.propertiesExpression (expressionFUNC);

INSTEAD OF...

function (object) {
  return object.get ('width') * object.get ('height');
}

USE...

Uize.propertiesExpression (
  function (width,height) {return width * height};
}

4. Derived Properties

A derived property is a special type of state property whose value is derived from the values of other state properties of the same instance.

EXAMPLE

_class.stateProperties ({
  _allSelected:{
    name:'allSelected',
    derived:'totalSelected,totalItems: totalSelected > 0 && totalSelected == totalItems'
  },
  _oneSelected:{
    name:'oneSelected',
    derived:'totalSelected: totalSelected == 1'
  },
  _someSelected:{
    name:'someSelected',
    derived:'totalSelected: totalSelected > 0'
  },
  _totalSelected:{
    name:'totalSelected',
    value:0
  },
  _totalItems:{
    name:'totalItems',
    value:0
  }
});

In the above example, the allSelected, oneSelected, and someSelected state properties are all derived properties. A state property is indicated as being a derived property by the presence of the derived property in the property profile. The derived property serves both to indicate that a state property is derived, as well to provide the deriver function that indicates from which other state properties the derived property is derived and how to calculate the derived value.

4.1. Implementation Questions

4.1.1. How Are Derived Properties Inherited

Currently, profiles for state properties are inherited through cloning of the definition objects.

If dynamically generated summary information is needed to improve the performance of derived properties, when will this summary information be generated for a class? And how is the information regenerated if it is invalidated by the subsequent declaration of more derived properties.

4.2. Implementation Approaches

4.2.1. Exploding Out the Properties Being Set

With this approach, setting values for derived state properties is worked into the process of setting values for properties that affect derived properties, by exploding out the properties being set to include all affected derived properties.

After setting values for the state properties that are being set explicitly, and before executing onChange handlers for any state properties whose values have changed, the declared state properties are scanned for derived state properties that may be affected by the properties being set explicitly. If any derived state properties are affected by any of the state properties whose values have changed, then values are computed for those derived properties and their values are set. This process is repeated to address state properties that are derived from derived properties whose values may have changed. The process is repeated until there are no longer any derived properties that are affected and that have not had new values computed.

4.2.1.1. Advantages

.

4.2.1.2. Disadvantages

.

4.2.2. Single Level Derived Property Batching

With this approach, values for all directly affected derived state properties are set in a batch set that occurs before onChange handlers are executed for the state properties being explicitly set.

4.2.3. Using onChange Handler Mechanism

With this approach, when a derived state property is declared, an onChange handler is registered with any property from which the derived property is derived.

4.2.3.1. Advantages

uses the existing optimization built into the onChange handlers mechanism
matches the way values for derived state properties are currently being updated

4.2.3.2. Disadvantages

involves a separate set for each derived state property whose value changes
requires management of onChange handlers and dealing with situations where state properties are re-declared

4.2.3.3. Issues to Deal With

4.2.3.3.1. Re-declaring a Non-derived State Property

How does one deal with re-declaring a state property that affects a derived state property?

Currently, everything gets blown away when re-declaring a state property. This means that the onChange handler that was added to the state property at the time of declaring the state property that is derived from it will get blown away, and the relationship of the derived property to the property from which it is derived will get blown away.

4.2.3.3.2. Re-declaring a Derived State Property

How does one deal with re-declaring a derived state property, where the new profile for the derived property defines a different relationship properties from which it is derived?

5. Property Bindings

Provide a way in the Uize.Class base class to bind two state properties together, in order to keep their values synchronized.

This would provide a more concise and lightweight way of binding properties than using an instance of the Uize.Util.PropertyAdapter class.

INSTEAD OF...

Uize.Util.PropertyAdapter ({propertyA:[this,'prop'],propertyB:[slider,'prop']});

USE...

m.bindProperty ('prop',[slider,'prop']);

BENEFITS

The bindProperty instance method would be a core capability of the Uize.Class base class, and all classes would get to benefit from this.
The bindProperty instance method should require a little less code to implement than the Uize.Util.PropertyAdapter class.

NOTES

The bindProperty instance method would support an optional value adapter, just like the Uize.Util.PropertyAdapter class.
The bindProperty instance method would return an array of all the wirings created, so that they could be unwired later.
The bindProperty instance method should ideally be implemented by factoring some code out of the Uize.Util.PropertyAdapter class, and then the Uize.Util.PropertyAdapter class could be reduced in size and made to leverage the bindProperty implementation in the Uize.Class base class.

6. Copy Ability for State Properties

Copy ability, for initial values of state properties that are arrays or objects.

Have a property that can be specified in a state property's profile, which can be used to cause properties whose initial values are object types to be initialized by cloning the initial value rather than simply setting a reference to a shared object.

7. Handle Simple Type in Place of Constructor Properties

Variation on constructor, where specifying a non-object for the properties has the effect of setting the value property.

For example, if Uize.Color were to become a subclass of Uize.Class...

EXAMPLE

Uize.Color ({value:'#ffffff'});  // old form
Uize.Color ('#ffffff');          // new form

Or, in the case of an existing widget class that supports the value interface...

EXAMPLE

Uize.Widget.Bar.Slider ({value:50});  // old form
Uize.Widget.Bar.Slider (50);          // old form

8. Improvements to Property Mechanism

8.1. New Profile Features

8.1.1. type

Can be used by interpolation code (such as fades).

Basic types...

string (coerce with value + '', implicit initial value is '')
boolean (coerce with !!value, implicit initial value is false)
number (coerce with +value, implicit initial value is 0)
date (coerce with new Date (value), implicit initial value is now)

Extended types (ideas for other useful types)...

switch (valid string values for true value, implicit initial value is false)
integer (coerce with Math.round (value))

8.1.2. validator

Different types of validators...

function that can return true or false
regular expression
array of valid values

General ideas / principles for validators...

a validator is a test
a validator may run asynchronously
a validator may compose other validators
if a validation fails, there can be a summuary, and arbitrary details specific to the validation
support for read-only properties (how would that work, exactly? Only settable through private name?)
problem: there's currently no way to use the set method to set the value for a state property to undefined. This is lame. The original reason for this had to do with the optimizing performance for the very first set during construction. This behavior is beneficial for state properties that have no initial value (what percentage of the overall is that?).

9. constructed Property

to indicate that the instance has been constructed
can be used by onChange handlers for state properties to conditionalize actions
particularly compelling to widgets, since being completely constructed is a good indicator child widgets added during construction exist and can be accessed
some classes may already be doing this with their own private properties

10. Originator of a Set

The originator of a property set knows that the property is being set, so doesn't want to be informed of a change in the value?

A way to provide an ID for the originator of a set? The basic ongoing problem is when multiple sources want to be able to change and also be informed of changes in a particular property. How does one make this more efficient and eliminate multiple redundant execution triggered by events?