cocoon-docs mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From stev...@outerthought.org
Subject [WIKI-UPDATE] Woody CubistForms WoodyScratchpad DeleteMe Tue Apr 13 00:00:10 2004
Date Mon, 12 Apr 2004 22:00:11 GMT
Page: http://wiki.cocoondev.org/Wiki.jsp?page=Woody , version: 33 on Sun Apr 12 21:06:09 2004
by TimLarson

+ * [CubistForms] - Checking to see if we are covering all the angles in the drive towards
"stable".


Page: http://wiki.cocoondev.org/Wiki.jsp?page=CubistForms , version: 1 on Sun Apr 12 21:10:10
2004 by TimLarson

New page created:
+ This is a for-discussion-and-revision document, not a statement of fact.
+ So, please jump in, discuss, revise, and thoroughly refactor :)
+ 
+ The page layout is intentionally rough to encourage perfectionists to contribute ;)
+ 
+ !!First let's express the needs from the standpoint of various people:
+ 
+ 
+ !User (What does the end user care about?)
+ *Data Entry
+ **field (string, number, date, all with various formatting)
+ ***   "required" indicator
+ ***"help" link
+ ***selection lists
+ ****"please choose" message
+ ****default selection(s)
+ ****option sets
+ **toggle (checkbox, set of radio buttons)
+ **text entry (textarea, htmlarea, other web-based editors)
+ **grid (table)
+ *Navigation
+ **buttons (trigger action, validate, submit form)
+ **drill-down/help/etc. (expand inline, floating pane, spawned window, replaced page)
+ *Buglets
+ **Page scroll position is lost after a round-trip to the server.
+ 
+ !Visual/HTML Designer (How do we implement this, and how do we make it look the way we want?)
+ *Data Entry
+ **field (input)
+ **toggle (input type="checkbox", input type="radio")
+ **text entry (whole list)
+ **grid
+ *Navigation
+ **buttons (all types)
+ **drill-down/help/etc.
+ ***expand inline
+ ****div + css + js
+ ****"choice" + POST + no js needed
+ ***floating pane
+ ****div + css + js
+ ****"choice" + POST + no js needed
+ ***spawned window (GET/POST)
+ ***replaced page (GET/POST)
+ *Non-editable Data Display
+ **field (with all its types and various formatting)
+ **toggle (all types)
+ **grid (table)
+ *Other Stuff
+ 
+ !Binding Programmer (How do we interface with the data sources and data sinks?)
+ *Dynamic selection lists tied to live db queries, DAO's, lists, hashes, etc.
+ *For a Repeater part of the identity may be:
+ **Fields we want to expose to the user for display and/or update.
+ **Fields that we want to keep private to the form model (never sent to client).
+ ***This implies the need for a "private" widget attribute. (see below for details)
+ 
+ !Form Logic/Event Handler Programmer
+ *What can/cannot be dynamically referenced and modified?
+ *How do you manually update a selection list.
+ *How do you make a selection list automatically follow an existing live list datasource
(e.g. query, list, hash).
+ *We need support for a "binding direction"-like attribute for widgets:
+ **input-only (for passwords and other sensitive user data that should not be echoed back
to the user)
+ **input/output (normal, editable widgets)
+ **output-only (for display only, readFromRequest() disabled to prevent both null-reset and
modification by user)
+ **private (for data not to be sent to or modified by the user, such as part of a Repeater
binding identity keyset)
+ 
+ !Things to check before we are finished:
+ *Do all widget types have corresponding bindings and templates?
+ *Can all values and attributes be referenced and manipulated from all environments where
appropriate?
+ **(e.g. java, js, event handlers, bindings, templates)?
+ *Does the transformer have any compelling use-cases left where it is better than the JXGenerator
approach?
+ **If desired, can the JXGenerator be extended to handle id/extends/defines and choice? (probably
yes)
+ 
+ !! Now let's toss out some more ideas to refine:
+ 
+ 
+ !Other Random Thoughts:
+ *BooleanField
+ **Even if we use a custom class to implement BooleanField's, why do we expose this in the
XML definitions?
+ **We need support for both Booleans (true/false) and "Trileans" (true/false/null).
+ *Struct
+ **Rename "Struct" to "Composite", "Group", or whatever make the most sense to us.
+ *Convertor
+ **Rename to "Converter"? (Check relative hit-counts on google)
+ *Repeater
+ **Use an established terms for this concept: "Array", "Grid", "List", ...
+ **Do we need more direct support for other variants, such as sparse arrays and multi-dimensional
arrays?
+ *MultiValueField versus Repeater
+ **We have single value widgets (Field, BooleanField, Output)
+ **We have multi-value widgets (MultiValueField, Repeater)
+ **And the progression is something like this:
+ ***Field->MultiValueField->Repeater
+ **What benefits does MultiValueField give us over Repeater?
+ ***Four less lines to type each time. (ouch)
+ ***One less widget id to create.
+ **What do we pay for this?
+ ***One more concept to learn/teach/maintain in the model, binding, and template. (main point)
+ ***Only works like a list of Field-type widgets, not BooleanField, Repeater, etc.
+ ***No support in the binding for identity and Repeater's set of binding strategies.
+ **What is missing to drop MultiValueField in favor of using Repeater?
+ ***(Not suggesting to do this drop, just looking at the possibility to see if there are
any benefits.)
+ ***Design Repeater selection-list to at least match features with the MultiValueField selection
list.
+ **Other questions:
+ ***Is Repeater's auto-numbered row wrappers too much overhead when replacing MultiValueField's?
+ ***Should we use a common XML syntax, while backing it by the more efficient MultiValueField-like
class?
+ **An alternate idea would be to make the Repeater semantics more integrated:
+ ***Eliminate Repeater and MultiValueField and instead allow any type of widget to be "repeated".
+ ***For example: (*Not* suggesting syntax, just *very rough* semantics to get ideas flowing)
+ ****MultiValueField: <fd:field id="some-id" multi="true"/>
+ ****Repeater: <fd:composite id="some-id" multi="true"/>
+ 


