[KSS-checkins] r50936 - in kukit/kukit.js/branch/ree-1.4-markup-and-syntax-changes: doc kukit tests

reebalazs at codespeak.net reebalazs at codespeak.net
Wed Jan 23 17:35:36 CET 2008


Author: reebalazs
Date: Wed Jan 23 17:35:34 2008
New Revision: 50936

Modified:
   kukit/kukit.js/branch/ree-1.4-markup-and-syntax-changes/doc/HISTORY.txt
   kukit/kukit.js/branch/ree-1.4-markup-and-syntax-changes/kukit/commandreg.js
   kukit/kukit.js/branch/ree-1.4-markup-and-syntax-changes/kukit/dom.js
   kukit/kukit.js/branch/ree-1.4-markup-and-syntax-changes/kukit/eventreg.js
   kukit/kukit.js/branch/ree-1.4-markup-and-syntax-changes/kukit/forms.js
   kukit/kukit.js/branch/ree-1.4-markup-and-syntax-changes/kukit/kssparser.js
   kukit/kukit.js/branch/ree-1.4-markup-and-syntax-changes/kukit/oper.js
   kukit/kukit.js/branch/ree-1.4-markup-and-syntax-changes/kukit/plugin.js
   kukit/kukit.js/branch/ree-1.4-markup-and-syntax-changes/kukit/providerreg.js
   kukit/kukit.js/branch/ree-1.4-markup-and-syntax-changes/kukit/requestmanager.js
   kukit/kukit.js/branch/ree-1.4-markup-and-syntax-changes/kukit/resourcedata.js
   kukit/kukit.js/branch/ree-1.4-markup-and-syntax-changes/kukit/selectorreg.js
   kukit/kukit.js/branch/ree-1.4-markup-and-syntax-changes/kukit/serveraction.js
   kukit/kukit.js/branch/ree-1.4-markup-and-syntax-changes/kukit/tokenizer.js
   kukit/kukit.js/branch/ree-1.4-markup-and-syntax-changes/tests/runtests.js
   kukit/kukit.js/branch/ree-1.4-markup-and-syntax-changes/tests/test_kssparser.js
   kukit/kukit.js/branch/ree-1.4-markup-and-syntax-changes/tests/test_requestmanager.js
   kukit/kukit.js/branch/ree-1.4-markup-and-syntax-changes/tests/test_utils.js
Log:
Rebase branch on gotcha's last merge

Modified: kukit/kukit.js/branch/ree-1.4-markup-and-syntax-changes/doc/HISTORY.txt
==============================================================================
--- kukit/kukit.js/branch/ree-1.4-markup-and-syntax-changes/doc/HISTORY.txt	(original)
+++ kukit/kukit.js/branch/ree-1.4-markup-and-syntax-changes/doc/HISTORY.txt	Wed Jan 23 17:35:34 2008
@@ -6,6 +6,23 @@
     
     - ...
 
+    - refactor the value provider registry to use
+      a single registry in place of 3.
+      This will enable to define value
+      providers that recieve non-string parameters
+      like a node selection.
+
+      Remove previously deprecated form() and
+      currentForm() value providers from normal
+      action parameters (remark: they should
+      be used with kssSelector.)
+      They now give a parsing error.
+
+      Implement multiproperties in
+      * action-client and action-server
+      * any value provider
+      [ree]
+
     - Use functions in token table instead of code strings
       that were evaluated. 'eval' is very slow.
       [gotcha]
@@ -15,6 +32,11 @@
 
     - Fix multiple selection form fields marshalling on Safari 
       (fixes #22 in kssproject) and on IE.
+      
+    - Fix multiple selection form fields
+      marshalling on Safari 
+      (fixes #22 in kssproject)
+      and on IE.
       [ree]
 
     - Fix error fallback handling

Modified: kukit/kukit.js/branch/ree-1.4-markup-and-syntax-changes/kukit/commandreg.js
==============================================================================
--- kukit/kukit.js/branch/ree-1.4-markup-and-syntax-changes/kukit/commandreg.js	(original)
+++ kukit/kukit.js/branch/ree-1.4-markup-and-syntax-changes/kukit/commandreg.js	Wed Jan 23 17:35:34 2008
@@ -118,10 +118,30 @@
 };
 
 var _executeCommandOnSelector = function(oper) {
-    var selfunc = kukit.selectorTypesGlobalRegistry.get(this.selectorType);
-    // When applying the selection, the original event target will be used
+    // if the selector type is null or undefined or '',
+    // we use the default type.
+    var selectorType = this.selectorType || 
+                       kukit.selectorTypesGlobalRegistry.defaultSelectorType;
+    // Use the provider registry to look up the selection provider.
+    var providerClass = kukit.pprovidersGlobalRegistry.get(selectorType);
+    // See if if is really a selection provider.
+    if (providerClass.prototype.returnType != 'selection') {
+        kukit.E = 'Undefined selector type [' + selectorType + '], ';
+        kukit.E = 'it exists as provider but it does not return a selection.';
+        throw new Error(kukit.E);
+    }
+    // Instantiate it
+    var provider = new providerClass();
+    var args = [this.selector];
+;;; // Check the provider first.
+;;; provider.check(args);
+    // When evaluating the provider, the original event target will be used
     // as a starting point for the selection.
-    var nodes = selfunc(this.selector, oper.orignode, {});
+    // args will contain a single item, since the server side currently
+    // cannot marshall selectors with more parameters
+    // defaultParameters will be empty when using from commands.
+    var nodes = provider.eval(args, oper.orignode, {});
+    //
 ;;;var printType;
 ;;;if (this.selectorType) {
 ;;;    printType = this.selectorType;

Modified: kukit/kukit.js/branch/ree-1.4-markup-and-syntax-changes/kukit/dom.js
==============================================================================
--- kukit/kukit.js/branch/ree-1.4-markup-and-syntax-changes/kukit/dom.js	(original)
+++ kukit/kukit.js/branch/ree-1.4-markup-and-syntax-changes/kukit/dom.js	Wed Jan 23 17:35:34 2008
@@ -227,27 +227,57 @@
 
 var _kssAttrNamespace = 'kssattr';
 
+// the namespace prefix for kss values, 
+// i.e.:
+//              class="... kss-attr-key-value..."
+//              id=="kss-id-key-value"
+// (XHTML:)     kss-attr:key-value 
+//
+var _kssNamespacePrefix = 'kss';
+
+var _getKssValueFromEncodings = function(encodings, prefix) {
+    // Value us a list of values.
+    // If a value equals prefix-value, it will find it
+    // and return the value after the prefix and the dash.
+    // (First value found will be returned.)
+    //
+    // For example:
+    //
+    //     _getKssValueFromEncodings(['kss-attr-key1-value1', 'kss-attr-key2-value2',
+    //          'kss-id-key1-value1'], "kss-attr-key1')
+    //
+    // results 'value1'.
+    //
+    // Legacy example:
+    //
+    //    _getKssValueFromEncodings(['kssattr-key1-value1', 'kssatt-rkey2-value2'], 
+    //          "kss-attr-key1')
+    //
+    //  results 'value1'.
+    //
+    prefix = prefix + '-';
+    var prefixLength = prefix.length;
+    for (var i=0; i<encodings.length; i++) {
+        var encoding = encodings[i];
+        // Does the value start with the prefix?
+        if (encoding.substr(0, prefixLength) == prefix) {
+            // Found it.
+            return encoding.substr(prefixLength);
+        }
+    }
+    return null;
+};
+
+// BBB hint: used by getKssAttribute only, for providers
+// kssAttr and  currentFormVarForKssAttr.
 var _getKssClassAttribute = function(node, attrname) {
     // Gets a given kss attribute from the class
     var klass = dom.getAttribute(node, 'class');
-    var result = null;
     if (klass) {
         var splitclass = klass.split(/ +/);
-        for (var i=0; i<splitclass.length; i++) {
-            var elem = splitclass[i];
-            var splitelem = elem.split('-', 3);
-            if (splitelem.length == 3 &&
-                splitelem[0] == _kssAttrNamespace
-                    && splitelem[1] == attrname) {
-                // Found it. (The last one will be valid,
-                // in case of duplication)
-                var index = splitelem[0].length + splitelem[1].length + 2;
-                result = elem.substr(index);
-            }
-
-        }
+        return _getKssValueFromEncodings(splitclass, 'kssattr-' + attrname);
     }
-    return result;
+    return null;
 };
 
 dom.getKssAttribute = function(node, attrname) {
@@ -271,15 +301,68 @@
     dom.setAttribute(node, fullName);
 };
 
+/* 
+ * Handling of kss values
+ */
+
+dom.getKssValue = function(node, keyType, key) {
+    // Gets a given kss value
+    // first try from the namespace (XHTML), then from the class and id
+    var namespacedName = _kssNamespacePrefix + '-' + keyType;
+    // We access node.getAttribute directly, because we don't need the
+    // other checks in dom.getAttribute
+    var attrName = namespacedName + ':' + key;
+    var result = node.getAttribute(attrName);
+    // XXX if this was '' it is the same as notfound,
+    // so it shadows the class attribute!
+    // This means setting an attribute to '' is the same as deleting it - 
+    // at least at the moment
+    if (! result) {
+        // Make sure result is null, in case we can't produce one
+        // below.
+        result = null;
+        // Now try to get it from the class and id encodings.
+        // Having it in the id gives the advantage that we can use
+        // kss-id-key-value both as a unique html id, and widget markup.
+        var klass = dom.getAttribute(node, 'class');
+        var encodings;
+        if (klass) {
+            encodings = klass.split(/ +/);
+        } else {
+            encodings = [];
+        }
+        var id = dom.getAttribute(node, 'id');
+        if (id) {
+            // We have an id, consider it too
+            // id will be inserted 1st, ie. it overrides possible doubles in classes
+            encodings.unshift(id);
+        }
+        // Get the result-
+        var prefix = namespacedName + '-' + key;
+        return _getKssValueFromEncodings(encodings, prefix);
+    }
+    return result;
+};
+
+dom.setKssValue = function(node, keyType, key, value) {
+    // Sets a given kss attribute on the namespace
+    var namespacedName = _kssNamespacePrefix + '-' + keyType;
+    // We access node.setAttribute directly, because we don't need the
+    // other checks in dom.setAttribute
+    var attrName = namespacedName + ':' + key;
+    node.setAttribute(attrName, value);
+};
+
+
 /* Recursive query of node attributes
    getter is a function that gets the value from the node.
 */
 
-dom.getRecursiveAttribute =
-    function(node, attrname, recurseParents, getter) {
-    var value = getter(node, attrname);
+dom.locateMarkup =
+    function(node, recurseParents, getter, p1, p2, p3, p4, p5) {
+    var value = getter(node, p1, p2, p3, p4, p5);
+    var element = node;
     if (recurseParents) {
-        var element = node;
         // need to recurse even if value="" !
         // We cannot figure out if there exists
         // and attribute in a crossbrowser way, or it is set to "".
@@ -288,16 +371,24 @@
             if (! element || ! element.getAttribute) {
                 break;
             }
-            value = getter(element, attrname);
+            value = getter(element, p1, p2, p3, p4, p5);
         }
     } 
     if (typeof(value) == 'undefined') {
         // notfound arguments will get null
         value = null;
     }
-    return value;
+    // We return both the value and the node where
+    // it was found.
+    return {value:value, node:element};
 };
 
+dom.getRecursiveAttribute =
+    function(node, attrname, recurseParents, getter) {
+    return dom.locateMarkup(node,
+            recurseParents, getter, attrname).value;
+}
+
 /*
 * From http://xkr.us/articles/dom/iframe-document/
 * Note it's not necessary for the iframe to have the name

Modified: kukit/kukit.js/branch/ree-1.4-markup-and-syntax-changes/kukit/eventreg.js
==============================================================================
--- kukit/kukit.js/branch/ree-1.4-markup-and-syntax-changes/kukit/eventreg.js	(original)
+++ kukit/kukit.js/branch/ree-1.4-markup-and-syntax-changes/kukit/eventreg.js	Wed Jan 23 17:35:34 2008
@@ -631,6 +631,38 @@
 this.initialize = function(binder) {
     this.binder = binder;
     this.bound = new _OperRegistry();
+
+    this.getBinder = function () {
+        return this.binder;
+    };
+
+    this.startBindingPhase = function () {
+        // The binding phase starts and it has the information for
+        // the currently on-bound events.
+        this.binding = new _OperRegistry();
+    };
+
+    this.bindOper = function (oper) {
+        // We mark a given oper. This means a binding on the binder 
+        // for given event, node and eventRule (containing event namespace,
+        // name, and evt- parms.)
+        //
+        // first see if it can go to already bound ones
+        this.bound.checkOperBindable(oper);
+        // then register it properly to the binding events
+        this.binding.bindOper(oper);
+    };
+
+    this.processBindingEvents = function () {
+        // We came to the end of the binding phase. Now we process all our binding
+        // events, This will do the actual binding on the browser side.
+        this.binding.processBindingEvents(this.binder);
+        // Now we to add these to the new ones.
+        this.binding.propagateTo(this.bound);
+        // Delete them from the registry, to protect against accidents.
+        this.binding = null;
+    };
+
     this.startBindingPhase();
 };
 

Modified: kukit/kukit.js/branch/ree-1.4-markup-and-syntax-changes/kukit/forms.js
==============================================================================
--- kukit/kukit.js/branch/ree-1.4-markup-and-syntax-changes/kukit/forms.js	(original)
+++ kukit/kukit.js/branch/ree-1.4-markup-and-syntax-changes/kukit/forms.js	Wed Jan 23 17:35:34 2008
@@ -1,5 +1,5 @@
 /*
-* Copyright (c) 2005-2007
+* Copyright (c) 2005-2008
 * Authors: KSS Project Contributors (see doc/CREDITS.txt)
 *
 * This program is free software; you can redistribute it and/or modify
@@ -170,14 +170,14 @@
     this.formname = formname;
 };
 
-this.getForm = fo.CurrentFormLocator.getForm;
-
 this.queryForm = function() {
     // Find the form with the given name.
     return document.forms[this.formname];
 };
 
+this.initialize.apply(this, arguments);
 };
+fo.NamedFormLocator.prototype = new fo.CurrentFormLocator();
 
 /* methods to take the desired value(s) from the form */
 
@@ -210,13 +210,21 @@
                 }
             }
         }
