UIZE JavaScript Framework

TO DO - General

This document lists to do tasks that relate to the UIZE JavaScript Framework in general - not relating to the documentation or the site (see TO DO - Documentation), or specific JavaScript modules (see TO DO - Modules).

1. Split UIZE Core and UIZE Web Site

Split out the UIZE core and UIZE Web site code into two separate repositories.

the UIZE Web site will build like any other site that uses UIZE
after the split, there will be two repos - one for the UIZE JavaScript Framework and one for the UIZE Web aite
the split should be done in such a way as the full revision history is retained for files in both of the two new repos
perhaps this would be the right time to create a new "uize" project for the core (as opposed to the current and slightly clumsy "UIZE-JavaScript-Framework"), so then we could have: uize and uize-site

1.1. Update Documentation

Documentation in the UIZE site should be updated appropriately to reflect the new structure, including...

setup reference docs
reference docs that mention that the repo contains a full Web site with examples

1.2. Improved Development Discipline

Creating a separate repo for the Web site would reinforce discipline around how changes to the UIZE core are made.

It would no longer be so easy to make changes across the core and Web site code in a single refactoring operation. So, treating the UIZE Web site as a true user of the framework, separate from the core code, will help to encourage more thoughtful evolutionary changes to the framework.

REFERENCE

https://confluence.atlassian.com/bitbucket/split-a-repository-in-two-313464964.html

2. Migrate Modules Into Deeper Namespaces

Migrate some modules at the root Uize namespace into deeper namespaces in order to tuck them away.

Uize.Tooltip  ->  ???
Uize.Xml      ->  ???

3. Localization

3.1. Defaulting Missing Translations

3.1.1. Questions

is it appropriate to default missing strings to the primary language counterparts, or should they remain empty?
if missing strings are defaulted, should they be wrapped in some way to indicate that they have been defaulted, for the sake of development, QA testing, linguistic QA, etc.
should defaulting / fallback be a configurable behavior?
should the defaulting approach be different for different environments / situations (dev vs production)?
should defaulting be handled by a project's own build process, or can it be handled by the localization service? Is defaulting a service that can be made available to a project's own build process?

3.1.2. Ways to Handle Missing Strings

they remain blank
they are defaulted to the key
they are defaulted to the primary language value (e.g. fr-CA -> en-US)
they are defaulted to a fallback language's value (e.g. fr-CA -> fr-FR)
they are defaulted using a cascade of fallback languages' values, which may include the primary language (e.g. fr-CA -> fr-FR -> fr-CH -> en-US)
they are optionally wrapped with an indicator that they have been defaulted

3.2. System for Discouraging Concatenation

Develop an approach that discourages developers from concatenating resource strings together.

At the very least

make it hard / uncomfortable to perform concatenations (force the developer to jump through some hoops)
make it easy to scan for concatenations using static analysis
produce warnings or errors at runtime when concatenations are performed in lazy ways

The basic principle of the proposed approach is that the binding logic that displays text to the user by binding data to the UI requires that the strings be "blessed" by localization code.

3.2.1. Resource strings, as obtained from the resource files, are "blessed".

Represented as functions, blessing the resource strings would involve assigning a special property on the functions that the UI binding code would check for.

3.2.2. Resource strings cannot be programmatically concatenated

This is accomplished by making the strings functions, so that concatenating the functions would invoke the toString implicit method to serialize the functions and it would be obvious immediately to the developer that they can't do that.

Similarly, attempting to call String methods on the resource strings would fail. The only way to fool the system would be to call the functions, concatenated the results, and then wrap the result in a function that returns that result and is blessed by assigning the special property on the function. This is something that would be easy to scan for in static analysis of the code, so it would be easy to audit the code for cheats.

3.2.3. Compile-to-objects Approach

When the resource strings are compiled, they are compiled to objects that implement the valueOf and toString methods in such a way as to throw an error when invoked - this is to discourage simple use of resource strings in expressions like concatenations.

In order to use a resource string in an expression, the developer would have to call a specially named method on the resource string, and such instances in the code would be easy to detect for during static analysis of the code. This makes it much easier to audit the code in order to review cases where resource strings are being used in ways that are recommended against.

EXAMPLE

var resourceStringsInExpressionsBehavior = 'error'; // 'error' | 'warning' | ''

function ResourceString (value) {
  this.value = value;
}

ResourceString.prototype.valueOf = ResourceString.prototype.toString = function () {
  if (resourceStringsInExpressionsBehavior == 'error') {
    throw new Error ('Resource strings must not be used directly in expressions.');
  } else {
    if (resourceStringsInExpressionsBehavior == 'warning') {
      console.warn ('Resource strings must not be used directly in expressions.');
    }
    return this.value;
  }
};

ResourceString.prototype.resolveResourceString = function () {
  return this.value;
};

var
  stringA = new ResourceString ('This is a '),
  stringB = new ResourceString ('resource string')
;

stringA + stringB;

3.2.3.1. Implications

There are two ways that a developer can use a resource string...

they can pass a reference to the resource string to a method that will process the resource string by calling the appropriate method on the string object
they can call the appropriate method on the string object themselves in order to resolve it

Generally, the developer should not often need to explicitly resolve resource strings themselves, since this should be centralized in the framework's binding mechanism.

4. Eliminate All Extension Modules

Eliminate all extension modules and replace them with either helper objects containing purely static methods or mixin modules.

4.1. Extensions as Anti-Pattern

Extension modules, like plugins, can be considered an anti-pattern because loading them has side effects on other loaded modules.

In that sense, they are not isolated. The side effects of loading an extension module are deliberate and are their one benefit, but this pattern causes several problems...

4.1.1. Interoperability Issues

Extension modules can cause problems of interoperability, since shared modules are affected.

The effect is much like that of setting global variables or modifying the prototypes of built-in objects. There is no guarantee that two different extension modules won't have interactions / conflicts.

4.1.2. Dependency Management Issues

Extension modules can cause problems of dependency management in two key ways...

4.1.2.1. Dependencies are Unclear from Code

Since an extension module affects an object or class other than itself, it can be unclear from viewing code that the code has a dependency on an extension module.

