heinrichapfelmus / threepenny-gui Goto Github PK
View Code? Open in Web Editor NEWGUI framework that uses the web browser as a display.
Home Page: https://heinrichapfelmus.github.io/threepenny-gui/
License: Other
GUI framework that uses the web browser as a display.
Home Page: https://heinrichapfelmus.github.io/threepenny-gui/
License: Other
This might be a problem with my particular usage. Every time I do anything with the GUI, I see the memory footprint of my program shoot up 100-400 KB. Every time I drag and drop. Every time I click on a tab. (These are pretty much the only things my GUI can do right now.)
It would be cool if we could host the examples live, so that people can try them out without downloading anything.
FP Haskell Center offers to live hosting of Haskell code, but their terms of use are too vague for my taste.
At the moment, the application would have to be restarted every now and then, because event handlers of DOM elements are not garbage collected.
I would like to simplify the API for GUI layout.
Since our focus is on GUIs, I wonder if we should downplay the full HTML capability and instead provide a few combinators for aligning GUI elements. WxHaskell has a layout combinators like grid
, row
and column
that make it very easy to align elements. For instance, the following screen layout
was created by the following code
do
f <- frame [ text := "CRUD Example (Simple)" ]
listBox <- singleListBox f []
createBtn <- button f [ text := "Create" ]
deleteBtn <- button f [ text := "Delete" ]
filterEntry <- entry f [ ]
firstname <- entry f [ ]
lastname <- entry f [ ]
let dataItem = grid 10 10 [[label "First Name:", widget firstname]
,[label "Last Name:" , widget lastname]]
set f [layout := margin 10 $
grid 10 5
[[row 5 [label "Filter prefix:", widget filterEntry], glue]
,[minsize (sz 200 300) $ widget listBox, dataItem]
,[row 10 [widget createBtn, widget deleteBtn], glue]
]]
Even though the layout is fairly complex, it can be specified in just 18 lines of Haskell code, half of which are essentially just a list of widgets.
The thing is that HTML allows very rich and aesthetically appealing user interfaces, but the design tends to take a lot of time (also because HTML+CSS has an impoverished box model compared to, say, TeX). When writing a GUI application, I wager that programmers probably to prototype the functionality first and upgrade the design later. Hence, a couple combinators for quickly creating layouts might come in very handy.
What is your opinion of the combinators grid
, row
, column
?
Concerning style, WxHaskell specifies attributes as
set x [ attr := value, attr2 := value ]
but I don't think that this is worth copying. I prefer the elegant Ji style that uses chains of #
in a clever way.
However, I would like to reduce the number of variants of #
, #+
, #=
and so on, and streamline this part of the API as well. Unfortunately, there are many possibilities for doing so, and I have a hard time making decisions without guidance from example GUI code.
@daniel-r-austin, I would would be very interested in a screenshot of the GUI program you mentioned. Also, did you create elements mostly with the Haskell code (new
and so on), or did you specify the layout by writing a HTML page first? What about GUI elements that are created dynamically, like elements of, say, a shopping cart?
While connecting to GUIs via a web browser is nice, it would also be great if we could package Threepenny apps as native applications.
Technology-wise, the idea is to write a native app ("shell") which contains the Threepenny application as resource. When run, the native app forks the Threepenny app, embeds a browser (say WebKit) and connects to the Threepenny server. Further more, the shell injects some JavaScript plugins into the web browser, which can be called from driver.js
.
For instance, this would allow us to better deal with file system operations like opening and saving files, and we can use the system menu bar.
Ideally, the whole thing would be integrated with cabala, similar to the cabal-macosx package. I'm thinking of a package named threepenny-wrapper
that hooks into cabal and which depends on threepenny-wrapper-wine
and so on depending on the platform.
Such a system subsumes issue #27 where the question was about packaging resources with the library.
This is essentially a continuation of issue #24 .
The goal of Threepenny is to make GUI development easy, and this also includes the visual aspects of UI design. Unfortunately, HTML and CSS are terrible languages for specifying box layouts.
What we really want is a nice Haskell API that hides the complexities of CSS and offers a nice way to specify layout. The grid
, column
and row
combinators are a good start, but they are currently implemented as CSS tables, which tend to behave unpredictable, especially when content size changes dynamically.
Fortunately, it appears that the CSS 3 offers a new feature, flexbox layout, which apperas to solve most of the layout woes. Flexboxes may be a good start for implementing proper layout combinators in Haskell.
Flexboxes only work in newer browsers, but we could bundle our own browser during deployment #52 .
template-haskell < 2.9 is needed, but 2.8.x cannot be built on ghc 7.8.x.
aeson-0.6.x has the same problem (also see issue #77).
aeson-0.6.2.1 depends on template-haskell-2.8.0.0 which failed to install.
threepenny-gui-0.4.1.0 depends on template-haskell-2.8.0.0 which failed to install.
Other than the fact that HJscript seems to have no documentation, it would be good to explain the difference in the README.
(I was unsure about to which repository I should post this. The code has actually more to do with reactive-banana than with Threepenny, but the case being made is mainly about Threepenny.)
I was wondering how convenient it would be to write reusable widgets for Threepenny. Nothing sophisticated would be needed at first, just the bare minimum so that we wouldn't have to rewrite or copy-paste stuff like a custom file picker on every project. So I went ahead and made a proof-of-concept, and now I am stunned at how easy it was, given that I basically started from scratch. It could be even simpler - someone wishing to use similar methods right now without any fanciness could just drop the trivial Component
class.
I do not know how sound this approach to components would be in the long run, and interesting questions would arise were it to be made more general. For instance, how to minimize the boilerplate needed for defining the component data type? Or what the best way to let users style components is? (Just export the Element
fields and let users do whatever they want with them? Or perhaps add styling hooks into the component network?) In any case, and however the actual code might look like, I believe it would be good if Threepenny users were made aware of the possibility of defining reusable widgets, be it through the packaged examples, or, eventually, even through novel support modules.
Hello again! It's been a while, but I finally got back to playing with Threepenny. My latest experiment involved bindings to a small subset of jQuery UI. While it works very well, the trickery involved was, ahem, interesting. Quoting one of my commit messages:
Experimenting with bindings to JQuery UI's Autocomplete widget.
The key complication arises from the fact that we need to have the library
fully loaded by the time we callautocompleteInit
on the text box. As of
Threepenny 0.4.0.2, following usual JavaScript practice by chaining the
initialisation steps with callbacks is not feasible, at least as far as I can
see. Using theload
event of thescript
element does not work either, as
JQuery (which handles element appendage behind the scenes) will evaluate the
script and eliminate the DOM element. The next best option, then, is to load
the script via a synchronous request. The JavaScript code for doing so was
wrapped withcallFunction
to keep it blocking.It should be mentioned that the easiest way to load something like JQuery UI
would probably be throughtpCustomHTML
. That, however, would be rather
opaque and inflexible.See also http://stackoverflow.com/a/2880147/2751851 , from which the sync
request snippet was mostly taken.
How sane do you think this approach is, and how long is it likely to survive given the evolution of the API? Also, I noticed that improvements to the FFI are being prepared for 0.5, including support for exporting Haskell callbacks. Will they be applicable to this scenario - for instance, by loading a library with jQuery's getScript
while passing the rest of the Haskell initialization as a callback?
We should probably put the drag & drop attributes and events into a single module.
We should also add an example that showcases all the available events and attributes.
Also think about drag data. Ideally, we want to put arbitrary Haskell values there, though that would probably require an FFI construction à la StablePointer. This discussion is probably best left to issue #23, though.
It appears that Chrome caches stylesheet files regardless of whether the server would return a newer one. This messes up the display when trying different examples (For example first Chat.hs, then BarTab.hs) or when developing an application.
I don't know how to fix this right now, but it probably involves setting sone sort of "no-cache" header in the HTTP response. This should be done not only for style files, but for all other files (JS, loadFile) as well. We assume that the server runs on localhost anyway.
The default configuration for a Threepenny program is to listen on port 10000. However it turns out that µTorrent is listening on that port as well, which means that you can't use Threepenny applications while the µTorrent application is running.
This has caused at least one user to have installation woes with Threepenny, something which I wanted to avoid at all cost.
Any suggestions for a default port number that Threepenny should use instead?
The library no longer works in older versions of Safari, like 5.1. Apparently, this is due to changes in the websockets-0.8
library. The server logs the following message:
MalformedRequest (RequestHead {requestPath = "/websocket", requestHeaders = [("Sec-WebSocket-Key1","m669x[G8 1E i#h31rN04"),("Sec-WebSocket-Key2","^5l847(61z 5( 44!"),("Host","localhost:10000"),("Origin","http://localhost:10000"),("Connection","Upgrade"),("Upgrade","WebSocket")], requestSecure = False}) "Header missing: Sec-WebSocket-Key"
Issue reference in the dependency: jaspervdj/websockets#51 and jaspervdj/websockets#49 .
This is unlikely to be fixed, older browsers will probably not be supported.
I'm trying to install threepenny-gui version 0.4.1.0 through cabal, but I'm getting the following error:
src\Graphics\UI\Threepenny\Internal\Driver.hs:251:24:
Not in scope: `LBS.fromStrict'
Version 0.4.0.2 compiles fine.
I find that HTML attributes in Graphics.UI.Threepenny.Attributes
module are all WriteAttr
. I haven't found out how to get the id_ attribute (or any attribute) of an element?
BTW, is there a plan to support the data-
attributes?
Daniel Diaz suggests:
My only suggestion is that a little example should be included in the API documentation, maybe in the Graphics.UI.Threepenny module. The examples provided in the library are nice, but sometimes you look at the API first (as I do) and it might help. Personal opinion, of course.
Also, you may point to the Graphics.UI.Threepenny.Core module in the cabal description or the Graphics.UI.Threepenny module, since I think is the best place to start reading the API docs.
EDIT: You can also point to some information about how to use FRP with threepenny-gui!
I think this library should be able to drop the snap dependency and be framework independent.
On noticing newEventsNamed
, my first thought was "here is a drop-in replacement for Control.Event.newEventsTagged
". The second thought, of course, was "but how do I fire the events"? Eventually, I understood that newEventsNamed
should be the way it is; partly by finding its uses in the rest of Threepenny, and partly from trying to make it equivalent to the old newEventsTagged
only to realize it is not as simple as it seems. On the other hand, it is easy to implement newEventsTagged using only the exported functions of Reactive.Threepenny
, and it works perfectly well (I use it to create event-based getters without having to expose the corresponding Behavior
). Given all of that, I am left with two questions: Is that a sensible use of newEventsNamed
? And do you see a place for something in the vein of newEventsTagged
in the API?
Let's keep this going! I noticed an issue the other day and I am not sure how to diagnose it. My TP worker starts out doing an IO action to read in a data file and build some Maps. After this is complete and I'm ready to start using my GUI, my program uses around 110-120 MB of memory. If I hit refresh in my browser, the memory in use goes to around 240-250 MB. The increase in memory make sense to me - the map is being rebuilt just like the first time. However, I don't understand why the old session's memory isn't cleaned up. I let my program idle for 20 minutes to be sure there is plenty of time for cleanup timers and whatnot to run, but the memory never goes down.
I threw in some trace calls to try to figure it out but have had no luck so far.
This is not really an issue, but arguably it qualifies as a meta-issue. I have just created a threepenny-gui tag in SO and added the handful of existing Threepenny questions to it. I used "threepenny-gui" rather than "threepenny" merely because that seems to be what askers are more likely to use. However, I just noticed there is a link in the Haskell Wiki page about Threepenny which leads to the new question interface in SO initialised with the (not yet existent) "threepenny" tag. That being so, you might want to take some of the following measures:
This is a suggestion based on a particular experience I had when just getting a hang of Haskell. I saw needlessly large memory usage when using String keys in Maps. See my short blog post on the topic here.
In FNIStash, I use a lot of TPG code to set up the GUI. Because the driver code is written in a recursive fashion, a lot of recursion goes on. Couple these things together and you can fairly easily hit the recursion limit in JS and get "too much recursion" errors in the web console. At first this was being triggered by JSON.stringify
in console_log
calls, but after commenting those out it still can arise.
Note that I encountered the recursion limit in FF, which caused TPG to be entirely unresponsive. When I switched to Chrome, which has a much higher limit, the issue disappeared. (for now)
Hi,
threepenny-gui 0.4.1 requires "bytestring >=0.9.2 && <0.11", however Graphics / UI / Threepenny / Internal / Driver.hs uses "LBS.fromStrict" which has been introduced in bytestring-0.10.0.0.
On my system (GHC 7.4.1 + HP), "cabal install threepenny-gui" fails because of that.
I have noticed that work on integrated FRP has already stared in the embed-frp branch. I realize that I am probably jumping the gun by raising this issue now, given how very new that is, but anyway: do you plan to support reactive-banana-threepenny once 0.3.0.0 is released?
Context: I have just attempted to build my current project with the head of embed-frp, hoping that it would take little more than averting name clashes and replacing the Control.Event
functions with the corresponding Threepenny.Reactive
ones. Obviously that didn't work, as things like blur
in Graphics.UI.Threepenny.Events
now have quite different types.Of course, there is no urgency about it (just me being nosy and trying to build stuff off the development head!), but I would like to plan ahead in case there will be a need to, e.g. port my code (and any missing reactive-banana combinators it might need) to Threepenny.Reactive
, or writing an alternative Control.Event
able to bridge reactive-banana and threepenny 0.3.*.
When I run TPG, I get a warning as soon as I start it up that access and error logs will be written to std error. I have been unsuccessful in identifying the path where I need to put the log files to get TPG (Snap) to use them. I've tried a few, but each time I get the same notice when I start my program.
I think TPG should create these files if they don't exist so that logging never encounters this issue. Also nice would be allowing the user to configure the path used for the log files.
Getting started with threepenny-gui and SVG I ported the simple example code from, http://www.w3schools.com/svg/, to this threepenny-gui Haskell,
module W3Svg (main) where
import Control.Monad (void)
import qualified Graphics.UI.Threepenny as UI
import Graphics.UI.Threepenny.Core
main :: IO ()
main = startGUI defaultConfig setup
setup :: Window -> UI ()
setup w = void $ do
return w # set title "W3 Schools Svg"
caption <- UI.h1 # set text "My first SVG in Haskell"
-- <svg width="100" height="100">
context <- mkElement "svg" # set (strAttr "width") "100"
# set (strAttr "height") "100"
-- <circle cx="50" cy="50" r="40" stroke="green" stroke-width="4" fill="yellow" />
circle <- mkElement "circle" # set (strAttr "cx") "50"
# set (strAttr "cy") "50"
# set (strAttr "r") "40"
# set (strAttr "stroke") "green"
# set (strAttr "stroke-width") "4"
# set (strAttr "fill") "yellow"
getBody w #+ [element caption, element context #+ [element circle]]
-- Copied from Graphics.UI.Threepenny.Attributes
strAttr :: String -> WriteAttr Element String
strAttr name = mkWriteAttr (set' (attr name))
However, when pointing a browser to http://localhost:8023 I see only the caption output and not the green and yellow circle of the example. Checking with the DOM inspector the tags seem to present, complete, and in the correct order.
When I do cabal install threepenny-gui
I get the following error:
....
In-place registering threepenny-gui-0.1.0.0...
Preprocessing executable 'threepenny-examples-bartab' for
threepenny-gui-0.1.0.0...
src/BarTab.hs:9:8:
Could not find module `Paths'
Use -v to see a list of the files searched for.
Failed to install threepenny-gui-0.1.0.0
I'm running Ubuntu with ghc version 7.6.2. cabal-install version 1.16.0.2 using version 1.16.0.3 of the Cabal library.
When using a Haskell string as a property value on some element, Scandinavian characters (probably others as well) display incorrectly. Using a custom HTML file with a <meta charset="utf-8">
doesn't affect the issue.
The following minimal example should create a button with the text åäö
. However, it actually creates a button with the text 98¦
:
import Graphics.UI.Threepenny
main = do
startGUI defaultConfig $ \w -> do
getBody w #+ [button # set text "åäö"]
return ()
I have just finished a rewrite of the bounded input widget of Stunts Cartography with the explicit goal of making it conform to the three principles proposed by Apfelmus in this blog post. I am pleased with the result - it does everything I need, and both widget and application code are better than before. You can check the widget implementation and how the rest of the application uses it (look for the BI.
import qualifiers). The rewrite was hugely instructive, and there are several interesting little points to be made; in order not to bore you with a(n even longer) wall of text, however, I will stick to the essentials for now, and wait for your comments:
Basic usage: new
returns a widget with no model, which is then connected to the rest of the application with either plugModel
or its convenience applications simpleModel
and userModel
. All of the these three functions return the model (i.e. a Behavior whose value is displayed and possibly modified through the widget and which follows whatever promises the widget specification makes - e.g., for BoundedInput
, that the value will be constrained to the bounds specified through new
). In my application, I had no need of using the more general plugModel
, as I do not need to filter or otherwise process the raw user event before using it to define the model. If you want an example of it in action, the implementation of simpleModel
should give the general idea.
Given the decoupling of model and widget in implementations like this one, I reckon that the best description of their relation is not "the widget has a model which is used by the application", but "the widget is a tool used by the application to define a model". In support of that point of view, I mention an analogy born out of a discarded experiment. Imagine that we modified new
so that it incorporated plugModel
in order to return both the Behavior and the widget in a tuple. It would then be used like this...
(bFoo, widgetFoo) <- new ..
... which looks a lot like this:
(eFoo, fireFoo) <- newEvent
Just as newEvent
produces an Event and an IO action to trigger it, the combination of new
and plugModel
produces a Behavior and a IO tool to display and modify it; that is, the widget.
It is almost spooky how this style seems to ensure that the only convenient way of doing things is the clean, DRY one. Once I bought into the model-widget decoupling idea, everything fell into its right place, and many design improvements suddenly became obvious. That applies not only to the BoundedInput
itself but also to the application code which uses it - for one, it made me realize that Behaviors are vastly superior to Events with respect to defining the semantically relevant parts of the event network (as opposed to mere glue code).
(This issue is a follow-up of sorts to #40 and #49. It is related to, but distinct from and possibly complementary to, #53.)
For the upcoming release, I would like to include links to and screenshots of applications developed with Threepenny.
@daniel-r-austin has a couple of screenshots on his projects' webpage http://fluffynukeit.com/?p=488, so I will just pick the most colorful one.
@duplode , could you post some visual fluff from your Stunts project?
I would like to streamline the API by removing the TP
monad and the MonadTP
class.
The TP
monad carries around some information about the session. However, the observation is that for functions like appendTo
or getValue
that operate on a particular element, the session information is essentially already encoded in the element argument. After all, the Element
type can be thought of as pointing to one particular element in one particular browser window; so it's not just an "abstract" DOM node, but a specific instance in a particular session. To make a long story short, we can change the type to
getValue :: Element -> IO String
by tracking the session context with every Element
.
This does not work for all functions. For instance, the getHead
or getElementById
functions need to refer to a particular session. However, I think it is natural to add an argument called Window
which represents a particular browser window (and associated session context).
getElementById :: Window -> IO (Maybe Element)
I think that these two changes would improve the API syntactically while keeping it conceptually simple.
Please let me know what you think.
Currently, text versions 1.0 and 1.1 are excluded by the version bounds. Could you release a new version with a relaxed upper bound on text?
Would give an arm for templates, url routing and some nice nice tutorial!
XxxXXX>>>>>>> Please plz plz don't let this project die!!!!
getElementsByClassName
is giving me problems. When calling it, I get the following error:
user error (Pattern match failure in do expression at Graphics/UI/Threepenny/Core.hs:143:5-15)
To reproduce:
add to <body>
in wwwroot/chat.html:
<div class="test">
</div>
replace in setup
src/Chat.hs:
getBody window #+
by
first <- head <$> getElementsByClassName window "test"
element first #+
Drawing is important for GUI applications and I propose that threepenny-gui offer some out-of-the-box facilities for that.
As a first step, I would be happy with a small number of drawing primitives that offer what the old Hugs Graphics Library or the newer gloss library can do.
Later on, we might ponder integration with the diagrams library.
When doing nix-env -i haskell-threepenny-gui-ghc7.6.3
the following errors are obtained: http://lpaste.net/105233.
This is probably due to the constraint on aeson version, which is ==0.6.*
, while the nix packaged version is 0.7.0.3
json
0.7 is now out, which is what we have packaged in NixOS. This means that I can't build threepenny-gui
on NixOS, as threepenny-gui
requires json
< 0.6.
To make installation of executables that use this library simple, the library should include all necessary resources, like the JS driver code or HTML pages, in the compiled executable and not refer to any outside directories.
This can be done using QuasiQuotation, but unfortunately, this triggers a bug in Haddock #12 , so I have disabled this feature for now.
The commit 059aeee with the checkedChange
event was not merged with develop along with the rest of the embed-frp branch. I would have sent a pull request adding it back, but I don't know if your preference is to merge or to rebase in such cases.
Hi,
Maybe a solution for too much traffic generated between server/client is to move the client code to the client (Haskell->JS) so the most of the client stuff that happen on client, stays on client.
Google’s GWT has something similar for Java and its solution might be used in 3p as well.
In GWT you're writing all the web-app code in Java, but the project is physically separated into 3 top directories/sections: server, client and shared.
Client code is written in files that will be compiled into JS. That code has limitations on functions that can be used, but it is possible to use FFI for third-party JS functions and wrappers for JS vars.
Server code is full blown Haskell code that will be executed on host.
Not so much server/client communication.
Best regards,
vlatko
If I understand that correctly, calling a JS function from the serve side has a latency of ~500ms because the client side has to poll commands from the server. I don't mind a little latency, but with several function calls on the server side, this will become big very soon.
An implementation using websockets would alleviate this problem.
Then again, we may not want to reinvent the wheel and instead build everything on the recently released sunroof project, which is a full-blown JavaScript DSL in Haskell. It is very similar to the threepenny-gui approach, though with a slightly different emphasis.
No handler accepted "/"
Tried to install threepenny-gui for the first time. The threepenny-examples-buttons failed to build because the json package is hidden. I added it to the exe's build-depends, but that led to the same issue with system.filepath. As a work around, I removed all the exe's from the cabal file and installed only the library (I believe successfully).
The documentation and examples must be updated to be consistent with the new threepenny-gui branding.
UI is a monad, and theoretically every monad is also an applicative functor. However, there's currently no Applicative instance for UI.
I'm currently experimenting with implementing a small application for annotating videos in threepenny-gui.
In HTML5, videos can be included with the video
tag like this
<video id="presentation-video" controls>
<source src="data/video.mov">
<source src="data/video.ogv" type="video/ogg">
</video>
I would like users to load their local video files into the player. However, for security reasons, the browser refused to accept URIs of the form file://
in the src
tag. This not only applies to videos, but images and audio as well. The only way to pass a local file to the browser window is to mirror it via the threepenny server first.
Hence, I propose to add two functions
type URI = String
loadFile :: FilePath -> IO URI
loadDirectory :: FilePath -> IO URI
that instruct the web server to serve a file or directory under an URI of its choosing. In the case of a video, I can now load a local file into the player with
remoteFilename <- loadFile localFilename
element videoSource # set (attr "src") remoteFilename
A nice side effect of these functions is that they make the tpStatic
parameter of the server configuration obsolete. The directoy for static resources can now be loaded dynamically in the setup.
static <- loadDirectory "wwwroot"
addStyleSheet (static </> "buttons.css")
I get the following compilation failure when building both from the latest version on github and the latest hackage version:
src/Graphics/UI/Threepenny/Internal/Resources.hs:15:7:
Exception when trying to run compile-time code:
src/Graphics/UI/jquery.js: hGetContents: invalid argument (invalid byte sequence)
Code: Language.Haskell.TH.Quote.quoteExp
include "Graphics/UI/jquery.js"
I would like to make event handling more pleasant by making "the process of registering event handlers" first class.
The concept is probably best explained by referring to the source code of the Control.AddHandler module which I've introduced in commit fecc5c6 . The idea is to give a name to the "process of registering event handlers".
type Handler a = a -> IO ()
newtype AddHandler a = AddHandler { register :: Handler a -> IO (IO ()) }
In other words, events like button clicks or mouse movements are now represented by an AddHandler
.
onClick :: Element -> AddHandler ()
onMouseMove :: Element -> AddHandler MousePosition
onKey :: Element -> AddHandler KeyWithModifiers
Besides being conceptually appealing, I think that this approach has two main advantages:
AddHandler
themselves. For example, they are an instance of the Functor
class, so that a mapping between event values a -> b
induces a mapping AddHandler a -> AddHandler b
, allowing us to obtain seemingly new events like onModifiers
from old ones like onKey
.AddHandler
being first-class.Essentially, this is a baby version of FRP, but I think it makes a lot of sense in the imperative style. Of course, if more complicated transformations of events are desired (merging), then one should use a full-blown FRP library instead. Even then, the first-class event handling presented here provides a smooth transition.
Perhaps we should even go so far to call this thing Event
instead of using the ugly name AddHandler
.
What do you think?
Haddock fails with the message
During interactive linking, GHCi couldn't find the following symbol:
threepennyzmguizm0zi1zi0zi0_GraphicsziUIziThreepennyziInternalziInclude_include_closure
It appears that we've bumped into a GHC/Haddock bug http://trac.haskell.org/haddock/ticket/187 .
TPG should offer users a way to register actions to be triggered when a user disconnects, navigates away from the page, closes the window, etc. Among other things, this would allow easy freeing of resources that were allocated for the user's session.
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.