class XFormsEngine(object): # NOTE: This assumes the document itself does not change underneath us. def __init__(self, xform_doc_file): self.doc_tree = build_xpath_tree(xform_doc_file) self.doc_engine = ExpressionEngine( self.doc_tree, variables={}, function_libraries=[XFormsFunctionLibrary()]) self.doc_event_manager = DOMEventFlowManager(self.doc_tree) self._xev_cache = {} self._models = {} for model_node in self.xev('//xforms:model', self.doc_tree): self._models[model_node] = XFormsModel(self, model_node) def xev(self, expr, node=None, pos=1, size=1, replace_namespaces=True): if replace_namespaces: expr = self._replace_namespaces(expr) ckey = (expr, node, pos, size) if ckey not in self._xev_cache: self._xev_cache[ckey] = self.doc_engine.evaluate( expr, node, context_position=pos, context_size=size).value return self._xev_cache[ckey] def _replace_namespaces(self, expr): for expr_prefix, expr_uri in NAMESPACES: for prefix, uri in self.doc_tree._namespaces.items(): if uri == expr_uri: expr = expr.replace( '%s:' % (expr_prefix,), '%s:' % (prefix,)) break return expr
class DOMEventFlowManagerTestCase(TestCase): def setUp(self): self.doc = build_xpath_tree(make_doc(EVENTS_XML)) self.engine = ExpressionEngine(self.doc) self.manager = DOMEventFlowManager(self.doc) def get_node(self, expr): [node] = self.engine.evaluate(expr, self.doc).value return node def add_listener(self, target_expr, event_type, listener, capture=False): target = self.get_node(target_expr) self.manager.add_event_listener(target, event_type, listener, capture) def make_incr_handler(self, data, key): def handler(event): data.setdefault(key, 0) data[key] += 1 return handler def test_dispatch_events_no_listeners(self): self.manager.dispatch_event(self.get_node('/'), ToyEvent()) self.manager.dispatch_event(self.get_node('//elem1'), ToyEvent()) self.manager.dispatch_event(self.get_node('//elem2'), ToyEvent()) self.manager.dispatch_event(self.get_node('//elem3'), ToyEvent()) def test_dispatch_event_target_listeners(self): data = {} listener1 = self.make_incr_handler(data, 'listener1') listener2 = self.make_incr_handler(data, 'listener2') self.add_listener('//elem1', 'toy-event', listener1) self.add_listener('//elem2', 'toy-event', listener1) self.add_listener('//elem3', 'toy-event', listener1) self.add_listener('//elem2', 'toy-event', listener2) self.assertEqual(data, {}) self.manager.dispatch_event(self.get_node('//elem2'), ToyEvent()) self.assertEqual(data, {'listener1': 1, 'listener2': 1}) def test_dispatch_event_target_and_bubble_listeners(self): data = {} listener1 = self.make_incr_handler(data, 'listener1') listener2 = self.make_incr_handler(data, 'listener2') self.add_listener('//elem1', 'bubble-event', listener1) self.add_listener('//elem2', 'bubble-event', listener1) self.add_listener('//elem3', 'bubble-event', listener1) self.add_listener('//elem2', 'bubble-event', listener2) self.assertEqual(data, {}) self.manager.dispatch_event(self.get_node('//elem2'), BubbleEvent()) self.assertEqual(data, {'listener1': 2, 'listener2': 1}) def test_dispatch_event_bubble_listeners(self): data = {} listener1 = self.make_incr_handler(data, 'listener1') self.add_listener('//elem1', 'bubble-event', listener1) self.add_listener('//elem2', 'bubble-event', listener1) self.assertEqual(data, {}) self.manager.dispatch_event(self.get_node('//elem3'), BubbleEvent()) self.assertEqual(data, {'listener1': 2}) def test_dispatch_event_target_capture_listeners(self): data = {} listener1 = self.make_incr_handler(data, 'listener1') listener2 = self.make_incr_handler(data, 'listener2') self.add_listener('//elem1', 'toy-event', listener1, True) self.add_listener('//elem2', 'toy-event', listener1, True) self.add_listener('//elem3', 'toy-event', listener1, True) self.add_listener('//elem2', 'toy-event', listener2) self.assertEqual(data, {}) self.manager.dispatch_event(self.get_node('//elem2'), ToyEvent()) self.assertEqual(data, {'listener1': 1, 'listener2': 1}) def test_dispatch_event_target_capture_bubble_listeners(self): data = {} listener1 = self.make_incr_handler(data, 'listener1') listener2 = self.make_incr_handler(data, 'listener2') self.add_listener('//elem1', 'bubble-event', listener1, True) self.add_listener('//elem2', 'bubble-event', listener1, True) self.add_listener('//elem3', 'bubble-event', listener1, True) self.add_listener('//elem1', 'bubble-event', listener2) self.add_listener('//elem2', 'bubble-event', listener2) self.add_listener('//elem3', 'bubble-event', listener2) self.assertEqual(data, {}) self.manager.dispatch_event(self.get_node('//elem2'), BubbleEvent()) self.assertEqual(data, {'listener1': 1, 'listener2': 2})