Page: http://wiki.cocoondev.org/Wiki.jsp?page=WoodyScratchpad , version: 17 on Sun Apr 12
21:26:51 2004 by MarcPortier

+ 
+ 
+ !Implementation ideas...
+ 
+ The introduction of the above attributes largely have an influence on the process of "Building
The WidgetDefinitions". This process is about interpreting the form-definition files and making
the corresponding WidgetDefinition instances out of it.  
+ 
+ Without the @define and @extend attributes these WidgetDefinition instances only had one
purpose: to produce Widget instances of them (through createInstance()) to be used in actual
form-models used during the control of the end-user interaction with a cforms based application.
+ 
+ With the advent of these new attributes we are obliged to solve the following issues:
+ * @extend: requires us to solve 
+ ** lookup of a registered, existing 'base-definition'
+ ** extending that 'base' with additional configurational info
+ * @define: 
+ ** creation of a WidgetDefinition that has no 'id', and that because of that cannot be asked
to produce actual widgets over the createInstance() (if you look at WidgetDefinitions as being
Classes, you could see this state of base-definition as being 'abstract')
+ ** registration of that base-WidgetDefinition for later reference
+ 
+ Above can be grouped into two new aspects to cover:
+ # registration/lookup of abstract-like base-definitions (no 'id', can't produce instances)
+ # all of the actual creation (@define), the extension(@extends) and the 'concretization'
(@id) of the WidgetDefinitions
+ 
+ 
+ The registration/lookup seems logical to be moved under a specific component that uses 
+ the tuple source-of-definition-file and basename-of-widgetdefinition as a key to find back
the actual base-definitions.  This needs some aditional thinking:
+ * IIRC there was the need to refer to base-definitions that only get loaded later in the
file?
+ * And in the more general case one could be parsing a definition file which refers to a
source that wasn't loaded yet --> unless we require the wd:import upfront!
+ * we should also have some concurrency management on these things since we wouldn't want
to have two concurrent calls for some form to be triggering the concurrent loading of the
same definition-source twice?
+ 
+ AbstractDefinitionRegistry would thus minimally allow for:
+ WidgetDefinition lookup(String source, String baseName)
+ void register(String source, String baseName, WidgetDefinition newBaseDef)
+ 
+ 
+ The registration/lookup seems to be a task for the various WidgetBuilders. This would call
for their buildWidgetDefinition method to take a second argument that gets passed down in
the builder hierarchy and allows for the register/lookup.  This should not be the actual AbstractDefinitionRegistry
mentioned before but a Helper class that is tight to the processing of the current source.
 Like this it could automatically insert the current source in the register() action, but
