From reebalazs at codespeak.net Mon Dec 11 11:36:27 2006 From: reebalazs at codespeak.net (reebalazs at codespeak.net) Date: Mon, 11 Dec 2006 11:36:27 +0100 (CET) Subject: [KSS-checkins] r35561 - kukit/kss.core/trunk Message-ID: <20061211103627.BBAC410063@code0.codespeak.net> Author: reebalazs Date: Mon Dec 11 11:36:24 2006 New Revision: 35561 Modified: kukit/kss.core/trunk/azaxview.py Log: Start fixing the event acquisition and test issues (ongoing...) Modified: kukit/kss.core/trunk/azaxview.py ============================================================================== --- kukit/kss.core/trunk/azaxview.py (original) +++ kukit/kss.core/trunk/azaxview.py Mon Dec 11 11:36:24 2006 @@ -62,6 +62,7 @@ class SiteView(BrowserView): """A browser view that is its own site """ + implements(ISite) def __init__(self, context, request): super(SiteView, self).__init__(context, request) @@ -69,14 +70,15 @@ next_sitemanager = component.getSiteManager() self._sitemanager = ViewSiteManager('siteview') - interface.alsoProvides(self, ISite) self._sitemanager.__bases__ = (next_sitemanager, ) # register object event handler - self._sitemanager.registerHandler(self._eventRedispatcher) - setHooks() - setSite(self) + # we should wrap it in the acquisition context + wrapped_view = self.__of__(self.context) + self._sitemanager.registerHandler(wrapped_view._eventRedispatcher) + ##setHooks() + ##setSite(self) def getSiteManager(self): return self._sitemanager @@ -87,10 +89,11 @@ @component.adapter(Interface) def _eventRedispatcher(self, event): if not IAzaxEvent.providedBy(event): - notify(AzaxEvent(self, event)) + azaxevent = AzaxEvent(self, event) + notify(azaxevent) def render(self): - clearSite() + pass #clearSite() class AzaxBaseView(SiteView): """ Base kss view From reebalazs at codespeak.net Tue Dec 12 19:31:32 2006 From: reebalazs at codespeak.net (reebalazs at codespeak.net) Date: Tue, 12 Dec 2006 19:31:32 +0100 (CET) Subject: [KSS-checkins] r35639 - in kukit/kss.core/trunk: . tests Message-ID: <20061212183132.72BD310093@code0.codespeak.net> Author: reebalazs Date: Tue Dec 12 19:31:28 2006 New Revision: 35639 Modified: kukit/kss.core/trunk/azaxview.py kukit/kss.core/trunk/azaxview.txt kukit/kss.core/trunk/siteview.txt kukit/kss.core/trunk/tests/base.py kukit/kss.core/trunk/tests/configure-unittest.zcml kukit/kss.core/trunk/tests/test_azaxview.py Log: Fix tests apart from azaxview.txt and siteview.txt Modified: kukit/kss.core/trunk/azaxview.py ============================================================================== --- kukit/kss.core/trunk/azaxview.py (original) +++ kukit/kss.core/trunk/azaxview.py Tue Dec 12 19:31:28 2006 @@ -73,9 +73,17 @@ self._sitemanager.__bases__ = (next_sitemanager, ) + # On Five, we should wrap it in the acquisition context + # see, if self has aq_parent, it is done obligatoraly + try: + self.context.aq_parent + except AttributeError: + # Zope3 - No problem. + wrapped_view = self + else: + wrapped_view = self.__of__(self.context) + # register object event handler - # we should wrap it in the acquisition context - wrapped_view = self.__of__(self.context) self._sitemanager.registerHandler(wrapped_view._eventRedispatcher) ##setHooks() ##setSite(self) Modified: kukit/kss.core/trunk/azaxview.txt ============================================================================== --- kukit/kss.core/trunk/azaxview.txt (original) +++ kukit/kss.core/trunk/azaxview.txt Tue Dec 12 19:31:28 2006 @@ -17,16 +17,23 @@ >>> from kss.core.azaxview import AzaxBaseView >>> from kss.core.interfaces import IAzaxEvent - >>> from kss.core.tests.base import DebugTestRequest + >>> from kss.core.tests.base import IDebugRequest >>> from zope import component >>> from zope.lifecycleevent import ObjectModifiedEvent >>> from zope.lifecycleevent.interfaces import IObjectModifiedEvent >>> from zope.event import notify >>> from zope.app.component.interfaces import ISite + >>> from zope.interface import directlyProvides, directlyProvidedBy + >>> from zope.publisher.browser import TestRequest >>> from zope.app.folder import folder >>> myfolder = folder.rootFolder() +This will make the commands rendered as test-friendly structures. + + >>> request = TestRequest() + >>> directlyProvides(request, directlyProvidedBy(request) + IDebugRequest) + Now we will write our custom. >>> class SampleView(AzaxBaseView): @@ -35,7 +42,6 @@ ... self.handle(ObjectModifiedEvent(title)) ... return self.render() - >>> request = DebugTestRequest() >>> view = SampleView(myfolder, request) >>> view.add_page("some title") [] Modified: kukit/kss.core/trunk/siteview.txt ============================================================================== --- kukit/kss.core/trunk/siteview.txt (original) +++ kukit/kss.core/trunk/siteview.txt Tue Dec 12 19:31:28 2006 @@ -21,6 +21,7 @@ When created this view will make it's manager the default site manager. +Context must be >>> from zope import component >>> old_sitemanager = component.getSiteManager() >>> view = SiteView(None, None) Modified: kukit/kss.core/trunk/tests/base.py ============================================================================== --- kukit/kss.core/trunk/tests/base.py (original) +++ kukit/kss.core/trunk/tests/base.py Tue Dec 12 19:31:28 2006 @@ -22,15 +22,12 @@ from Testing.ZopeTestCase import ZopeTestCase import kss.core from kss.core import AzaxBaseView -#from kss.core import config -#from ZPublisher.HTTPRequest import HTTPRequest -#from cStringIO import StringIO -#from Globals import InitializeClass from OFS.SimpleItem import SimpleItem from textwrap import dedent from zope.publisher.browser import TestRequest from zope.publisher.interfaces.browser import IBrowserRequest from zope.interface import Interface, implements +from zope import interface as iapi try: # Zope > 2.8 @@ -39,47 +36,24 @@ # Zope == 2.8 from zope.app.tests import placelesssetup +# Test view +# + +class TestView(AzaxBaseView): + def testMethod(self): + 'Yes.' + # Debug request # This has a modified render. class IDebugRequest(IBrowserRequest): 'The debug request' -class DebugTestRequest(TestRequest): - 'Debug test request' - implements(IDebugRequest) - def __init__(self): - self.RESPONSE = DebugTestResponse() - self.form = {} - -class DebugTestResponse: - def __init__(self, status=200): - self.status = status - def getStatus(self): - return self.status - def setStatus(self, status): - self.status = status - -# Fake content - -class FakeContent(SimpleItem, object): - pass - -#InitializeClass(FakeContent) - class AzaxViewTestCase(ZopeTestCase): def afterSetUp(self): placelesssetup.setUp() - # fake content - fakecontent = FakeContent() - self.folder._setObject('ob', fakecontent) - fakecontent = fakecontent.__of__(self.folder) - # Set up a fake view (with no content) - fakerequest = TestRequest() - debugfakerequest = DebugTestRequest() - self.view = AzaxBaseView(fakecontent, fakerequest) - self.debug_view = AzaxBaseView(fakecontent, debugfakerequest) + # Allow traversing try: import Products.Five @@ -88,7 +62,7 @@ pass # XXX TODO fix this?? --- never run yet on Z3 from zope.configuration.xmlconfig import XMLConfig - XMLConfig('tests/configure-unittes.zcml', kss.core)() + XMLConfig('tests/configure-unittest.zcml', kss.core)() else: from Products.Five.zcml import load_string, load_config load_config('meta.zcml', package=Products.Five) @@ -122,7 +96,17 @@ load_config('meta.zcml', package=kss.core) load_config('configure.zcml', package=kss.core) load_config('configure-unittest.zcml', package=kss.core.tests) - + + def createView(self): + "Set up a fake view (with no content)" + self.view = self.folder.restrictedTraverse('testMethod') + return self.view + + def setDebugRequest(self): + 'commands will be rendered as test friendly data structures' + request = self.portal.REQUEST + iapi.directlyProvides(request, iapi.directlyProvidedBy(request) + IDebugRequest) + def beforeTearDown(self): placelesssetup.tearDown() try: Modified: kukit/kss.core/trunk/tests/configure-unittest.zcml ============================================================================== --- kukit/kss.core/trunk/tests/configure-unittest.zcml (original) +++ kukit/kss.core/trunk/tests/configure-unittest.zcml Tue Dec 12 19:31:28 2006 @@ -5,6 +5,7 @@ > + + + Modified: kukit/kss.core/trunk/tests/test_azaxview.py ============================================================================== --- kukit/kss.core/trunk/tests/test_azaxview.py (original) +++ kukit/kss.core/trunk/tests/test_azaxview.py Tue Dec 12 19:31:28 2006 @@ -22,7 +22,7 @@ import unittest, os from textwrap import dedent from zope.testing import doctest -from base import AzaxViewTestCase, FakeContent, TestRequest, DebugTestRequest +from base import AzaxViewTestCase from kss.core import AzaxUnicodeError from kss.core.plugins.core.interfaces import IKSSCoreCommands from zope.testing.cleanup import CleanUp as PlacelessSetup @@ -68,12 +68,12 @@ class TestAzaxView(AzaxViewTestCase): def test_empty(self): - view = self.view + view = self.createView() commands = view.getCommands() self.assertEqual(len(commands), 0) def test_addCommand(self): - view = self.view + view = self.createView() commands = view.getCommands() command = commands.addCommand('replaceInnerHTML', 'selector') self.assertEqual(len(commands), 1) @@ -86,7 +86,7 @@ # Nevertheless, we test all these cases def _checkSetHtmlResult(self, content, content2=None): - view = self.view + view = self.createView() view.getCommandSet('core').replaceInnerHTML('div.class', content) commands = view.getCommands() self.assertEqual(len(commands), 1) @@ -155,13 +155,13 @@ self.assertXMLEquals(a, self._wrapped_commands(b)) def test_empty(self): - view = self.view + view = self.createView() result = view.render() - self.assertEquals(view.request.response.getHeader('Content-Type'), 'text/xml;charset=utf-8') + self.assertEquals(view.request.response.getHeader('content-type'), 'text/xml;charset=utf-8') self.assertCommandsEqual(result, '') def test_replaceInnerHTML(self): - view = self.view + view = self.createView() view.getCommandSet('core').replaceInnerHTML('div.class', 'new content') result = view.render() awaited = u'''\ @@ -173,7 +173,7 @@ self.assertCommandsEqual(result, awaited) def test_setCommandSet(self): - view = self.view + view = self.createView() cs = view.getCommandSet('core') cs.replaceInnerHTML('div.class', 'new content') result = view.render() From reebalazs at codespeak.net Tue Dec 12 20:18:36 2006 From: reebalazs at codespeak.net (reebalazs at codespeak.net) Date: Tue, 12 Dec 2006 20:18:36 +0100 (CET) Subject: [KSS-checkins] r35644 - kukit/kss.core/trunk/tests Message-ID: <20061212191836.26A4C10086@code0.codespeak.net> Author: reebalazs Date: Tue Dec 12 20:18:34 2006 New Revision: 35644 Modified: kukit/kss.core/trunk/tests/base.py Log: Separate loadCoreConfig method to be called from inherited tests Modified: kukit/kss.core/trunk/tests/base.py ============================================================================== --- kukit/kss.core/trunk/tests/base.py (original) +++ kukit/kss.core/trunk/tests/base.py Tue Dec 12 20:18:34 2006 @@ -53,7 +53,9 @@ def afterSetUp(self): placelesssetup.setUp() + self.loadCoreConfig() + def loadCoreConfig(self, kss_core=True): # Allow traversing try: import Products.Five @@ -93,8 +95,9 @@ except IOError: # Zope 2.10 / Five 1.3.6 does not have it pass - load_config('meta.zcml', package=kss.core) - load_config('configure.zcml', package=kss.core) + if kss_core: + load_config('meta.zcml', package=kss.core) + load_config('configure.zcml', package=kss.core) load_config('configure-unittest.zcml', package=kss.core.tests) def createView(self): From reebalazs at codespeak.net Tue Dec 12 21:44:51 2006 From: reebalazs at codespeak.net (reebalazs at codespeak.net) Date: Tue, 12 Dec 2006 21:44:51 +0100 (CET) Subject: [KSS-checkins] r35657 - kukit/kss.demo/trunk/tests Message-ID: <20061212204451.2F7581008A@code0.codespeak.net> Author: reebalazs Date: Tue Dec 12 21:44:50 2006 New Revision: 35657 Modified: kukit/kss.demo/trunk/tests/test_azaxview.py Log: Fix tests Modified: kukit/kss.demo/trunk/tests/test_azaxview.py ============================================================================== --- kukit/kss.demo/trunk/tests/test_azaxview.py (original) +++ kukit/kss.demo/trunk/tests/test_azaxview.py Tue Dec 12 21:44:50 2006 @@ -21,29 +21,27 @@ import unittest, os from zope.testing import doctest from Testing.ZopeTestCase import ZopeTestCase -from kss.core.tests.base import AzaxViewTestCase, FakeContent, \ - TestRequest, DebugTestRequest +from kss.core.tests.base import AzaxViewTestCase from kss.demo.azaxview import AzaxView from Products.Five.zcml import load_string, load_config import kss.demo +try: + import Products.Five +except AttributeError: + from kss.demo.simplecontent_z3 import SimpleContent +else: + from kss.demo.simplecontent import SimpleContent + class AzaxDemoTestCase(AzaxViewTestCase): def afterSetUp(self): AzaxViewTestCase.afterSetUp(self) load_config('meta.zcml', package=kss.demo) load_config('configure.zcml', package=kss.demo) - # fake content - # XXX This is a holy mess. Go go macro adapters! - fakecontent = FakeContent() - self.folder._delObject('ob') - self.folder._setObject('ob', fakecontent) - fakecontent = fakecontent.__of__(self.folder) - # Set up a fake view (with no content) - # XXX commands will be rendered as data structures, - # because we use DebugTestRequest instead of TestRequest. - fakedebugrequest = DebugTestRequest() - self.view = AzaxView(fakecontent, fakedebugrequest) + self.setDebugRequest() + self.folder._setObject('demo', SimpleContent('Demo', 'Demo')) + self.view = self.folder.demo.restrictedTraverse('getDivContent') def test_instantiation(self): view = self.view From reebalazs at codespeak.net Tue Dec 12 21:45:31 2006 From: reebalazs at codespeak.net (reebalazs at codespeak.net) Date: Tue, 12 Dec 2006 21:45:31 +0100 (CET) Subject: [KSS-checkins] r35658 - kukit/kss.core/trunk/tests Message-ID: <20061212204531.F38AE1008A@code0.codespeak.net> Author: reebalazs Date: Tue Dec 12 21:45:30 2006 New Revision: 35658 Modified: kukit/kss.core/trunk/tests/base.py Log: Fix test, it is better to use self.portal.REQUEST Modified: kukit/kss.core/trunk/tests/base.py ============================================================================== --- kukit/kss.core/trunk/tests/base.py (original) +++ kukit/kss.core/trunk/tests/base.py Tue Dec 12 21:45:30 2006 @@ -107,7 +107,7 @@ def setDebugRequest(self): 'commands will be rendered as test friendly data structures' - request = self.portal.REQUEST + request = self.folder.REQUEST iapi.directlyProvides(request, iapi.directlyProvidedBy(request) + IDebugRequest) def beforeTearDown(self): From jvloothuis at codespeak.net Sat Dec 16 00:01:37 2006 From: jvloothuis at codespeak.net (jvloothuis at codespeak.net) Date: Sat, 16 Dec 2006 00:01:37 +0100 (CET) Subject: [KSS-checkins] r35824 - in kukit/kss.core/trunk: . tests Message-ID: <20061215230137.3DE731007C@code0.codespeak.net> Author: jvloothuis Date: Sat Dec 16 00:01:34 2006 New Revision: 35824 Modified: kukit/kss.core/trunk/azaxview.py kukit/kss.core/trunk/azaxview.txt kukit/kss.core/trunk/tests/test_azaxview.py Log: Fixed a problem with the tests and the registration of the site manager, it now directly hooks into the component api instead of going through the previously disabled zope.app.component setSite stuff. Modified: kukit/kss.core/trunk/azaxview.py ============================================================================== --- kukit/kss.core/trunk/azaxview.py (original) +++ kukit/kss.core/trunk/azaxview.py Sat Dec 16 00:01:34 2006 @@ -41,17 +41,14 @@ from interfaces import IAzaxEvent, IAzaxView from pluginregistry.commandset import getRegisteredCommandSet from zope import app, component, interface -from zope.app.component.hooks import setSite, setHooks -from zope.app.component.interfaces import ISite, ILocalSiteManager -from zope.app.component.site import clearSite +from zope.component import getSiteManager from zope.component.globalregistry import BaseGlobalComponents +from zope.component.persistentregistry import PersistentAdapterRegistry from zope.component.interfaces import IComponentLookup +from zope.component.interfaces import ComponentLookupError from zope.event import notify from zope.interface import implements, Interface from zope.publisher.browser import BrowserView -from zope.component.persistentregistry import PersistentAdapterRegistry -from zope.app.component.site import _findNextSiteManager -from zope.component.interfaces import ComponentLookupError class ViewSiteManager(BaseGlobalComponents): @@ -62,7 +59,6 @@ class SiteView(BrowserView): """A browser view that is its own site """ - implements(ISite) def __init__(self, context, request): super(SiteView, self).__init__(context, request) @@ -85,14 +81,12 @@ # register object event handler self._sitemanager.registerHandler(wrapped_view._eventRedispatcher) - ##setHooks() - ##setSite(self) - def getSiteManager(self): - return self._sitemanager + # make ourselve the default site manager + getSiteManager.sethook(self.getSiteManager) - def setSiteManager(self, sm): - raise NotImplementedError('You can only get the site manager') + def getSiteManager(self, context=None): + return self._sitemanager @component.adapter(Interface) def _eventRedispatcher(self, event): @@ -101,7 +95,8 @@ notify(azaxevent) def render(self): - pass #clearSite() + # reset the site manager to its original one + getSiteManager.reset() class AzaxBaseView(SiteView): """ Base kss view Modified: kukit/kss.core/trunk/azaxview.txt ============================================================================== --- kukit/kss.core/trunk/azaxview.txt (original) +++ kukit/kss.core/trunk/azaxview.txt Sat Dec 16 00:01:34 2006 @@ -25,6 +25,7 @@ >>> from zope.app.component.interfaces import ISite >>> from zope.interface import directlyProvides, directlyProvidedBy >>> from zope.publisher.browser import TestRequest + >>> import zope.component.event >>> from zope.app.folder import folder >>> myfolder = folder.rootFolder() Modified: kukit/kss.core/trunk/tests/test_azaxview.py ============================================================================== --- kukit/kss.core/trunk/tests/test_azaxview.py (original) +++ kukit/kss.core/trunk/tests/test_azaxview.py Sat Dec 16 00:01:34 2006 @@ -39,6 +39,7 @@ from zope import component from Products.Five import zcml import Products.Five +import zope.component.event #from zope.app.component.hooks import setSite, getSite, setHooks def setUpDoctTest(test=None): From jvloothuis at codespeak.net Sat Dec 16 11:51:27 2006 From: jvloothuis at codespeak.net (jvloothuis at codespeak.net) Date: Sat, 16 Dec 2006 11:51:27 +0100 (CET) Subject: [KSS-checkins] r35831 - kukit/kss.core/trunk Message-ID: <20061216105127.7F4BC1007F@code0.codespeak.net> Author: jvloothuis Date: Sat Dec 16 11:51:24 2006 New Revision: 35831 Modified: kukit/kss.core/trunk/azaxview.py kukit/kss.core/trunk/azaxview.txt kukit/kss.core/trunk/siteview.txt Log: Added a stopEventListening method to the site view. This makes it possible to deregister the view for event interception. The change will be used in unit tests but also may have some merrit in specific places. Modified: kukit/kss.core/trunk/azaxview.py ============================================================================== --- kukit/kss.core/trunk/azaxview.py (original) +++ kukit/kss.core/trunk/azaxview.py Sat Dec 16 11:51:24 2006 @@ -94,9 +94,13 @@ azaxevent = AzaxEvent(self, event) notify(azaxevent) - def render(self): + def stopEventListening(self): # reset the site manager to its original one - getSiteManager.reset() + if self.getSiteManager() is component.getSiteManager(): + getSiteManager.reset() + + def render(self): + self.stopEventListening() class AzaxBaseView(SiteView): """ Base kss view Modified: kukit/kss.core/trunk/azaxview.txt ============================================================================== --- kukit/kss.core/trunk/azaxview.txt (original) +++ kukit/kss.core/trunk/azaxview.txt Sat Dec 16 11:51:24 2006 @@ -25,7 +25,6 @@ >>> from zope.app.component.interfaces import ISite >>> from zope.interface import directlyProvides, directlyProvidedBy >>> from zope.publisher.browser import TestRequest - >>> import zope.component.event >>> from zope.app.folder import folder >>> myfolder = folder.rootFolder() Modified: kukit/kss.core/trunk/siteview.txt ============================================================================== --- kukit/kss.core/trunk/siteview.txt (original) +++ kukit/kss.core/trunk/siteview.txt Sat Dec 16 11:51:24 2006 @@ -2,9 +2,9 @@ Site view ========= -All Azax views are not only a browser view but a site as well. A site is Zope -used as a local component registry. You can hookup adapters etc. in such a -place. Azax views are made sites to intercept all incomming events. +All Azax views are not only a browser view but provide a site manager as well. +The site manager is hooked into the component framework on creation time. This +allows the Azax views to intercept all incomming events. By doing so the view is able to hookup it's own event redispatcher. This is a normal event handler which generates the specific Azax events. These events @@ -15,7 +15,7 @@ instance when you change a title in a document you also want the menu reloaded. By using events for this we can achieve a degree of decoupling. -The main class which implements views as a site is `SiteView`. +The main class which implements views with a site manager is `SiteView`. >>> from kss.core.azaxview import SiteView @@ -69,3 +69,23 @@ >>> view.render() >>> view.getSiteManager() is component.getSiteManager() False + +The view also has a specific way of unregistering itself for events. You can +use this from your tests or other specific use cases. First we will create a +new view to start listening. + + >>> view = SiteView(None, None) + +Now we will stop the view from listening to the events. + + >>> view.stopEventListening() + +If we raise an event we should only get the one event and not the AzaxEvent as well. + + >>> clearEvents() + >>> notify(ObjectModifiedEvent(None)) + >>> len(getEvents()) + 1 + >>> original_event = getEvents()[0] + >>> IObjectModifiedEvent.providedBy(original_event) + True From jvloothuis at codespeak.net Sat Dec 16 12:11:13 2006 From: jvloothuis at codespeak.net (jvloothuis at codespeak.net) Date: Sat, 16 Dec 2006 12:11:13 +0100 (CET) Subject: [KSS-checkins] r35832 - kukit/kss.core/trunk Message-ID: <20061216111113.4E82F1007F@code0.codespeak.net> Author: jvloothuis Date: Sat Dec 16 12:11:08 2006 New Revision: 35832 Modified: kukit/kss.core/trunk/azaxview.py Log: Made the stop event listening method set the hook to the previous one instead of resitting it. This should make sure that it doesn't break other overrides. Modified: kukit/kss.core/trunk/azaxview.py ============================================================================== --- kukit/kss.core/trunk/azaxview.py (original) +++ kukit/kss.core/trunk/azaxview.py Sat Dec 16 12:11:08 2006 @@ -63,11 +63,11 @@ def __init__(self, context, request): super(SiteView, self).__init__(context, request) - next_sitemanager = component.getSiteManager() + _next_sitemanager = component.getSiteManager() self._sitemanager = ViewSiteManager('siteview') - self._sitemanager.__bases__ = (next_sitemanager, ) + self._sitemanager.__bases__ = (_next_sitemanager, ) # On Five, we should wrap it in the acquisition context # see, if self has aq_parent, it is done obligatoraly @@ -82,7 +82,10 @@ # register object event handler self._sitemanager.registerHandler(wrapped_view._eventRedispatcher) - # make ourselve the default site manager + + # first get a reference to the old implementation before making + # ourselves the new default site manager + self._getSiteManagerHook = getSiteManager.implementation getSiteManager.sethook(self.getSiteManager) def getSiteManager(self, context=None): @@ -96,8 +99,7 @@ def stopEventListening(self): # reset the site manager to its original one - if self.getSiteManager() is component.getSiteManager(): - getSiteManager.reset() + getSiteManager.sethook(self._getSiteManagerHook) def render(self): self.stopEventListening() From jvloothuis at codespeak.net Tue Dec 19 21:16:47 2006 From: jvloothuis at codespeak.net (jvloothuis at codespeak.net) Date: Tue, 19 Dec 2006 21:16:47 +0100 (CET) Subject: [KSS-checkins] r35903 - kukit/kss.core/trunk Message-ID: <20061219201647.B542110075@code0.codespeak.net> Author: jvloothuis Date: Tue Dec 19 21:16:45 2006 New Revision: 35903 Modified: kukit/kss.core/trunk/azaxview.py kukit/kss.core/trunk/azaxview.txt Log: Removed unneeded handle method which did the same as event.notify Modified: kukit/kss.core/trunk/azaxview.py ============================================================================== --- kukit/kss.core/trunk/azaxview.py (original) +++ kukit/kss.core/trunk/azaxview.py Tue Dec 19 21:16:45 2006 @@ -140,12 +140,6 @@ def getCommands(self): return self.commands - def handle(self, *args): - for event in args: # first fire all normal stuff - notify(event) - for event in args: # now do the kss bits - component.handle(AzaxEvent(self, event)) - def getCommandSet(self, name): commandset = getRegisteredCommandSet(name) # return the adapted view Modified: kukit/kss.core/trunk/azaxview.txt ============================================================================== --- kukit/kss.core/trunk/azaxview.txt (original) +++ kukit/kss.core/trunk/azaxview.txt Tue Dec 19 21:16:45 2006 @@ -25,6 +25,7 @@ >>> from zope.app.component.interfaces import ISite >>> from zope.interface import directlyProvides, directlyProvidedBy >>> from zope.publisher.browser import TestRequest + >>> from zope import event >>> from zope.app.folder import folder >>> myfolder = folder.rootFolder() @@ -39,7 +40,7 @@ >>> class SampleView(AzaxBaseView): ... def add_page(self, title): ... # normally you would change the zope database here - ... self.handle(ObjectModifiedEvent(title)) + ... event.notify(ObjectModifiedEvent(title)) ... return self.render() >>> view = SampleView(myfolder, request) @@ -59,26 +60,6 @@ When we call the renderer now it should have some more data in it. + >>> view = SampleView(myfolder, request) >>> view.add_page("some title")[0]['params']['html'] u'some title' - -The example above used our convenience method to generate events. You normally -do this for all mutations you make yourself. Not all events are generated this -way though. In case of a workflow transition events may be fired as well. Azax -views account for this automatically. You don't need to do anything special. - -We will demonstrate this using a simple view. This view will generate the -modified event through normal component api instead of our handle method. - - >>> class AnotherView(AzaxBaseView): - ... def add_page(self, title): - ... # normally you would change the zope database here - ... notify(ObjectModifiedEvent(title)) - ... return self.render() - -This should now still invoke our handler. - - >>> view = AnotherView(myfolder, request) - >>> view.add_page("another title")[0]['params']['html'] - u'another title' - From reebalazs at codespeak.net Fri Dec 22 11:31:35 2006 From: reebalazs at codespeak.net (reebalazs at codespeak.net) Date: Fri, 22 Dec 2006 11:31:35 +0100 (CET) Subject: [KSS-checkins] r35946 - in kukit/kss.core/trunk: . tests Message-ID: <20061222103135.1A12C10082@code0.codespeak.net> Author: reebalazs Date: Fri Dec 22 11:31:16 2006 New Revision: 35946 Added: kukit/kss.core/trunk/siteview_life.txt Modified: kukit/kss.core/trunk/azaxview.py kukit/kss.core/trunk/tests/base.py kukit/kss.core/trunk/tests/test_siteview.py Log: kss: fix the siteview. It needs to stopEventListening if an EndRequest event arrives. Without this the failing requests linger forever listening, and only zope restart clears the situation. Modified: kukit/kss.core/trunk/azaxview.py ============================================================================== --- kukit/kss.core/trunk/azaxview.py (original) +++ kukit/kss.core/trunk/azaxview.py Fri Dec 22 11:31:16 2006 @@ -49,6 +49,7 @@ from zope.event import notify from zope.interface import implements, Interface from zope.publisher.browser import BrowserView +from zope.app.publication.interfaces import IEndRequestEvent class ViewSiteManager(BaseGlobalComponents): @@ -93,6 +94,10 @@ @component.adapter(Interface) def _eventRedispatcher(self, event): + if IEndRequestEvent.providedBy(event): + # If this happens, we must finish activity + self.stopEventListening() + return if not IAzaxEvent.providedBy(event): azaxevent = AzaxEvent(self, event) notify(azaxevent) Added: kukit/kss.core/trunk/siteview_life.txt ============================================================================== --- (empty file) +++ kukit/kss.core/trunk/siteview_life.txt Fri Dec 22 11:31:16 2006 @@ -0,0 +1,104 @@ +===================== +Site view, life cycle +===================== + +... or, making the view a site manager is a good idea after +all, but let's see what dangers are lurking in the dark. + +Checking if the view finishes its lifetime +------------------------------------------ + +It is important that the view does not stay on after the +request. This would cause them to continue listening to +events. We need a few imports first. + + >>> from kss.core.azaxview import SiteView + + >>> from zope.interface import Interface, implements + >>> from zope.component import adapter + >>> from zope.lifecycleevent import ObjectModifiedEvent + >>> from zope.event import notify + >>> from zope.app.publication.interfaces import IEndRequestEvent + >>> try: + ... from Products.Five.testbrowser import Browser + ... except ImportError: + ... from zope.testbrowser.browser import Browser + +First, let's create a funky view that has two methods, one +failing and one succeeding, and a habit to choke on any +events. + + >>> class FunkyView(SiteView): + ... def IAmGood(self): + ... 'XXX' + ... return self.render() + ... def IAmBad(self): + ... 'XXX' + ... raise Exception, 'Generic badness' + ... @adapter(Interface) + ... def _eventRedispatcher(self, event): + ... SiteView._eventRedispatcher(self, event) + ... if not IEndRequestEvent.providedBy(event): + ... raise Exception, 'Too late event %r' % event + + >>> import kss.core.tests + >>> kss.core.tests.FunkyView = FunkyView + +We provide this view as a browser page. We care to register +it properly, otherwise we would miss some Five acquisition +woodoo. (XXX Note that this must be adjusted to run on Zope3.) + + >>> try: + ... import Products.Five + ... except ImportError: + ... # probably zope 3, not supported + ... raise 'Zope3 not supported in this test' + ... else: + ... from Products.Five.zcml import load_string, load_config + + >>> load_string(''' + ... + ... + ... + ... + ... ''') + +Create a test browser now, so we can finally start. + + >>> browser = Browser() + +Let's call up the good request. + + >>> browser.open(self.folder.absolute_url() + '/@@funky_view/IAmGood') + +Now, if we happen to send an event... nothing happens, since +the render() method has taken care of unregistering the +event as a SiteView. + + >>> notify(ObjectModifiedEvent(None)) + +But it is also important, that even in case the render +method does not run (it gives an error since we raised an +exception, this is all right). We would already get an error +during this, thanks to the RequestEvent that arrives. + + >>> browser = browser.open('http://nohost/@@funky_view/IAmBad') + Traceback (most recent call last): + ... + HTTPError: HTTP Error 500: Internal Server Error + +And even if we send a new event, it must not get to the +redispatcher of the view. + + >>> notify(ObjectModifiedEvent(None)) + Modified: kukit/kss.core/trunk/tests/base.py ============================================================================== --- kukit/kss.core/trunk/tests/base.py (original) +++ kukit/kss.core/trunk/tests/base.py Fri Dec 22 11:31:16 2006 @@ -19,7 +19,7 @@ # Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA # 02111-1307, USA. # -from Testing.ZopeTestCase import ZopeTestCase +from Testing.ZopeTestCase import ZopeTestCase, FunctionalTestCase import kss.core from kss.core import AzaxBaseView from OFS.SimpleItem import SimpleItem @@ -49,7 +49,7 @@ class IDebugRequest(IBrowserRequest): 'The debug request' -class AzaxViewTestCase(ZopeTestCase): +class KssViewTestCase(ZopeTestCase): def afterSetUp(self): placelesssetup.setUp() @@ -120,3 +120,10 @@ else: import Products.Five.zcml Products.Five.zcml._context = None + +class KssViewFunctionalTestCase(FunctionalTestCase, KssViewTestCase): + 'Functional test base' + + +# backward compatibility +AzaxViewTestCase = KssViewTestCase Modified: kukit/kss.core/trunk/tests/test_siteview.py ============================================================================== --- kukit/kss.core/trunk/tests/test_siteview.py (original) +++ kukit/kss.core/trunk/tests/test_siteview.py Fri Dec 22 11:31:16 2006 @@ -1,25 +1,14 @@ -#from base import AzaxViewTestCase, FakeContent, TestRequest, DebugTestRequest -#from kss.core import AzaxUnicodeError -#from kss.core.events import AzaxEvent -#from kss.core.interfaces import IAzaxCommands, IAzaxEvent -#from kss.core.interfaces import IAzaxView -#from kss.core.pluginregistry.action import Action -#from kss.core.pluginregistry.commandset import CommandSet -#from kss.core.pluginregistry.interfaces import IAction, ICommandSet -#from kss.core.pluginregistry.plugin import registerPlugin -#from kss.core.plugins.core.commands import KSSCoreCommands -#from kss.core.plugins.core.interfaces import IKSSCoreCommands -#from kss.core.tests.base import IDebugRequest -#from kss.core.tests.commandinspector import CommandInspectorView from Products.Five import zcml from zope import component from zope.component import eventtesting from zope.testing import doctest from zope.testing.cleanup import CleanUp as PlacelessSetup import Products.Five -import unittest #, os +import unittest +from Testing.ZopeTestCase import FunctionalDocFileSuite +from base import KssViewFunctionalTestCase -def setUpDoctTest(test=None): +def setUpDocTest(test=None): PlacelessSetup().setUp() eventtesting.setUp() @@ -29,11 +18,31 @@ zcml.load_config("configure.zcml", Products.Five.site) -def tearDownDoctTest(test=None): +def tearDownDocTest(test=None): PlacelessSetup().tearDown() +def setUpFDocTest(test=None): + #PlacelessSetup().setUp() + KssViewFunctionalTestCase.setUp(test) + eventtesting.setUp() + +# zcml.load_config("meta.zcml", Products.Five) +# zcml.load_config("permissions.zcml", Products.Five) +# zcml.load_config("configure.zcml", Products.Five.component) +# +# zcml.load_config("configure.zcml", Products.Five.site) +# zcml.load_config("configure.zcml", Products.Five.site) + +def tearDownFDocTest(test=None): + #PlacelessSetup().tearDown() + KssViewFunctionalTestCase.tearDown(test) + def test_suite(): - suite = doctest.DocFileSuite('../siteview.txt', - setUp=setUpDoctTest, - tearDown=tearDownDoctTest) + suite = FunctionalDocFileSuite('../siteview.txt', + setUp=setUpDocTest, + tearDown=tearDownDocTest) + suite = FunctionalDocFileSuite('../siteview_life.txt', + test_class=KssViewFunctionalTestCase, + setUp=setUpFDocTest, + tearDown=tearDownFDocTest) return unittest.TestSuite(suite) From reebalazs at codespeak.net Fri Dec 22 12:01:18 2006 From: reebalazs at codespeak.net (reebalazs at codespeak.net) Date: Fri, 22 Dec 2006 12:01:18 +0100 (CET) Subject: [KSS-checkins] r35948 - in kukit/kss.core/trunk: . plugins/core plugins/effects Message-ID: <20061222110118.DABB910086@code0.codespeak.net> Author: reebalazs Date: Fri Dec 22 12:01:15 2006 New Revision: 35948 Modified: kukit/kss.core/trunk/azaxview.py kukit/kss.core/trunk/interfaces.py kukit/kss.core/trunk/plugins/core/commands.py kukit/kss.core/trunk/plugins/effects/commands.py Log: Renamed AzaxViewAdapter to CommandSet. Fixed its lieing interface. Moved __allow...unprotected to the CommandSet from the plugin implementations. Modified: kukit/kss.core/trunk/azaxview.py ============================================================================== --- kukit/kss.core/trunk/azaxview.py (original) +++ kukit/kss.core/trunk/azaxview.py Fri Dec 22 12:01:15 2006 @@ -38,7 +38,7 @@ from commands import AzaxCommands from events import AzaxEvent -from interfaces import IAzaxEvent, IAzaxView +from interfaces import IAzaxEvent, IAzaxView, ICommandSet from pluginregistry.commandset import getRegisteredCommandSet from zope import app, component, interface from zope.component import getSiteManager @@ -150,8 +150,13 @@ # return the adapted view return commandset.provides(self) -class AzaxViewAdapter: - implements(IAzaxView) +class CommandSet: + implements(ICommandSet) + + # XXX This is really bad. Is is needed for restricted access? + # If not, it has to go. If no, it needs an alternate solution. + # also we need test for this. + __allow_access_to_unprotected_subobjects__ = True def __init__(self, view): self.view = view @@ -161,3 +166,6 @@ def getCommandSet(self, name): return self.view.getCommandSet(name) + +# XXX to be deprecated +AzaxViewAdapter = CommandSet Modified: kukit/kss.core/trunk/interfaces.py ============================================================================== --- kukit/kss.core/trunk/interfaces.py (original) +++ kukit/kss.core/trunk/interfaces.py Fri Dec 22 12:01:15 2006 @@ -110,6 +110,12 @@ def render(): '' +class ICommandSet(Interface): + 'Methods of this class implement a command set' + + def getCommandSet(self, name): + 'Returns the command set for a given name' + class IAzaxEvent(Interface): """Used to notify of events during an Ajax call Modified: kukit/kss.core/trunk/plugins/core/commands.py ============================================================================== --- kukit/kss.core/trunk/plugins/core/commands.py (original) +++ kukit/kss.core/trunk/plugins/core/commands.py Fri Dec 22 12:01:15 2006 @@ -1,13 +1,12 @@ from interfaces import IKSSCoreCommands from kss.core.selectors import Selector, CssSelector, HtmlIdSelector -from kss.core.azaxview import AzaxViewAdapter +from kss.core.azaxview import CommandSet from kss.core.deprecated import deprecated from kss.core.parsers import XmlParser, HtmlParser from kss.core.plugins.core.interfaces import IKSSCoreCommands from zope.interface import implements -class KSSCoreCommands(AzaxViewAdapter): - __allow_access_to_unprotected_subobjects__ = 1 +class KSSCoreCommands(CommandSet): implements(IKSSCoreCommands) def getSelector(self, type, selector): Modified: kukit/kss.core/trunk/plugins/effects/commands.py ============================================================================== --- kukit/kss.core/trunk/plugins/effects/commands.py (original) +++ kukit/kss.core/trunk/plugins/effects/commands.py Fri Dec 22 12:01:15 2006 @@ -1,8 +1,7 @@ from interfaces import IScriptaculousEffectsCommands -from kss.core.azaxview import AzaxViewAdapter +from kss.core.azaxview import CommandSet -class ScriptaculousEffectsCommands(AzaxViewAdapter): - __allow_access_to_unprotected_subobjects__ = 1 +class ScriptaculousEffectsCommands(CommandSet): def effect(self, selector, type): """ see interfaces.py """ From reebalazs at codespeak.net Tue Dec 26 12:16:46 2006 From: reebalazs at codespeak.net (reebalazs at codespeak.net) Date: Tue, 26 Dec 2006 12:16:46 +0100 (CET) Subject: [KSS-checkins] r35983 - kukit/kukit.js/trunk/kukit Message-ID: <20061226111646.969381007A@code0.codespeak.net> Author: reebalazs Date: Tue Dec 26 12:16:44 2006 New Revision: 35983 Modified: kukit/kukit.js/trunk/kukit/kukit.js kukit/kukit.js/trunk/kukit/plugin.js Log: Implement an error command that can be used to signal an error condition with a reason displayed in the kss log. Modified: kukit/kukit.js/trunk/kukit/kukit.js ============================================================================== --- kukit/kukit.js/trunk/kukit/kukit.js (original) +++ kukit/kukit.js/trunk/kukit/kukit.js Tue Dec 26 12:16:44 2006 @@ -221,6 +221,16 @@ /* Server notification */ +// this should be thrown with the error command as parameter +kukit.ExplicitError = kukit.ut.exceptionFactory('ExplicitError'); +kukit.ExplicitError.prototype.__superinit__ = kukit.ExplicitError.prototype.__init__; +kukit.ExplicitError.prototype.__init__ = function(name, errorcommand) { + var message = 'Explicit error, reason=' + errorcommand.parms.message; + var kw = this.__superinit__(name, message); + kw.errorcommand = errorcommand; + return kw +}; + // Backparms can be used on command execution. kukit.notifyServer = function(url, params, oper) { var sendHook = function(queueItem) { @@ -278,6 +288,8 @@ kukit.logFatal(msg); // just throw it too... throw msg; + } else if (e.name == 'ExplicitError') { + kukit.processError(oper, e.errorcommand); } else { kukit.logError('Unhandled error during command execution: ' + e); // also IE acts foul on thrown errors @@ -312,8 +324,7 @@ // 1. No response from server, and browser notifies us with an empty response // 2. There was an error on the server, and we got an error message as response // Call the error handler. - kukit.processError(oper); - return; + throw new kukit.ExplicitError(); } // Opera <= 8.5 does not have the parseError attribute, so check for it first if (domXml.parseError && (domXml.parseError != 0)) { @@ -330,18 +341,22 @@ command_processor.executeCommands(oper); }; -kukit.processError = function(oper) { +kukit.processError = function(oper, errorcommand) { var error_action = null; if (oper.eventrule) { var error_action = oper.eventrule.actions.getErrorActionFor(oper.action); } + var reason = ''; + if (typeof(errorcommand) != 'undefined') { + reason = ', reason="' + errorcommand.parms.message + '" ' + } if (error_action) { - kukit.logWarning('Request failed at url ' + oper.queueItem.url + ', rid=' + oper.queueItem.rid + ', will be handled by action "' + error_action.name + '"'); + kukit.logWarning('Request failed at url ' + oper.queueItem.url + ', rid=' + oper.queueItem.rid + reason + ', will be handled by action "' + error_action.name + '"'); // Individual error handler was defined. Execute it! error_action.execute(oper); } else { // Unhandled: just log it... - kukit.logError('Request failed at url ' + oper.queueItem.url + ', rid=' + oper.queueItem.rid); + kukit.logError('Request failed at url ' + oper.queueItem.url + ', rid=' + oper.queueItem.rid) + reason; } }; @@ -363,6 +378,14 @@ for (var y=0;y < commands.length;y++) { var command = commands[y]; this.parseCommand(command, transport); + // If we receive an error command, we handle that separately. + // We abort immediately and let the processError handler do its job. + // This means that although no other commands should be in commands, + // we make sure we execute none of them. + var lastcommand = this.commands[this.commands.length-1]; + if (lastcommand.name == 'error') { + throw new kukit.ExplicitError(lastcommand); + } } }; Modified: kukit/kukit.js/trunk/kukit/plugin.js ============================================================================== --- kukit/kukit.js/trunk/kukit/plugin.js (original) +++ kukit/kukit.js/trunk/kukit/plugin.js Tue Dec 26 12:16:44 2006 @@ -312,6 +312,12 @@ * They also get registered as commands */ +kukit.ar.actionRegistry.register("error", function (oper) { + throw 'The builtin error action should never execute.'; + } +); +kukit.cr.commandRegistry.registerFromAction('error', kukit.cr.makeGlobalCommand); + kukit.ar.actionRegistry.register("logDebug", function (oper) { oper.completeParms([], {'message': 'Logging from Event'}, 'logDebug action'); var node = oper.node; From reebalazs at codespeak.net Tue Dec 26 12:24:56 2006 From: reebalazs at codespeak.net (reebalazs at codespeak.net) Date: Tue, 26 Dec 2006 12:24:56 +0100 (CET) Subject: [KSS-checkins] r35984 - in kukit/kss.core/trunk: . plugins/core tests Message-ID: <20061226112456.F08F61007A@code0.codespeak.net> Author: reebalazs Date: Tue Dec 26 12:24:54 2006 New Revision: 35984 Added: kukit/kss.core/trunk/actionwrapper.py Modified: kukit/kss.core/trunk/__init__.py kukit/kss.core/trunk/azaxview.py kukit/kss.core/trunk/plugins/core/configure.zcml kukit/kss.core/trunk/tests/test_azaxview.py Log: Implement kssaction wrapper for action view methods This is an alternate way of making view methods. First, self.render() is not needed to be returned at the end. Second, if KssExplicitError is raised, that will not cause an error log on the server, but instead it sends the error command to the client, which in return displays the fallback reason and executes its error action. Modified: kukit/kss.core/trunk/__init__.py ============================================================================== --- kukit/kss.core/trunk/__init__.py (original) +++ kukit/kss.core/trunk/__init__.py Tue Dec 26 12:24:54 2006 @@ -18,16 +18,18 @@ # Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA # 02111-1307, USA. # -__all__ = ('AzaxBaseView', 'force_unicode', 'AzaxUnicodeError', 'AzaxCommands') +__all__ = ('AzaxBaseView', 'force_unicode', 'AzaxUnicodeError', + 'IKssExplicitError', 'KssExplicitError', 'kssaction', + ) import mimetypes mimetypes.types_map['.kkt'] = 'text/xml' # XXX legacy! mimetypes.types_map['.kukit'] = 'text/xml' -from azaxview import AzaxBaseView +from azaxview import AzaxBaseView +from actionwrapper import KssExplicitError, kssaction from unicode_quirks import force_unicode, AzaxUnicodeError -from commands import AzaxCommands, AzaxCommand, AzaxParam try: import Products.Five @@ -36,6 +38,7 @@ else: # Allow to build commands from restricted code from AccessControl import allow_class + from commands import AzaxCommands, AzaxCommand, AzaxParam allow_class(AzaxCommands) allow_class(AzaxCommand) allow_class(AzaxParam) Added: kukit/kss.core/trunk/actionwrapper.py ============================================================================== --- (empty file) +++ kukit/kss.core/trunk/actionwrapper.py Tue Dec 26 12:24:54 2006 @@ -0,0 +1,248 @@ +# Copyright (c) 2005-2006 +# Authors: KSS project contributors +# +# 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 textwrap import dedent +from inspect import formatargspec, getargspec, getargvalues, \ + formatargvalues, currentframe +from zope.interface import implements + +class KssExplicitError(Exception): + 'Explicit error to be raised' + +class kssaction(object): + '''Descriptor to bundle kss server actions. + + - render() will be called automatically if there is no + return value + + - if KssExplicitError is raised, a normal response is returned, + containing a single command:error azax command. + + Let's say we have a class here - that is supposed to be a kss view. + + >>> from kss.core import kssaction, KssExplicitError, AzaxBaseView + + >>> class MyView(AzaxBaseView): + ... def ok(self, a, b, c=0): + ... return 'OK %s %s %s' % (a, b, c) + ... def notok(self, a, b, c=0): + ... pass + ... def error(self, a, b, c=0): + ... raise KssExplicitError, 'The error' + ... def exception(self, a, b, c=0): + ... raise Exception, 'Unknown exception' + + Now we try qualifying with kssaction. We overwrite render too, + just to enable sensible testing of the output: + + >>> class MyView(AzaxBaseView): + ... def render(self): + ... return 'Rendered' + ... @kssaction + ... def ok(self, a, b, c=3): + ... return 'OK %s %s %s' % (a, b, c) + ... @kssaction + ... def notok(self, a, b, c=3): + ... pass + ... @kssaction + ... def error(self, a, b, c=3): + ... raise KssExplicitError, 'The error' + ... @kssaction + ... def exception(self, a, b, c=3): + ... raise Exception, 'Unknown exception' + + Instantiate a view. + + >>> view = MyView(None, None) + + Now, of course ok renders well. + + >>> view.ok(1, b=2) + 'OK 1 2 3' + + Not ok will have implicit rendering. + + >>> view.notok(1, b=2) + 'Rendered' + + The third type will return an error action. But it will render + instead of an error. + + >>> view.error(1, b=2) + 'Rendered' + + The fourth type will be a real error. + + >>> view.exception(1, b=2) + Traceback (most recent call last): + ... + Exception: Unknown exception + + Now for the sake of it, let's test the rendered kukit response. + So, we don't overwrite render like as we did in the previous + tests. + + >>> from zope.publisher.browser import TestRequest + + >>> class MyView(AzaxBaseView): + ... @kssaction + ... def error(self, a, b, c=3): + ... raise KssExplicitError, 'The error' + ... @kssaction + ... def with_docstring(self, a, b, c=3): + ... "Docstring" + ... raise KssExplicitError, 'The error' + + >>> request = TestRequest() + >>> view = MyView(None, request) + + Set debug-mode command rendering so we can see the results in a + more structured form. + + >>> from zope import interface as iapi + >>> from kss.core.tests.base import IDebugRequest + >>> iapi.directlyProvides(request, iapi.directlyProvidedBy(request) + IDebugRequest) + + See the results: + + >>> view.error(1, b=2) + [{'selectorType': None, 'params': {'message': u'The error'}, 'name': 'error', 'selector': None}] + + Usage of the method wrapped in browser view + ------------------------------------------- + + Finally, let's check if the method appears if defined on a browser view. + Since there could be a thousand reasons why Five's magic could fail, + it's good to check this. (XXX Note that this must be adjusted to run on Zope3.) + + >>> try: + ... import Products.Five + ... except ImportError: + ... # probably zope 3, not supported + ... raise 'Zope3 not supported in this test' + ... else: + ... from Products.Five.zcml import load_string, load_config + + >>> import kss.core.tests + >>> kss.core.tests.MyView = MyView + + We check for two basic types of declaration. The first one declares + a view with different attributes. The second one declares a dedicated + view with the method as the view default method. This is how we use + it in several places. + + >>> load_string(""" + ... + ... + ... + ... + ... + ... + ... """) + + Let's check it now: + + >>> self.folder.restrictedTraverse('/@@my_view/error') + >> v = self.folder.restrictedTraverse('/my_view2') + >>> isinstance(v, MyView) + True + >>> hasattr(v, 'error') + True + >>> v(1, b=2) + [{'selectorType': None, 'params': {'message': u'The error'}, 'name': 'error', 'selector': None}] + + In addition, to be publishable, the docstring must exist. Let's + see if the wrapper actually does this. If the method had a docstring, + it will be reused, but a docstring is provided in any case. + + >>> v = self.folder.restrictedTraverse('/@@my_view') + >>> bool(v.error.__doc__) + True + + >>> v.with_docstring.__doc__ + 'Docstring' + + ''' + def __init__(self, f): + self.f = f + # Now this is a solution I don't like, but we need the same + # function signature, otherwise the ZPublisher won't marshall + # the parameters. *arg, **kw would not suffice since no parameters + # would be marshalled at all. + argspec = getargspec(f) + orig_args = formatargspec(*argspec)[1:-1] + if argspec[3] is None: + fixed_args_num = len(argspec[0]) + else: + fixed_args_num = len(argspec[0]) - len(argspec[3]) + values_list = [v for v in argspec[0][:fixed_args_num]] + values_list.extend(['%s=%s' % (v, v) for v in argspec[0][fixed_args_num:]]) + values_args = ', '.join(values_list) + # provide a docstring in any case. + if self.f.__doc__ is not None: + docstring = repr(f.__doc__) + else: + docstring = '"XXX"' + # orig_args: "a, b, c=2" + # values_args: "a, b, c=c" + code = dedent('''\n + def wrapper(%s): + %s + return descr.apply(%s) + ''' % (orig_args, docstring, values_args)) + self.wrapper_code = compile(code, '', 'exec') + + def __get__(self, obj, cls=None): + d = {'descr': self, 'self': obj} + exec(self.wrapper_code, d) + wrapper = d['wrapper'].__get__(obj, cls) + return wrapper + + def apply(self, obj, *arg, **kw): + try: + result = self.f(obj, *arg, **kw) + except KssExplicitError, exc: + # Clear all the commands, and emit an error command + obj._initcommands() + obj.commands.addCommand('error', message=str(exc)) + result = None + if result is None: + # render not returned - so we do it. + result = obj.render() + return result Modified: kukit/kss.core/trunk/azaxview.py ============================================================================== --- kukit/kss.core/trunk/azaxview.py (original) +++ kukit/kss.core/trunk/azaxview.py Tue Dec 26 12:24:54 2006 @@ -120,6 +120,9 @@ def __init__(self, context, request): super(AzaxBaseView, self).__init__(context, request) + self._initcommands() + + def _initcommands(self): self.commands = AzaxCommands() def _set_context(self, context): Modified: kukit/kss.core/trunk/plugins/core/configure.zcml ============================================================================== --- kukit/kss.core/trunk/plugins/core/configure.zcml (original) +++ kukit/kss.core/trunk/plugins/core/configure.zcml Tue Dec 26 12:24:54 2006 @@ -112,7 +112,15 @@ - + + + + + Author: reebalazs Date: Tue Dec 26 12:25:39 2006 New Revision: 35985 Modified: kukit/kss.demo/trunk/azaxview.py kukit/kss.demo/trunk/browser/error_handling.pt Log: Modify the error_handling demo to check the explitit error marshalling. Modified: kukit/kss.demo/trunk/azaxview.py ============================================================================== --- kukit/kss.demo/trunk/azaxview.py (original) +++ kukit/kss.demo/trunk/azaxview.py Tue Dec 26 12:25:39 2006 @@ -19,7 +19,7 @@ # 02111-1307, USA. # -from kss.core import AzaxBaseView, force_unicode +from kss.core import AzaxBaseView, force_unicode, KssExplicitError, kssaction import datetime class AzaxView(AzaxBaseView): @@ -154,9 +154,12 @@ self.getCommandSet('effects').effect('.effects', 'appear') return self.render() + @kssaction def errTest(self, id, act): if act == 'error': raise Exception, 'We have an error here.' + elif act == 'explicit': + raise KssExplicitError, 'Explicit error raised.' elif act == 'empty': # Just do nothing, we want to return a response with no commands. # This is valid behaviour, should raise no error, however Modified: kukit/kss.demo/trunk/browser/error_handling.pt ============================================================================== --- kukit/kss.demo/trunk/browser/error_handling.pt (original) +++ kukit/kss.demo/trunk/browser/error_handling.pt Tue Dec 26 12:25:39 2006 @@ -42,6 +42,8 @@ value="Error" /> +