There may be a call to an instance method of an instance of a class, but that method may not be defined in the class but actually in an extension module that modifies the class.

4.1.2.2. Modules Use Stuff That is Found Lying Around

Since an extension module modifies a class or object that is shared and may be in use by other modules, that modified class or object may then appear to have features to the code in other modules that that code isn't aware is defined in an extension.

Code in other modules may just discover instance methods (through an IDE's code auto-complete feature, for example) that are "lying around" and start using them, without realizing that the dependency on the extension module also needs to be declared in the module's code. Then, if that module is used in a different context where the extension module hasn't been required, the module's code can fail at runtime under some specific condition where the methods that would have been added by the extension module are called.

4.1.3. Code Analysis Problems

Since extension modules affect objects or classes other than themselves, they can cause problems for code analysis because they can make modules appear to define more features than they actually do.

If a class module is loaded, then an extension module is loaded that modifies that class, and then a subclass module is loaded, if that subclass is examined for features, it will appear to define features that are not actually defined by it, but were in fact defined by the extension module that modified its base class. This can complicate the task of code analysis to perform feature discovery. Features added by extension modules are mis-attributed.

4.2. Extension Modules to Eliminate

5. Code Size Optimization

5.1. Lightweight JSON Module

Implement lighter weight JSON module.

It's time. There are now enough clients that support the built-in JSON object that it's time to create a lightweight, non-pretty print serializer and parser for JSON objects that can be used in modules where control over formatting is not needed.

5.2. Improved Module Declaration Semantics

5.2.1. Module Declaration Short Form

Support a new short form for module declaration as an alternative to the object form.

INSTEAD OF...

Uize.module ({
  name:'MyNamespace.MyModule',
  required:[
    'RequiredModule1',
    'RequiredModule2'
  ],
  builder:function () {
    // build and return the module
  }
});

USE...

Uize.module (
  'MyNamespace.MyModule',
  [
    'RequiredModule1',
    'RequiredModule2'
  ],
  function () {
    // build and return the module
  }
);

OR...

Uize.module ([
  'MyNamespace.MyModule',
  [
    'RequiredModule1',
    'RequiredModule2'
  ],
  function () {
    // build and return the module
  }
]);

5.3. Migrate or Remove Features

Look at migrating some lesser used features out of core modules into new / other modules.

5.3.1. Uize.Widget

Specific features to be decided.

5.4. Tougher to Accomplish

5.4.1. Pure Namespace Modules at Second Level

Try to make all modules at the second level purely namespace modules.

Current violators...

Uize.Fx
Uize.Data
Uize.Date

The above modules include code that then becomes baggage for all modules under those namespaces.

6. Folder Organization of JavaScript Modules

Support the ability to have JavaScript modules optionally organized inside folders, rather than all being in a flat list inside a single folder.

6.1. Proposed Solution

A means will be provided to specify one or more namespaces, under which all modules will be organized by folder rather than in a flat list.

For all modules not under the specified folder organization namespaces, modules will be organized in a flat list. It will not be possible to mix different organization types at different levels along a module namespace path. For, for instance, if all modules under the namespace Foo.Bar are configured to be organized by folder, then it will not be possible to have modules under the namespace Foo.Bar.Baz.Qux be organized by flat list.

6.1.1. Folder Organization is the Future

It is believed that folder organization of all modules in a codebase is generally the preferred approach going forward.

Therefore, supporting folder organization only for configured namespaces is primarily a migration strategy in order to support backwards compatibility with existing codebases while the migration is performed over time.

6.1.2. Finding Modules

All places in the code where locations of modules are calculated will need to be updated in order to support configurable folder organization of modules under specific namespaces.

Some of the places that will be affected include...

6.1.2.1. Dynamic Module Loader

.

6.1.2.2. File Builder

.

6.1.3. Module Resources

Modules that have dependencies on resources such as images and want to generate paths to those resources inside their implementation code should use the Uize.Class.pathToResources property.

The value of the Uize.Class.pathToResources property is calculated for each module to take into account whether or not the module is under a namespace that uses folder organization.

7. Eliminate Private Methods As Properties

In all modules in the UIZE codebase, eliminate all private instance and static methods in favor of functions that get passed the context as the first argument.

NOTES

update guide documentation on classes, inheritance, feature declaration, and such to no longer recommend defining private methods as "_" prefixed properties on the instance or class
there will be a few cases where private instance methods are provided as onChange handlers for state properties - these will have to be left as is, and if they are also called on this, then they will have to be called using the call or apply methods

8. Possible New Namespaces

Uize.Crypto

9. Code to Factor Out

Code to factor out of widget classes into non-Web specific modules...

Uize.Widget.Drag - the Uize.Widget.Drag.insertShield and Uize.Widget.Drag.resizeShield static methods should maybe be factored out into a generic shield module (possibly a package module under the Uize.Dom namespace)
Uize.Widget.ImagePort - the Uize.Widget.ImagePort.getScaledRect and Uize.Widget.ImagePort.getSizingAndAlign static methods have been factored out into the Uize.Math.LogicalPos module, so they should now be deprecated in the Uize.Widget.ImagePort module
Uize.Widget.Population - pure population string functionality should be migrated into a new Uize.Str.Population module (or Uize.Template.Population?)
Uize.Widget.Tree - model stuff for the data structure that represents a tree (Uize.Data.Tree?)

Solve the problem of some widget classes being used only for their static methods and not their full functionality. Perhaps some helper method functionality should be separated out into packages that can be used outside of the context of widgets. As a general rule, if some functionality might be useful without widgets being involved, then it should be implemented in a separate package module.

Uize.Widget.Page - the Uize.Widget.Page.launchPopup static method

10. General Drag and Drop Framework

Virtual dom events to mimic new HTML5 dnd events.

11. Iterator Interface

11.1. Instance Methods

first - rewinds the iterator to the beginning and returns the value for the first iteration
next - advances to the next iteration and returns the value for the iteration
advance - advances to the next iteration, if possible, and returns a boolean indicating success
rewind - rewinds the iterator, so that calling next will return the value for the first iteration
reset - synonymous with rewind
forEach - executes the entire iteration, calling the specified iteration handler function for each iteration
end - ends the iteration, after which calling hasNext will return false

11.2. Instance Properties

value - the value for the current iteration
current - synonymous with value
key - the key / index for the current iteration
ended - a boolean, indicating whether or not the iteration has ended

11.3. Usages

EXAMPLE

for (var currentSum = series.first(); !series.ended; currentSum = series.next();) {
  // do stuff
}

EXAMPLE

var currentSum;
while (series.advance()) {
  currentSum = series.value;
  // do stuff
}

11.4. Uize.Iterator

The Uize.Iterator object implements the iterator interface.

11.4.1. As a Wrapper

A Uize.Iterator object can be instantiated as a wrapper around a number of different source values.

11.4.1.1. Wrapping a Number

.

11.4.1.2. Wrapping an Array

.

11.4.1.3. Wrapping an Object

.

11.4.1.4. Wrapping a JavaScript Iterator

.

11.4.2. Modules Supporting Iterators

Several UIZE modules provide built-in support for the Uize.Iterator class.

For example, the Uize.Fade module supports wrapping a Uize.Fade value series as an iterator.

Uize.Data.Combinations
Uize.Str.Lines
Uize.Color.Util
Uize.Curve

11.4.3. Iterator Modifier Function

A function, in the spirit of a curve function modifier, that returns an iterator function that is a modification of the source iterator function (or the source resolved to an iterator function).

An iterator modifier function can accept a source that is not an iterator object, which will first be resolved to an iterator object.

Examples of iterator modifier functions...

Uize.Iterator.map - the new iterator produces every value from the source iterator, transformed through a specified value transformer
Uize.Iterator.filter - produces an iterator with only those iterations whose values pass the specified value matcher
Uize.Iterator.stretch - stretches out the number of iterations by either repeating or interpolating between the values in the original iterator function
Uize.Iterator.slice - produces an iterator that includes only the specified slice of iterations from the source iterator
Uize.Iterator.sliceByMatch - produces a slice of the source iterator, where the first and last iterations are determined by specified value matchers
Uize.Iterator.concat - produces a new iterator by concatenating multiple iterators
Uize.Iterator.conflate - takes multiple source iterators and produces a new iterator where the value for each iteration is generated by the specified function that takes the values from all the source iterators as its input
Uize.Iterator.nest - produces an iterator where for each iteration of an outer source iterator, an inner "nested" iterator is iterated over, where the inner iterator is provided the value of an iteration of the outer iterator as a seed value, and where the resulting iterator returns the values from the nested iterator
Uize.Iterator.cycle - produces an iterator where the specified source iterator is cycled through the specified number of times
Uize.Iterator.interleave - produces an iterator by interleaving multiple source iterators together (i.e. where each iteration alternates through the specified source iterators)

12. Safe Privates

A new system to support safe private properties and methods - for both instance as well as static private properties and methods.

EXAMPLE

/*** create variables for mapping between pretty name of privates and generated names ***/
  var
    _myProperty = _class.priv ('myProperty'),
    _myMethod = _class.priv ('myMethod')
  });

