# -*- test-case-name: nevow.test.test_livepage -*- # Copyright (c) 2004 Divmod. # See LICENSE for details. """Provides a bidirectional channel for sending out-of-band events between client and server without refreshing the whole page. """ import itertools, types import warnings from zope.interface import implements, Interface from twisted.internet import defer, error from twisted.internet.task import LoopingCall from twisted.python import log from nevow import tags, inevow, context, static, flat, rend, url, util, stan # If you need to debug livepage itself or your livepage app, set this to true DEBUG = False _jslog = None def _openjslog(): global _jslog if _jslog is None: _jslog = file("js.log", "w") _jslog.write("**********\n") _jslog.flush() return _jslog def jslog(*x): if DEBUG: mylog = _openjslog() for y in x: mylog.write(str(y)) mylog.flush() class JavascriptContext(context.WovenContext): def __init__(self, parent=None, tag=None, isAttrib=None, inJSSingleQuoteString=None, remembrances=None): super(JavascriptContext, self).__init__( parent, tag, inJS=True, isAttrib=isAttrib, inJSSingleQuoteString=inJSSingleQuoteString, remembrances=None) class TimeoutException(Exception): pass class ClientSideException(Exception): pass class SingleQuote(object): def __init__(self, children): self.children = children def __repr__(self): return "%s(%s)" % (type(self).__name__, self.children) def flattenSingleQuote(singleQuote, ctx): new = JavascriptContext(ctx, tags.invisible[singleQuote], inJSSingleQuoteString=True) return flat.serialize(singleQuote.children, new) flat.registerFlattener(flattenSingleQuote, SingleQuote) class _js(object): """Stan for Javascript. There is a convenience instance of this class named "js" in the livepage module which you should use instead of the _js class directly. Marker indicating literal Javascript should be rendered. No escaping will be performed. When inside a JavascriptContext, Nevow will automatically put apostrophe quote marks around any Python strings it renders. This makes turning a Python string into a JavaScript string very easy. However, there are often situations where you wish to generate some literal Javascript code and do not wish quote marks to be placed around it. In this situation, the js object should be used. The simplest usage is to simply pass a python string to js. When the js object is rendered, the python string will be rendered as if it were literal javascript. For example: client.send(js(\"alert('hello')\")) However, to make the generation of Javascript more convenient, the js object also provides safe implementations of __getattr__, __call__, and __getitem__. See the following examples to get an idea of how to use it. The Python code is to the left of the -> and the Javascript which results is to the right. js(\"alert('any javascript you like')\") -> alert('any javascript you like') js.window.title -> window.title js.document.getElementById('foo') -> document.getElementById('foo') js.myFunction('my argument') -> myFunction('my argument') js.myFunction(True, 5, \"it's a beautiful day\") -> myFunction(true, 5, 'it\\'s a beautiful day') js.document.all[\"something\"] -> document.all['something'] js[1, 2] -> [1, 2] XXX TODO support javascript object literals somehow? (They look like dicts) perhaps like this: js[\"one\": 1, \"two\": 2] -> {\"one\": 1, \"two\": 2} The livepage module includes many convenient instances of the js object. It includes the literals: document window this self It includes shorthand for commonly called javascript functions: alert -> alert get -> document.getElementById set -> nevow_setNode append -> nevow_appendNode prepend -> nevow.prependNode insert -> nevow.insertNode It includes convenience calls against the client-side server object: server.handle('callMe') -> server.handle('callMe') It includes commonly-used fragments of javascript: stop -> ; return false; eol -> \\n Stop is used to prevent the browser from executing it's default event handler. For example: button(onclick=[server.handle('click'), stop]) ->