benzap / Flyer.js
Programming Languages
Labels
Projects that are alternatives of or similar to Flyer.js
-
Flyer.js
[[./doc/intro.png]]
flyer.js is a lightweight messaging library written for clojurescript & javascript.
It provides broadcast messaging between frames, iframes, and windows.
[[https://clojars.org/flyer][https://img.shields.io/clojars/v/flyer.svg]]
-
Including flyer in your clojurescript project ** Leiningen #+BEGIN_SRC clojure [flyer "1.1.2"] #+END_SRC
** Clojure CLI/deps.edn
#+BEGIN_SRC clojure flyer {:mvn/version "1.1.2"} #+END_SRC
** Gradle #+BEGIN_SRC sh compile 'flyer:flyer:1.1.2' #+END_SRC
** Maven #+BEGIN_SRC xml flyer flyer 1.1.2 #+END_SRC
- Features and Operation
- Simple API, from which you can build more elaborate messaging systems.
- Messages are broadcasted to all frames and registered windows, regardless of whether or not they want them (hence, the name)
- Frames can subscribe to specific channels, and can regex-match to broader topics being sent on that channel
- Javascript Configuration
- Include /flyer.js/ at the end of your page body #+BEGIN_SRC html
#+END_SRC
- In situations where you would use window.open, use flyer.window.open instead. This is required in order to track window references.
- Download
- [[https://github.com/benzap/flyer.js/releases/tag/v1.1.2][Version 1.1.2]]
- Javascript API
** flyer.broadcast([Options])
*** Options
- channel :: the channel you wish to broadcast on. default is "*", which stands for all channels
- topic :: the topic of your broadcast message. default is "*", which stands for all topics
- data :: any JSON serializable object
- target :: determines what type of target domain is expected to receive this message. By default, the target is "all", but it can be set to "local", or a target domain of your choosing. *** Examples #+BEGIN_SRC js flyer.broadcast({ channel: "default", topic: "person.insert", data: {id: 1, name: "Ben"} });
flyer.broadcast({ channel: "default", topic: "person.delete", data: {id: 1} }); #+END_SRC
** flyer.subscribe([Options]) *** Options - channel :: the channel you wish to subscribe to. default is "", which stands for all channels - topic :: the topic you wish to subscribe to. default is "", which stands for all topics. Note that this can also be a string representation of a regex expression. - callback :: callback function of the form function(data, [topic], [channel] [origin]) that you wish to call when the subscription is made. - origin :: refers to the origin, or domain from which the messages will be received. The default is all, but it can be set to local, or to another origin *** Examples #+BEGIN_SRC js flyer.subscribe({ channel: "default", topic: "person.*", callback: function(data, topic, channel) { if (topic == "person.insert") { console.log("Inserted Person! - " + data.name); } else if (topic == "person.delete") { console.log("Removed Person with id - " + data.id); } } }); #+END_SRC
** flyer.window.open(url, name, [Options]) /follows the same API as window.open/
[[https://developer.mozilla.org/en-US/docs/Web/API/Window.open][Mozilla API Page]]
-
Clojurescript API (untested) ** flyer.messaging/broadcast *** (broadcast & options) *** Options
- channel :: the channel you wish to broadcast on. default is "*", which stands for all channels
- topic :: the topic of your broadcast message. default is "*", which stands for all topics
- data :: any JSON serializable object
- target :: refers to the target origin, or domain in which to post the message. The default is :all, but it can also be :local, or a target origin of your choosing *** Example #+BEGIN_SRC clojurescript (broadcast :channel "default" :topic "person.insert" :data {:id 1 :name "Ben"} :origin :all) #+END_SRC ** flyer.messaging/subscribe *** (subscribe & options) *** Options
- channel :: the channel you wish to subscribe to. default is "*", which stands for all channels
- topic :: the topic you wish to subscribe to. default is "*", which stands for all topics. Note that this can also be a string representation of a regex expression.
- callback :: callback function of the form (fn [data] [topic] [channel] [origin]) that you wish to call when the subscription is made.
- origin :: the origin you wish to subscribe to. This is decides on the domain that messages can be received. The default is :all, but it can also be :local, or an origin of your choice *** Example #+BEGIN_SRC clojurescript (subscribe :channel "default" :origin :local :topic "person.*" :callback (fn [data topic channel] (condp = topic "person.insert" (.log js/console "Inserting person! - " (.-name data)) "person.delete" (.log js/console "Deleting person! - #" (.-id data))))) #+END_SRC ** flyer.window/open *** (open url name & options) *** url parameter The window URL *** name parameter The unique name you wish to give the window *** Options key / value pairs of options equivalent to window.open options *** Example #+BEGIN_SRC clojurescript (open "frame_login.html" "login-page" :width 400 :height 600) #+END_SRC
-
Example /Examples Outdated/
-
Project Compilation
- Clone this Repository
- Install [[http://leiningen.org/][Leiningen]]
- cd into flyer.js directory
- type lein deps
- resulting flyer.js should now be present in ./resources/public/js/
-
Issues
- In order to communicate with frames and windows that are within an external window, you need to replace window.open with flyer.window.open
- The size of flyer.js is quite big, at a whopping 1mb. This is due to the nature of compilation. Use flyer.min.js to bring this down to 100kb
- Refreshing the parent window of an opened window will break any messages from being broadcasted throughout the application. This is due to the external window frame losing its parent (window.opener).
- external windows can be refreshed without losing communications, however, it requires that flyer.js be included within that html page
-
Technical Details ** How it works flyer.js works by hijacking window.postMessage, and the event generated, which can be attached to through the "message" event
[[https://developer.mozilla.org/en-US/docs/Web/API/Window.postMessage][Mozilla API Page]]
#+BEGIN_SRC js //attaching a listener to frame[0] window.frame[0].addEventListener("message", function(event) { console.log(event.data, event.origin) });
//posting a message to frame[0] window.frame[0].postMessage("some message", "*") #+END_SRC
It also does a few other things:
- generates a list of frames, by performing a traversal through all of the frames and external windows.
- wraps the functionality into two sane functions.
The full set of steps when performing a broadcast:
- Generate list of frames and external window frames (flyer.traversal)
- Generate a message, by stringifying a defined message object {channel:..., topic:..., data:...} (flyer.messaging)
- For each frame, f, perform f.postMessage(msg, target)
The full steps when performing a subscribe:
- Grab the callback function, and add a "message" event listener
decorated with a set of rules
- Does it have the same channel?
- Does it have the same topic?
- If it isn't the same topic, does the provided callback topic regex match the broadcasted topic?
- Does it have a lax origin, or is it accepting all origins?
- If it passes the conditions in step 1, the main callback is called with the results of the broadcast. Further conditions can be provided at the developers discretion.