+    // Safari 3.0.3 no longer has "item", instead it works
+    // with direct array access []. Although other browsers
+    // seem to support this as well, we provide checking
+    // in both ways. (No idea if item is still needed.)
     } else if (typeof element.length != 'undefined' && 
-        typeof element.item != 'undefined' && 
-        element.item(0).type == "radio") {
+        ((typeof element[0] != 'undefined' && 
+        element[0].type == "radio") ||
+        (typeof element.item(0) != 'undefined' &&
+        element.item(0).type == "radio"))) {
+        // element really contains a list of input nodes,
+        // in this case.
         var radioList = element;
         value = null;
         for (var i=0; i < radioList.length; i++) {
-            var radio = radioList.item(i);
+            var radio = radioList[i] || radioList.item(i);
             if (radio.checked) {
                 value = radio.value;
             }
@@ -245,6 +253,8 @@
     // Extract the value of a formvar
     var value = null;
     var element = form[name];
+    // (in case of a radio button this will give a collection
+    // that contains the list of input nodes.)
     if (element) {
         var value = fo.getValueOfFormElement(element);
 ;;;     if (value != null) {
@@ -326,14 +336,14 @@
 this.fieldUpdateRegistry = new _FieldUpdateRegistry();
 
 
-// Registry of the pprovider functions for kssSubmitForm
-
-fo.pproviderFormRegistry = new kukit.pr.ValueProviderRegistry();
-
-// form, currentForm will provide identical functions to those 
-// in normal parameters
-// except they return a tuple list, not a dictionary.
+//
+// form, currentForm will fetch an entire form for marshalling.
 // This is needed because duplications and order must be preserved.
+// The returnType of them will be registered as "formquery". This
+// represents a list of (key, value) tuples that need to be marshalled.
+// This assures to preserve order of keys, which is important
+// for multi-values.
+//
 
 /*
 *
@@ -356,7 +366,7 @@
 
 };
 
-fo.pproviderFormRegistry.register('form', _FormValueProvider);
+kukit.pprovidersGlobalRegistry.register('form', _FormValueProvider, 'formquery');
 
 /*
 *
@@ -379,11 +389,7 @@
 
 };
 
-fo.pproviderFormRegistry.register('currentForm', _CurrentFormValueProvider);
-
-// If a string is given, that will look like a form lookup,
-// ie. identical to form
-fo.pproviderFormRegistry.register('', _FormValueProvider);
+kukit.pprovidersGlobalRegistry.register('currentForm', _CurrentFormValueProvider, 'formquery');
 
 
 /* BBB. To be deprecated on 2008-06-15 */

Modified: kukit/kukit.js/branch/ree-1.4-markup-and-syntax-changes/kukit/kssparser.js
==============================================================================
--- kukit/kukit.js/branch/ree-1.4-markup-and-syntax-changes/kukit/kssparser.js	(original)
+++ kukit/kukit.js/branch/ree-1.4-markup-and-syntax-changes/kukit/kssparser.js	Wed Jan 23 17:35:34 2008
@@ -1,5 +1,5 @@
 /*
-* Copyright (c) 2005-2007
+* Copyright (c) 2005-2008
 * Authors: KSS Project Contributors (see doc/CREDITS.txt)
 *
 * This program is free software; you can redistribute it and/or modify
@@ -159,9 +159,9 @@
             break;
         }
         this.expectToken(context, kssp.colon);
-        this.expectToken(context, kssp.PropValue);
+        this.expectToken(context, kssp.MultiPropValue);
         // store the wrapped prop
-        this.addDeclaration(key, context.token.value);
+        this.addDeclaration(key, context.token.values);
         if (context.nextTokenIndex == this.result.length-1) break;
         this.expectToken(context, kssp.semicolon);
     }
@@ -217,8 +217,7 @@
     return results;
 };
 
-this.addEventDeclaration = function(key, splitkey, value) {
-
+this.addEventDeclaration = function(key, splitkey, values) {
     // evt-<EVTNAME>-<PARAMETER>: <VALUE>
     // evt-<NAMESPACE>-<EVTNAME>-<PARAMETER>: <VALUE>
 ;;; if (splitkey.length < 3) {
@@ -245,6 +244,11 @@
         eventKey = splitkey[3];
         eventFullName = eventNamespace + '-' + eventName;
     }
+    // preprocess values
+    var allowedReturnTypes;
+;;; allowedReturnTypes = {string: true};
+;;; kukit.E = 'event parameter [' + key + ']';
+    var value = this.preprocessValues(values, allowedReturnTypes, kukit.E).string;
 ;;; if (value.isMethod != false) {
 ;;;     kukit.E = 'Wrong value for key [' + key + '] : ';
 ;;;     kukit.E += 'value providers are not ';
@@ -260,7 +264,7 @@
     eventParameters[eventKey] = value.txt;
 };
 
-this.addActionDeclaration = function(key, splitkey, value) {
+this.addActionDeclaration = function(key, splitkey, values) {
     // action-server: <ACTIONNAME>
     // action-client: <ACTIONNAME>
     // action-client: <NAMESPACE>-<ACTIONNAME>
@@ -270,13 +274,7 @@
 ;;;     kukit.E = 'Wrong key [' + key + '] : ';
 ;;;     kukit.E += 'action-<QUALIFIER> keys can have only one dash.';
 ;;;     this.emitError(kukit.E);
-;;; }
-;;; if (value.isMethod != false) {
-;;;     kukit.E = 'Wrong value for key [' + key + '] : ';
-;;;     kukit.E += 'value providers are not ';
-;;;     kukit.E += 'allowed for action-<QUALIFIER> keys.';
-;;;     this.emitError(kukit.E);
-;;; }
+;;;     }
     var atab = {'server': 'S', 'client': 'C', 'cancel': 'X'};
     var actionType = atab[splitkey[1]];
 ;;; if (! actionType) {
@@ -284,7 +282,28 @@
 ;;;     kukit.E += 'qualifier in action-<QUALIFIER> keys must be ';
 ;;;     kukit.E += '"server" or "client" or "cancel".'; 
 ;;;     this.emitError(kukit.E);
-;;; }    
+;;;     }    
+    // preprocess values
+    var allowedReturnTypes;
+;;; if (actionType == 'S') {
+;;;     // action-server
+;;;     allowedReturnTypes = {string: true, formquery: true, url: true};
+;;; } else if (actionType == 'C') {
+;;;     // action-client
+;;;     allowedReturnTypes = {string: true, selection: true, alias: true};
+;;; } else {
+;;;     allowedReturnTypes = {string: true, selection: true};
+;;; }
+;;; kukit.E = 'action definition [' + key + ']';
+    var valuesByReturnType = this.preprocessValues(values, allowedReturnTypes, kukit.E);
+    var value = valuesByReturnType.string;
+    //
+;;; if (value.isMethod != false) {
+;;;     kukit.E = 'Wrong value for key [' + key + '] : ';
+;;;     kukit.E += 'value providers are not ';
+;;;     kukit.E += 'allowed for action-<QUALIFIER> keys.';
+;;;     this.emitError(kukit.E);
+;;;     }
 ;;; // force value to be <ACTIONNAME> or <NAMESPACE>-<ACTIONNAME>
 ;;; var splitvalue = value.txt.split('-');
 ;;; if (splitvalue.length > 2) {
@@ -294,17 +313,28 @@
 ;;;     this.emitError(kukit.E);
 ;;; }
     // set it
-    var action = this.actions.getOrCreateAction(value.txt);
-    if (actionType != 'X' || action.type == null) {
-        action.setType(actionType);
+    if (actionType != 'X') {
+        // any other qualifier then delete
+        var action = this.actions.getOrCreateAction(value.txt, valuesByReturnType);
+        if (action.type == null) {
+            action.setType(actionType);
+        }
     } else {
+        // action-cancel
         this.actions.deleteAction(value.txt);
     }
 };
 
-this.addActionError = function(action, key, value) {
+this.addActionError = function(action, key, values) {
     // <ACTIONNAME>-error: <VALUE>
     // default-error: <VALUE>
+    //
+    // This can only accept string. 
+    var allowedReturnTypes;
+;;; allowedReturnTypes = {string: true};
+;;; kukit.E = 'action error parameter [' + key + ']';
+    var value = this.preprocessValues(values, allowedReturnTypes, kukit.E).string;
+;;; // It cannot be a provider, it must be a real string.
 ;;; if (value.isMethod == true) {
 ;;;     kukit.E = 'Wrong value for key [' + key + '] : ';
 ;;;     kukit.E += 'value providers are not ';
@@ -313,17 +343,11 @@
 ;;; }
     action.setError(value.txt);
     // also create the action for the error itself.
-    var err_action = this.actions.getOrCreateAction(value.txt);
+    var err_action = this.actions.getOrCreateAction(value.txt, {});
     err_action.setType('E');
 };
 
-this.addActionParameter = function(action, key, value) {
-    var ppRegistries = {
-        '': kukit.pprovidersGlobalRegistry,
-        'kssSelector': kukit.sr.pproviderSelRegistry,
-        'kssSubmitForm': kukit.fo.pproviderFormRegistry
-    };
-
+this.addActionParameter = function(action, key, values) {
     // <ACTIONNAME>-<KEY>: <VALUE>
     // default-<KEY>: <VALUE>
     // 
@@ -334,26 +358,54 @@
     // This will also set the value providers on the value
     // (from check).
     //
-    // Figure out which registry to use.
-    var registry = ppRegistries[key];
-    if (typeof(registry) == 'undefined') {
-        // use default pproviders
-        registry = ppRegistries[''];
-    }
-    //
-    try {
-        // Check also sets the value provider on the value.
-        value.check(registry);
-    } catch(e) {
-;;;     kukit.E = 'Error in value : ' + e + '.';
-        this.emitError(kukit.E);
+    var value;
+    if (key.substr(0, 3) == 'kss') {
+;;;     // Special selector types can have only one value
+;;;     if (values.length != 1) {
+;;;         kukit.E = 'Must have exactly one value, and got [' + values.length;
+;;;         kukit.E += '] in the kss action parameter [' + key + '].';
+;;;         this.emitError(kukit.E);
+;;;     }
+        value = values[0];
+;;;     // kss special parameter need special checking of the strings.
+;;;     // (not needed in production mode, since we have the value already)
+;;;     var allowedReturnTypes = {};
+;;;     if (key == 'kssSelector') {
+;;;         // for kssSelector, one of string or formquery expected
+;;;         allowedReturnTypes = {string: true, selection: true};
+;;;     } else if (key == 'kssSubmitForm') {
+;;;         // for kssSubmitForm string or formquery expected
+;;;         allowedReturnTypes = {string: true, formquery: true};
+;;;     } else if (key == 'kssUrl') {
+;;;         // for kssUrl string or url expected
+;;;         allowedReturnTypes = {string: true, url: true};
+;;;     }
+;;;     // We ignore actual results here, and just check. 
+;;;     kukit.E = 'kss action parameter [' + key + ']';
+        // Call preprocessValues in both production and development mode:
+        // it is always needed, since it calls check() on the value.
+        // Last parameter is true: means we do _not_ require the existence
+        // of a string type.
+        this.preprocessValues(values, allowedReturnTypes, kukit.E, true);
+    } else {
+        // Normal selectors: can have more values
+        // check its return types
+        var allowedReturnTypes;
+;;;     allowedReturnTypes = {string: true, selection: true};
+;;;     kukit.E = 'action parameter [' + key + ']';
+        var valuesByReturnType = this.preprocessValues(values, allowedReturnTypes, kukit.E);
+        value = valuesByReturnType.string;
+        // Store the selector on the value.
+        value.selectionValue = valuesByReturnType.selection;
     }
+    // store the (main, string) value
     action.parms[key] = value;
 };
 
-this.addDeclaration = function(key, value) {
-    // p.s. value is here a KssXxParm. In most cases we check and unwrap it.
-    // the keys look like this:
+this.addDeclaration = function(key, values) {
+    // values contains a list of arguments (KssTextValue or KssMethodValue)
+    //
+    // the key looks like this:
     //
     // evt-<EVTNAME>-<KEY>: <VALUE>
     // evt-<NAMESPACE>-<EVTNAME>-<KEY>: <VALUE>
@@ -381,11 +433,13 @@
 ;;;     kukit.E += '"evt-<NAMESPACE>-<EVENTNAME>-<PARAMETER>".';
 ;;;     this.emitError(kukit.E);
 ;;; }
+    // Preprocess the values
+    //
     var name = splitkey[0];
     if (name == 'evt') {
-        this.addEventDeclaration(key, splitkey, value);
+        this.addEventDeclaration(key, splitkey, values);
     } else if (name == 'action') {
-        this.addActionDeclaration(key, splitkey, value);
+        this.addActionDeclaration(key, splitkey, values);
     } else {
         // <ACTIONNAME>-<KEY>: <VALUE>
         // <NAMESPACE>-<ACTIONNAME>-<KEY>: <VALUE>
@@ -408,13 +462,77 @@
             actionName = splitkey[0] + '-' + splitkey[1];
             actionKey = splitkey[2];
         }
-        var action = this.actions.getOrCreateAction(actionName);
+        var action = this.actions.getOrCreateAction(actionName, {});
         if (actionKey == 'error') {
-            this.addActionError(action, key, value);
+            this.addActionError(action, key, values);
         } else {
-            this.addActionParameter(action, actionKey, value);
+            this.addActionParameter(action, actionKey, values);
+        }
+    }
+};
+
+this.preprocessValues = function(values, allowedReturnTypes, 
+        errInfo, noStringRequired) {
+    // allowedReturnTypes is a dict keyed by the returnType, containing true as value.
+    // key is only used for the error reporting
+    // This will also call check on all the value names!
+    // noStringRequired is set to true at the kss special parameters. All other
+    // occasions require at least a string to be present, so we check for that too.
+    var valuesByReturnType = {};
+
+    for (var i=0; i<values.length; i++) {
+        var value = values[i];
+        // Checking the value
+        // this is needed for later evaluation.
+        try {
+            // Check also sets the value provider on the value.
+            value.check();
+        } catch(e) {
+;;;         kukit.E = 'Error in value for ' + errInfo + ' : ' + e + '.';
+            this.emitError(kukit.E);
         }
+        // XXX text values are not wrapped. So we need to check for the
+        // pprovider....
+        var returnType = (typeof(value.pprovider) != 'undefined') && value.pprovider.returnType;
+        //for(var xx in value) {print (xx, value[xx]);}
+        // Default return type is "string".
+        if (! returnType) {
+            returnType = 'string';
+        }
+;;;     // Check if return type is allowed.
+;;;     if (! allowedReturnTypes[returnType]){
+;;;         kukit.E = 'Provider result type [' + returnType;
+;;;         kukit.E += '] not allowed in the ' + errInfo +  '.';
+;;;         this.emitError(kukit.E);
+;;;     }
+;;;     // Check duplicate type. Only one provider is allowed
+;;;     // from each return type, ie. maximum one string,
+;;;     // one selector, etc.
+;;;     if (typeof(valuesByReturnType[returnType]) != 'undefined') {
+;;;         if (returnType == 'string') {
+;;;             // Give a more sensible message for strings.
+;;;             // (Do not mention the word "provider" in the message
+;;;             // as action-xxx cannot take providers, only real strings.
+;;;             kukit.E = 'Only one [string] value ';
+;;;             kukit.E += 'is allowed in the ' + errInfo +  '.';
+;;;         } else {
+;;;             kukit.E = 'Only one provider with result type [' + returnType;
+;;;             kukit.E += '] is allowed in the ' + errInfo +  '.';
+;;;         }
+;;;         this.emitError(kukit.E);
+;;;     }
+        // store it
+        valuesByReturnType[returnType] = value;
     }
+;;; // Check we have at least a string type. (unless asked otherwise)
+;;; if (! noStringRequired && typeof(valuesByReturnType.string) == 'undefined') {
+;;;     // (Do not mention the word "provider" in the message
+;;;     // as action-xxx cannot take providers, only real strings.
+;;;     kukit.E = 'Missing [string] value ';
+;;;     kukit.E += 'in the ' + errInfo +  '.';
+;;;     this.emitError(kukit.E);
+;;; }
+    return valuesByReturnType;
 };
 
 };
@@ -422,7 +540,7 @@
     ";": _mkReturnToken(kssp.semicolon),
     ":": function() {
              return [new kssp.colon(this.cursor), 
-                 new kssp.PropValue(this.cursor)]
+                 new kssp.MultiPropValue(this.cursor)]
              },
     "}": _mkEmitAndReturnToken(kssp.closeBrace)
     },
@@ -435,67 +553,110 @@
 var _PropValue = function() {
 
 this.process = function() {
+    // For multivalue only
+    this.values = []
     // Parse all tokens (including first and last)
     var context = {'nextTokenIndex': 0};
-    this.digestTxt(context, kukit.tk.Fraction, kssp.Comment);
     this.txt = '';
-    var txt = context.txt;
-    if (this.notInTokens(context, kssp.String)) {
-        // The previous txt must be all whitespace.
-        if (txt) {
-;;;         kukit.E = 'Wrong value : unallowed characters [' + txt + ']';
-;;;         kukit.E += ' before a string.';
-            this.emitError(kukit.E);
-        }
-        // the next one must be a string.
-        this.expectToken(context, kssp.String);
-        this.produceTxt(context.token.txt);
-    } else if (this.notInTokens(context, kssp.MethodArgs)) {
-        // see if not empty and has no spaces in it 
-        if (! txt || txt.indexOf(' ') != -1) {
-;;;         kukit.E = 'Wrong value : method name [' + txt + '] cannot ';
-;;;         kukit.E += 'have spaces.';
-            this.emitError(kukit.E);
-        }
-        // the next one must be the rules
-        this.expectToken(context, kssp.MethodArgs);
-        this.value = new this.valueClass(txt, context.token.args);
-    } else {
-        // not a string or method: check if we allowed multiword.
-        if (! this.multiword_allowed && txt.indexOf(' ') != -1) {
-;;;         kukit.E = 'Wrong value : [' + txt + '] cannot have spaces.';
-            this.emitError(kukit.E);
+    // Iterate for multiple values (in case allowed.)
+    // txtCarry holds the part of text that we need to consider
+    // as a possible method name, in case method args follow.
+    var txtCarry = '';
+    while (context.nextTokenIndex < this.result.length) { 
+        if (this.notInTokens(context, kukit.kssp.String)) {
+            // A string token follows:
+            if (txtCarry) {
+                // If we have a txt carry left, it needs to be 
+                // produced first, separately.
+                this.produceTxt(txtCarry);
+                txtCarry = '';
+            }
+            // the next one must be a string.
+            this.expectToken(context, kukit.kssp.String);
+            this.produceTxt(context.token.txt);
+        } else if (this.notInTokens(context, kukit.kssp.MethodArgs)) {
+            // A MethodArgs token follows:
+            // see if not empty
+            if (! txtCarry) {
+;;;             // Be a little more intelligent with this error.
+;;;             // If we are single value, and there is a value,
+;;;             // the following raises a smarter error message, complaining
+;;;             // about the () as excess.
+;;;             this.addValue(null, '(');
+;;;             // otherwise, just do the next error message:
+;;;             kukit.E = 'Wrong value : empty method name.';
+                this.emitError(kukit.E);
+            }
+            // the next one must be the (a1, a2, ...an) method args.
+            this.expectToken(context, kukit.kssp.MethodArgs);
+            // The txtCarry will be used as the name of the method.
+            this.addValue(new kukit.rd.KssMethodValue(txtCarry, context.token.args),
+                         txtCarry);
+            txtCarry = '';
+        } else {
+            // Try to digest another fraction.
+            this.digestTxt(context, kukit.tk.Fraction, kukit.kssp.Comment);
+            //
+            // Split the fraction to words. We may have a word
+            // and we may have a MethodArg after:
+            //   wordone ... wordlast(...) ...
+            //   ^^^^^^^^^^^^^^^^^^^^           - these are in the Fraction
+            //                       ^^^^^      - these are the MethodArgs 
+            // So we produce all strings except the last one, and
+            // continue the cycle with the last one (worlast) as txt.
+            // This enables it to be produced with the MethodArgs.
+            //
+            var words = context.txt.split(' ');
+            // Emit the original txtCarry - if there is one.
+            if (txtCarry) {
+                this.produceTxt(txtCarry);
+                txtCarry = '';
+            }
+            // If we have input, process it.
+            if (words.length > 0) {
+                // Produce all strings except the last one
+                for (var i=0; i<words.length - 1; i++) {
+                    this.produceTxt(words[i]);
+                }
+                // Carry the last one to the next iteration.
+                txtCarry = words[words.length - 1];
+            }
         }
-        this.produceTxt(txt);
     }
-    // see what's after
-    if (context.nextTokenIndex < this.result.length) {
-        this.digestTxt(context, kukit.tk.Fraction, kssp.Comment);
-        // we have to be at the end and have no text after
-        if (context.nextTokenIndex < this.result.length || context.txt) {
-;;;         kukit.E = 'Wrong value : unallowed characters after ';
-;;;         kukit.E += 'the property.';
-            this.emitError(kukit.E);
-        }
+    if (txtCarry) {
+        // If we have a txt carry, it needs to be produced finally.
+        this.produceTxt(txtCarry);
     }
     this.result = [];
 };
 
 this.initialize = function() {
-    this.multiword_allowed = true;
+    this.multiword_allowed = false;
     this.valueClass = kukit.rd.KssMethodValue;
 };
 
 this.produceTxt = function(txt) {
-    // txt parms are returned embedded
-    this.value = new kukit.rd.KssTextValue(txt);
+    this.addValue(new kukit.rd.KssTextValue(txt), txt);
+};
+
+this.addValue = function(value, errInfo) {
+    // Do not allow a second value
+    if (this.value) {
+;;;     kukit.E = 'Wrong value : unallowed characters [';
+;;;     kukit.E += errInfo + '] after ';
+;;;     kukit.E += 'the argument.';
+        this.emitError(kukit.E);
+    }
+    this.value = value;
 };
+
 this.initialize.apply(this, arguments);
 };
 kssp.PropValue = kukit.tk.mkParser('propValue', {
     ";": _emitAndReturn,
     "}": _emitAndReturn,
     ")": _emitAndReturn,
+    "]": _emitAndReturn,
     ",": _emitAndReturn,
     "'": _returnString,
     '"': _returnString2,
@@ -506,36 +667,35 @@
     );
 
 /*
-* class PropValueInMethod
-*
-* PropValue in method cannot have method-style vars.
+* class MultiPropValue
+* 
+* A list of PropValue-s (arguments), separated by whitespace
 */
-var _PropValueInMethod = function() {
+var _MultiPropValue = function() {
 
-this.initialize = function() {
-    this.multiword_allowed = false;
-};
+    this.addValue = function(value, errInfo) {
+        this.values.push(value);
+    };
+
+    this.initialize = function() {
+        this.multiword_allowed = true;
+    };
 
-this.produceTxt = function(txt) {
-    // txt parms are returned unwrapped
-    this.txt = txt;
-};
-this.initialize.apply(this, arguments);
 };
-// this assignment needs to remain after initialization of _PropValue
-kssp.PropValueInMethod = kukit.tk.mkParser('propValue', {
+_MultiPropValue.prototype = new _PropValue();
+kssp.MultiPropValue = kukit.tk.mkParser('multiPropValue', {
     ";": _emitAndReturn,
     "}": _emitAndReturn,
     ")": _emitAndReturn,
-    "]": _emitAndReturn,
     ",": _emitAndReturn,
     "'": _returnString,
     '"': _returnString2,
-    "\/\*": _returnComment
+    "\/\*": _returnComment,
+    "(": _returnMethodArgs
     },
-    _PropValueInMethod
+    _MultiPropValue
     );
-kssp.PropValueInMethod.prototype.process = kssp.PropValue.prototype.process;
+
 
 /*
 * class EventValue
@@ -864,7 +1024,7 @@
             } break;
         }
     }
-    // Now we found the token that must be <fraction> <colon> <propValue>.
+    // Now we found the token that must be <fraction> <colon> <multiPropValue>.
     tokenIndex -= 2;
     if (tokenIndex < 0
          || (this.result[tokenIndex+2].symbol !=
@@ -942,7 +1102,7 @@
 ;;;     } else {
 ;;;         throw e;
 ;;;     }
-;;; }
+;;; };
     this.txt = '';
     this.result = [];
 };

Modified: kukit/kukit.js/branch/ree-1.4-markup-and-syntax-changes/kukit/oper.js
==============================================================================
--- kukit/kukit.js/branch/ree-1.4-markup-and-syntax-changes/kukit/oper.js	(original)
+++ kukit/kukit.js/branch/ree-1.4-markup-and-syntax-changes/kukit/oper.js	Wed Jan 23 17:35:34 2008
@@ -59,6 +59,44 @@
     this.orignode = null;
     this.action = null;
     this.browserevent = null;
+
+    this.clone = function(dict, restricted) {
+        var newoper = new kukit.op.Oper(this);
+        newoper.unrestrictedUpdate(dict, restricted);
+        return newoper;
+    };
+
+    this.update = function(dict) {
+        // restricted attrs must not be changed on existing oper.
+        this.unrestrictedUpdate(dict, true);
+    };
+
+    this.unrestrictedUpdate = function(dict, restricted) {
+        if (typeof(dict) == 'undefined') {
+            return;
+        }
+        for (var key in dict) {
+;;;         if (typeof(checkKey) == 'undefined') {
+;;;             var checkKey = function(key) {
+;;;                 var isNode = key == 'node';
+;;;                 var isParameters = key == 'parms';
+;;;                 var isEventRule = key == 'eventRule';
+;;;                 var isBinder = key == 'binder';
+;;;                 var isOrig = key == 'orignode';
+;;;             return isNode || isParameters || isEventRule || isBinder || isOrig;
+;;;             };
+;;;         }
+;;;         if (restricted && checkKey(key)) {
+;;;             kukit.E = 'Illegal update on oper object, protected attribute [';
+;;;             kukit.E += key + '].';
+;;;             throw new Error(kukit.E);
+;;;         }
+            var value = dict[key];
+            if (typeof(value) != 'function') {
+                this[key] = value;
+            }
+        }
+    };
     // update from the dict
     this.unrestrictedUpdate(dict);
 };
@@ -206,18 +244,27 @@
 };
 
 this.executeServerAction = function(name) {
-;;; for (key in this.kssParms) {
-;;;     if (key == 'kssUrl') {
-;;;         // Value will be evaluated.
-;;;     } else if (key == 'kssSubmitForm') {
+    for (key in this.kssParms) {
+        if (key == 'kssSubmitForm') {
+            // Value has been evaluated at this point.
+            var formQuery = this.kssParms[key];
+            // If a string is returned: this is to support
+            // kssSubmitForm: "formname";
+            // in this case this is evaluated as form("formname").
+            if (typeof(formQuery) == 'string') {
+                var locator = new kukit.fo.NamedFormLocator(formQuery);
+                var collector = new kukit.ut.TupleCollector();
+                formQuery = kukit.fo.getAllFormVars(locator, collector);
+            }
+;;;     } else if (key == 'kssUrl') {
 ;;;         // Value will be evaluated.
 ;;;     } else {
 ;;;        kukit.E = 'Wrong parameter : [' + key + '] starts with "kss";';
 ;;;         kukit.E += ' normal parms (that do not start with kss)';
-;;;         kukit.E += ' only are allowed in action-server keys.';
+;;;         kukit.E += ' only are allowed in action-default keys.';
 ;;;         throw new Error(kukit.E);
-;;;     }
-;;; }
+        }
+    }
     // oper will be accessible to some commands that execute in return
     var sa = new kukit.sa.ServerAction(name, this);
 };

Modified: kukit/kukit.js/branch/ree-1.4-markup-and-syntax-changes/kukit/plugin.js
==============================================================================
--- kukit/kukit.js/branch/ree-1.4-markup-and-syntax-changes/kukit/plugin.js	(original)
+++ kukit/kukit.js/branch/ree-1.4-markup-and-syntax-changes/kukit/plugin.js	Wed Jan 23 17:35:34 2008
@@ -541,7 +541,8 @@
 
 this.timeoutSetState = function() {
     // really call the bound actions which should set the spinner
-    this.func_to_bind();
+    var func = this.func_to_bind;
+    func();
 };
 this.initialize.apply(this, arguments);
 };

Modified: kukit/kukit.js/branch/ree-1.4-markup-and-syntax-changes/kukit/providerreg.js
==============================================================================
--- kukit/kukit.js/branch/ree-1.4-markup-and-syntax-changes/kukit/providerreg.js	(original)
+++ kukit/kukit.js/branch/ree-1.4-markup-and-syntax-changes/kukit/providerreg.js	Wed Jan 23 17:35:34 2008
@@ -1,5 +1,5 @@
 /*
-* Copyright (c) 2005-2007
+* Copyright (c) 2005-2008
 * Authors: KSS Project Contributors (see doc/CREDITS.txt)
 *
 * This program is free software; you can redistribute it and/or modify
@@ -32,7 +32,7 @@
     this.content = {};
 };
 
-this.register = function(name, func) {
+this.register = function(name, func, returnType) {
     if (typeof(func) == 'undefined') {
 ;;;     kukit.E = 'func argument is mandatory when registering a parameter'
 ;;;     kukit.E += ' provider [ValueProviderRegistry.register].';
@@ -46,6 +46,11 @@
 ;;;    return;
 ;;; }
     this.content[name] = func;
+    // Handle return type
+    // XXX Store it on the func's prototype.
+    // This is a temporary solution, the service-layer
+    // branch offers a proper way to do this.
+    func.prototype.returnType = returnType;
 };
 
 this.exists = function(name) {
@@ -64,6 +69,9 @@
 this.initialize.apply(this, arguments);
 };
 
+}();                              /// MODULE END
+
+kukit.dummy = new function() {   /// MODULE START
 /*
 * Register the core parameter providers
 *
@@ -164,8 +172,7 @@
     if (args.length == 2) {
 ;;;     kukit.E = '2nd attribute of currentFormVarForKssAttr must be a';
 ;;;     kukit.E += ' boolean';
-        kukit.ut.evalBool(args[1], kukit.E);
-        recurseParents = args[1];
+        recurseParents = kukit.ut.evalBool(args[1], kukit.E);
     }
     var formvarname = kukit.dom.getRecursiveAttribute(node, argname,
         recurseParents, kukit.dom.getKssAttribute);
@@ -176,50 +183,6 @@
 };
 
 
-/* BBB. To be deprecated at 2007-08-15 */
-/*
-*  class _FormPP
-*/
-var _FormPP = function() {
-
-this.check = function(args) {
-;;; if (args.length != 1) {
-;;;     throw new Error('form method needs 1 arguments [formname]');
-;;; }
-;;; var msg = 'Deprecated the [form(formname)] parameter provider,';
-;;; msg += ' use [xxx-kssSubmitForm: form(formname)] instead !';
-;;; kukit.logWarning(msg);
-};
-
-this.eval = function(args, node) {
-    return kukit.fo.getAllFormVars(new kukit.fo.NamedFormLocator(args[0]),
-        new kukit.ut.DictCollector());
-};
-
-};
-
-/* BBB. To be deprecated at 2007-08-15 */
-/*
-*  class _CurrentFormPP
-*/
-var _CurrentFormPP = function() {
-
-this.check = function(args) {
-;;; if (args.length != 0) {
-;;;     throw new Error('currentForm method needs no argument');
-;;; }
-;;; var msg = 'Deprecated the [currentForm()] parameter provider,';
-;;; msg += ' use [xxx-kssSubmitForm: currentForm()] instead !';
-;;; kukit.logWarning(msg);
-};
-
-this.eval = function(args, node) {
-    return kukit.fo.getAllFormVars(new kukit.fo.CurrentFormLocator(node),
-        new kukit.ut.DictCollector());
-};
-
-};
-
 /*
 *  class _NodeAttrPP
 */
@@ -231,10 +194,14 @@
 ;;;     kukit.E += ' [recurseParents]).';
 ;;;     throw new Error(kukit.E);
 ;;; }
-;;; if (args[0].toLowerCase() == 'style') {
+};
+
+this.eval = function(args, node) {
+    var argname = args[0];
+;;; if (argname.toLowerCase() == 'style') {
 ;;;     throw new Error('nodeAttr method does not accept [style] as attrname.');
 ;;; }
-;;; if (args[0].match(/[ ]/)) {
+;;; if (argname.match(/[ ]/)) {
 ;;;     throw new Error('attrname parameter in nodeAttr method cannot contain space.');
 ;;; }
 };
@@ -245,7 +212,7 @@
     if (args.length == 2) {
         recurseParents = args[1];
 ;;;     kukit.E = '2nd attribute of nodeAttr must be a boolean.';
-        kukit.ut.evalBool(recurseParents, kukit.E);
+        recurseParents = kukit.ut.evalBool(recurseParents, kukit.E);
     }
     return kukit.dom.getRecursiveAttribute(node, argname, recurseParents,
         kukit.dom.getAttribute);
@@ -259,12 +226,29 @@
 var _KssAttrPP = function() {
 
 this.check = function(args) {
+;;; // Uncomment next part to activate BBB:
+;;; //kukit.E = 'kssAttr is deprecated and will be removed at ';
+;;; //kukit.E += '2008-XX-XX';
+;;; //kukit.E += ', use kssValue. Change your html ';
+;;; //kukit.E += 'class markup from kssattr-key-value to ';
+;;; //kukit.E += 'kss-attr-key-value, ';
+;;; //kukit.E += 'and change the provider from kssAttr(key, true) to ';
+;;; //kukit.E += 'kssValue(attr, key). Note that kssValue has a third ';
+;;; //kukit.E += 'parameter to enable/disable recursion, but in contrary ';
+;;; //kukit.E += 'to kssAttr, kssValue has recursion by default enabled ';
+;;; //kukit.E += '(true).';
+;;; //kukit.logWarning(kukit.E);
 ;;; if (args.length != 1 && args.length != 2) {
 ;;;     kukit.E = 'kssAttr method needs 1 or 2 argument (attrname,';
 ;;;     kukit.E += ' [recurseParents]).';
 ;;;     throw new Error(kukit.E);
 ;;; }
-;;; if (args[0].match(/[ -]/)) {
+};
+
+this.eval = function(args, node) {
+    var argname =  args[0];
+    var recurseParents = false;
+;;; if (argname.match(/[ -]/)) {
 ;;;     kukit.E = 'attrname parameter in kssAttr method cannot contain';
 ;;;     kukit.E += ' dashes or spaces.';
 ;;;     throw new Error(kukit.E);
@@ -277,7 +261,7 @@
     if (args.length == 2) {
         recurseParents = args[1];
 ;;;     kukit.E = '2nd attribute of kssAttr must be a boolean.';
-        kukit.ut.evalBool(recurseParents, kukit.E);
+        recurseParents = kukit.ut.evalBool(recurseParents, kukit.E);
     }
     return kukit.dom.getRecursiveAttribute(node, argname, recurseParents,
         kukit.dom.getKssAttribute);
@@ -354,8 +338,114 @@
 
 };
 
+var _KssValuePP = function() {
+
+    this.check = function(args) {
+;;;     if (args.length != 2 && args.length != 3) {
+;;;         kukit.E = 'kssValue provider needs 2 or 3 argument (keytype, key,';
+;;;         kukit.E += ' [recurseParents]).';
+;;;         throw new Error(kukit.E);
+;;;     }
+    };
+
+    this.eval = function(args, node) {
+        var keytype =  args[0];
+        var key =  args[1];
+        // recurseParents is by default true
+        var recurseParents = true;
+;;;     if (keytype.match(/[ -]/)) {
+;;;         kukit.E = 'keytype parameter in kssValue provider cannot contain';
+;;;         kukit.E += ' dashes or spaces.';
+;;;         throw new Error(kukit.E);
+;;;     }
+;;;     if (key.match(/[ -]/)) {
+;;;         kukit.E = 'key parameter in kssValue provider cannot contain';
+;;;         kukit.E += ' dashes or spaces.';
+;;;         throw new Error(kukit.E);
+;;;     }
+        if (args.length == 3) {
+            recurseParents = args[2];
+;;;         kukit.E = '3rd attribute of kssAttr must be a boolean.';
+            recurseParents = kukit.ut.evalBool(recurseParents, kukit.E);
+        }
+        return kukit.dom.locateMarkup(node, recurseParents, 
+                kukit.dom.getKssValue, 
+                keytype, key).value;
+
+    };
+
+};
+
+var _KssIdOfValuePP = function() {
+
+    this.check = function(args) {
+;;;     if (args.length != 2) {
+;;;         kukit.E = 'kssIdOfValue provider needs 2 arguments (keytype, key).';
+;;;         throw new Error(kukit.E);
+;;;     }
+    },
+
+    this.eval = function(args, node) {
+        var keytype =  args[0];
+        var key =  args[1];
+;;;     if (keytype.match(/[ -]/)) {
+;;;         kukit.E = 'keytype parameter in kssIdOfValue provider cannot contain';
+;;;         kukit.E += ' dashes or spaces.';
+;;;         throw new Error(kukit.E);
+;;;     }
+;;;     if (key.match(/[ -]/)) {
+;;;         kukit.E = 'key parameter in kssIdOfValue provider cannot contain';
+;;;         kukit.E += ' dashes or spaces.';
+;;;         throw new Error(kukit.E);
+;;;     }
+        var markup = kukit.dom.locateMarkup(node, true, 
+                kukit.dom.getKssValue, 
+                keytype, key);
+        // return the id of the node where the markup is found
+        var id = markup.node.id;
+        if (typeof(id) == 'undefined') {
+            // notfound arguments will get null
+            id = null;
+        }
+        return id;
+    }
+};
 
-kukit.pprovidersGlobalRegistry = new this.ValueProviderRegistry();
+
+/* The url() provider just passes the parameter, and is used to have
+ * a different return type. It can be used in the line of action-server.
+ * as an alternative to a separate kssUrl line.
+ */
+var _UrlPP = function() {
+    this.check = function(args) {
+;;;     if (args.length != 1) {
+;;;         throw new Error('url() needs 1 argument');
+;;;     }
+    };
+};
+_UrlPP.prototype = new _IdentityPP();
+
+
+/* The alias() provider just passes the parameter, and is used to have
+ * a different return type. It can be used in the line of action-client.
+ */
+var _AliasPP = function() {
+    this.check = function(args) {
+;;;     if (args.length != 1) {
+;;;         throw new Error('alias() needs 1 argument');
+;;;     }
+;;;     if (args[0].isMethod) {
+;;;         kukit.E = 'Value providers are not ';
+;;;         kukit.E += 'allowed as argument for ';
+;;;         kukit.E += 'alias(), [' + args[0].methodName + '] found.';
+;;;         throw new Error(kukit.E);
+;;;     }
+    };
+};
+_AliasPP.prototype = new _IdentityPP();
+
+
+kukit.pprovidersGlobalRegistry = new kukit.pr.ValueProviderRegistry();
 
 kukit.pprovidersGlobalRegistry.register('', _IdentityPP);
 kukit.pprovidersGlobalRegistry.register('currentFormVar',
@@ -368,8 +458,13 @@
 kukit.pprovidersGlobalRegistry.register('pass', _PassPP);
 kukit.pprovidersGlobalRegistry.register('nodeContent', _NodeContentPP);
 kukit.pprovidersGlobalRegistry.register('nodeAttr', _NodeAttrPP);
-kukit.pprovidersGlobalRegistry.register('form', _FormPP);
-kukit.pprovidersGlobalRegistry.register('currentForm', _CurrentFormPP);
+kukit.pprovidersGlobalRegistry.register('kssValue', _KssValuePP);
+kukit.pprovidersGlobalRegistry.register('kssIdOfValue', _KssIdOfValuePP);
+// returnType = 'url'
+kukit.pprovidersGlobalRegistry.register('url', _UrlPP, 'url');
+// returnType = 'alias'
+kukit.pprovidersGlobalRegistry.register('alias', _AliasPP, 'alias');
 
 }();                              /// MODULE END
 
+

Modified: kukit/kukit.js/branch/ree-1.4-markup-and-syntax-changes/kukit/requestmanager.js
==============================================================================
--- kukit/kukit.js/branch/ree-1.4-markup-and-syntax-changes/kukit/requestmanager.js	(original)
+++ kukit/kukit.js/branch/ree-1.4-markup-and-syntax-changes/kukit/requestmanager.js	Wed Jan 23 17:35:34 2008
@@ -171,7 +171,7 @@
 */
 rm.RequestManager = function () {
 
-this.initialize = function (maxNr, name, schedulerClass) {
+this.initialize = function (name, maxNr, schedulerClass) {
     // schedulerClass is mainly provided for debugging...
     this.waitingQueue = new kukit.ut.FifoQueue();
     this.sentNr = 0;
@@ -189,9 +189,12 @@
         nameString = '[' + name + '] ';
         }
     this.nameString = nameString;
-    if (typeof(maxNr) != 'undefined' && maxNr != null) {
-        this.maxNr = maxNr;
+    // max request number
+    if (typeof(maxNr) == 'undefined' || maxNr == null) {
+        // Default is 4
+        maxNr = 4;
     }
+    this.maxNr = maxNr;
     // sets the timeout scheduler
     var checkTimeout = function() {
        self.checkTimeout();

Modified: kukit/kukit.js/branch/ree-1.4-markup-and-syntax-changes/kukit/resourcedata.js
==============================================================================
--- kukit/kukit.js/branch/ree-1.4-markup-and-syntax-changes/kukit/resourcedata.js	(original)
+++ kukit/kukit.js/branch/ree-1.4-markup-and-syntax-changes/kukit/resourcedata.js	Wed Jan 23 17:35:34 2008
@@ -1,5 +1,5 @@
 /*
-* Copyright (c) 2005-2007
+* Copyright (c) 2005-2008
 * Authors: KSS Project Contributors (see doc/CREDITS.txt)
 *
 * This program is free software; you can redistribute it and/or modify
@@ -28,7 +28,7 @@
 */
 rd.KssSelector = function() {
 
-this.initialize = function(isEvent, css, name, namespace, id, ppid, eventRegistry) {
+this.initialize = function(isEvent, css, name, namespace, id, ppid) {
     this.isEventSelector = isEvent;
     this.isMethodSelector = ! isEvent;
 // XXX GC row and column are wrong...
@@ -70,16 +70,19 @@
     this.className = null;
     this.id = id;
     this.ppid = ppid;
-    this.setClassName(eventRegistry);
+    // finish up the KSS on it
+    // XXX This disables testing the parser
+    // without a plugin registry, since it needs access to the registry.
+    this.setClassName();
 };
     
 // finish up the KSS on it
-this.setClassName = function(eventRegistry) {
+this.setClassName = function() {
     // Sets up id and class on the selector, based on registration info
     // XXX GC instead of relying on exceptions, test if key exists
     try {
-        this.className = eventRegistry.get(
-            this.namespace, this.name).className;
+        this.className = kukit.eventsGlobalRegistry.get(
+        this.namespace, this.name).className;
     } catch(e) {
         throw kukit.err.parsingError(e.message);
     }
@@ -158,7 +161,7 @@
 
 this.check = function(registry) {
     // use the IdentityPP provider.
-    this.pprovider = new (registry.get(''))();
+    this.pprovider = new (kukit.pprovidersGlobalRegistry.get(''))();
 };
 
 this.evaluate =
@@ -186,24 +189,60 @@
 
 this.check = function(registry) {
     // Check syntax
-    var f = registry.get(this.methodName);
+    var f = kukit.pprovidersGlobalRegistry.get(this.methodName);
     this.pprovider = new f();
-    for(i=0; i < this.args.length; i++){
+;;; //Check the provider first.
+;;; this.pprovider.check(this.args);
+    // After checking the provider, we check the args recursively.
+    for(var i=0; i < this.args.length; i++){
         // XXX We treat text values separetly because
         // they are now currently wrapped as KssTextValue
         // (as they should). TODO
         var arg = this.args[i];
+        // XXX this is a check for a MethodValue, since
+        // all text arguments are strings. -- this is fixed
+        // on the service-layer branch
         if(arg.check){
-            // With the recursion we always use the global
-            // provider registry
-            arg.check(kukit.pprovidersGlobalRegistry);
+            arg.check();
+;;;         // The page provider should have checked if the parameters
+;;;         // return the appropriate value type. If it has done
+;;;         // this check, it has set checkedArgTypes. 
+;;;         // If a provider expects all strings
+;;;         // (like most value providers), it simply leaves this flag 
+;;;         // intact, and we do the check here.
+;;;         if (! this.pprovider.checkedArgTypes) {
+;;;             // We expect a string to each position.
+;;;             // By default, returnType is "string" so we also
+;;;             // check undefined.
+;;;             var returnType = arg.pprovider.returnType;
+;;;             if (returnType && returnType != 'string') {
+;;;                 kukit.E = 'Expected string value and got [' + returnType;
+;;;                 kukit.E += '] in argument #[' + (i + 1) + '] of provider [';
+;;;                 kukit.E += this.methodName + '].';
+;;;                 throw new Error(kukit.E);
+;;;             }
+;;;         }
+
         }
     }
-;;; this.pprovider.check(this.args);
 };
 
 this.evaluate =
     function(node, defaultParameters) {
+    // In case we have a selector, evaluate it.
+    if (this.selectionValue) {
+        var nodes = this.selectionValue.evaluate(node, defaultParameters)
+        // This must have returned exactly one node. If not, we raise error.
+        if (nodes.length != 1) {
+;;;         kukit.E = 'Selection provider [' + this.selectionValue.methodName;
+;;;         kukit.E += '] of value provider [' + this.methodName;
+;;;         kukit.E += '] must select exactly one node, '
+;;;         kukit.E += 'got [' + nodes.length + '] instead.';
+            throw new Error(kukit.E);
+        }
+        // Use this as node!
+        node = nodes[0];
+    }
     // First recursivly evaluate all arguments
     var newArgs = [];
     for(var i=0; i < this.args.length; i++){
@@ -492,13 +531,39 @@
     }
 };
 
-this.getOrCreateAction = function(name) {
+this.getOrCreateAction = function(name, valuesByReturnType) {
+    // kss parameters will ve set from valuesByReturnType 
+    //
+    // In case we alias, use the alias for name, this will become
+    // the action name used for execution. The alias name will
+    // be used as name, and serve for decide merging.
+    var nameOverride;
+    if (valuesByReturnType.alias) {
+        nameOverride = name;
+        // This is always a string, no provider allowed.
+        // 
+        // XXX atm, strings are unwrapped. (this is fixed
+        // in service-layer branch)
+        name = valuesByReturnType.alias.args[0];
+    }
+    // Check if we have this action already
     var action = this.content[name];
     if (typeof(action) == 'undefined') {
         action = new _Action();
-        action.setName(name);
+        action.setName(name, nameOverride);
         this.content[name] = action;
     }
+    // Set other values that were given at the same line as the name.
+    // This enables individual overriding.
+    if (valuesByReturnType.selection) {
+        action.parms.kssSelector = valuesByReturnType.selection;
+    }
+    if (valuesByReturnType.formquery) {
+        action.parms.kssSubmitForm = valuesByReturnType.formquery;
+    }
+    if (valuesByReturnType.url) {
+        action.parms.kssUrl = valuesByReturnType.url;
+    }
     return action;
 };
 
@@ -541,15 +606,55 @@
     this.error = null;
     this.parms = {};
     this.type = null;
+    this.nameOverride = null;
 };
 
-this.setName = function(name) {
-;;; if (this.name != null && this.name != name) {
-;;;     var msg = 'Error overriding action name [' + this.name;
-;;;     msg = msg + '] to [' + name + '] (Unmatching action names at merge?)';
-;;;     throw kukit.err.ruleMergeError(msg);
+this.getExecutingName = function getExecutingName() {
+    // Returns action name that is to be used for execution.
+    // In case nameOverride is empty, name is used both as merging
+    // key, and for selecting the action at execution.
+    // In case nameOverride is specified, name is still used for
+    // merging, but nameOverride is used when we need to
+    // execute the action.
+    // This is used for  action-client: nameOverride alias(name).
+    return this.nameOverride || this.name;
+};
+
+this.setName = function(name, nameOverride) {
+    if (typeof(nameOverride) == 'undefined' || name == nameOverride) {
+        // use null for no-value.
+        //
+        // Also: If we alias to the same name as the action name,
+        // simply ignore aliasing and just handle the real action.
+        nameOverride = null;
+    }
+;;; // We check that the name did not change.
+;;; if (this.name != null) {
+;;;     if (this.name != name) {
+;;;         kukit.E = 'Error overriding action name [' + this.name;
+;;;         kukit.E += '] to [' + name + '] (Unmatching action names or aliases at merge?)';
+;;;         throw kukit.err.ruleMergeError(kukit.E);
+;;;     }
+;;;     // nameOverride can only be specified when name is also specified.
+;;;     // We also check that the override cannot change, ie. it is not
+;;;     // possible to use the same alias for different actions.
+;;;     // However we allow this.nameOverride to have a value and nameOverride
+;;;     // to be null.
+;;;     if (nameOverride != null && this.nameOverride != nameOverride) {
+;;;         kukit.E = 'Error overriding action name for alias [' + this.name;
+;;;         kukit.E += '] from [' + this.nameOverride;
+;;;         kukit.E += '] to [' + nameOverride + '] ';
+;;;         kukit.E += '(Different actions aliased by the same alias?)';
+;;;         throw kukit.err.ruleMergeError(kukit.E);
+;;;     }
 ;;; }
+    // Store the values.
     this.name = name;
+    // nameOverride is only overwritten if value exists.
+    if (nameOverride != null) {
+        this.nameOverride = nameOverride;
+    }
+    // Handle default action.
     if (name == 'default') {
 ;;;     if (this.type != null && this.type != 'D') {
 ;;;         var msg = 'Error setting action to default on action [' + this.name;
@@ -601,7 +706,8 @@
 this.merge = function(other) {
     // Merge to the instance.
     if (other.name != null) { 
-        this.setName(other.name);
+        // We also use nameOverride from the other.
+        this.setName(other.name, other.nameOverride);
     }
     if (other.type != null) { 
         this.setType(other.type);
@@ -615,6 +721,17 @@
     }
 };
 
+// The evaluation of string is handled specially
+// in case of some parameter names.
+//
+//     kssSelector    string "foo" evaluates as css("foo")
+//     kssSubmitForm  string "foo" evaluates as form("foo")
+//
+var _defaultStringHandling = {
+    'kssSelector': 'css',
+    'kssSubmitForm': 'form'
+};
+
 this.makeActionOper = function(oper) {
     // Fill the completed action parms, based on the node
     // The kssXxx parms, reserved for the action, are 
@@ -626,16 +743,30 @@
     if (typeof(oper.defaultParameters) == 'undefined') {
         oper.defaultParameters = {};
     }
+    // Evaluate all parameters.
     for (var key in this.parms) {
-        var kssvalue = this.parms[key]; 
+        // Evaluate the value of the parameter.
+        var value = this.parms[key].evaluate(oper.node,
+                oper.defaultParameters);
+        // Final handling of special cases.
+        // This is needed in case we have a string, and we
+        // look up the provider we need from the _defaultStringHandling table.
+        var providerName = _defaultStringHandling[key];
+        if (providerName && typeof(value) == 'string') {
+            // Use the value provider. This means the string is
+            // a shortcut and this provider is applied.
+            var providerClass = kukit.pprovidersGlobalRegistry.get(providerName);
+            var provider = new providerClass();
+            // check is not needed now... we evaluate it right away
+            value = provider.eval([value], oper.node, oper.defaultParameters);
+        }
+        // Store it, depending if it's a kss or normal parameter.
         if (key.match(/^kss/)) {
             // kssXxx parms are separated to kssParms.
-            kssParms[key] = kssvalue.evaluate(oper.node,
-                oper.defaultParameters); 
+            kssParms[key] = value; 
         } else {
             // evaluate the method parms into parms
-            parms[key] = kssvalue.evaluate(oper.node,
-                oper.defaultParameters); 
+            parms[key] = value;
         }
     }
     var anOper = oper.clone({
@@ -660,7 +791,9 @@
         } break;
         case 'C': {
             // Client action.
-            oper.executeClientAction(this.name);
+            // Need to execute the real name,
+            // since aliasing is possible here.
+            oper.executeClientAction(this.getExecutingName());
         } break;
         case 'E': {
             // Error action (= client action)

Modified: kukit/kukit.js/branch/ree-1.4-markup-and-syntax-changes/kukit/selectorreg.js
==============================================================================
--- kukit/kukit.js/branch/ree-1.4-markup-and-syntax-changes/kukit/selectorreg.js	(original)
+++ kukit/kukit.js/branch/ree-1.4-markup-and-syntax-changes/kukit/selectorreg.js	Wed Jan 23 17:35:34 2008
@@ -1,5 +1,5 @@
 /*
-* Copyright (c) 2005-2007
+* Copyright (c) 2005-2008
 * Authors: KSS Project Contributors (see doc/CREDITS.txt)
 *
 * This program is free software; you can redistribute it and/or modify
@@ -84,7 +84,7 @@
 };
 
 };
-sr.pproviderSelRegistry.register('passnode', _PassnodePP);
+sr.pproviderSelRegistry.register('passnode', _PassnodePP, 'selection');
 
 
 /* 
@@ -115,7 +115,8 @@
     this.mapping[name] = func;
     // Also register the selector param provider
     var pp = sr.makeAnyPP(name);
-    sr.pproviderSelRegistry.register(name, pp);
+    // register them with returnType = 'nodes'
+    kukit.pprovidersGlobalRegistry.register(name, pp, 'selection');
 };
 
 this.get = function(name) {
@@ -184,4 +185,35 @@
     return results;
 });
 
+var _KssMarkedNodePP = function() {
+    this.check = function(args){
+;;;     if (args.length != 2) {
+;;;         throw new Error('kssMarkedNode selector method needs 2 arguments (keyType, key)');
+;;;     }
+    };
+
+    this.eval = function(args, node, defaultParameters) {
+        var keyType =  args[0];
+        var key =  args[1];
+;;;     if (keyType.match(/[ -]/)) {
+;;;         kukit.E = 'keyType parameter in kssMarkedNode selection provider cannot contain';
+;;;         kukit.E += ' dashes or spaces.';
+;;;         throw new Error(kukit.E);
+;;;     }
+;;;     if (key.match(/[ -]/)) {
+;;;         kukit.E = 'key parameter in kssMarkedNode provider cannot contain';
+;;;         kukit.E += ' dashes or spaces.';
+;;;         throw new Error(kukit.E);
+;;;     }
+        var markup = kukit.dom.locateMarkup(node, true, 
+                kukit.dom.getKssValue, 
+                keyType, key);
+        // Just return the markup's node as a single selection result.
+        return [markup.node];
+    };
+
+};
+kukit.pprovidersGlobalRegistry.register('kssMarkedNode', _KssMarkedNodePP, 'selection');
+
 }();                              /// MODULE END
+

Modified: kukit/kukit.js/branch/ree-1.4-markup-and-syntax-changes/kukit/serveraction.js
==============================================================================
--- kukit/kukit.js/branch/ree-1.4-markup-and-syntax-changes/kukit/serveraction.js	(original)
+++ kukit/kukit.js/branch/ree-1.4-markup-and-syntax-changes/kukit/serveraction.js	Wed Jan 23 17:35:34 2008
@@ -29,6 +29,26 @@
     if (typeof(this.url) == 'undefined') {
         this.url = name;
     }
+
+    this.calculateAbsoluteURL = function(url) {
+        //
+        // If the url is an absolute path, it is used
+        //
+        // If the url is not an absolute path, it is put at the end of the context
+        // url.
+        //
+        // example: url='@theview/getName',
+        //          context='http://your.site.com/portal/folder/object'
+        //
+        //     result='http://your.site.com/portal/folder/object/@@theview/getName'
+        //
+        if (url.match(RegExp('/^https?:\/\//'))) {
+            return url;
+        } else {
+            var result = kukit.engine.baseUrl + '/' + url;
+            return result;
+        }
+    };
     this.url = this.calculateAbsoluteURL(this.url);
     this.notifyServer();
 };
@@ -134,7 +154,7 @@
                 }
             }
         }
-    }
+    };
 };
 
 this.processResult = function(domDoc) {
@@ -164,9 +184,86 @@
             }
             commandstags = kukit.dom.getNsTags(dom, 'commands');
             if (commandstags.length != 1) {
-                // no good
+                // no good, maybe better luck with it as html payload
                 dom = null;
             }
+        }
+        // Check for html too, this enables setting the kss error command on the 
+        // error response.
+        if (dom == null) {
+            // Read the header and load it as xml, if defined.
+            var payload = domDoc.getResponseHeader('X-KSSCOMMANDS');
+            if (payload) {
+                try {
+                    dom = (new DOMParser()).parseFromString(payload, "text/xml");
+                } catch(e) {
+;;;                 kukit.E = 'Error parsing X-KSSCOMMANDS header.';
+                    throw kukit.err.responseParsingError(kukit.E);
+                }
+                commandstags = kukit.dom.getNsTags(dom, 'commands');
+                if (commandstags.length != 1) {
+                    // no good
+                    dom = null;
+                }
+            } else {
+                // Ok. we have not found it either in the headers.
+                // Check if there was a parsing error in the xml, 
+                // and log it as reported from the dom
+                // Opera <= 8.5 does not have the parseError attribute,
+                // so check for it first
+;;;             dom = domDoc.responseXML;
+;;;             kukit.E = 'Unknown server error (invalid KSS response, no error';
+;;;             kukit.E += ' info received)';
+;;;             if (dom && dom.parseError && (dom.parseError != 0)) {
+;;;                 kukit.E += ' : ' + Sarissa.getParseErrorText(dom);
+;;;                 }
+                throw kukit.err.responseParsingError(kukit.E);
+            }
+        }
+        if (dom == null) {
+            // this should not happen
+;;;         kukit.E = 'Neither xml nor html payload.';
+            throw kukit.err.responseParsingError(msg);
+        }
+        // find the commands (atm we don't limit ourselves inside the commandstag)
+        var commands = kukit.dom.getNsTags(dom, 'command');
+        // Warning, if there is a valid response containing 0 commands.
+        if (commands.length == 0) {
+;;;         kukit.log('No commands in kukit response');
+            return;
+        }
+        // One or more valid commands to parse
+        var command_processor = new kukit.cp.CommandProcessor();
+        command_processor.parseCommands(commands, domDoc);
+        kukit.engine.beginSetupEventsCollection();
+        command_processor.executeCommands(this.oper);
+        kukit.engine.finishSetupEventsCollection();
+    };
+
+    this.processError = function(errorcommand) {
+        var error_action = null;
+        if (this.oper.eventRule) {
+            var error_action = this.oper.eventRule.actions.getErrorActionFor(
+                this.oper.action);
+            }
+;;;     var reason = '';
+;;;     if (typeof(errorcommand) == 'string') {
+;;;         // not a command, just a string
+;;;         reason = ', client_reason="' + errorcommand + '" ';
+;;;     } else if (typeof(errorcommand) != 'undefined') {
+;;;         // a real error command, sent by the server
+;;;         // as kukit payload.
+;;;         // this way the server sends whatever message he wants as a parameter
+;;;         // to the error command.
+;;;         reason = ', server_reason="' + errorcommand.parms.message + '" ';
+;;;     }
+        if (error_action) {
+;;;         kukit.E = 'Request failed at url ' + this.oper.queueItem.url;
+;;;         kukit.E += ', rid=' + this.oper.queueItem.rid + reason;
+;;;         kukit.E += ', will be handled by action "' + error_action.name + '"';
+;;;         kukit.logWarning(kukit.E);
+            // Individual error handler was defined. Execute it!
+            error_action.execute(this.oper);
         } else {
             // Ok. we have not found it either in the headers.
             // Check if there was a parsing error in the xml, 

Modified: kukit/kukit.js/branch/ree-1.4-markup-and-syntax-changes/kukit/tokenizer.js
==============================================================================
--- kukit/kukit.js/branch/ree-1.4-markup-and-syntax-changes/kukit/tokenizer.js	(original)
+++ kukit/kukit.js/branch/ree-1.4-markup-and-syntax-changes/kukit/tokenizer.js	Wed Jan 23 17:35:34 2008
@@ -55,6 +55,12 @@
 */
 tk._ParserBase = function() {
 
+// Provide an empty initialize. This allows
+// that the tokens will inherit it and are
+// not forced to implement it themselves.
+this.initialize = function() {
+};
+
 this.emitAndReturn = function(token) {
     // handle return to the next level
     this.finished = true;
@@ -249,13 +255,29 @@
             this.updateFinished();
         }
         this.endpos = cursor.pos;
+        // Call initialize with the original arguments
+        // (no need to call it earlier, as
+        this.initialize.apply(this, arguments);
         // post processing
         this.process();
         
         //this.cursor = null;
     };
-    _class.prototype = new tk._ParserBase();
-    f.prototype = new _class(); 
+    // Extend class's prototype, instead of overwriting
+    // it, since it may have its own methods!
+    // This means: the parser class we create
+    // double inherits from the specified parser class
+    // and the paeser base.
+    f.prototype = new tk._ParserBase();
+    var _prototype = new _class();
+    for (key in _prototype) {
+        // Set the method (or attribute) on the new prototype.
+        // This allows that a parser class may eventually 
+        // override some methods of _ParserBase: for example,
+        // process is usually overwritten.
+        f.prototype[key] = _prototype[key];
+    }
+    // Set the symbol on the new class, too
     f.prototype.symbol = symbol;
     return f;
 };

Modified: kukit/kukit.js/branch/ree-1.4-markup-and-syntax-changes/tests/runtests.js
==============================================================================
--- kukit/kukit.js/branch/ree-1.4-markup-and-syntax-changes/tests/runtests.js	(original)
+++ kukit/kukit.js/branch/ree-1.4-markup-and-syntax-changes/tests/runtests.js	Wed Jan 23 17:35:34 2008
@@ -23,6 +23,7 @@
     testsuite.registerTest(kukit.TokenizerTestCase);
     testsuite.registerTest(kukit.KssParserTestCase);
     testsuite.registerTest(kukit.KssParserSelectorsTestCase);
+    testsuite.registerTest(kukit.KssParserValueProvidersCheckTestCase);
     testsuite.registerTest(kukit.KssParserSelectorTestCase);
     testsuite.runSuite();
 };

Modified: kukit/kukit.js/branch/ree-1.4-markup-and-syntax-changes/tests/test_kssparser.js
==============================================================================
--- kukit/kukit.js/branch/ree-1.4-markup-and-syntax-changes/tests/test_kssparser.js	(original)
+++ kukit/kukit.js/branch/ree-1.4-markup-and-syntax-changes/tests/test_kssparser.js	Wed Jan 23 17:35:34 2008
@@ -69,89 +69,6 @@
 kukit.KssParserTestCase = function() {
     this.name = 'kukit.KssParserTestCase';
  
-    this.testPropvalueInMethod = function() {
-        // Parsing prop values (no methods allowed)
-        var txt= "apple;";
-        var cursor = new kukit.tk.Cursor(txt);
-        var parser = new kukit.kssp.PropValueInMethod(cursor, null, true);
-        this.assertEquals(parser.finished, true);
-        this.assertEquals(parser.txt, 'apple');
-
-        txt= "'a  string';";
-        cursor = new kukit.tk.Cursor(txt);
-        parser = new kukit.kssp.PropValueInMethod(cursor, null, true);
-        this.assertEquals(parser.finished, true);
-        this.assertEquals(parser.txt, 'a  string');
-
-        txt= '"a  string";';
-        cursor = new kukit.tk.Cursor(txt);
-        parser = new kukit.kssp.PropValueInMethod(cursor, null, true);
-        this.assertEquals(parser.finished, true);
-        this.assertEquals(parser.txt, 'a  string');
-
-        txt= '"a  \\"string";';
-        cursor = new kukit.tk.Cursor(txt);
-        parser = new kukit.kssp.PropValueInMethod(cursor, null, true);
-        this.assertEquals(parser.finished, true);
-        this.assertEquals(parser.txt, 'a  "string');
-
-        txt= " /* valid */ 'a  string' /* here*/ /*and*/ /*there*/;";
-        cursor = new kukit.tk.Cursor(txt);
-        parser = new kukit.kssp.PropValueInMethod(cursor, null, true);
-        this.assertEquals(parser.finished, true);
-        this.assertEquals(parser.txt, 'a  string');
-
-        txt= " in /* valid */ 'a  string';";
-        cursor = new kukit.tk.Cursor(txt);
-        this.assertParsingError(kukit.kssp.PropValueInMethod, cursor, null, true, 'Wrong value : unallowed characters [in] before a string.');
-
-        txt= " 'a  string' trashy;";
-        cursor = new kukit.tk.Cursor(txt);
-        this.assertParsingError(kukit.kssp.PropValueInMethod, cursor, null, true, 'Wrong value : unallowed characters after the property.');
-
-        txt= " 'a  string' trashy \"trishy\";";
-        cursor = new kukit.tk.Cursor(txt);
-        this.assertParsingError(kukit.kssp.PropValueInMethod, cursor, null, true, 'Wrong value : unallowed characters after the property.');
-
-        // multiword not ok
-        txt= "b   c";
-        cursor = new kukit.tk.Cursor(txt);
-        this.assertParsingError(kukit.kssp.PropValueInMethod, cursor, null, true,
-            'Wrong value : [b c] cannot have spaces.', 5);
-
-        txt= "  apples and   oranges   ;";
-        cursor = new kukit.tk.Cursor(txt);
-        this.assertParsingError(kukit.kssp.PropValueInMethod, cursor, null, true,
-            'Wrong value : [apples and oranges] cannot have spaces.', 25);
-
-        txt= " /* comments; */ apples and  /* more comments and*/ oranges   ;";
-        cursor = new kukit.tk.Cursor(txt);
-        this.assertParsingError(kukit.kssp.PropValueInMethod, cursor, null, true,
-            //'Wrong value : [/* comments; */ apples and /* more comments and*/ oranges ;] cannot have spaces.', 62);
-            'Wrong value : [apples and oranges] cannot have spaces.', 62);
-
-        // in string, multiword ok even in method
-        txt= "'b   c' ";
-        cursor = new kukit.tk.Cursor(txt);
-        parser = new kukit.kssp.PropValueInMethod(cursor, null, true);
-        this.assertEquals(parser.finished, true);
-        this.assertEquals(parser.txt, 'b   c');
-        this.assertEquals(parser.parms, null);
-
-        // Not ok
-        txt= "a'b c'";
-        cursor = new kukit.tk.Cursor(txt);
-        this.assertParsingError(kukit.kssp.PropValueInMethod, cursor, null, true,
-            'Wrong value : unallowed characters [a] before a string', 6);
-
-        // Not ok
-        txt= "'a''b c'";
-        cursor = new kukit.tk.Cursor(txt);
-        this.assertParsingError(kukit.kssp.PropValueInMethod, cursor, null, true,
-            'Wrong value : unallowed characters after the property.', 6);
-
-    };
-
     this.testPropValue = function() {
         // Parsing property values 
 
@@ -162,28 +79,27 @@
         this.assertEquals(parser.value.isMethod, false);
         this.assertEquals(parser.value.txt, 'b');
 
-        // multiword ok
+        // XXX multiword in PropValue was supported by the token
+        // previously, but it really was never used.
+
+        // multiword is not allowed.
         txt= "b   c";
         cursor = new kukit.tk.Cursor(txt);
-        parser = new kukit.kssp.PropValue(cursor, null, true);
-        this.assertEquals(parser.finished, true);
-        this.assertEquals(parser.value.isMethod, false);
-        this.assertEquals(parser.value.txt, 'b c');
+        this.assertParsingError(kukit.kssp.PropValue, cursor, null, true,
+            'Wrong value : unallowed characters [c] after the argument.')
 
+        // multiword is not allowed.
         txt= "  apples and   oranges   ;";
         cursor = new kukit.tk.Cursor(txt);
-        parser = new kukit.kssp.PropValue(cursor, null, true);
-        this.assertEquals(parser.finished, true);
-        this.assertEquals(parser.value.isMethod, false);
-        this.assertEquals(parser.value.txt, 'apples and oranges');
+        this.assertParsingError(kukit.kssp.PropValue, cursor, null, true,
+            'Wrong value : unallowed characters [and] after the argument.')
 
+        // multiword is not allowed.
         txt= " /* comments; */ apples and  /* more comments and*/ oranges   ;";
         cursor = new kukit.tk.Cursor(txt);
-        parser = new kukit.kssp.PropValue(cursor, null, true);
-        this.assertEquals(parser.finished, true);
-        this.assertEquals(parser.value.isMethod, false);
-        this.assertEquals(parser.value.txt, 'apples and oranges');
-
+        this.assertParsingError(kukit.kssp.PropValue, cursor, null, true,
+            'Wrong value : unallowed characters [and] after the argument.')
+ 
         // params ok
         txt= "formVar(x, y) ";
         cursor = new kukit.tk.Cursor(txt);
@@ -214,19 +130,205 @@
         txt= " a formVar(x, y)";
         cursor = new kukit.tk.Cursor(txt);
         this.assertParsingError(kukit.kssp.PropValue, cursor, null, true,
-            'Wrong value : method name [a formVar] cannot have spaces.', 16);
+            'Wrong value : unallowed characters [formVar] after the argument.')
 
         txt= " 'formVar'(x, y)";
         cursor = new kukit.tk.Cursor(txt);
         this.assertParsingError(kukit.kssp.PropValue, cursor, null, true,
-            'Wrong value : unallowed characters after the property', 16);
+            'Wrong value : unallowed characters [(] after the argument.')
 
         txt= "formVar(x, y) xxx";
         cursor = new kukit.tk.Cursor(txt);
         this.assertParsingError(kukit.kssp.PropValue, cursor, null, true,
-            'Wrong value : unallowed characters after the property', 17);
+            'Wrong value : unallowed characters [xxx] after the argument.')
     };
-    
+
+    this.testPropValueNoParam = function() {
+        // no parameters ok in a provider.
+        var txt= "formVar()";
+        var cursor = new kukit.tk.Cursor(txt);
+        var parser = new kukit.kssp.PropValue(cursor, null, true);
+        this.assertEquals(parser.finished, true);
+        this.assertEquals(parser.value.isMethod, true);
+        this.assertEquals(parser.value.methodName, 'formVar');
+        this.assertListEquals(parser.value.args, []);
+    };
+
+    this.testPropValueNoMethodName = function() {
+        var txt= " (x, y)";
+        var cursor = new kukit.tk.Cursor(txt);
+        this.assertParsingError(kukit.kssp.PropValue, cursor, null, true,
+            'Wrong value : empty method name.');
+    };
+ 
+    this.testMultiPropValueSingleWord = function() {
+        // Multi prop value with single word
+        var txt= "b";
+        var cursor = new kukit.tk.Cursor(txt);
+        var parser = new kukit.kssp.MultiPropValue(cursor, null, true);
+        this.assertEquals(parser.finished, true);
+        this.assertEquals(parser.values.length, 1);
+        this.assertEquals(parser.values[0].isMethod, false);
+        this.assertEquals(parser.values[0].txt, 'b');
+    };
+
+    this.testMultiPropValueMultiWord = function() {
+        // Multi prop value with multi word.
+        var txt= "b   c";
+        var cursor = new kukit.tk.Cursor(txt);
+        var parser = new kukit.kssp.MultiPropValue(cursor, null, true);
+        this.assertEquals(parser.finished, true);
+        this.assertEquals(parser.values.length, 2);
+        this.assertEquals(parser.values[0].isMethod, false);
+        this.assertEquals(parser.values[0].txt, 'b');
+        this.assertEquals(parser.values[1].isMethod, false);
+        this.assertEquals(parser.values[1].txt, 'c');
+    };
+
+    this.testMultiPropValueMultiWord2 = function() {
+        // Multi prop value with multi word.
+        var txt= "  apples and   oranges   ;";
+        var cursor = new kukit.tk.Cursor(txt);
+        var parser = new kukit.kssp.MultiPropValue(cursor, null, true);
+        this.assertEquals(parser.finished, true);
+        this.assertEquals(parser.values.length, 3);
+        this.assertEquals(parser.values[0].isMethod, false);
+        this.assertEquals(parser.values[0].txt, 'apples');
+        this.assertEquals(parser.values[1].isMethod, false);
+        this.assertEquals(parser.values[1].txt, 'and');
+        this.assertEquals(parser.values[2].isMethod, false);
+        this.assertEquals(parser.values[2].txt, 'oranges');
+    };
+
+    this.testMultiPropValueMultiWord2 = function() {
+        // Multi prop value with multi word and comments.
+        var txt= " /* comments; */ apples and  /* more comments and*/ oranges   ;";
+        var cursor = new kukit.tk.Cursor(txt);
+        var parser = new kukit.kssp.MultiPropValue(cursor, null, true);
+        this.assertEquals(parser.finished, true);
+        this.assertEquals(parser.values.length, 3);
+        this.assertEquals(parser.values[0].isMethod, false);
+        this.assertEquals(parser.values[0].txt, 'apples');
+        this.assertEquals(parser.values[1].isMethod, false);
+        this.assertEquals(parser.values[1].txt, 'and');
+        this.assertEquals(parser.values[2].isMethod, false);
+        this.assertEquals(parser.values[2].txt, 'oranges');
+    };
+
+
+    this.testMultiPropValueStringAndWord = function() {
+        // Multi prop value with string and word.
+        var txt= "'apples' and oranges;";
+        var cursor = new kukit.tk.Cursor(txt);
+        var parser = new kukit.kssp.MultiPropValue(cursor, null, true);
+        this.assertEquals(parser.finished, true);
+        this.assertEquals(parser.values.length, 3);
+        this.assertEquals(parser.values[0].isMethod, false);
+        this.assertEquals(parser.values[0].txt, 'apples');
+        this.assertEquals(parser.values[1].isMethod, false);
+        this.assertEquals(parser.values[1].txt, 'and');
+        this.assertEquals(parser.values[2].isMethod, false);
+        this.assertEquals(parser.values[2].txt, 'oranges');
+    };
+
+    this.testMultiPropValueWordAndString = function() {
+        // Multi prop value with string and word.
+        var txt= "'apples' and oranges;";
+        var cursor = new kukit.tk.Cursor(txt);
+        var parser = new kukit.kssp.MultiPropValue(cursor, null, true);
+        this.assertEquals(parser.finished, true);
+        this.assertEquals(parser.values.length, 3);
+        this.assertEquals(parser.values[0].isMethod, false);
+        this.assertEquals(parser.values[0].txt, 'apples');
+        this.assertEquals(parser.values[1].isMethod, false);
+        this.assertEquals(parser.values[1].txt, 'and');
+        this.assertEquals(parser.values[2].isMethod, false);
+        this.assertEquals(parser.values[2].txt, 'oranges');
+    };
+
+    this.testMultiPropValueWordAndProvider = function() {
+        // Multi prop value with word and provider and word.
+        var txt= "apples formVar(x, y) oranges;";
+        var cursor = new kukit.tk.Cursor(txt);
+        var parser = new kukit.kssp.MultiPropValue(cursor, null, true);
+        this.assertEquals(parser.finished, true);
+        this.assertEquals(parser.values.length, 3);
+        this.assertEquals(parser.values[0].isMethod, false);
+        this.assertEquals(parser.values[0].txt, 'apples');
+        this.assertEquals(parser.values[1].isMethod, true);
+        this.assertEquals(parser.values[1].methodName, 'formVar');
+        this.assertListEquals(parser.values[1].args, ['x', 'y']);
+        this.assertEquals(parser.values[2].isMethod, false);
+        this.assertEquals(parser.values[2].txt, 'oranges');
+    };
+
+    this.testMultiPropValueProviderAndWord = function() {
+        // Multi prop value with provider and word.
+        var txt= "formVar(x, y) and oranges;";
+        var cursor = new kukit.tk.Cursor(txt);
+        var parser = new kukit.kssp.MultiPropValue(cursor, null, true);
+        this.assertEquals(parser.finished, true);
+        this.assertEquals(parser.values.length, 3);
+        this.assertEquals(parser.values[0].isMethod, true);
+        this.assertEquals(parser.values[0].methodName, 'formVar');
+        this.assertListEquals(parser.values[0].args, ['x', 'y']);
+        this.assertEquals(parser.values[1].isMethod, false);
+        this.assertEquals(parser.values[1].txt, 'and');
+        this.assertEquals(parser.values[2].isMethod, false);
+        this.assertEquals(parser.values[2].txt, 'oranges');
+    };
+
+    this.testMultiPropValueMethodArgsWithSpace = function() {
+        // Multi prop value with space after the provider name.
+        var txt= "formVar   (x, y) and oranges;";
+        var cursor = new kukit.tk.Cursor(txt);
+        var parser = new kukit.kssp.MultiPropValue(cursor, null, true);
+        this.assertEquals(parser.finished, true);
+        this.assertEquals(parser.values.length, 3);
+        this.assertEquals(parser.values[0].isMethod, true);
+        this.assertEquals(parser.values[0].methodName, 'formVar');
+        this.assertListEquals(parser.values[0].args, ['x', 'y']);
+        this.assertEquals(parser.values[1].isMethod, false);
+        this.assertEquals(parser.values[1].txt, 'and');
+        this.assertEquals(parser.values[2].isMethod, false);
+        this.assertEquals(parser.values[2].txt, 'oranges');
+    };
+
+    this.testMultiPropValueManyProviders = function() {
+        // Multi prop value with many providers
+        var txt= "formVar(x, y) kssAttr(foo, true) formVar(a, b);";
+        var cursor = new kukit.tk.Cursor(txt);
+        var parser = new kukit.kssp.MultiPropValue(cursor, null, true);
+        this.assertEquals(parser.finished, true);
+        this.assertEquals(parser.values.length, 3);
+        this.assertEquals(parser.values[0].isMethod, true);
+        this.assertEquals(parser.values[0].methodName, 'formVar');
+        this.assertListEquals(parser.values[0].args, ['x', 'y']);
+        this.assertEquals(parser.values[1].isMethod, true);
+        this.assertEquals(parser.values[1].methodName, 'kssAttr');
+        this.assertListEquals(parser.values[1].args, ['foo', 'true']);
+        this.assertEquals(parser.values[2].isMethod, true);
+        this.assertEquals(parser.values[2].methodName, 'formVar');
+        this.assertListEquals(parser.values[2].args, ['a', 'b']);
+    };
+
+    this.testMultiPropValueStringAndManyProviders = function() {
+        // Multi prop value with a string and many providers
+        var txt= "blah kssAttr(foo, true) formVar(a, b);";
+        var cursor = new kukit.tk.Cursor(txt);
+        var parser = new kukit.kssp.MultiPropValue(cursor, null, true);
+        this.assertEquals(parser.finished, true);
+        this.assertEquals(parser.values.length, 3);
+        this.assertEquals(parser.values[0].isMethod, false);
+        this.assertEquals(parser.values[0].txt, 'blah');
+        this.assertEquals(parser.values[1].isMethod, true);
+        this.assertEquals(parser.values[1].methodName, 'kssAttr');
+        this.assertListEquals(parser.values[1].args, ['foo', 'true']);
+        this.assertEquals(parser.values[2].isMethod, true);
+        this.assertEquals(parser.values[2].methodName, 'formVar');
+        this.assertListEquals(parser.values[2].args, ['a', 'b']);
+    };
+
     this.testEventValueSimple = function() {
         // Parsing event value
         var txt= "b";
@@ -353,6 +455,15 @@
 
     };
 
+    this.testMethodArgsNoParam = function() {
+        // Parsing method args with no parameters
+        txt= "()";
+        cursor = new kukit.tk.Cursor(txt);
+        parser = new kukit.kssp.MethodArgs(cursor, kukit.kssp.openParent, true);
+        this.assertEquals(parser.finished, true);
+        this.assertListEquals(parser.args, []);
+    };
+
     this.testMethodArgsRecursive = function() {
         var txt= "(a, b(c, d))";
         var cursor = new kukit.tk.Cursor(txt);
@@ -813,6 +924,549 @@
 
 kukit.KssParserTestCase.prototype = new kukit.KssParserTestCaseBase;
 
+kukit.KssParserValueProvidersCheckTestCase = function() {
+    this.name = 'kukit.KssParserValueProvidersCheckTestCase';
+    // Different tests to see if the syntax type check of
+    // the value providers is working correctly.
+    // At the moment we have the following return value types:
+    //
+    //   string:     almost all normal providers return string
+    //   selection:  a selector provider returns a list of nodes
+    //   formquery:   a form provider returns an ordered list
+    //               of key-value pairs to be marshalled
+    //   url:        the return type of the url() provider
+    //
+    // We do not check the actual evaluation here, as we
+    // have no DOM at hand.
+    //
+    // We also check how these providers can be combined
+    // on one line.
+    //
+    // This testcase can run in DEVELOPMENT MODE ONLY,
+    // (because the checks are ignored in production mode)
+    // and all tests will be skipped
+    // and pass GREEN in production mode.
+    
+    this.testNormalProviderAcceptsString = function() {
+        // normal providers does accept string
+        //
+        // This test can only run in development mode, pass otherwise.
+        if (! kukit.isDevelMode) {return;}
+        //
+        var txt= "nodeAttr('id')";
+        var cursor = new kukit.tk.Cursor(txt);
+        var parser = new kukit.kssp.PropValue(cursor, null, true);
+        var value = parser.value;
+        value.check();
+    };
+
+    this.testNormalProviderRejectsSelectionAsParameter = function() {
+        // normal providers does not accept selection
+        //
+        // This test can only run in development mode, pass otherwise.
+        if (! kukit.isDevelMode) {return;}
+        //
+        var txt= "nodeAttr(htmlid('id'))";
+        var cursor = new kukit.tk.Cursor(txt);
+        var parser = new kukit.kssp.PropValue(cursor, null, true);
+        var value = parser.value;
+        this.assertThrows(function() {
+            value.check();
+            },
+            Error);
+    };
+ 
+    this.testNormalProviderRejectsSelectionFullRule = function() {
+        // normal providers do not accept selection
+        // full rule
+        //
+        // This test can only run in development mode, pass otherwise.
+        if (! kukit.isDevelMode) {return;}
+        //
+        var txt= "#id:click {\n"
+               + "    action-client: log;\n"
+               + "    log-message:   nodeAttr(htmlid('id'));\n"
+               + "}\n"
+        var cursor = new kukit.tk.Cursor(txt);
+        this.assertParsingError(kukit.kssp.Document, cursor, null, true,
+            // XXX This error message will be fixed in service-layer branch
+            // XXX This will also fix running from IE, currently broken at error assert.
+            'Error in value for action parameter [message] : Error: Expected string value and got [selection] in argument #[1] of provider [nodeAttr].., at row 1, column 11');
+    };
+
+    this.testNormalProviderRejectsFormData = function() {
+        // normal providers do not accept form query
+        //
+        // This test can only run in development mode, pass otherwise.
+        if (! kukit.isDevelMode) {return;}
+        //
+        var txt= "nodeAttr(form('name'))";
+        var cursor = new kukit.tk.Cursor(txt);
+        var parser = new kukit.kssp.PropValue(cursor, null, true);
+        var value = parser.value;
+        this.assertThrows(function() {
+            value.check();
+            },
+            Error);
+    };
+ 
+    this.testNormalProviderRejectsFormDataFullRule = function() {
+        // normal providers do not accept form query
+        // full rule
+        //
+        // This test can only run in development mode, pass otherwise.
+        if (! kukit.isDevelMode) {return;}
+        //
+        var txt= "#id:click {\n"
+               + "    action-client: log;\n"
+               + "    log-message:   nodeAttr(form('name'));\n"
+               + "}\n"
+        var cursor = new kukit.tk.Cursor(txt);
+        this.assertParsingError(kukit.kssp.Document, cursor, null, true,
+            // XXX This error message will be fixed in service-layer branch
+            // XXX This will also fix running from IE, currently broken at error assert.
+            'Error in value for action parameter [message] : Error: Expected string value and got [formquery] in argument #[1] of provider [nodeAttr].., at row 1, column 11');
+    };
+
+    this.testNormalParameterRejectsSelectorInItself = function() {
+        // normal parameters do not accept selector (in itself)
+        //
+        // This test can only run in development mode, pass otherwise.
+        if (! kukit.isDevelMode) {return;}
+        //
+        var txt= "#id:click {\n"
+               + "    action-client: log;\n"
+               + "    log-message:   htmlid('id');\n"
+               + "}\n"
+        var cursor = new kukit.tk.Cursor(txt);
+        this.assertParsingError(kukit.kssp.Document, cursor, null, true,
+            // XXX This error message will be fixed in service-layer branch
+            // XXX This will also fix running from IE, currently broken at error assert.
+            'Missing [string] value in the action parameter [message]., at row 1, column 11');
+    };
+
+    this.testNormalParameterRejectsFormData = function() {
+        // normal parameters do not accept form query
+        //
+        // This test can only run in development mode, pass otherwise.
+        if (! kukit.isDevelMode) {return;}
+        //
+        var txt= "#id:click {\n"
+               + "    action-client: log;\n"
+               + "    log-message:   form('name');\n"
+               + "}\n"
+        var cursor = new kukit.tk.Cursor(txt);
+        this.assertParsingError(kukit.kssp.Document, cursor, null, true,
+            // XXX This error message will be fixed in service-layer branch
+            // XXX This will also fix running from IE, currently broken at error assert.
+            'Provider result type [formquery] not allowed in the action parameter [message]., at row 1, column 1');
+    };
+
+    this.testKssSelectorAcceptsSelector = function() {
+        // kssSelector accepts selector
+        //
+        // This test can only run in development mode, pass otherwise.
+        if (! kukit.isDevelMode) {return;}
+        //
+        var txt= "#id:click {\n"
+               + "    action-client:              setAttribute;\n"
+               + "    setAttribute-kssSelector:   htmlid('id');\n"
+               + "    setAttribute-name:          name;\n"
+               + "    setAttribute-value:          value;\n"
+               + "}\n"
+        var cursor = new kukit.tk.Cursor(txt);
+        var parser = new kukit.kssp.Document(cursor, null, true);
+        this.assertEquals(parser.finished, true);
+    };
+
+    this.testKssSelectorAcceptsString = function() {
+        // kssSelector accepts string
+        // (it will evaluate as css(xxx), but we can't check that without a dom)
+        //
+        // This test can only run in development mode, pass otherwise.
+        if (! kukit.isDevelMode) {return;}
+        //
+        var txt= "#id:click {\n"
+               + "    action-client:              setAttribute;\n"
+               + "    setAttribute-kssSelector:   htmlid('id');\n"
+               + "    setAttribute-name:          name;\n"
+               + "    setAttribute-value:          value;\n"
+               + "}\n"
+        var cursor = new kukit.tk.Cursor(txt);
+        var parser = new kukit.kssp.Document(cursor, null, true);
+        this.assertEquals(parser.finished, true);
+    };
+
+    this.testKssSelectorRejectsFormData = function() {
+        // kssSelector rejects form query
+        //
+        // This test can only run in development mode, pass otherwise.
+        if (! kukit.isDevelMode) {return;}
+        //
+        var txt= "#id:click {\n"
+               + "    action-client:              setAttribute;\n"
+               + "    setAttribute-kssSelector:   form('name');\n"
+               + "    setAttribute-name:          name;\n"
+               + "    setAttribute-value:          value;\n"
+               + "}\n"
+        var cursor = new kukit.tk.Cursor(txt);
+        this.assertParsingError(kukit.kssp.Document, cursor, null, true,
+            // XXX This error message will be fixed in service-layer branch
+            // XXX This will also fix running from IE, currently broken at error assert.
+            'Provider result type [formquery] not allowed in the kss action parameter [kssSelector]., at row 1, column 11');
+    };
+
+    this.testKssSubmitFormAcceptsFormData = function() {
+        // kssSubmitForm accepts form query
+        //
+        // This test can only run in development mode, pass otherwise.
+        if (! kukit.isDevelMode) {return;}
+        //
+        var txt= "#id:click {\n"
+               + "    action-server:              doIt;\n"
+               + "    doIt-kssSubmitForm:         form('name');\n"
+               + "}\n"
+        var cursor = new kukit.tk.Cursor(txt);
+        var parser = new kukit.kssp.Document(cursor, null, true);
+        this.assertEquals(parser.finished, true);
+    };
+
+    this.testKssSubmitFormAcceptsString = function() {
+        // kssSubmitForm accepts string
+        // (it will evaluate as form(xxx), but we can't check that without a dom)
+        //
+        // This test can only run in development mode, pass otherwise.
+        if (! kukit.isDevelMode) {return;}
+        //
+        var txt= "#id:click {\n"
+               + "    action-server:              doIt;\n"
+               + "    doIt-kssSubmitForm:         'name';\n"
+               + "}\n"
+        var cursor = new kukit.tk.Cursor(txt);
+        var parser = new kukit.kssp.Document(cursor, null, true);
+        this.assertEquals(parser.finished, true);
+    };
+
+    this.testKssSubmitFormRejectsSelection = function() {
+        // kssSubmitForm rejects selection
+        //
+        // This test can only run in development mode, pass otherwise.
+        if (! kukit.isDevelMode) {return;}
+        //
+        var txt= "#id:click {\n"
+               + "    action-server:              doIt;\n"
+               + "    doIt-kssSubmitForm:         htmlid('id');\n"
+               + "}\n"
+        var cursor = new kukit.tk.Cursor(txt);
+        this.assertParsingError(kukit.kssp.Document, cursor, null, true,
+            // XXX This error message will be fixed in service-layer branch
+            // XXX This will also fix running from IE, currently broken at error assert.
+            'Provider result type [selection] not allowed in the kss action parameter [kssSubmitForm]., at row 1, column 11');
+    };
+
+    this.testCombinedClientAction = function() {
+        // Client action accepts a list of combined providers.
+        //
+        // This test can only run in development mode, pass otherwise.
+        if (! kukit.isDevelMode) {return;}
+        //
+        var txt= "#id:click {\n"
+               + "    action-client:   htmlid(id) doIt;\n"
+               + "}\n"
+        var cursor = new kukit.tk.Cursor(txt);
+        var parser = new kukit.kssp.Document(cursor, null, true);
+        this.assertEquals(parser.finished, true);
+    };
+
+    this.testCombinedClientActionRejectsFormData = function() {
+        // Client action rejects form query.
+        //
+        // This test can only run in development mode, pass otherwise.
+        if (! kukit.isDevelMode) {return;}
+        //
+        var txt= "#id:click {\n"
+               + "    action-client:   htmlid(id) doIt form();\n"
+               + "}\n"
+        var cursor = new kukit.tk.Cursor(txt);
+        this.assertParsingError(kukit.kssp.Document, cursor, null, true,
+            // XXX This error message will be fixed in service-layer branch
+            // XXX This will also fix running from IE, currently broken at error assert.
+            'Error in value for action definition [action-client] : Error: form method needs 1 arguments (formname)., at row 1, column 11');
+    };
+
+    this.testCombinedServerAction = function() {
+        // Server action accepts a list of combined providers.
+        //
+        // This test can only run in development mode, pass otherwise.
+        if (! kukit.isDevelMode) {return;}
+        //
+        var txt= "#id:click {\n"
+               + "    action-server:   doIt currentForm();\n"
+               + "}\n"
+        var cursor = new kukit.tk.Cursor(txt);
+        var parser = new kukit.kssp.Document(cursor, null, true);
+        this.assertEquals(parser.finished, true);
+    };
+
+    this.testCombinedServerActionRejectsSelector = function() {
+        // Server action rejects a selection provider.
+        //
+        // This test can only run in development mode, pass otherwise.
+        if (! kukit.isDevelMode) {return;}
+        //
+        var txt= "#id:click {\n"
+               + "    action-server:   doIt currentForm() htmlid(id);\n"
+               + "}\n"
+        var cursor = new kukit.tk.Cursor(txt);
+        this.assertParsingError(kukit.kssp.Document, cursor, null, true,
+            // XXX This error message will be fixed in service-layer branch
+            // XXX This will also fix running from IE, currently broken at error assert.
+            'Provider result type [selection] not allowed in the action definition [action-server]., at row 1, column 11');
+    };
+
+    this.testCombinedServerActionAcceptsStringAndUrl = function() {
+        // Server action accepts a string and an url.
+        //
+        // This test can only run in development mode, pass otherwise.
+        if (! kukit.isDevelMode) {return;}
+        //
+        var txt= "#id:click {\n"
+               + "    action-server:   doIt url('http://foo.bar');\n"
+               + "}\n"
+        var cursor = new kukit.tk.Cursor(txt);
+        var parser = new kukit.kssp.Document(cursor, null, true);
+        this.assertEquals(parser.finished, true);
+    };
+
+    this.testCombinedServerActionAcceptsUrlAndString = function() {
+        // Server action accepts a string and an url.
+        //
+        // This test can only run in development mode, pass otherwise.
+        if (! kukit.isDevelMode) {return;}
+        //
+        var txt= "#id:click {\n"
+               + "    action-server:   doIt url('http://foo.bar');\n"
+               + "}\n"
+        var cursor = new kukit.tk.Cursor(txt);
+        var parser = new kukit.kssp.Document(cursor, null, true);
+        this.assertEquals(parser.finished, true);
+    };
+
+    this.testCombinedServerActionAcceptsStringAndFormAndUrl = function() {
+        // Server action accepts string, form, and url providers together.
+        //
+        // This test can only run in development mode, pass otherwise.
+        if (! kukit.isDevelMode) {return;}
+        //
+        var txt= "#id:click {\n"
+               + "    action-server:   doIt currentForm() url('http://foo.bar');\n"
+               + "}\n"
+        var cursor = new kukit.tk.Cursor(txt);
+        var parser = new kukit.kssp.Document(cursor, null, true);
+        this.assertEquals(parser.finished, true);
+    };
+
+    this.testCombinedServerActionRejectsUrlInItself = function() {
+        // Server action rejects url() in itself.
+        // It should have a string in any case.
+        //
+        // This test can only run in development mode, pass otherwise.
+        if (! kukit.isDevelMode) {return;}
+        //
+        var txt= "#id:click {\n"
+               + "    action-server:   url('http://foo.bar');\n"
+               + "}\n"
+        var cursor = new kukit.tk.Cursor(txt);
+        this.assertParsingError(kukit.kssp.Document, cursor, null, true,
+            // XXX This error message will be fixed in service-layer branch
+            // XXX This will also fix running from IE, currently broken at error assert.
+            'Missing [string] value in the action definition [action-server]., at row 1, column 11');
+    };
+
+    this.testCombinedServerActionRejectsTwoStrings = function() {
+        // Server action rejects two strings.
+        //
+        // This test can only run in development mode, pass otherwise.
+        if (! kukit.isDevelMode) {return;}
+        //
+        var txt= "#id:click {\n"
+               + "    action-server:   foo 'bar';\n"
+               + "}\n"
+        var cursor = new kukit.tk.Cursor(txt);
+        this.assertParsingError(kukit.kssp.Document, cursor, null, true,
+            // XXX This error message will be fixed in service-layer branch
+            // XXX This will also fix running from IE, currently broken at error assert.
+            'Only one [string] value is allowed in the action definition [action-server]., at row 1, column 11');
+    };
+
+
+    this.testCombinedServerActionRejectsUrlWithoutParms = function() {
+        // Server action rejects url() if url has no parameter.
+        // It should have a string in any case.
+        //
+        // This test can only run in development mode, pass otherwise.
+        if (! kukit.isDevelMode) {return;}
+        //
+        var txt= "#id:click {\n"
+               + "    action-server:   doIt url();\n"
+               + "}\n"
+        var cursor = new kukit.tk.Cursor(txt);
+        this.assertParsingError(kukit.kssp.Document, cursor, null, true,
+            // XXX This error message will be fixed in service-layer branch
+            // XXX This will also fix running from IE, currently broken at error assert.
+            'Error in value for action definition [action-server] : Error: url() needs 1 argument., at row 1, column 11');
+    };
+
+    this.testServerActionRejectsValueProviderForString = function() {
+        // Server action must have a string, no value provider is allowed here.
+        //
+        // This test can only run in development mode, pass otherwise.
+        if (! kukit.isDevelMode) {return;}
+        //
+        var txt= "#id:click {\n"
+               + "    action-server:   kssAttr(blah);\n"
+               + "}\n"
+        var cursor = new kukit.tk.Cursor(txt);
+        this.assertParsingError(kukit.kssp.Document, cursor, null, true,
+            // XXX This error message will be fixed in service-layer branch
+            // XXX This will also fix running from IE, currently broken at error assert.
+            'Wrong value for key [action-server] : value providers are not allowed for action-<QUALIFIER> keys., at row 1, column 11');
+    };
+
+    this.testNormalProviderAcceptsValueAndSelector = function() {
+        // normal parameters accepts value and selector
+        //
+        // This test can only run in development mode, pass otherwise.
+        if (! kukit.isDevelMode) {return;}
+        //
+        var txt= "#id:click {\n"
+               + "    action-client: log;\n"
+               + "    log-message:   kssAttr(blah) htmlid('id');\n"
+               + "}\n"
+        var cursor = new kukit.tk.Cursor(txt);
+        var parser = new kukit.kssp.Document(cursor, null, true);
+        this.assertEquals(parser.finished, true);
+    };
+
+    this.testNormalProviderAcceptsSelectorAndValue = function() {
+        // normal parameters accepts value and selector
+        //
+        // This test can only run in development mode, pass otherwise.
+        if (! kukit.isDevelMode) {return;}
+        //
+        var txt= "#id:click {\n"
+               + "    action-client: log;\n"
+               + "    log-message:   htmlid('id') kssAttr(blah);\n"
+               + "}\n"
+        var cursor = new kukit.tk.Cursor(txt);
+        var parser = new kukit.kssp.Document(cursor, null, true);
+        this.assertEquals(parser.finished, true);
+    };
+
+    this.testNormalProviderAcceptsStringAndSelector = function() {
+        // normal parameters accepts string and selector
+        // although this does not make much sense... but it's allowed.
+        //
+        // This test can only run in development mode, pass otherwise.
+        if (! kukit.isDevelMode) {return;}
+        //
+        var txt= "#id:click {\n"
+               + "    action-client: log;\n"
+               + "    log-message:   'message' htmlid('id');\n"
+               + "}\n"
+        var cursor = new kukit.tk.Cursor(txt);
+        var parser = new kukit.kssp.Document(cursor, null, true);
+        this.assertEquals(parser.finished, true);
+    };
+
+    this.testNormalProviderAcceptsSelectorAndString = function() {
+        // normal parameters accepts selector and string
+        // although this does not make much sense... but it's allowed.
+        //
+        // This test can only run in development mode, pass otherwise.
+        if (! kukit.isDevelMode) {return;}
+        //
+        var txt= "#id:click {\n"
+               + "    action-client: log;\n"
+               + "    log-message:   htmlid('id') 'message';\n"
+               + "}\n"
+        var cursor = new kukit.tk.Cursor(txt);
+        var parser = new kukit.kssp.Document(cursor, null, true);
+        this.assertEquals(parser.finished, true);
+    };
+
+    this.testNormalProviderAcceptsValueAndSelector = function() {
+        // normal parameters accepts value and selector
+        //
+        // This test can only run in development mode, pass otherwise.
+        if (! kukit.isDevelMode) {return;}
+        //
+        var txt= "#id:click {\n"
+               + "    action-client: log;\n"
+               + "    log-message:   kssAttr(blah) htmlid('id');\n"
+               + "}\n"
+        var cursor = new kukit.tk.Cursor(txt);
+        var parser = new kukit.kssp.Document(cursor, null, true);
+        this.assertEquals(parser.finished, true);
+    };
+
+    this.testAliasedClientAction = function() {
+        // Client action can be aliased.
+        //
+        // This test can only run in development mode, pass otherwise.
+        // Note that merging the rules is not really tested from here,
+        // as we don't have DOM. So we can't really see if the alias
+        // is working, only that it is parsed well.
+        if (! kukit.isDevelMode) {return;}
+        //
+        var txt= "#id:click {\n"
+               + "    action-client:   doIt alias(doAlias);\n"
+               + "    doAlias-foo:     bar;\n"
+               + "}\n"
+        var cursor = new kukit.tk.Cursor(txt);
+        var parser = new kukit.kssp.Document(cursor, null, true);
+        this.assertEquals(parser.finished, true);
+    };
+
+    this.testServerActionRejectsAlias = function() {
+        // Server action rejects alias().
+        //
+        // This test can only run in development mode, pass otherwise.
+        if (! kukit.isDevelMode) {return;}
+        //
+        var txt= "#id:click {\n"
+               + "    action-server:   doIt alias(doAlias);\n"
+               + "    doAlias-foo:     bar;\n"
+               + "}\n"
+        var cursor = new kukit.tk.Cursor(txt);
+        this.assertParsingError(kukit.kssp.Document, cursor, null, true,
+            // XXX This error message will be fixed in service-layer branch
+            // XXX This will also fix running from IE, currently broken at error assert.
+            'Provider result type [alias] not allowed in the action definition [action-server]., at row 1, column 11');
+    };
+
+    this.testNormalParameterRejectsAlias = function() {
+        // normal parameters do not accept alias.
+        //
+        // This test can only run in development mode, pass otherwise.
+        if (! kukit.isDevelMode) {return;}
+        //
+        var txt= "#id:click {\n"
+               + "    action-client: log;\n"
+               + "    log-message:   whatever alias('name');\n"
+               + "}\n"
+        var cursor = new kukit.tk.Cursor(txt);
+        this.assertParsingError(kukit.kssp.Document, cursor, null, true,
+            // XXX This error message will be fixed in service-layer branch
+            // XXX This will also fix running from IE, currently broken at error assert.
+            'Provider result type [alias] not allowed in the action parameter [message]., at row 1, column 11');
+    };
+
+}; 
+
+kukit.KssParserValueProvidersCheckTestCase.prototype = new kukit.KssParserTestCaseBase;
+
+
 kukit.KssParserSelectorTestCase = function() {
     this.name = 'kukit.KssParserSelectorTestCase';
 
@@ -1115,6 +1769,7 @@
         this.assertParsingError(kukit.kssp.KssSelector, cursor, null, true,
             'Error : undefined namespace or event in [dnd-drog].');
     }
+
 }; 
 
 kukit.KssParserSelectorTestCase.prototype = new kukit.KssParserTestCaseBase;
@@ -1476,6 +2131,8 @@
 if (typeof(testcase_registry) != 'undefined') {
     testcase_registry.registerTestCase(kukit.KssParserTestCase,
                                        'kukit.KssParserTestCase');
+    testcase_registry.registerTestCase(kukit.KssParserValueProvidersCheckTestCase,
+                                       'kukit.KssParserValueProvidersCheckTestCase');
     testcase_registry.registerTestCase(kukit.KssParserSelectorTestCase,
                                        'kukit.KssParserSelectorTestCase');
     testcase_registry.registerTestCase(kukit.KssParserSelectorsTestCase,

Modified: kukit/kukit.js/branch/ree-1.4-markup-and-syntax-changes/tests/test_requestmanager.js
==============================================================================
--- kukit/kukit.js/branch/ree-1.4-markup-and-syntax-changes/tests/test_requestmanager.js	(original)
+++ kukit/kukit.js/branch/ree-1.4-markup-and-syntax-changes/tests/test_requestmanager.js	Wed Jan 23 17:35:34 2008
@@ -79,7 +79,7 @@
 
     this.testNormalSend = function() {
         // Test a simple send situation
-        var rm = new kukit.rm.RequestManager(2, null, kukit.DummyScheduler);
+        var rm = new kukit.rm.RequestManager(null, 2, kukit.DummyScheduler);
         this.assertRmQueues(rm, 0, 0);
         // queues
         var sent = [];
@@ -116,7 +116,7 @@
 
     this.testSendWithTimeouts = function() {
         // Test a simple timeout situation
-        var rm = new kukit.rm.RequestManager(2, null, kukit.DummyScheduler);
+        var rm = new kukit.rm.RequestManager(null, 2, kukit.DummyScheduler);
         this.assertRmQueues(rm, 0, 0);
         // queues
         var sent = [];
@@ -161,7 +161,7 @@
  
     this.testSendWithQueuedTimeout = function() {
         // Test timeout with queues not sent out
-        var rm = new kukit.rm.RequestManager(2, null, kukit.DummyScheduler);
+        var rm = new kukit.rm.RequestManager(null, 2, kukit.DummyScheduler);
         this.assertRmQueues(rm, 0, 0);
         // queues
         var sent = [];
@@ -203,7 +203,7 @@
  
     this.testSendWithQueuedSwallowed = function() {
         // If the queued element is timed out, it it not sent out
-        var rm = new kukit.rm.RequestManager(2, null, kukit.DummyScheduler);
+        var rm = new kukit.rm.RequestManager(null, 2, kukit.DummyScheduler);
         this.assertRmQueues(rm, 0, 0);
         // queues
         var sent = [];
@@ -246,7 +246,7 @@
 
     this.testAllTimedOut = function() {
         // If all elements are timed out
-        var rm = new kukit.rm.RequestManager(2, null, kukit.DummyScheduler);
+        var rm = new kukit.rm.RequestManager(null, 2, kukit.DummyScheduler);
         this.assertRmQueues(rm, 0, 0);
         // queues
         var sent = [];
@@ -284,7 +284,7 @@
 
     this.testTimeoutHooks = function() {
         // Test if timeout hook(s) are called
-        var rm = new kukit.rm.RequestManager(2, null, kukit.DummyScheduler);
+        var rm = new kukit.rm.RequestManager(null, 2, kukit.DummyScheduler);
         this.assertRmQueues(rm, 0, 0);
         // queues
         var sent = [];

Modified: kukit/kukit.js/branch/ree-1.4-markup-and-syntax-changes/tests/test_utils.js
==============================================================================
--- kukit/kukit.js/branch/ree-1.4-markup-and-syntax-changes/tests/test_utils.js	(original)
+++ kukit/kukit.js/branch/ree-1.4-markup-and-syntax-changes/tests/test_utils.js	Wed Jan 23 17:35:34 2008
@@ -227,7 +227,7 @@
         var base = kukit.ut.calculateBase(this.doc, this.pageLocation);
         this.assertEquals(base, this.pageRoot + '/');
     };
-}
+};
 
 kukit.BaseURLTestCase.prototype = new kukit.UtilsTestCaseBase;
 


More information about the Kukit-checkins mailing list