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