- Contents
- 1. General Drag and Drop Framework
- 2. Types for Properties
- 3. Iterator Interface
- 4. Safe Privates
- 5. Mixins
- 6. Rethinking Module Definitions
- 7. Version Support in Module Mechanism
- 7.1. Requirements
- 7.2. - possible approach...
- 7.3. - declaring information about a module variation
- 7.4. - requiring specific versions of modules...
- 7.5. - requiring a variation of a module using a custom match...
- 7.6. In a Nutshell
- 7.7. Ideas
- 7.8. Module Registry
- 7.9. Module Meta Data
- 7.10. Loading of Modules
- 7.11. Module Variations
- 7.12. Module Specifier
- 7.13. Variation Qualifier
- 7.14. Issues to Address
- 8. JavaScript Language Unit Tests
- 9. Function Argument Validation
- 10. Client Services
- 11. Test Improvements
- 12. Node as a Widget
- 13. Test Modules to Implement Next...
- 14. Value Transformer Function
- 15. Profiling Support
- 16. Performance Questions...
- 17. Idea for Handling Functions That May Be Asynchronous
- 18. - the most challenging and difficult problems to solve
- 19. Generic Solution for Tracking
- 20. Only Use set Method For Changing Property Values
- 21. - factor out code for validating a value, where the validator can be...
- 22. - should factor out code to set HTML for frame or iframe (best implementation so far in Simple Doc Tester)
- 23. Key Aspects of a Framework
- 24. - Uize.Delayed
- 25. More Unobtrusive JavaScript Features
- 26. Code Development (in order of priority)
- 26.1. **** property changed events refactoring
- 26.2. - high-minded ideas
- 26.3. - memory usage optimizations
- 26.4. - performance optimizations
- 26.5. - new subclassing syntax
- 26.6. widget ID scheme refactoring
- 26.7. image border fade overlay
- 26.8. Graphing DHTML
- 26.9. Image Letters Widget (Uize.Widget.Spritext)
- 26.10. Auto-wired hide-reveal mechanism
- 26.11. Stars Rating Widget
- 26.12. Utility routine to easily make a bunch of links open in a new window
- 26.13. Auto-viewer for Images
- 26.14. IDEAS
- 26.15. Puzzle Game
- 27. BUGS
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. General Drag and Drop Framework
Virtual dom events to mimic new HTML5 dnd events.
2. Types for Properties
Can be used by interpolation code (such as fades).
3. Iterator Interface
3.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 |
3.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 |
3.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 }
3.4. Uize.Iterator
The Uize.Iterator
object implements the iterator interface.
3.4.1. As a Wrapper
A Uize.Iterator
object can be instantiated as a wrapper around a number of different source values.
3.4.1.1. Wrapping a Number
document...
3.4.1.2. Wrapping an Array
document...
3.4.1.3. Wrapping an Object
document...
3.4.1.4. Wrapping a JavaScript Iterator
document...
3.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.String.Lines | |
Uize.Color.xUtil | |
Uize.Curve |
3.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.combine - 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 (ie. where each iteration alternates through the specified source iterators) |
4. 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') }); _classPrototype [_myProperty] = 'blah'; // declaring instance property _classPrototype [_myMethod] = function () {}; // declaring instance method 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? |
5. Mixins
Add support for mix-ins.
Mixing in would...
copy all properties of the prototype | |
copy all static properties | |
copy in all information of registered state properties |
ISSUES
namespace conflict for all instance properties |
6. Rethinking Module Definitions
6.1. Using a Provide-Need Pattern as Foundation
6.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 |
6.1.2. Other Patterns That Can Be Modeled on Provide-Need
6.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.
6.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 } );
6.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 () { } );
7. Version Support in Module Mechanism
7.1. Requirements
7.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 |
7.2. - possible approach...
VARIATION 1
Uize.module ({ 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 ({ 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 ()... } });
7.3. - declaring information about a module variation
EXAMPLE
Uize.module ({ name:'Uize.Widget.FooBar', version:'2', builder:function (_super,m) { // build the module } });
7.4. - requiring specific versions of modules...
VARIATION 1
Uize.module ({ 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 ({ 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 ()... } });
7.5. - requiring a variation of a module using a custom match...
EXAMPLE
Uize.module ({ 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 ()... } });
7.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 |
7.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 |
7.8. Module Registry
7.8.1. Querying the Module Registry
Discovering the Loaded Modules
7.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');
7.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.
7.9. Module Meta Data
EXAMPLE
Uize.module ({ name:'Uize.Widget.FooBar', version:'2', experiment:'performance-optimized', builder:function (_super,m) { // build the module } });
7.10. Loading of Modules
7.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 |
7.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; } });
7.11. Module Variations
7.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.
7.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.
7.12. Module Specifier
A module specifier identifies a specific module, by name alone, or by a combination of name and an additional variation qualifier.
7.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.
7.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 ({ 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 ()... } });
7.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? |
8. JavaScript Language Unit Tests
Implement unit tests for all features of the JavaScript language.
8.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 (ie. ['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 ; }
9. 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.
9.1. Method Signature Validation as Optional Layer
Possibly a way generally to have method signature validation as a separate optional layer of code.
9.1.1. As a Separate Module
Maybe a separate module that can accompany the main module?
9.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.
10. 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:''}) |
10.1. Example 1
BEFORE
myWidget.callInherited ('ensureLoggedIn') (function () {});
AFTER
myWidget.ajax ({service:'login'},function () {}); // or... myWidget.service ('login',function () {});
10.2. Example 2
BEFORE
myWidget.callInherited ('enableProfile') (function () {});
AFTER
myWidget.ajax ({service:'enableProfile'},function () {}); or... myWidget.service ('enableProfile',function () {});
10.3. What All Can Services Replace or Do?
10.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 |
10.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.
10.5. Zazzle Specific Registration of Services
SYNTAX
{ service:serviceNameSTR, module:moduleNameSTR, methodName:methodNameSTR }
EXAMPLE - EXISTING CODE
{ service:'isValidHandle', module:'Zazzle.Validator', methodName:'handle' }
EXAMPLE - NEW CODE
{ service:'enableProfile', performService:function (_params,_directives) { var _this = this; Uize.module ({ required:'Zazzle.Services.MemberProfile', builder:function () { Zazzle.Services.MemberProfile.enable (_params,_this); } }); } }
10.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)
11. Test Improvements
11.1. Make Unit Test Build Scripts Generic
11.1.1. Shareable Code to Dynamically Add Tests
Have shareable code that can take a list of module names, and dynamically add tests for modules for which no dedicated test modules have been created.
This code would be used in the UIZE Unit Tests example page, by supplying the list of modules from the UizeSite.ModulesTree
module, and in the _run-unit-tests-scrunched.js
and _run-unit-tests-source.js
build scripts which would obtain a list of modules using Uize.Wsh.getFiles
.
11.2. Clean Up Tests
11.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 |
11.3. 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.
11.4. 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.
11.5. 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.
12. Node as a Widget
a lot of widgets have to synchronize state to implied 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, implied 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 implied nodes?
modifying the className to reflect state | |
modifying position | |
modifying dimensions | |
modifying color | |
wiring event handlers |
13. Test Modules to Implement Next...
Uize.Test.Uize.Template | |
Uize.Test.Uize | |
Uize.Test.Uize.Json | |
Uize.Test.Uize.Color | |
Uize.Test.Uize.Color.xUtil | |
Uize.Test.Uize.Curve | |
Uize.Test.Uize.Build.Scruncher | |
Uize.Test.Uize.Curve.Rubber | |
Uize.Test.Uize.Curve.Mod |
14. 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 |
14.1. - good candidates for methods to support value transformers...
myInstance.set | |
MyClass.set | |
Uize.Fade.fadeProperty | |
Uize.Fade.fadeProperties | |
Uize.Fx.fadeStyle | |
Uize.Node.setStyle, myWidget.setNodeStyle | |
Uize.Node.setProperty, myWidget.setNodeProperty |
makes sense where the value for which a value transformer is being specified is intended to specify a value for something for which a current value is known |
14.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)}
14.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 |
14.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 ( _functon, arguments.length > 1 && Array.prototype.slice.call (arguments,1) ) ; } else { _valueTransformer = _cachedValueTransformers [_unresolvedValueTransformer += '']; if (!_valueTransformer) { _valueTransformer = _cachedValueTransformers [_unresolvedValueTransformer] = new Function ( 'x', 'return ' + _unresolvedValueTransformer ); _valueTransformer.isValueTransformer = true; } } return _valueTransformer; };
function _x () {return _makeValueTransformer (this,arguments)} Uize.exify = function (_function,_wrapOriginal) { var _arity = _function.arity || _function.length; if (_wrapOriginal) { var _originalFunction = _function; _function = function () {return _originalFunction.apply (this,arguments}; } if (_arity < 2) _function.isValueTransformer = true; _function.x = _x; return _function; };
// define Uize.divide = Uize.exify (function (x,denominator) {return x / denominator}); // use Uize.divide (10,2); Uize.divide.x (2); // define Uize.round = Uize.exify (Math.round,true); // wrap original, so as not to modify native function's properties // define Uize.isType = Uize.exify (function (x,type) {return typeof x == type}); // use Uize.isNumber = Uize.isType.x ('number'); Uize.isString = Uize.isType.x ('string');
Uize.willCall (Uize.isType,[0,'number'],0) Uize.isTypeOf.x ('number')
_makeExify ('divide',function (x,value) {return x / value});
15. Profiling Support
15.1. - a means for getting reports of the time that certain operations take on a page
16. Performance Questions...
16.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. |
16.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 ? |
16.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 ();
17. Idea for Handling Functions That May Be Asynchronous
17.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) { }
17.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 } );
18. - the most challenging and difficult problems to solve
generic I18N resource string dependency system | |
CSS dependency resolution system | |
generic tracking/logging solution | |
unit testing |
19. 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 |
20. Only Use set Method For Changing Property Values
Make sure that all setting of properties is done through the set method (ie. no more adhoc setting by assigning using the private name). Use a regular expression to search through the code.
20.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 registered properties, and then uses those names in generated regular expressions to find direct assignments.
21. - 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 |
21.1. - could be used...
Uize (modify Uize.recordMatches) | |
Uize.Node.find |
22. - should factor out code to set HTML for frame or iframe (best implementation so far in Simple Doc Tester)
22.1. - while at it, should factor out code for replacing contents of any window, and move into Uize.Node.setInnerHtml? Or Uize.Node.injectHtml? Or should there be a window utilities package?
22.1.1. Uize.Browser.Window.write
Uize.Browser.Window.write (window,content)
Uize.Browser.Window.write (window,content,contentType)
Uize.Browser.Window.launch
22.1.2. Uize.Browser.Window.center
Uize.Browser.Window.center (window)
Uize.Browser.Window.center ()
22.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')
23. 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 |
24. - Uize.Delayed
24.1. Portion of Implementation
_classPrototype.cancel = function () { if (_this._timeout) { clearTimeout (_this._timeout); _this._timeout = _null; } } _classPrototype.perform (_actionFunction) { // support optional delay param var _this = this, _delay = _this._delay ; _this.cancel (); _delay ? (_this._timeout = setTimeout (_actionFunction,_delay)) : _actionFunction (); };
24.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 _this = this, _arguments = arguments ; return (_timeout = setTimeout (function () {_callMethod.apply (_this,_arguments)},_delay)); } ; (_caller.cancel = function () {if (_timeout) _timeout = clearTimeout (_timeout)}) (); return _caller; } else { return _callMethod; } };
24.3. Sample Usage
24.3.1. Approach 1
_this._delayedAction = Uize.Delayed ({delay:1000}); _this.wireNode ( node, { mouseover:function () {_this._delayed.perform (function () {_this.doSomething ()})}, mouseout:function () {_this._delayed.cancel ()} } );
24.3.2. Approach 2
var _delayedCaller = Uize.caller (_this,'doSomething',null,1000); _this.wireNode ( node, { mouseover:_delayedCaller, mouseout:function () {_delayedCaller.cancel ()} } );
24.4. Thoughts
function () {_this.setNodeStyle ('blah',{color:'#000'})} Uize.caller (_this,'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 |
25. 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]") |
25.1. - expand/collapse
a lightweight way to get expand/collapse behavior into documents, without having to instantiate widgets |
26. Code Development (in order of priority)
26.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 |
26.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 (eg. when value and value set are changed in one action) |
26.3. - memory usage optimizations
use prototype for state properties? |
26.4. - performance optimizations
a way to avoid calling onChange handlers at construction time |
26.5. - new subclassing syntax
MyClass.subclass ({ alphastructor:{ }, omegastructor:{ }, instanceMethods:{ }, staticMethods:{ }, instaticMethods:{ }, setGetProperties:{ } });
26.6. widget ID scheme refactoring
26.6.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") |
26.7. 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 (ie. insufficient contrast)
26.8. Graphing DHTML
overlay for stock price chart images to highlight date and price at date
26.9. Image Letters Widget (Uize.Widget.Spritext)
an easy way to display words using character set table images
26.10. 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
26.11. 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
26.12. 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 |
26.13. 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 |
26.14. IDEAS
facilitate multiple controls controlling the same data (eg. 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 (ie. 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 |
26.15. 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.) |
27. BUGS
27.1. General
27.1.1. - examples/button-types.html - nodes type button
when disabled or selected, busy cursor doesn't display | |
in IE, when in normal state, busy cursor only display when mousing over certain regions |
27.2. Firefox
in the button-types example, the frames style button does not fire the "Click" event (seems to have something to do with the mousedown event handler's execution) |
27.3. Safari
for all behaviors that are modified using the Ctrl key, should also be modified by the metaKey (for Mac users) | |
the slideshow stuff is not working | |
the ThumbZoom class zoom out effect is not centering in the window when the window is scrolled | |
after an image has zoomed out, there is a brief moment where the shield displays all solid before the opacity kicks in |
27.3.1. ...ImagePort.Draggable
no way to initiate Ctrl modifier key behaviors
27.3.2. Color Pickers With Gradient example
extremely slow
27.3.3. 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?) |
27.4. 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) |