_class.declare ({
  instanceProperties:Uize.pairUp (_myProperty,'initial value'),
  instanceMethods:Uize.pairUp (_myMethod,function () {/* method implementation */})
});

alert (this [_myProperty]); // accessing instance property
this [_myMethod] ();        // calling instance method

ISSUES

all accesses and assignments of privates involve an additional variable lookup step, and dereferencing with the result of an expression (so, some precompilation benefits are lost)
"lookup" of private names involves accessing variables in a higher scope than point of access, so performance cost
names must be generated for all privates, which adds setup code
makes it a little bit harder to do impromptu assignments of privates
accessing state properties via their private names becomes rather inconvenient, and their private names must be registered in an extra step

QUESTIONS

how does one provide private names for state properties? Provide an example.
should multiple calls to the priv method on the same class for the same named private always return the same result? If so, this would suggest that external code could probe around and easily discover the internal name for a private.
how is the mapping / registry of privates for a class inherited by a subclass? Does it have to be?

13. Rethinking Module Definitions

13.1. Using a Provide-Need Pattern as Foundation

13.1.1. In Essence

the needer specifies the criteria for what is needed
from the registered providers, a provider is selected that can best satisfy the need
the chosen provider sees if anything is already cached that matches the need
if something is cached, the provider passes it on to the needer
if nothing is cached, then...
the provider goes about obtaining something that matches the need
the provider caches the thing that it obtained, for the benefit of others that may have matching needs
the provider passes the needed item on to the needer

13.1.2. Other Patterns That Can Be Modeled on Provide-Need

13.1.2.1. Needing an Instance

An instance provider would be given criteria for the instance needed, such as class module, initial / constructor properties, etc.

The provider registered for providing instances would in turn need the class module for a specific instance that is needed.

13.1.2.2. Needing a Session

Code that needs the user to be logged in and to have a session could use a provide-need pattern, where a registered provider for session would go about prompting the user to log in.

Uize.provide (
  {type: 'module', org: 'Uize'},
  function (needed, deliver) {
    // code here to load Uize modules
  }
);
Uize.provide (
  {type: 'module', org: 'MyCompany'},
  function (needed, deliver) {
    // code here to load MyCompany modules
  }
);
Uize.providers
Uize.need (
  {type: 'module', org: 'Uize', name: 'Uize.Widget'},
  function (Uize_Widget) {
    // now we can use the Uize.Widget class
  }
);

13.2. Uize.module And Uize.require as Syntactical Sugar

Uize.module ({
  org: 'MyCompany',
  name: 'MyCompany.Foo.Bar',
  builder: function () {
    // build and return the module
  }
});
Uize.require (
  {
    org: 'MyCompany',
    name: 'MyCompany.Foo.Bar'
  },
  function (MyCompany_Foo_Bar) {

  }
);
Uize.require(
  'MyCompany:MyCompany.Foo.Bar',
  function () {
  }
);

14. Version Support in Module Mechanism

14.1. Requirements

14.1.1. Support the following...

ability to have multiple versions of UIZE on the same page
ability to have different versions of the same module on the same page
ability for modules to have dependencies on specific versions of other modules
it must still be possible for a module to declare itself and then be available as a required module for other modules that are subsequently declared in the same scope

