[KSS-checkins] r50918 - kukit/kss.base/trunk/kss/base
jvloothuis at codespeak.net
jvloothuis at codespeak.net
Wed Jan 23 15:19:35 CET 2008
Author: jvloothuis
Date: Wed Jan 23 15:19:35 2008
New Revision: 50918
Modified:
kukit/kss.base/trunk/kss/base/__init__.py
kukit/kss.base/trunk/kss/base/commands.py
kukit/kss.base/trunk/kss/base/commands.txt
kukit/kss.base/trunk/kss/base/corecommands.py
kukit/kss.base/trunk/kss/base/corecommands.txt
Log:
Made the protocol compatible with the recent changes made to kss.core (which where fixes in problems with the old protocol)
Modified: kukit/kss.base/trunk/kss/base/__init__.py
==============================================================================
--- kukit/kss.base/trunk/kss/base/__init__.py (original)
+++ kukit/kss.base/trunk/kss/base/__init__.py Wed Jan 23 15:19:35 2008
@@ -1,3 +1,4 @@
from kss.base.commands import KSSCommands
from kss.base.selectors import selectors
from kss.base.plugin import load_plugins
+from kss.base.commands import xmldata, htmldata, cdatadata
Modified: kukit/kss.base/trunk/kss/base/commands.py
==============================================================================
--- kukit/kss.base/trunk/kss/base/commands.py (original)
+++ kukit/kss.base/trunk/kss/base/commands.py Wed Jan 23 15:19:35 2008
@@ -1,21 +1,37 @@
-from xml.sax.saxutils import quoteattr
+from xml.sax.saxutils import quoteattr, escape
from kss.base.registry import command_set_registry
from kss.base.selectors import Selector
-from kss.base.selectors import css
kss_response_header = '''<?xml version="1.0" ?>
-<kukit xmlns="http://www.kukit.org/commands/1.0"><commands>
+<kukit xmlns="http://www.kukit.org/commands/1.1"><commands>
'''
kss_response_footer = '</commands></kukit>'
-
kss_command_start = '<command selector=%(selector)s name=%(action)s selectorType=%(selector_type)s>'
-kss_command_startglobal = '<command name=%(action)s>'
+
+kss_command_start_global = '<command name=%(action)s>'
kss_command_end = '</command>'
-kss_param = '<param name=%(name)s><![CDATA[%(value)s]]></param>'
+kss_param = '<param name=%(name)s>%(value)s</param>'
+
+class cdatadata(object):
+ def __init__(self, value):
+ self.value = value
+
+ def node(self):
+ '''Return the XML node representation of this object'''
+ return '<![CDATA[%s]]>' % self.value.replace(']]>', ']]>')
+
+ def __repr__(self):
+ return "%s('%s')" % (self.__class__.__name__, self.value)
+
+class htmldata(cdatadata):
+ pass
+
+class xmldata(cdatadata):
+ pass
class KSSCommands(object):
'''Command renderer for creating KSS responses'''
@@ -25,9 +41,6 @@
def add(self, action, selector, **kwargs):
self._strip_none_parameters(kwargs)
- if selector is not None and not isinstance(selector, Selector):
- selector = css(selector)
-
self.commands.append((action, selector, kwargs))
def _strip_none_parameters(self, parameters):
@@ -38,19 +51,37 @@
def render(self):
output = [kss_response_header]
for action, selector, options in self.commands:
- if selector is not None:
- # selector command
- output.append(kss_command_start % dict(
- selector=quoteattr(selector.value),
- selector_type=quoteattr(selector.type),
- action=quoteattr(action)))
+ if selector is None:
+ output.append(kss_command_start_global % dict(
+ action=quoteattr(action)))
else:
- # global command
- output.append(kss_command_startglobal % dict(
- action=quoteattr(action)))
+ try:
+ selector_type = selector.type
+ selector = selector.value
+ except AttributeError:
+ # It is probably a string or unicode object so we
+ # can let the client decide the default selector
+ selector_type = ''
+
+ output.append(kss_command_start % dict(
+ selector=quoteattr(selector),
+ selector_type=quoteattr(selector_type),
+ action=quoteattr(action)))
+
for name, value in options.items():
+ try:
+ node = value.node()
+ except AttributeError:
+ # If it the value does not explicitly convert to a
+ # node make it a text node, unless it is larger
+ # than 4KB (since this triggers a problem with
+ # Firefox and large text nodes).
+ if len(value)>= 4096:
+ node = cdatadata(value).node()
+ else:
+ node = escape(value)
output.append(kss_param % dict(
- name=quoteattr(name), value=value))
+ name=quoteattr(name), value=node))
output.append(kss_command_end)
output.append(kss_response_footer)
return ''.join(output)
@@ -59,18 +90,21 @@
self.commands = []
def __str__(self):
- def format_options(options):
- if not options:
- return ''
- return ', ' + ', '.join(
- ["%s='%s'" % item for item in options.items()])
-
lines = []
for action, selector, options in self.commands:
- lines.append("%(action)s(%(selector)s%(options)s)" % {
- 'action': action,
- 'selector': selector,
- 'options': format_options(options)})
+ line = '%s(' % action
+ if isinstance(selector, Selector):
+ line += '%s' % selector
+ elif isinstance(selector, basestring):
+ line += "'%s'" % selector
+
+ if options:
+ if selector is not None:
+ line += ', '
+ line += ', '.join(
+ ["%s=%r" % (key, value) for
+ key, value in options.items()])
+ lines.append(line + ')')
return '\n'.join(lines)
def __getattr__(self, name):
Modified: kukit/kss.base/trunk/kss/base/commands.txt
==============================================================================
--- kukit/kss.base/trunk/kss/base/commands.txt (original)
+++ kukit/kss.base/trunk/kss/base/commands.txt Wed Jan 23 15:19:35 2008
@@ -55,7 +55,32 @@
[<DOM Element: command at ...>, <DOM Element: command at ...>]
Each parameter is represented by a child node in a command. Their name
-is stored in the attribute and their value is put within CDATA blocks.
+is stored in the attribute and their value is put within text nodes or
+CDATA blocks. Which type of node is used depends on the type of
+the keyword argument given to the command.
+
+Depending on the type the serialisation to XML changes. Strings and
+unicode objects will be send as text nodes. You can also mark data as
+HTML, XML or CDATA blocks. This is used so that these can have special
+escaping rules.
+
+ >>> from kss.base import xmldata, htmldata, cdatadata
+
+Now if we make a command with these types the output will be different.
+
+ >>> commands = KSSCommands()
+ >>> commands.add('htmlAction', css('#someid'), html=htmldata('some value'))
+ >>> commands.add('cdataAction', css('#otherid'), arg=cdatadata('some arg'))
+ >>> commands.add('xmlAction', css('#otherid'), arg=xmldata('some arg'))
+ >>> commands.add('normalAction', css('#otherid'), arg='normal arg')
+ >>> doc = minidom.parseString(commands.render())
+ >>> for command in doc.getElementsByTagName('command'):
+ ... params = command.getElementsByTagName('param')
+ ... print params[0].childNodes[0].nodeType == doc.CDATA_SECTION_NODE
+ True
+ True
+ True
+ False
>>> replace_command = doc.getElementsByTagName('command')[0]
@@ -70,9 +95,28 @@
>>> commands.render()
'...<![CDATA[some value]]>...'
-We are using CDATA because Firefox chops text nodes at 4KB blocks
-(which makes the client side handling more difficult). Using CDATA
-avoids the chopping.
+CDATA nodes are used for serializing XML or HTML. This makes the
+response more readable when looking at it from traffic sniffers or
+other debugging tools.
+
+We have another case where CDATA is used. That is when we serialize a
+normal value larger than 4KB. This is because Firefox chops text nodes
+at 4KB blocks (which makes the client side handling more
+difficult). Using CDATA avoids the chopping.
+
+The example below demonstrates this behaviour.
+
+ >>> commands = KSSCommands()
+ >>> commands.add('smallValueAction', '#test', value='tiny')
+ >>> 'CDATA' in commands.render()
+ False
+
+Now run the example again with a larger value.
+
+ >>> commands = KSSCommands()
+ >>> commands.add('smallLargeAction', '#test', value='huge' * 4096)
+ >>> 'CDATA' in commands.render()
+ True
String representation
@@ -125,12 +169,12 @@
You can also use strings instead of a selector instance as a value for
selector. In this case the string will automatically be converted to a
-CSS selector.
+selector on the client. By default this is the CSS selector.
>>> commands.clear()
>>> commands.add('replaceHTML', '#someid', html='some value')
>>> print commands
- replaceHTML(css('#someid'), html='some value')
+ replaceHTML('#someid', html='some value')
Command sets
@@ -182,6 +226,6 @@
>>> commands.core.replaceInnerHTML(css('div'), 'example')
>>> print commands
- replaceInnerHTML(css('div'), html='example')
+ replaceInnerHTML(css('div'), html=htmldata('example'))
- >>> command_set_registry.unregister('core')
\ No newline at end of file
+ >>> command_set_registry.unregister('core')
Modified: kukit/kss.base/trunk/kss/base/corecommands.py
==============================================================================
--- kukit/kss.base/trunk/kss/base/corecommands.py (original)
+++ kukit/kss.base/trunk/kss/base/corecommands.py Wed Jan 23 15:19:35 2008
@@ -1,4 +1,5 @@
from kss.base.commands import KSSCommandSet
+from kss.base import htmldata
class KSSCoreCommands(KSSCommandSet):
@@ -27,7 +28,7 @@
extra_args = {}
if not withKssSetup:
extra_args['withKssSetup'] = 'False'
- self.commands.add('replaceInnerHTML', selector, html=value,
+ self.commands.add('replaceInnerHTML', selector, html=htmldata(value),
**extra_args)
def replaceHTML(self, selector, value, withKssSetup=True):
Modified: kukit/kss.base/trunk/kss/base/corecommands.txt
==============================================================================
--- kukit/kss.base/trunk/kss/base/corecommands.txt (original)
+++ kukit/kss.base/trunk/kss/base/corecommands.txt Wed Jan 23 15:19:35 2008
@@ -95,15 +95,15 @@
>>> commands.clear()
>>> core.replaceInnerHTML(css('div'), 'some html')
>>> print commands
- replaceInnerHTML(css('div'), html='some html')
+ replaceInnerHTML(css('div'), html=htmldata('some html'))
You can also avoid KSS event setup. Use this only if you really need
the speedup because KSS will not be applied to these new nodes.
>>> core.replaceInnerHTML(css('div'), 'some html', withKssSetup=False)
>>> print commands
- replaceInnerHTML(css('div'), html='some html')
- replaceInnerHTML(css('div'), html='some html', withKssSetup='False')
+ replaceInnerHTML(css('div'), html=htmldata('some html'))
+ replaceInnerHTML(css('div'), html=htmldata('some html'), withKssSetup='False')
Replace HTML
@@ -261,7 +261,7 @@
>>> commands.clear()
>>> core.setStateVar('varname', 'value')
>>> print commands
- setStateVar(None, varname='varname', value='value')
+ setStateVar(varname='varname', value='value')
Trigger event
-------------
@@ -269,4 +269,4 @@
>>> commands.clear()
>>> core.triggerEvent('eventname')
>>> print commands
- triggerEvent(None, name='eventname')
+ triggerEvent(name='eventname')
More information about the Kukit-checkins
mailing list