could also maintain the local prefix-to-source-mapping so it can assist to translate prefix
to source during lookup.
+ 
+ so rather some DefinitionRegistryWrapper:
+ * <init> taking the String source of the currently processed file, and a ref to the
actual AbstractDefinitionRegistry 
+ * void pushPrefixMapping(String pfx, String source);
+ * String popPrefixMapping(String pfx);
+ * WidgetDefinition lookup(String baseNameWithPrefix);
+ * void register(String localBaseName, WidgetDefinition newBaseDef);
+ 
+ 
+ 
+ Now to the second aspect: the various instances of 'similar' WidgetDefinitions.
+ The WidgetDefinitions are to be unique and distinct (and immutable IMHO) for any of their
possible incarnations matching a certain occurence in some definition file.  This means that
there should be distinct instances for each @define, @define and @extend, @id, @id and @extend
occurance of the widget-definition (all with their own Location position, and base/extended
configuration settings).  Making the actual members of these Widgets into final fields will
help us in making sure that we're not altering exisiting WidgetDefinition instances, but really
are making new ones.
+ 
+ As a consequence however we will need to provide so called copy-constructors for these WidgetDefinition
classes that allow to instantiate new ones by copying over and extending the member fields
into the new instance.
+ 
+ The WidgetDefinitionBuilder, having access to the registry (see above) could then be following
this pattern.
+ 
+ Note: The instant idea of the Config inner class is to prevent the ugly long parameter-lists
of the constructors as seen in todays Binding classes and to keep the configuration logic
of interpreting the XML config central to the Builder class.
+ 
+ {{{
+ public class XYZWidgetDefinitionBuilder {
+ 
+   Config interpretXMLConfig(Element elmConfig) {
+     // read various parts of the config
+     final TypeK newPartK = DomHelper.....(elmConfig);
+     final TypeL newPartL = ...
+     
+     // Note: this should also have ready build children for those
+     // widget-definitions that contain other widget-definitions
+     // note however that these nested Definitions all will need to 
+     // have their @id being set!
+ 
+     return new Object() {
+       TypeK getPartK(TypeK basePartK) {
+         //merges overrides or keeps basePartK over newPartK
+         return newPartK;
+       }
+       TypeL getPartL(TypeL basePartL) {
+         //merges overrides or keeps basePartL over newPartL
+         return newPartL;
+       }
+     };
+   }
+ 
+ 
+   XYZWidgetDefinition buildWidgetDefinition(Element elm, DefinitionRegistryWrapper reg)
{
+     Config conf = interpretXMLConfig(elm);
+     String location = DomHelper.getLocation(elm);
+ 
+     String baseName = DomHelper.getAttribute("extends", null);
+     XYZWidgetDefinition definition= null;
+     if(baseName != null)  { 
+       definition = reg.lookup(baseName);
+     }
+     
+     String defines = DomHelper.getAttribute("defines", null);
+     if (defines != null) {
+       definition = new XYZWidgetDefinition(null, location, definition , config);
+       reg.register(defines, definition);
+       config = null;
+     }
+ 
+     String id = DomHelper.getAttribute("id", null);
+     if (id != null) {
+       definition = new XYZWidgetDefinition(null, location, definition , config);
+     }
+ 
+     //possibly throw an exception if both @id and @defines where null?
+     return definition ;
+   }
+ 
+ }}}
+ 
+ 
+ Inside XYZWidgetDefinition's constructor something like the following could go on:
+ 
+ {{{
+ 
+   private final String id;
+   private final String location;
+   private final TypeK partK;
+   private final TypeL partL;
+   ...
+ 
+   XYZWidgetDefinition(String id, String location, 
+                       XYZWidgetDefinition base, XYZWidgetConfig config) {
+     this.id = id;
+     if (base != null} {
+       this.lccation = location + "\n\tBased on defition at " + base.location;
+       this.partK = config.getPartK(base.partK);
+       this.partL = config.getPartL(base.partL);
+       ...
+     } else {
+       this.location = location;
+       this.partK = config.getPartK(base.partK);
+       this.partL = config.getPartL(base.partL);
+       ...
+     }
+   }
+ 
+   // some more ideas:
+   boolean isAbstract() {
+     return (this.id != null);
+   }
+ 
+   XYZWidget createInstance() {
+     if isAbstract() throw new ....
+     // from here somethin like current instantiation could happen
+   }
+ 
+ 
+ }}}
+ 
+ 
+ 


Page: http://wiki.cocoondev.org/Wiki.jsp?page=DeleteMe , version: 53 on Sun Apr 12 21:41:16
2004 by JoergHeinicke

+ * [ShaquilleONeal]



Mime
View raw message