14.2. - possible approach...

VARIATION 1

Uize.module ({
  name:'MyNamespace.MyModule',
  required:[
    'Uize.Curve',     // end up getting version 2, let's say
    'Uize.Curve.Mod'  // end up getting version 3, let's say
  ],
  builder:function (_superclass,m) {
    // referencing required modules inside this scope...
    m ('Uize.Curve')...
    m ('Uize.Curve.Mod')...
  }
});

VARIATION 2

Uize.module ({
  name:'MyNamespace.MyModule',
  required:{
    _Uize_Curve:'Uize.Curve',         // end up getting version 2, let's say
    _Uize_Curve_Mod:'Uize.Curve.Mod'  // end up getting version 3, let's say
  },
  builder:function (_superclass,m) {
    // referencing required modules inside this scope...
    m._Uize_Curve ()...
    m._Uize_Curve_Mod ()...
  }
});

14.3. - declaring information about a module variation

EXAMPLE

Uize.module ({
  name:'Uize.Widget.FooBar',
  version:'2',
  builder:function (_super,m) {
    // build the module
  }
});

14.4. - requiring specific versions of modules...

VARIATION 1

Uize.module ({
  name:'MyNamespace.MyModule',
  required:[
    'Uize.Curve[2]',      // require version 2 of this module
    'Uize.Curve.Mod[3-]'  // require version 3 or higher of this module
  ],
  builder:function (_superclass,m) {
    // referencing required modules inside this scope...
    m ('Uize.Curve[2]')...
    m ('Uize.Curve.Mod')...
  }
});

VARIATION 2

Uize.module ({
  name:'MyNamespace.MyModule',
  required:{
    _Uize_Curve:'Uize.Curve[2]',          // require version 2 of this module
    _Uize_Curve_Mod:'Uize.Curve.Mod[3-]'  // require version 3 or higher of this module
  },
  builder:function (_superclass,m) {
    // referencing required modules inside this scope...
    m._Uize_Curve ()...
    m._Uize_Curve_Mod ()...
  }
});

14.5. - requiring a variation of a module using a custom match...

EXAMPLE

Uize.module ({
  name:'MyNamespace.MyModule',
  required:{
    _Uize_Curve:{
      name:'Uize.Curve',
      version:/^2.[1|2](\..*)?$/  // require versions 2.1 and subversions, or 2,2 and subversions
    }
  },
  builder:function (_superclass,m) {
    // referencing required modules inside this scope...
    _Uize_Curve ()...
  }
});

14.6. In a Nutshell

modules declare themselves and provide meta data (such as version number) that can be used to uniquely identify / disambiguate the module when requiring the module in other modules
when a module requires another module, it can provide additional information over and above the required module's name that can be used to identify the module, should multiple variations of the required module be loaded concurrently
when a module is declared, all information identifying the module is stored in a global registry. Different variations of the same named module can be loaded concurrently, and the identifying information

NOTES

it should be possible to use multiple versions of the framework at the same time
two variations of the same named module cannot be loaded in the same scope and have all the same other identifying information (such as version)
specifying a version number in the module name string is a shorthand way of specifying both a name and version properties

14.7. Ideas

it should be possible to load a module and have the module be defined without actually building it
it should be possible to determine all the modules that have been loaded
building a module should not have side effects outside of the definition of the module, such that building a module but not accessing it can affect the way other code behaves in such a way that other code relies upon those side effects and it becomes impossible to defer the building of the module until the first access to it without breaking code

14.8. Module Registry

14.8.1. Querying the Module Registry

Discovering the Loaded Modules

14.8.1.1. Getting a Module Profile

After a module has been loaded, the module registry can be queried to obtain a profile for the loaded module - even before the module has been built.

Obtaining a module profile for a module is done by calling the getProfile method on the module registry, as follows...

EXAMPLE

Uize.modules.getProfile ('Uize.Widget.Page');
14.8.1.1.1. Module Profile is Persisted

After a module has been built, it is still possible to query the module registry to get the profile for the module in order to find out more about it.

The name, superclass, required list, version, etc. are all persisted in the module registry. In the case of a class module, the profile for a module is assigned to the moduleProfile property of the module, so it is not necessary to use the module registry interface. However, in the case of a module where it is not appropriate to stitch in properties (such as data modules), getting a module profile must be done through the module registry interface.

14.9. Module Meta Data

EXAMPLE

Uize.module ({
  name:'Uize.Widget.FooBar',
  version:'2',
  experiment:'performance-optimized',
  builder:function (_super,m) {
    // build the module
  }
});

14.10. Loading of Modules

14.10.1. General principles

it is not the responsibility of the code requiring a module to specify how the module should be obtained
when a module is obtained, "where" is merely a qualifier to how, and how the location is specified will depend on the method of retrieval

14.10.2. Loader Configuration

Configuration of the module loading mechanism is independent of how modules are declared or required and is environment specific.

EXAMPLE 1

