PageSourceSearch

https://www.euroclix.nl/assets/f659334231b7e40d/core/t5-pubsub.js

js euroclix.nl collected 2026-09-24 09:00:52 UTC 8,452 bytes, 248 lines download raw bytes

1T5.define("pubsub", function() {
2
3    var _ = T5._;
4
5    // Element keys: topic, element, listenerfn
6    // May be multiple elements with some topic/element pair
7    // element property may be undefined
8    var subscribers = [];
9
10    // Element keys: topic, element, publisherfn
11    var publishers = [];
12
13    // Necessary since T5.dom depends on T5.pubsub
14    function $(element) {
15        return T5.$(element);
16    }
17
18    function purgePublisherCache(topic) {
19        _.each(publishers, function(publisher) {
20            if (publisher.topic === topic) {
21                publisher.listeners = undefined;
22            }
23        });
24    }
25
26    function findListeners(topic, element) {
27        var gross = _.select(subscribers, function(subscriber) {
28            return subscriber.topic === topic;
29        });
30
31        var primary = _.select(gross, function(subscriber) {
32            return subscriber.element === element;
33        });
34
35        var secondary = _.select(gross, function(subscriber) {
36            // Match where the element is null or undefined
37            return !subscriber.element;
38        });
39
40        // Return the listenerfn property from each match.
41        return _(primary).chain().union(secondary).pluck("listenerfn").value();
42    }
43
44    /**
45     * Subscribes a listener function to the selector. The listener function
46     * will be invoked when a message for the given topic is published. If an
47     * element is specified, then the listener will only be invoked when the
48     * subscribed element matches the published element.
49     *
50     * @param topic
51     *            a topic name, which must not be blank
52     * @param element
53     *            a DOM element, which may be null to subscribe to all messages
54     *            for the topic. If a string, then T5.$() is used to locate the
55     *            DOM element with the matching client id.
56     * @param listenerfn
57     *            function invoked when a message for the topic is published.
58     *            The function is invoked only if the supplied selector element
59     *            is undefined OR exactly matches the source element node. The
60     *            return value of the listenerfn will be accumulated in an array
61     *            and returned to the publisher.
62     *
63     *            The listener function is passed a message object as the first parameter; this is provided
64     *            on each call to the topic's publish function. The second parameter is an object with two
65     *            properties:  An element property to identify the source of the message, and a cancel() function property
66     *            that prevents further listeners from being invoked.
67     * @return a function of no arguments used to unsubscribe the listener
68     */
69    function subscribe(topic, element, listenerfn) {
70
71        var subscriber = {
72            topic : topic,
73            element : $(element),
74            listenerfn : listenerfn
75        };
76
77        subscribers.push(subscriber);
78        purgePublisherCache(subscriber.topic);
79
80        // To prevent memory leaks via closure:
81
82        topic = null;
83        element = null;
84        listenerfn = null;
85
86        // Return a function to unsubscribe
87        return function() {
88            subscribers = _.without(subscribers, subscriber);
89            purgePublisherCache(subscriber.topic);
90        }
91    }
92
93    /**
94     * Creates a publish function for the indicated topic name and DOM element. For global
95     * events, the convention is to use the document object.
96     *
97     * <p>
98     * The returned function is used to publish a message. Messages are
99     * published synchronously. The publish function will invoke listener
100     * functions for matching subscribers (subscribers to the same topic). Exact
101     * subscribers (matching the specific element) are invoked first, then
102     * general subscribers (not matching any specific element). The return value
103     * for the publish function is an array of all the return values from all
104     * invoked listener functions.
105     *
106     * <p>
107     * Listener functions are passed the message object and a second (optional) object.
108     * The second object contains two keys:  The first, "element", identifies the element for which the publisher was created, i.e.,
109     * the source of the message. The second, "cancel", is a function used to prevent further listeners
110     * from being invoked.
111     *
112     * <p>
113     * There is not currently a way to explicitly remove a publisher; however,
114     * when the DOM element is removed properly, all publishers and subscribers
115     * for the specific element will be removed as well.
116     *
117     * <p>
118     * Publish functions are cached, repeated calls with the same topic and
119     * element return the same publish function.
120     *
121     * @param topic
122     *            used to select listeners
123     * @param element
124     *            the DOM element used as the source of the published message
125     *            (also used to select listeners). Passed through T5.$(), the
126     *            result must not be null.   The element will be passed to listener function as
127     *            the second parameter.
128     * @return publisher function used to publish a message
129     */
130    function createPublisher(topic, element) {
131
132        element = $(element);
133
134        if (element == null) {
135            throw "Element may not be null when creating a publisher.";
136        }
137
138        var existing = _.detect(publishers, function(publisher) {
139            return publisher.topic === topic && publisher.element === element;
140        });
141
142        if (existing) {
143            return existing.publisherfn;
144        }
145
146        var publisher = {
147            topic : topic,
148            element : element,
149            publisherfn : function(message) {
150
151                if (publisher.listeners == undefined) {
152                    publisher.listeners = findListeners(publisher.topic,
153                        publisher.element);
154                }
155
156                var canceled = false;
157
158                var meta = {
159                    element : publisher.element,
160                    cancel : function() {
161                        canceled = true;
162                    }
163                };
164
165                var result = [];
166
167                for (var i = 0; i < publisher.listeners.length; i++) {
168
169                    var listenerfn = publisher.listeners[i];
170
171                    result.push(listenerfn(message, meta));
172
173                    if (canceled) {
174                        break;
175                    }
176                }
177
178                return result;
179            }
180        };
181
182        publishers.push(publisher);
183
184        // If only there was an event or something that would inform us when the
185        // element was removed. Certainly, IE doesn't support that! Have to rely
186        // on T5.dom.remove() to inform us.
187
188        // Mark the element to indicate it requires cleanup once removed from
189        // the DOM.
190
191        element.t5pubsub = true;
192
193        // Don't want to hold a reference via closure:
194
195        topic = null;
196        element = null;
197
198        return publisher.publisherfn;
199    }
200
201    /**
202     * Creates a publisher and immediately publishes the message, return the
203     * array of results.
204     */
205    function publish(topic, element, message) {
206        return createPublisher(topic, element)(message);
207    }
208
209    /**
210     * Invoked whenever an element is about to be removed from the DOM to remove
211     * any publishers or subscribers for the element.
212     */
213    function cleanup(element) {
214        subscribers = _.reject(subscribers, function(subscriber) {
215            return subscriber.element === element
216        });
217
218        // A little evil to modify the publisher object at the same time it is
219        // being removed.
220
221        publishers = _.reject(publishers, function(publisher) {
222            var match = publisher.element === element;
223
224            if (match) {
225                publisher.listeners = undefined;
226                publisher.element = undefined;
227            }
228
229            return match;
230        });
231    }
232
233    return {
234        createPublisher : createPublisher,
235        subscribe : subscribe,
236        publish : publish,
237        cleanupRemovedElement : cleanup
238    };
239});
240
241/**
242 * Create aliases on T5 directly: pub -&gt; T5.pubsub.publish and sub -&gt;
243 * T5.pubsub.subscribe.
244 */
245T5.extend(T5, {
246    pub : T5.pubsub.publish,
247    sub : T5.pubsub.subscribe
248});

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.