1 /*
2  * This file is part of libdom.
3  * Licensed under the MIT License,
4  *                http://www.opensource.org/licenses/mit-license.php
5  * Copyright 2009 Bo Yang <struggleyb.nku@gmail.com>
6  */
7 
8 #include <assert.h>
9 #include <stdlib.h>
10 
11 #include "events/event.h"
12 #include "events/event_listener.h"
13 #include "events/event_target.h"
14 
15 #include "core/document.h"
16 #include "core/node.h"
17 #include "core/string.h"
18 
19 #include "utils/utils.h"
20 #include "utils/validate.h"
21 
event_target_destroy_listener(struct listener_entry * e)22 static void event_target_destroy_listener(struct listener_entry *e)
23 {
24 	list_del(&e->list);
25 	dom_event_listener_unref(e->listener);
26 	dom_string_unref(e->type);
27 	free(e);
28 }
event_target_destroy_listeners(struct listener_entry * list)29 static void event_target_destroy_listeners(struct listener_entry *list)
30 {
31 	struct listener_entry *next;
32 
33 	while (list != (struct listener_entry *) list->list.next) {
34 		next = (struct listener_entry *) list->list.next;
35 		event_target_destroy_listener(list);
36 		list = next;
37 	}
38 
39 	event_target_destroy_listener(list);
40 }
41 
42 /* Initialise this EventTarget */
_dom_event_target_internal_initialise(dom_event_target_internal * eti)43 dom_exception _dom_event_target_internal_initialise(
44 		dom_event_target_internal *eti)
45 {
46 	eti->listeners = NULL;
47 
48 	return DOM_NO_ERR;
49 }
50 
51 /* Finalise this EventTarget */
_dom_event_target_internal_finalise(dom_event_target_internal * eti)52 void _dom_event_target_internal_finalise(dom_event_target_internal *eti)
53 {
54 	if (eti->listeners != NULL) {
55 		event_target_destroy_listeners(eti->listeners);
56 		eti->listeners = NULL;
57 	}
58 }
59 
60 /*-------------------------------------------------------------------------*/
61 /* The public API */
62 
63 /**
64  * Add an EventListener to the EventTarget
65  *
66  * \param et        The EventTarget object
67  * \param type      The event type which this event listener listens for
68  * \param listener  The event listener object
69  * \param capture   Whether add this listener in the capturing phase
70  * \return DOM_NO_ERR on success, appropriate dom_exception on failure.
71  */
_dom_event_target_add_event_listener(dom_event_target_internal * eti,dom_string * type,struct dom_event_listener * listener,bool capture)72 dom_exception _dom_event_target_add_event_listener(
73 		dom_event_target_internal *eti,
74 		dom_string *type, struct dom_event_listener *listener,
75 		bool capture)
76 {
77 	struct listener_entry *le = NULL;
78 
79 	le = malloc(sizeof(struct listener_entry));
80 	if (le == NULL)
81 		return DOM_NO_MEM_ERR;
82 
83 	/* Initialise the listener_entry */
84 	list_init(&le->list);
85 	le->type = dom_string_ref(type);
86 	le->listener = listener;
87 	dom_event_listener_ref(listener);
88 	le->capture = capture;
89 
90 	if (eti->listeners == NULL) {
91 		eti->listeners = le;
92 	} else {
93 		list_append(&eti->listeners->list, &le->list);
94 	}
95 
96 	return DOM_NO_ERR;
97 }
98 
99 /**
100  * Remove an EventListener from the EventTarget
101  *
102  * (LibDOM extension: If type is NULL, remove all listener registrations
103  * regardless of type and cature)
104  *
105  * \param et        The EventTarget object
106  * \param type      The event type this listener is registered for
107  * \param listener  The listener object
108  * \param capture   Whether the listener is registered at the capturing phase
109  * \return DOM_NO_ERR on success, appropriate dom_exception on failure.
110  */
_dom_event_target_remove_event_listener(dom_event_target_internal * eti,dom_string * type,struct dom_event_listener * listener,bool capture)111 dom_exception _dom_event_target_remove_event_listener(
112 		dom_event_target_internal *eti,
113 		dom_string *type, struct dom_event_listener *listener,
114 		bool capture)
115 {
116 	if (eti->listeners != NULL) {
117 		struct listener_entry *le = eti->listeners;
118 
119 		do {
120 			bool matches;
121 			if (type == NULL) {
122 				matches = (le->listener == listener);
123 			} else {
124 				matches = dom_string_isequal(le->type, type) &&
125 					(le->listener == listener) &&
126 					(le->capture == capture);
127 			}
128 			if (matches) {
129 				if (le->list.next == &le->list) {
130 					eti->listeners = NULL;
131 				} else {
132 					eti->listeners =
133 						(struct listener_entry *)
134 						le->list.next;
135 				}
136 				list_del(&le->list);
137 				dom_event_listener_unref(le->listener);
138 				dom_string_unref(le->type);
139 				free(le);
140 				break;
141 			}
142 
143 			le = (struct listener_entry *) le->list.next;
144 		} while (eti->listeners != NULL && le != eti->listeners);
145 	}
146 
147 	return DOM_NO_ERR;
148 }
149 
150 /**
151  * Add an EventListener
152  *
153  * \param et         The EventTarget object
154  * \param namespace  The namespace of this listener
155  * \param type       The event type which this event listener listens for
156  * \param listener   The event listener object
157  * \param capture    Whether add this listener in the capturing phase
158  * \return DOM_NO_ERR on success, appropriate dom_exception on failure.
159  *
160  * We don't support this API now, so it always return DOM_NOT_SUPPORTED_ERR.
161  */
_dom_event_target_add_event_listener_ns(dom_event_target_internal * eti,dom_string * namespace,dom_string * type,struct dom_event_listener * listener,bool capture)162 dom_exception _dom_event_target_add_event_listener_ns(
163 		dom_event_target_internal *eti,
164 		dom_string *namespace, dom_string *type,
165 		struct dom_event_listener *listener, bool capture)
166 {
167 	UNUSED(eti);
168 	UNUSED(namespace);
169 	UNUSED(type);
170 	UNUSED(listener);
171 	UNUSED(capture);
172 
173 	return DOM_NOT_SUPPORTED_ERR;
174 }
175 
176 /**
177  * Remove an EventListener
178  *
179  * \param et         The EventTarget object
180  * \param namespace  The namespace of this listener
181  * \param type       The event type which this event listener listens for
182  * \param listener   The event listener object
183  * \param capture    Whether add this listener in the capturing phase
184  * \return DOM_NO_ERR on success, appropriate dom_exception on failure.
185  *
186  * We don't support this API now, so it always return DOM_NOT_SUPPORTED_ERR.
187  */
_dom_event_target_remove_event_listener_ns(dom_event_target_internal * eti,dom_string * namespace,dom_string * type,struct dom_event_listener * listener,bool capture)188 dom_exception _dom_event_target_remove_event_listener_ns(
189 		dom_event_target_internal *eti,
190 		dom_string *namespace, dom_string *type,
191 		struct dom_event_listener *listener, bool capture)
192 {
193 	UNUSED(eti);
194 	UNUSED(namespace);
195 	UNUSED(type);
196 	UNUSED(listener);
197 	UNUSED(capture);
198 
199 	return DOM_NOT_SUPPORTED_ERR;
200 }
201 
202 /*-------------------------------------------------------------------------*/
203 
204 /**
205  * Dispatch an event on certain EventTarget
206  *
207  * \param et       The EventTarget object
208  * \param eti      Internal EventTarget object
209  * \param evt      The event object
210  * \param success  Indicates whether any of the listeners which handled the
211  *                 event called Event.preventDefault(). If
212  *                 Event.preventDefault() was called the returned value is
213  *                 false, else it is true.
214  * \return DOM_NO_ERR on success, appropriate dom_exception on failure.
215  */
_dom_event_target_dispatch(dom_event_target * et,dom_event_target_internal * eti,struct dom_event * evt,dom_event_flow_phase phase,bool * success)216 dom_exception _dom_event_target_dispatch(dom_event_target *et,
217 		dom_event_target_internal *eti,
218 		struct dom_event *evt, dom_event_flow_phase phase,
219 		bool *success)
220 {
221 	if (eti->listeners != NULL) {
222 		struct listener_entry *le = eti->listeners;
223 
224 		evt->current = et;
225 
226 		do {
227 			if (dom_string_isequal(le->type, evt->type)) {
228 				assert(le->listener->handler != NULL);
229 
230 				if ((le->capture &&
231 						phase == DOM_CAPTURING_PHASE) ||
232 				    (le->capture == false &&
233 						phase == DOM_BUBBLING_PHASE) ||
234 				    (evt->target == evt->current &&
235 						phase == DOM_AT_TARGET)) {
236 					le->listener->handler(evt,
237 							le->listener->pw);
238 					/* If the handler called
239 					 * stopImmediatePropagation, we should
240 					 * break */
241 					if (evt->stop_now == true)
242 						break;
243 				}
244 			}
245 
246 			le = (struct listener_entry *) le->list.next;
247 		} while (le != eti->listeners);
248 	}
249 
250 	if (evt->prevent_default == true)
251 		*success = false;
252 
253 	return DOM_NO_ERR;
254 }
255 
256