From reebalazs at codespeak.net Fri Jun 2 11:06:49 2006 From: reebalazs at codespeak.net (reebalazs at codespeak.net) Date: Fri, 2 Jun 2006 11:06:49 +0200 (CEST) Subject: [Kukit-checkins] r28071 - kukit/azaxdemo/branch/kss2 Message-ID: <20060602090649.660191006B@code0.codespeak.net> Author: reebalazs Date: Fri Jun 2 11:06:47 2006 New Revision: 28071 Added: kukit/azaxdemo/branch/kss2/ - copied from r28070, kukit/azaxdemo/trunk/ Log: kss2 branch From reebalazs at codespeak.net Fri Jun 2 11:13:45 2006 From: reebalazs at codespeak.net (reebalazs at codespeak.net) Date: Fri, 2 Jun 2006 11:13:45 +0200 (CEST) Subject: [Kukit-checkins] r28072 - in kukit/azaxdemo/branch/kss2: . browser Message-ID: <20060602091345.B99551006B@code0.codespeak.net> Author: reebalazs Date: Fri Jun 2 11:13:39 2006 New Revision: 28072 Added: kukit/azaxdemo/branch/kss2/browser/azax_instant_edit.kss kukit/azaxdemo/branch/kss2/browser/azax_three_autoupdate.kss kukit/azaxdemo/branch/kss2/browser/azax_tree.kss kukit/azaxdemo/branch/kss2/browser/azax_two_select.kss kukit/azaxdemo/branch/kss2/browser/cancel_submit.kss Removed: kukit/azaxdemo/branch/kss2/browser/azax_demo.kukit kukit/azaxdemo/branch/kss2/browser/azax_instant_edit.kukit kukit/azaxdemo/branch/kss2/browser/azax_three_autoupdate.kukit kukit/azaxdemo/branch/kss2/browser/azax_tree.kukit kukit/azaxdemo/branch/kss2/browser/azax_two_select.kukit kukit/azaxdemo/branch/kss2/browser/cancel_submit.kukit Modified: kukit/azaxdemo/branch/kss2/azaxview.py kukit/azaxdemo/branch/kss2/browser/azax_demo.kss kukit/azaxdemo/branch/kss2/browser/azax_demo_index.pt kukit/azaxdemo/branch/kss2/browser/azax_instant_edit.pt kukit/azaxdemo/branch/kss2/browser/azax_three_autoupdate.pt kukit/azaxdemo/branch/kss2/browser/azax_tree.pt kukit/azaxdemo/branch/kss2/browser/azax_two_select.pt kukit/azaxdemo/branch/kss2/browser/cancel_submit.pt kukit/azaxdemo/branch/kss2/configure.zcml Log: Make demos work with kss2 Modified: kukit/azaxdemo/branch/kss2/azaxview.py ============================================================================== --- kukit/azaxdemo/branch/kss2/azaxview.py (original) +++ kukit/azaxdemo/branch/kss2/azaxview.py Fri Jun 2 11:13:39 2006 @@ -87,12 +87,16 @@ self.setHtmlAsChild('div#text', value+'') return self.render() - #we'll need parameter passing first do this in a sane way - def getSubTree(self, value): - """ returns the current time """ - self.setHtmlAsChild('div#text', 'works') + def expandSubTree(self, value): + 'Expands given subtree' + self.setHtmlAsChild('#text', 'works, expand %s' % value) return self.render() + def collapseSubTree(self, value): + 'Collapses given subtree' + self.setHtmlAsChild('#text', 'works, collapse %s' % value) + return self.render() + def cancelSubmitSave(self, text_save): self.setHtmlAsChild('div#async', 'Async saved %s' % text_save) return self.render() Modified: kukit/azaxdemo/branch/kss2/browser/azax_demo.kss ============================================================================== --- kukit/azaxdemo/branch/kss2/browser/azax_demo.kss (original) +++ kukit/azaxdemo/branch/kss2/browser/azax_demo.kss Fri Jun 2 11:13:39 2006 @@ -1,23 +1,21 @@ -button#copyFrom:click { - remote: copyFromDivContent; +button#copyFrom click { + kss-action: copyFromDivContent; } -button#copyTo:click { - remote: copyToDivContent; +button#copyTo click { + kss-action: copyToDivContent; } -button#moveTo:click { - remote: moveToDivContent; +button#moveTo click { + kss-action: moveToDivContent; } -button#clear:click { - remote: clearDivContent; +button#clear click { + kss-action: clearDivContent; } -button#change:click { - remote: getDivContent; - log: "WE LOG from getDivContent"; -/* alert: "WE LOG from getDivContent"; */ +button#change click { + kss-action: getDivContent; } Deleted: /kukit/azaxdemo/branch/kss2/browser/azax_demo.kukit ============================================================================== --- /kukit/azaxdemo/branch/kss2/browser/azax_demo.kukit Fri Jun 2 11:13:39 2006 +++ (empty file) @@ -1,26 +0,0 @@ - - - - copyFromDivContent - - - copyToDivContent - - - moveToDivContent - - - - - clearDivContent - - - - - - getDivContent - - - - - Modified: kukit/azaxdemo/branch/kss2/browser/azax_demo_index.pt ============================================================================== --- kukit/azaxdemo/branch/kss2/browser/azax_demo_index.pt (original) +++ kukit/azaxdemo/branch/kss2/browser/azax_demo_index.pt Fri Jun 2 11:13:39 2006 @@ -8,8 +8,7 @@
  • Three autoupdate
  • instant edit
  • Cancel Submit Click
  • - - +
  • Tree
  • Added: kukit/azaxdemo/branch/kss2/browser/azax_instant_edit.kss ============================================================================== --- (empty file) +++ kukit/azaxdemo/branch/kss2/browser/azax_instant_edit.kss Fri Jun 2 11:13:39 2006 @@ -0,0 +1,10 @@ +div#text click { + kss-action: getInputField; + value: currentformvar(value); +} + +input#save click { + kss-action: saveText; + value: currentformvar(value); +} + Deleted: /kukit/azaxdemo/branch/kss2/browser/azax_instant_edit.kukit ============================================================================== --- /kukit/azaxdemo/branch/kss2/browser/azax_instant_edit.kukit Fri Jun 2 11:13:39 2006 +++ (empty file) @@ -1,9 +0,0 @@ - - - - getInputField - - - saveText - - Modified: kukit/azaxdemo/branch/kss2/browser/azax_instant_edit.pt ============================================================================== --- kukit/azaxdemo/branch/kss2/browser/azax_instant_edit.pt (original) +++ kukit/azaxdemo/branch/kss2/browser/azax_instant_edit.pt Fri Jun 2 11:13:39 2006 @@ -1,7 +1,7 @@ - + @@ -17,7 +17,10 @@ - +
    +

    Noone except Godefroid knows, what the part below this does. You +can safely ignore it, just click on "Click me".

    +

    ab

    -

    Remove Node with XPath

    XPath

    next 1

    Added: kukit/azaxdemo/branch/kss2/browser/azax_three_autoupdate.kss ============================================================================== --- (empty file) +++ kukit/azaxdemo/branch/kss2/browser/azax_three_autoupdate.kss Fri Jun 2 11:13:39 2006 @@ -0,0 +1,9 @@ +div#update-area timeout { + evt-delay: 2000; + kss-action: getCurrentTime; +} + +input#start-update click { + kss-action: getAutoupdateMarkup; +} + Deleted: /kukit/azaxdemo/branch/kss2/browser/azax_three_autoupdate.kukit ============================================================================== --- /kukit/azaxdemo/branch/kss2/browser/azax_three_autoupdate.kukit Fri Jun 2 11:13:39 2006 +++ (empty file) @@ -1,15 +0,0 @@ - - - - - - getCurrentTime - - - - - - getAutoupdateMarkup - - - Modified: kukit/azaxdemo/branch/kss2/browser/azax_three_autoupdate.pt ============================================================================== --- kukit/azaxdemo/branch/kss2/browser/azax_three_autoupdate.pt (original) +++ kukit/azaxdemo/branch/kss2/browser/azax_three_autoupdate.pt Fri Jun 2 11:13:39 2006 @@ -1,7 +1,7 @@ - + + + +

    All demos

    +

    More complex selectors

    + +

    +This demo implements the annoyUser kukit plugin that shows a simple +pattern of creating stateful (class-like) events in a plugin +and how to bind them from kss. +

    + +

    +The first button and the second button are bound to two event +instances, the first one sends every 3rd click to the server and +executes a local action otherwise; the second button does +the same but with a count of two. +

    + + +

    Demo

    +
    +
    + + + + Modified: kukit/azaxdemo/branch/kss2/configure.zcml ============================================================================== --- kukit/azaxdemo/branch/kss2/configure.zcml (original) +++ kukit/azaxdemo/branch/kss2/configure.zcml Sun Jun 11 16:45:40 2006 @@ -1,6 +1,7 @@ + xmlns:five="http://namespaces.zope.org/five" + xmlns:azax="http://namespaces.zope.org/azax"> + + + + + + + + + + + + + + - - - + - - + + From reebalazs at codespeak.net Tue Jun 20 17:14:36 2006 From: reebalazs at codespeak.net (reebalazs at codespeak.net) Date: Tue, 20 Jun 2006 17:14:36 +0200 (CEST) Subject: [Kukit-checkins] r29004 - in kukit/kukit.js: branch/kss1 trunk Message-ID: <20060620151436.760A610064@code0.codespeak.net> Author: reebalazs Date: Tue Jun 20 17:14:35 2006 New Revision: 29004 Added: kukit/kukit.js/branch/kss1/ - copied from r29003, kukit/kukit.js/trunk/ Removed: kukit/kukit.js/trunk/ Log: Move away From reebalazs at codespeak.net Tue Jun 20 17:15:29 2006 From: reebalazs at codespeak.net (reebalazs at codespeak.net) Date: Tue, 20 Jun 2006 17:15:29 +0200 (CEST) Subject: [Kukit-checkins] r29005 - kukit/kukit.js/trunk Message-ID: <20060620151529.1671010064@code0.codespeak.net> Author: reebalazs Date: Tue Jun 20 17:15:28 2006 New Revision: 29005 Added: kukit/kukit.js/trunk/ - copied from r29004, kukit/kukit.js/branch/kss2/ Log: Move away From reebalazs at codespeak.net Tue Jun 20 17:16:59 2006 From: reebalazs at codespeak.net (reebalazs at codespeak.net) Date: Tue, 20 Jun 2006 17:16:59 +0200 (CEST) Subject: [Kukit-checkins] r29006 - in kukit/azax: branch/kss1 trunk Message-ID: <20060620151659.13E7510064@code0.codespeak.net> Author: reebalazs Date: Tue Jun 20 17:16:57 2006 New Revision: 29006 Added: kukit/azax/branch/kss1/ - copied from r29005, kukit/azax/trunk/ Removed: kukit/azax/trunk/ Log: Move away From reebalazs at codespeak.net Tue Jun 20 17:17:20 2006 From: reebalazs at codespeak.net (reebalazs at codespeak.net) Date: Tue, 20 Jun 2006 17:17:20 +0200 (CEST) Subject: [Kukit-checkins] r29007 - kukit/azax/trunk Message-ID: <20060620151720.CD76710064@code0.codespeak.net> Author: reebalazs Date: Tue Jun 20 17:17:19 2006 New Revision: 29007 Added: kukit/azax/trunk/ - copied from r29006, kukit/azax/branch/kss2/ Log: Move away From reebalazs at codespeak.net Tue Jun 20 17:18:53 2006 From: reebalazs at codespeak.net (reebalazs at codespeak.net) Date: Tue, 20 Jun 2006 17:18:53 +0200 (CEST) Subject: [Kukit-checkins] r29008 - kukit/azax/branch/kss1 Message-ID: <20060620151853.0E53110064@code0.codespeak.net> Author: reebalazs Date: Tue Jun 20 17:18:52 2006 New Revision: 29008 Modified: kukit/azax/branch/kss1/ (props changed) kukit/azax/branch/kss1/EXTERNALS.TXT Log: Move away Modified: kukit/azax/branch/kss1/EXTERNALS.TXT ============================================================================== --- kukit/azax/branch/kss1/EXTERNALS.TXT (original) +++ kukit/azax/branch/kss1/EXTERNALS.TXT Tue Jun 20 17:18:52 2006 @@ -5,4 +5,4 @@ # You can update your working dir by: # svn propset svn:externals -F EXTERNALS.TXT . # -kukit http://codespeak.net/svn/kukit/kukit.js/trunk +kukit http://codespeak.net/svn/kukit/kukit.js/branch/kss1 From reebalazs at codespeak.net Tue Jun 20 17:23:28 2006 From: reebalazs at codespeak.net (reebalazs at codespeak.net) Date: Tue, 20 Jun 2006 17:23:28 +0200 (CEST) Subject: [Kukit-checkins] r29010 - kukit/azax/trunk Message-ID: <20060620152328.AFAD710064@code0.codespeak.net> Author: reebalazs Date: Tue Jun 20 17:23:27 2006 New Revision: 29010 Modified: kukit/azax/trunk/ (props changed) Log: Move away From reebalazs at codespeak.net Tue Jun 20 17:28:02 2006 From: reebalazs at codespeak.net (reebalazs at codespeak.net) Date: Tue, 20 Jun 2006 17:28:02 +0200 (CEST) Subject: [Kukit-checkins] r29012 - in kukit/azaxdemo: branch/kss1 trunk Message-ID: <20060620152802.0180110068@code0.codespeak.net> Author: reebalazs Date: Tue Jun 20 17:28:01 2006 New Revision: 29012 Added: kukit/azaxdemo/branch/kss1/ - copied from r29011, kukit/azaxdemo/trunk/ Removed: kukit/azaxdemo/trunk/ Log: Move away From reebalazs at codespeak.net Tue Jun 20 17:28:15 2006 From: reebalazs at codespeak.net (reebalazs at codespeak.net) Date: Tue, 20 Jun 2006 17:28:15 +0200 (CEST) Subject: [Kukit-checkins] r29013 - kukit/azaxdemo/trunk Message-ID: <20060620152815.4580A10068@code0.codespeak.net> Author: reebalazs Date: Tue Jun 20 17:28:13 2006 New Revision: 29013 Added: kukit/azaxdemo/trunk/ - copied from r29012, kukit/azaxdemo/branch/kss2/ Log: Move away From reebalazs at codespeak.net Wed Jun 21 11:39:52 2006 From: reebalazs at codespeak.net (reebalazs at codespeak.net) Date: Wed, 21 Jun 2006 11:39:52 +0200 (CEST) Subject: [Kukit-checkins] r29042 - kukit/kukit.js/trunk/kukit Message-ID: <20060621093952.01B5D1006F@code0.codespeak.net> Author: reebalazs Date: Wed Jun 21 11:39:51 2006 New Revision: 29042 Modified: kukit/kukit.js/trunk/kukit/kukit.js Log: not important Modified: kukit/kukit.js/trunk/kukit/kukit.js ============================================================================== --- kukit/kukit.js/trunk/kukit/kukit.js (original) +++ kukit/kukit.js/trunk/kukit/kukit.js Wed Jun 21 11:39:51 2006 @@ -509,9 +509,10 @@ kukit.CommandProcessor.prototype.executeCommand = function(command) { kukit.logDebug('Selector type: '+command.selectorType); kukit.logDebug('Selector : '+command.selector); - var nodes = kukit.selectors.get(command.selectorType)(command.selector); + var selfunc = kukit.selectors.get(command.selectorType); + var nodes = selfunc(command.selector); var func = null; - if (nodes.length == 0) { + if (!nodes || nodes.length == 0) { kukit.logError('Command found no nodes'); } else { func = kukit.commandRegistry.getFunc(command.name); From reebalazs at codespeak.net Thu Jun 22 22:00:17 2006 From: reebalazs at codespeak.net (reebalazs at codespeak.net) Date: Thu, 22 Jun 2006 22:00:17 +0200 (CEST) Subject: [Kukit-checkins] r29173 - kukit/azaxdemo/trunk/browser Message-ID: <20060622200017.C20A210069@code0.codespeak.net> Author: reebalazs Date: Thu Jun 22 22:00:13 2006 New Revision: 29173 Modified: kukit/azaxdemo/trunk/browser/azax_demo.kss kukit/azaxdemo/trunk/browser/azax_demo_index.pt kukit/azaxdemo/trunk/browser/azax_instant_edit.kss kukit/azaxdemo/trunk/browser/azax_three_autoupdate.kss kukit/azaxdemo/trunk/browser/azax_tree.kss kukit/azaxdemo/trunk/browser/azax_two_select.kss kukit/azaxdemo/trunk/browser/cancel_submit.kss kukit/azaxdemo/trunk/browser/more_selectors.kss Log: KSS3 minisprint result Modified: kukit/azaxdemo/trunk/browser/azax_demo.kss ============================================================================== --- kukit/azaxdemo/trunk/browser/azax_demo.kss (original) +++ kukit/azaxdemo/trunk/browser/azax_demo.kss Thu Jun 22 22:00:13 2006 @@ -1,21 +1,21 @@ -button#copyFrom click { - kss-action: copyFromDivContent; +button#copyFrom:click { + action-server: copyFromDivContent; } -button#copyTo click { - kss-action: copyToDivContent; +button#copyTo:click { + action-server: copyToDivContent; } -button#moveTo click { - kss-action: moveToDivContent; +button#moveTo:click { + action-server: moveToDivContent; } -button#clear click { - kss-action: clearDivContent; +button#clear:click { + action-server: clearDivContent; } -button#change click { - kss-action: getDivContent; +button#change:click { + action-server: getDivContent; } Modified: kukit/azaxdemo/trunk/browser/azax_demo_index.pt ============================================================================== --- kukit/azaxdemo/trunk/browser/azax_demo_index.pt (original) +++ kukit/azaxdemo/trunk/browser/azax_demo_index.pt Thu Jun 22 22:00:13 2006 @@ -8,6 +8,7 @@
  • Three autoupdate
  • instant edit
  • Cancel Submit Click
  • +
  • Tree
  • More complex selectors
  • Modified: kukit/azaxdemo/trunk/browser/azax_instant_edit.kss ============================================================================== --- kukit/azaxdemo/trunk/browser/azax_instant_edit.kss (original) +++ kukit/azaxdemo/trunk/browser/azax_instant_edit.kss Thu Jun 22 22:00:13 2006 @@ -1,10 +1,10 @@ -div#text click { - kss-action: getInputField; - value: currentformvar(value); +div#text:click { + action-server: getInputField; + getInputField-value: currentformvar(value); } -input#save click { - kss-action: saveText; - value: currentformvar(value); +input#save:click { + action-server: saveText; + saveText-value: currentformvar(value); } Modified: kukit/azaxdemo/trunk/browser/azax_three_autoupdate.kss ============================================================================== --- kukit/azaxdemo/trunk/browser/azax_three_autoupdate.kss (original) +++ kukit/azaxdemo/trunk/browser/azax_three_autoupdate.kss Thu Jun 22 22:00:13 2006 @@ -1,9 +1,9 @@ -div#update-area timeout { - evt-delay: 2000; - kss-action: getCurrentTime; +div#update-area:timeout { + evt-timeout-delay: 2000; + action-server: getCurrentTime; } -input#start-update click { - kss-action: getAutoupdateMarkup; +input#start-update:click { + action-server: getAutoupdateMarkup; } Modified: kukit/azaxdemo/trunk/browser/azax_tree.kss ============================================================================== --- kukit/azaxdemo/trunk/browser/azax_tree.kss (original) +++ kukit/azaxdemo/trunk/browser/azax_tree.kss Thu Jun 22 22:00:13 2006 @@ -1,9 +1,9 @@ -.state-expanded click { - kss-action: collapseSubTree; - value: nodeattr("id"); +.state-expanded:click { + action-server: collapseSubTree; + collapseSubTree-value: nodeattr("id"); } -.state-collapsed click { - kss-action: expandSubTree; - value: nodeattr("id"); +.state-collapsed:click { + action-server: expandSubTree; + expandSubTree-value: nodeattr("id"); } Modified: kukit/azaxdemo/trunk/browser/azax_two_select.kss ============================================================================== --- kukit/azaxdemo/trunk/browser/azax_two_select.kss (original) +++ kukit/azaxdemo/trunk/browser/azax_two_select.kss Thu Jun 22 22:00:13 2006 @@ -1,4 +1,4 @@ -select#first change { - kss-action: getCorrespondingSelect; - value: currentformvar(value); +select#first:change { + action-server: getCorrespondingSelect; + getCorrespondingSelect-value: currentformvar(value); } Modified: kukit/azaxdemo/trunk/browser/cancel_submit.kss ============================================================================== --- kukit/azaxdemo/trunk/browser/cancel_submit.kss (original) +++ kukit/azaxdemo/trunk/browser/cancel_submit.kss Thu Jun 22 22:00:13 2006 @@ -1,4 +1,4 @@ -input#submit cancelSubmitClick { - kss-action: save; - text_save: currentformvar(text_save); +input#submit:cancelSubmitClick { + action-server: save; + save-text_save: currentformvar(text_save); } Modified: kukit/azaxdemo/trunk/browser/more_selectors.kss ============================================================================== --- kukit/azaxdemo/trunk/browser/more_selectors.kss (original) +++ kukit/azaxdemo/trunk/browser/more_selectors.kss Thu Jun 22 22:00:13 2006 @@ -1,21 +1,23 @@ -#button-one click[class=annoyClicker,id=annoy-me] { - kss-action: clickedButton; - id: nodeattr(id); +#button-one:annoyClicker-click(annoyMe) { + action-server: clickedButton; + clickedButton-id: nodeattr(id); + action-client: log; + log-message: "Was here."; } -annoy#annoy-me { - kss-action: alert; - message: "You are an idiot! Ha ha ha. (But just keep on trying...)"; +document:annoy(annoyMe) { + action-client: alert; + alert-message: "You are an idiot! Ha ha ha. (But just keep on trying...)"; } -#button-two click[class=annoyClicker,id=annoy-you] { - evt-count: 2; - kss-action: clickedButton; - id: nodeattr(id); +#button-two:annoyClicker-click(annoyYou) { + evt-click-count: 2; + action-server: clickedButton; + clickedButton-id: nodeattr(id); } -annoy#annoy-you { - kss-action: alert; - message: "You are an idiot too, but not so big as I am."; +document:annoy(annoyYou) { + action-client: alert; + alert-message: "You are an idiot too, but not so big as I am."; } From reebalazs at codespeak.net Thu Jun 22 22:01:27 2006 From: reebalazs at codespeak.net (reebalazs at codespeak.net) Date: Thu, 22 Jun 2006 22:01:27 +0200 (CEST) Subject: [Kukit-checkins] r29175 - in kukit/azax/trunk: . plugins Message-ID: <20060622200127.50D2510069@code0.codespeak.net> Author: reebalazs Date: Thu Jun 22 22:01:24 2006 New Revision: 29175 Modified: kukit/azax/trunk/azaxview.py kukit/azax/trunk/commands.py kukit/azax/trunk/configure.zcml kukit/azax/trunk/plugins/configure.zcml Log: KSS3 minisprint result Modified: kukit/azax/trunk/azaxview.py ============================================================================== --- kukit/azax/trunk/azaxview.py (original) +++ kukit/azax/trunk/azaxview.py Thu Jun 22 22:01:24 2006 @@ -56,8 +56,8 @@ BrowserView.__init__(self, context, request) self.commands = AzaxCommands() - def addCommand(self, name, selector): - command = AzaxCommand(name, selector) + def addCommand(self, name, selector=None): + command = AzaxCommand(name, selector=selector) self.commands.append(command) return command Modified: kukit/azax/trunk/commands.py ============================================================================== --- kukit/azax/trunk/commands.py (original) +++ kukit/azax/trunk/commands.py Thu Jun 22 22:01:24 2006 @@ -54,14 +54,18 @@ class AzaxCommand: implements(IAzaxCommand) - def __init__(self, name, selector): + def __init__(self, name, selector=None): Command.checkRegistered(name) if isinstance(selector, basestring): self.selector = selector self.selectorType = '' else: - self.selector = selector.value - self.selectorType = selector.type + if selector is not None: + self.selector = selector.value + self.selectorType = selector.type + else: + self.selector = 'dummy' #None + self.selectorType = 'dummy' #None self.name = name self.params = [] Modified: kukit/azax/trunk/configure.zcml ============================================================================== --- kukit/azax/trunk/configure.zcml (original) +++ kukit/azax/trunk/configure.zcml Thu Jun 22 22:01:24 2006 @@ -20,6 +20,7 @@ kukit/kukit/forms.js kukit/kukit/plugin.js" name="kukit.js" + compress_level="none" /> + + - - Author: reebalazs Date: Thu Jun 22 22:03:28 2006 New Revision: 29176 Added: kukit/bluekit/ Log: Create From reebalazs at codespeak.net Thu Jun 22 22:05:45 2006 From: reebalazs at codespeak.net (reebalazs at codespeak.net) Date: Thu, 22 Jun 2006 22:05:45 +0200 (CEST) Subject: [Kukit-checkins] r29178 - kukit/bluekit/trunk/.bzr Message-ID: <20060622200545.BA0E710069@code0.codespeak.net> Author: reebalazs Date: Thu Jun 22 22:05:44 2006 New Revision: 29178 Removed: kukit/bluekit/trunk/.bzr/ Log: From reebalazs at codespeak.net Thu Jun 22 22:07:00 2006 From: reebalazs at codespeak.net (reebalazs at codespeak.net) Date: Thu, 22 Jun 2006 22:07:00 +0200 (CEST) Subject: [Kukit-checkins] r29179 - kukit/bluekit/branch Message-ID: <20060622200700.61FED10069@code0.codespeak.net> Author: reebalazs Date: Thu Jun 22 22:06:59 2006 New Revision: 29179 Added: kukit/bluekit/branch/ Log: Create From reebalazs at codespeak.net Thu Jun 22 22:07:06 2006 From: reebalazs at codespeak.net (reebalazs at codespeak.net) Date: Thu, 22 Jun 2006 22:07:06 +0200 (CEST) Subject: [Kukit-checkins] r29180 - kukit/bluekit/tag Message-ID: <20060622200706.31AEA10069@code0.codespeak.net> Author: reebalazs Date: Thu Jun 22 22:07:05 2006 New Revision: 29180 Added: kukit/bluekit/tag/ Log: Create From reebalazs at codespeak.net Fri Jun 2 11:27:47 2006 From: reebalazs at codespeak.net (reebalazs at codespeak.net) Date: Fri, 02 Jun 2006 09:27:47 -0000 Subject: [Kukit-checkins] r28078 - in kukit/kukit.js/branch/kss2: kukit tests Message-ID: <20060602092747.8C1231006B@code0.codespeak.net> Author: reebalazs Date: Fri Jun 2 11:27:40 2006 New Revision: 28078 Added: kukit/kukit.js/branch/kss2/kukit/actionreg.js kukit/kukit.js/branch/kss2/kukit/eventreg.js kukit/kukit.js/branch/kss2/kukit/forms.js kukit/kukit.js/branch/kss2/kukit/kssparser.js kukit/kukit.js/branch/kss2/kukit/plugin.js kukit/kukit.js/branch/kss2/kukit/resourcedata.js kukit/kukit.js/branch/kss2/kukit/tokenizer.js kukit/kukit.js/branch/kss2/tests/test_kssparser.js kukit/kukit.js/branch/kss2/tests/test_tokenizer.js Removed: kukit/kukit.js/branch/kss2/kukit/kukit.BsCommentParser.js kukit/kukit.js/branch/kss2/kukit/kukit.BsMethodParser.js kukit/kukit.js/branch/kss2/kukit/kukit.BsParser.js kukit/kukit.js/branch/kss2/kukit/kukit.BsPropertyParser.js kukit/kukit.js/branch/kss2/kukit/kukit.BsSelector.js kukit/kukit.js/branch/kss2/kukit/kukit.BsStringParser.js kukit/kukit.js/branch/kss2/kukit/kukit.KssParser.js kukit/kukit.js/branch/kss2/kukit/kukit.Parser.js kukit/kukit.js/branch/kss2/kukit/kukit.Utils.js kukit/kukit.js/branch/kss2/tests/kukit.BsParserTestCase.js kukit/kukit.js/branch/kss2/tests/kukit.KssParserTestCase.js kukit/kukit.js/branch/kss2/tests/kukit.PythonMethodSignatureTestCase.js kukit/kukit.js/branch/kss2/tests/testStyleParse.js Modified: kukit/kukit.js/branch/kss2/kukit/kukit.js kukit/kukit.js/branch/kss2/tests/runner.html kukit/kukit.js/branch/kss2/tests/runtests.js kukit/kukit.js/branch/kss2/tests/runtests.sh Log: Kss2 changes, old xml format temporarily ripped out. Added: kukit/kukit.js/branch/kss2/kukit/actionreg.js ============================================================================== --- (empty file) +++ kukit/kukit.js/branch/kss2/kukit/actionreg.js Fri Jun 2 11:27:40 2006 @@ -0,0 +1,44 @@ + +/* Event registration */ + +kukit.ar = {}; + +/* Event action registry +* +* The local event actions need to be registered here. +* +*/ + +/* Action registry */ + +kukit.ar.EventActionRegistry = function () { + this.content = {}; +}; + +kukit.ar.EventActionRegistry.prototype.register = function(name, func) { + if (typeof(func) == 'undefined') { + throw 'Func is mandatory.'; + } + if (this.content[name]) { + // Do not allow redefinition + kukit.logError('Error : redefinition attempt of action ' + name); + return; + } + this.content[name] = func; +}; + +kukit.ar.EventActionRegistry.prototype.exists = function(name) { + var entry = this.content[name]; + return (typeof(entry) != 'undefined'); +}; + +kukit.ar.EventActionRegistry.prototype.get = function(name) { + var func = this.content[name]; + if (! func) { + // not found + kukit.logError('Error : undefined action ' + name); + } + return func; +}; + +kukit.ar.eventActionRegistry = new kukit.ar.EventActionRegistry(); Added: kukit/kukit.js/branch/kss2/kukit/eventreg.js ============================================================================== --- (empty file) +++ kukit/kukit.js/branch/kss2/kukit/eventreg.js Fri Jun 2 11:27:40 2006 @@ -0,0 +1,93 @@ + +/* Event registration */ + +kukit.er = {}; + +/* Event class registry +* +* available for plugin registration +* +* class must be the *name* of the event class +* func must be a class (constructor) function. +* +*/ + +kukit.er.EventClassRegistry = function () { + this.content = {}; +}; + +kukit.er.EventClassRegistry.prototype.register = function(klass, func) { + if (typeof(func) == 'undefined') { + throw 'Func is mandatory.'; + } + if (this.content[klass]) { + // Do not allow redefinition + kukit.logError('Error : redefinition attempt of event class ' + klass); + return; + + } + // Decorate and store the class + kukit.er.decorateEventClass(func); + this.content[klass] = func; +}; + +kukit.er.EventClassRegistry.prototype.exists = function(klass) { + var func = this.content[klass]; + return (typeof(func) != 'undefined'); +}; + +kukit.er.EventClassRegistry.prototype.get = function(klass) { + var func = this.content[klass]; + if (! func) { + // not found + kukit.logError('Error : undefined event setup type ' + klass); + } + return func; +}; + +kukit.er.eventClassRegistry = new kukit.er.EventClassRegistry(); + +/* Event class decoration +* +* poor man's subclassing +* This is called automatically on registration, to dress +* up the event class with the necessary methods +* +*/ + +/* This can be called on the event and will execute the +* desired event action. Parameters will be these + those +* executed in the KSS. +*/ + +kukit.er.Event__trigger_action__ = function(name, parms) { + // TODO implement this + throw 'Not implemented'; +}; + + +kukit.er.decorateEventClass = function(cls) { + cls.prototype.__trigger_action__ = kukit.er.Event__trigger_action__; +}; + +/* Event instance registry +* +* used in run-time to keep track of the event instances +* +*/ + +kukit.er.EventInstanceRegistry = function () { + this.content = {}; +}; + +kukit.er.EventInstanceRegistry.prototype.getOrCreateEvent = function (id, klass) { + // Get or create the event. + var eventinstance = this.content[id]; + if (typeof(eventinstance) == 'undefined') { + // Create a new event. + eventinstance = this.content[id] = new (kukit.er.eventClassRegistry.get(klass))(); + } + return eventinstance; +}; + +kukit.er.eventInstanceRegistry = new kukit.er.EventInstanceRegistry(); Added: kukit/kukit.js/branch/kss2/kukit/forms.js ============================================================================== --- (empty file) +++ kukit/kukit.js/branch/kss2/kukit/forms.js Fri Jun 2 11:27:40 2006 @@ -0,0 +1,176 @@ + +/* Form handling utilities */ + +kukit.fo = {}; + +/* form query assembler */ + +kukit.fo.FormQueryElem = function(name, value) { + this.name = name; + this.value = value; +}; + +kukit.fo.FormQueryElem.prototype.encode = function() { + return this.name+ "=" + encodeURIComponent(this.value); +}; + +kukit.fo.FormQuery = function() { + this.l = []; +}; + +kukit.fo.FormQuery.prototype.appendElem = function(name, value) { + var elem = new kukit.fo.FormQueryElem(name, value); + this.l[this.l.length] = elem; +}; + +kukit.fo.FormQuery.prototype.encode = function() { + var poster = []; + for (var i=0;i < this.l.length;i++) { + poster[poster.length] = this.l[i].encode(); + } + return poster.join("&"); +}; + +kukit.fo.FormQuery.prototype.toDict = function() { + var d = {}; + for (var i=0;i < this.l.length;i++) { + var elem = this.l[i]; + d[elem.name] = elem.value; + } + return d; +}; + +/* Form data extraction */ + +kukit.fo.findContainer = function(node, func) { + // Starting with the given node, find the nearest containing element + // for which the given function returns true. + + while (node != null) { + if (func(node)) { + return node; + } + node = node.parentNode; + } + return false; +}; + +kukit.fo.getCurrentForm = function(target) { + // Find the form that contains the target node. + return kukit.fo.findContainer(target, function(node) { + if (!node.nodeName) { + return false; + } + if (node.nodeName.toLowerCase() == "form") { + return true; + } else { + return false; + } + }); +}; + +kukit.fo.getValueOfFormElement = function(element) { + // Returns the value of the form element / or null + if (element.selectedIndex != undefined) { + if (element.selectedIndex < 0) { + value=""; + } else { + var option = element.options[element.selectedIndex]; + value = option.value; + if (value == "") + value = option.text; + } + } else if (element.type == "checkbox") { + value = element.checked; + } else if (element.type == "radio") { + if (element.checked) { + value = element.value; + } else { + value = null; + } + } else if ((element.tagName.toLowerCase() == 'textarea') + || (element.tagName.toLowerCase() == 'input') + || (element.tagName.toLowerCase() == 'button') + ) { + value = element.value; + } else { + value = null; + } + return value; +}; + +kukit.fo.getFormVarFromCurrentForm = function(target, name) { + // Just get one formvar, from the form that contains the target node + var form = kukit.fo.getCurrentForm(target); + if (!form) { + kukit.logWarning("No form found"); + return null; + } + return kukit.fo.getFormVar(form, name); +} + +kukit.fo.getFormVarFromNamedForm = function(formname, name) { + // Just get one formvar, from the named form + var form = document.forms[formname]; + if (!form) { + kukit.logWarning("No form found"); + return null; + } + return kukit.fo.getFormVar(form, name); +} + +kukit.fo.getFormVar = function(form, name) { + // Extract the value of a formvar, from a given form + var value = null; + var element = form[name]; + if (element) { + var value = kukit.fo.getValueOfFormElement(element); + if (value == null) { + kukit.logWarning('Form element not harvested: '+element.tagName); + } else { + kukit.logDebug("Form element ("+element.tagName+"): name="+element.name+", value="+value); + } + } else { + kukit.logWarning('Form element '+ name + '" not found in form.'); + } + return value; +}; + + +// XXX XXX below this it will be deprecated, I think +// since now we extract stuff into the parms first.... + +kukit.fo.extractFormQuery = function(target) { + throw 'Deprecated?'; + // Extract the query that contains the target. + var query = new kukit.fo.FormQuery(); + // We now put isKukitRequest=1; XXX now deprecated. + //query.appendElem("isKukitRequest", "1"); + if (!target) { + kukit.logWarning("No target given"); + return query; + } + var form = kukit.fo.getFormForNode(target); + if (!form) { + kukit.logWarning("No form found"); + return query; + } + var elements = form.elements; + for (var y=0;y < elements.length;y++) { + var element = elements[y]; + var value = kukit.fo.getValueOfFormElement(element); + if (value == null) { + kukit.logWarning('Form element not harvested: '+element.tagName); + } else { + kukit.logDebug("Form element ("+element.tagName+"): name="+element.name+", value="+value); + query.appendElem(element.name, value); + } + } + return query; +}; + +kukit.fo.extractFormData = function(target) { + throw 'Deprecated?'; + return kukit.fo.extractFormQuery(target).encode(); +}; + Added: kukit/kukit.js/branch/kss2/kukit/kssparser.js ============================================================================== --- (empty file) +++ kukit/kukit.js/branch/kss2/kukit/kssparser.js Fri Jun 2 11:27:40 2006 @@ -0,0 +1,372 @@ + +/* Tokens of the kss parser */ + +kukit.kssp = {}; + +/* Tokens */ + +kukit.kssp.commentbegin = kukit.tk.mkToken('commentbegin', "/*"); +kukit.kssp.commentend = kukit.tk.mkToken('commentend', "*/"); +kukit.kssp.openbrace = kukit.tk.mkToken('openbrace', "{"); +kukit.kssp.closebrace = kukit.tk.mkToken('closebrace', "}"); +kukit.kssp.openbracket = kukit.tk.mkToken('openbracket', "["); +kukit.kssp.closebracket = kukit.tk.mkToken('closebracket', "]"); +kukit.kssp.openparent = kukit.tk.mkToken('openparent', "("); +kukit.kssp.closeparent = kukit.tk.mkToken('closeparent', ")"); +kukit.kssp.semicolon = kukit.tk.mkToken('semicolon', ";"); +kukit.kssp.colon = kukit.tk.mkToken('colon', ":"); +kukit.kssp.quote = kukit.tk.mkToken('quote', "'"); +kukit.kssp.dquote = kukit.tk.mkToken('dquote', '"'); +kukit.kssp.backslash = kukit.tk.mkToken('backslash', '\\'); +kukit.kssp.comma = kukit.tk.mkToken('comma', ","); +kukit.kssp.equals = kukit.tk.mkToken('equals', "="); + +/* Parsers */ + +kukit.kssp.document = kukit.tk.mkParser('document', { + "/*": 'new kukit.kssp.comment(this.src, kukit.kssp.commentbegin)', + "{": 'new kukit.kssp.block(this.src, kukit.kssp.openbrace)' + }); +kukit.kssp.document.prototype.process = function() { + this.eventRules = []; + var cursor = {'next': 0}; + while (cursor.next < this.result.length) { + this.digestTxt(cursor, kukit.tk.Fraction, kukit.kssp.comment); + var key = cursor.txt; + if (! key) { + break; + } + this.expectToken(cursor, kukit.kssp.block); + this.addBlock(key, cursor.token); + } + this.result = []; + this.txt = ''; +}; +kukit.kssp.document.prototype.addBlock = function(key, block) { + // Prepare the selector + // split it on spaces. + var split_selector = key.split(' '); + var css = null; + var name; + var klass = null; + var id = null; + var isEvent; + if (split_selector.length == 0) { + this.emitError("Zero length selector"); + } else if (split_selector.length == 1) { + //If there is only one tag, it's a method selector. + isEvent = false; + name = key; + } else { + // More tags: an event selector. + isEvent = true; + name = split_selector.pop(); + css = split_selector.join(' '); + } + var kssSelector = new kukit.rd.KssSelector(isEvent, css, name, klass, id); + // Create the event rule. (one action only) + var eventRule = new kukit.rd.EventRule(kssSelector, block.evt_parms, block.action); + // Sture the rule + this.eventRules.push(eventRule); +}; + +// it's not 100% good, but will do +kukit.kssp.comment = kukit.tk.mkParser('comment', { + "*/": 'this.emitAndReturn(new kukit.kssp.commentend(this.src))' + }); +kukit.kssp.comment.prototype.process = function() { + this.result = []; + this.txt = ' '; +}; + + +kukit.kssp.block = kukit.tk.mkParser('block', { + ";": 'new kukit.kssp.semicolon(this.src)', + ":": '[new kukit.kssp.colon(this.src), new kukit.kssp.propvalue(this.src)]', + "}": 'this.emitAndReturn(new kukit.kssp.closebrace(this.src))' + }); +kukit.kssp.block.prototype.process = function() { + this.parms = {}; + this.evt_parms = {}; + this.action = null; + this.error = null; + var cursor = {'next': 1}; + while (cursor.next < this.result.length-1) { + this.digestTxt(cursor, kukit.tk.Fraction, kukit.kssp.comment); + var key = cursor.txt; + if (! key) { + break; + } + this.expectToken(cursor, kukit.kssp.colon); + this.expectToken(cursor, kukit.kssp.propvalue); + // store the wrapped prop + this.addDeclaration(key, cursor.token.value); + if (cursor.next == this.result.length-1) break; + this.expectToken(cursor, kukit.kssp.semicolon); + } + this.result = []; + this.txt = ''; + // set result action, this and evt_parms are the output. + this.action = new kukit.rd.Action(this.action, this.error, this.parms); + this.error = null; + this.parms = null; +}; +kukit.kssp.block.prototype.addDeclaration = function(key, value) { + // p.s. value is here a KssXxParm. In most cases we check and unwrap it. + if (key.substr(0, 4) == 'kss-') { + key = key.substr(4); + if (key == 'any') { + if (value.isMethod != true) { + this.emitError('kss-any: must have a method parm value'); + } + this.parms['*'] = value; + } else if (key == 'action') { + if (value.isMethod != false) { + this.emitError('kss-action: must not have a method parm value'); + } + this.action = value.txt; + } else if (key == 'error') { + if (value.isMethod != false) { + this.emitError('kss-error: must not have a method parm value'); + } + this.error = value.txt; + } else { + this.emitError('Bad kss-key: "' + key + '"'); + } + } else if (key.substr(0, 4) == 'evt-') { + key = key.substr(4); + if (value.isMethod != false) { + this.emitError('evt-key: must not have a method parm value, key "' + key + '"'); + } + this.evt_parms[key] = value.txt; + } else { + if (key == '*') { + this.emitError('Bad action key: "' + key + '"'); + } else { + // these may be either txt or method parms, and they stored with the wrapper. + this.parms[key] = value; + } + } +}; + +kukit.kssp.propvalue = kukit.tk.mkParser('propvalue', { + ";": 'this.emitAndReturn()', + "}": 'this.emitAndReturn()', + ")": 'this.emitAndReturn()', + ",": 'this.emitAndReturn()', + "'": 'new kukit.kssp.string(this.src, kukit.kssp.quote)', + '"': 'new kukit.kssp.string2(this.src, kukit.kssp.dquote)', + "/*": 'new kukit.kssp.comment(this.src, kukit.kssp.commentbegin)', + "(": 'new kukit.kssp.methodargs(this.src, kukit.kssp.openparent)' + }); +kukit.kssp.propvalue.prototype.process = function() { + var cursor = {'next': 0}; + this.digestTxt(cursor, kukit.tk.Fraction, kukit.kssp.comment); + this.txt = ''; + var txt = cursor.txt; + if (this.ifToken(cursor, kukit.kssp.string)) { + // The previous txt must be all whitespace. + if (txt) { + this.emitError('Excess characters before the string in property value'); + } + // the next one must be a string. + this.expectToken(cursor, kukit.kssp.string); + this.produceTxt(cursor.token.txt); + } else if (this.ifToken(cursor, kukit.kssp.methodargs)) { + // see if not empty and has no spaces in it + if (! txt || txt.indexOf(' ') != -1) { + this.emitError('Method property value must have a one-word method name'); + } + // the next one must be the params + this.expectToken(cursor, kukit.kssp.methodargs); + this.value = new kukit.rd.KssMethodValue(txt, cursor.token.args); + } else { + // not a string or method: check if we allowed multiword. + if (! this.multiword_allowed && txt.indexOf(' ') != -1) { + this.emitError('Property value must be one word'); + } + this.produceTxt(txt); + } + // see what's after + if (cursor.next < this.result.length) { + this.digestTxt(cursor, kukit.tk.Fraction, kukit.kssp.comment); + // we have to be at the end and have no text after + if (cursor.next < this.result.length || cursor.txt) { + this.emitError('Excess characters after the property value'); + } + } + this.result = []; + // Check the syntax of the value, enables early error detection. + if (typeof this.value != 'undefined') { + this.value.check(); + } +}; +kukit.kssp.propvalue.prototype.multiword_allowed = true; +kukit.kssp.propvalue.prototype.produceTxt = function(txt) { + // txt parms are returned embedded + this.value = new kukit.rd.KssTextValue(txt); +} + +// propvalue in method cannot contain method-style vars. +kukit.kssp.propvalue_in_method = kukit.tk.mkParser('propvalue', { + ";": 'this.emitAndReturn()', + "}": 'this.emitAndReturn()', + ")": 'this.emitAndReturn()', + "]": 'this.emitAndReturn()', + ",": 'this.emitAndReturn()', + "'": 'new kukit.kssp.string(this.src, kukit.kssp.quote)', + '"': 'new kukit.kssp.string2(this.src, kukit.kssp.dquote)', + "/*": 'new kukit.kssp.comment(this.src, kukit.kssp.commentbegin)' //, + }); +kukit.kssp.propvalue_in_method.prototype.multiword_allowed = false; +kukit.kssp.propvalue_in_method.prototype.process = kukit.kssp.propvalue.prototype.process; +kukit.kssp.propvalue_in_method.prototype.produceTxt = function(txt) { + // txt parms are returned unwrapped + this.txt = txt; +}; + +kukit.kssp.string = kukit.tk.mkParser('string', { + "'": 'this.emitAndReturn(new kukit.kssp.quote(this.src))', + "\\": 'new kukit.kssp.backslashed(this.src, kukit.kssp.backslash)' + }); +kukit.kssp.string.prototype.process = function() { + // collect up the value of the string, omitting the quotes + this.txt = ''; + for (var i=1; iNote: Gets abused by {@code kukit.BsParser} - * - * @author Martin Heidegger - * @version 1.0 - */ -kukit.BsCommentParser = function() {} - -/** - * Removes from the content until the next end of the content. - * - * @param options parseoptions passed by {@code kukit.Parser} - */ -kukit.BsCommentParser.parse = function(options) { - var src = options.src; - var subsrc = src; - var pos = subsrc.indexOf("*/"); - var subpos = pos; - while (subsrc.charAt(subpos-1) == "\\" && subsrc.charAt(subpos-2) != "\\") { - subsrc = subsrc.substring(subpos+2); - subpos = subsrc.indexOf("*/"); - pos += subpos+2; - } - options.src = src.substring(0,options.pos)+src.substr(pos+2); -} Deleted: /kukit/kukit.js/branch/kss2/kukit/kukit.BsMethodParser.js ============================================================================== --- /kukit/kukit.js/branch/kss2/kukit/kukit.BsMethodParser.js Fri Jun 2 11:27:40 2006 +++ (empty file) @@ -1,59 +0,0 @@ -/** - * {@code kukit.BsMethodParser} parses a method as property value for {@code kukit.BsPropertyParser}. - * - *

    Note: Gets abused by {@code kukit.BsParser} - * - * @author Martin Heidegger - * @version 1.0 - */ -kukit.BsMethodParser = function(){} - -/** - * Central parsing method - * - * @param options parseoptions passed by {@code kukit.Parser} - */ -kukit.BsMethodParser.parse = function(options) { - var methodName = options.src.substring(0,options.pos); - // Ignore an empty method name! - // this is somewhat "off line" but we like this. - var value = []; - if (methodName != '') { - value.push(methodName); - } - var properties = options.src.substring(options.pos+1); - parseoptions = kukit.Parser.parse(this, properties, value, this.parseSettings); - options.result.push(value); - options.src = parseoptions.src; -} - -/** - * Handles if the end of the property "," occurs. - * - * @param options parseoptions passed by {@code kukit.Parser} - */ -kukit.BsMethodParser.parsePropertyEnd = function(options) { - var name = kukit.Utils.trim(options.src.substring(0,options.pos)); - if (name != "") - options.result.push(name); - options.src = options.src.substring(options.pos+1); -} - -/** - * Handles if the end of the method occus. - * - * @param options parseoptions passed by {@code kukit.Parser} - */ -kukit.BsMethodParser.parseEnd = function(options) { - this.parsePropertyEnd(options); - options.exit = 0; -} - -// Settings for the method block parsing -kukit.BsMethodParser.parseSettings = { - "}": kukit.Parser.parserError("Method needs to be closed by )"), - "\"": kukit.BsStringParser.parse, - "/*": kukit.BsCommentParser.parse, - ",": kukit.BsMethodParser.parsePropertyEnd, - ")": kukit.BsMethodParser.parseEnd -} Deleted: /kukit/kukit.js/branch/kss2/kukit/kukit.BsParser.js ============================================================================== --- /kukit/kukit.js/branch/kss2/kukit/kukit.BsParser.js Fri Jun 2 11:27:40 2006 +++ (empty file) @@ -1,224 +0,0 @@ -/** - * {@code BsParser} is a Parser that parses any bs string. - * - *

    BS stands for "Behaviour Sheet" and is ment as format for defining - * behaviors to bind logic with html elements like css is bind styles with html - * elements. - * - *

    {@code BsParser} is written to parse the CSS syntax and create a object - * model. To invoke the BsParser you just need to call: - * {@code kukit.BsParser.parse("...")} - * - *

    {@code BsParser} is based on {@link kukit.Parser} mechianisms. This requires - * to have parser settings that are defined at the end of the file and refer to - * certain sub-parsermethods. - * - * - * XXX XXX XXX I changed this, please revise the following docs! - * (i.e. where there can be a list there is now always a list etc.) - * - *

    Example: - * {@code BsParser} would transform this css sytax: - * - * myselector:mytype(typearg,typearg) { - * property: value1 value2 value3(valuearg, valuearg); - * anotherproperty: "value with space"; - * } - * - * - * Javascript Object - * - * { - * myselector: { - * selector: myselector, - * type: { - * name: "mytype", - * properties: ["typearg", "typearg"] - * } - * properties: { - * property: [ - * "value1", - * "value2", - * ["value3", "valuearg", "valuearg"] - * ], - * anotherproperty: [ - * "value with space" - * ] - * } - * } - * } - * - * - *

    If you define the same selector and type (including arguments) it combines - * all together to one property information like: - * - * BehaviorSheet - * - * tag { - * key1: value; - * } - * tag { - * key2: value; - * } - * - * - * JavaScript Object - * - * { - * tag: { - * key1: "value", - * key2: "value" - * } - * } - * - * - * @see kukit.Parser.parse - * @author Martin Heidegger - * @version 1.0 - */ -kukit.BsParser = function() {}; - -/** - * Parses a BS string - * - * @param src source to be parsed - */ -kukit.BsParser.parse = function(src) { - var result = {}; - // Base parsing should just recognize each block - kukit.Parser.parse(this, src, result, { - "{": this.parseBlock, - "/*": kukit.BsCommentParser.parse // integrated without scope insurance - // for perfomance saving - }); - return result; -} - -// Definitions of white spaces to be ignored -kukit.BsParser.WHITE_SPACES = " \t"; - -/** - * Removes unnecessary white spaces inside the block content. - * - * @param options parseoptions passed by {@code kukit.Parser} - */ -kukit.BsParser.parseWhiteSpaces = function(options) { - var src = options.src.substring(options.pos); - var whitespaces = this.WHITE_SPACES; - while (whitespaces.indexOf(src.charAt(0)) != -1) { - src = src.substr(1); - } - options.src = options.src.substring(0, options.pos)+src; -} - -/** - * Handles the end of a block - * - * @param options parseoptions passed by {@code kukit.Parser} - */ -kukit.BsParser.parseBlockEnd = function(options) { - options.src = options.src.substring(options.pos+1); - options.exit = 0; -} - -/** - * Parses the selector and passes the block content to certain sub parsers. - * - * @param options parseoptions passed by {@code kukit.Parser} - */ -kukit.BsParser.parseBlock = function(options) { - var src = options.src; - var rawselectors = src.substring(0, options.pos).split(","); - var selectors = {}; - - // Formatting the selector and register them - for (var i=0; i 0) - options.exit = parseoptions.exit; -} - -/** - * Parses the selector and returns it. - * - * @param selector raw selector name - * @return {@link kukit.BsSelector} - */ -kukit.BsParser.getSelectorInfos = function(selector) { - var infos = new kukit.BsSelector(); - // : indicates type value - var typestart = selector.indexOf(":"); - if (typestart > -1) { - - infos.selector = selector.substring(0,typestart); - - var temp = []; - var parserresult = kukit.Parser.parse(this, selector.substring(typestart+1), temp, { - "(": kukit.Utils.cachedCall(kukit.BsMethodParser, "parse") - }); - - var rest = kukit.Utils.trim(parserresult.src); - - // Handling if the rest if the type arguments - infos.type.name = null; - infos.type.properties = []; - if (rest != "" && !infos.type.name) { - infos.type.name = rest; - } else { - // Since the MethodParser works a different way for BsPropertyParser it - // needs to be reformatted - - if(temp[0]) - temp = temp[0]; - - for (var j=0; jProperties inside a BehaviourSheet are to complex for inline processing - * so this class handles the content used within a selector block. - * - * @author Martin Heidegger - * @version 1.0 - */ -kukit.BsPropertyParser = function() {} - -/** - * Parse starting with the property indiciator : - * - * @param options parseoptions passed by {@code kukit.Parser} - */ -kukit.BsPropertyParser.parse = function(options) { - var key = this.checkProperty(options.src.substring(0,options.pos)); - var properties = []; - var rest = options.src.substring(options.pos+1); - parseroptions = kukit.Parser.parse(this, rest, properties, this.parseSettings); - options.src = parseroptions.src; - options.result[key] = properties; - if (parseroptions.exit > 1) { - options.error = parseroptions.error; - options.exit = parseroptions.exit; - } -} - -/** - * Parsing next value for a key indicated by the space ( ). - * - *

    This is a subparser method for properties. - * - * @param options parseoptions passed by {@code kukit.Parser} - */ -kukit.BsPropertyParser.parseNextProperty = function(options) { - this.addProperty(options, options.src.substring(0,options.pos)); - options.src = options.src.substring(options.pos+1); -} - -/** - * Ends the processing of a block - * - *

    This is a subparser method for properties. - * - * @param options parseoptions passed by {@code kukit.Parser} - */ -kukit.BsPropertyParser.parsePropertyBlockEnd = function(options) { - this.addProperty(options, options.src.substring(0,options.pos)); - options.src = options.src.substring(options.pos); - options.exit = 0; -} - -/** - * Finishes the processing of any property. - * - * @param options parseoptions passed by {@code kukit.Parser} - */ -kukit.BsPropertyParser.parsePropertyEnd = function(options) { - this.parseNextProperty(options); - options.exit = 0; -} - -/** - * Helper for adding a property to the result. - * - * @param options parseoptions passed by {@code kukit.Parser} - * @param property property - */ -kukit.BsPropertyParser.addProperty = function(options, property) { - property = this.checkProperty(property); - if (property != "") - // XXX Since we could have an array of properties here, - // for consistence this simple case will be pushed as - // a one-element array as well. - options.result.push([property]); -} - -/** - * Validates if a property matches all states. - * - * @param options parseoptions passed by {@code kukit.Parser} - * @param property property - */ -kukit.BsPropertyParser.checkProperty = function(property) { - property = kukit.Utils.trim(property); - property = property.split("\\n").join("\n"); - property = property.split("\\t").join("\t"); - property = property.split("\\b").join("\b"); - property = property.split("\\b").join("\b"); - return property; -} - -// Settings for the property parsing -kukit.BsPropertyParser.parseSettings = { - "(": kukit.Utils.cachedCall(kukit.BsMethodParser, "parse"), - "\"": kukit.BsStringParser.parse, - "/*": kukit.BsCommentParser.parse, - " ": kukit.BsPropertyParser.parseNextProperty, - ";": kukit.BsPropertyParser.parsePropertyEnd, - "}": kukit.BsPropertyParser.parsePropertyBlockEnd -} Deleted: /kukit/kukit.js/branch/kss2/kukit/kukit.BsSelector.js ============================================================================== --- /kukit/kukit.js/branch/kss2/kukit/kukit.BsSelector.js Fri Jun 2 11:27:40 2006 +++ (empty file) @@ -1,38 +0,0 @@ -/** - * {@code BsSelector} is a data holder for the informations including its (pseudo)class called "type" - * - * @author Martin Heidegger - * @version 1.0 - */ -kukit.BsSelector = function() { - this.properties = {}; // properties for the type - this.type = {}; // type informations - this.selector = ""; // selector to be used -} -/** - * Transforms the selector into a string. - * - *

    This method is important for identifing a certain selector including - * its method informations. - * - * @return selector as string - */ -kukit.BsSelector.prototype.id = function() { - var result = this.selector; - - with (this.type) { - if (typeof name != "undefined") { - result += ":"+name+"("; - if (typeof properties != "undefined") { - for (var i=0; i< properties.length; i++) { - if (i != 0) - result += ","; - result += properties[i]; - } - } - result += ")"; - } - } - - return result; -} \ No newline at end of file Deleted: /kukit/kukit.js/branch/kss2/kukit/kukit.BsStringParser.js ============================================================================== --- /kukit/kukit.js/branch/kss2/kukit/kukit.BsStringParser.js Fri Jun 2 11:27:40 2006 +++ (empty file) @@ -1,39 +0,0 @@ -/** - * {@code kukit.BsStringParser} handles the parsing of a string value - * - *

    If you set a value with " you need to have different parsing. - * - * @author Martin Heidegger - * @version 1.0 - */ -kukit.BsStringParser = function() {} - -/** - * Removes the doublequotes and adds the content to the passed-in result. - * - * @param options parseoptions passed by {@code kukit.Parser} - */ -kukit.BsStringParser.parse = function(options) { - var content = ""; - var src = options.src.substring(options.pos+1); - var pos = src.indexOf("\""); - while (pos >= 0) { - content = src.substring(0, pos); - src = src.substring(pos+1); - - // Handle escaping of the doublequotes - if (src.charAt(pos-1) != "\\" || src.charAt(pos-2) != "\\") { - break; - } - content += "\""; - pos = src.indexOf("\""); - } - options.src = options.src.substring(0, options.pos)+options.src.substring(options.pos+content.length+2); - // XXX Since we could have an array of properties here, - // for consistence this simple case will be pushed as - // a one-element array as well. - // XXX but this is principally broken because this has nothing to - // do with string parsing - only I cannot figure out how to do - // this from an embedding part. - options.result.push([kukit.BsPropertyParser.checkProperty(content)]); -} Deleted: /kukit/kukit.js/branch/kss2/kukit/kukit.KssParser.js ============================================================================== --- /kukit/kukit.js/branch/kss2/kukit/kukit.KssParser.js Fri Jun 2 11:27:40 2006 +++ (empty file) @@ -1,117 +0,0 @@ - -/* -* -* Parse the entire rule file from kss format -* -*/ - - -/* -* -* Converters that parse from the format the -* parser gives us as result -* -* We need to have our first class object -* structure EventRule -> Action -* -*/ - -// XXX Note this is principally broken because of -// the possibility of ""-s in kw values, and the =-s -// in string args. -// XXX Parsing must be done entirely by the main parser. -// This is no better than a workaround. - -kukit.ParmConverter = function(parameters) { - // Accept an array of parameters, - // converts them to args and kw. - this.args = [] - this.kw = {} - var found_kw = false; - for (var i=0; i{@code kukit.Parser} provides a generic way of parsing text by taking - * parseMethods registered to characters. If one of the registered characters - * occurs it calls the related method together with a parsing scope. - * - *

    The parsing scope contains the result and the rest of the remaining stuff - * to parse the code. - * - * @author Martin Heidegger - * @version 1.0 - */ -kukit.Parser = function() {} - -/** - * Parses a certain source. - * - * @param scope scope where the subparsers will be executed - * @param src src that should be parsed - * @param result result that can be accessed by each subparser - * @subparsers map of subparsers mapped to characters - * @return options to be used during execution (containing the rest string in .src) - */ -kukit.Parser.parse = function(scope, src, result, subparsers) { - var options = {scope: scope, src:src, result:result, subparsers:subparsers, exit: -1}; - while (this.nextStep(options) && options.exit == -1); - return options; -} - -// List of errors that occured -kukit.Parser.errors = {}; - -/** - * Executes the next step of parsing. - * - * @param options options for all - * @return true if it could find something to parse - */ -kukit.Parser.nextStep = function(options) { - - // Take the next matching subparser by its identifier - var next = -1; - var parser; - var parsername; - for (var i in options.subparsers) { - var pos = options.src.indexOf(i); - if ((pos < next || next == -1) && pos != -1) { - next = pos; - parsername = i; - parser = options.subparsers[i]; - } - } - options.pos = next; - - // Execute the parser to the scope - if (parser) { - var n = "__parserMethod__" - options.scope[n] = parser; - try { - options.scope[n](options); - } catch(e) { - options.error = e; - options.exit = 2; - print(e); - } - } else if(next >= 0) { - options.error = "Parser for > "+parsername+" < not found"; - options.exit = 2; - print(options.error); - } - return (next >=0); -} - -/** - * Util that exits parsing with a error if a character occurs. - * - * @param error Error that should be set if a character occurs - * @return parser-method to be integrated into the parser - */ -kukit.Parser.parserError = function(error) { - errormethod = this.errors[error]; - if (!errormethod) { - errormethod = function(options) { - options.error = error; - options.exit = 1; - } - } - return errormethod; -} \ No newline at end of file Deleted: /kukit/kukit.js/branch/kss2/kukit/kukit.Utils.js ============================================================================== --- /kukit/kukit.js/branch/kss2/kukit/kukit.Utils.js Fri Jun 2 11:27:40 2006 +++ (empty file) @@ -1,47 +0,0 @@ -// Namespace declarations -if (typeof(kukit) == "undefined") { - var kukit = {}; -} - -/** - * Collection of utils for kukit. - * - * @author Martin Heidegger - * @version 1.0 - */ -kukit.Utils = function() {} - -/** - * Creates a function that executes a method inside a scope and stores it. - * - *

    In different to other scope keeper implementations, this implementation - * stores the method call in a field so its not recreated again and again. - * - * @todo integrate generic call (currently only one arguments is supported) - * - * @param scope Scope of the method call - * @param methodName Name of the method in the scope - * @return - */ -kukit.Utils.cachedCall = function(scope, methodName) { - var method = scope[methodName+"_ref"]; - if (!method) { - method = scope[methodName+"_ref"] = function(options) { - return scope.parse(options); - } - } - return method; -} - -/** - * Trims a string. - * - * @param str String to be trimmed - * @param chars Characters that should be trimmed - * @return Trimmed string - */ -kukit.Utils.trim = function(str, chars) { - if (!chars) - chars='\\s\\n\\r' - return str.replace(new RegExp("^["+chars+"]*(.*?)["+chars+"]*$"), "$1"); -} Modified: kukit/kukit.js/branch/kss2/kukit/kukit.js ============================================================================== --- kukit/kukit.js/branch/kss2/kukit/kukit.js (original) +++ kukit/kukit.js/branch/kss2/kukit/kukit.js Fri Jun 2 11:27:40 2006 @@ -20,6 +20,58 @@ kukit.logWarning = kukit.log; } +/* +* Exception factory +* +* Create exception types: +* +* myError = kukit.exceptionFactory("myError", "My special error: "); +* +* Throwing: +* +* throw new myError("There was an error in my program."); +* +* Catching example: +* +* ... +* } catch(e) { +* if (e.name == 'JSONRPCError') { +* ... +* } else { +* throw(e); +* } +* } +* +*/ + +// XXX TODO what about IE or other browsers? +// - on IE6, the error text is not printed. + +kukit.exceptionFactory = function(name) { + var exc = function (arg1, arg2, arg3, arg4, arg5) { + var kw = this.__init__(name, arg1, arg2, arg3, arg4, arg5); + var err = new Error(kw.message); + for (var key in kw) { + err[key] = kw[key]; + } + // number is an IE-only property + if (typeof err.number == 'number') { + // show sensible error on IE + err.toString = function () { + return this.name + ': ' + this.message; + } + } + return err + } + exc.prototype.__init__ = function(name, message) { + var kw = {}; + kw.name = name; + kw.message = message; + return kw; + } + return exc +}; + /* Request manager */ kukit.RequestManager = function (name, maxNr) { @@ -37,102 +89,102 @@ if (typeof(maxNr) != undefined && maxNr != null) { this.maxNr = maxNr; } -} +}; // max request number kukit.RequestManager.prototype.maxNr = 4; kukit.RequestManager.prototype.getInfo = function() { return '(RQ: ' + this.sentNr + ' OUT, ' + this.waitingQueue.size() + ' WAI)'; -} +}; kukit.RequestManager.prototype.log = function(txt) { kukit.logDebug('RequestManager ' + this.namestr + txt + ' ' + this.getInfo()); -} +}; kukit.RequestManager.prototype.pushWaitingRequest = function(func, url) { this.waitingQueue.push([func, url]); -} +}; kukit.RequestManager.prototype.popWaitingRequest = function() { return this.waitingQueue.pop(); -} +}; kukit.RequestManager.prototype.isWaitingRequestQueueEmpty = function() { return this.waitingQueue.empty(); -} +}; kukit.RequestManager.prototype.pushSentRequest = function(func, url) { // we do not store the elems, since they are not needed now this.sentNr = this.sentNr + 1; -} +}; kukit.RequestManager.prototype.popSentRequest = function() { this.sentNr = this.sentNr - 1; -} +}; kukit.RequestManager.prototype.isSentRequestQueueFull = function() { return (this.sentNr >= this.maxNr) -} +}; /* request manager notification API */ kukit.RequestManager.prototype.notifyServer = function(func, url) { - // func must be a partial (e.g. use Mochikit or wrap up) - // here url is only for the logging - if (! this.isSentRequestQueueFull()) { - // can be sent if we are not over the limit. - this.pushSentRequest(func, url); - this.log('Notify server at ' + url); - func(); - } else { - this.pushWaitingRequest(func, url); - this.log('Queue server notification at ' + url); - } -} + // func must be a partial (e.g. use Mochikit or wrap up) + // here url is only for the logging + if (! this.isSentRequestQueueFull()) { + // can be sent if we are not over the limit. + this.pushSentRequest(func, url); + this.log('Notify server at ' + url); + func(); + } else { + this.pushWaitingRequest(func, url); + this.log('Queue server notification at ' + url); + } +}; kukit.RequestManager.prototype.receivedResult = function() { - // must be called when one result arrived - // Mark that we have one less request out. - this.popSentRequest(); - if (! this.isWaitingRequestQueueEmpty()) { - // see if we can send another request in place of the received one - // request is waiting, send it. - var waiting = this.popWaitingRequest(); - var func = waiting[0]; - var url = waiting[1]; - this.pushSentRequest(func, url); - this.log("Send queued notification to server at " + url); - func(); - } else { - this.log("Request queue empty."); - } -} + // must be called when one result arrived + // Mark that we have one less request out. + this.popSentRequest(); + if (! this.isWaitingRequestQueueEmpty()) { + // see if we can send another request in place of the received one + // request is waiting, send it. + var waiting = this.popWaitingRequest(); + var func = waiting[0]; + var url = waiting[1]; + this.pushSentRequest(func, url); + this.log("Send queued notification to server at " + url); + func(); + } else { + this.log("Request queue empty."); + } +}; /* simple FIFO queue */ kukit.FifoQueue = function () { this.reset(); -} +}; kukit.FifoQueue.prototype.reset = function() { this.elements = new Array(); -} +}; kukit.FifoQueue.prototype.push = function(obj) { this.elements.push(obj); -} +}; kukit.FifoQueue.prototype.pop = function() { return this.elements.shift(); -} +}; kukit.FifoQueue.prototype.empty = function() { return ! this.elements.length; -} +}; kukit.FifoQueue.prototype.size = function() { return this.elements.length; -} +}; kukit.FifoQueue.prototype.front = function() { return this.elements[0]; -} +}; /* instantiate request manager */ @@ -142,25 +194,22 @@ it's used in CompositePack */ kukit.storedResults = new Array(); -kukit.storeResults = function(results) -{ -kukit.storedResults[kukit.storedResults.length] = results; -} +kukit.storeResults = function(results) { + kukit.storedResults[kukit.storedResults.length] = results; +}; -kukit.getLastResults = function() -{ - var length = kukit.storedResults.length; - if (length != 0) - { - return kukit.storedResults[length-1]; - } -} +kukit.getLastResults = function() { + var length = kukit.storedResults.length; + if (length != 0){ + return kukit.storedResults[length-1]; + } +}; /* end of XXX */ kukit.RuleSheetLink = function(href, res_type) { this.href = href; this.res_type = res_type; -} +}; kukit.getRuleSheetLinks = function() { var nodes = document.getElementsByTagName("link"); @@ -171,15 +220,14 @@ // Resource syntax is decided on type attribute. if((nodes[i].type == 'text/css') || (nodes[i].type == 'text/kss')) { res_type = 'kss'; - } else { // text/xml or nothing (to keep back compatibility) - res_type = 'xml'; } results[results.length] = new kukit.RuleSheetLink(nodes[i].href, res_type); } } return results; -} +}; +kukit.rules = new Array(); kukit.rule_processors = new Array(); kukit.calculateBase = function() { @@ -199,13 +247,13 @@ } else { kukit.base = nodes[0].href; } -} +}; kukit.calculateBase(); // table from res_type to rule processor // we could make this as a registry but no sense at the moment -kukit.ruleProcessorClasses = {} +kukit.ruleProcessorClasses = {}; kukit.initializeRules = function() { var rulelinks = kukit.getRuleSheetLinks(); @@ -223,14 +271,18 @@ } } kukit.setupEvents(); -} +}; -kukit.setupEvents = function(node) { +kukit.setupEvents = function(in_node) { kukit.log("Setting up events"); - for (var i=0; i - if (params.type == 'timeout') { - var p = arg.split(' '); - if (p.length != 2) { - throw "Awaited url and timeout, got: "+arg; - } else { - arg = p[0]; - params.delay = p[1]; - } - } - } else if (property_type != "event") { - throw "Unknown property type ("+property_type+"): must be one of event, kukitevent"; - } - - // Generic action shortcut. If there is no action, a remote - // action is created by default, using the arg. - if (actions.length == 0) { - if (!arg) { - throw 'In case there are no actions, a parameter must be given'; - } - var defparams = {}; - var action = new kukit.Action('remote', [arg], defparams); - actions[actions.length] = action; - } - - result[result.length] = new kukit.EventRule(params.type, selector, [], params, actions); - } - - return result; -} - -kukit.RuleProcessor.prototype.parseAction = function(action_node) { - // parameters and type are in attributes - var params = {}; - var action_attributes = action_node.attributes; - for (var i=0; i typename -} - -kukit.EventTypeRegistry.prototype.register = function(name, func, sig, eventnames) { - if (typeof(func) == 'undefined' || typeof(sig) == 'undefined') { - throw 'Func and sig are mandatory.'; - } - if (typeof(eventnames) == 'undefined') { - eventnames = []; - } - if (this.content[name]) { - // Do not allow redefinition - kukit.logError('Error : redefinition attempt of event setup type ' + name); - return; - } - var entry = {} - entry['func'] = func; - entry['sig'] = sig; - entry['type'] = name; - this.content[name] = entry; - // do the eventnames - for (var i=0; i 1) { - // XXX suppose not <= 2 though... - value = item[1]; - } - // XXX these are encoded. - // I think we would need to decode them, or else... - query.appendElem('kukitHref_' + key, value); - } - } - } -*/ - - return query; -} - -kukit.extractFormData = function(target) { - return kukit.extractFormQuery(target).encode(); -} - /* Server notification */ -kukit.notifyServer = function(url, target) { - kukit.requestManager.notifyServer(partial(kukit.reallyNotifyServer, url, target), url); -} - -kukit.reallyNotifyServer = function(url, target) -{ - // make a deferred callback - var domDoc = new XMLHttpRequest(); - var notifyServer_done = MochiKit.Base.partial(kukit.notifyServer_done, domDoc); - // sending form - var form_data = kukit.extractFormData(target); - var ts = new Date().getTime(); - kukit.logDebug('TS: '+ts); - var tsurl = url + "?kukitTimeStamp=" + ts; - domDoc.open("POST", tsurl, true); - domDoc.onreadystatechange = notifyServer_done; - domDoc.setRequestHeader("Content-Type", "application/x-www-form-urlencoded"); - domDoc.send(form_data); -} - -kukit.notifyServerWithParams = function(url, params) { - kukit.requestManager.notifyServer(partial(kukit.reallyNotifyServerWithParams, url, params), url); -} +kukit.notifyServer = function(url, params) { + var f = function() { + kukit.reallyNotifyServer(url, params); + }; + kukit.requestManager.notifyServer(f, url); +}; -kukit.reallyNotifyServerWithParams = function(url, params) -{ - // make a deferred callback - var domDoc = new XMLHttpRequest(); - notifyServer_done = MochiKit.Base.partial(kukit.notifyServer_done, domDoc); - // convert params - var query = new kukit.FormQuery(); - for (var key in params) { - query.appendElem(key, params[key]); - } - var encoded = query.encode(); - // sending form - var ts = new Date().getTime(); - kukit.logDebug('TS: '+ts); - var tsurl = url + "?kukitTimeStamp=" + ts; - domDoc.open("POST", tsurl, true); - domDoc.onreadystatechange = notifyServer_done; - domDoc.setRequestHeader("Content-Type", "application/x-www-form-urlencoded"); - domDoc.send(encoded); -} +kukit.reallyNotifyServer = function(url, params) { + // make a deferred callback + var domDoc = new XMLHttpRequest(); + var notifyServer_done = function() { + kukit.notifyServer_done(domDoc); + }; + // convert params + var query = new kukit.fo.FormQuery(); + for (var key in params) { + query.appendElem(key, params[key]); + } + var encoded = query.encode(); + // sending form + var ts = new Date().getTime(); + kukit.logDebug('TS: '+ts); + var tsurl = url + "?kukitTimeStamp=" + ts; + domDoc.open("POST", tsurl, true); + domDoc.onreadystatechange = notifyServer_done; + domDoc.setRequestHeader("Content-Type", "application/x-www-form-urlencoded"); + domDoc.send(encoded); +}; -kukit.notifyServer_done = function(domDoc) -{ - if (domDoc.readyState == 4) - { - kukit.processResult(domDoc.responseXML); +kukit.notifyServer_done = function(domDoc) { + if (domDoc.readyState == 4) + { + kukit.processResult(domDoc.responseXML); /* } else { - kukit.logDebug('Request arrived with readyState = ' + domDoc.readyState); */ - } -} + kukit.logDebug('Request arrived with readyState = ' + domDoc.readyState); */ + } +}; -kukit.processResult = function(domDoc) -{ - kukit.requestManager.receivedResult(); - if (!domDoc) - { - kukit.logError('Error : no kukit response'); - return; - } - // Opera <= 8.5 does not have the parseError attribute, so check for it first - if (domDoc.parseError && (domDoc.parseError != 0)) - { - kukit.logError(Sarissa.getParseErrorText(domDoc)); - return; - } - if (domDoc.getElementsByTagNameNS) { - commands = domDoc.getElementsByTagNameNS("http://www.kukit.org/commands/1.0", - "command"); - } else { - //IE does not know DOM2 - commands = domDoc.getElementsByTagName("kukit:command"); - } - if (commands.length == 0) - { - kukit.logWarning('No commands in kukit response'); - return; - } - var command_processor = new kukit.CommandProcessor(); - command_processor.parseCommands(commands); - command_processor.executeCommands(); -} +kukit.processResult = function(domDoc) { + kukit.requestManager.receivedResult(); + if (!domDoc) { + kukit.logError('Error : no kukit response'); + return; + } + // Opera <= 8.5 does not have the parseError attribute, so check for it first + if (domDoc.parseError && (domDoc.parseError != 0)) { + kukit.logError(Sarissa.getParseErrorText(domDoc)); + return; + } + if (domDoc.getElementsByTagNameNS) { + commands = domDoc.getElementsByTagNameNS("http://www.kukit.org/commands/1.0", + "command"); + } else { + //IE does not know DOM2 + commands = domDoc.getElementsByTagName("kukit:command"); + } + if (commands.length == 0) { + kukit.logWarning('No commands in kukit response'); + return; + } + var command_processor = new kukit.CommandProcessor(); + command_processor.parseCommands(commands); + command_processor.executeCommands(); +}; kukit.CommandProcessor = function() { - this.commands = new Array(); -} + this.commands = new Array(); +}; kukit.CommandProcessor.prototype.parseCommands = function(commands) { - kukit.log('Parse commands'); - kukit.logDebug('Number of commands: ' + commands.length); - for (var y=0;y < commands.length;y++) - { - var command = commands[y]; - this.parseCommand(command); - } -} + kukit.log('Parse commands'); + kukit.logDebug('Number of commands: ' + commands.length); + for (var y=0;y < commands.length;y++) { + var command = commands[y]; + this.parseCommand(command); + } +}; kukit.CommandProcessor.prototype.parseCommand = function(command) { var selector = ""; @@ -1022,87 +454,78 @@ selector = command.getAttribute("selector"); if (selector == null) selector = ""; - if (selector) - { + if (selector) { name = command.getAttribute("name"); type = command.getAttribute("selectorType"); if (name == null) name = ""; kukit.log('Command name: '+ name); var childNodes = command.childNodes; - for (var n=0;n < childNodes.length;n++) - { - var childNode = childNodes[n]; - kukit.logDebug('NodeType: '+ childNode.nodeType); - if (childNode.nodeType != 1) - continue; - kukit.logDebug('NodeName: '+ childNode.nodeName); - if (childNode.localName) { - if (childNode.localName.toLowerCase() != "param") - continue; - } else { - //IE does not know DOM2 - if (childNode.nodeName.toLowerCase() != "kukit:param") + for (var n=0;n < childNodes.length;n++) { + var childNode = childNodes[n]; + kukit.logDebug('NodeType: '+ childNode.nodeType); + if (childNode.nodeType != 1) continue; - } - data = childNode.getAttribute('name'); - if (data != null) - { - params[data] = childNode; - has_params = true; - } + kukit.logDebug('NodeName: '+ childNode.nodeName); + if (childNode.localName) { + if (childNode.localName.toLowerCase() != "param") + continue; + } else { + //IE does not know DOM2 + if (childNode.nodeName.toLowerCase() != "kukit:param") + continue; + } + data = childNode.getAttribute('name'); + if (data != null) { + params[data] = childNode; + has_params = true; + } } kukit.log('Command params: '+ has_params); - if (selector != "" && has_params && name != "") - { - var command = new kukit.Command(selector, name, type, params); - this.addCommand(command); + if (selector != "" && has_params && name != "") { + var command = new kukit.Command(selector, name, type, params); + this.addCommand(command); } } -} +}; kukit.CommandProcessor.prototype.addCommand = function(command) { this.commands[this.commands.length] = command; -} +}; -kukit.CommandProcessor.prototype.executeCommands = function() -{ - var commands = this.commands - for (var y=0;y < commands.length;y++) - { - var command = commands[y]; - this.executeCommand(command); - } -} +kukit.CommandProcessor.prototype.executeCommands = function() { + var commands = this.commands + for (var y=0;y < commands.length;y++) { + var command = commands[y]; + this.executeCommand(command); + } +}; -kukit.CommandProcessor.prototype.executeCommand = function(command) -{ - kukit.logDebug('Selector type: '+command.selectorType); - kukit.logDebug('Selector : '+command.selector); - var nodes = kukit.selectors.get(command.selectorType)(command.selector); - var func = null; - if (nodes.length == 0) { - kukit.logError('Command found no nodes'); - } else { - func = kukit.commandRegistry.getFunc(command.name); - } - for (var i=0;i < nodes.length;i++) - { - var node = nodes[i]; - //XXX error handling for wrong command name - kukit.logDebug('Command Name: '+command.name); - var results = func(node, command.params); - kukit.storeResults(results); // XXX see above - } -} +kukit.CommandProcessor.prototype.executeCommand = function(command) { + kukit.logDebug('Selector type: '+command.selectorType); + kukit.logDebug('Selector : '+command.selector); + var nodes = kukit.selectors.get(command.selectorType)(command.selector); + var func = null; + if (nodes.length == 0) { + kukit.logError('Command found no nodes'); + } else { + func = kukit.commandRegistry.getFunc(command.name); + } + for (var i=0;i < nodes.length;i++) { + var node = nodes[i]; + //XXX error handling for wrong command name + kukit.logDebug('Command Name: '+command.name); + var results = func(node, command.params); + kukit.storeResults(results); // XXX see above + } +}; -kukit.Command = function(selector, name, type, params) -{ - this.selector = selector; - this.name = name; - this.selectorType = type; - this.params = params; -} +kukit.Command = function(selector, name, type, params) { + this.selector = selector; + this.name = name; + this.selectorType = type; + this.params = params; +}; /* selector registry */ @@ -1115,14 +538,14 @@ throw 'Func is mandatory.'; } kukit.selectors._mapping[name] = func; -} +}; kukit.selectors.get = function(name) { var result = kukit.selectors._mapping[name]; if (!result && name != 'default') return kukit.selectors.get('default'); return result; -} +}; kukit.selectors.register('htmlid', function(expr, node) { if (!node) @@ -1133,13 +556,13 @@ nodes[nodes.length] = node; kukit.logDebug('HTMLID nodes number: '+nodes.length); return nodes; -}) +}); kukit.selectors.register('css', function(expr, node) { var nodes = cssQuery(expr, node); kukit.logDebug('CSS nodes number: '+nodes.length); return nodes; -}) +}); kukit.selectors.register('xpath', function(expr, node) { if (!node) @@ -1149,29 +572,29 @@ var nodes = xpath_res.nodeSetValue(); kukit.logDebug('XPath nodes number: '+nodes.length); return nodes; -}) +}); -kukit.selectors.register('default', kukit.selectors.get('css')) +kukit.selectors.register('default', kukit.selectors.get('css')); /* general dom helpers */ -kukit.dom = {} +kukit.dom = {}; kukit.dom.getPreviousSiblingTag = function(node) { - var toNode = node.previousSibling; - while ((toNode != null) && (toNode.nodeType != 1)) { - toNode = toNode.previousSibling; - } - return toNode; -} + var toNode = node.previousSibling; + while ((toNode != null) && (toNode.nodeType != 1)) { + toNode = toNode.previousSibling; + } + return toNode; +}; kukit.dom.getNextSiblingTag = function(node) { - var toNode = node.nextSibling; - while ((toNode != null) && (toNode.nodeType != 1)) { - toNode = toNode.nextSibling; - } - return toNode; + var toNode = node.nextSibling; + while ((toNode != null) && (toNode.nodeType != 1)) { + toNode = toNode.nextSibling; + } + return toNode; } kukit.dom.insertBefore = function(nodeFrom, parentNode, nodeTo) { @@ -1181,15 +604,14 @@ if(ownerDoc.importNode && (!_SARISSA_IS_IE)) { for(var i=0;i < nodes.length;i++) { result[i] = parentNode.insertBefore(ownerDoc.importNode(nodes[i], true), nodeTo); - }; - } - else{ + } + } else { for(var i=0;i < nodes.length;i++) { result[i] = parentNode.insertBefore(nodes[i].cloneNode(true), nodeTo); - }; - }; + } + } return result; -} +}; kukit.dom.appendChildren = function(nodes, toNode) { var ownerDoc = toNode.nodeType == Node.DOCUMENT_NODE ? toNode : toNode.ownerDocument; @@ -1197,20 +619,20 @@ if(ownerDoc.importNode && (!_SARISSA_IS_IE)) { for(var i=0;i < nodes.length;i++) { result[i] = toNode.appendChild(ownerDoc.importNode(nodes[i], true)); - }; + } }else{ for(var i=0;i < nodes.length;i++) { result[i] = toNode.appendChild(nodes[i].cloneNode(true)); - }; - }; + } + } return result; -} +}; /* Command registry */ kukit.CommandRegistry = function () { this.content = {}; -} +}; kukit.CommandRegistry.prototype.register = function(name, func) { if (this.content[name]) { @@ -1219,7 +641,7 @@ return; } this.content[name] = func; -} +}; kukit.CommandRegistry.prototype.getFunc = function(name) { var func = this.content[name]; @@ -1228,129 +650,117 @@ kukit.logError('Error : undefined command ' + name); } return func; -} +}; kukit.commandRegistry = new kukit.CommandRegistry(); /* Core commands */ -kukit.commandRegistry.register('setHtmlAsChild', function(node, command_data) -{ +kukit.commandRegistry.register('setHtmlAsChild', function(node, command_data) { var content = document.importNode(command_data['html'], true); Sarissa.clearChildNodes(node); kukit.dom.appendChildren(content.childNodes, node); kukit.setupEvents(node); -}) +}); -kukit.commandRegistry.register('replaceNode', function(node, command_data) - { - var childNodes = command_data['html'].childNodes; - var sourceSelector = command_data['selector'].firstChild.nodeValue || null; - var parentNode = node.parentNode; - var newNode = parentNode.cloneNode(false); - try { - kukit.dom.appendChildren(childNodes, newNode); - } catch(exc) { - newNode.innerHTML = Sarissa.serialize(command_data['html']); - } - if (sourceSelector) { - var element = cssQuery(sourceSelector, newNode)[0]; - if (element) - parentNode.replaceChild(element, node); - else - kukit.logDebug("Found no elements in response with selector '"+sourceSelector+"'."); - } else { - parentNode.replaceChild(newNode.firstChild, node); - } - kukit.setupEvents(parentNode); +kukit.commandRegistry.register('replaceNode', function(node, command_data) { + var childNodes = command_data['html'].childNodes; + var sourceSelector = command_data['selector'].firstChild.nodeValue || null; + var parentNode = node.parentNode; + var newNode = parentNode.cloneNode(false); + try { + kukit.dom.appendChildren(childNodes, newNode); + } catch(exc) { + newNode.innerHTML = Sarissa.serialize(command_data['html']); + } + if (sourceSelector) { + var element = cssQuery(sourceSelector, newNode)[0]; + if (element) + parentNode.replaceChild(element, node); + else + kukit.logDebug("Found no elements in response with selector '"+sourceSelector+"'."); + } else { + parentNode.replaceChild(newNode.firstChild, node); } -) + kukit.setupEvents(parentNode); +}); -kukit.commandRegistry.register('setAttribute', function(node, command_data) -{ - var name = command_data['name'].firstChild.nodeValue; - var value = command_data['value'].firstChild.nodeValue; - node.setAttribute(name, value); -}) +kukit.commandRegistry.register('setAttribute', function(node, command_data) { + var name = command_data['name'].firstChild.nodeValue; + var value = command_data['value'].firstChild.nodeValue; + node.setAttribute(name, value); +}); -kukit.commandRegistry.register('addAfter', function(node, command_data) -{ - var content = document.importNode(command_data['html'], true); - var parentNode = node.parentNode; - var toNode = kukit.dom.getNextSiblingTag(node); - if (toNode == null) { - var inserted = kukit.dom.appendChildren(content.childNodes, parentNode); - } else { - var inserted = kukit.dom.insertBefore(content, parentNode, toNode); - } - // update the events for the new nodes - kukit.logDebug("Inserted nodes length: "+inserted.length); - kukit.setupEvents(node); - return inserted; -}) - -kukit.commandRegistry.register('removeNextSibling', function(node, command_data) -{ - kukit.logDebug('removeNextSibling'); - var parentNode = node.parentNode; - var toNode = kukit.dom.getNextSiblingTag(node); - if (toNode != null) { - parentNode.removeChild(toNode); - } -}) - -kukit.commandRegistry.register('removePreviousSibling', function(node, command_data) -{ - kukit.logDebug('removePreviousSibling'); - var parentNode = node.parentNode; - var toNode = kukit.dom.getPreviousSiblingTag(node); - parentNode.removeChild(toNode); -}) +kukit.commandRegistry.register('addAfter', function(node, command_data) { + var content = document.importNode(command_data['html'], true); + var parentNode = node.parentNode; + var toNode = kukit.dom.getNextSiblingTag(node); + if (toNode == null) { + var inserted = kukit.dom.appendChildren(content.childNodes, parentNode); + } else { + var inserted = kukit.dom.insertBefore(content, parentNode, toNode); + } + // update the events for the new nodes + kukit.logDebug("Inserted nodes length: "+inserted.length); + kukit.setupEvents(node); + return inserted; +}); -kukit.commandRegistry.register('removeNode', function(node, command_data) -{ - var parentNode = node.parentNode; - parentNode.removeChild(node); -}) +kukit.commandRegistry.register('removeNextSibling', function(node, command_data) { + kukit.logDebug('removeNextSibling'); + var parentNode = node.parentNode; + var toNode = kukit.dom.getNextSiblingTag(node); + if (toNode != null) { + parentNode.removeChild(toNode); + } +}); + +kukit.commandRegistry.register('removePreviousSibling', function(node, command_data) { + kukit.logDebug('removePreviousSibling'); + var parentNode = node.parentNode; + var toNode = kukit.dom.getPreviousSiblingTag(node); + parentNode.removeChild(toNode); +}); + +kukit.commandRegistry.register('removeNode', function(node, command_data) { + var parentNode = node.parentNode; + parentNode.removeChild(node); +}); -kukit.commandRegistry.register('clearChildren', function(node, command_data) -{ - Sarissa.clearChildNodes(node); -}) +kukit.commandRegistry.register('clearChildren', function(node, command_data) { + Sarissa.clearChildNodes(node); +}); -kukit.commandRegistry.register('moveNodeAfter', function(node, command_data) -{ - var parentNode = node.parentNode; - parentNode.removeChild(node); +kukit.commandRegistry.register('moveNodeAfter', function(node, command_data) { + var parentNode = node.parentNode; + parentNode.removeChild(node); - var id = command_data['html_id'].firstChild.nodeValue; - var toNode = document.getElementById(id); + var id = command_data['html_id'].firstChild.nodeValue; + var toNode = document.getElementById(id); - var nextNode = kukit.dom.getNextSiblingTag(toNode); - if (nextNode == null) { - toNode.parentNode.appendChild(node); - } else { - parentNode.insertBefore(node, nextNode); - } -}) - -kukit.commandRegistry.register('copyChildrenFrom', function(node, command_data) -{ - var id = command_data['html_id'].firstChild.nodeValue; - var fromNode = document.getElementById(id); - Sarissa.copyChildNodes(fromNode, node); -}) + var nextNode = kukit.dom.getNextSiblingTag(toNode); + if (nextNode == null) { + toNode.parentNode.appendChild(node); + } else { + parentNode.insertBefore(node, nextNode); + } +}); -kukit.commandRegistry.register('copyChildrenTo', function(node, command_data) -{ - var id = command_data['html_id'].firstChild.nodeValue; - toNode = document.getElementById(id); - Sarissa.copyChildNodes(node, toNode); +kukit.commandRegistry.register('copyChildrenFrom', function(node, command_data) { + var id = command_data['html_id'].firstChild.nodeValue; + var fromNode = document.getElementById(id); + Sarissa.copyChildNodes(fromNode, node); +}); + +kukit.commandRegistry.register('copyChildrenTo', function(node, command_data) { + var id = command_data['html_id'].firstChild.nodeValue; + toNode = document.getElementById(id); + Sarissa.copyChildNodes(node, toNode); }) kukit.commandRegistry.register('executeCode', function(node, command_data) { - var code = command_data['code'].firstChild.nodeValue; - node.eval(code); -}) + var code = command_data['code'].firstChild.nodeValue; + node.eval(code); +}); Added: kukit/kukit.js/branch/kss2/kukit/plugin.js ============================================================================== --- (empty file) +++ kukit/kukit.js/branch/kss2/kukit/plugin.js Fri Jun 2 11:27:40 2006 @@ -0,0 +1,203 @@ + +/* Core plugins and utilities */ + +kukit.pl = {}; + +/* Utility for parameter checking */ + +kukit.pl.completeParms = function(parms, mandatory, defaults, errname) { + // Checks if mandatory params are supplied and there are no excess params + // also fill up default values + // Parms are cloned and returned. + // Call example: parms=kukit.pl.completeParms(parms, ['mand1', 'mand2'], {'key1': 'defval'}, 'event X'); + var newparms = {}; + for (var i=0; i__(parms, func_to_bind) +* should be defined to make binding of event to the given function. +* (Return true if binding was successful.) +* +* The event action hooks +* __exec__(name, parms) +* __exec___(parms) +* can be defined to override the default event action. +* (Return true if execution was successful or false if +* chain should be continued.) +* +*/ + +kukit.pl.getTargetForBrowserEvent = function(e) { + // this prevents the handler to be called on wrong elements, which + // can happen because of propagation or bubbling + // XXX this needs to be tested in all browsers + if (!e) var e=window.event; + var target = null; + if (e.target) { + target = e.target; + } else if (e.srcElement) { + target = e.srcElement; + } + /* ??? + if (e.currentTarget) + if (target != e.currentTarget) + target = null;*/ + return target; +}; + + +kukit.pl.NativeEvent = function() { +}; + +kukit.pl.NativeEvent.prototype.__bind__ = function(name, parms, func_to_bind, node) { + parms = kukit.pl.completeParms(parms, [], {}, 'native event binding'); + var func = function(e) { + target = kukit.pl.getTargetForBrowserEvent(e); + if (target == node) { + // Execute the action + func_to_bind(); + } else { + kukit.log('Ignored event for "' + name + '", possibly wrong target'); + } + } + kukit.registerEventListener(node, name, func); + return true; +}; + +kukit.er.eventClassRegistry.register('native', kukit.pl.NativeEvent); + +// Timer events. The binding of this event will start one counter +// per event rule. No matter how many nodes matched it. +// The timer will tick for ever (i.e. won't stop +// even if the binding nodes are all deleted) + +kukit.pl.TimerCounter = function(delay, func) { + this.delay = delay; + this.func = func; +}; + +kukit.pl.TimerCounter.prototype.start = function() { + var self = this; + var func = function() { + self.timeout(); + } + setTimeout(func, this.delay); +}; + +kukit.pl.TimerCounter.prototype.timeout = function() { + // Call the event action + this.func(); + // Restart the timer + this.start(); +}; + +kukit.pl.TimeoutEvent = function() { + this.counters = {}; +}; + +kukit.pl.TimeoutEvent.prototype.__bind_timeout__ = function(parms, func_to_bind, node, eventrule) { + parms = kukit.pl.completeParms(parms, ['delay'], {}, 'timeout event binding'); + var key = eventrule.getNr(); + if (this.counters[key]) { + // Don't bind the counter if we matched this eventrule already + kukit.logDebug('timer event key ignored for actionEvent #' + key + ' ' + + eventrule.selector); + } else { + kukit.logDebug('timer event key entered for actionEvent #' + key + ' ' + + eventrule.selector); + var counter = new kukit.pl.TimerCounter(parms.delay, func_to_bind) + this.counters[key] = counter; + // Start the counter + counter.start(); + } + // Success in any case. + return true; +}; + +kukit.er.eventClassRegistry.register('timeout', kukit.pl.TimeoutEvent); + +// CancelSubmitClick. This is a mutated version of +// the browser click event. + +kukit.pl.CancelSubmitClickEvent = function() { +}; + +kukit.pl.CancelSubmitClickEvent.prototype.__bind_cancelSubmitClick__ = function(parms, func_to_bind, node) { + parms = kukit.pl.completeParms(parms, [], {}, 'cancelSubmitClick event binding'); + var func = function(e) { + target = kukit.pl.getTargetForBrowserEvent(e); + if (target == node) { + // Execute the action + func_to_bind(); + } else { + kukit.log('Ignored event for "' + name + '", possibly wrong target') + } + // Cancel default event + // W3C style + if (e.preventDefault) + e.preventDefault(); + // MS style + try { e.returnValue = false; } catch (exc) {} + } + kukit.registerEventListener(node, 'click', func); + return true; +}; + +kukit.er.eventClassRegistry.register('cancelSubmitClick', kukit.pl.CancelSubmitClickEvent); + + +/* Core actions +* +* The core local actions that can be executed on the client +* side. +*/ + + + +kukit.ar.eventActionRegistry.register("logDebug", function (node, parms, eventrule) { + parms = kukit.pl.completeParms(parms, [], {'message': 'Logging from Event'}, 'logDebug action'); + kukit.logDebug(parms.message + ', rule=#' + eventrule.getNr() + ', node=' + node.nodeName); + } +); + +kukit.ar.eventActionRegistry.register("log", function (node, parms, eventrule) { + parms = kukit.pl.completeParms(parms, [], {'message': 'Logging from Event'}, 'log action'); + kukit.log(parms.message + ', rule=#' + eventrule.getNr() + ', node=' + node.nodeName); + } +); + +kukit.ar.eventActionRegistry.register("alert", function (node, parms, eventrule) { + parms = kukit.pl.completeParms(parms, [], {'message': 'Logging from Event'}, 'alert action'); + alert(parms.message + ', rule=#' + eventrule.getNr() + ', node=' + node.nodeName); + } +); + Added: kukit/kukit.js/branch/kss2/kukit/resourcedata.js ============================================================================== --- (empty file) +++ kukit/kukit.js/branch/kss2/kukit/resourcedata.js Fri Jun 2 11:27:40 2006 @@ -0,0 +1,377 @@ + +/* Supplemental data that the parser builds up */ + +kukit.rd = {}; + +kukit.rd.KssSelector = function(isEvent, css, name, klass, id) { + this.isEventSelector = isEvent; + this.isMethodSelector = ! isEvent; + if (! name) { + throw 'KssSelector must have name'; + } + if (! isEvent) { + // method rule + if (css != null) { + throw 'KssMethodSelector must have css=null'; + } + if (klass != null && id != null || klass == null && id == null) { + throw 'KssMethodSelector "' + name + '" must have either class or id, but not both'; + } + } + this.css = css; + this.name = name; + this.klass = klass; + this.id = id; +}; + +kukit.rd.KssSelector.prototype.setIdAndClass = function() { + // Sets up id and class on the selector, based on registration info + if (this.isEventSelector) { + // event rule + // fill up values for class, id + if (this.klass == null) { + // try: same as name, if that is in the registry. + if (kukit.er.eventClassRegistry.exists(this.name)) { + this.klass = this.name; + } else { + // else, use "native" + this.klass = 'native'; + } + } + if (this.id == null) { + // singleton for class + this.id = '__' + this.klass; + } + } +}; + +/* +* Kss parameter values. There are two kinds: text and method. +* +* They are evaluated in two phases: check is invoked at parsing, +* allowing the early detection of errors. Evaluate is called +* when the action is to be called. This allows a kss method +* to add any parameter to the action. +*/ + +kukit.rd.KssTextValue = function(txt) { + // A text parameter in the format + // key: value; + this.txt = txt; +}; +kukit.rd.KssTextValue.prototype.isMethod = false; +kukit.rd.KssTextValue.prototype.check = function() { +}; +kukit.rd.KssTextValue.prototype.evaluate = function(parms, key) { + parms[key] = this.txt; +}; + +kukit.rd.KssMethodValue = function(methodname, args) { + // A method parameter in the format + // key: methodname(v1, v2, ... vn); + this.methodname = methodname; + this.args = args; +}; +kukit.rd.KssMethodValue.prototype.isMethod = true; +kukit.rd.KssMethodValue.prototype.check = function() { + // Check syntax + switch (this.methodname) { + case 'formvar': { + if (this.args.length != 2) { + throw 'formvar method needs 2 arguments (formname, varname)'; + } + } break; + case 'currentformvar': { + if (this.args.length != 1) { + throw 'currentformvar method needs 1 argument (varname)'; + } + } break; + case 'nodeattr': { + if (this.args.length != 1) { + throw 'nodeattr method needs 1 argument (attrname)'; + } + } break; + default: { + throw 'Not implemented kss parameter method "' + this.methodname + '"'; + } break; + } +}; +kukit.rd.KssMethodValue.prototype.evaluate = function(parms, key, node) { + // Evaluate into parms. + switch (this.methodname) { + case 'formvar': { + parms[key] = kukit.fo.getFormVarFromNamedForm(this.args[0], this.args[1]); + } break; + case 'currentformvar': { + parms[key] = kukit.fo.getFormVarFromCurrentForm(node, this.args[0]); + } break; + case 'nodeattr': { + var argname = this.args[0]; + // XXX this works but not for kukit:xxx args + var value = node[argname]; + // XXX this might have problems with certain attrs on IE, and completely broke on Opera + //var value = node.getAttribute(argname); + if (typeof(value) == 'undefined') { + // notfound arguments will get null + value = null; + } + parms[key] = value; + } break; + default: { + throw 'Ignored kss parameter method.'; + } break; + } +}; + + +kukit.rd.EventRuleNr = 0; // just a counter + +kukit.rd.EventRule = function(kss_selector, parms, action) { + if (typeof(parms) == 'undefined') { + // called for merging clone + this.kss_selector = kss_selector; + } else { + this.nr = kukit.rd.EventRuleNr; + this.mergednr = null; + kukit.rd.EventRuleNr = this.nr + 1; + kukit.logDebug("EventRule #" + this.nr + ": " + kss_selector.css); + this.kss_selector = kss_selector; + this.parms = parms; + this.action = action; + } +}; + +kukit.rd.EventRule.prototype.getNr = function() { + if (this.mergednr) { + return this.mergednr; + } else { + return this.nr; + } +}; + +kukit.rd.EventRule.prototype.mergeForSelectedNodes = function(ruletable, in_node) { + // Select all nodes within the in_node. (or null) + // Merge itself to the selected nodes. + if (this.kss_selector.isEventSelector) { + // XXX this might need to be changed to a global match and only applying + // to nodes inside the given one + var nodes = cssQuery(this.kss_selector.css, in_node); + for (var y=0; y < nodes.length; y++) + { + ruletable.add(nodes[y], this); + } + } +}; + +kukit.rd.EventRule.prototype.getEventInstance = function() { + // Gets the event instance for the rule. + return kukit.er.eventInstanceRegistry.getOrCreateEvent(this.kss_selector.id, this.kss_selector.klass); +}; + +/* +* bind(node) : calls binder hook on event instance. +* These hooks are tried in order, if succeeds it must return true: +* +* __bind__(name, parms, func_to_bind, node, eventrule) +* __bind___(parms, func_to_bind, node, eventrule) +* +* If none succeeds is an error. +* +*/ + +kukit.rd.EventRule.prototype.bind = function(node) { + var eventinstance = this.getEventInstance(); + var name = this.kss_selector.name; + var parms = this.parms; + var method = eventinstance['__bind_' + name + '__']; + var self = this; + var func_to_bind = function(evt) { + self.trigger_event(node, eventinstance); + } + var retstat = false; + if (typeof(method) != 'undefined') { + retstat = method.call(eventinstance, parms, func_to_bind, node, this); + } + if (! retstat) { + method = eventinstance.__bind__; + if (typeof(method) != 'undefined') { + retstat = method.call(eventinstance, name, parms, func_to_bind, node, this); + } + if (! retstat) { + // An error. + throw 'Could not bind event name "' + name + '" on class "' + this.kss_selector.klass + '"'; + } + } +}; + +/* +* trigger_event(node, eventinstance) : calls event trigger hook on event instance. +* These hooks are tried in order, if succeeds it must return true: +* +* __exec__(name, parms) +* __exec___(parms) +* <> +* +* One of them executes in each case. +* +*/ + +kukit.rd.EventRule.prototype.trigger_event = function(node, eventinstance) { + var name = this.kss_selector.name; + var parms = this.getActionParms(node); + var method = eventinstance['__exec_' + name + '__']; + var retstat = false; + if (typeof(method) != 'undefined') { + retstat = method.call(eventinstance, parms); + } + if (! retstat) { + method = eventinstance.__exec__; + if (typeof(method) != 'undefined') { + retstat = method.call(eventinstance, name, parms); + } + if (! retstat) { + // execute the action! + this.action.execute(parms, node, this); + } + } +}; + +kukit.rd.EventRule.prototype.getActionParms = function(node) { + // Return the completed action parameters, based on the node + var parms = {}; + for (var key in this.action.parms) { + var kssvalue = this.action.parms[key]; + // evaluate the method parameters into parms + kssvalue.evaluate(parms, key, node); + } + return parms; +}; + +// +// Merging event rules +// + +kukit.rd.EventRule.prototype.isMerged = function() { + return (this.mergednr != null); +}; + +kukit.rd.EventRule.prototype.cloneForMerge = function() { + // Do not touch ourselves, make a new copy for the merge. + var merged = new kukit.rd.EventRule(this.kss_selector); + merged.action = new kukit.rd.Action(null, null, {}); + merged.parms = {}; + merged.mergednr = 'X'; + merged.merge(this); + merged.mergednr = this.getNr(); + return merged; +}; + +kukit.rd.EventRule.prototype.merge = function(other) { + if (! this.isMerged()) { + throw "Cannot merge into a genuine event rule"; + } + if (this.kss_selector.id != other.kss_selector.id) { + throw "Differing kss selector ids in event rule merge"; + } + if (this.kss_selector.klass != other.kss_selector.klass) { + throw "Differing kss selector classes in event rule merge"; + } + this.mergednr = this.mergednr + ',' + other.getNr(); + for (var key in other.parms) { + this.parms[key] = other.parms[key]; + } + this.action.merge(other.action); +}; + +kukit.rd.Action = function(name, error, parms) { + this.name = name; + this.error = error; + this.parms = parms; +}; + +kukit.rd.Action.prototype.merge = function(other) { + // Merge to the instance. + this.name = other.name; + this.error = other.error; + for (var key in other.parms) { + this.parms[key] = other.parms[key]; + } +}; + +kukit.rd.Action.prototype.execute = function(parms, node, eventrule) { + // If there exists this name, it will be local; otherwise remote. + if (kukit.ar.eventActionRegistry.exists(this.name)) { + // Local action. + var func = kukit.ar.eventActionRegistry.get(this.name); + func(node, parms, eventrule); + } else { + // Remote action. + var action = kukit.calculateAbsoluteURL(this.name); + kukit.notifyServer(action, parms); + } +}; + +/* Rule table + + Used for binding rules to nodes, and handling the merges. + It is a two level dictionary. + + There are more rules that match a given node and event id. + They will be merged appropriately. The event id is also + important. The event class must be the same with merge + rules (within the id). +*/ + +kukit.rd.RuleTable = function() { + this.nodes = {} +}; + +kukit.rd.RuleTable.prototype.add = function(node, eventrule) { + // look up node + var nodehash = kukit.rd.hashnode(node); + var nodeval = this.nodes[nodehash]; + if (typeof(nodeval) == 'undefined') { + nodeval = {'node': node, 'val': {}}; + this.nodes[nodehash] = nodeval; + } + // look up id + var mergedrule = nodeval.val[eventrule.kss_selector.id]; + if (typeof(mergedrule) == 'undefined') { + nodeval.val[eventrule.kss_selector.id] = eventrule; + } else { + if (! mergedrule.isMerged()) { + // Make sure genuine instances are replaced + mergedrule = mergedrule.cloneForMerge(); + nodeval.val[eventrule.kss_selector.id] = mergedrule; + } + mergedrule.merge(eventrule); + } +}; + +kukit.rd.RuleTable.prototype.bindall = function() { + // Bind all nodes + for (var nodehash in this.nodes) { + var nodeval = this.nodes[nodehash]; + for (var id in nodeval.val) { + var eventrule = nodeval.val[id]; + eventrule.bind(nodeval.node); + } + } +}; + +kukit.rd.uid = 0; + +kukit.rd.hashnode = function(node) { + // It is, generally, not possible to use a node as a key. + // However we try to set this right. + // We generate an uniqueID on the node. This does not work + // on MSIE but it already has an uniqueID. + // XXX Konqueror? Other browsers? + var id = node.uniqueID; + if (typeof(id) == 'undefined') { + id = kukit.rd.uid; + node.uniqueID = id; + kukit.rd.uid ++; + } + return id; +}; Added: kukit/kukit.js/branch/kss2/kukit/tokenizer.js ============================================================================== --- (empty file) +++ kukit/kukit.js/branch/kss2/kukit/tokenizer.js Fri Jun 2 11:27:40 2006 @@ -0,0 +1,196 @@ + +/* Simple but effective tokenizing parser engine */ + +kukit.tk = {}; +kukit.tk.ParsingError = kukit.exceptionFactory('ParsingError'); +kukit.tk.ParsingError.prototype.__superinit__ = kukit.tk.ParsingError.prototype.__init__; +kukit.tk.ParsingError.prototype.__init__ = function(name, message, errpos) { + var kw = this.__superinit__(name, message); + kw.errpos = errpos; + kw.message = kw.message + ' at position ' + errpos; + return kw +}; + +/* Class methods of tokens and parsers */ + +kukit.tk._TokenBase = function() { +}; + +kukit.tk._TokenBase.prototype.emitError = function(txt) { + throw new kukit.tk.ParsingError(txt, this.src.pos); +}; + +kukit.tk._TokenBase.prototype.setSrcStatus = function(eofOk) { + if (! this.finished && this.src.text.length == this.src.pos) { + if (eofOk) { + this.finished = true; + } else { + this.emitError('Unexpected EOF'); + } + } +}; + + +kukit.tk._ParserBase = function() { +}; + +kukit.tk._ParserBase.prototype = new kukit.tk._TokenBase; + +kukit.tk._ParserBase.prototype.emitAndReturn = function(token) { + // handle return to the next level + this.finished = true; + return token; +}; + +kukit.tk._ParserBase.prototype.nextStep = function(table) { + var src = this.src; + // Search for symbol according to table. + var best_pos = src.text.length; + var best_symbol = null; + for (var symbol in table) { + var pos = src.text.indexOf(symbol, src.pos); + if (pos != -1 && pos < best_pos) { + best_pos = pos; + best_symbol = symbol; + } + } + // eat up till the symbol found (of EOF) + if (best_pos > src.pos) { + this.result.push(new kukit.tk.Fraction(src.text.substring(src.pos, best_pos))); + src.pos = best_pos; + } + // handle cursor point + if (best_symbol) { + // found a symbol, handle that + // make the token and push it + var tokens = eval(table[best_symbol]); + if (typeof(tokens) != 'undefined') { + if (typeof(tokens.length) == 'undefined') { + tokens = [tokens]; + } + for (var i=0; i= this.result.length) { + this.emitError('Expected [' + symbol + ']'); + } else if (this.result[i].symbol != symbol) { + this.emitError('Expected [' + symbol + '], found [' + this.result[i].symbol + ']'); + } + } else { + if (i >= this.result.length) { + this.emitError('Expected token'); + } + } + cursor.token = this.result[i]; + cursor.next += 1; +}; + +kukit.tk._ParserBase.prototype.ifToken = function(cursor, token1, token2, token3, token4) { + var i = cursor.next; + return (! (i >= this.result.length || this.result[i].symbol != token1.prototype.symbol + && (!token2 || this.result[i].symbol != token2.prototype.symbol + && (!token3 || this.result[i].symbol != token3.prototype.symbol + && (!token4 || this.result[i].symbol != token4.prototype.symbol))))); +}; + +kukit.tk._ParserBase.prototype.digestTxt = function(cursor, token1, token2, token3, token4) { + // digests the txt from the tokens, ignores given token + // returns txt and next index + var result = ''; + while (this.ifToken(cursor, token1, token2, token3, token4)) { + result += this.result[cursor.next].txt; + cursor.next ++; + } + cursor.txt = this.dewhitespaceAndTrim(result); +}; + +kukit.tk._ParserBase.prototype.dewhitespace = function(txt) { + // removes ws but leaves leading and trailing one + if (txt != ' ') { //speedup only + txt = txt.replace(/(\r|\n|\t| )+/g, ' '); + } + return txt; +}; + +kukit.tk._ParserBase.prototype.dewhitespaceAndTrim = function(txt) { + txt = this.dewhitespace(txt); + txt = txt.replace(/^ /, ''); + txt = txt.replace(/ $/, ''); + return txt; +}; + +kukit.tk.Fraction = function(txt) { + this.txt = txt; + this.finished = true; +}; +kukit.tk.Fraction.prototype.symbol = 'fraction'; + + +/* Factories to make tokens and parsers */ + +kukit.tk.mkToken = function(symbol, txt) { + // Poor man's subclassing. + f = function(src) { + this.src = src; + if (src.text.substr(src.pos, txt.length) != txt) { + this.emitError('Expected "' + txt + '", found "' + src.text.substr(src.pos, txt.length) + '"'); + } else { + src.pos += txt.length; + this.finished = true; + } + this.src = null; + } + f.prototype = new kukit.tk._TokenBase; + f.prototype.symbol = symbol; + f.prototype.txt = txt; + return f; +}; + +kukit.tk.mkParser = function(symbol, table) { + // Poor man's subclassing. + f = function(src, tokenClass, eofOk) { + this.src = src; + this.finished = false; + this.result = []; + if (tokenClass) { + // Reentry with starting token propagated. + this.result.push(new tokenClass(this.src)); + } + this.setSrcStatus(eofOk); + while (!this.finished) { + this.nextStep(table); + this.setSrcStatus(eofOk); + } + // post processing + this.process(); + this.src = null; + } + f.prototype = new kukit.tk._ParserBase; + f.prototype.symbol = symbol; + return f; +}; + +kukit.tk.Cursor = function(txt) { + this.text = txt; + this.pos = 0; + this.errtxt = null; + this.errpos = null; +}; Deleted: /kukit/kukit.js/branch/kss2/tests/kukit.BsParserTestCase.js ============================================================================== --- /kukit/kukit.js/branch/kss2/tests/kukit.BsParserTestCase.js Fri Jun 2 11:27:40 2006 +++ (empty file) @@ -1,264 +0,0 @@ -if (typeof(kukit) == "undefined") { - var kukit = {}; -} -kukit.BsParserTestCase = function() { - this.name = 'kukit.BsParserTestCase'; - - this.setUp = function() { - /* not in use here, didn't have to define it but this might be - used as a reference - */ - }; - - this.testEmptyRule = function() { - var src = "#noneselector {}"; - var rules = kukit.BsParser.parse(src); - this.assertFalse("#noneselector" in rules) - }; - - this.testIdRule = function() { - var src = "#idselector {\n key: value; \n}\n"; - var rules = kukit.BsParser.parse(src); - this.assertTrue("#idselector" in rules); - } - - this.testSeveralSelectorRule = function() { - var src = "#noneselector {}\n\n#idselector {\n key: value; \n}\n"; - var rules = kukit.BsParser.parse(src); - this.assertFalse("#noneselector" in rules) - this.assertTrue("#idselector" in rules); - } - - this.testClassSelectorRule = function() { - var src = "#noneselector {}\n\n.classselector \n{key:value;}\n"; - var rules = kukit.BsParser.parse(src); - this.assertFalse("#noneselector" in rules); - this.assertTrue(".classselector" in rules); - } - - this.testTagSelectorRule = function() { - var src = "tagselector{\n /* comment */\n key:value;\n}\n"; - var rules = kukit.BsParser.parse(src); - this.assertTrue("tagselector" in rules); - } - - this.testComments = function() { - var src = "tag{\n /* comment\\*/key2:value; */\n key:value;\n}\n\n/* comment outside */\n"; - var rules = kukit.BsParser.parse(src); - this.assertTrue("tag" in rules); - this.assertEquals(rules["tag"].properties["key"][0], "value"); - this.assertFalse("key2" in rules["tag"].properties); - } - - this.testMultilineComments = function() { - var src = "/* multi\n line\n comment */tag { key: value }"; - var rules = kukit.BsParser.parse(src); - this.assertTrue("tag" in rules); - this.assertEquals(rules["tag"].properties["key"][0], "value"); - } - - this.testValidTagInComment = function() { - var src = "/*\n #commented-id {\n }\n*/"; - var rules = kukit.BsParser.parse(src); - this.assertFalse("#commented-id" in rules); - } - - this.testEmptyComment = function() { - var src = "tag/**/ {key:value}"; - var rules = kukit.BsParser.parse(src); - this.assertTrue("tag" in rules); - } - - this.testComplexComments = function() { - var src = "#property-id {\n key1: value1;\n key2 :value2 ; key3:value3;key4:/*comment*/value4;\n key5/*comment*/:value5;\n/*}*/\n key6/*fun:*/:value/*;*/6;\n}"; - var rules = kukit.BsParser.parse(src); - var properties = rules["#property-id"].properties; - for (var i in properties) { - switch (i) { - case "key1": - this.assertEquals(properties[i][0], "value1"); - break; - case "key2": - this.assertEquals(properties[i][0], "value2"); - break; - case "key3": - this.assertEquals(properties[i][0], "value3"); - break; - case "key4": - this.assertEquals(properties[i][0], "value4"); - break; - case "key5": - this.assertEquals(properties[i][0], "value5"); - break; - case "key6": - this.assertEquals(properties[i][0], "value6"); - break; - default: - print("FAIL: unexpected property found: "+i); - } - } - } - - this.testParameterResetting = function() { - var src = ".class2 {\n key: value-old;\n key: value-new;\n}"; - var rules = kukit.BsParser.parse(src); - this.assertEquals(rules[".class2"].properties["key"][0], "value-new"); - } - - this.testMultipleSelectors = function() { - var src = "#id1, .class6, tag {\n key: value;\n}"; - var rules = kukit.BsParser.parse(src); - this.assertEquals(rules["#id1"].properties["key"][0], "value"); - this.assertEquals(rules[".class6"].properties["key"][0], "value"); - this.assertEquals(rules["tag"].properties["key"][0], "value"); - } - - this.testSpaceSeperatedSelectors = function() { - var src = "tag .class7 {\n key: value;\n}"; - var rules = kukit.BsParser.parse(src); - this.assertTrue("tag .class7" in rules); - } - - this.testReturnSeperatedSelectors = function() { - var src = "tag.class8,\n#id1 { key:value; }"; - var rules = kukit.BsParser.parse(src); - this.assertEquals(rules["tag.class8"].properties["key"][0], "value"); - this.assertEquals(rules["#id1"].properties["key"][0], "value"); - } - - this.testReturnSeperatedSelectors = function() { - var src = "tag.class9\n,\n#id2\n{ key:value; }"; - var rules = kukit.BsParser.parse(src); - this.assertEquals(rules["tag.class9"].properties["key"][0], "value"); - this.assertEquals(rules["#id2"].properties["key"][0], "value"); - } - - this.testMultipleDeclarationsSelectors = function() { - var src = "tag {key1:value1}\ntag{key2:value2}"; - var rules = kukit.BsParser.parse(src); - this.assertEquals(rules["tag"].properties["key1"][0], "value1"); - this.assertEquals(rules["tag"].properties["key2"][0], "value2"); - } - - this.testMulitpleDeclarationsAndMultipleSelectors = function() { - var src = "tag, anotherTag{key1:value1}\ntag{key2:value2}"; - var rules = kukit.BsParser.parse(src); - this.assertEquals(rules["tag"].properties["key1"][0], "value1"); - this.assertEquals(rules["anotherTag"].properties["key1"][0], "value1"); - this.assertEquals(rules["tag"].properties["key2"][0], "value2"); - this.assertFalse("key2" in rules["anotherTag"]); - } - - this.testMultipleValues = function() { - var src = "tag{key:value1 value2;}"; - var rules = kukit.BsParser.parse(src); - this.assertEquals(rules["tag"].properties["key"][0], "value1"); - this.assertEquals(rules["tag"].properties["key"][1], "value2"); - } - - this.testStringValue = function() { - var src = "tag{key:\"value1 is big\";}"; - var rules = kukit.BsParser.parse(src); - this.assertEquals(rules["tag"].properties["key"][0], "value1 is big"); - } - - this.testCommentedStringValue = function() { - var src = "tag{key:\"value1 /* is bi*/g\";}"; - var rules = kukit.BsParser.parse(src); - this.assertEquals(rules["tag"].properties["key"][0], "value1 /* is bi*/g"); - } - - this.testMultipleStringValues = function() { - var src = "tag{key:\"value1 is big\" value2;}"; - var rules = kukit.BsParser.parse(src); - this.assertEquals(rules["tag"].properties["key"][0], "value1 is big"); - this.assertEquals(rules["tag"].properties["key"][1], "value2"); - } - - this.testEmptyValueParameters = function() { - var src = "tag{key:value1();}"; - var rules = kukit.BsParser.parse(src); - this.assertEquals(rules["tag"].properties["key"][0][0], "value1"); - } - - this.testFilledValueParameters = function() { - var src = "tag{key:value1(temp1, temp2, temp3) value2;}"; - var rules = kukit.BsParser.parse(src); - this.assertEquals(rules["tag"].properties["key"][0][0], "value1"); - this.assertEquals(rules["tag"].properties["key"][0][1], "temp1"); - this.assertEquals(rules["tag"].properties["key"][0][2], "temp2"); - this.assertEquals(rules["tag"].properties["key"][1], "value2"); - } - - this.testNumberValue = function() { - var src = "tag{key:1}"; - var rules = kukit.BsParser.parse(src); - this.assertEquals(rules["tag"].properties["key"][0], 1); - } - - // XXX TODO Tests for method parsing? - // these are tested in the Kss parser, but... - - this.testTimeoutParsing = function() { - var src = "#calendar-previous a:click(cancelSubmit=True) {\n" - +" remote: kukitresponse/kukitGetPreviousMonth;\n" - +"}\n" - +"div#update-area:timeout(millis=2000) {\n" - +" effect: fade; \n" - +" remote: getCurrentTime;\n" - +"}\n" - +"#calendar-previous a:leave(cancelSubmit=True) {\n" - +" remote: kukitresponse/kukitPreviousMonth;\n" - +"}\n" - +"button#change:startdrag {\n remote: getDivContent(fgh, foo=bar) getSlowOne(fgd);\n log: \"WE LOG from getDivContent\";}"; - var rules = kukit.BsParser.parse(src); - this.assertEquals(rules["#calendar-previous a:click(cancelSubmit=True)"].type.name, "click"); - this.assertEquals(rules["#calendar-previous a:click(cancelSubmit=True)"].type.properties.length, 1); - this.assertEquals(rules["#calendar-previous a:click(cancelSubmit=True)"].type.properties[0], "cancelSubmit=True"); - this.assertEquals(rules["#calendar-previous a:click(cancelSubmit=True)"].properties["remote"].length, 1); - // this can be read by both as a string or an array of strings but we prefer the second one. - /* Depr' */ this.assertEquals(rules["#calendar-previous a:click(cancelSubmit=True)"].properties["remote"][0], "kukitresponse/kukitGetPreviousMonth"); - this.assertEquals(rules["#calendar-previous a:click(cancelSubmit=True)"].properties["remote"][0].length, 1); - this.assertEquals(rules["#calendar-previous a:click(cancelSubmit=True)"].properties["remote"][0][0], "kukitresponse/kukitGetPreviousMonth"); - this.assertEquals(rules["div#update-area:timeout(millis=2000)"].type.name, "timeout"); - this.assertEquals(rules["div#update-area:timeout(millis=2000)"].type.properties[0], "millis=2000"); - this.assertEquals(rules["div#update-area:timeout(millis=2000)"].type.properties.length, 1); - this.assertEquals(rules["div#update-area:timeout(millis=2000)"].properties["effect"].length, 1); - /* Depr' */ this.assertEquals(rules["div#update-area:timeout(millis=2000)"].properties["effect"][0], "fade"); - this.assertEquals(rules["div#update-area:timeout(millis=2000)"].properties["effect"][0].length, 1); - this.assertEquals(rules["div#update-area:timeout(millis=2000)"].properties["effect"][0][0], "fade"); - this.assertEquals(rules["div#update-area:timeout(millis=2000)"].properties["remote"].length, 1); - /* Depr' */ this.assertEquals(rules["div#update-area:timeout(millis=2000)"].properties["remote"][0], "getCurrentTime"); - this.assertEquals(rules["div#update-area:timeout(millis=2000)"].properties["remote"][0].length, 1); - this.assertEquals(rules["div#update-area:timeout(millis=2000)"].properties["remote"][0][0], "getCurrentTime"); - this.assertEquals(rules["#calendar-previous a:leave(cancelSubmit=True)"].type.name, "leave"); - this.assertEquals(rules["#calendar-previous a:leave(cancelSubmit=True)"].type.properties.length, 1); - this.assertEquals(rules["#calendar-previous a:leave(cancelSubmit=True)"].type.properties[0], "cancelSubmit=True"); - this.assertEquals(rules["#calendar-previous a:leave(cancelSubmit=True)"].properties["remote"].length, 1); - /* Depr' */ this.assertEquals(rules["#calendar-previous a:leave(cancelSubmit=True)"].properties["remote"][0], "kukitresponse/kukitPreviousMonth"); - this.assertEquals(rules["#calendar-previous a:leave(cancelSubmit=True)"].properties["remote"][0].length, 1); - this.assertEquals(rules["#calendar-previous a:leave(cancelSubmit=True)"].properties["remote"][0][0], "kukitresponse/kukitPreviousMonth"); - this.assertEquals(rules["button#change:startdrag()"].type.name, "startdrag"); - this.assertEquals(rules["button#change:startdrag()"].type.properties.length, 0); - this.assertEquals(rules["button#change:startdrag()"].properties["remote"].length, 2); - this.assertEquals(rules["button#change:startdrag()"].properties["remote"][0].length, 3); - this.assertEquals(rules["button#change:startdrag()"].properties["remote"][0][0], "getDivContent"); - this.assertEquals(rules["button#change:startdrag()"].properties["remote"][0][1], "fgh"); - this.assertEquals(rules["button#change:startdrag()"].properties["remote"][0][2], "foo=bar"); - this.assertEquals(rules["button#change:startdrag()"].properties["remote"][1].length, 2); - this.assertEquals(rules["button#change:startdrag()"].properties["remote"][1][0], "getSlowOne"); - this.assertEquals(rules["button#change:startdrag()"].properties["remote"][1][1], "fgd"); - this.assertEquals(rules["button#change:startdrag()"].properties["log"].length, 1); - /* Depr' */ this.assertEquals(rules["button#change:startdrag()"].properties["log"][0], "WE LOG from getDivContent"); - this.assertEquals(rules["button#change:startdrag()"].properties["log"][0].length, 1); - /* XXX this is very important. Currently I hacked the parser in an unacceptable way to achieve this. */ - this.assertEquals(rules["button#change:startdrag()"].properties["log"][0][0], "WE LOG from getDivContent"); - } - -}; - -kukit.BsParserTestCase.prototype = new TestCase; - -if (typeof(testcase_registry) != 'undefined') { - testcase_registry.registerTestCase(kukit.BsParserTestCase, 'kukit.BSParserTestCase'); -} Deleted: /kukit/kukit.js/branch/kss2/tests/kukit.KssParserTestCase.js ============================================================================== --- /kukit/kukit.js/branch/kss2/tests/kukit.KssParserTestCase.js Fri Jun 2 11:27:40 2006 +++ (empty file) @@ -1,143 +0,0 @@ -if (typeof(kukit) == "undefined") { - var kukit = {}; -} - -kukit.KssParserTestCase = function() { - this.name = 'kukit.KssParserTestCase'; - - this.setUp = function() { - /* not in use here, didn't have to define it but this might be - used as a reference - */ - }; - - this.assertDictEquals = function(a, b) { - for (var key in a) { - this.assertNotEquals(typeof(b[key]), 'undefined', 'key ' + key + ' missing from dict 2'); - this.assertEquals(a[key], b[key], 'mismatch at key ' + key); - } - for (var key in b) { - this.assertNotEquals(typeof(a[key]), 'undefined', 'key ' + key + ' missing from dict 1'); - this.assertEquals(a[key], b[key], 'mismatch at key ' + key); - } - } - - this.testParmConverter = function() { - // Basic case. - var pc = new kukit.ParmConverter(['aaa', 'bbb', 'ccc=ddd', 'eee=fff']); - this.assertEquals(pc.args, ['aaa', 'bbb']); - this.assertDictEquals(pc.kw, {'ccc': 'ddd', 'eee': 'fff'}); - // Args cannot follow keywords. - this.assertThrows(kukit.ParmConverter, 'Args cannot follow keywords.', null, ['aaa', 'bbb', 'ccc=ddd', 'eee']); - // XXX Should be supported. - //var pc = new kukit.ParmConverter(['aaa', 'bbb', 'ccc="ddd"', 'eee="fff"']); - //this.assertEquals(pc.args, ['aaa', 'bbb']); - //this.assertDictEquals(pc.kw, {'ccc': 'ddd', 'eee': 'fff'}); - } - - this.testFullKssParsing = function() { - // Example 1. - var src = "#calendar-previous a:click(cancelSubmit=True) {\n" - +" remote: kukitresponse/kukitGetPreviousMonth;\n" - +"}\n" - +"div#update-area:timeout(millis=2000) {\n" - +" effect: fade; \n" - +" remote: getCurrentTime;\n" - +"}\n" - +"#calendar-previous a:leave(cancelSubmit=True) {\n" - +" remote: kukitresponse/kukitPreviousMonth;\n" - +"}\n" - +"button#change:startdrag {\n remote: getDivContent(fgh, foo=bar) getSlowOne(fgd);\n log: \"WE LOG from getDivContent\";}\n" - +"#kukitportlet-recent-click:click {\n" - +" replaceMacro: (selector=#portlet-recent, macropath=portlet_recent/macros/portlet);\n" - +" replaceMacro2: #portlet-recent(macropath=portlet_recent/macros/portlet);\n" - +" replaceMacro3: #portlet-recent(portlet_recent/macros/portlet);\n" - +"}"; - var ruleProcessor = new kukit.KssRuleProcessor('http://foo.bar'); - ruleProcessor.parseResource(src); - this.assertEquals(ruleProcessor.rules.length, 5); - var rule = null; - // rule 0 - rule = ruleProcessor.rules[0]; - this.assertEquals(rule.type, 'click'); - this.assertEquals(rule.selector, '#calendar-previous a'); - this.assertEquals(rule.args, []); - this.assertDictEquals(rule.kw, {'cancelSubmit': 'True'}); - this.assertEquals(rule.actions.length, 1); - // - this.assertEquals(rule.actions[0].type, 'remote'); - this.assertEquals(rule.actions[0].args, ['kukitresponse/kukitGetPreviousMonth']); - this.assertDictEquals(rule.actions[0].kw, {}); - // rule 1 - rule = ruleProcessor.rules[1]; - this.assertEquals(rule.type, 'timeout'); - this.assertEquals(rule.selector, 'div#update-area'); - this.assertEquals(rule.args, []); - this.assertDictEquals(rule.kw, {'millis': '2000'}); - this.assertEquals(rule.actions.length, 2); - // - this.assertEquals(rule.actions[0].type, 'effect'); - this.assertEquals(rule.actions[0].args, ['fade']); - this.assertDictEquals(rule.actions[0].kw, {}); - // - this.assertEquals(rule.actions[1].type, 'remote'); - this.assertEquals(rule.actions[1].args, ['getCurrentTime']); - this.assertDictEquals(rule.actions[1].kw, {}); - // rule 2 - rule = ruleProcessor.rules[2]; - this.assertEquals(rule.type, 'leave'); - this.assertEquals(rule.selector, '#calendar-previous a'); - this.assertEquals(rule.args, []); - this.assertDictEquals(rule.kw, {'cancelSubmit': 'True'}); - this.assertEquals(rule.actions.length, 1); - // - this.assertEquals(rule.actions[0].type, 'remote'); - this.assertEquals(rule.actions[0].args, ['kukitresponse/kukitPreviousMonth']); - this.assertDictEquals(rule.actions[0].kw, {}); - // rule 3 - rule = ruleProcessor.rules[3]; - this.assertEquals(rule.type, 'startdrag'); - this.assertEquals(rule.selector, 'button#change'); - this.assertEquals(rule.args, []); - this.assertDictEquals(rule.kw, {}); - this.assertEquals(rule.actions.length, 3); - // - this.assertEquals(rule.actions[0].type, 'remote'); - this.assertEquals(rule.actions[0].args, ['getDivContent', 'fgh']); - this.assertDictEquals(rule.actions[0].kw, {'foo': 'bar'}); - // - this.assertEquals(rule.actions[1].type, 'remote'); - this.assertEquals(rule.actions[1].args, ['getSlowOne', 'fgd']); - this.assertDictEquals(rule.actions[1].kw, {}); - // - this.assertEquals(rule.actions[2].type, 'log'); - this.assertEquals(rule.actions[2].args, ['WE LOG from getDivContent']); - this.assertDictEquals(rule.actions[2].kw, {}); - // rule 4 -- the method name can be omitted. - rule = ruleProcessor.rules[4]; - this.assertEquals(rule.type, 'click'); - this.assertEquals(rule.selector, '#kukitportlet-recent-click'); - this.assertEquals(rule.args, []); - this.assertDictEquals(rule.kw, {}); - this.assertEquals(rule.actions.length, 3); - // - this.assertEquals(rule.actions[0].type, 'replaceMacro'); - this.assertEquals(rule.actions[0].args, []); // this must be nothing. Not [''] ! - this.assertDictEquals(rule.actions[0].kw, {'selector': '#portlet-recent', 'macropath': 'portlet_recent/macros/portlet'}); - // - this.assertEquals(rule.actions[1].type, 'replaceMacro2'); - this.assertEquals(rule.actions[1].args, ['#portlet-recent']); - this.assertDictEquals(rule.actions[1].kw, {'macropath': 'portlet_recent/macros/portlet'}); - // - this.assertEquals(rule.actions[2].type, 'replaceMacro3'); - this.assertEquals(rule.actions[2].args, ['#portlet-recent', 'portlet_recent/macros/portlet']); - this.assertDictEquals(rule.actions[2].kw, {}); - } - -}; - -kukit.KssParserTestCase.prototype = new TestCase; - -if (typeof(testcase_registry) != 'undefined') { - testcase_registry.registerTestCase(kukit.KssParserTestCase, 'kukit.KssParserTestCase'); -} Deleted: /kukit/kukit.js/branch/kss2/tests/kukit.PythonMethodSignatureTestCase.js ============================================================================== --- /kukit/kukit.js/branch/kss2/tests/kukit.PythonMethodSignatureTestCase.js Fri Jun 2 11:27:40 2006 +++ (empty file) @@ -1,36 +0,0 @@ -if (typeof(kukit) == "undefined") { - var kukit = {}; -} - -kukit.PythonMethodSignatureTestCase = function() { - this.name = 'kukit.PythonMethodSignatureTestCase'; - - this.setUp = function() { - }; - - this.assertDictEquals = function(a, b) { - for (var key in a) { - this.assertNotEquals(typeof(b[key]), 'undefined', 'key ' + key + ' missing from dict 2'); - this.assertEquals(a[key], b[key], 'mismatch at key ' + key); - } - for (var key in b) { - this.assertNotEquals(typeof(a[key]), 'undefined', 'key ' + key + ' missing from dict 1'); - this.assertEquals(a[key], b[key], 'mismatch at key ' + key); - } - } - - this.testMain = function() { - var sig = new kukit.PythonMethodSignature(['a', 'b'], {'c': 1, 'd': 2}); - // - this.assertDictEquals(sig.f_keywords(['x'], {'b': 'y', 'c': 'z'}), {'a': 'x', 'b': 'y', 'c': 'z', 'd': 2}); - this.assertThrows(sig.f_keywords, 'Excess args in python-like method call (3 > 2)', sig, ['x', 'y', 'z'], {'b': 'y', 'c': 'z'}); - this.assertThrows(sig.f_keywords, 'Missing args in python-like method call"b"', sig, ['x'], {'d': 3}); - this.assertThrows(sig.f_keywords, 'Multiple values for keyword argument "a"', sig, ['x', 'y'], {'a': '1'}); - } -} - -kukit.PythonMethodSignatureTestCase.prototype = new TestCase; - -if (typeof(testcase_registry) != 'undefined') { - testcase_registry.registerTestCase(kukit.PythonMethodSignatureTestCase, 'kukit.PythonMethodSignatureTestCase'); -} Modified: kukit/kukit.js/branch/kss2/tests/runner.html ============================================================================== --- kukit/kukit.js/branch/kss2/tests/runner.html (original) +++ kukit/kukit.js/branch/kss2/tests/runner.html Fri Jun 2 11:27:40 2006 @@ -14,14 +14,18 @@ } - - - - - - - + + + + + + + + + + + Modified: kukit/kukit.js/branch/kss2/tests/runtests.js ============================================================================== --- kukit/kukit.js/branch/kss2/tests/runtests.js (original) +++ kukit/kukit.js/branch/kss2/tests/runtests.js Fri Jun 2 11:27:40 2006 @@ -17,10 +17,8 @@ function runTests() { var reporter = new StdoutReporter; var testsuite = new TestSuite(reporter); - testsuite.registerTest(kukit.BsParserTestCase); + testsuite.registerTest(kukit.TokenizerTestCase); testsuite.registerTest(kukit.KssParserTestCase); - testsuite.registerTest(kukit.PythonMethodSignatureTestCase); - //testsuite.registerTest(kukit.RuleProcessorTestCase); testsuite.runSuite(); }; Modified: kukit/kukit.js/branch/kss2/tests/runtests.sh ============================================================================== --- kukit/kukit.js/branch/kss2/tests/runtests.sh (original) +++ kukit/kukit.js/branch/kss2/tests/runtests.sh Fri Jun 2 11:27:40 2006 @@ -1,18 +1,14 @@ js \ -f ecmaunit.js \ -f unittestUtilities.js \ - -f testStyleParse.js \ - -f kukit.BsParserTestCase.js \ - -f ../kukit/kukit.Utils.js \ - -f ../kukit/kukit.Parser.js \ - -f ../kukit/kukit.BsSelector.js \ - -f ../kukit/kukit.BsCommentParser.js \ - -f ../kukit/kukit.BsStringParser.js \ - -f ../kukit/kukit.BsMethodParser.js \ - -f ../kukit/kukit.BsPropertyParser.js \ - -f ../kukit/kukit.BsParser.js \ - -f kukit.KssParserTestCase.js \ - -f kukit.PythonMethodSignatureTestCase.js \ -f ../kukit/kukit.js \ - -f ../kukit/kukit.KssParser.js \ + -f ../kukit/tokenizer.js \ + -f ../kukit/resourcedata.js \ + -f ../kukit/kssparser.js \ + -f ../kukit/eventreg.js \ + -f ../kukit/actionreg.js \ + -f ../kukit/forms.js \ + -f ../kukit/plugin.js \ + -f test_tokenizer.js \ + -f test_kssparser.js \ runtests.js Deleted: /kukit/kukit.js/branch/kss2/tests/testStyleParse.js ============================================================================== --- /kukit/kukit.js/branch/kss2/tests/testStyleParse.js Fri Jun 2 11:27:40 2006 +++ (empty file) @@ -1,131 +0,0 @@ -function RuleParseTestCase() { - this.name = 'RuleParseTestCase'; -} - -RuleParseTestCase.prototype = new TestCase; -Class = RuleParseTestCase.prototype; - -Class.setUp = function() { - this.preprocessor = new kukit.RuleProcessor(); - this.doc = new DOMParser(); -}; - -Class.tearDown = function() { -}; - - -Class.testOneRule = function() { - input = 'getDivContent'; - var dom = this.doc.parseFromString(input, 'text/xml') - this.preprocessor.parseRuleDom(dom); - rules = this.preprocessor.rules; - this.assertEquals(rules.length, 1); - rule = rules[0]; - this.assertEquals(rule.selector, 'button.button'); - this.assertEquals(rule.property_type, 'event'); - this.assertEquals(rule.name, 'click'); - this.assertEquals(rule.action, 'getDivContent'); -} - -Class.testOneWrongSelector = function() { - input = 'getDivContent'; - var dom = this.doc.parseFromString(input, 'text/xml') - this.assertThrows(this.preprocessor.parseRuleDom, undefined, dom); - rules = this.preprocessor.rules; - this.assertEquals(rules.length, 0); -} - -Class.testOneWrongEvent = function() { - input = 'getDivContent'; - var dom = this.doc.parseFromString(input, 'text/xml') - this.assertThrows(this.preprocessor.parseRuleDom, undefined, dom); - rules = this.preprocessor.rules; - this.assertEquals(rules.length, 0); -} - -Class.testOneWrongAction = function() { - input = ''; - var dom = this.doc.parseFromString(input, 'text/xml') - this.assertThrows(this.preprocessor.parseRuleDom, undefined, dom); - rules = this.preprocessor.rules; - this.assertEquals(rules.length, 0); -} - -Class.testCorrectRules = function() { - input = 'getDivContentSecond'; - var dom = this.doc.parseFromString(input, 'text/xml') - this.preprocessor.parseRuleDom(dom); - rules = this.preprocessor.rules; - this.assertEquals(rules.length, 2); - rule = rules[0]; - this.assertEquals(rule.selector, 'button.button'); - this.assertEquals(rule.property_type, 'event'); - this.assertEquals(rule.name, 'click'); - this.assertEquals(rule.action, 'getDivContent'); - rule = rules[1]; - this.assertEquals(rule.selector, 'button.second'); - this.assertEquals(rule.property_type, 'event'); - this.assertEquals(rule.name, 'click'); - this.assertEquals(rule.action, 'Second'); -} - -Class.xxx_testCorrectRulesPlusOneWrong = function() { - // this should throw an error, diabled till this is implemented - input = '' + - '' + - '' + - 'getDivContent' + - '' + - '' + - 'Second' + - '' + - '' + - 'getDivContent' + - 'getDivContent' + - '' + - ''; - var dom = this.doc.parseFromString(input, 'text/xml') - this.preprocessor.parseRuleDom(dom); - rules = this.preprocessor.rules; - this.assertEquals(rules.length, 2); - rule = rules[0]; - this.assertEquals(rule.selector, 'button.button'); - this.assertEquals(rule.event, 'click'); - this.assertEquals(rule.action, 'getDivContent'); - rule = rules[1]; - this.assertEquals(rule.selector, 'button.second'); - this.assertEquals(rule.event, 'click'); - this.assertEquals(rule.action, 'Second'); -} - -testcase_registry.registerTestCase(RuleParseTestCase, 'ruleparse'); - -function CommandsParseTestCase() { - this.name = 'CommandsParseTestCase'; -} - -CommandsParseTestCase.prototype = new TestCase; -Class = CommandsParseTestCase.prototype; - -Class.setUp = function() { - this.preprocessor = new kukit.RuleProcessor(); - this.doc = new DOMParser(); -}; - -Class.tearDown = function() { -}; - - -Class.testOneCommand = function() { - /*input = 'button.buttonclickgetDivContent'; - var dom = this.doc.parseFromString(input, 'text/xml') - this.preprocessor.parseRuleDom(dom); - rules = this.preprocessor.rules; - this.assertEquals(rules.length, 1); - rule = rules[0]; - this.assertEquals(rule.selector, 'button.button'); - this.assertEquals(rule.event, 'click'); - this.assertEquals(rule.action, 'getDivContent');*/ -} - -testcase_registry.registerTestCase(CommandsParseTestCase, 'commandparse'); Added: kukit/kukit.js/branch/kss2/tests/test_kssparser.js ============================================================================== --- (empty file) +++ kukit/kukit.js/branch/kss2/tests/test_kssparser.js Fri Jun 2 11:27:40 2006 @@ -0,0 +1,414 @@ +if (typeof(kukit) == "undefined") { + var kukit = {}; +} + +kukit.KssParserTestCase = function() { + this.name = 'kukit.KssParserTestCase'; + + this.setUp = function() { + }; + + this.printDebug = function(parser, prefix) { + if (typeof(prefix) == "undefined") { + prefix = ''; + print('########################'); + } + for (var i=0; i Author: reebalazs Date: Thu Jun 22 22:01:10 2006 New Revision: 29174 Modified: kukit/kukit.js/trunk/kukit/eventreg.js kukit/kukit.js/trunk/kukit/kssparser.js kukit/kukit.js/trunk/kukit/kukit.js kukit/kukit.js/trunk/kukit/plugin.js kukit/kukit.js/trunk/kukit/resourcedata.js kukit/kukit.js/trunk/tests/test_kssparser.js Log: KSS3 minisprint result Modified: kukit/kukit.js/trunk/kukit/eventreg.js ============================================================================== --- kukit/kukit.js/trunk/kukit/eventreg.js (original) +++ kukit/kukit.js/trunk/kukit/eventreg.js Thu Jun 22 22:01:10 2006 @@ -16,37 +16,108 @@ this.content = {}; }; -kukit.er.EventClassRegistry.prototype.register = function(klass, func) { +kukit.er.EventClassRegistry.prototype.register = function(classname, func) { if (typeof(func) == 'undefined') { throw 'Func is mandatory.'; } - if (this.content[klass]) { + if (this.content[classname]) { // Do not allow redefinition - kukit.logError('Error : redefinition attempt of event class ' + klass); + kukit.logError('Error : redefinition attempt of event class ' + classname); return; } // Decorate and store the class kukit.er.decorateEventClass(func); - this.content[klass] = func; + this.content[classname] = func; }; -kukit.er.EventClassRegistry.prototype.exists = function(klass) { - var func = this.content[klass]; +kukit.er.EventClassRegistry.prototype.exists = function(classname) { + var func = this.content[classname]; return (typeof(func) != 'undefined'); }; -kukit.er.EventClassRegistry.prototype.get = function(klass) { - var func = this.content[klass]; +kukit.er.EventClassRegistry.prototype.get = function(classname) { + var func = this.content[classname]; if (! func) { // not found - throw 'Error : undefined event setup type ' + klass; + throw 'Error : undefined event setup type ' + classname; } return func; }; kukit.er.eventClassRegistry = new kukit.er.EventClassRegistry(); +/* Event registry +* +* available for plugin registration +* +* usage: +* +* kukit.er.eventRegistry.register(namespace, eventname, classname, +* bindmethodname, defaultactionmethodname); +* +* namespace = null: means global namespace +* defaultactionmethodname = null: if there is no default action implemented +* +*/ + +kukit.er.EventRegistry = function () { + this.content = {}; +}; + +kukit.er.EventRegistry.prototype.register = function(namespace, eventname, classname, + bindmethodname, defaultactionmethodname) { + if (typeof(defaultactionmethodname) == 'undefined') { + throw 'EventRegistry.register misses some parameters'; + } + if (!eventname || !classname || !bindmethodname) { + throw 'In EventRegistry.register eventname, classname, bindmethodname must be non-empty'; + } + var key = this._getKey(namespace, eventname); + var entry = this.content[key]; + if (typeof(entry) != 'undefined') { + if (key[0] == '-') { + key = key.substring(1); + } + throw 'In EventRegistry.register double registration of key "' + key + '"'; + } + // register it + this.content[key] = { + 'classname': classname, + 'bindmethodname': bindmethodname, + 'defaultactionmethodname': defaultactionmethodname, + }; +}; + +kukit.er.EventRegistry.prototype._getKey = function(namespace, eventname) { + if (namespace == null) { + namespace = ''; + } else if (namespace.split('-') > 1) { + throw 'In EventRegistry.register namespace cannot contain -'; + } + return namespace + '-' + eventname; +} + +kukit.er.EventRegistry.prototype.exists = function(namespace, eventname) { + var key = this._getKey(namespace, eventname); + var entry = this.content[key]; + return (typeof(entry) != 'undefined'); +}; + +kukit.er.EventRegistry.prototype.get = function(namespace, eventname) { + var key = this._getKey(namespace, eventname); + var entry = this.content[key]; + if (typeof(entry) == 'undefined') { + if (key[0] == '-') { + key = key.substring(1); + } + throw 'Error : undefined event key ' + key; + } + return entry; +}; + +kukit.er.eventRegistry = new kukit.er.EventRegistry(); + /* Event class decoration * * poor man's subclassing @@ -84,19 +155,38 @@ this.content = {}; }; -kukit.er.EventInstanceRegistry.prototype.getOrCreateEvent = function (id, klass) { +kukit.er.EventInstanceRegistry.prototype.getOrCreateEvent = function (id, classname, namespace) { // Get or create the event. var eventinstance = this.content[id]; if (typeof(eventinstance) == 'undefined') { // Create a new event. - eventinstance = this.content[id] = new (kukit.er.eventClassRegistry.get(klass))(); + eventinstance = this.content[id] = new (kukit.er.eventClassRegistry.get(classname))(); // decorate it with id and class eventinstance.__event_id__ = id; - eventinstance.__event_class__ = klass; - } else if (eventinstance.__event_class__ != klass) { + eventinstance.__event_classname__ = classname; + eventinstance.__event_namespace__ = namespace; + } else if (eventinstance.__event_classname__ != classname) { // just paranoia - throw 'Conflicting class for event id "' + id + '", "' + eventinstance.__event_class__ - + '" != "' + klass + '"'; + throw 'Conflicting class for event id "' + id + '", "' + eventinstance.__event_classname__ + + '" != "' + classname + '"'; + } + return eventinstance; +}; + +kukit.er.EventInstanceRegistry.prototype.getEventById = function (id) { + // Get an event. + var eventinstance = this.content[id]; + if (typeof(eventinstance) == 'undefined') { + throw 'Event with id "' + id + '" not found.' + } + return eventinstance; +}; + +kukit.er.EventInstanceRegistry.prototype.getSingletonEventByClass = function (classname) { + // Get an event. + var eventinstance = this.content['@@' + classname]; + if (typeof(eventinstance) == 'undefined') { + throw 'Singleton event with class "' + classname + '" not found.' } return eventinstance; }; Modified: kukit/kukit.js/trunk/kukit/kssparser.js ============================================================================== --- kukit/kukit.js/trunk/kukit/kssparser.js (original) +++ kukit/kukit.js/trunk/kukit/kssparser.js Thu Jun 22 22:01:10 2006 @@ -44,10 +44,14 @@ }; kukit.kssp.document.prototype.addBlock = function(key, block) { // Parse the part in an embedded parser - var src = new kukit.tk.Cursor(key); + var src = new kukit.tk.Cursor(key + ' '); var parser = new kukit.kssp.kssselector(src, null, true); + // check the evt_name equals the actual event name + if (block.evt_name != null && block.evt_name != parser.kssSelector.name) { + this.emitError('In evt-xxx-yyy xxx must correspond to the event name, "' + block.evt_name + '" != "' + parser.kssSelector.name + '"'); + } // Create the event rule. (one action only) - var eventRule = new kukit.rd.EventRule(parser.kssSelector, block.evt_parms, block.action); + var eventRule = new kukit.rd.EventRule(parser.kssSelector, block.evt_parms, block.actions); // Store the rule this.eventRules.push(eventRule); }; @@ -68,10 +72,10 @@ "}": 'this.emitAndReturn(new kukit.kssp.closebrace(this.src))' }); kukit.kssp.block.prototype.process = function() { - this.parms = {}; + //this.parms = {}; this.evt_parms = {}; - this.action = null; - this.error = null; + this.evt_name = null; // we don't know at this point + this.actions = new kukit.rd.ActionSet(); var cursor = {'next': 1}; while (cursor.next < this.result.length-1) { this.digestTxt(cursor, kukit.tk.Fraction, kukit.kssp.comment); @@ -88,45 +92,78 @@ } this.result = []; this.txt = ''; - // set result action, this and evt_parms are the output. - this.action = new kukit.rd.Action(this.action, this.error, this.parms); - this.error = null; - this.parms = null; }; kukit.kssp.block.prototype.addDeclaration = function(key, value) { // p.s. value is here a KssXxParm. In most cases we check and unwrap it. - if (key.substr(0, 4) == 'kss-') { - key = key.substr(4); - if (key == 'any') { - if (value.isMethod != true) { - this.emitError('kss-any: must have a method parm value'); - } - this.parms['*'] = value; - } else if (key == 'action') { - if (value.isMethod != false) { - this.emitError('kss-action: must not have a method parm value'); - } - this.action = value.txt; - } else if (key == 'error') { - if (value.isMethod != false) { - this.emitError('kss-error: must not have a method parm value'); - } - this.error = value.txt; - } else { - this.emitError('Bad kss-key: "' + key + '"'); - } - } else if (key.substr(0, 4) == 'evt-') { - key = key.substr(4); + // the keys look like this: + // + // evt--: + // + // action-server: + // action-client: + // + // -: + // -error: + // + // default-: + // default-error: + // + var splitkey = key.split('-'); + if (splitkey.length < 2 || splitkey.length > 3) { + this.emitError('kss param key must be like xxx-yyy or evt-xxx-yyy"' + key + '"'); + } + var name = splitkey[0]; + var qualifier = splitkey[1]; + if (splitkey.length == 3) { + if (name != 'evt') { + this.emitError('kss param key must be like xxx-yyy or evt-xxx-yyy"' + key + '"'); + } + if (this.evt_name != null && qualifier != this.evt_name) { + this.emitError('kss param key evt--yyy must not have different names "' + key + '", it must be "' + this.evt_name + '"'); + } if (value.isMethod != false) { - this.emitError('evt-key: must not have a method parm value, key "' + key + '"'); + this.emitError('evt-xxx-yyy: cannot use method as parm value, key "' + key + '"'); } - this.evt_parms[key] = value.txt; + this.evt_name = qualifier; + var qualifier2 = splitkey[2]; + // set it + this.evt_parms[qualifier2] = value.txt; } else { - if (key == '*') { - this.emitError('Bad action key: "' + key + '"'); + // xxx-yyy, two tags only + if (name == 'action') { + if (value.isMethod != false) { + this.emitError('action-xxx: cannot use method as parm value, key "' + key + '"'); + } + var isRemote; + switch (qualifier) { + case 'server': { + isRemote = true; + } break; + case 'client': { + isRemote = false; + } break; + default: { + this.emitError('kss param key must be action-server or action-client "' + key + '"'); + } break; + } + var action = this.actions.getOrCreateAction(value.txt); + action.isRemote = isRemote; } else { - // these may be either txt or method parms, and they stored with the wrapper. - this.parms[key] = value; + // name is the action name. + var action = this.actions.getOrCreateAction(name); + switch (qualifier) { + case 'error': { + if (value.isMethod != false) { + this.emitError('xxx-error: cannot use method as parm value, key "' + key + '"'); + } + action.error = value.txt; + } break; + default: { + // qualifier is the name of the key + // these may be either txt or method parms, and they stored with the wrapper. + action.parms[qualifier] = value; + } break; + } } } }; @@ -161,7 +198,7 @@ } // the next one must be the params this.expectToken(cursor, kukit.kssp.methodargs); - this.value = new kukit.rd.KssMethodValue(txt, cursor.token.args); + this.value = new this.valueClass(txt, cursor.token.args); } else { // not a string or method: check if we allowed multiword. if (! this.multiword_allowed && txt.indexOf(' ') != -1) { @@ -180,10 +217,15 @@ this.result = []; // Check the syntax of the value, enables early error detection. if (typeof this.value != 'undefined') { - this.value.check(); + try { + this.value.check(); + } catch(e) { + throw new kukit.tk.ParsingError('Error in value: ' + e, this.src.pos); + } } }; kukit.kssp.propvalue.prototype.multiword_allowed = true; +kukit.kssp.propvalue.prototype.valueClass = kukit.rd.KssMethodValue; kukit.kssp.propvalue.prototype.produceTxt = function(txt) { // txt parms are returned embedded this.value = new kukit.rd.KssTextValue(txt); @@ -207,6 +249,25 @@ this.txt = txt; }; +// propvalue in pseudo must ba single word with no spaces around. +kukit.kssp.propvalue_in_pseudo = kukit.tk.mkParser('propvalue', { + "{": 'this.emitAndReturn()', + " ": 'this.emitAndReturn()', + "\t": 'this.emitAndReturn()', + "\n": 'this.emitAndReturn()', + "\r": 'this.emitAndReturn()', + "/*": 'this.emitAndReturn()', + ":": 'this.emitAndReturn()', + "(": 'this.emitAndReturn(new kukit.kssp.methodargs(this.src, kukit.kssp.openparent))' + }); +kukit.kssp.propvalue_in_pseudo.prototype.multiword_allowed = false; +kukit.kssp.propvalue_in_pseudo.prototype.process = kukit.kssp.propvalue.prototype.process; +kukit.kssp.propvalue_in_pseudo.prototype.valueClass = kukit.rd.KssPseudoValue; +kukit.kssp.propvalue_in_pseudo.prototype.produceTxt = function(txt) { + // txt parms are returned embedded + this.value = new kukit.rd.KssPseudoValue(txt, []); +} + kukit.kssp.string = kukit.tk.mkParser('string', { "'": 'this.emitAndReturn(new kukit.kssp.quote(this.src))', "\\": 'new kukit.kssp.backslashed(this.src, kukit.kssp.backslash)' @@ -243,34 +304,6 @@ this.txt = this.result[1].txt; }; - -// methodparams are [k1=v1, ... kn=vn] lists. -kukit.kssp.methodparams = kukit.tk.mkParser('methodparams', { - ",": 'new kukit.kssp.comma(this.src)', - "=": '[new kukit.kssp.equals(this.src), new kukit.kssp.propvalue_in_method(this.src)]', - "]": 'this.emitAndReturn(new kukit.kssp.closebracket(this.src))', - "/*": 'new kukit.kssp.comment(this.src, kukit.kssp.commentbegin)' - }); -kukit.kssp.methodparams.prototype.process = function() { - this.parms = {}; - var cursor = {'next': 1}; - while (cursor.next < this.result.length-1) { - this.digestTxt(cursor, kukit.tk.Fraction, kukit.kssp.comment); - var key = cursor.txt; - if (! key) { - break; - } - this.expectToken(cursor, kukit.kssp.equals); - this.expectToken(cursor, kukit.kssp.propvalue); - // unwrap the value txt - this.parms[key] = cursor.token.txt; - if (cursor.next == this.result.length-1) break; - this.expectToken(cursor, kukit.kssp.comma); - } - this.txt = ''; - this.result = []; -}; - // methodargs are (a, b, c) lists. kukit.kssp.methodargs = kukit.tk.mkParser('methodargs', { "'": 'new kukit.kssp.string(this.src, kukit.kssp.quote)', @@ -307,115 +340,90 @@ // embedded parser to parse the selector // kss event selector: (has spaces in it) -// name[id=xxx, class=yyy] +// selector:name(id) // kss method selector: (has no spaces in it) -// name#id or name.class +// document:name(id) kukit.kssp.kssselector = kukit.tk.mkParser('kssselector', { - "[": 'new kukit.kssp.methodparams(this.src, kukit.kssp.openbracket)', - "}": 'this.emitAndReturn()', + ":": '[new kukit.kssp.colon(this.src), new kukit.kssp.propvalue_in_pseudo(this.src)]', + "{": 'this.emitAndReturn()', "/*": 'new kukit.kssp.comment(this.src, kukit.kssp.commentbegin)' }); kukit.kssp.kssselector.prototype.process = function() { - var cursor = {'next': 0}; var name; - var klass = null; + var namespace = null; var id = null; var tokenindex = this.result.length - 1; // Find the method parms and calculate the end of css parms. (RL) var cycle = true; - var parmstoken = null; - var lasttokenpos = this.endpos; while (cycle && tokenindex >= 0) { var token = this.result[tokenindex]; switch (token.symbol) { case kukit.tk.Fraction.prototype.symbol: { - var txt = token.txt; // if all spaces, go to previous one - if (txt.match(/^[\r\n\t ]*$/) != null) { + if (token.txt.match(/^[\r\n\t ]*$/) != null) { tokenindex -= 1; - } - else { - // found a good string. - cycle = false; - // however if there is a token, it must not end with space - if (parmstoken && txt.match(/[\r\n\t ]$/) != null) { - // name [..] (space between) - this.emitError('Kss event selector must have a one-word name'); - } + } else { + // Error. + this.emitError('Kss event selector must end with an event qualifier :event or :event(id)'); } } break; - case kukit.kssp.methodparams.prototype.symbol: { - if (parmstoken) { - // [..][..] - this.emitError('Kss event selector must have a one-word name'); - } - parmstoken = token; - lasttokenpos = parmstoken.startpos; + case kukit.kssp.comment.prototype.symbol: { tokenindex -= 1; } break; - default: { // comment - lasttokenpos = token.startpos; - tokenindex -= 1; + default: { + cycle = false; } break; } } - // Find the end of the css parms. Use original source. - var txt = ''; - if (tokenindex >= 0) { - txt = this.result[tokenindex].txt; - } - txt = txt.replace(/[\r\n\t ]/g, ' '); - var txt2 = txt.replace(/( )+$/, ''); - var cssendpos = txt2.lastIndexOf(' '); - if (cssendpos == -1) { - cssendpos = 0; - name = txt2; - } else { - name = txt2.substring(cssendpos + 1); + // Now we found the token that must be . + tokenindex -= 2 + if (tokenindex < 0 + || this.result[tokenindex+2].symbol != kukit.kssp.propvalue_in_pseudo.prototype.symbol + || this.result[tokenindex+1].symbol != kukit.kssp.colon.prototype.symbol + || this.result[tokenindex].symbol != kukit.tk.Fraction.prototype.symbol) { + this.emitError('Kss event selector must end with an event qualifier :event or :event(id)'); + } + // See that the last fraction does not end with space. + var lasttoken = this.result[tokenindex]; + var commatoken = this.result[tokenindex+1]; + var pseudotoken = this.result[tokenindex+2]; + var txt = lasttoken.txt; + if (txt.match(/[\r\n\t ]$/) != null) { + this.emitError('In kss event selector no space can be before the colon'); + } + if (! pseudotoken.value.methodname) { + this.emitError('Kss event selector must have a one-word name after the colon'); + } + if (pseudotoken.value.args.length > 1) { + this.emitError('Kss pseudo value must not have more then one parameters'); + } + css = this.src.text.substring(this.startpos, commatoken.startpos); + //print ('>>' + css + ':' + pseudotoken.value.methodname); + // Decide if we have an event or a method selector. + // We have a method selector if a single word "document". + var singleword = css.replace(/[\r\n\t ]/g, ' '); + if (singleword && singleword[0] == ' ') { + singleword = singleword.substring(1); } - cssendpos = lasttokenpos - txt.length + cssendpos; - if (name == '') { - this.emitError('Kss event selector must have a one-word name'); - } - css = this.src.text.substring(this.startpos, cssendpos); - //print (cssendpos + '>' + css + '@' + this.src.text.substring(cssendpos)); - // Decide if we have an event or a method selector. (Is css empty?) - var isEvent = css.match(/^[\r\n\t ]*$/) == null; - if (isEvent) { - // Process event selector. - if (parmstoken) { - parms = parmstoken.parms; - for (var key in parms) { - if (key != 'class' && key != 'id') { - this.emitError('Unknown parameter in kss selector, only class and id are valid "' + key + '"'); - } - } - if (typeof(parms['class']) != 'undefined') - klass = parms['class']; - if (typeof(parms.id) != 'undefined') - id = parms.id; - } - } else { - // Process method selector. - if (parmstoken) { - this.emitError('Method selector must not have parameters [] (or css selector missing in front)'); - } - // process the name further, it's name.class or name#id . - // See if we find a . or a # in it. - var splitstr = name.split(/[.#]/, 2) - if (splitstr.length != 2) { - this.emitError('Method selector must be either name.class or name#id'); - } - if (name[splitstr[0].length] == '#') { - id = splitstr[1]; - } else { - klass = splitstr[1]; - } - name = splitstr[0]; + var isEvent = singleword != 'document'; + if (! isEvent) { css = null; } // create the selector. - this.kssSelector = new kukit.rd.KssSelector(isEvent, css, name, klass, id); + var id = null; + if (pseudotoken.value.args.length == 1) { + id = pseudotoken.value.args[0]; + } + var name = pseudotoken.value.methodname; + var splitname = name.split('-'); + var namespace = null; + if (splitname.length > 2) { + this.emitError('Kss event selector must be id or class-id but no more dashes, "' + name + '"'); + } else if (splitname.length == 2) { + name = splitname[1]; + namespace = splitname[0]; + } + this.kssSelector = new kukit.rd.KssSelector(isEvent, css, name, namespace, id); this.txt = ''; this.result = []; }; Modified: kukit/kukit.js/trunk/kukit/kukit.js ============================================================================== --- kukit/kukit.js/trunk/kukit/kukit.js (original) +++ kukit/kukit.js/trunk/kukit/kukit.js Thu Jun 22 22:01:10 2006 @@ -404,36 +404,37 @@ kukit.notifyServer_done = function(domDoc) { if (domDoc.readyState == 4) { - kukit.processResult(domDoc.responseXML); + kukit.processResult(domDoc); /* } else { kukit.logDebug('Request arrived with readyState = ' + domDoc.readyState); */ } }; kukit.processResult = function(domDoc) { + var domXml = domDoc.responseXML; kukit.requestManager.receivedResult(); - if (!domDoc) { + if (!domXml) { kukit.logError('Error : no kukit response'); return; } // Opera <= 8.5 does not have the parseError attribute, so check for it first - if (domDoc.parseError && (domDoc.parseError != 0)) { - kukit.logError(Sarissa.getParseErrorText(domDoc)); + if (domXml.parseError && (domXml.parseError != 0)) { + kukit.logError(Sarissa.getParseErrorText(domXml)); return; } - if (domDoc.getElementsByTagNameNS) { - commands = domDoc.getElementsByTagNameNS("http://www.kukit.org/commands/1.0", + if (domXml.getElementsByTagNameNS) { + commands = domXml.getElementsByTagNameNS("http://www.kukit.org/commands/1.0", "command"); } else { //IE does not know DOM2 - commands = domDoc.getElementsByTagName("kukit:command"); + commands = domXml.getElementsByTagName("kukit:command"); } if (commands.length == 0) { kukit.logWarning('No commands in kukit response'); return; } var command_processor = new kukit.CommandProcessor(); - command_processor.parseCommands(commands); + command_processor.parseCommands(commands, domDoc); command_processor.executeCommands(); }; @@ -441,16 +442,16 @@ this.commands = new Array(); }; -kukit.CommandProcessor.prototype.parseCommands = function(commands) { +kukit.CommandProcessor.prototype.parseCommands = function(commands, transport) { kukit.log('Parse commands'); kukit.logDebug('Number of commands: ' + commands.length); for (var y=0;y < commands.length;y++) { var command = commands[y]; - this.parseCommand(command); + this.parseCommand(command, transport); } }; -kukit.CommandProcessor.prototype.parseCommand = function(command) { +kukit.CommandProcessor.prototype.parseCommand = function(command, transport) { var selector = ""; var params = new Array(); var name = ""; @@ -488,8 +489,8 @@ } kukit.log('Command params: '+ has_params); if (selector != "" && has_params && name != "") { - var command = new kukit.Command(selector, name, type, params); - this.addCommand(command); + var command = new kukit.makeCommand(selector, name, type, params, transport); + this.addCommand(command); } } }; @@ -502,37 +503,10 @@ var commands = this.commands for (var y=0;y < commands.length;y++) { var command = commands[y]; - this.executeCommand(command); + command.execute(); } }; -kukit.CommandProcessor.prototype.executeCommand = function(command) { - kukit.logDebug('Selector type: '+command.selectorType); - kukit.logDebug('Selector : '+command.selector); - var selfunc = kukit.selectors.get(command.selectorType); - var nodes = selfunc(command.selector); - var func = null; - if (!nodes || nodes.length == 0) { - kukit.logError('Command found no nodes'); - } else { - func = kukit.commandRegistry.getFunc(command.name); - } - for (var i=0;i < nodes.length;i++) { - var node = nodes[i]; - //XXX error handling for wrong command name - kukit.logDebug('Command Name: '+command.name); - var results = func(node, command.params); - kukit.storeResults(results); // XXX see above - } -}; - -kukit.Command = function(selector, name, type, params) { - this.selector = selector; - this.name = name; - this.selectorType = type; - this.params = params; -}; - /* selector registry */ kukit.selectors = {}; @@ -640,44 +614,97 @@ this.content = {}; }; -kukit.CommandRegistry.prototype.register = function(name, func) { +kukit.CommandRegistry.prototype.register = function(name, klass) { if (this.content[name]) { // Do not allow redefinition kukit.logError('Error : redefinition attempt of command ' + name); return; } - this.content[name] = func; + this.content[name] = klass; }; -kukit.CommandRegistry.prototype.getFunc = function(name) { - var func = this.content[name]; - if (! func) { +kukit.CommandRegistry.prototype.get = function(name) { + var klass = this.content[name]; + if (! klass) { // not found kukit.logError('Error : undefined command ' + name); } - return func; + return klass; }; kukit.commandRegistry = new kukit.CommandRegistry(); +/* Command factories */ + +kukit.makeCommand = function(selector, name, type, params, transport) { + var commandClass = kukit.commandRegistry.get(name); + var command = new commandClass(); + command.selector = selector; + command.name = name; + command.selectorType = type; + command.params = params; + command.transport = transport; + return command; +} + +kukit._Command_execute_selector = function() { + kukit.logDebug('Selector type: ' + this.selectorType); + kukit.logDebug('Selector : ' + this.selector); + var selfunc = kukit.selectors.get(this.selectorType); + var nodes = selfunc(this.selector); + if (!nodes || nodes.length == 0) { + kukit.logError('Command found no nodes'); + } + for (var i=0;i < nodes.length;i++) { + var node = nodes[i]; + //XXX error handling for wrong command name + kukit.logDebug('Command Name: ' + this.name); + var results = this.executeOnSingleNode(node); + kukit.storeResults(results); // XXX see above + } +}; + +kukit.makeSelectorCommand = function(name, executeOnSingleNode) { + var commandClass = function() {}; + commandClass.prototype = { + execute: kukit._Command_execute_selector, + executeOnSingleNode: executeOnSingleNode + }; + kukit.commandRegistry.register(name, commandClass); +}; + +kukit.makeGlobalCommand = function(name, executeOnce) { + var commandClass = function() {}; + commandClass.prototype = { + execute: executeOnce + }; + kukit.commandRegistry.register(name, commandClass); +}; + /* Core commands */ -kukit.commandRegistry.register('setHtmlAsChild', function(node, command_data) { - var content = document.importNode(command_data['html'], true); +kukit.makeGlobalCommand('prototypeResponse', function(node) { + // supposed to have a single cdata node + this.transport.responseText = this.params['html'].firstChild.data; + this.transport.responseXML = null; +}); + +kukit.makeSelectorCommand('setHtmlAsChild', function(node) { + var content = document.importNode(this.params['html'], true); Sarissa.clearChildNodes(node); kukit.dom.appendChildren(content.childNodes, node); kukit.setupEvents(node); }); -kukit.commandRegistry.register('replaceNode', function(node, command_data) { - var childNodes = command_data['html'].childNodes; - var sourceSelector = command_data['selector'].firstChild.nodeValue || null; +kukit.makeSelectorCommand('replaceNode', function(node) { + var childNodes = this.params['html'].childNodes; + var sourceSelector = this.params['selector'].firstChild.nodeValue || null; var parentNode = node.parentNode; var newNode = parentNode.cloneNode(false); try { kukit.dom.appendChildren(childNodes, newNode); } catch(exc) { - newNode.innerHTML = Sarissa.serialize(command_data['html']); + newNode.innerHTML = Sarissa.serialize(this.params['html']); } if (sourceSelector) { var element = cssQuery(sourceSelector, newNode)[0]; @@ -692,14 +719,14 @@ }); -kukit.commandRegistry.register('setAttribute', function(node, command_data) { - var name = command_data['name'].firstChild.nodeValue; - var value = command_data['value'].firstChild.nodeValue; +kukit.makeSelectorCommand('setAttribute', function(node) { + var name = this.params['name'].firstChild.nodeValue; + var value = this.params['value'].firstChild.nodeValue; node.setAttribute(name, value); }); -kukit.commandRegistry.register('addAfter', function(node, command_data) { - var content = document.importNode(command_data['html'], true); +kukit.makeSelectorCommand('addAfter', function(node) { + var content = document.importNode(this.params['html'], true); var parentNode = node.parentNode; var toNode = kukit.dom.getNextSiblingTag(node); if (toNode == null) { @@ -713,7 +740,7 @@ return inserted; }); -kukit.commandRegistry.register('removeNextSibling', function(node, command_data) { +kukit.makeSelectorCommand('removeNextSibling', function(node) { kukit.logDebug('removeNextSibling'); var parentNode = node.parentNode; var toNode = kukit.dom.getNextSiblingTag(node); @@ -722,27 +749,27 @@ } }); -kukit.commandRegistry.register('removePreviousSibling', function(node, command_data) { +kukit.makeSelectorCommand('removePreviousSibling', function(node) { kukit.logDebug('removePreviousSibling'); var parentNode = node.parentNode; var toNode = kukit.dom.getPreviousSiblingTag(node); parentNode.removeChild(toNode); }); -kukit.commandRegistry.register('removeNode', function(node, command_data) { +kukit.makeSelectorCommand('removeNode', function(node) { var parentNode = node.parentNode; parentNode.removeChild(node); }); -kukit.commandRegistry.register('clearChildren', function(node, command_data) { +kukit.makeSelectorCommand('clearChildren', function(node) { Sarissa.clearChildNodes(node); }); -kukit.commandRegistry.register('moveNodeAfter', function(node, command_data) { +kukit.makeSelectorCommand('moveNodeAfter', function(node) { var parentNode = node.parentNode; parentNode.removeChild(node); - var id = command_data['html_id'].firstChild.nodeValue; + var id = this.params['html_id'].firstChild.nodeValue; var toNode = document.getElementById(id); var nextNode = kukit.dom.getNextSiblingTag(toNode); @@ -753,20 +780,20 @@ } }); -kukit.commandRegistry.register('copyChildrenFrom', function(node, command_data) { - var id = command_data['html_id'].firstChild.nodeValue; +kukit.makeSelectorCommand('copyChildrenFrom', function(node) { + var id = this.params['html_id'].firstChild.nodeValue; var fromNode = document.getElementById(id); Sarissa.copyChildNodes(fromNode, node); }); -kukit.commandRegistry.register('copyChildrenTo', function(node, command_data) { - var id = command_data['html_id'].firstChild.nodeValue; +kukit.makeSelectorCommand('copyChildrenTo', function(node) { + var id = this.params['html_id'].firstChild.nodeValue; toNode = document.getElementById(id); Sarissa.copyChildNodes(node, toNode); }) -kukit.commandRegistry.register('executeCode', function(node, command_data) +kukit.makeSelectorCommand('executeCode', function(node) { - var code = command_data['code'].firstChild.nodeValue; + var code = this.params['code'].firstChild.nodeValue; node.eval(code); }); Modified: kukit/kukit.js/trunk/kukit/plugin.js ============================================================================== --- kukit/kukit.js/trunk/kukit/plugin.js (original) +++ kukit/kukit.js/trunk/kukit/plugin.js Thu Jun 22 22:01:10 2006 @@ -94,6 +94,8 @@ }; kukit.er.eventClassRegistry.register('native', kukit.pl.NativeEvent); +kukit.er.eventRegistry.register(null, 'click', 'native', '__bind__', null); +kukit.er.eventRegistry.register(null, 'change', 'native', '__bind__', null); // Timer events. The binding of this event will start one counter // per event rule. No matter how many nodes matched it. @@ -124,7 +126,7 @@ this.counters = {}; }; -kukit.pl.TimeoutEvent.prototype.__bind_timeout__ = function(parms, func_to_bind, node, eventrule) { +kukit.pl.TimeoutEvent.prototype.__bind__ = function(name, parms, func_to_bind, node, eventrule) { parms = kukit.pl.completeParms(parms, ['delay'], {}, 'timeout event binding'); var key = eventrule.getNr(); if (this.counters[key]) { @@ -144,6 +146,7 @@ }; kukit.er.eventClassRegistry.register('timeout', kukit.pl.TimeoutEvent); +kukit.er.eventRegistry.register(null, 'timeout', 'timeout', '__bind__', null); // CancelSubmitClick. This is a mutated version of // the browser click event. @@ -151,7 +154,7 @@ kukit.pl.CancelSubmitClickEvent = function() { }; -kukit.pl.CancelSubmitClickEvent.prototype.__bind_cancelSubmitClick__ = function(parms, func_to_bind, node) { +kukit.pl.CancelSubmitClickEvent.prototype.__bind__ = function(name, parms, func_to_bind, node) { parms = kukit.pl.completeParms(parms, [], {}, 'cancelSubmitClick event binding'); var func = function(e) { target = kukit.pl.getTargetForBrowserEvent(e); @@ -173,11 +176,12 @@ }; kukit.er.eventClassRegistry.register('cancelSubmitClick', kukit.pl.CancelSubmitClickEvent); +kukit.er.eventRegistry.register(null, 'cancelSubmitClick', 'cancelSubmitClick', '__bind__', null); kukit.pl.LoadEvent = function() { }; -kukit.pl.LoadEvent.prototype.__bind_load__ = function(parms, func_to_bind, node) { +kukit.pl.LoadEvent.prototype.__bind__ = function(name, parms, func_to_bind, node) { parms = kukit.pl.completeParms(parms, [], {}, 'load event binding'); // Just execute the action right now. func_to_bind() @@ -185,6 +189,7 @@ }; kukit.er.eventClassRegistry.register('load', kukit.pl.LoadEvent); +kukit.er.eventRegistry.register(null, 'load', 'load', '__bind__', null); /* Core actions @@ -193,6 +198,26 @@ * side. */ +kukit.ar.eventActionRegistry.register("cascade", function (node, parms, eventrule) { + parms = kukit.pl.completeParms(parms, ['name'], {'id': null, 'class': null}, 'cascade action'); + if (parms.id == null && parms['class'] == null || parms.id != null && parms['class'] != null) { + throw 'Must specify either class or id in cascade action, rule=#' + eventrule.getNr() + ', node=' + node.nodeName; + } + var eventinstance; + if (parms.id) { + // by id + eventinstance = kukit.er.eventInstanceRegistry(parms.id); + } else { + // singleton by class + eventinstance = kukit.er.eventInstanceRegistry(parms['class']); + } + // marshall it + actionparms = {}; // XXX could be specified too! + eventinstance.__trigger_action__(parms.name, actionparms, node); + } +); + + kukit.ar.eventActionRegistry.register("logDebug", function (node, parms, eventrule) { parms = kukit.pl.completeParms(parms, [], {'message': 'Logging from Event'}, 'logDebug action'); Modified: kukit/kukit.js/trunk/kukit/resourcedata.js ============================================================================== --- kukit/kukit.js/trunk/kukit/resourcedata.js (original) +++ kukit/kukit.js/trunk/kukit/resourcedata.js Thu Jun 22 22:01:10 2006 @@ -3,7 +3,7 @@ kukit.rd = {}; -kukit.rd.KssSelector = function(isEvent, css, name, klass, id) { +kukit.rd.KssSelector = function(isEvent, css, name, namespace, id) { this.isEventSelector = isEvent; this.isMethodSelector = ! isEvent; if (! name) { @@ -13,45 +13,35 @@ throw 'Kss selector name must not contain @: "' + name + '"'; if (id && id.indexOf('@') != -1) throw 'Kss selector id must not contain @: "' + id + '"'; - if (klass && klass.indexOf('@') != -1) - throw 'Kss selector class must not contain @: "' + klass + '"'; + if (namespace && namespace.indexOf('@') != -1) + throw 'Kss selector class must not contain @: "' + namespace + '"'; if (! isEvent) { // method rule if (css != null) { - throw 'KssMethodSelector must have css=null'; - } - if (klass != null && id != null || klass == null && id == null) { - throw 'KssMethodSelector "' + name + '" must have either class or id, but not both'; + throw 'KssMethodSelector "' + name + '" must have css=null'; } } this.css = css; this.name = name; - this.klass = klass; + this.namespace = namespace; + this.classname = null; this.id = id; }; kukit.rd.KssSelector.prototype.setIdAndClass = function() { // Sets up id and class on the selector, based on registration info - if (this.isEventSelector) { - // event rule - // fill up values for class, id - if (this.klass == null) { - // try: same as name, if that is in the registry. - if (kukit.er.eventClassRegistry.exists(this.name)) { - this.klass = this.name; - } else { - // else, use "native" - this.klass = 'native'; - } - } - if (this.id == null) { - // singleton for class - this.id = '@@' + this.klass; - } + this.classname = kukit.er.eventRegistry.get(this.namespace, this.name).classname + if (this.id == null) { + // singleton for class + this.id = '@@' + this.classname; } // Also set the merge id. The rules with the same merge // id should be merged on the same node. - this.mergeid = this.id + '@' + this.name + var namespace = ''; + if (this.namespace != null) { + namespace = this.namespace; + } + this.mergeid = this.id + '@' + namespace + '@' + this.name }; /* @@ -132,6 +122,7 @@ parms[key] = value; } break; case 'eval': { + // XXX do it with the variable registry parms[key] = eval(this.args[0]); } break; default: { @@ -140,10 +131,19 @@ } }; +kukit.rd.KssPseudoValue = function(methodname, args) { + // A method parameter in the format + // methodname(v1) + this.methodname = methodname; + this.args = args; +}; +kukit.rd.KssPseudoValue.prototype.isMethod = true; +kukit.rd.KssPseudoValue.prototype.check = function() { +}; kukit.rd.EventRuleNr = 0; // just a counter -kukit.rd.EventRule = function(kss_selector, parms, action) { +kukit.rd.EventRule = function(kss_selector, parms, actions) { if (typeof(parms) == 'undefined') { // called for merging clone this.kss_selector = kss_selector; @@ -154,7 +154,7 @@ kukit.logDebug("EventRule #" + this.nr + ": " + kss_selector.css); this.kss_selector = kss_selector; this.parms = parms; - this.action = action; + this.actions = actions; } }; @@ -188,7 +188,8 @@ kukit.rd.EventRule.prototype.getEventInstance = function() { // Gets the event instance for the rule. - return kukit.er.eventInstanceRegistry.getOrCreateEvent(this.kss_selector.id, this.kss_selector.klass); + return kukit.er.eventInstanceRegistry.getOrCreateEvent(this.kss_selector.id, this.kss_selector.classname, + this.kss_selector.namespace); }; /* @@ -208,7 +209,7 @@ var parms = this.parms; var method = eventinstance['__bind_' + name + '__']; var self = this; - var func_to_bind = function(evt) { + var func_to_bind = function() { self.trigger_event(node, eventinstance); } var retstat = false; @@ -222,7 +223,7 @@ } if (! retstat) { // An error. - throw 'Could not bind event name "' + name + '" on class "' + this.kss_selector.klass + '"'; + throw 'Could not bind event name "' + name + '" on class "' + this.kss_selector.classname + '"'; } } }; @@ -242,9 +243,16 @@ kukit.rd.EventRule.prototype.trigger_event = function(node, eventinstance) { // Node will be null if executed for a method rule. var name = this.kss_selector.name; - var parms = this.getActionParms(node); var method = eventinstance['__exec_' + name + '__']; var retstat = false; + // XXX ... move this to a method of actionset ? + var defaultaction = this.actions.getDefaultAction(); + var parms; + if (defaultaction) { + parms = defaultaction.getParms(node); + } else { + parms = {}; + } if (typeof(method) != 'undefined') { retstat = method.call(eventinstance, parms, node); } @@ -254,23 +262,12 @@ retstat = method.call(eventinstance, name, parms, node); } if (! retstat) { - // execute the action! - this.action.execute(parms, node, this); + // execute the actions! + this.actions.execute(node, this); } } }; -kukit.rd.EventRule.prototype.getActionParms = function(node) { - // Return the completed action parameters, based on the node - var parms = {}; - for (var key in this.action.parms) { - var kssvalue = this.action.parms[key]; - // evaluate the method parameters into parms - kssvalue.evaluate(parms, key, node); - } - return parms; -}; - // // Merging event rules // @@ -282,7 +279,7 @@ kukit.rd.EventRule.prototype.cloneForMerge = function() { // Do not touch ourselves, make a new copy for the merge. var merged = new kukit.rd.EventRule(this.kss_selector); - merged.action = new kukit.rd.Action(null, null, {}); + merged.actions = new kukit.rd.ActionSet(); merged.parms = {}; merged.mergednr = 'X'; merged.merge(this); @@ -298,7 +295,7 @@ if (this.kss_selector.id != other.kss_selector.id) { throw "Differing kss selector ids in event rule merge"; } - if (this.kss_selector.klass != other.kss_selector.klass) { + if (this.kss_selector.classname != other.kss_selector.classname) { throw "Differing kss selector classes in event rule merge"; } } @@ -309,7 +306,7 @@ for (var key in other.parms) { this.parms[key] = other.parms[key]; } - this.action.merge(other.action); + this.actions.merge(other.actions); if (this.mergednr[0] != 'X') // ignore initial clone-merge kukit.logDebug('Merged rule ' + this.mergednr + ' mergeid ' + this.kss_selector.mergeid); @@ -335,14 +332,65 @@ } }; -kukit.rd.Action = function(name, error, parms) { +kukit.rd.ActionSet = function() { + this.content = {}; +}; + +kukit.rd.ActionSet.prototype.merge = function(other) { + for (var key in other.content) { + var action = this.content[key]; + if (typeof(action) == 'undefined') { + // new action + action = new kukit.rd.Action(null, null, {}, null); + this.content[key] = action; + } + // merge the action + action.merge(other.content[key]); + } +}; + +kukit.rd.ActionSet.prototype.execute = function(node, eventrule) { + for (var key in this.content) { + var action = this.content[key]; + action.execute(node, eventrule); + } +}; + +kukit.rd.ActionSet.prototype.getOrCreateAction = function(name) { + var action = this.content[name]; + if (typeof(action) == 'undefined') { + action = new kukit.rd.Action(name, null, {}, null); + this.content[name] = action; + } + return action; +}; + +kukit.rd.ActionSet.prototype.getDefaultAction = function() { + var action = this.content['default']; + if (typeof(action) == 'undefined') { + action = null; + } + return action; +} + +kukit.rd.Action = function(name, error, parms, isRemote) { this.name = name; this.error = error; this.parms = parms; + this.isRemote = isRemote }; kukit.rd.Action.prototype.merge = function(other) { // Merge to the instance. + if (this.name != null && this.name != other.name) { + throw 'Unmatching action names at merge' ; + } + if (other.isRemote != null) { + if (this.isRemote != null && this.isRemote != other.isRemote) { + throw 'Attempt to merge a client action and a server action' ; + } + this.isRemote = other.isRemote; + } this.name = other.name; this.error = other.error; for (var key in other.parms) { @@ -350,16 +398,29 @@ } }; -kukit.rd.Action.prototype.execute = function(parms, node, eventrule) { - // If there exists this name, it will be local; otherwise remote. - if (kukit.ar.eventActionRegistry.exists(this.name)) { - // Local action. - var func = kukit.ar.eventActionRegistry.get(this.name); - func(node, parms, eventrule); - } else { + +kukit.rd.Action.prototype.getParms = function(node) { + // Return the completed action parameters, based on the node + var parms = {}; + for (var key in this.parms) { + var kssvalue = this.parms[key]; + // evaluate the method parameters into parms + kssvalue.evaluate(parms, key, node); + } + return parms; +}; + + +kukit.rd.Action.prototype.execute = function(node, eventrule) { + var parms = this.getParms(node); + if (this.isRemote) { // Remote action. var action = kukit.calculateAbsoluteURL(this.name); kukit.notifyServer(action, parms); + } else { + // Local action. + var func = kukit.ar.eventActionRegistry.get(this.name); + func(node, parms, eventrule); } }; @@ -449,7 +510,8 @@ this.content[eventrule.kss_selector.name] = entry; } // Merge by class and by id - eventrule.mergeIntoDict(entry.byclass, eventrule.kss_selector.klass, eventrule); + // XXX must be put back + //eventrule.mergeIntoDict(entry.byclass, eventrule.kss_selector.classname, eventrule); eventrule.mergeIntoDict(entry.byid, eventrule.kss_selector.id, eventrule); }; @@ -462,12 +524,13 @@ return null; } // look up the rule and merge if necessary - var klass = eventinstance.__event_klass__; + var namespace = eventinstance.__event_namespace__; + var classname = eventinstance.__event_classname__; var id = eventinstance.__event_id__; var mergedrule = entry.cookedbyid[id]; if (typeof(mergedrule) == 'undefined') { // Prepare this rule. - mergedrule = entry.byclass[klass]; + mergedrule = entry.byclass[classname]; var rule2 = entry.byid[id]; if (typeof(mergedrule) != 'undefined' && typeof(rule2) != 'undefined') { mergedrule = mergedrule.cloneForMerge(); @@ -478,7 +541,7 @@ entry.byid[id] = null; // free garbage } else if (typeof(mergedrule) != 'undefined') { throw 'No method rule found event name="' + name + '" id="' + id + - '" class="' + klass + '"'; + '" namespace="' + namespace + '"'; mergedrule = null } entry.cookedbyid[id] = mergedrule; Modified: kukit/kukit.js/trunk/tests/test_kssparser.js ============================================================================== --- kukit/kukit.js/trunk/tests/test_kssparser.js (original) +++ kukit/kukit.js/trunk/tests/test_kssparser.js Thu Jun 22 22:01:10 2006 @@ -215,53 +215,57 @@ this.assertParsingError(kukit.kssp.propvalue, src, null, true, 'Excess characters after the property value', 17); }; + + this.testPropValueInPseudo = function() { + // Parsing prop values in pseudo (no methods allowed) - this.testMethodParams = function() { - // Parsing method params - var txt= "[a = b, c = d]"; + var txt= "b"; var src = new kukit.tk.Cursor(txt); - var parser = new kukit.kssp.methodparams(src, kukit.kssp.openbracket, true); - this.assertEquals(parser.finished, true); - this.assertDictEquals(parser.parms, {'a': 'b', 'c': 'd'}); - - txt= "[a = 'b', c = /* to annoy you */ \"d\"]"; - src = new kukit.tk.Cursor(txt); - parser = new kukit.kssp.methodparams(src, kukit.kssp.openbracket, true); + var parser = new kukit.kssp.propvalue_in_pseudo(src, null, true); this.assertEquals(parser.finished, true); - this.assertDictEquals(parser.parms, {'a': 'b', 'c': 'd'}); + this.assertEquals(parser.value.methodname, 'b'); - txt= "[a = ' b multi', c = /* to annoy you */ \"d multi \"]"; + // multiword ok but does not finish + txt= "b c"; src = new kukit.tk.Cursor(txt); - parser = new kukit.kssp.methodparams(src, kukit.kssp.openbracket, true); + parser = new kukit.kssp.propvalue_in_pseudo(src, null, true); this.assertEquals(parser.finished, true); - this.assertDictEquals(parser.parms, {'a': ' b multi', 'c': 'd multi '}); + this.assertEquals(src.pos, 1); + this.assertEquals(parser.value.methodname, 'b'); - txt= "[a = 'b', c /*comment*/ = /* to annoy you */ \"d\"]"; + // space ok but does not finish + txt= " b"; src = new kukit.tk.Cursor(txt); - parser = new kukit.kssp.methodparams(src, kukit.kssp.openbracket, true); + parser = new kukit.kssp.propvalue_in_pseudo(src, null, true); this.assertEquals(parser.finished, true); - this.assertDictEquals(parser.parms, {'a': 'b', 'c': 'd'}); + this.assertEquals(src.pos, 0); + this.assertEquals(parser.value.methodname, ''); - txt= "[a = b, c = d, ]"; + // ok, does not finish + txt= "apples/* more comments and*/"; src = new kukit.tk.Cursor(txt); - parser = new kukit.kssp.methodparams(src, kukit.kssp.openbracket, true); + parser = new kukit.kssp.propvalue_in_pseudo(src, null, true); this.assertEquals(parser.finished, true); - this.assertDictEquals(parser.parms, {'a': 'b', 'c': 'd'}); + this.assertEquals(src.pos, 6); + this.assertEquals(parser.value.methodname, 'apples'); - txt= "[a = b, c = d, x ]"; + // params ok + txt= "click(x)"; src = new kukit.tk.Cursor(txt); - this.assertParsingError(kukit.kssp.methodparams, src, kukit.kssp.openbracket, true, - 'Expected [equals], found [closebracket]', 18); + parser = new kukit.kssp.propvalue_in_pseudo(src, null, true); + this.assertEquals(parser.finished, true); + this.assertEquals(parser.value.methodname, 'click'); + this.assertListEquals(parser.value.args, ['x']); - txt= "[a = b, c = d e ]"; - src = new kukit.tk.Cursor(txt); - this.assertParsingError(kukit.kssp.methodparams, src, kukit.kssp.openbracket, true, - 'Property value must be one word', 16); + // more then 1 args not ok (but we check it only from kss selector) + //txt= "drag(x, y)"; + //src = new kukit.tk.Cursor(txt); - txt= "[a = b, c = d 'x' ]"; - src = new kukit.tk.Cursor(txt); - this.assertParsingError(kukit.kssp.methodparams, src, kukit.kssp.openbracket, true, - 'Excess characters before the string in property value', 18); + // not ok but we don't parse an error + //txt= "'drag'(x)"; + //src = new kukit.tk.Cursor(txt); + //this.assertParsingError(kukit.kssp.propvalue_in_pseudo, src, null, true, + // 'Excess characters after the property value', 16); }; @@ -311,229 +315,250 @@ this.testKssSelector = function() { // Parsing event selector params - var txt= "a drag[class= dnd, id=hello]"; + var txt= "a:drag(hello)"; var src = new kukit.tk.Cursor(txt); var parser = new kukit.kssp.kssselector(src, null, true); this.assertEquals(parser.finished, true); this.assertEquals(parser.kssSelector.isEventSelector, true); this.assertEquals(parser.kssSelector.css, 'a'); this.assertEquals(parser.kssSelector.name, 'drag'); - this.assertEquals(parser.kssSelector.klass, 'dnd'); + this.assertEquals(parser.kssSelector.namespace, null); this.assertEquals(parser.kssSelector.id, 'hello'); - txt= " a div#id drag[class= dnd, id=hello]"; + var txt= "a:dnd-drag(hello)"; + var src = new kukit.tk.Cursor(txt); + var parser = new kukit.kssp.kssselector(src, null, true); + this.assertEquals(parser.finished, true); + this.assertEquals(parser.kssSelector.isEventSelector, true); + this.assertEquals(parser.kssSelector.css, 'a'); + this.assertEquals(parser.kssSelector.name, 'drag'); + this.assertEquals(parser.kssSelector.namespace, 'dnd'); + this.assertEquals(parser.kssSelector.id, 'hello'); + + var txt= "a:dnd-drag-toomuch(hello)"; + var src = new kukit.tk.Cursor(txt); + this.assertParsingError(kukit.kssp.kssselector, src, null, true, + 'Kss event selector must be id or class-id but no more dashes, "dnd-drag-toomuch"', 25); + + // maybe in std css space is not allowed in the parents, + // but we tolerate it + txt= " a div#id:drag( hello)"; src = new kukit.tk.Cursor(txt); parser = new kukit.kssp.kssselector(src, null, true); this.assertEquals(parser.kssSelector.isEventSelector, true); this.assertEquals(parser.kssSelector.css, ' a div#id'); this.assertEquals(parser.kssSelector.name, 'drag'); - this.assertEquals(parser.kssSelector.klass, 'dnd'); + this.assertEquals(parser.kssSelector.namespace, null); this.assertEquals(parser.kssSelector.id, 'hello'); - txt= " a div#id drag [class= dnd, id=hello]"; + // We do not allow space here + txt= " a div#id:drag (hello)"; src = new kukit.tk.Cursor(txt); this.assertParsingError(kukit.kssp.kssselector, src, null, true, - 'Kss event selector must have a one-word name', 40); + 'Kss event selector must end with an event qualifier :event or :event(id)', 25); - txt= "a div#id drop[class= dnd]"; + // We do not allow space here + txt= " a div#id: drag(hello)"; + src = new kukit.tk.Cursor(txt); + this.assertParsingError(kukit.kssp.kssselector, src, null, true, + 'Kss event selector must end with an event qualifier :event or :event(id)', 23); + + txt= "a div#id:drop "; src = new kukit.tk.Cursor(txt); parser = new kukit.kssp.kssselector(src, null, true); this.assertEquals(parser.kssSelector.isEventSelector, true); this.assertEquals(parser.kssSelector.css, 'a div#id'); this.assertEquals(parser.kssSelector.name, 'drop'); - this.assertEquals(parser.kssSelector.klass, 'dnd'); + this.assertEquals(parser.kssSelector.namespace, null); this.assertEquals(parser.kssSelector.id, null); - txt= "a div.class drop[id = 'hello']"; + txt= "a div.class:drop "; src = new kukit.tk.Cursor(txt); parser = new kukit.kssp.kssselector(src, null, true); this.assertEquals(parser.finished, true); this.assertEquals(parser.kssSelector.isEventSelector, true); this.assertEquals(parser.kssSelector.css, 'a div.class'); this.assertEquals(parser.kssSelector.name, 'drop'); - this.assertEquals(parser.kssSelector.klass, null); - this.assertEquals(parser.kssSelector.id, 'hello'); + this.assertEquals(parser.kssSelector.namespace, null); + this.assertEquals(parser.kssSelector.id, null); - txt= "a click"; + txt= "a:click "; src = new kukit.tk.Cursor(txt); parser = new kukit.kssp.kssselector(src, null, true); this.assertEquals(parser.finished, true); this.assertEquals(parser.kssSelector.isEventSelector, true); this.assertEquals(parser.kssSelector.css, 'a'); this.assertEquals(parser.kssSelector.name, 'click'); - this.assertEquals(parser.kssSelector.klass, null); + this.assertEquals(parser.kssSelector.namespace, null); this.assertEquals(parser.kssSelector.id, null); - // test that only id and class are valid parameters - txt= "a drop[bad = 'hello']"; + // two params: not allowed + txt= "a:drop('hello', bello)"; src = new kukit.tk.Cursor(txt); this.assertParsingError(kukit.kssp.kssselector, src, null, true, - 'Unknown parameter in kss selector, only class and id are valid "bad"', 21); + 'Kss pseudo value must not have more then one parameters', 22); - txt= " [id = 'hello']"; + // zero params: not std css but tolerated + txt= "a:drop()"; src = new kukit.tk.Cursor(txt); + parser = new kukit.kssp.kssselector(src, null, true); this.assertParsingError(kukit.kssp.kssselector, src, null, true, - 'Kss event selector must have a one-word name', 17); + 'Kss event selector must end with an event qualifier :event or :event(id)', 8); - txt= "hello [id = 'hello']"; + txt= " (hello)"; src = new kukit.tk.Cursor(txt); this.assertParsingError(kukit.kssp.kssselector, src, null, true, - 'Kss event selector must have a one-word name', 21); + 'Kss event selector must end with an event qualifier :event or :event(id)', 10); - txt= "a[href=xxx] [id = 'hello']"; + txt= "hello ('bello')"; src = new kukit.tk.Cursor(txt); this.assertParsingError(kukit.kssp.kssselector, src, null, true, - 'Kss event selector must have a one-word name', 27); + 'Kss event selector must end with an event qualifier :event or :event(id)', 16); - txt= "a[href=xxx] b [id = 'hello']"; + txt= "a:lang(hu) (hello)"; src = new kukit.tk.Cursor(txt); this.assertParsingError(kukit.kssp.kssselector, src, null, true, - 'Kss event selector must have a one-word name', 28); + 'Kss event selector must end with an event qualifier :event or :event(id)', 19); + txt= "a:lang(hu) b (hello)"; + src = new kukit.tk.Cursor(txt); + this.assertParsingError(kukit.kssp.kssselector, src, null, true, + 'Kss event selector must end with an event qualifier :event or :event(id)', 20); // A valid attr selector in the css selector part. - txt= "a[href=hello].class div#id click"; + txt= "a[href=hello].class:lang(hu) div#id:click "; src = new kukit.tk.Cursor(txt); parser = new kukit.kssp.kssselector(src, null, true); - this.assertEquals(parser.finished, true); this.assertEquals(parser.kssSelector.isEventSelector, true); - this.assertEquals(parser.kssSelector.css, "a[href=hello].class div#id"); + this.assertEquals(parser.kssSelector.css, "a[href=hello].class:lang(hu) div#id"); this.assertEquals(parser.kssSelector.name, 'click'); - this.assertEquals(parser.kssSelector.klass, null); + this.assertEquals(parser.kssSelector.namespace, null); this.assertEquals(parser.kssSelector.id, null); - txt= "a[href=hello].class div#id drop[class=dnd] "; + txt= "a[href=hello].class:lang(hu) div#id:drop(hello) "; src = new kukit.tk.Cursor(txt); parser = new kukit.kssp.kssselector(src, null, true); this.assertEquals(parser.finished, true); this.assertEquals(parser.kssSelector.isEventSelector, true); - this.assertEquals(parser.kssSelector.css, "a[href=hello].class div#id"); + this.assertEquals(parser.kssSelector.css, "a[href=hello].class:lang(hu) div#id"); this.assertEquals(parser.kssSelector.name, 'drop'); - this.assertEquals(parser.kssSelector.klass, 'dnd'); - this.assertEquals(parser.kssSelector.id, null); + this.assertEquals(parser.kssSelector.namespace, null); + this.assertEquals(parser.kssSelector.id, 'hello'); - txt= " a[id = hello] click "; + txt= " a:lang(hu) click "; src = new kukit.tk.Cursor(txt); - parser = new kukit.kssp.kssselector(src, null, true); - this.assertEquals(parser.finished, true); - this.assertEquals(parser.kssSelector.isEventSelector, true); - this.assertEquals(parser.kssSelector.css, " a[id = hello]"); - this.assertEquals(parser.kssSelector.name, 'click'); - this.assertEquals(parser.kssSelector.klass, null); - this.assertEquals(parser.kssSelector.id, null); + this.assertParsingError(kukit.kssp.kssselector, src, null, true, + 'Kss event selector must end with an event qualifier :event or :event(id)', 20); // Spaces in the end - txt= " a[id = 'hello'] click "; + txt= " a:lang(hu, uh) b:click "; src = new kukit.tk.Cursor(txt); parser = new kukit.kssp.kssselector(src, null, true); this.assertEquals(parser.finished, true); this.assertEquals(parser.kssSelector.isEventSelector, true); - this.assertEquals(parser.kssSelector.css, " a[id = 'hello']"); + this.assertEquals(parser.kssSelector.css, " a:lang(hu, uh) b"); this.assertEquals(parser.kssSelector.name, 'click'); - this.assertEquals(parser.kssSelector.klass, null); + this.assertEquals(parser.kssSelector.namespace, null); this.assertEquals(parser.kssSelector.id, null); // Comment in the end - txt= " a[id = 'hello'] click/*comment here*/"; + txt= " a:lang(hu, uh) b:click/*comment here*/"; src = new kukit.tk.Cursor(txt); parser = new kukit.kssp.kssselector(src, null, true); this.assertEquals(parser.finished, true); this.assertEquals(parser.kssSelector.isEventSelector, true); - this.assertEquals(parser.kssSelector.css, " a[id = 'hello']"); + this.assertEquals(parser.kssSelector.css, " a:lang(hu, uh) b"); this.assertEquals(parser.kssSelector.name, 'click'); - this.assertEquals(parser.kssSelector.klass, null); + this.assertEquals(parser.kssSelector.namespace, null); this.assertEquals(parser.kssSelector.id, null); // Should be ok. - txt= "a[id=hello]/*comment here*/click"; + txt= "a:lang(hu)/*comment here*/b:click "; src = new kukit.tk.Cursor(txt); parser = new kukit.kssp.kssselector(src, null, true); - this.assertEquals(parser.finished, true); this.assertEquals(parser.kssSelector.isEventSelector, true); - this.assertEquals(parser.kssSelector.css, "a[id=hello]/*comment here*/"); + this.assertEquals(parser.kssSelector.css, "a:lang(hu)/*comment here*/b"); this.assertEquals(parser.kssSelector.name, 'click'); - this.assertEquals(parser.kssSelector.klass, null); + this.assertEquals(parser.kssSelector.namespace, null); this.assertEquals(parser.kssSelector.id, null); // Should be ok. - txt= "a[id=hello] click/*comment here*/clack"; + txt= "a:lang(hu) click/*comment here*/b:clack "; src = new kukit.tk.Cursor(txt); parser = new kukit.kssp.kssselector(src, null, true); this.assertEquals(parser.finished, true); this.assertEquals(parser.kssSelector.isEventSelector, true); - this.assertEquals(parser.kssSelector.css, "a[id=hello] click/*comment here*/"); + this.assertEquals(parser.kssSelector.css, "a:lang(hu) click/*comment here*/b"); this.assertEquals(parser.kssSelector.name, 'clack'); - this.assertEquals(parser.kssSelector.klass, null); + this.assertEquals(parser.kssSelector.namespace, null); this.assertEquals(parser.kssSelector.id, null); - txt= "click[id=hello][id=hello]"; + txt= "a:click:clack "; src = new kukit.tk.Cursor(txt); this.assertParsingError(kukit.kssp.kssselector, src, null, true, - 'Kss event selector must have a one-word name', 25); + 'Kss event selector must end with an event qualifier :event or :event(id)', 14); - txt= "click[id=hello] [id=hello]"; + txt= "a:click :clack "; src = new kukit.tk.Cursor(txt); this.assertParsingError(kukit.kssp.kssselector, src, null, true, - 'Kss event selector must have a one-word name', 29); + 'In kss event selector no space can be before the colon', 18); - txt= "click[id=hello]/*comment */[id=hello]"; + txt= "a:click/*comment */:clack "; src = new kukit.tk.Cursor(txt); this.assertParsingError(kukit.kssp.kssselector, src, null, true, - 'Kss event selector must have a one-word name', 37); + 'Kss event selector must end with an event qualifier :event or :event(id)', 26); - txt= "click/*comment here*/[id=hello]"; + txt= "click/*comment here*/:clack "; src = new kukit.tk.Cursor(txt); this.assertParsingError(kukit.kssp.kssselector, src, null, true, - 'Method selector must not have parameters [] (or css selector missing in front', 31); + 'Kss event selector must end with an event qualifier :event or :event(id)', 28); - txt= " click[id=hello]"; + txt= "/*comment here*/click:clack "; src = new kukit.tk.Cursor(txt); - this.assertParsingError(kukit.kssp.kssselector, src, null, true, - 'Method selector must not have parameters [] (or css selector missing in front', 16); + parser = new kukit.kssp.kssselector(src, null, true); + + txt= " no-document:click(hello)"; + src = new kukit.tk.Cursor(txt); + parser = new kukit.kssp.kssselector(src, null, true); + this.assertEquals(parser.finished, true); + this.assertEquals(parser.kssSelector.isEventSelector, true); + this.assertEquals(parser.kssSelector.css, " no-document"); + this.assertEquals(parser.kssSelector.name, 'click'); + this.assertEquals(parser.kssSelector.namespace, null); + this.assertEquals(parser.kssSelector.id, "hello"); + // Event method selectors - txt= " click.the-class "; + txt= " document:click(hello) "; src = new kukit.tk.Cursor(txt); parser = new kukit.kssp.kssselector(src, null, true); this.assertEquals(parser.finished, true); this.assertEquals(parser.kssSelector.isMethodSelector, true); this.assertEquals(parser.kssSelector.css, null); this.assertEquals(parser.kssSelector.name, 'click'); - this.assertEquals(parser.kssSelector.klass, 'the-class'); - this.assertEquals(parser.kssSelector.id, null); + this.assertEquals(parser.kssSelector.namespace, null); + this.assertEquals(parser.kssSelector.id, 'hello'); - txt= " click#the-id "; + txt= " document:native-click(hello) "; src = new kukit.tk.Cursor(txt); parser = new kukit.kssp.kssselector(src, null, true); this.assertEquals(parser.finished, true); this.assertEquals(parser.kssSelector.isMethodSelector, true); this.assertEquals(parser.kssSelector.css, null); this.assertEquals(parser.kssSelector.name, 'click'); - this.assertEquals(parser.kssSelector.klass, null); - this.assertEquals(parser.kssSelector.id, 'the-id'); - - txt= " click#the-id[id=the-id] "; + this.assertEquals(parser.kssSelector.namespace, 'native'); + this.assertEquals(parser.kssSelector.id, 'hello'); + + txt= "document"; src = new kukit.tk.Cursor(txt); this.assertParsingError(kukit.kssp.kssselector, src, null, true, - 'Method selector must not have parameters [] (or css selector missing in front)', 26); + 'Kss event selector must end with an event qualifier :event or :event(id)', 8); - txt= "click"; + txt= "document: "; src = new kukit.tk.Cursor(txt); this.assertParsingError(kukit.kssp.kssselector, src, null, true, - 'Method selector must be either name.class or name#id', 5); - - // that's accepted... - txt= " click#the-id.xxx "; - src = new kukit.tk.Cursor(txt); - parser = new kukit.kssp.kssselector(src, null, true); - this.assertEquals(parser.finished, true); - - // that's accepted too... - txt= " click.the-id#xxx "; - src = new kukit.tk.Cursor(txt); - parser = new kukit.kssp.kssselector(src, null, true); - this.assertEquals(parser.finished, true); + 'Kss event selector must have a one-word name after the colon', 10); } @@ -561,42 +586,57 @@ +"** comment\n" +"*/\n" +"\n" - +"#calendar-previous a click {\n" - +" kss-action : kukitresponse/kukitGetPreviousMonth;\n" + +"#calendar-previous a:click {\n" + +" action-server : kukitresponse/kukitGetPreviousMonth;\n" + +"}\n" + +"div#update-area:timeout {\n" + +" evt-timeout-delay: 2000; \n" + +" action-server: getCurrentTime;\n" + +" getCurrentTime-effect: fade; \n" +"}\n" - +"div#update-area timeout {\n" - +" evt-delay: 2000; \n" - +" effect: fade; \n" - +" kss-action: getCurrentTime;\n" + +"#calendar-previous a:click {\n" + +" action-server: 'kukitresponse/kukitGetPreviousMonth' /* place comment here*/;\n" +"}\n" - +"#calendar-previous a click {\n" - +" kss-action : 'kukitresponse/kukitGetPreviousMonth' /* place comment here*/;\n" + +"#calendar-previous a:click {\n" + +" action-server : kukitGetPreviousMonth /* place comment here*/;\n" + +" kukitGetPreviousMonth-member: formvar(edit, 'f_member');\n" +"}\n" - +"#calendar-previous a click {\n" - +" kss-action : 'kukitresponse/kukitGetPreviousMonth' /* place comment here*/;\n" - +" member: formvar(edit, 'f_member');\n" + +"#calendar-previous a:dnd-drag(shelve) {\n" + +" action-server : whatever\n" +"}\n" - +"#calendar-previous a drag[class=dnd, id=shelve] {\n" - +" kss-action : whatever\n" + +"#button-one:annoyClicker-click(annoy-me) {\n" + +" action-server: clickedButton;\n" + +" clickedButton-id: nodeattr(id);\n" +"}\n" - +"#button-one click[class=annoyClicker,id=annoy-me] {\n" - +" kss-action: clickedButton;\n" - +" id: nodeattr(id);\n" + +"document:annoy(annoyMe) {\n" + +" action-client: alert;\n" + +' alert-message: "You are an idiot! Ha ha ha. (But just keep on trying...)";\n' +"}\n" - +"annoy#annoy-me {\n" - +" kss-action: alert;\n" - +' message: "You are an idiot! Ha ha ha. (But just keep on trying...)";\n' + +"document:annoyClicker-annoy(annoyMe) {\n" + +" action-client: alert;\n" + +' alert-message: "You are an idiot! Ha ha ha. (But just keep on trying...)";\n' + +"}\n" + +"div#update-area:timeout {\n" + +" evt-timeout-delay: 2000; \n" + +" action-server: getCurrentTime;\n" + +" getCurrentTime-effect: fade; \n" + +" action-client: log;\n" + +' log-message: "Logging";\n' +"}\n"; + var src = new kukit.tk.Cursor(txt); + // XXX TODO change comments + var parser = new kukit.kssp.document(src, null, true); this.assertEquals(parser.finished, true); - this.assertEquals(parser.eventRules.length, 7); + this.assertEquals(parser.eventRules.length, 9); var rule; - + var action; + // rule 0 - // #calendar-previous a click { + // #calendar-previous a:click { // kss-action : kukitresponse/kukitGetPreviousMonth; // } rule = parser.eventRules[0]; @@ -604,14 +644,16 @@ this.assertEquals(rule.kss_selector.isEventSelector, true); this.assertEquals(rule.kss_selector.css, '#calendar-previous a'); this.assertEquals(rule.kss_selector.name, 'click'); - this.assertEquals(rule.kss_selector.klass, null); + this.assertEquals(rule.kss_selector.namespace, null); this.assertEquals(rule.kss_selector.id, null); - this.assertEquals(rule.action.name, 'kukitresponse/kukitGetPreviousMonth'); - this.assertEquals(rule.action.error, null); - this.assertKssParmEquals(rule.action.parms, {}); - + action = rule.actions.content['kukitresponse/kukitGetPreviousMonth']; + this.assertEquals(action.isRemote, true); + this.assertEquals(action.name, 'kukitresponse/kukitGetPreviousMonth'); + this.assertEquals(action.error, null); + this.assertKssParmEquals(action.parms, {}); + // rule 1 - // div#update-area timeout { + // div#update-area:timeout { // evt-delay: 2000; // effect: fade; // kss-action: getCurrentTime; @@ -621,16 +663,18 @@ this.assertEquals(rule.kss_selector.isEventSelector, true); this.assertEquals(rule.kss_selector.css, 'div#update-area'); this.assertEquals(rule.kss_selector.name, 'timeout'); - this.assertEquals(rule.kss_selector.klass, null); + this.assertEquals(rule.kss_selector.namespace, null); this.assertEquals(rule.kss_selector.id, null); - this.assertEquals(rule.action.name, 'getCurrentTime'); - this.assertEquals(rule.action.error, null); - this.assertKssParmEquals(rule.action.parms, { + action = rule.actions.content['getCurrentTime']; + this.assertEquals(action.isRemote, true); + this.assertEquals(action.name, 'getCurrentTime'); + this.assertEquals(action.error, null); + this.assertKssParmEquals(action.parms, { 'effect': new kukit.rd.KssTextValue('fade') }); // rule 2 - // #calendar-previous a click { + // #calendar-previous a:click { // kss-action : 'kukitresponse/kukitGetPreviousMonth' /* place comment here*/; // } rule = parser.eventRules[2]; @@ -638,14 +682,16 @@ this.assertEquals(rule.kss_selector.css, '#calendar-previous a'); this.assertEquals(rule.kss_selector.isEventSelector, true); this.assertEquals(rule.kss_selector.name, 'click'); - this.assertEquals(rule.kss_selector.klass, null); + this.assertEquals(rule.kss_selector.namespace, null); this.assertEquals(rule.kss_selector.id, null); - this.assertEquals(rule.action.name, 'kukitresponse/kukitGetPreviousMonth'); - this.assertEquals(rule.action.error, null); - this.assertKssParmEquals(rule.action.parms, {}); + action = rule.actions.content['kukitresponse/kukitGetPreviousMonth']; + this.assertEquals(action.isRemote, true); + this.assertEquals(action.name, 'kukitresponse/kukitGetPreviousMonth'); + this.assertEquals(action.error, null); + this.assertKssParmEquals(action.parms, {}); // rule 3 - // #calendar-previous a click { + // #calendar-previous a:click { // kss-action : 'kukitresponse/kukitGetPreviousMonth' /* place comment here*/; // member: formvar(edit, 'f_member'); // } @@ -654,16 +700,18 @@ this.assertEquals(rule.kss_selector.css, '#calendar-previous a'); this.assertEquals(rule.kss_selector.isEventSelector, true); this.assertEquals(rule.kss_selector.name, 'click'); - this.assertEquals(rule.kss_selector.klass, null); + this.assertEquals(rule.kss_selector.namespace, null); this.assertEquals(rule.kss_selector.id, null); - this.assertEquals(rule.action.name, 'kukitresponse/kukitGetPreviousMonth'); - this.assertEquals(rule.action.error, null); - this.assertKssParmEquals(rule.action.parms, { + action = rule.actions.content['kukitGetPreviousMonth']; + this.assertEquals(action.isRemote, true); + this.assertEquals(action.name, 'kukitGetPreviousMonth'); + this.assertEquals(action.error, null); + this.assertKssParmEquals(action.parms, { 'member': new kukit.rd.KssMethodValue('formvar', ['edit', 'f_member']) }); // rule 4 - // #calendar-previous a drag[class=dnd, id=shelve] { + // #calendar-previous a:dnd-drag(shelve) { // kss-action : whatever // } rule = parser.eventRules[4]; @@ -671,15 +719,17 @@ this.assertEquals(rule.kss_selector.css, '#calendar-previous a'); this.assertEquals(rule.kss_selector.isEventSelector, true); this.assertEquals(rule.kss_selector.name, 'drag'); - this.assertEquals(rule.kss_selector.klass, 'dnd'); + this.assertEquals(rule.kss_selector.namespace, 'dnd'); this.assertEquals(rule.kss_selector.id, 'shelve'); - this.assertEquals(rule.action.name, 'whatever'); - this.assertEquals(rule.action.error, null); - this.assertKssParmEquals(rule.action.parms, { + action = rule.actions.content['whatever']; + this.assertEquals(action.isRemote, true); + this.assertEquals(action.name, 'whatever'); + this.assertEquals(action.error, null); + this.assertKssParmEquals(action.parms, { }); // rule 5 - //#button-one click[class=annoyClicker,id=annoy-me] { + //#button-one:annoyClicker-click(annoyMe) { // kss-action: clickedButton; // id: nodeattr(id); //} @@ -688,16 +738,18 @@ this.assertEquals(rule.kss_selector.css, '#button-one'); this.assertEquals(rule.kss_selector.isEventSelector, true); this.assertEquals(rule.kss_selector.name, 'click'); - this.assertEquals(rule.kss_selector.klass, 'annoyClicker'); + this.assertEquals(rule.kss_selector.namespace, 'annoyClicker'); this.assertEquals(rule.kss_selector.id, 'annoy-me'); - this.assertEquals(rule.action.name, 'clickedButton'); - this.assertEquals(rule.action.error, null); - this.assertKssParmEquals(rule.action.parms, { + action = rule.actions.content['clickedButton']; + this.assertEquals(action.isRemote, true); + this.assertEquals(action.name, 'clickedButton'); + this.assertEquals(action.error, null); + this.assertKssParmEquals(action.parms, { 'id': new kukit.rd.KssMethodValue('nodeattr', ['id']) }); // rule 6 - // annoy#annoy-me { + // document:annoy(annoyMe) { // kss-action: alert; // message: "You are an idiot! Ha ha ha. (But just keep on trying...)"; //} @@ -706,14 +758,60 @@ this.assertEquals(rule.kss_selector.css, null); this.assertEquals(rule.kss_selector.isMethodSelector, true); this.assertEquals(rule.kss_selector.name, 'annoy'); - this.assertEquals(rule.kss_selector.klass, null); - this.assertEquals(rule.kss_selector.id, 'annoy-me'); - this.assertEquals(rule.action.name, 'alert'); - this.assertEquals(rule.action.error, null); - this.assertKssParmEquals(rule.action.parms, { + this.assertEquals(rule.kss_selector.namespace, null); + this.assertEquals(rule.kss_selector.id, 'annoyMe'); + action = rule.actions.content['alert']; + this.assertEquals(action.isRemote, false); + this.assertEquals(action.name, 'alert'); + this.assertEquals(action.error, null); + this.assertKssParmEquals(action.parms, { 'message': new kukit.rd.KssTextValue( "You are an idiot! Ha ha ha. (But just keep on trying...)") }); - + + // rule 7 + // document:annoyClicker-annoy(annoyMe) { + // annoy#annoy-me { + // kss-action: alert; + // message: "You are an idiot! Ha ha ha. (But just keep on trying...)"; + //} + rule = parser.eventRules[7]; + this.assertDictEquals(rule.parms, {}); + this.assertEquals(rule.kss_selector.css, null); + this.assertEquals(rule.kss_selector.isMethodSelector, true); + this.assertEquals(rule.kss_selector.name, 'annoy'); + this.assertEquals(rule.kss_selector.namespace, 'annoyClicker'); + this.assertEquals(rule.kss_selector.id, 'annoyMe'); + action = rule.actions.content['alert']; + this.assertEquals(action.isRemote, false); + this.assertEquals(action.name, 'alert'); + this.assertEquals(action.error, null); + this.assertKssParmEquals(action.parms, { + 'message': new kukit.rd.KssTextValue( "You are an idiot! Ha ha ha. (But just keep on trying...)") + }); + + // rule 8 + rule = parser.eventRules[8]; + this.assertDictEquals(rule.parms, {'delay': '2000'}); + this.assertEquals(rule.kss_selector.isEventSelector, true); + this.assertEquals(rule.kss_selector.css, 'div#update-area'); + this.assertEquals(rule.kss_selector.name, 'timeout'); + this.assertEquals(rule.kss_selector.namespace, null); + this.assertEquals(rule.kss_selector.id, null); + action = rule.actions.content['getCurrentTime']; + this.assertEquals(action.isRemote, true); + this.assertEquals(action.name, 'getCurrentTime'); + this.assertEquals(action.error, null); + this.assertKssParmEquals(action.parms, { + 'effect': new kukit.rd.KssTextValue('fade') + }); + action = rule.actions.content['log']; + this.assertEquals(action.isRemote, false); + this.assertEquals(action.name, 'log'); + this.assertEquals(action.error, null); + this.assertKssParmEquals(action.parms, { + 'message': new kukit.rd.KssTextValue('Logging') + }); + }; }; From reebalazs at codespeak.net Thu Jun 22 22:04:00 2006 From: reebalazs at codespeak.net (reebalazs at codespeak.net) Date: Thu, 22 Jun 2006 22:04:00 +0200 (CEST) Subject: [Kukit-checkins] r29177 - in kukit/bluekit/trunk: . .bzr .bzr/branch .bzr/branch-lock .bzr/branch/lock .bzr/checkout .bzr/checkout/lock browser Message-ID: <20060622200400.B1DD910069@code0.codespeak.net> Author: reebalazs Date: Thu Jun 22 22:03:56 2006 New Revision: 29177 Added: kukit/bluekit/trunk/ kukit/bluekit/trunk/.bzr/ kukit/bluekit/trunk/.bzr/README kukit/bluekit/trunk/.bzr/branch/ kukit/bluekit/trunk/.bzr/branch-format kukit/bluekit/trunk/.bzr/branch-lock/ kukit/bluekit/trunk/.bzr/branch/branch-name kukit/bluekit/trunk/.bzr/branch/format kukit/bluekit/trunk/.bzr/branch/lock/ kukit/bluekit/trunk/.bzr/branch/revision-history kukit/bluekit/trunk/.bzr/checkout/ kukit/bluekit/trunk/.bzr/checkout/basis-inventory kukit/bluekit/trunk/.bzr/checkout/conflicts kukit/bluekit/trunk/.bzr/checkout/format kukit/bluekit/trunk/.bzr/checkout/inventory kukit/bluekit/trunk/.bzr/checkout/last-revision kukit/bluekit/trunk/.bzr/checkout/lock/ kukit/bluekit/trunk/.bzr/checkout/merge-hashes kukit/bluekit/trunk/.bzr/checkout/pending-merges kukit/bluekit/trunk/.bzr/checkout/stat-cache kukit/bluekit/trunk/__init__.py kukit/bluekit/trunk/bluekitview.py kukit/bluekit/trunk/browser/ kukit/bluekit/trunk/browser/bluekit.js (contents, props changed) kukit/bluekit/trunk/browser/bluekit.kss kukit/bluekit/trunk/browser/bluekitdemo1.html (contents, props changed) kukit/bluekit/trunk/browser/mockup.js (contents, props changed) kukit/bluekit/trunk/browser/prototype.js (contents, props changed) kukit/bluekit/trunk/browser/simple.html (contents, props changed) kukit/bluekit/trunk/browser/update.html (contents, props changed) kukit/bluekit/trunk/configure.zcml Log: Initial import Added: kukit/bluekit/trunk/.bzr/README ============================================================================== --- (empty file) +++ kukit/bluekit/trunk/.bzr/README Thu Jun 22 22:03:56 2006 @@ -0,0 +1,2 @@ +This is a Bazaar-NG control directory. +Do not change any files in this directory. Added: kukit/bluekit/trunk/.bzr/branch-format ============================================================================== --- (empty file) +++ kukit/bluekit/trunk/.bzr/branch-format Thu Jun 22 22:03:56 2006 @@ -0,0 +1 @@ +Bazaar-NG meta directory, format 1 Added: kukit/bluekit/trunk/.bzr/branch/branch-name ============================================================================== Added: kukit/bluekit/trunk/.bzr/branch/format ============================================================================== --- (empty file) +++ kukit/bluekit/trunk/.bzr/branch/format Thu Jun 22 22:03:56 2006 @@ -0,0 +1 @@ +Bazaar-NG branch format 5 Added: kukit/bluekit/trunk/.bzr/branch/revision-history ============================================================================== --- (empty file) +++ kukit/bluekit/trunk/.bzr/branch/revision-history Thu Jun 22 22:03:56 2006 @@ -0,0 +1,8 @@ +ree at greenfinity.hu-20060620164433-47ae3b66ed431c5c +ree at greenfinity.hu-20060620202538-8cf91bdac5672f36 +ree at greenfinity.hu-20060620202911-bc13ff4f75a7a657 +ree at greenfinity.hu-20060620204244-945cc4d71100547f +ree at greenfinity.hu-20060621094005-a632fb77ec258a23 +ree at greenfinity.hu-20060621160202-b654e0c2510e1423 +ree at greenfinity.hu-20060622102057-ad37769d3b1f8dc0 +ree at greenfinity.hu-20060622195611-b3b8b1a39a7a156b \ No newline at end of file Added: kukit/bluekit/trunk/.bzr/checkout/basis-inventory ============================================================================== --- (empty file) +++ kukit/bluekit/trunk/.bzr/checkout/basis-inventory Thu Jun 22 22:03:56 2006 @@ -0,0 +1,13 @@ + + + + + + + + + + + + + Added: kukit/bluekit/trunk/.bzr/checkout/conflicts ============================================================================== --- (empty file) +++ kukit/bluekit/trunk/.bzr/checkout/conflicts Thu Jun 22 22:03:56 2006 @@ -0,0 +1 @@ +BZR conflict list format 1 Added: kukit/bluekit/trunk/.bzr/checkout/format ============================================================================== --- (empty file) +++ kukit/bluekit/trunk/.bzr/checkout/format Thu Jun 22 22:03:56 2006 @@ -0,0 +1 @@ +Bazaar-NG Working Tree format 3 \ No newline at end of file Added: kukit/bluekit/trunk/.bzr/checkout/inventory ============================================================================== --- (empty file) +++ kukit/bluekit/trunk/.bzr/checkout/inventory Thu Jun 22 22:03:56 2006 @@ -0,0 +1,13 @@ + + + + + + + + + + + + + Added: kukit/bluekit/trunk/.bzr/checkout/last-revision ============================================================================== --- (empty file) +++ kukit/bluekit/trunk/.bzr/checkout/last-revision Thu Jun 22 22:03:56 2006 @@ -0,0 +1 @@ +ree at greenfinity.hu-20060622195611-b3b8b1a39a7a156b \ No newline at end of file Added: kukit/bluekit/trunk/.bzr/checkout/merge-hashes ============================================================================== --- (empty file) +++ kukit/bluekit/trunk/.bzr/checkout/merge-hashes Thu Jun 22 22:03:56 2006 @@ -0,0 +1 @@ +BZR merge-modified list format 1 Added: kukit/bluekit/trunk/.bzr/checkout/pending-merges ============================================================================== Added: kukit/bluekit/trunk/.bzr/checkout/stat-cache ============================================================================== --- (empty file) +++ kukit/bluekit/trunk/.bzr/checkout/stat-cache Thu Jun 22 22:03:56 2006 @@ -0,0 +1,16 @@ +### bzr hashcache v5 +browser/bluekit.kss// ef7ba3cd31d63d08436acda4dafa8a12983016fe 104 1150991870 1150991870 720276 769 33204 +configure.zcml// 0bd4ce26e3d20b18ec3e55271b7b18e58461137f 1667 1150968322 1150968322 967969 769 33188 +browser/kukitsimple.html// bb619da813541063be392b5533c8af202da007c6 22 1150823772 1150835265 1080474 769 33252 +browser/kukitsimple.txt// bb619da813541063be392b5533c8af202da007c6 22 1150823772 1150834941 1080474 769 33252 +browser/simple.html// d10806ec5abdec08c31e7819ff69be518db6c553 41 1150902109 1150902109 167294 769 33252 +browser/prototype.js// 3b91e2e77fb52eb876bb38ad92394a050eb27006 55149 1150824397 1150824397 21849 769 33252 +__init__.py// a1d3c51a42818d174d39fe68ad2092d497536aa6 22 1150824563 1150824563 1080495 769 33188 +bluekitview.py// dea46299262ee5dab0921668fe71c44cc487c8cf 1537 1150905265 1150905265 588405 769 33204 +browser/simple.txt// 0a03e3b6cb90e3c9c9a38c5922723f4f8487f1f8 14 1150823772 1150834423 1080480 769 33252 +browser/update.html// df4ef1db11ba8836064975b886ed2f075de9be76 30 1150823772 1150824014 1080479 769 33252 +browser/bluekitdemo1.html// 17399f748e3700e996f56184f5615cd8f780cbdc 1110 1150968815 1150968815 710247 769 33252 +browser/blukitdemo1.html// 6fd4bf9c38786cc8d3bb57e9d6d994e58fcc43e6 549 1150821516 1150821516 325167 769 33216 +browser/bluekit.js// 673f8968e2e140e86de6b6d5c9c37aea39381505 2836 1150969171 1150969171 594988 769 33252 +browser/mockup.js// 6558c27addae67fe5515569f0a89d2427a774d19 1160 1150991846 1150991846 209927 769 33252 +browser/kukitupdate.html// 938a4f3f8d23a993116cf2aab6bbecbbc8fa51fa 36 1150823772 1150824014 1080478 769 33252 Added: kukit/bluekit/trunk/__init__.py ============================================================================== --- (empty file) +++ kukit/bluekit/trunk/__init__.py Thu Jun 22 22:03:56 2006 @@ -0,0 +1,4 @@ +'''\ +Module init +''' + Added: kukit/bluekit/trunk/bluekitview.py ============================================================================== --- (empty file) +++ kukit/bluekit/trunk/bluekitview.py Thu Jun 22 22:03:56 2006 @@ -0,0 +1,41 @@ +# -*- coding: ISO-8859-15 -*- +# Copyright (c) 2005 +# Authors: +# Godefroid Chapelle +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License version 2 as published +# by the Free Software Foundation. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA +# 02111-1307, USA. +# + +from Products.azax import AzaxBaseView +from Products.azax.parsers import XmlParser, HtmlParser +import datetime + +from zope.app.pagetemplate.viewpagetemplatefile import ViewPageTemplateFile + +class BluekitView(AzaxBaseView): + + def prototypeResponse(self, new_value): + command = self.addCommand('prototypeResponse') + data = command.addParam('html', '' % (new_value, )) + + def doBluekit(self): + self.setHtmlAsChild('div#demo', '

    it worked

    ') + self.prototypeResponse('

    patched again

    and again

    ') + return self.render() + + def doBluekitUpdate(self): + self.setHtmlAsChild('div#demo', '

    Update worked

    ') + self.prototypeResponse('

    we did it

    again

    ') + return self.render() Added: kukit/bluekit/trunk/browser/bluekit.js ============================================================================== --- (empty file) +++ kukit/bluekit/trunk/browser/bluekit.js Thu Jun 22 22:03:56 2006 @@ -0,0 +1,96 @@ +var Bluekit = { + monkeypatch: function(instance, method_name, new_function) { + instance["old_"+method_name] = instance[method_name].bind(instance); + instance[method_name] = new_function.bind(instance); + }, + getTransport: function() { + return new Bluekit.Transport(this.old_getTransport()); + }, + kukitComplete: function(transport, object) { + kukit.logDebug('parse kukit commands'); + kukit.processResult(transport); + this.old_onComplete(transport, object); + }, + injectKukitRequestAndCommands: function(request, transport) { + /* patch for commands parser */ + if (request.options.onComplete) { + Bluekit.monkeypatch(request.options, 'onComplete', Bluekit.kukitComplete); + }; + }, + setup: function() { + Ajax.Responders.register({ + onCreate: Bluekit.injectKukitRequestAndCommands + }); + Bluekit.monkeypatch(Ajax, 'getTransport', Bluekit.getTransport); + } +}; + +Bluekit.Transport = function(transport) { + this._transport = transport; + this._headers = $H(); + this.onreadystatechange = Prototype.emptyFunction.bind(this); + this._patchOnreadystatechange = function() { + try { + this.status = this._transport.status; + } + catch (e) {}; + try { + this.overrideMimeType = this._transport.overrideMimeType; + } + catch (e) {}; + try { + this.readyState = this._transport.readyState; + } + catch (e) {}; + try { + this.responseText = this._transport.responseText; + } + catch (e) {}; + try { + this.responseXML = this._transport.responseXML; + } + catch (e) {}; + this.onreadystatechange(); + }; + this._transport.onreadystatechange = + this._patchOnreadystatechange.bind(this); +}; + +Bluekit.Transport.prototype = { + getResponseHeader : function(name) { + this._transport.getResponseHeader(name); + }, + + /* store values for deferred call */ + open : function(method, url, asynchronous) { + this._method = method; + this._url = url; + this._asynchronous = asynchronous; + }, + + /* store values for deferred call */ + setRequestHeader : function(key, value) { + this._headers[key] = value; + }, + + setRequestHeaderIterator : function(key) { + this._transport.setRequestHeader(key, this._headers[key]); + }, + + /* actually make the call */ + send : function(body) { + var self = this; + var f = function() { + self._transport.open(self._method, self._url, self._asynchronous); + self._headers.keys().each(self.setRequestHeaderIterator.bind(self)); + self._transport.send(body); + }; + kukit.requestManager.notifyServer(f, this._url); + + + } + +}; + + +Bluekit.setup(); Added: kukit/bluekit/trunk/browser/bluekit.kss ============================================================================== --- (empty file) +++ kukit/bluekit/trunk/browser/bluekit.kss Thu Jun 22 22:03:56 2006 @@ -0,0 +1,5 @@ + +#buttonupdate:bluekit-update { + default-url: kukitupdate.html; + default-nodeid: target; +} Added: kukit/bluekit/trunk/browser/bluekitdemo1.html ============================================================================== --- (empty file) +++ kukit/bluekit/trunk/browser/bluekitdemo1.html Thu Jun 22 22:03:56 2006 @@ -0,0 +1,33 @@ + + + + + + + + + + + + +
    Here it goes.
    + + +
    Target
    + + Added: kukit/bluekit/trunk/browser/mockup.js ============================================================================== --- (empty file) +++ kukit/bluekit/trunk/browser/mockup.js Thu Jun 22 22:03:56 2006 @@ -0,0 +1,45 @@ +var Foo = Class.create(); +Foo.prototype = { + initialize : function() {}, + update : function(nodeid, url) { + new Ajax.Updater($(nodeid), url); + } +}; + +// new Ajax.Updater($('target'), 'update.html'); + +//var foo = new Foo(); + +kukit.er.eventClassRegistry.register('update', Foo); +kukit.er.eventRegistry.register('bluekit', 'update', 'update', '__bind__', '__exec__'); + +Foo.prototype.__bind__ = function(name, parms, func_to_bind, node) { + kukit.registerEventListener(node, 'click', func_to_bind); + return true; +}; + +Foo.prototype.__exec__ = function(name, parms, node) { + parms = kukit.pl.completeParms(parms, ['nodeid', 'url'], {}); + this.update(parms.nodeid, parms.url); + return true; +}; + +// + + +var click = function() { + new Ajax.Request('simple.txt', { + onComplete : function(transport, object) { + alert('FROM click: ' +transport.responseText); + //alert('XMLFROM click: ' +transport.responseXML); + } + }); +}; + +var load = function() { + Event.observe($('buttonclick'), 'click', click); + //Event.observe($('buttonupdate'), 'click', foo.update, false); +} + +Event.observe(window, 'load', load, false); + Added: kukit/bluekit/trunk/browser/prototype.js ============================================================================== --- (empty file) +++ kukit/bluekit/trunk/browser/prototype.js Thu Jun 22 22:03:56 2006 @@ -0,0 +1,2005 @@ +/* Prototype JavaScript framework, version 1.5.0_rc0 + * (c) 2005 Sam Stephenson + * + * Prototype is freely distributable under the terms of an MIT-style license. + * For details, see the Prototype web site: http://prototype.conio.net/ + * +/*--------------------------------------------------------------------------*/ + +var Prototype = { + Version: '1.5.0_rc0', + ScriptFragment: '(?:)((\n|\r|.)*?)(?:<\/script>)', + + emptyFunction: function() {}, + K: function(x) {return x} +} + +var Class = { + create: function() { + return function() { + this.initialize.apply(this, arguments); + } + } +} + +var Abstract = new Object(); + +Object.extend = function(destination, source) { + for (var property in source) { + destination[property] = source[property]; + } + return destination; +} + +Object.inspect = function(object) { + try { + if (object == undefined) return 'undefined'; + if (object == null) return 'null'; + return object.inspect ? object.inspect() : object.toString(); + } catch (e) { + if (e instanceof RangeError) return '...'; + throw e; + } +} + +Function.prototype.bind = function() { + var __method = this, args = $A(arguments), object = args.shift(); + return function() { + return __method.apply(object, args.concat($A(arguments))); + } +} + +Function.prototype.bindAsEventListener = function(object) { + var __method = this; + return function(event) { + return __method.call(object, event || window.event); + } +} + +Object.extend(Number.prototype, { + toColorPart: function() { + var digits = this.toString(16); + if (this < 16) return '0' + digits; + return digits; + }, + + succ: function() { + return this + 1; + }, + + times: function(iterator) { + $R(0, this, true).each(iterator); + return this; + } +}); + +var Try = { + these: function() { + var returnValue; + + for (var i = 0; i < arguments.length; i++) { + var lambda = arguments[i]; + try { + returnValue = lambda(); + break; + } catch (e) {} + } + + return returnValue; + } +} + +/*--------------------------------------------------------------------------*/ + +var PeriodicalExecuter = Class.create(); +PeriodicalExecuter.prototype = { + initialize: function(callback, frequency) { + this.callback = callback; + this.frequency = frequency; + this.currentlyExecuting = false; + + this.registerCallback(); + }, + + registerCallback: function() { + setInterval(this.onTimerEvent.bind(this), this.frequency * 1000); + }, + + onTimerEvent: function() { + if (!this.currentlyExecuting) { + try { + this.currentlyExecuting = true; + this.callback(); + } finally { + this.currentlyExecuting = false; + } + } + } +} +Object.extend(String.prototype, { + gsub: function(pattern, replacement) { + var result = '', source = this, match; + replacement = arguments.callee.prepareReplacement(replacement); + + while (source.length > 0) { + if (match = source.match(pattern)) { + result += source.slice(0, match.index); + result += (replacement(match) || '').toString(); + source = source.slice(match.index + match[0].length); + } else { + result += source, source = ''; + } + } + return result; + }, + + sub: function(pattern, replacement, count) { + replacement = this.gsub.prepareReplacement(replacement); + count = count === undefined ? 1 : count; + + return this.gsub(pattern, function(match) { + if (--count < 0) return match[0]; + return replacement(match); + }); + }, + + scan: function(pattern, iterator) { + this.gsub(pattern, iterator); + return this; + }, + + truncate: function(length, truncation) { + length = length || 30; + truncation = truncation === undefined ? '...' : truncation; + return this.length > length ? + this.slice(0, length - truncation.length) + truncation : this; + }, + + strip: function() { + return this.replace(/^\s+/, '').replace(/\s+$/, ''); + }, + + stripTags: function() { + return this.replace(/<\/?[^>]+>/gi, ''); + }, + + stripScripts: function() { + return this.replace(new RegExp(Prototype.ScriptFragment, 'img'), ''); + }, + + extractScripts: function() { + var matchAll = new RegExp(Prototype.ScriptFragment, 'img'); + var matchOne = new RegExp(Prototype.ScriptFragment, 'im'); + return (this.match(matchAll) || []).map(function(scriptTag) { + return (scriptTag.match(matchOne) || ['', ''])[1]; + }); + }, + + evalScripts: function() { + return this.extractScripts().map(function(script) { return eval(script) }); + }, + + escapeHTML: function() { + var div = document.createElement('div'); + var text = document.createTextNode(this); + div.appendChild(text); + return div.innerHTML; + }, + + unescapeHTML: function() { + var div = document.createElement('div'); + div.innerHTML = this.stripTags(); + return div.childNodes[0] ? div.childNodes[0].nodeValue : ''; + }, + + toQueryParams: function() { + var pairs = this.match(/^\??(.*)$/)[1].split('&'); + return pairs.inject({}, function(params, pairString) { + var pair = pairString.split('='); + params[pair[0]] = pair[1]; + return params; + }); + }, + + toArray: function() { + return this.split(''); + }, + + camelize: function() { + var oStringList = this.split('-'); + if (oStringList.length == 1) return oStringList[0]; + + var camelizedString = this.indexOf('-') == 0 + ? oStringList[0].charAt(0).toUpperCase() + oStringList[0].substring(1) + : oStringList[0]; + + for (var i = 1, len = oStringList.length; i < len; i++) { + var s = oStringList[i]; + camelizedString += s.charAt(0).toUpperCase() + s.substring(1); + } + + return camelizedString; + }, + + inspect: function() { + return "'" + this.replace(/\\/g, '\\\\').replace(/'/g, '\\\'') + "'"; + } +}); + +String.prototype.gsub.prepareReplacement = function(replacement) { + if (typeof replacement == 'function') return replacement; + var template = new Template(replacement); + return function(match) { return template.evaluate(match) }; +} + +String.prototype.parseQuery = String.prototype.toQueryParams; + +var Template = Class.create(); +Template.Pattern = /(^|.|\r|\n)(#\{(.*?)\})/; +Template.prototype = { + initialize: function(template, pattern) { + this.template = template.toString(); + this.pattern = pattern || Template.Pattern; + }, + + evaluate: function(object) { + return this.template.gsub(this.pattern, function(match) { + var before = match[1]; + if (before == '\\') return match[2]; + return before + (object[match[3]] || '').toString(); + }); + } +} + +var $break = new Object(); +var $continue = new Object(); + +var Enumerable = { + each: function(iterator) { + var index = 0; + try { + this._each(function(value) { + try { + iterator(value, index++); + } catch (e) { + if (e != $continue) throw e; + } + }); + } catch (e) { + if (e != $break) throw e; + } + }, + + all: function(iterator) { + var result = true; + this.each(function(value, index) { + result = result && !!(iterator || Prototype.K)(value, index); + if (!result) throw $break; + }); + return result; + }, + + any: function(iterator) { + var result = true; + this.each(function(value, index) { + if (result = !!(iterator || Prototype.K)(value, index)) + throw $break; + }); + return result; + }, + + collect: function(iterator) { + var results = []; + this.each(function(value, index) { + results.push(iterator(value, index)); + }); + return results; + }, + + detect: function (iterator) { + var result; + this.each(function(value, index) { + if (iterator(value, index)) { + result = value; + throw $break; + } + }); + return result; + }, + + findAll: function(iterator) { + var results = []; + this.each(function(value, index) { + if (iterator(value, index)) + results.push(value); + }); + return results; + }, + + grep: function(pattern, iterator) { + var results = []; + this.each(function(value, index) { + var stringValue = value.toString(); + if (stringValue.match(pattern)) + results.push((iterator || Prototype.K)(value, index)); + }) + return results; + }, + + include: function(object) { + var found = false; + this.each(function(value) { + if (value == object) { + found = true; + throw $break; + } + }); + return found; + }, + + inject: function(memo, iterator) { + this.each(function(value, index) { + memo = iterator(memo, value, index); + }); + return memo; + }, + + invoke: function(method) { + var args = $A(arguments).slice(1); + return this.collect(function(value) { + return value[method].apply(value, args); + }); + }, + + max: function(iterator) { + var result; + this.each(function(value, index) { + value = (iterator || Prototype.K)(value, index); + if (result == undefined || value >= result) + result = value; + }); + return result; + }, + + min: function(iterator) { + var result; + this.each(function(value, index) { + value = (iterator || Prototype.K)(value, index); + if (result == undefined || value < result) + result = value; + }); + return result; + }, + + partition: function(iterator) { + var trues = [], falses = []; + this.each(function(value, index) { + ((iterator || Prototype.K)(value, index) ? + trues : falses).push(value); + }); + return [trues, falses]; + }, + + pluck: function(property) { + var results = []; + this.each(function(value, index) { + results.push(value[property]); + }); + return results; + }, + + reject: function(iterator) { + var results = []; + this.each(function(value, index) { + if (!iterator(value, index)) + results.push(value); + }); + return results; + }, + + sortBy: function(iterator) { + return this.collect(function(value, index) { + return {value: value, criteria: iterator(value, index)}; + }).sort(function(left, right) { + var a = left.criteria, b = right.criteria; + return a < b ? -1 : a > b ? 1 : 0; + }).pluck('value'); + }, + + toArray: function() { + return this.collect(Prototype.K); + }, + + zip: function() { + var iterator = Prototype.K, args = $A(arguments); + if (typeof args.last() == 'function') + iterator = args.pop(); + + var collections = [this].concat(args).map($A); + return this.map(function(value, index) { + return iterator(collections.pluck(index)); + }); + }, + + inspect: function() { + return '#'; + } +} + +Object.extend(Enumerable, { + map: Enumerable.collect, + find: Enumerable.detect, + select: Enumerable.findAll, + member: Enumerable.include, + entries: Enumerable.toArray +}); +var $A = Array.from = function(iterable) { + if (!iterable) return []; + if (iterable.toArray) { + return iterable.toArray(); + } else { + var results = []; + for (var i = 0; i < iterable.length; i++) + results.push(iterable[i]); + return results; + } +} + +Object.extend(Array.prototype, Enumerable); + +if (!Array.prototype._reverse) + Array.prototype._reverse = Array.prototype.reverse; + +Object.extend(Array.prototype, { + _each: function(iterator) { + for (var i = 0; i < this.length; i++) + iterator(this[i]); + }, + + clear: function() { + this.length = 0; + return this; + }, + + first: function() { + return this[0]; + }, + + last: function() { + return this[this.length - 1]; + }, + + compact: function() { + return this.select(function(value) { + return value != undefined || value != null; + }); + }, + + flatten: function() { + return this.inject([], function(array, value) { + return array.concat(value && value.constructor == Array ? + value.flatten() : [value]); + }); + }, + + without: function() { + var values = $A(arguments); + return this.select(function(value) { + return !values.include(value); + }); + }, + + indexOf: function(object) { + for (var i = 0; i < this.length; i++) + if (this[i] == object) return i; + return -1; + }, + + reverse: function(inline) { + return (inline !== false ? this : this.toArray())._reverse(); + }, + + inspect: function() { + return '[' + this.map(Object.inspect).join(', ') + ']'; + } +}); +var Hash = { + _each: function(iterator) { + for (var key in this) { + var value = this[key]; + if (typeof value == 'function') continue; + + var pair = [key, value]; + pair.key = key; + pair.value = value; + iterator(pair); + } + }, + + keys: function() { + return this.pluck('key'); + }, + + values: function() { + return this.pluck('value'); + }, + + merge: function(hash) { + return $H(hash).inject($H(this), function(mergedHash, pair) { + mergedHash[pair.key] = pair.value; + return mergedHash; + }); + }, + + toQueryString: function() { + return this.map(function(pair) { + return pair.map(encodeURIComponent).join('='); + }).join('&'); + }, + + inspect: function() { + return '#'; + } +} + +function $H(object) { + var hash = Object.extend({}, object || {}); + Object.extend(hash, Enumerable); + Object.extend(hash, Hash); + return hash; +} +ObjectRange = Class.create(); +Object.extend(ObjectRange.prototype, Enumerable); +Object.extend(ObjectRange.prototype, { + initialize: function(start, end, exclusive) { + this.start = start; + this.end = end; + this.exclusive = exclusive; + }, + + _each: function(iterator) { + var value = this.start; + do { + iterator(value); + value = value.succ(); + } while (this.include(value)); + }, + + include: function(value) { + if (value < this.start) + return false; + if (this.exclusive) + return value < this.end; + return value <= this.end; + } +}); + +var $R = function(start, end, exclusive) { + return new ObjectRange(start, end, exclusive); +} + +var Ajax = { + getTransport: function() { + return Try.these( + function() {return new XMLHttpRequest()}, + function() {return new ActiveXObject('Msxml2.XMLHTTP')}, + function() {return new ActiveXObject('Microsoft.XMLHTTP')} + ) || false; + }, + + activeRequestCount: 0 +} + +Ajax.Responders = { + responders: [], + + _each: function(iterator) { + this.responders._each(iterator); + }, + + register: function(responderToAdd) { + if (!this.include(responderToAdd)) + this.responders.push(responderToAdd); + }, + + unregister: function(responderToRemove) { + this.responders = this.responders.without(responderToRemove); + }, + + dispatch: function(callback, request, transport, json) { + this.each(function(responder) { + if (responder[callback] && typeof responder[callback] == 'function') { + try { + responder[callback].apply(responder, [request, transport, json]); + } catch (e) {} + } + }); + } +}; + +Object.extend(Ajax.Responders, Enumerable); + +Ajax.Responders.register({ + onCreate: function() { + Ajax.activeRequestCount++; + }, + + onComplete: function() { + Ajax.activeRequestCount--; + } +}); + +Ajax.Base = function() {}; +Ajax.Base.prototype = { + setOptions: function(options) { + this.options = { + method: 'post', + asynchronous: true, + contentType: 'application/x-www-form-urlencoded', + parameters: '' + } + Object.extend(this.options, options || {}); + }, + + responseIsSuccess: function() { + return this.transport.status == undefined + || this.transport.status == 0 + || (this.transport.status >= 200 && this.transport.status < 300); + }, + + responseIsFailure: function() { + return !this.responseIsSuccess(); + } +} + +Ajax.Request = Class.create(); +Ajax.Request.Events = + ['Uninitialized', 'Loading', 'Loaded', 'Interactive', 'Complete']; + +Ajax.Request.prototype = Object.extend(new Ajax.Base(), { + initialize: function(url, options) { + this.transport = Ajax.getTransport(); + this.setOptions(options); + this.request(url); + }, + + request: function(url) { + var parameters = this.options.parameters || ''; + if (parameters.length > 0) parameters += '&_='; + + try { + this.url = url; + if (this.options.method == 'get' && parameters.length > 0) + this.url += (this.url.match(/\?/) ? '&' : '?') + parameters; + + Ajax.Responders.dispatch('onCreate', this, this.transport); + + this.transport.open(this.options.method, this.url, + this.options.asynchronous); + + if (this.options.asynchronous) { + this.transport.onreadystatechange = this.onStateChange.bind(this); + setTimeout((function() {this.respondToReadyState(1)}).bind(this), 10); + } + + this.setRequestHeaders(); + + var body = this.options.postBody ? this.options.postBody : parameters; + this.transport.send(this.options.method == 'post' ? body : null); + + } catch (e) { + this.dispatchException(e); + } + }, + + setRequestHeaders: function() { + var requestHeaders = + ['X-Requested-With', 'XMLHttpRequest', + 'X-Prototype-Version', Prototype.Version, + 'Accept', 'text/javascript, text/html, application/xml, text/xml, */*']; + + if (this.options.method == 'post') { + requestHeaders.push('Content-type', this.options.contentType); + + /* Force "Connection: close" for Mozilla browsers to work around + * a bug where XMLHttpReqeuest sends an incorrect Content-length + * header. See Mozilla Bugzilla #246651. + */ + if (this.transport.overrideMimeType) + requestHeaders.push('Connection', 'close'); + } + + if (this.options.requestHeaders) + requestHeaders.push.apply(requestHeaders, this.options.requestHeaders); + + for (var i = 0; i < requestHeaders.length; i += 2) + this.transport.setRequestHeader(requestHeaders[i], requestHeaders[i+1]); + }, + + onStateChange: function() { + var readyState = this.transport.readyState; + if (readyState != 1) + this.respondToReadyState(this.transport.readyState); + }, + + header: function(name) { + try { + return this.transport.getResponseHeader(name); + } catch (e) {} + }, + + evalJSON: function() { + try { + return eval('(' + this.header('X-JSON') + ')'); + } catch (e) {} + }, + + evalResponse: function() { + try { + return eval(this.transport.responseText); + } catch (e) { + this.dispatchException(e); + } + }, + + respondToReadyState: function(readyState) { + var event = Ajax.Request.Events[readyState]; + var transport = this.transport, json = this.evalJSON(); + + if (event == 'Complete') { + try { + (this.options['on' + this.transport.status] + || this.options['on' + (this.responseIsSuccess() ? 'Success' : 'Failure')] + || Prototype.emptyFunction)(transport, json); + } catch (e) { + this.dispatchException(e); + } + + if ((this.header('Content-type') || '').match(/^text\/javascript/i)) + this.evalResponse(); + } + + try { + (this.options['on' + event] || Prototype.emptyFunction)(transport, json); + Ajax.Responders.dispatch('on' + event, this, transport, json); + } catch (e) { + this.dispatchException(e); + } + + /* Avoid memory leak in MSIE: clean up the oncomplete event handler */ + if (event == 'Complete') + this.transport.onreadystatechange = Prototype.emptyFunction; + }, + + dispatchException: function(exception) { + (this.options.onException || Prototype.emptyFunction)(this, exception); + Ajax.Responders.dispatch('onException', this, exception); + } +}); + +Ajax.Updater = Class.create(); + +Object.extend(Object.extend(Ajax.Updater.prototype, Ajax.Request.prototype), { + initialize: function(container, url, options) { + this.containers = { + success: container.success ? $(container.success) : $(container), + failure: container.failure ? $(container.failure) : + (container.success ? null : $(container)) + } + + this.transport = Ajax.getTransport(); + this.setOptions(options); + + var onComplete = this.options.onComplete || Prototype.emptyFunction; + this.options.onComplete = (function(transport, object) { + this.updateContent(); + onComplete(transport, object); + }).bind(this); + + this.request(url); + }, + + updateContent: function() { + var receiver = this.responseIsSuccess() ? + this.containers.success : this.containers.failure; + var response = this.transport.responseText; + if (!this.options.evalScripts) + response = response.stripScripts(); + + if (receiver) { + if (this.options.insertion) { + new this.options.insertion(receiver, response); + } else { + Element.update(receiver, response); + } + } + + if (this.responseIsSuccess()) { + if (this.onComplete) + setTimeout(this.onComplete.bind(this), 10); + } + } +}); + +Ajax.PeriodicalUpdater = Class.create(); +Ajax.PeriodicalUpdater.prototype = Object.extend(new Ajax.Base(), { + initialize: function(container, url, options) { + this.setOptions(options); + this.onComplete = this.options.onComplete; + + this.frequency = (this.options.frequency || 2); + this.decay = (this.options.decay || 1); + + this.updater = {}; + this.container = container; + this.url = url; + + this.start(); + }, + + start: function() { + this.options.onComplete = this.updateComplete.bind(this); + this.onTimerEvent(); + }, + + stop: function() { + this.updater.onComplete = undefined; + clearTimeout(this.timer); + (this.onComplete || Prototype.emptyFunction).apply(this, arguments); + }, + + updateComplete: function(request) { + if (this.options.decay) { + this.decay = (request.responseText == this.lastText ? + this.decay * this.options.decay : 1); + + this.lastText = request.responseText; + } + this.timer = setTimeout(this.onTimerEvent.bind(this), + this.decay * this.frequency * 1000); + }, + + onTimerEvent: function() { + this.updater = new Ajax.Updater(this.container, this.url, this.options); + } +}); +function $() { + var results = [], element; + for (var i = 0; i < arguments.length; i++) { + element = arguments[i]; + if (typeof element == 'string') + element = document.getElementById(element); + results.push(Element.extend(element)); + } + return results.length < 2 ? results[0] : results; +} + +document.getElementsByClassName = function(className, parentElement) { + var children = ($(parentElement) || document.body).getElementsByTagName('*'); + return $A(children).inject([], function(elements, child) { + if (child.className.match(new RegExp("(^|\\s)" + className + "(\\s|$)"))) + elements.push(Element.extend(child)); + return elements; + }); +} + +/*--------------------------------------------------------------------------*/ + +if (!window.Element) + var Element = new Object(); + +Element.extend = function(element) { + if (!element) return; + if (_nativeExtensions) return element; + + if (!element._extended && element.tagName && element != window) { + var methods = Element.Methods, cache = Element.extend.cache; + for (property in methods) { + var value = methods[property]; + if (typeof value == 'function') + element[property] = cache.findOrStore(value); + } + } + + element._extended = true; + return element; +} + +Element.extend.cache = { + findOrStore: function(value) { + return this[value] = this[value] || function() { + return value.apply(null, [this].concat($A(arguments))); + } + } +} + +Element.Methods = { + visible: function(element) { + return $(element).style.display != 'none'; + }, + + toggle: function() { + for (var i = 0; i < arguments.length; i++) { + var element = $(arguments[i]); + Element[Element.visible(element) ? 'hide' : 'show'](element); + } + }, + + hide: function() { + for (var i = 0; i < arguments.length; i++) { + var element = $(arguments[i]); + element.style.display = 'none'; + } + }, + + show: function() { + for (var i = 0; i < arguments.length; i++) { + var element = $(arguments[i]); + element.style.display = ''; + } + }, + + remove: function(element) { + element = $(element); + element.parentNode.removeChild(element); + }, + + update: function(element, html) { + $(element).innerHTML = html.stripScripts(); + setTimeout(function() {html.evalScripts()}, 10); + }, + + replace: function(element, html) { + element = $(element); + if (element.outerHTML) { + element.outerHTML = html.stripScripts(); + } else { + var range = element.ownerDocument.createRange(); + range.selectNodeContents(element); + element.parentNode.replaceChild( + range.createContextualFragment(html.stripScripts()), element); + } + setTimeout(function() {html.evalScripts()}, 10); + }, + + getHeight: function(element) { + element = $(element); + return element.offsetHeight; + }, + + classNames: function(element) { + return new Element.ClassNames(element); + }, + + hasClassName: function(element, className) { + if (!(element = $(element))) return; + return Element.classNames(element).include(className); + }, + + addClassName: function(element, className) { + if (!(element = $(element))) return; + return Element.classNames(element).add(className); + }, + + removeClassName: function(element, className) { + if (!(element = $(element))) return; + return Element.classNames(element).remove(className); + }, + + // removes whitespace-only text node children + cleanWhitespace: function(element) { + element = $(element); + for (var i = 0; i < element.childNodes.length; i++) { + var node = element.childNodes[i]; + if (node.nodeType == 3 && !/\S/.test(node.nodeValue)) + Element.remove(node); + } + }, + + empty: function(element) { + return $(element).innerHTML.match(/^\s*$/); + }, + + childOf: function(element, ancestor) { + element = $(element), ancestor = $(ancestor); + while (element = element.parentNode) + if (element == ancestor) return true; + return false; + }, + + scrollTo: function(element) { + element = $(element); + var x = element.x ? element.x : element.offsetLeft, + y = element.y ? element.y : element.offsetTop; + window.scrollTo(x, y); + }, + + getStyle: function(element, style) { + element = $(element); + var value = element.style[style.camelize()]; + if (!value) { + if (document.defaultView && document.defaultView.getComputedStyle) { + var css = document.defaultView.getComputedStyle(element, null); + value = css ? css.getPropertyValue(style) : null; + } else if (element.currentStyle) { + value = element.currentStyle[style.camelize()]; + } + } + + if (window.opera && ['left', 'top', 'right', 'bottom'].include(style)) + if (Element.getStyle(element, 'position') == 'static') value = 'auto'; + + return value == 'auto' ? null : value; + }, + + setStyle: function(element, style) { + element = $(element); + for (var name in style) + element.style[name.camelize()] = style[name]; + }, + + getDimensions: function(element) { + element = $(element); + if (Element.getStyle(element, 'display') != 'none') + return {width: element.offsetWidth, height: element.offsetHeight}; + + // All *Width and *Height properties give 0 on elements with display none, + // so enable the element temporarily + var els = element.style; + var originalVisibility = els.visibility; + var originalPosition = els.position; + els.visibility = 'hidden'; + els.position = 'absolute'; + els.display = ''; + var originalWidth = element.clientWidth; + var originalHeight = element.clientHeight; + els.display = 'none'; + els.position = originalPosition; + els.visibility = originalVisibility; + return {width: originalWidth, height: originalHeight}; + }, + + makePositioned: function(element) { + element = $(element); + var pos = Element.getStyle(element, 'position'); + if (pos == 'static' || !pos) { + element._madePositioned = true; + element.style.position = 'relative'; + // Opera returns the offset relative to the positioning context, when an + // element is position relative but top and left have not been defined + if (window.opera) { + element.style.top = 0; + element.style.left = 0; + } + } + }, + + undoPositioned: function(element) { + element = $(element); + if (element._madePositioned) { + element._madePositioned = undefined; + element.style.position = + element.style.top = + element.style.left = + element.style.bottom = + element.style.right = ''; + } + }, + + makeClipping: function(element) { + element = $(element); + if (element._overflow) return; + element._overflow = element.style.overflow; + if ((Element.getStyle(element, 'overflow') || 'visible') != 'hidden') + element.style.overflow = 'hidden'; + }, + + undoClipping: function(element) { + element = $(element); + if (element._overflow) return; + element.style.overflow = element._overflow; + element._overflow = undefined; + } +} + +Object.extend(Element, Element.Methods); + +var _nativeExtensions = false; + +if(!HTMLElement && /Konqueror|Safari|KHTML/.test(navigator.userAgent)) { + var HTMLElement = {} + HTMLElement.prototype = document.createElement('div').__proto__; +} + +Element.addMethods = function(methods) { + Object.extend(Element.Methods, methods || {}); + + if(typeof HTMLElement != 'undefined') { + var methods = Element.Methods, cache = Element.extend.cache; + for (property in methods) { + var value = methods[property]; + if (typeof value == 'function') + HTMLElement.prototype[property] = cache.findOrStore(value); + } + _nativeExtensions = true; + } +} + +Element.addMethods(); + +var Toggle = new Object(); +Toggle.display = Element.toggle; + +/*--------------------------------------------------------------------------*/ + +Abstract.Insertion = function(adjacency) { + this.adjacency = adjacency; +} + +Abstract.Insertion.prototype = { + initialize: function(element, content) { + this.element = $(element); + this.content = content.stripScripts(); + + if (this.adjacency && this.element.insertAdjacentHTML) { + try { + this.element.insertAdjacentHTML(this.adjacency, this.content); + } catch (e) { + var tagName = this.element.tagName.toLowerCase(); + if (tagName == 'tbody' || tagName == 'tr') { + this.insertContent(this.contentFromAnonymousTable()); + } else { + throw e; + } + } + } else { + this.range = this.element.ownerDocument.createRange(); + if (this.initializeRange) this.initializeRange(); + this.insertContent([this.range.createContextualFragment(this.content)]); + } + + setTimeout(function() {content.evalScripts()}, 10); + }, + + contentFromAnonymousTable: function() { + var div = document.createElement('div'); + div.innerHTML = '' + this.content + '
    '; + return $A(div.childNodes[0].childNodes[0].childNodes); + } +} + +var Insertion = new Object(); + +Insertion.Before = Class.create(); +Insertion.Before.prototype = Object.extend(new Abstract.Insertion('beforeBegin'), { + initializeRange: function() { + this.range.setStartBefore(this.element); + }, + + insertContent: function(fragments) { + fragments.each((function(fragment) { + this.element.parentNode.insertBefore(fragment, this.element); + }).bind(this)); + } +}); + +Insertion.Top = Class.create(); +Insertion.Top.prototype = Object.extend(new Abstract.Insertion('afterBegin'), { + initializeRange: function() { + this.range.selectNodeContents(this.element); + this.range.collapse(true); + }, + + insertContent: function(fragments) { + fragments.reverse(false).each((function(fragment) { + this.element.insertBefore(fragment, this.element.firstChild); + }).bind(this)); + } +}); + +Insertion.Bottom = Class.create(); +Insertion.Bottom.prototype = Object.extend(new Abstract.Insertion('beforeEnd'), { + initializeRange: function() { + this.range.selectNodeContents(this.element); + this.range.collapse(this.element); + }, + + insertContent: function(fragments) { + fragments.each((function(fragment) { + this.element.appendChild(fragment); + }).bind(this)); + } +}); + +Insertion.After = Class.create(); +Insertion.After.prototype = Object.extend(new Abstract.Insertion('afterEnd'), { + initializeRange: function() { + this.range.setStartAfter(this.element); + }, + + insertContent: function(fragments) { + fragments.each((function(fragment) { + this.element.parentNode.insertBefore(fragment, + this.element.nextSibling); + }).bind(this)); + } +}); + +/*--------------------------------------------------------------------------*/ + +Element.ClassNames = Class.create(); +Element.ClassNames.prototype = { + initialize: function(element) { + this.element = $(element); + }, + + _each: function(iterator) { + this.element.className.split(/\s+/).select(function(name) { + return name.length > 0; + })._each(iterator); + }, + + set: function(className) { + this.element.className = className; + }, + + add: function(classNameToAdd) { + if (this.include(classNameToAdd)) return; + this.set(this.toArray().concat(classNameToAdd).join(' ')); + }, + + remove: function(classNameToRemove) { + if (!this.include(classNameToRemove)) return; + this.set(this.select(function(className) { + return className != classNameToRemove; + }).join(' ')); + }, + + toString: function() { + return this.toArray().join(' '); + } +} + +Object.extend(Element.ClassNames.prototype, Enumerable); +var Selector = Class.create(); +Selector.prototype = { + initialize: function(expression) { + this.params = {classNames: []}; + this.expression = expression.toString().strip(); + this.parseExpression(); + this.compileMatcher(); + }, + + parseExpression: function() { + function abort(message) { throw 'Parse error in selector: ' + message; } + + if (this.expression == '') abort('empty expression'); + + var params = this.params, expr = this.expression, match, modifier, clause, rest; + while (match = expr.match(/^(.*)\[([a-z0-9_:-]+?)(?:([~\|!]?=)(?:"([^"]*)"|([^\]\s]*)))?\]$/i)) { + params.attributes = params.attributes || []; + params.attributes.push({name: match[2], operator: match[3], value: match[4] || match[5] || ''}); + expr = match[1]; + } + + if (expr == '*') return this.params.wildcard = true; + + while (match = expr.match(/^([^a-z0-9_-])?([a-z0-9_-]+)(.*)/i)) { + modifier = match[1], clause = match[2], rest = match[3]; + switch (modifier) { + case '#': params.id = clause; break; + case '.': params.classNames.push(clause); break; + case '': + case undefined: params.tagName = clause.toUpperCase(); break; + default: abort(expr.inspect()); + } + expr = rest; + } + + if (expr.length > 0) abort(expr.inspect()); + }, + + buildMatchExpression: function() { + var params = this.params, conditions = [], clause; + + if (params.wildcard) + conditions.push('true'); + if (clause = params.id) + conditions.push('element.id == ' + clause.inspect()); + if (clause = params.tagName) + conditions.push('element.tagName.toUpperCase() == ' + clause.inspect()); + if ((clause = params.classNames).length > 0) + for (var i = 0; i < clause.length; i++) + conditions.push('Element.hasClassName(element, ' + clause[i].inspect() + ')'); + if (clause = params.attributes) { + clause.each(function(attribute) { + var value = 'element.getAttribute(' + attribute.name.inspect() + ')'; + var splitValueBy = function(delimiter) { + return value + ' && ' + value + '.split(' + delimiter.inspect() + ')'; + } + + switch (attribute.operator) { + case '=': conditions.push(value + ' == ' + attribute.value.inspect()); break; + case '~=': conditions.push(splitValueBy(' ') + '.include(' + attribute.value.inspect() + ')'); break; + case '|=': conditions.push( + splitValueBy('-') + '.first().toUpperCase() == ' + attribute.value.toUpperCase().inspect() + ); break; + case '!=': conditions.push(value + ' != ' + attribute.value.inspect()); break; + case '': + case undefined: conditions.push(value + ' != null'); break; + default: throw 'Unknown operator ' + attribute.operator + ' in selector'; + } + }); + } + + return conditions.join(' && '); + }, + + compileMatcher: function() { + this.match = new Function('element', 'if (!element.tagName) return false; \ + return ' + this.buildMatchExpression()); + }, + + findElements: function(scope) { + var element; + + if (element = $(this.params.id)) + if (this.match(element)) + if (!scope || Element.childOf(element, scope)) + return [element]; + + scope = (scope || document).getElementsByTagName(this.params.tagName || '*'); + + var results = []; + for (var i = 0; i < scope.length; i++) + if (this.match(element = scope[i])) + results.push(Element.extend(element)); + + return results; + }, + + toString: function() { + return this.expression; + } +} + +function $$() { + return $A(arguments).map(function(expression) { + return expression.strip().split(/\s+/).inject([null], function(results, expr) { + var selector = new Selector(expr); + return results.map(selector.findElements.bind(selector)).flatten(); + }); + }).flatten(); +} +var Field = { + clear: function() { + for (var i = 0; i < arguments.length; i++) + $(arguments[i]).value = ''; + }, + + focus: function(element) { + $(element).focus(); + }, + + present: function() { + for (var i = 0; i < arguments.length; i++) + if ($(arguments[i]).value == '') return false; + return true; + }, + + select: function(element) { + $(element).select(); + }, + + activate: function(element) { + element = $(element); + element.focus(); + if (element.select) + element.select(); + } +} + +/*--------------------------------------------------------------------------*/ + +var Form = { + serialize: function(form) { + var elements = Form.getElements($(form)); + var queryComponents = new Array(); + + for (var i = 0; i < elements.length; i++) { + var queryComponent = Form.Element.serialize(elements[i]); + if (queryComponent) + queryComponents.push(queryComponent); + } + + return queryComponents.join('&'); + }, + + getElements: function(form) { + form = $(form); + var elements = new Array(); + + for (var tagName in Form.Element.Serializers) { + var tagElements = form.getElementsByTagName(tagName); + for (var j = 0; j < tagElements.length; j++) + elements.push(tagElements[j]); + } + return elements; + }, + + getInputs: function(form, typeName, name) { + form = $(form); + var inputs = form.getElementsByTagName('input'); + + if (!typeName && !name) + return inputs; + + var matchingInputs = new Array(); + for (var i = 0; i < inputs.length; i++) { + var input = inputs[i]; + if ((typeName && input.type != typeName) || + (name && input.name != name)) + continue; + matchingInputs.push(input); + } + + return matchingInputs; + }, + + disable: function(form) { + var elements = Form.getElements(form); + for (var i = 0; i < elements.length; i++) { + var element = elements[i]; + element.blur(); + element.disabled = 'true'; + } + }, + + enable: function(form) { + var elements = Form.getElements(form); + for (var i = 0; i < elements.length; i++) { + var element = elements[i]; + element.disabled = ''; + } + }, + + findFirstElement: function(form) { + return Form.getElements(form).find(function(element) { + return element.type != 'hidden' && !element.disabled && + ['input', 'select', 'textarea'].include(element.tagName.toLowerCase()); + }); + }, + + focusFirstElement: function(form) { + Field.activate(Form.findFirstElement(form)); + }, + + reset: function(form) { + $(form).reset(); + } +} + +Form.Element = { + serialize: function(element) { + element = $(element); + var method = element.tagName.toLowerCase(); + var parameter = Form.Element.Serializers[method](element); + + if (parameter) { + var key = encodeURIComponent(parameter[0]); + if (key.length == 0) return; + + if (parameter[1].constructor != Array) + parameter[1] = [parameter[1]]; + + return parameter[1].map(function(value) { + return key + '=' + encodeURIComponent(value); + }).join('&'); + } + }, + + getValue: function(element) { + element = $(element); + var method = element.tagName.toLowerCase(); + var parameter = Form.Element.Serializers[method](element); + + if (parameter) + return parameter[1]; + } +} + +Form.Element.Serializers = { + input: function(element) { + switch (element.type.toLowerCase()) { + case 'submit': + case 'hidden': + case 'password': + case 'text': + return Form.Element.Serializers.textarea(element); + case 'checkbox': + case 'radio': + return Form.Element.Serializers.inputSelector(element); + } + return false; + }, + + inputSelector: function(element) { + if (element.checked) + return [element.name, element.value]; + }, + + textarea: function(element) { + return [element.name, element.value]; + }, + + select: function(element) { + return Form.Element.Serializers[element.type == 'select-one' ? + 'selectOne' : 'selectMany'](element); + }, + + selectOne: function(element) { + var value = '', opt, index = element.selectedIndex; + if (index >= 0) { + opt = element.options[index]; + value = opt.value || opt.text; + } + return [element.name, value]; + }, + + selectMany: function(element) { + var value = []; + for (var i = 0; i < element.length; i++) { + var opt = element.options[i]; + if (opt.selected) + value.push(opt.value || opt.text); + } + return [element.name, value]; + } +} + +/*--------------------------------------------------------------------------*/ + +var $F = Form.Element.getValue; + +/*--------------------------------------------------------------------------*/ + +Abstract.TimedObserver = function() {} +Abstract.TimedObserver.prototype = { + initialize: function(element, frequency, callback) { + this.frequency = frequency; + this.element = $(element); + this.callback = callback; + + this.lastValue = this.getValue(); + this.registerCallback(); + }, + + registerCallback: function() { + setInterval(this.onTimerEvent.bind(this), this.frequency * 1000); + }, + + onTimerEvent: function() { + var value = this.getValue(); + if (this.lastValue != value) { + this.callback(this.element, value); + this.lastValue = value; + } + } +} + +Form.Element.Observer = Class.create(); +Form.Element.Observer.prototype = Object.extend(new Abstract.TimedObserver(), { + getValue: function() { + return Form.Element.getValue(this.element); + } +}); + +Form.Observer = Class.create(); +Form.Observer.prototype = Object.extend(new Abstract.TimedObserver(), { + getValue: function() { + return Form.serialize(this.element); + } +}); + +/*--------------------------------------------------------------------------*/ + +Abstract.EventObserver = function() {} +Abstract.EventObserver.prototype = { + initialize: function(element, callback) { + this.element = $(element); + this.callback = callback; + + this.lastValue = this.getValue(); + if (this.element.tagName.toLowerCase() == 'form') + this.registerFormCallbacks(); + else + this.registerCallback(this.element); + }, + + onElementEvent: function() { + var value = this.getValue(); + if (this.lastValue != value) { + this.callback(this.element, value); + this.lastValue = value; + } + }, + + registerFormCallbacks: function() { + var elements = Form.getElements(this.element); + for (var i = 0; i < elements.length; i++) + this.registerCallback(elements[i]); + }, + + registerCallback: function(element) { + if (element.type) { + switch (element.type.toLowerCase()) { + case 'checkbox': + case 'radio': + Event.observe(element, 'click', this.onElementEvent.bind(this)); + break; + case 'password': + case 'text': + case 'textarea': + case 'select-one': + case 'select-multiple': + Event.observe(element, 'change', this.onElementEvent.bind(this)); + break; + } + } + } +} + +Form.Element.EventObserver = Class.create(); +Form.Element.EventObserver.prototype = Object.extend(new Abstract.EventObserver(), { + getValue: function() { + return Form.Element.getValue(this.element); + } +}); + +Form.EventObserver = Class.create(); +Form.EventObserver.prototype = Object.extend(new Abstract.EventObserver(), { + getValue: function() { + return Form.serialize(this.element); + } +}); +if (!window.Event) { + var Event = new Object(); +} + +Object.extend(Event, { + KEY_BACKSPACE: 8, + KEY_TAB: 9, + KEY_RETURN: 13, + KEY_ESC: 27, + KEY_LEFT: 37, + KEY_UP: 38, + KEY_RIGHT: 39, + KEY_DOWN: 40, + KEY_DELETE: 46, + + element: function(event) { + return event.target || event.srcElement; + }, + + isLeftClick: function(event) { + return (((event.which) && (event.which == 1)) || + ((event.button) && (event.button == 1))); + }, + + pointerX: function(event) { + return event.pageX || (event.clientX + + (document.documentElement.scrollLeft || document.body.scrollLeft)); + }, + + pointerY: function(event) { + return event.pageY || (event.clientY + + (document.documentElement.scrollTop || document.body.scrollTop)); + }, + + stop: function(event) { + if (event.preventDefault) { + event.preventDefault(); + event.stopPropagation(); + } else { + event.returnValue = false; + event.cancelBubble = true; + } + }, + + // find the first node with the given tagName, starting from the + // node the event was triggered on; traverses the DOM upwards + findElement: function(event, tagName) { + var element = Event.element(event); + while (element.parentNode && (!element.tagName || + (element.tagName.toUpperCase() != tagName.toUpperCase()))) + element = element.parentNode; + return element; + }, + + observers: false, + + _observeAndCache: function(element, name, observer, useCapture) { + if (!this.observers) this.observers = []; + if (element.addEventListener) { + this.observers.push([element, name, observer, useCapture]); + element.addEventListener(name, observer, useCapture); + } else if (element.attachEvent) { + this.observers.push([element, name, observer, useCapture]); + element.attachEvent('on' + name, observer); + } + }, + + unloadCache: function() { + if (!Event.observers) return; + for (var i = 0; i < Event.observers.length; i++) { + Event.stopObserving.apply(this, Event.observers[i]); + Event.observers[i][0] = null; + } + Event.observers = false; + }, + + observe: function(element, name, observer, useCapture) { + var element = $(element); + useCapture = useCapture || false; + + if (name == 'keypress' && + (navigator.appVersion.match(/Konqueror|Safari|KHTML/) + || element.attachEvent)) + name = 'keydown'; + + this._observeAndCache(element, name, observer, useCapture); + }, + + stopObserving: function(element, name, observer, useCapture) { + var element = $(element); + useCapture = useCapture || false; + + if (name == 'keypress' && + (navigator.appVersion.match(/Konqueror|Safari|KHTML/) + || element.detachEvent)) + name = 'keydown'; + + if (element.removeEventListener) { + element.removeEventListener(name, observer, useCapture); + } else if (element.detachEvent) { + element.detachEvent('on' + name, observer); + } + } +}); + +/* prevent memory leaks in IE */ +if (navigator.appVersion.match(/\bMSIE\b/)) + Event.observe(window, 'unload', Event.unloadCache, false); +var Position = { + // set to true if needed, warning: firefox performance problems + // NOT neeeded for page scrolling, only if draggable contained in + // scrollable elements + includeScrollOffsets: false, + + // must be called before calling withinIncludingScrolloffset, every time the + // page is scrolled + prepare: function() { + this.deltaX = window.pageXOffset + || document.documentElement.scrollLeft + || document.body.scrollLeft + || 0; + this.deltaY = window.pageYOffset + || document.documentElement.scrollTop + || document.body.scrollTop + || 0; + }, + + realOffset: function(element) { + var valueT = 0, valueL = 0; + do { + valueT += element.scrollTop || 0; + valueL += element.scrollLeft || 0; + element = element.parentNode; + } while (element); + return [valueL, valueT]; + }, + + cumulativeOffset: function(element) { + var valueT = 0, valueL = 0; + do { + valueT += element.offsetTop || 0; + valueL += element.offsetLeft || 0; + element = element.offsetParent; + } while (element); + return [valueL, valueT]; + }, + + positionedOffset: function(element) { + var valueT = 0, valueL = 0; + do { + valueT += element.offsetTop || 0; + valueL += element.offsetLeft || 0; + element = element.offsetParent; + if (element) { + p = Element.getStyle(element, 'position'); + if (p == 'relative' || p == 'absolute') break; + } + } while (element); + return [valueL, valueT]; + }, + + offsetParent: function(element) { + if (element.offsetParent) return element.offsetParent; + if (element == document.body) return element; + + while ((element = element.parentNode) && element != document.body) + if (Element.getStyle(element, 'position') != 'static') + return element; + + return document.body; + }, + + // caches x/y coordinate pair to use with overlap + within: function(element, x, y) { + if (this.includeScrollOffsets) + return this.withinIncludingScrolloffsets(element, x, y); + this.xcomp = x; + this.ycomp = y; + this.offset = this.cumulativeOffset(element); + + return (y >= this.offset[1] && + y < this.offset[1] + element.offsetHeight && + x >= this.offset[0] && + x < this.offset[0] + element.offsetWidth); + }, + + withinIncludingScrolloffsets: function(element, x, y) { + var offsetcache = this.realOffset(element); + + this.xcomp = x + offsetcache[0] - this.deltaX; + this.ycomp = y + offsetcache[1] - this.deltaY; + this.offset = this.cumulativeOffset(element); + + return (this.ycomp >= this.offset[1] && + this.ycomp < this.offset[1] + element.offsetHeight && + this.xcomp >= this.offset[0] && + this.xcomp < this.offset[0] + element.offsetWidth); + }, + + // within must be called directly before + overlap: function(mode, element) { + if (!mode) return 0; + if (mode == 'vertical') + return ((this.offset[1] + element.offsetHeight) - this.ycomp) / + element.offsetHeight; + if (mode == 'horizontal') + return ((this.offset[0] + element.offsetWidth) - this.xcomp) / + element.offsetWidth; + }, + + clone: function(source, target) { + source = $(source); + target = $(target); + target.style.position = 'absolute'; + var offsets = this.cumulativeOffset(source); + target.style.top = offsets[1] + 'px'; + target.style.left = offsets[0] + 'px'; + target.style.width = source.offsetWidth + 'px'; + target.style.height = source.offsetHeight + 'px'; + }, + + page: function(forElement) { + var valueT = 0, valueL = 0; + + var element = forElement; + do { + valueT += element.offsetTop || 0; + valueL += element.offsetLeft || 0; + + // Safari fix + if (element.offsetParent==document.body) + if (Element.getStyle(element,'position')=='absolute') break; + + } while (element = element.offsetParent); + + element = forElement; + do { + valueT -= element.scrollTop || 0; + valueL -= element.scrollLeft || 0; + } while (element = element.parentNode); + + return [valueL, valueT]; + }, + + clone: function(source, target) { + var options = Object.extend({ + setLeft: true, + setTop: true, + setWidth: true, + setHeight: true, + offsetTop: 0, + offsetLeft: 0 + }, arguments[2] || {}) + + // find page position of source + source = $(source); + var p = Position.page(source); + + // find coordinate system to use + target = $(target); + var delta = [0, 0]; + var parent = null; + // delta [0,0] will do fine with position: fixed elements, + // position:absolute needs offsetParent deltas + if (Element.getStyle(target,'position') == 'absolute') { + parent = Position.offsetParent(target); + delta = Position.page(parent); + } + + // correct by body offsets (fixes Safari) + if (parent == document.body) { + delta[0] -= document.body.offsetLeft; + delta[1] -= document.body.offsetTop; + } + + // set position + if(options.setLeft) target.style.left = (p[0] - delta[0] + options.offsetLeft) + 'px'; + if(options.setTop) target.style.top = (p[1] - delta[1] + options.offsetTop) + 'px'; + if(options.setWidth) target.style.width = source.offsetWidth + 'px'; + if(options.setHeight) target.style.height = source.offsetHeight + 'px'; + }, + + absolutize: function(element) { + element = $(element); + if (element.style.position == 'absolute') return; + Position.prepare(); + + var offsets = Position.positionedOffset(element); + var top = offsets[1]; + var left = offsets[0]; + var width = element.clientWidth; + var height = element.clientHeight; + + element._originalLeft = left - parseFloat(element.style.left || 0); + element._originalTop = top - parseFloat(element.style.top || 0); + element._originalWidth = element.style.width; + element._originalHeight = element.style.height; + + element.style.position = 'absolute'; + element.style.top = top + 'px';; + element.style.left = left + 'px';; + element.style.width = width + 'px';; + element.style.height = height + 'px';; + }, + + relativize: function(element) { + element = $(element); + if (element.style.position == 'relative') return; + Position.prepare(); + + element.style.position = 'relative'; + var top = parseFloat(element.style.top || 0) - (element._originalTop || 0); + var left = parseFloat(element.style.left || 0) - (element._originalLeft || 0); + + element.style.top = top + 'px'; + element.style.left = left + 'px'; + element.style.height = element._originalHeight; + element.style.width = element._originalWidth; + } +} + +// Safari returns margins on body which is incorrect if the child is absolutely +// positioned. For performance reasons, redefine Position.cumulativeOffset for +// KHTML/WebKit only. +if (/Konqueror|Safari|KHTML/.test(navigator.userAgent)) { + Position.cumulativeOffset = function(element) { + var valueT = 0, valueL = 0; + do { + valueT += element.offsetTop || 0; + valueL += element.offsetLeft || 0; + if (element.offsetParent == document.body) + if (Element.getStyle(element, 'position') == 'absolute') break; + + element = element.offsetParent; + } while (element); + + return [valueL, valueT]; + } +} Added: kukit/bluekit/trunk/browser/simple.html ============================================================================== --- (empty file) +++ kukit/bluekit/trunk/browser/simple.html Thu Jun 22 22:03:56 2006 @@ -0,0 +1 @@ +

    patched again

    and again

    Added: kukit/bluekit/trunk/browser/update.html ============================================================================== --- (empty file) +++ kukit/bluekit/trunk/browser/update.html Thu Jun 22 22:03:56 2006 @@ -0,0 +1,3 @@ +
      +
    • Updated
    • +
    Added: kukit/bluekit/trunk/configure.zcml ============================================================================== --- (empty file) +++ kukit/bluekit/trunk/configure.zcml Thu Jun 22 22:03:56 2006 @@ -0,0 +1,67 @@ + + + + + + + + + + + + + + + + + + + + + + + From reebalazs at codespeak.net Thu Jun 29 17:12:28 2006 From: reebalazs at codespeak.net (reebalazs at codespeak.net) Date: Thu, 29 Jun 2006 17:12:28 +0200 (CEST) Subject: [Kukit-checkins] r29494 - kukit/bluekit/trunk Message-ID: <20060629151228.A6C3B10076@code0.codespeak.net> Author: reebalazs Date: Thu Jun 29 17:12:27 2006 New Revision: 29494 Modified: kukit/bluekit/trunk/configure.zcml Log: move the plugin here from the core Modified: kukit/bluekit/trunk/configure.zcml ============================================================================== --- kukit/bluekit/trunk/configure.zcml (original) +++ kukit/bluekit/trunk/configure.zcml Thu Jun 29 17:12:27 2006 @@ -55,10 +55,16 @@ permission="zope2.View" /> - + + + Author: reebalazs Date: Thu Jun 29 17:12:55 2006 New Revision: 29495 Modified: kukit/kukit.js/trunk/kukit/eventreg.js kukit/kukit.js/trunk/kukit/kssparser.js kukit/kukit.js/trunk/kukit/kukit.js kukit/kukit.js/trunk/kukit/plugin.js kukit/kukit.js/trunk/kukit/resourcedata.js kukit/kukit.js/trunk/tests/test_kssparser.js Log: Make it work, actually Modified: kukit/kukit.js/trunk/kukit/eventreg.js ============================================================================== --- kukit/kukit.js/trunk/kukit/eventreg.js (original) +++ kukit/kukit.js/trunk/kukit/eventreg.js Thu Jun 29 17:12:55 2006 @@ -70,8 +70,8 @@ if (typeof(defaultactionmethodname) == 'undefined') { throw 'EventRegistry.register misses some parameters'; } - if (!eventname || !classname || !bindmethodname) { - throw 'In EventRegistry.register eventname, classname, bindmethodname must be non-empty'; + if (!eventname || !classname) { + throw 'In EventRegistry.register eventname, classname must be non-empty'; } var key = this._getKey(namespace, eventname); var entry = this.content[key]; @@ -110,8 +110,10 @@ if (typeof(entry) == 'undefined') { if (key[0] == '-') { key = key.substring(1); + throw 'Error : undefined global event key ' + key + ' (or maybe namespace is missing?)'; + } else { + throw 'Error : undefined event key ' + key; } - throw 'Error : undefined event key ' + key; } return entry; }; @@ -133,7 +135,7 @@ kukit.er.Event__trigger_action__ = function(name, parms, node) { // Can be called from programs to execute an action programmatically. - var eventrule = kukit.rd.methodTable.getMergedRule(name, this); + var eventrule = kukit.rd.methodTable.getMergedRule('kss', name, this); // getMergedRule gave a warning (once by page), so be silent if not found if (eventrule) { eventrule.trigger_event(node, this); Modified: kukit/kukit.js/trunk/kukit/kssparser.js ============================================================================== --- kukit/kukit.js/trunk/kukit/kssparser.js (original) +++ kukit/kukit.js/trunk/kukit/kssparser.js Thu Jun 29 17:12:55 2006 @@ -400,14 +400,15 @@ css = this.src.text.substring(this.startpos, commatoken.startpos); //print ('>>' + css + ':' + pseudotoken.value.methodname); // Decide if we have an event or a method selector. - // We have a method selector if a single word "document". + // We have a method selector if a single word "document" or "kss". var singleword = css.replace(/[\r\n\t ]/g, ' '); if (singleword && singleword[0] == ' ') { singleword = singleword.substring(1); } - var isEvent = singleword != 'document'; + var isEvent = (singleword != 'document' && singleword != 'kss'); if (! isEvent) { - css = null; + // just store the single word, in case of event selectors + css = singleword; } // create the selector. var id = null; Modified: kukit/kukit.js/trunk/kukit/kukit.js ============================================================================== --- kukit/kukit.js/trunk/kukit/kukit.js (original) +++ kukit/kukit.js/trunk/kukit/kukit.js Thu Jun 29 17:12:55 2006 @@ -190,22 +190,6 @@ kukit.requestManager = new kukit.RequestManager(); -/* XXX this needs to be looked at - it's used in CompositePack */ -kukit.storedResults = new Array(); - -kukit.storeResults = function(results) { - kukit.storedResults[kukit.storedResults.length] = results; -}; - -kukit.getLastResults = function() { - var length = kukit.storedResults.length; - if (length != 0){ - return kukit.storedResults[length-1]; - } -}; -/* end of XXX */ - kukit.RuleSheetLink = function(href, res_type) { this.href = href; this.res_type = res_type; @@ -659,8 +643,7 @@ var node = nodes[i]; //XXX error handling for wrong command name kukit.logDebug('Command Name: ' + this.name); - var results = this.executeOnSingleNode(node); - kukit.storeResults(results); // XXX see above + this.executeOnSingleNode(node); } }; @@ -683,12 +666,7 @@ /* Core commands */ -kukit.makeGlobalCommand('prototypeResponse', function(node) { - // supposed to have a single cdata node - this.transport.responseText = this.params['html'].firstChild.data; - this.transport.responseXML = null; -}); - +// innerHTML kukit.makeSelectorCommand('setHtmlAsChild', function(node) { var content = document.importNode(this.params['html'], true); Sarissa.clearChildNodes(node); @@ -696,6 +674,7 @@ kukit.setupEvents(node); }); +// outerHTML ? kukit.makeSelectorCommand('replaceNode', function(node) { var childNodes = this.params['html'].childNodes; var sourceSelector = this.params['selector'].firstChild.nodeValue || null; @@ -737,7 +716,6 @@ // update the events for the new nodes kukit.logDebug("Inserted nodes length: "+inserted.length); kukit.setupEvents(node); - return inserted; }); kukit.makeSelectorCommand('removeNextSibling', function(node) { @@ -791,9 +769,3 @@ toNode = document.getElementById(id); Sarissa.copyChildNodes(node, toNode); }) - -kukit.makeSelectorCommand('executeCode', function(node) -{ - var code = this.params['code'].firstChild.nodeValue; - node.eval(code); -}); Modified: kukit/kukit.js/trunk/kukit/plugin.js ============================================================================== --- kukit/kukit.js/trunk/kukit/plugin.js (original) +++ kukit/kukit.js/trunk/kukit/plugin.js Thu Jun 29 17:12:55 2006 @@ -28,7 +28,7 @@ } for (var key in parms){ if (typeof(newparms[key]) == 'undefined') { - throw 'Excess parameter "' + key + ' in ' + errname; + throw 'Excess parameter "' + key + '" in ' + errname; } } return newparms; Modified: kukit/kukit.js/trunk/kukit/resourcedata.js ============================================================================== --- kukit/kukit.js/trunk/kukit/resourcedata.js (original) +++ kukit/kukit.js/trunk/kukit/resourcedata.js Thu Jun 29 17:12:55 2006 @@ -17,8 +17,8 @@ throw 'Kss selector class must not contain @: "' + namespace + '"'; if (! isEvent) { // method rule - if (css != null) { - throw 'KssMethodSelector "' + name + '" must have css=null'; + if (css != 'document' && css != 'kss') { + throw 'KssMethodSelector "' + name + '" must have one of the allowed names'; } } this.css = css; @@ -28,6 +28,10 @@ this.id = id; }; +kukit.rd.makeMergeId = function(id, namespace, name) { + return id + '@' + namespace + '@' + name; +}; + kukit.rd.KssSelector.prototype.setIdAndClass = function() { // Sets up id and class on the selector, based on registration info this.classname = kukit.er.eventRegistry.get(this.namespace, this.name).classname @@ -41,7 +45,7 @@ if (this.namespace != null) { namespace = this.namespace; } - this.mergeid = this.id + '@' + namespace + '@' + this.name + this.mergeid = kukit.rd.makeMergeId(this.id, namespace, this.name); }; /* @@ -205,27 +209,23 @@ kukit.rd.EventRule.prototype.bind = function(node) { var eventinstance = this.getEventInstance(); + var namespace = this.kss_selector.namespace; var name = this.kss_selector.name; var parms = this.parms; - var method = eventinstance['__bind_' + name + '__']; + var methodname = kukit.er.eventRegistry.get(namespace, name).bindmethodname + if (! methodname) { + throw 'Could not bind event name "' + name + '" on namespace "' + namespace + '", because the method is not defined as bindable.'; + } + var method = eventinstance[methodname]; + if (! method) { + throw 'Could not bind event name "' + name + '" on namespace "' + namespace + '", because the method "' + methodname + '" does not exist.'; + } var self = this; var func_to_bind = function() { self.trigger_event(node, eventinstance); } - var retstat = false; - if (typeof(method) != 'undefined') { - retstat = method.call(eventinstance, parms, func_to_bind, node, this); - } - if (! retstat) { - method = eventinstance.__bind__; - if (typeof(method) != 'undefined') { - retstat = method.call(eventinstance, name, parms, func_to_bind, node, this); - } - if (! retstat) { - // An error. - throw 'Could not bind event name "' + name + '" on class "' + this.kss_selector.classname + '"'; - } - } + // do the binding + method.call(eventinstance, name, parms, func_to_bind, node, this); }; /* @@ -241,31 +241,28 @@ */ kukit.rd.EventRule.prototype.trigger_event = function(node, eventinstance) { - // Node will be null if executed for a method rule. + // Take care of the default action - if any. + var namespace = this.kss_selector.namespace; var name = this.kss_selector.name; - var method = eventinstance['__exec_' + name + '__']; - var retstat = false; - // XXX ... move this to a method of actionset ? - var defaultaction = this.actions.getDefaultAction(); - var parms; - if (defaultaction) { - parms = defaultaction.getParms(node); - } else { - parms = {}; - } - if (typeof(method) != 'undefined') { - retstat = method.call(eventinstance, parms, node); - } - if (! retstat) { - method = eventinstance.__exec__; - if (typeof(method) != 'undefined') { - retstat = method.call(eventinstance, name, parms, node); - } - if (! retstat) { - // execute the actions! - this.actions.execute(node, this); + var methodname = kukit.er.eventRegistry.get(namespace, name).defaultactionmethodname + if (methodname) { + var method = eventinstance[methodname]; + if (! method) { + throw 'Could not bind event name "' + name + '" on namespace "' + namespace + '", because the method "' + methodname + '" does not exist.'; + } + // get the default action parms + var defaultaction = this.actions.getDefaultAction(); + var parms; + if (defaultaction) { + parms = defaultaction.getParms(node); + } else { + parms = {}; } + // call it + method.call(eventinstance, name, parms, node); } + // Call the actions, in any case + this.actions.execute(node, this); }; // @@ -500,51 +497,38 @@ kukit.rd.MethodTable = function() { this.content = {}; + this.content['document'] = {}; + this.content['kss'] = {}; }; kukit.rd.MethodTable.prototype.add = function(eventrule) { - // Get the entry by name - var entry = this.content[eventrule.kss_selector.name]; - if (typeof(entry) == 'undefined') { - entry = {'byclass': {}, 'byid': {}, 'cookedbyid': {}}; - this.content[eventrule.kss_selector.name] = entry; - } - // Merge by class and by id - // XXX must be put back - //eventrule.mergeIntoDict(entry.byclass, eventrule.kss_selector.classname, eventrule); - eventrule.mergeIntoDict(entry.byid, eventrule.kss_selector.id, eventrule); + // Get the entry by the type which is now at css + var category = eventrule.kss_selector.css; + var dict = this.content[category]; + if (typeof(dict) == 'undefined') { + throw 'Unknown method rule category "' + category + '"'; + } + // Merge into the corresponding category + eventrule.mergeIntoDict(dict, eventrule.kss_selector.mergeid, eventrule); }; -kukit.rd.MethodTable.prototype.getMergedRule = function(name, eventinstance) { +kukit.rd.MethodTable.prototype.getMergedRule = function(category, name, eventinstance) { // Returns the rule for a given event instance, - // Get the entry by name - var entry = this.content[name]; - if (typeof(entry) == 'undefined') { - throw 'No method rule found event name="' + name + '"'; - return null; + // Get the entry by category (= document or kss) + var dict = this.content[category]; + if (typeof(dict) == 'undefined') { + throw 'Unknown method rule category "' + category + '"'; } // look up the rule and merge if necessary var namespace = eventinstance.__event_namespace__; var classname = eventinstance.__event_classname__; var id = eventinstance.__event_id__; - var mergedrule = entry.cookedbyid[id]; + var mergeid = kukit.rd.makeMergeId(id, namespace, name); + var mergedrule = dict[mergeid]; if (typeof(mergedrule) == 'undefined') { - // Prepare this rule. - mergedrule = entry.byclass[classname]; - var rule2 = entry.byid[id]; - if (typeof(mergedrule) != 'undefined' && typeof(rule2) != 'undefined') { - mergedrule = mergedrule.cloneForMerge(); - mergedrule.merge(rule2); - entry.byid[id] = null; // free garbage - } else if (typeof(rule2) != 'undefined') { - mergedrule = rule2; - entry.byid[id] = null; // free garbage - } else if (typeof(mergedrule) != 'undefined') { - throw 'No method rule found event name="' + name + '" id="' + id + + throw 'No method rule found category="' + category + '", event name="' + name + '" id="' + id + '" namespace="' + namespace + '"'; - mergedrule = null - } - entry.cookedbyid[id] = mergedrule; + mergedrule = null; } return mergedrule; }; Modified: kukit/kukit.js/trunk/tests/test_kssparser.js ============================================================================== --- kukit/kukit.js/trunk/tests/test_kssparser.js (original) +++ kukit/kukit.js/trunk/tests/test_kssparser.js Thu Jun 29 17:12:55 2006 @@ -535,7 +535,7 @@ parser = new kukit.kssp.kssselector(src, null, true); this.assertEquals(parser.finished, true); this.assertEquals(parser.kssSelector.isMethodSelector, true); - this.assertEquals(parser.kssSelector.css, null); + this.assertEquals(parser.kssSelector.css, 'document'); this.assertEquals(parser.kssSelector.name, 'click'); this.assertEquals(parser.kssSelector.namespace, null); this.assertEquals(parser.kssSelector.id, 'hello'); @@ -545,7 +545,7 @@ parser = new kukit.kssp.kssselector(src, null, true); this.assertEquals(parser.finished, true); this.assertEquals(parser.kssSelector.isMethodSelector, true); - this.assertEquals(parser.kssSelector.css, null); + this.assertEquals(parser.kssSelector.css, 'document'); this.assertEquals(parser.kssSelector.name, 'click'); this.assertEquals(parser.kssSelector.namespace, 'native'); this.assertEquals(parser.kssSelector.id, 'hello'); @@ -755,7 +755,7 @@ //} rule = parser.eventRules[6]; this.assertDictEquals(rule.parms, {}); - this.assertEquals(rule.kss_selector.css, null); + this.assertEquals(rule.kss_selector.css, 'document'); this.assertEquals(rule.kss_selector.isMethodSelector, true); this.assertEquals(rule.kss_selector.name, 'annoy'); this.assertEquals(rule.kss_selector.namespace, null); @@ -776,7 +776,7 @@ //} rule = parser.eventRules[7]; this.assertDictEquals(rule.parms, {}); - this.assertEquals(rule.kss_selector.css, null); + this.assertEquals(rule.kss_selector.css, 'document'); this.assertEquals(rule.kss_selector.isMethodSelector, true); this.assertEquals(rule.kss_selector.name, 'annoy'); this.assertEquals(rule.kss_selector.namespace, 'annoyClicker'); From reebalazs at codespeak.net Thu Jun 29 17:13:06 2006 From: reebalazs at codespeak.net (reebalazs at codespeak.net) Date: Thu, 29 Jun 2006 17:13:06 +0200 (CEST) Subject: [Kukit-checkins] r29496 - kukit/azax/trunk/plugins Message-ID: <20060629151306.2C66B10076@code0.codespeak.net> Author: reebalazs Date: Thu Jun 29 17:13:04 2006 New Revision: 29496 Modified: kukit/azax/trunk/plugins/configure.zcml Log: Make it work, actually Modified: kukit/azax/trunk/plugins/configure.zcml ============================================================================== --- kukit/azax/trunk/plugins/configure.zcml (original) +++ kukit/azax/trunk/plugins/configure.zcml Thu Jun 29 17:13:04 2006 @@ -71,13 +71,6 @@ name="copyChildrenTo" /> - - - From reebalazs at codespeak.net Fri Jun 30 14:58:29 2006 From: reebalazs at codespeak.net (reebalazs at codespeak.net) Date: Fri, 30 Jun 2006 14:58:29 +0200 (CEST) Subject: [Kukit-checkins] r29531 - kukit/azaxdemo/trunk/browser Message-ID: <20060630125829.BB95D10077@code0.codespeak.net> Author: reebalazs Date: Fri Jun 30 14:58:27 2006 New Revision: 29531 Modified: kukit/azaxdemo/trunk/browser/more_selectors.js kukit/azaxdemo/trunk/browser/more_selectors.kss Log: Make it work with the non-hijacking default action Modified: kukit/azaxdemo/trunk/browser/more_selectors.js ============================================================================== --- kukit/azaxdemo/trunk/browser/more_selectors.js (original) +++ kukit/azaxdemo/trunk/browser/more_selectors.js Fri Jun 30 14:58:27 2006 @@ -5,7 +5,7 @@ kukit.more_selectors.AnnoyClickerEvent = function() { }; -kukit.more_selectors.AnnoyClickerEvent.prototype.__bind_click__ = function(parms, func_to_bind, node, eventrule) { +kukit.more_selectors.AnnoyClickerEvent.prototype.__bind_click__ = function(name, parms, func_to_bind, node, eventrule) { // validate and set parameters parms = kukit.pl.completeParms(parms, [], {'count': '3'}, 'annoyClicker event binding'); var count; @@ -21,22 +21,22 @@ this.count = this.countsomuch; // Just bind the event via the native event binder kukit.pl.NativeEvent.prototype.__bind__('click', {}, func_to_bind, node); - return true; }; -kukit.more_selectors.AnnoyClickerEvent.prototype.__exec_click__ = function(parms, node) { +kukit.more_selectors.AnnoyClickerEvent.prototype.__default_click__ = function(name, parms, node) { this.count -= 1; if (this.count == 0) { // Continue with the real action. this.count = this.countsomuch; - return false; + this.__trigger_action__('doit', parms, node); } else { - // Hijack real action and annoy user instead. - //alert('Bugged'); this.__trigger_action__('annoy', parms, node); - return true; } }; kukit.er.eventClassRegistry.register('annoyClicker', kukit.more_selectors.AnnoyClickerEvent); +kukit.er.eventRegistry.register('annoyclicker', 'click', 'annoyClicker', '__bind_click__', '__default_click__'); +kukit.er.eventRegistry.register('annoyclicker', 'annoy', 'annoyClicker', null, null); +kukit.er.eventRegistry.register('annoyclicker', 'doit', 'annoyClicker', null, null); + Modified: kukit/azaxdemo/trunk/browser/more_selectors.kss ============================================================================== --- kukit/azaxdemo/trunk/browser/more_selectors.kss (original) +++ kukit/azaxdemo/trunk/browser/more_selectors.kss Fri Jun 30 14:58:27 2006 @@ -1,23 +1,29 @@ -#button-one:annoyClicker-click(annoyMe) { +#button-one:annoyclicker-click(annoyMe) { +} + +kss:annoyclicker-doit(annoyMe) { action-server: clickedButton; clickedButton-id: nodeattr(id); action-client: log; log-message: "Was here."; } -document:annoy(annoyMe) { +kss:annoyclicker-annoy(annoyMe) { action-client: alert; alert-message: "You are an idiot! Ha ha ha. (But just keep on trying...)"; } -#button-two:annoyClicker-click(annoyYou) { +#button-two:annoyclicker-click(annoyYou) { evt-click-count: 2; +} + +kss:annoyclicker-doit(annoyYou) { action-server: clickedButton; clickedButton-id: nodeattr(id); } -document:annoy(annoyYou) { +kss:annoyclicker-annoy(annoyYou) { action-client: alert; alert-message: "You are an idiot too, but not so big as I am."; } From reebalazs at codespeak.net Fri Jun 30 14:58:51 2006 From: reebalazs at codespeak.net (reebalazs at codespeak.net) Date: Fri, 30 Jun 2006 14:58:51 +0200 (CEST) Subject: [Kukit-checkins] r29532 - kukit/kukit.js/trunk/kukit Message-ID: <20060630125851.5B04510077@code0.codespeak.net> Author: reebalazs Date: Fri Jun 30 14:58:48 2006 New Revision: 29532 Modified: kukit/kukit.js/trunk/kukit/eventreg.js kukit/kukit.js/trunk/kukit/plugin.js kukit/kukit.js/trunk/kukit/resourcedata.js Log: Cleaned up internal event ids Modified: kukit/kukit.js/trunk/kukit/eventreg.js ============================================================================== --- kukit/kukit.js/trunk/kukit/eventreg.js (original) +++ kukit/kukit.js/trunk/kukit/eventreg.js Fri Jun 30 14:58:48 2006 @@ -184,11 +184,12 @@ return eventinstance; }; -kukit.er.EventInstanceRegistry.prototype.getSingletonEventByClass = function (classname) { +kukit.er.EventInstanceRegistry.prototype.getSingletonEventByName = function (namespace, name) { // Get an event. - var eventinstance = this.content['@@' + classname]; + var id = kukit.rd.makeId(namespace, name); + var eventinstance = this.content[id]; if (typeof(eventinstance) == 'undefined') { - throw 'Singleton event with class "' + classname + '" not found.' + throw 'Singleton event with namespace "' + namespace + '" and name "' + name + '" not found.' } return eventinstance; }; Modified: kukit/kukit.js/trunk/kukit/plugin.js ============================================================================== --- kukit/kukit.js/trunk/kukit/plugin.js (original) +++ kukit/kukit.js/trunk/kukit/plugin.js Fri Jun 30 14:58:48 2006 @@ -199,20 +199,26 @@ */ kukit.ar.eventActionRegistry.register("cascade", function (node, parms, eventrule) { - parms = kukit.pl.completeParms(parms, ['name'], {'id': null, 'class': null}, 'cascade action'); - if (parms.id == null && parms['class'] == null || parms.id != null && parms['class'] != null) { - throw 'Must specify either class or id in cascade action, rule=#' + eventrule.getNr() + ', node=' + node.nodeName; - } + parms = kukit.pl.completeParms(parms, ['name'], {'id': null, 'namespace': null}, 'cascade action'); var eventinstance; if (parms.id) { // by id - eventinstance = kukit.er.eventInstanceRegistry(parms.id); + eventinstance = kukit.er.eventInstanceRegistry.getEventById(parms.id); + // if namespace is defined too, let's check it! + if (parms.namespace != null && parms.namespace != eventinstance.__event_namespace__) { + throw 'Id and namespace are conflicting in cascade action, rule=#' + eventrule.getNr() + ', node=' + node.nodeName; + } } else { // singleton by class - eventinstance = kukit.er.eventInstanceRegistry(parms['class']); + eventinstance = kukit.er.eventInstanceRegistry.getSingletonEventByName(parms.namespace, parms.name); + } + // marshall it, the rest of the parms will be passed + actionparms = {}; + for (var key in parms) { + if (key != 'name' && key != 'id' && key != 'namespace') { + actionparms[key] = parms[key]; + } } - // marshall it - actionparms = {}; // XXX could be specified too! eventinstance.__trigger_action__(parms.name, actionparms, node); } ); Modified: kukit/kukit.js/trunk/kukit/resourcedata.js ============================================================================== --- kukit/kukit.js/trunk/kukit/resourcedata.js (original) +++ kukit/kukit.js/trunk/kukit/resourcedata.js Fri Jun 30 14:58:48 2006 @@ -3,6 +3,20 @@ kukit.rd = {}; +kukit.rd.makeId = function(namespace, name) { + if (namespace == null) { + namespace = ''; + } + return '@' + namespace + '@' + name; +}; + +kukit.rd.makeMergeId = function(id, namespace, name) { + if (namespace == null) { + namespace = ''; + } + return id + '@' + namespace + '@' + name; +}; + kukit.rd.KssSelector = function(isEvent, css, name, namespace, id) { this.isEventSelector = isEvent; this.isMethodSelector = ! isEvent; @@ -14,11 +28,11 @@ if (id && id.indexOf('@') != -1) throw 'Kss selector id must not contain @: "' + id + '"'; if (namespace && namespace.indexOf('@') != -1) - throw 'Kss selector class must not contain @: "' + namespace + '"'; + throw 'Kss selector namespace must not contain @: "' + namespace + '"'; if (! isEvent) { // method rule if (css != 'document' && css != 'kss') { - throw 'KssMethodSelector "' + name + '" must have one of the allowed names'; + throw 'KssSpecialSelector "' + name + '" must have one of the allowed names'; } } this.css = css; @@ -28,24 +42,16 @@ this.id = id; }; -kukit.rd.makeMergeId = function(id, namespace, name) { - return id + '@' + namespace + '@' + name; -}; - kukit.rd.KssSelector.prototype.setIdAndClass = function() { // Sets up id and class on the selector, based on registration info this.classname = kukit.er.eventRegistry.get(this.namespace, this.name).classname if (this.id == null) { // singleton for class - this.id = '@@' + this.classname; + this.id = kukit.rd.makeId(this.namespace, this.name); } // Also set the merge id. The rules with the same merge // id should be merged on the same node. - var namespace = ''; - if (this.namespace != null) { - namespace = this.namespace; - } - this.mergeid = kukit.rd.makeMergeId(this.id, namespace, this.name); + this.mergeid = kukit.rd.makeMergeId(this.id, this.namespace, this.name); }; /*