The buttons in the second row have individual error handlers.

@@ -54,6 +56,8 @@ value="Error" /> +

You can also try suspending your server process and start generating timed out requests. From reebalazs at codespeak.net Tue Dec 26 13:14:41 2006 From: reebalazs at codespeak.net (reebalazs at codespeak.net) Date: Tue, 26 Dec 2006 13:14:41 +0100 (CET) Subject: [KSS-checkins] r35986 - kukit/kukit.js/trunk/kukit Message-ID: <20061226121441.762221007A@code0.codespeak.net> Author: reebalazs Date: Tue Dec 26 13:14:39 2006 New Revision: 35986 Modified: kukit/kukit.js/trunk/kukit/plugin.js kukit/kukit.js/trunk/kukit/utils.js Log: Fix kss logging to the FireFox console working with FF 2 too. Modified: kukit/kukit.js/trunk/kukit/plugin.js ============================================================================== --- kukit/kukit.js/trunk/kukit/plugin.js (original) +++ kukit/kukit.js/trunk/kukit/plugin.js Tue Dec 26 13:14:39 2006 @@ -84,11 +84,6 @@ this.__bind__(name, func_to_bind, oper); }; -// Sigh. We need this. -try { - kukit.pl.have_Safari = navigator.vendor && navigator.vendor.indexOf('Apple') != -1; -} catch (e) {} - kukit.pl.NativeEventBinder.prototype.__bind__ = function(name, func_to_bind, oper) { oper.completeParms([], {'preventdefault': '', 'allowbubbling': ''}, 'native event binding'); oper.evalBool('preventdefault', 'native event binding'); @@ -123,7 +118,7 @@ // necessary since Safari does not prevent the following // (in case of allowbubbling we have to apply it to all clicks, as there // might be a link inside that we cannot detect on the current node) - if (preventdefault && kukit.pl.have_Safari + if (preventdefault && kukit.HAVE_SAFARI && (allowbubbling || name == 'click' && node.tagName.toLowerCase() == 'a')) { function cancelClickSafari() { return false; Modified: kukit/kukit.js/trunk/kukit/utils.js ============================================================================== --- kukit/kukit.js/trunk/kukit/utils.js (original) +++ kukit/kukit.js/trunk/kukit/utils.js Tue Dec 26 13:14:39 2006 @@ -26,11 +26,21 @@ var kukit = {}; } +// Browser identification. We need this one only atm. +try { + kukit.HAVE_SAFARI = navigator.vendor && navigator.vendor.indexOf('Apple') != -1; +} catch (e) {} + /* check whether the logging stuff of Firebug is available */ try { console.log('Initializing kukit'); /* following call is needed to generate exception in Safari */ - console.assertEquals('kukit', 'kukit'); + // XXX this fails now on FF 2 too. Can some Safari user please + // check the current logging solution and adjust accordingly? + //console.assertEquals('kukit', 'kukit'); + if (kukit.HAVE_SAFARI) { + throw "Let's get out."; + } kukit.hasFirebug = true; } catch(e) { kukit.hasFirebug = false; From reebalazs at codespeak.net Wed Dec 27 11:23:16 2006 From: reebalazs at codespeak.net (reebalazs at codespeak.net) Date: Wed, 27 Dec 2006 11:23:16 +0100 (CET) Subject: [KSS-checkins] r35990 - kukit/kukit.js/trunk/kukit Message-ID: <20061227102316.801BA1007A@code0.codespeak.net> Author: reebalazs Date: Wed Dec 27 11:23:14 2006 New Revision: 35990 Modified: kukit/kukit.js/trunk/kukit/kukit.js Log: if a non-xml command result arrives, also analyze the X-KSSCOMMANDS response header for a payload. This makes it possible to attach a kss 'error' command on a standard error message page. Modified: kukit/kukit.js/trunk/kukit/kukit.js ============================================================================== --- kukit/kukit.js/trunk/kukit/kukit.js (original) +++ kukit/kukit.js/trunk/kukit/kukit.js Wed Dec 27 11:23:14 2006 @@ -225,12 +225,14 @@ kukit.ExplicitError = kukit.ut.exceptionFactory('ExplicitError'); kukit.ExplicitError.prototype.__superinit__ = kukit.ExplicitError.prototype.__init__; kukit.ExplicitError.prototype.__init__ = function(name, errorcommand) { - var message = 'Explicit error, reason=' + errorcommand.parms.message; + var message = 'Explicit error'; var kw = this.__superinit__(name, message); kw.errorcommand = errorcommand; return kw }; +kukit.ResponseParsingError = kukit.ut.exceptionFactory('ResponseParsingError'); + // Backparms can be used on command execution. kukit.notifyServer = function(url, params, oper) { var sendHook = function(queueItem) { @@ -241,7 +243,7 @@ var timeoutHook = function(queueItem) { // store the queue reception on the oper oper.queueItem = queueItem; - kukit.processError(oper); + kukit.processError(oper, 'timeout'); }; kukit.requestManager.notifyServer(sendHook, url, timeoutHook); }; @@ -288,6 +290,8 @@ kukit.logFatal(msg); // just throw it too... throw msg; + } else if (e.name == 'ResponseParsingError') { + kukit.processError(oper, 'Response parsing error: ' + e); } else if (e.name == 'ExplicitError') { kukit.processError(oper, e.errorcommand); } else { @@ -303,39 +307,75 @@ } }; -kukit.getNsTags = function(domXml, tagName) { - if (domXml.getElementsByTagNameNS) { - tags = domXml.getElementsByTagNameNS('http://www.kukit.org/commands/1.0', +kukit.getNsTags = function(dom, tagName) { + if (dom.getElementsByTagNameNS) { + tags = dom.getElementsByTagNameNS('http://www.kukit.org/commands/1.0', tagName); } else { //IE does not know DOM2 - tags = domXml.getElementsByTagName('kukit:' + tagName); + tags = dom.getElementsByTagName('kukit:' + tagName); } return tags; }; kukit.processResult = function(domDoc, oper) { - var domXml = domDoc.responseXML; - // for IE, an empty response is produced: we need to check the html tag - // On Opera, we don't even get to here: we can only catch timeouts elsewhere - if (domXml == null || typeof(domXml) == 'undefined' || kukit.getNsTags(domXml, 'commands').length != 1) { - // This will happen in case there are errors in the response - // Possible cases: - // 1. No response from server, and browser notifies us with an empty response - // 2. There was an error on the server, and we got an error message as response - // Call the error handler. - throw new kukit.ExplicitError(); - } - // Opera <= 8.5 does not have the parseError attribute, so check for it first - if (domXml.parseError && (domXml.parseError != 0)) { - kukit.logError(Sarissa.getParseErrorText(domXml)); - return; + // checking various dom process errors, and get the commands part + // + // + var dom; + var commandstags = []; + // Let's process xml payload first: + if (domDoc.responseXML) { + dom = domDoc.responseXML; + commandstags = kukit.getNsTags(dom, 'commands'); + if (commandstags.length != 1) { + // no good, maybe better luck with it as html payload + dom = null; + } + } + // Check for html too, this enables setting the kss error command on the + // error response. + if (dom == null) { + // Read the header and load it as xml, if defined. + var payload = domDoc.getResponseHeader('X-KSSCOMMANDS'); + if (payload) { + var root_txt = '' + payload + ''; + try { + dom = (new DOMParser()).parseFromString(root_txt, "text/xml"); + } catch(e) { + // XXX this does not work on Opera for sure + //throw new kukit.ResponseParsingError('Exception: "' + e + '"'); + throw new kukit.ResponseParsingError('Error parsing X-KSSCOMMANDS header.'); + } + commandstags = kukit.getNsTags(dom, 'commands'); + if (commandstags.length != 1) { + // no good + dom = null; + } + } else { + // Ok. we have not found it either in the headers. + // Check if there was a parsing error in the xml, and log it as reported from the dom + // Opera <= 8.5 does not have the parseError attribute, so check for it first + dom = domDoc.responseXML; + if (dom && dom.parseError && (dom.parseError != 0)) { + throw new kukit.ResponseParsingError('KSS payload not found: ' + Sarissa.getParseErrorText(dom)); + } else { + throw new kukit.ResponseParsingError('KSS payload not found'); + } + } } - commands = kukit.getNsTags(domXml, 'command'); + if (dom == null) { + // this should not happen + throw new kukit.ResponseParsingError('Neither xml nor html payload.'); + } + // find the commands (atm we don't limit ourselves inside the commandstag) + var commands = kukit.getNsTags(dom, 'command'); + // Warning, if there is a valid response containing 0 commands. if (commands.length == 0) { kukit.logWarning('No commands in kukit response'); return; } + // One or more valid commands to parse var command_processor = new kukit.CommandProcessor(); command_processor.parseCommands(commands, domDoc); command_processor.executeCommands(oper); @@ -347,8 +387,12 @@ var error_action = oper.eventrule.actions.getErrorActionFor(oper.action); } var reason = ''; - if (typeof(errorcommand) != 'undefined') { - reason = ', reason="' + errorcommand.parms.message + '" ' + if (typeof(errorcommand) == 'string') { + // not a command, just a string + reason = ', client_reason="' + errorcommand + '" '; + } else if (typeof(errorcommand) != 'undefined') { + // a real error command, sent by the server + reason = ', server_reason="' + errorcommand.parms.message + '" '; } if (error_action) { kukit.logWarning('Request failed at url ' + oper.queueItem.url + ', rid=' + oper.queueItem.rid + reason + ', will be handled by action "' + error_action.name + '"'); @@ -405,7 +449,8 @@ if (childNode.nodeType != 1) continue; if (childNode.localName) { - if (childNode.localName.toLowerCase() != "param") { + // (here tolerate both cases) + if (childNode.localName.toLowerCase() != "param" && childNode.nodeName.toLowerCase() != "kukit:param") { throw 'Bad payload, expected param'; } } else { From reebalazs at codespeak.net Wed Dec 27 13:51:42 2006 From: reebalazs at codespeak.net (reebalazs at codespeak.net) Date: Wed, 27 Dec 2006 13:51:42 +0100 (CET) Subject: [KSS-checkins] r35994 - kukit/kukit.js/trunk/kukit Message-ID: <20061227125142.3D44610083@code0.codespeak.net> Author: reebalazs Date: Wed Dec 27 13:51:40 2006 New Revision: 35994 Modified: kukit/kukit.js/trunk/kukit/kukit.js Log: the error attachement code needs to use a full xml, consequently we don't wrap it from js Modified: kukit/kukit.js/trunk/kukit/kukit.js ============================================================================== --- kukit/kukit.js/trunk/kukit/kukit.js (original) +++ kukit/kukit.js/trunk/kukit/kukit.js Wed Dec 27 13:51:40 2006 @@ -339,9 +339,8 @@ // Read the header and load it as xml, if defined. var payload = domDoc.getResponseHeader('X-KSSCOMMANDS'); if (payload) { - var root_txt = '' + payload + ''; try { - dom = (new DOMParser()).parseFromString(root_txt, "text/xml"); + dom = (new DOMParser()).parseFromString(payload, "text/xml"); } catch(e) { // XXX this does not work on Opera for sure //throw new kukit.ResponseParsingError('Exception: "' + e + '"'); From reebalazs at codespeak.net Wed Dec 27 13:51:51 2006 From: reebalazs at codespeak.net (reebalazs at codespeak.net) Date: Wed, 27 Dec 2006 13:51:51 +0100 (CET) Subject: [KSS-checkins] r35995 - in kukit/kss.core/trunk: . browser tests Message-ID: <20061227125151.3C4BD10084@code0.codespeak.net> Author: reebalazs Date: Wed Dec 27 13:51:49 2006 New Revision: 35995 Added: kukit/kss.core/trunk/browser/errorresponse.pt kukit/kss.core/trunk/browserview.py kukit/kss.core/trunk/tests/test_browserview.py Modified: kukit/kss.core/trunk/configure.zcml Log: Implement the error attach code with browser views Added: kukit/kss.core/trunk/browser/errorresponse.pt ============================================================================== --- (empty file) +++ kukit/kss.core/trunk/browser/errorresponse.pt Wed Dec 27 13:51:49 2006 @@ -0,0 +1,11 @@ + + + + + system + Exception: reason + + + Added: kukit/kss.core/trunk/browserview.py ============================================================================== --- (empty file) +++ kukit/kss.core/trunk/browserview.py Wed Dec 27 13:51:49 2006 @@ -0,0 +1,42 @@ +# -*- coding: UTF-8 -*- +# Copyright (c) 2006 +# Authors: KSS project contributors +# +# 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. +# + +import cgi +from Products.Five.browser import BrowserView +#from zope.app.pagetemplate.viewpagetemplatefile import ViewPageTemplateFile +from zope.pagetemplate.pagetemplatefile import PageTemplateFile + +class KssBrowserView(BrowserView): + + # XML output gets rendered via a page template + # XXX note: barefoot rendering, use python: only after zope2.9 + render_error = PageTemplateFile('browser/errorresponse.pt') + + def attach_error(self, err_type, err_value): + 'Attach the error payload on the response' + message = '%s: %s' % (err_type, err_value) + message = cgi.escape(message) + payload = self.render_error(type='system', message=message) + self.attach_payload(payload) + + def attach_payload(self, payload, header_name='X-KSSCOMMANDS'): + 'Attach the commands on the response' + # get rid of newlines + payload = payload.replace('\n', ' ') + self.request.RESPONSE.setHeader(header_name, payload) Modified: kukit/kss.core/trunk/configure.zcml ============================================================================== --- kukit/kss.core/trunk/configure.zcml (original) +++ kukit/kss.core/trunk/configure.zcml Wed Dec 27 13:51:49 2006 @@ -43,4 +43,13 @@ factory=".commands.CommandView" /> + + + Added: kukit/kss.core/trunk/tests/test_browserview.py ============================================================================== --- (empty file) +++ kukit/kss.core/trunk/tests/test_browserview.py Wed Dec 27 13:51:49 2006 @@ -0,0 +1,40 @@ +# -*- coding: ISO-8859-15 -*- +# Copyright (c) 2005-2006 +# Authors: KSS project contributors +# +# 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. +# +import unittest +from base import AzaxViewTestCase + +class TestBrowserView(AzaxViewTestCase): + + def test_attach_error(self): + 'Test if errors are attached properly' + # just render any page + context = self.folder + view = context.restrictedTraverse('@@kss_view') + self.assert_(view is not None) + view.attach_error(err_type='TheError', err_value='the_<>message\n\n') + response = view.request.RESPONSE + header = response.getHeader('x-ksscommands') + self.assert_('the_&lt;&gt;message' in header) # no < > in the message + self.assert_('\n' not in header) # no /n in the payload: would destroy the page + self.assertEqual(header, ' \t \t\tsystem \t\tTheError: the_&lt;&gt;message \t ') + +def test_suite(): + suites = [] + suites.append(unittest.makeSuite(TestBrowserView)) + return unittest.TestSuite(suites) From reebalazs at codespeak.net Thu Dec 28 11:28:56 2006 From: reebalazs at codespeak.net (reebalazs at codespeak.net) Date: Thu, 28 Dec 2006 11:28:56 +0100 (CET) Subject: [KSS-checkins] r36011 - kukit/kss.core/trunk Message-ID: <20061228102856.4251910086@code0.codespeak.net> Author: reebalazs Date: Thu Dec 28 11:28:54 2006 New Revision: 36011 Modified: kukit/kss.core/trunk/__init__.py Log: make CommandSet importable the kss.core namespace Modified: kukit/kss.core/trunk/__init__.py ============================================================================== --- kukit/kss.core/trunk/__init__.py (original) +++ kukit/kss.core/trunk/__init__.py Thu Dec 28 11:28:54 2006 @@ -19,7 +19,8 @@ # 02111-1307, USA. # __all__ = ('AzaxBaseView', 'force_unicode', 'AzaxUnicodeError', - 'IKssExplicitError', 'KssExplicitError', 'kssaction', + 'KssExplicitError', 'kssaction', + 'CommandSet', 'ICommandSet', ) import mimetypes @@ -27,9 +28,10 @@ mimetypes.types_map['.kkt'] = 'text/xml' # XXX legacy! mimetypes.types_map['.kukit'] = 'text/xml' -from azaxview import AzaxBaseView +from azaxview import AzaxBaseView, CommandSet from actionwrapper import KssExplicitError, kssaction from unicode_quirks import force_unicode, AzaxUnicodeError +from interfaces import ICommandSet try: import Products.Five From reebalazs at codespeak.net Thu Dec 28 13:01:43 2006 From: reebalazs at codespeak.net (reebalazs at codespeak.net) Date: Thu, 28 Dec 2006 13:01:43 +0100 (CET) Subject: [KSS-checkins] r36016 - kukit/kukit.js/trunk/kukit Message-ID: <20061228120143.6E3B610086@code0.codespeak.net> Author: reebalazs Date: Thu Dec 28 13:01:41 2006 New Revision: 36016 Modified: kukit/kukit.js/trunk/kukit/kukit.js Log: Fix display of error reason (syntax error) Modified: kukit/kukit.js/trunk/kukit/kukit.js ============================================================================== --- kukit/kukit.js/trunk/kukit/kukit.js (original) +++ kukit/kukit.js/trunk/kukit/kukit.js Thu Dec 28 13:01:41 2006 @@ -399,7 +399,7 @@ error_action.execute(oper); } else { // Unhandled: just log it... - kukit.logError('Request failed at url ' + oper.queueItem.url + ', rid=' + oper.queueItem.rid) + reason; + kukit.logError('Request failed at url ' + oper.queueItem.url + ', rid=' + oper.queueItem.rid + reason); } }; From reebalazs at codespeak.net Fri Dec 29 12:47:02 2006 From: reebalazs at codespeak.net (reebalazs at codespeak.net) Date: Fri, 29 Dec 2006 12:47:02 +0100 (CET) Subject: [KSS-checkins] r36032 - kukit/kukit.js/trunk/kukit Message-ID: <20061229114702.5565D10087@code0.codespeak.net> Author: reebalazs Date: Fri Dec 29 12:46:59 2006 New Revision: 36032 Modified: kukit/kukit.js/trunk/kukit/resourcedata.js Log: Important fix, this was broken on IE and it affected logging Modified: kukit/kukit.js/trunk/kukit/resourcedata.js ============================================================================== --- kukit/kukit.js/trunk/kukit/resourcedata.js (original) +++ kukit/kukit.js/trunk/kukit/resourcedata.js Fri Dec 29 12:46:59 2006 @@ -426,7 +426,7 @@ this.parms[key] = other.parms[key]; } this.actions.merge(other.actions); - if (this.mergednr[0] != 'X') + if (this.mergednr.substr(0, 1) != 'X') // ignore initial clone-merge kukit.logDebug('Merged rule ' + this.mergednr + ' mergeid ' + this.kss_selector.mergeid); }; From reebalazs at codespeak.net Fri Dec 29 12:52:23 2006 From: reebalazs at codespeak.net (reebalazs at codespeak.net) Date: Fri, 29 Dec 2006 12:52:23 +0100 (CET) Subject: [KSS-checkins] r36033 - kukit/kukit.js/branch/1.0/kukit Message-ID: <20061229115223.02C0110087@code0.codespeak.net> Author: reebalazs Date: Fri Dec 29 12:52:21 2006 New Revision: 36033 Modified: kukit/kukit.js/branch/1.0/kukit/resourcedata.js Log: Merge from trunk (Important fix, this was broken on IE and it affected logging) Modified: kukit/kukit.js/branch/1.0/kukit/resourcedata.js ============================================================================== --- kukit/kukit.js/branch/1.0/kukit/resourcedata.js (original) +++ kukit/kukit.js/branch/1.0/kukit/resourcedata.js Fri Dec 29 12:52:21 2006 @@ -426,7 +426,7 @@ this.parms[key] = other.parms[key]; } this.actions.merge(other.actions); - if (this.mergednr[0] != 'X') + if (this.mergednr.substr(0, 1) != 'X') // ignore initial clone-merge kukit.logDebug('Merged rule ' + this.mergednr + ' mergeid ' + this.kss_selector.mergeid); }; From reebalazs at codespeak.net Fri Dec 29 17:00:18 2006 From: reebalazs at codespeak.net (reebalazs at codespeak.net) Date: Fri, 29 Dec 2006 17:00:18 +0100 (CET) Subject: [KSS-checkins] r36039 - kukit/azax/branch/1.1 Message-ID: <20061229160018.2305E100A3@code0.codespeak.net> Author: reebalazs Date: Fri Dec 29 17:00:16 2006 New Revision: 36039 Modified: kukit/azax/branch/1.1/ (props changed) kukit/azax/branch/1.1/EXTERNALS.TXT Log: Make branch use the kukit.js trunk again Modified: kukit/azax/branch/1.1/EXTERNALS.TXT ============================================================================== --- kukit/azax/branch/1.1/EXTERNALS.TXT (original) +++ kukit/azax/branch/1.1/EXTERNALS.TXT Fri Dec 29 17:00:16 2006 @@ -5,5 +5,5 @@ # You can update your working dir by: # svn propset svn:externals -F EXTERNALS.TXT . # -kukit http://codespeak.net/svn/kukit/kukit.js/branch/1.0 +kukit http://codespeak.net/svn/kukit/kukit.js/trunk configfeature http://codespeak.net/svn/z3/jsonserver/branch/merge/configfeature From reebalazs at codespeak.net Fri Dec 29 18:13:14 2006 From: reebalazs at codespeak.net (reebalazs at codespeak.net) Date: Fri, 29 Dec 2006 18:13:14 +0100 (CET) Subject: [KSS-checkins] r36041 - in kukit/azax/branch/1.1: . browser Message-ID: <20061229171314.173331007F@code0.codespeak.net> Author: reebalazs Date: Fri Dec 29 18:13:11 2006 New Revision: 36041 Added: kukit/azax/branch/1.1/browser/errorresponse.pt kukit/azax/branch/1.1/browserview.py Modified: kukit/azax/branch/1.1/configure.zcml Log: Undo and fox the previous two commits, the default error handler and the kss_view (browser view) is backported from the kss trunk. Added: kukit/azax/branch/1.1/browser/errorresponse.pt ============================================================================== --- (empty file) +++ kukit/azax/branch/1.1/browser/errorresponse.pt Fri Dec 29 18:13:11 2006 @@ -0,0 +1,11 @@ + + + + + system + Exception: reason + + + Added: kukit/azax/branch/1.1/browserview.py ============================================================================== --- (empty file) +++ kukit/azax/branch/1.1/browserview.py Fri Dec 29 18:13:11 2006 @@ -0,0 +1,42 @@ +# -*- coding: UTF-8 -*- +# Copyright (c) 2006 +# Authors: KSS project contributors +# +# 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. +# + +import cgi +from Products.Five.browser import BrowserView +#from zope.app.pagetemplate.viewpagetemplatefile import ViewPageTemplateFile +from zope.pagetemplate.pagetemplatefile import PageTemplateFile + +class KssBrowserView(BrowserView): + + # XML output gets rendered via a page template + # XXX note: barefoot rendering, use python: only after zope2.9 + render_error = PageTemplateFile('browser/errorresponse.pt') + + def attach_error(self, err_type, err_value): + 'Attach the error payload on the response' + message = '%s: %s' % (err_type, err_value) + message = cgi.escape(message) + payload = self.render_error(type='system', message=message) + self.attach_payload(payload) + + def attach_payload(self, payload, header_name='X-KSSCOMMANDS'): + 'Attach the commands on the response' + # get rid of newlines + payload = payload.replace('\n', ' ') + self.request.RESPONSE.setHeader(header_name, payload) Modified: kukit/azax/branch/1.1/configure.zcml ============================================================================== --- kukit/azax/branch/1.1/configure.zcml (original) +++ kukit/azax/branch/1.1/configure.zcml Fri Dec 29 18:13:11 2006 @@ -43,5 +43,14 @@ factory=".commands.CommandView" name="render" /> + + + From reebalazs at codespeak.net Fri Dec 29 20:01:20 2006 From: reebalazs at codespeak.net (reebalazs at codespeak.net) Date: Fri, 29 Dec 2006 20:01:20 +0100 (CET) Subject: [KSS-checkins] r36042 - kukit/kukit.js/trunk/kukit Message-ID: <20061229190120.B571E1008F@code0.codespeak.net> Author: reebalazs Date: Fri Dec 29 20:01:18 2006 New Revision: 36042 Modified: kukit/kukit.js/trunk/kukit/dom.js Log: Fix setKssAttribute command Modified: kukit/kukit.js/trunk/kukit/dom.js ============================================================================== --- kukit/kukit.js/trunk/kukit/dom.js (original) +++ kukit/kukit.js/trunk/kukit/dom.js Fri Dec 29 20:01:18 2006 @@ -259,7 +259,7 @@ kukit.dom.setKssAttribute = function(node, attrname, value) { // Sets a given kss attribute on the namespace - kukit.dom.setAttribute(node, kukit.dom.namespace + ':' + attrname); + kukit.dom.setAttribute(node, kukit.dom.namespace + ':' + attrname, value); }; /* Recursive getting of node attributes From reebalazs at codespeak.net Fri Dec 29 22:16:53 2006 From: reebalazs at codespeak.net (reebalazs at codespeak.net) Date: Fri, 29 Dec 2006 22:16:53 +0100 (CET) Subject: [KSS-checkins] r36045 - kukit/kukit.js/trunk/kukit Message-ID: <20061229211653.6D9B010090@code0.codespeak.net> Author: reebalazs Date: Fri Dec 29 22:16:51 2006 New Revision: 36045 Modified: kukit/kukit.js/trunk/kukit/plugin.js kukit/kukit.js/trunk/kukit/utils.js Log: timer event binder should delete itself, in case the node it executed on, has been deleted in the meantime. Modified: kukit/kukit.js/trunk/kukit/plugin.js ============================================================================== --- kukit/kukit.js/trunk/kukit/plugin.js (original) +++ kukit/kukit.js/trunk/kukit/plugin.js Fri Dec 29 22:16:51 2006 @@ -190,9 +190,9 @@ // 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) -// or only once if repeat=false is given. +// The timer will tick for ever, +// unless the binding node has been deleted, in which case it stops, +// or it runs only once if repeat=false is given. kukit.pl.TimeoutEventBinder = function() { this.counters = {}; @@ -210,7 +210,18 @@ } else { kukit.logDebug('timer event key entered for actionEvent #' + key + ' ' + oper.eventrule.kss_selector.css); - var counter = new kukit.ut.TimerCounter(oper.parms.delay, func_to_bind, oper.parms.repeat); + var f = function() { + // check if the node has been deleted + // and weed it out if so + if (oper.node != null && ! oper.node.parentNode) { + kukit.logDebug('timer deleted for actionEvent #' + key + ' ' + + oper.eventrule.kss_selector.css); + this.clear(); + } else { + func_to_bind(); + } + }; + var counter = new kukit.ut.TimerCounter(oper.parms.delay, f, oper.parms.repeat); this.counters[key] = counter; // Start the counter counter.start(); Modified: kukit/kukit.js/trunk/kukit/utils.js ============================================================================== --- kukit/kukit.js/trunk/kukit/utils.js (original) +++ kukit/kukit.js/trunk/kukit/utils.js Fri Dec 29 22:16:51 2006 @@ -291,6 +291,7 @@ if (this.timer) { window.clearTimeout(this.timer); } + this.restart = false; }; From reebalazs at codespeak.net Fri Dec 29 22:18:03 2006 From: reebalazs at codespeak.net (reebalazs at codespeak.net) Date: Fri, 29 Dec 2006 22:18:03 +0100 (CET) Subject: [KSS-checkins] r36046 - kukit/kukit.js/branch/1.0/kukit Message-ID: <20061229211803.3D86810090@code0.codespeak.net> Author: reebalazs Date: Fri Dec 29 22:18:01 2006 New Revision: 36046 Modified: kukit/kukit.js/branch/1.0/kukit/dom.js Log: Backport from trunk, setKssAttribute dom helper method (and action) fixed Modified: kukit/kukit.js/branch/1.0/kukit/dom.js ============================================================================== --- kukit/kukit.js/branch/1.0/kukit/dom.js (original) +++ kukit/kukit.js/branch/1.0/kukit/dom.js Fri Dec 29 22:18:01 2006 @@ -259,7 +259,7 @@ kukit.dom.setKssAttribute = function(node, attrname, value) { // Sets a given kss attribute on the namespace - kukit.dom.setAttribute(node, kukit.dom.namespace + ':' + attrname); + kukit.dom.setAttribute(node, kukit.dom.namespace + ':' + attrname, value); }; /* Recursive getting of node attributes From reebalazs at codespeak.net Fri Dec 29 22:19:13 2006 From: reebalazs at codespeak.net (reebalazs at codespeak.net) Date: Fri, 29 Dec 2006 22:19:13 +0100 (CET) Subject: [KSS-checkins] r36047 - kukit/kukit.js/branch/1.0/kukit Message-ID: <20061229211913.711A510090@code0.codespeak.net> Author: reebalazs Date: Fri Dec 29 22:19:11 2006 New Revision: 36047 Modified: kukit/kukit.js/branch/1.0/kukit/plugin.js kukit/kukit.js/branch/1.0/kukit/utils.js Log: Backport of fix from trunk (timer event binder should delete itself, in case the node it executed on, has been deleted in the meantime) Modified: kukit/kukit.js/branch/1.0/kukit/plugin.js ============================================================================== --- kukit/kukit.js/branch/1.0/kukit/plugin.js (original) +++ kukit/kukit.js/branch/1.0/kukit/plugin.js Fri Dec 29 22:19:11 2006 @@ -195,9 +195,9 @@ // 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) -// or only once if repeat=false is given. +// The timer will tick for ever, +// unless the binding node has been deleted, in which case it stops, +// or it runs only once if repeat=false is given. kukit.pl.TimeoutEventBinder = function() { this.counters = {}; @@ -215,7 +215,18 @@ } else { kukit.logDebug('timer event key entered for actionEvent #' + key + ' ' + oper.eventrule.kss_selector.css); - var counter = new kukit.ut.TimerCounter(oper.parms.delay, func_to_bind, oper.parms.repeat); + var f = function() { + // check if the node has been deleted + // and weed it out if so + if (oper.node != null && ! oper.node.parentNode) { + kukit.logDebug('timer deleted for actionEvent #' + key + ' ' + + oper.eventrule.kss_selector.css); + this.clear(); + } else { + func_to_bind(); + } + }; + var counter = new kukit.ut.TimerCounter(oper.parms.delay, f, oper.parms.repeat); this.counters[key] = counter; // Start the counter counter.start(); Modified: kukit/kukit.js/branch/1.0/kukit/utils.js ============================================================================== --- kukit/kukit.js/branch/1.0/kukit/utils.js (original) +++ kukit/kukit.js/branch/1.0/kukit/utils.js Fri Dec 29 22:19:11 2006 @@ -262,6 +262,7 @@ if (this.timer) { window.clearTimeout(this.timer); } + this.restart = false; };