Uize.module ({
  name:'Uize.Widget.Droplist',
  superclass:'Uize.Widget',
  required:{
    _Uize_Widget_PopupPalette:'Uize.Widget.PopupPalette[2.*]',
    _Uize_Widget_FormElement:'Uize.Widget.FormElement'
  },
  builder:function (_superclass,m) {
    /*** Class Constructor ***/
      var
        _class = _superclass.subclass (
          _null,
          function () {
            this.addChild ('popupPalette',m._Uize_Widget_PopupPalette ());
            this.addChild ('input',m._Uize_Widget_FormElement ());
          }
      ;

      return _class;
  }
});

EXAMPLE 2

Uize.module ({
  name:'Uize.Widget.Droplist',
  superclass:'Uize.Widget',
  required:[
    'Uize.Widget.PopupPalette',
    'Uize.Widget.FormElement'
  },
  builder:function (_superclass,m) {
    /*** Class Constructor ***/
      var
        _class = _superclass.subclass (
          _null,
          function () {
            this.addChild ('popupPalette',m ('Uize.Widget.PopupPalette'));
            this.addChild ('input',m ('Uize.Widget.FormElement'));
          }
      ;

      return _class;
  }
});

14.11. Module Variations

14.11.1. Variations vs Versions

The system should generally support the notion of a variation of a module, rather than specifically versions.

Versions are a narrower application of the more general variation system.

14.11.2. Variation File Naming

In order for multiple variations of the same module to coexist alongside one another in the file system, the different variations must have different filenames.

While a required module qualifier can provide matching criteria that can be used to test if an existing loaded variation of the module matches the criteria, an explicit fallback must be specified in the event that no matching variation can be found in the currently loaded modules.

14.12. Module Specifier

A module specifier identifies a specific module, by name alone, or by a combination of name and an additional variation qualifier.

14.13. Variation Qualifier

A variation qualifier is a specialized kind of value matcher that is applied to all loaded modules to find a module that matches certain criteria.

14.13.1. Variation Qualifier for Specifying Version

In the simplest form, a variation qualifier can be used to indicate an acceptable version or versions for a module.

EXAMPLE

Uize.module ({
  name:'MyNamespace.MyModule',
  required:{
    _Uize_Curve:{
      name:'Uize.Curve',
      version:/^2.[1|2](\..*)?$/  // require versions 2.1 and subversions, or 2,2 and subversions
    }
  },
  builder:function (_superclass,m) {
    // referencing required modules inside this scope...
    _Uize_Curve ()...
  }
});

14.14. Issues to Address

if one has a reference to a module, such as in a tool like the Delve tool, how does one determine what the filename of a module is for the purpose of linking to reference documentation?
if a variation qualifier is used to indicate a very specific variation of a module, and if that variation is not yet loaded, how does the module loader mechanism know where to obtain a variation that matches the criteria of the variation qualifier?

15. JavaScript Language Unit Tests

Implement unit tests for all features of the JavaScript language.

15.1. For In Loops And Undefined Array Elements

In several versions of Microsoft's JScript interpreter, if an array is initialized using the literal syntax (i.e. ['value 1','value 2','value 3']), then any element whose value is initialized to undefined will not be encountered in a for...in loop.

EXAMPLE

var
  keysHash = {},
  myArray = ['foo',undefined,'bar']
;
for (key in myArray) {
  keysHash [key] = true;
}
alert (keysHash [1]);

In the above example, the alert statement would alert the value undefined in interpreters that exhibit the problematic behavior. This behavior could cause problems when using a for...in loop to compare arrays to see if their elements and custom properties are identical.

A test can be written for this issue as follows...

TEST

var _hasIssueWithForInLoopsAndUndefinedArrayElements = true;
for (var _key in [undefined]) {
  if (_key == 0)
    _hasIssueWithForInLoopsAndUndefinedArrayElements = false
  ;
}

16. Function Argument Validation

Provide a facility that can optionally be used for function argument validation.

An easy way to define validator logic that can be used to validate the arguments of a function call. It sounds kind of like a test, so maybe some convenience features to allow easily creating an arguments test.

16.1. Method Signature Validation as Optional Layer

Possibly a way generally to have method signature validation as a separate optional layer of code.

16.1.1. As a Separate Module

Maybe a separate module that can accompany the main module?

16.1.2. Validation Code Inside the Main Module

Maybe the validation code is inside the main module, but can be optimized / compiled out for scrunched production code?

There are some benefits to the validation code being inside the main module's implementation. A traditional approach here would be to have a compiler flag / directive that could affect whether or not the validation is included / enabled.

17. Client Services

unit conversion (possible to implement this on the client side, but might be appropriate to migrate such a service to server side at some stage, and in such a case it would be desirable to allow for such a migration in a way that doesn't heavily impact the code using such a service)
myWidget.ajax | myWidget.service
Uize.Widget.Page.MySite subclass implements performAjax
myWidget.ajax ({action:'convert',fromUnit:'inches',toUnit:''})

17.1. Example 1

BEFORE

myWidget.callInherited ('ensureLoggedIn') (function () {});

AFTER

myWidget.ajax ({service:'login'},function () {});

// or...

myWidget.service ('login',function () {});

17.2. Example 2

BEFORE

myWidget.callInherited ('enableProfile') (function () {});

AFTER

myWidget.ajax ({service:'enableProfile'},function () {});

or...

myWidget.service ('enableProfile',function () {});

17.3. What All Can Services Replace or Do?

17.3.1. - things like ensureLoggedIn & ensure (becomes login and services)

should be something like a login service
basic unit conversion, localization services, validation services
useDialog for probably a good number of existing dialogs that gather input / choices from the user
anything asynchronous that requires a callback

17.4. Dynamically Load Client Code Supporting Service

Look at the example of enableProfile.

Benefit of being able to dynamically load code supporting client side execution of portions of the service.

17.5. Site Specific Registration of Services

SYNTAX

{
  service:serviceNameSTR,
  module:moduleNameSTR,
  methodName:methodNameSTR
}

EXAMPLE - EXISTING CODE

{
  service:'isValidHandle',
  module:'MySite.Validator',
  methodName:'handle'
}

EXAMPLE - NEW CODE

{
  service:'enableProfile',
  performService:function (_params,_directives) {
    var m = this;
    Uize.require (
      'MySite.Services.MemberProfile',
      function () {
        MySite.Services.MemberProfile.enable (_params,m);
      }
    );
  }
}

17.6. Caching?

If implemented in Uize.Comm, can get the benefit of its client caching mechanism. How could one get that benefit using a different approach? (such as implementing in performAjax in page widget subclass)

18. Test Improvements

18.1. Put Tests Into Separate Uize.Tests Namespace

It would be better for tests to exist under a different namespace than Uize.Test, so that the Uize.Test namespace can be reserved for test subclasses for special types of tests.

18.2. Clean Up Tests

18.2.1. Make Performance Tests Legit

Performance tests that aren't browser dependent should be turned into true test modules.

they would exist under the namespace Uize.Test.Performance
they would be combined into a test suite module as Uize.Test.PerformanceTests
they would be runnable in the regular UIZE Unit Tests example
as real modules, they would automatically have reference documentation, which could contain the full description / explanation for what the tests aim to establish
some tests could become examples
some tests could be eliminated

18.3. For Unit Test Build Scripts

Consider testing the loading of modules in isolation of other modules, in order to determine that modules correctly declare their dependencies, without having missing declared dependencies masked by other modules that were loaded and built before them that shared some of their dependencies.

This approach would still not be foolproof, however, since merely loading and building a module can't determine that all modules that are needed are declared in the required list, since some required modules may only be accessed during runtime execution of some code within a module.

18.4. Test All JavaScript Files

It would be nice if the build script could also test code besides and other JavaScript files throughout the folder hierarchy of a site, rather than just testing the modules.

There might be numerous issues with testing arbitrary JavaScript files found spotted throughout a Web site's folders. For one thing, such JavaScript files may not be written as Uize JavaScript modules, and such files may not be able to be loaded without causing errors if they depend on other JavaScript code that they don't declare dependencies on.

19. Node as a Widget

a lot of widgets have to synchronize state to DOM nodes
to make it easier for widgets to optimize their performance and minimize the number of times that they touch the DOM in performing UI updates, it might be helpful to provide a representation of the state of a DOM node in the form of a widget. In this approach, DOM nodes are instead represented as node type child widgets. Instances of node type widgets can carry state for a node while the widget is not yet wired and while the node does not exist, to be synchronized with the node when the widget is wired up later.

In what different ways do widgets touch DOM nodes?

modifying the className to reflect state
modifying position
modifying dimensions
modifying color
wiring event handlers

20. Test Modules to Implement Next...

Uize.Test.Uize.Template
Uize.Test.Uize
Uize.Test.Uize.Json
Uize.Test.Uize.Color
Uize.Test.Uize.Color.Util
Uize.Test.Uize.Color.xUtil
Uize.Test.Uize.Curve
Uize.Test.Uize.Build.Scruncher
Uize.Test.Uize.Curve.Rubber
Uize.Test.Uize.Curve.Mod

21. Value Transformer Function

a function that is flagged as a value transformer
it is up to each function or method to determine if they will support value transformers or not

21.1. - good candidates for methods to support value transformers...

myInstance.set
MyClass.set
Uize.Fade.Factory.fadeProperty
Uize.Fade.Factory.fadeProperties
Uize.Fx.fadeStyle
Uize.Dom.Basics.setStyle, myWidget.setNodeStyle
Uize.Dom.Basics.setProperty, myWidget.setNodeProperty
makes sense where the value for which a value transformer is being specified is intended to set a new value for something for which a current value is known, where the new value is derived by applying the specified value transformer to the current value

21.2. Semantics

// plus value transformer
slider.set ({value:Uize.add.x (10)});
slider.set ({value:Uize.x ('x + 10')});
slider.set ({value:Uize.x (function (x) {return x + 10}}));

// boolean toggle value transformer
slider.set ({value:Uize.not})
slider.set ({value:Uize.x ('!x')})
slider.set ({value:Uize.x (function (x) {return !x})})

// multiply value transformer
slider.set ({value:Uize.multiply.x (10)});
slider.set ({value:Uize.x ('x * 10')});
slider.set ({value:Uize.x (function (x) {return x * 10})});

Uize.multiply.x (10)
Uize.x ('x * 10')
function (x) {return x * 10}

Uize.add.x (10)
Uize.x ('x + 10')
function (x) {return x + 10}

Uize.subtract.x (10)
Uize.x ('x - 10')
function (x) {return x - 10}

Uize.divide.x (10)
Uize.x ('x / 10')
function (x) {return x / 10}

Uize.mod.x (10)
Uize.x ('x % 10')
function (x) {return x % 10}

Uize.not
Uize.x ('!x')
function (x) {return !x}

Uize.round
Uize.x (Math.round)
Uize.x ('Math.round (x)');
function (x) {return Math.round (x)}

21.3. Behavior

for any state property that is not defined in its property profile as allowing function type values, a function value specified as the new value for the property in a call to the set method will be treated as a value transformer on the current value of the property
for any state property that is defined in its property profile as allowing function type values, but that is not defined as allowing value transformer function values, a function value that is a value transformer function and that is specified as the new value for the property in a call to the set method will be treated as a value transformer on the current value of the property
for any state property that is defined in its property profile as allowing function type values and that is also defined as allowing value transformer function values, a function value that is a value transformer function and that is specified as the new value for the property in a call to the set method will simply be set as the new value for that property

21.4. Possible Implementation

function _makeValueTransformer (_functon,_extraArguments) {
  var _valueTransformer = _extraArguments && _extraArguments.length
    ? function (x) {return _functon.apply (this,[x].concat (_extraArguments))}
    : function (x) {return _functon.call (this,x)}
  ;
  _valueTransformer.isValueTransformer = true;
  return _valueTransformer;
}
var _cachedValueTransformers = {};
Uize.x = function (_unresolvedValueTransformer) {
  var _valueTransformer = _unresolvedValueTransformer;
  if (typeof _valueTransformer == 'function') {
    if (!_valueTransformer.isValueTransformer)
      _valueTransformer = _makeValueTransformer (
        _valueTransformer,
        arguments.length > 1 && Array.prototype.slice.call (arguments,1)
      )
    ;
  } else {
    _valueTransformer = _cachedValueTransformers [_unresolvedValueTransformer += ''];
    if (!_valueTransformer) {
      _valueTransformer = _cachedValueTransformers [_unresolvedValueTransformer] = Function (
        'x',
        'return ' + _unresolvedValueTransformer
      );
      _valueTransformer.isValueTransformer = true;
    }
  }
  return _valueTransformer;
};

22. Profiling Support

22.1. - a means for getting reports of the time that certain operations take on a page

22.1.1. - module building time

time for building each module
total time for building all modules

22.1.2. - for widget instances (stored on each instance)...

construction time

22.1.2.1. - wiring time

total wiring time
wiring time for children
self wiring time
inspect by widget tree

22.1.2.2. - inspect by module

total number of instances
total construction time
total wiring time
average construction time
average wiring time

23. Performance Questions...

23.1. - is there any difference between array.push (element) and array [array.length] = element ?

there appears to be, with assign-to-end being faster, but it is not significant. In building an array of 1,000,000 elements, it can make a difference of up to 2 seconds. Difference is most pronounced in IE. At scales of 1000 elements, it makes a difference of just 1 or 2 ms. The assign-to-end approach adds to code size a tiny bit, requires maintaining a separate array length counter variable, and doesn't offer the convenience of pushing multiple elements in a single statement. Assign-to-end with accessing the length property is definitely not advisable, since that would eat into the performance benefit and more significantly add to code size.

23.2. - when getting a reference to a node, does it hurt to fall back to document.getElementsByName?

doesn't appear to make that much difference in cases of many lookups. Optimizing it out for most lookups might help a little bit, but it's not that compelling.
does setting a style property on a node always incur a cost, even if the value you're setting is the current value? If so, does accessing and testing before setting improve performance?
what's the performance difference between Math.round (myNumber) and (myNumber + .5) >> 0 ?

23.3. - what's the performance difference between...

function doSomething (value) {
  ...
}
doSomething ('value1');
doSomething ('value2');
doSomething ('value3');
doSomething ('value4');

...and...

for (var value in {value1:1,value2:1,value3:1,value4:1}) {
  ...
}
if (condition) doSomething ();

...and...

condition && doSomething ();

24. Idea for Handling Functions That May Be Asynchronous

24.1. - approach 1

function blah (param1,param2,param3,_returnResult) {
  var _returnResult = arguments.callee.returnResult || _returnResult;
  delete arguments.callee.returnResult;

  doAsyncStuff (
    function () {
      _returnResult (result);
    }
  );

  arguments.callee.isAsync = true;
}

function callAsAsync (_functionToCall,_args,_returnResult) {
  _functionToCall.returnResult = _returnResult;
  var
    result = _functionToCall.apply (_args),
    thisCallWasAsync = _functionToCall.isAsync
  ;
  delete _functionToCall.returnResult;
  delete _functionToCall.isAsync;
  thisCallWasAsync || setTimeout (0,function () {_returnResult (result)});
}

using it...

callAsAsync (blah,[1,2,3],handleReturn);
function handleReturn (result) {
}

24.2. - approach 2

function isValidUser (_user) {
  var _result = new Async;

  doAsyncUserValidation ({
    user:_user,
    callback:function (_isValidUser) {
      _result.returnResult
        ? _result.returnResult (_isValidUser)
        : (_result = _isValidUser)
      ;
    }
  });

  return _result;
}

function callAsAsync (_functionToCall,_args,_returnResult) {
  var _result = _functionToCall.apply (0,_args);
  _result instanceof Async
    ? (_result.returnResult = _returnResult)
    : _returnResult (_result)
  ;
}

using it...

callAsAsync (
  isValidUser,
  ['timipoo'],
  function (_isValid) {
    // do next stuff
  }
);

25. - the most challenging and difficult problems to solve

generic I18N resource string dependency system
CSS dependency resolution system
generic tracking/logging solution
unit testing

26. Generic Solution for Tracking

in most cases, should not require code changes
ability, from the outside of code, to track any event of any type of widget
whether or not to track an event is determined by a configurable rule
with tracked events, ability to log any aspects of state state that might be interesting
tracking is basically just logging by a different name
tracking and logging as good candidates for Aspect Oriented Programming

27. Only Change Property Values Using the set Method

Make sure that all setting of properties is done through the set method (i.e. no more adhoc setting by assigning using the private name). Use a regular expression to search through the code.

27.1. How to Find Offending Cases

To find most cases...

SEARCH REGEXP

/this\._\w+\s*=[^=]/

...or write a build script that scans through JS files, determines private names of declared state properties, and then uses those names in generated regular expressions to find direct assignments.

28. - factor out code for validating a value, where the validator can be...

a simple value, to which the value being tested should be compared for equality
a function, whose return result should indicate whether or not the value being tested is valid
a regular expression, which should be tested on the value to determine if it is valid
null or undefined, indicating that no test should be performed
an optional parameter, indicating whether or not equality, strict equality, or dynamic (or some better name) mode should be used

28.1. - could be used...

Uize (modify Uize.recordMatches)
Uize.Dom.Basics.find

29. - should factor out code to set HTML for frame or iframe (best implementation so far in Simple Doc Tester)

29.1. - while at it, should factor out code for replacing contents of any window, and move into Uize.Dom.Basics.setInnerHtml? Or Uize.Dom.Basics.injectHtml? Or should there be a window utilities package?

29.1.1. Uize.Browser.Window.write

Uize.Browser.Window.write (window,content)

Uize.Browser.Window.write (window,content,contentType)

Uize.Browser.Window.launch

29.1.2. Uize.Browser.Window.center

Uize.Browser.Window.center (window)

Uize.Browser.Window.center ()

29.1.3. Uize.Browser.Window.resize

Uize.Browser.Window.resize (windowOBJ,width,height,positionX,positionY)

Uize.Browser.Window.resize (window,600,400)

Uize.Browser.Window.resize (window,'max','max')

Uize.Browser.Window.resize (window,null,'max')

30. Key Aspects of a Framework

Solving fundamental problems in useful, convenient, friendly, understandable ways

performance (load time, interaction speed, memory usage (non-leaky))
i18n / L10n
interaction logging & tracking
multivariate testing
application robustness & state management
skinning / theming
troubleshooting
sensible code reuse
ease of development
easy wow (effects and animation)
user help
interoperability

31. - Uize.Delayed

31.1. Portion of Implementation

instanceMethods:{
  cancel:function () {
    var m = this;
    if (m._timeout) {
      clearTimeout (m._timeout);
      m._timeout = _null;
    }
  },

  perform:function (_actionFunction) { // support optional delay param
    var
      m = this,
      _delay = m._delay
    ;
    m.cancel ();
    _delay ? (m._timeout = setTimeout (_actionFunction,_delay)) : _actionFunction ();
  }
}

31.2. Another Possible Implementation

Uize.caller = function (_context,_method,_params,_delay) {
  function _callMethod () {
    var _function = typeof _method == 'string' ? _context [_method] : _method;
    _function.callerThis = this;
    _function.callerArguments = arguments;
    var _result = _params ? _function.apply (_context,_params) : _function.call (_context);
    delete _function.callerThis;
    delete _function.callerArguments;
    return _result;
  }
  _callMethod.cancel = function () {};
  if (_delay) {
    var
      _timeout,
      _caller = function () {
        var
          m = this,
          _arguments = arguments
        ;
        return (_timeout = setTimeout (function () {_callMethod.apply (m,_arguments)},_delay));
      }
    ;
    (_caller.cancel = function () {if (_timeout) _timeout = clearTimeout (_timeout)}) ();
    return _caller;
  } else {
    return _callMethod;
  }
};

31.3. Sample Usage

31.3.1. Approach 1

m._delayedAction = Uize.Delayed ({delay:1000});
m.wireNode (
  node,
  {
    mouseover:function () {m._delayed.perform (function () {m.doSomething ()})},
    mouseout:function () {m._delayed.cancel ()}
  }
);

31.3.2. Approach 2

var _delayedCaller = Uize.caller (m,'doSomething',null,1000);
m.wireNode (
  node,
  {
    mouseover:_delayedCaller,
    mouseout:function () {_delayedCaller.cancel ()}
  }
);

31.4. Thoughts

function () {m.setNodeStyle ('blah',{color:'#000'})}
Uize.caller (m,'setNodeStyle,['blah',{color:'#000'}])

Uize.defer

What's good about closures for node event handlers is that they can access...

the node as this
the event as the first parameter

What's bad about closures...

don't offer the delayed execution and cancelability supported with Uize.caller
code hangs on to state of closure's scope

32. More Unobtrusive JavaScript Features

Implement more unobtrusive features, where no JS is needed inside markup, such as...

links that are flagged to pop open windows (perhaps with target="[some window name]")

32.1. - expand/collapse

a lightweight way to get expand/collapse behavior into documents, without having to instantiate widgets

33. Code Development (in order of priority)

33.1. **** property changed events refactoring

some events that were being fired in the onChange handlers were not being fired right at the end, but now they in effect are because of the way the Changed.[propertyName] event mechanism is implemented. Could this cause any weird order of execution problems?
the code registered in handlers for the Changed.[propertyName] event is now being executed as a batch for the changed properties after the whole batch of onChange handlers is executed. Could this cause order of execution problems, with some code already expecting the previous behavior?
the Uize.Widget.Options class is using the '' event to bubble up events from the button instances. The Uize.Widget.Button class was previously firing an event for change of the 'selected' property value. Because of the way that the Changed.[propertyName] event is currently implemented, this event will no longer be bubbled up. Could this issue with the '' event become a general problem?
perhaps onChange handlers should get the previous value for the property as a parameter

33.2. - high-minded ideas

drag a value from any widget to any other widget that supports or has a child that supports the value as part of its interface
an easy way to bind two widgets to each other, so that values are syncronized
an orthogonal effect system that does not require widget code to implement effects
a codified system for registering optimized handlers for batch property changes (e.g. when value and value set are changed in one action)

33.3. - memory usage optimizations

use prototype for state properties?

33.4. - performance optimizations

a way to avoid calling onChange handlers at construction time

33.5. widget ID scheme refactoring

33.5.1. other...

possibly come up with a different term for the root node of a widget (since we still have shell references in identifiers in various places, possibly just "root" instead of "shell")

33.6. image border fade overlay

a convenient way to automatically overlay a border fade on images in a document

Uize.TextOutline: a little class to make it easy to create an outline effect around text, so that it can be legible when against a background of a similar tone (i.e. insufficient contrast)

33.7. Graphing DHTML

overlay for stock price chart images to highlight date and price at date

33.8. Image Letters Widget (Uize.Widget.Spritext)

an easy way to display words using character set table images

33.9. Auto-wired hide-reveal mechanism

for documents with sections of extra in-depth information that most users may not be interested. Allows the information to be available and read in the context of the larger document with an extra click, but without creating an overly heavy read for most users

33.10. Stars Rating Widget

a convenient way to have a rating value translated into a graphic of stars (whole and fractional). Could this be accomplished with a generalized bar / slider widget that has stars as its fullness bg?

Suggest / Auto-complete Widget

33.11. Utility routine to easily make a bunch of links open in a new window

mode to automatically detect links to larger images and wire to open correctly sized. Frill where linked thumbnail "throbs" outwardly to suggest enlarging.
mode to overlay alt/title on image with transparency effect

33.12. Auto-viewer for Images

Simply put in image tags in your page, let the auto-viewer present the images to the user in a professional layout

covenient skins for easy setup

33.13. IDEAS

facilitate multiple controls controlling the same data (e.g. two buttons for the same action) -- might be two different object instances linked in some way
combined with conformer mechanism, perhaps also the concept of discrete set value and resolved (i.e. calculated value) value -- so if there was a valid range and there was an attempt to set outside the valid range, the common value used by most code would be the resolved value, but the set value would also still be stored and accessible through some interface

33.14. Puzzle Game

takes an image and splits it up into puzzle fragments and then lets the user drag and drop them in place
race against time
mode where puzzle split if they haven't been used in a while
mode where unused pieces fade out over time
difficulty level can affect number of pieces
difficulty level can increase piece dimension variation
expand/collapse module for documents (to attach logic in similar way to Uize.Widget.Tree.List)
letters remaining widget implemented using slider indicator widget
XY selector widget
nifty javascript bookmarklets that allow you to view the online version of a local file, or the local version of an online file
table color fader
text color fader
ordering widget (for customizing table column order, etc.)

34. BUGS

34.1. Safari

for all behaviors that are modified using the Ctrl key, should also be modified by the metaKey (for Mac users)

34.1.1. ...ImagePort.Draggable

no way to initiate Ctrl modifier key behaviors

34.1.2. ThumbZoom

zoom out effect is very choppy
fade-to-black effect is very choppy
weird flash sometimes at start of fade-to-black
positioning is not adjusted for page being scrolled
zoomed image is spontaneously dismissed if page had scrollbars (some weird event thing?)

34.2. IE (in order of priority)

"Uize.WiseLoad Example": mouseover opacity effect on thumbnails not working (and trying to enable it using filter:alpha(opacity=...) was completely hosing my machine)