-
-
Save bitemyapp/f413bbfca07f83b0d88e98bb12a01d80 to your computer and use it in GitHub Desktop.
jQuery-based utilities for things that are hard to do in Elm. Modify as desired. It is used in a project that already depends on jQuery, but it only really needs jQuery for attaching event handlers to the app container, and normalizing key press events.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
JSCmd.elm | |
========== | |
port module JSCmd exposing (..) | |
port focus : String -> Cmd msg | |
port confirm : ( String, ReturnInfo ) -> Cmd msg | |
port highlight : String -> Cmd msg | |
port setValue : ( String, String ) -> Cmd msg | |
type alias ReturnInfo = | |
{ incomingPort : String | |
, id : Int | |
} | |
*/ | |
(function ($) { | |
'use strict' | |
/** | |
* Handlers for the JSCmd module's outgoing ports. Should | |
* work for most apps. | |
* | |
* Usage: | |
* | |
* var flags = {} | |
* var app = Elm.MyApp.embed(container, flags); | |
* ElmHandlers.setup(app, container, ElmHandlers.ALL); | |
* | |
* // Optional hacks that are difficult to do in Elm: | |
* ElmHandlers.preventTextBoxSubmit(container, 'input:text'); | |
* ElmHandlers.numericOnlyTextBoxes(container, 'input.numeric-only'); | |
* | |
* // Or specify your own character blacklist for certain inputs: | |
* ElmHandlers.customTextBoxKeyBlacklist(container, 'input.custom', [123]); | |
*/ | |
window.ElmHandlers = { | |
ALL: ['confirm', 'setValue', 'focus', 'highlight'], | |
setup: function (app, container, ports) { | |
var handlers = this; | |
if (!container) container = document; | |
if (!app.ports) return; | |
if (!ports) { | |
ports = handlers.ALL; | |
} | |
var context = { | |
app: app, | |
container: container | |
}; | |
$.each(ports, function (index) { | |
var portName = this; | |
var port = app.ports[portName]; | |
if (port) { | |
port.subscribe(function () { | |
handlers[portName].apply(context, arguments) | |
}); | |
} | |
}) | |
}, | |
/** | |
* Prevent text boxes from triggering a submit event when the enter key | |
* is pressed. If you embed an Elm app in Rails form, this can be a big | |
* problem. It is also currently difficult in Elm to stop event propagation | |
* for specific key presses. | |
*/ | |
preventTextBoxSubmit: function (appContainer, selector) { | |
$(appContainer).on('keydown', selector, function (event) { | |
if (event.which === 13) { | |
event.preventDefault(); | |
event.stopPropagation(); | |
} | |
}) | |
}, | |
/** | |
* Block non-numeric key presses for inputs matching a CSS selector. | |
* Helpful in creating inputs for currency and numbers, and a pain to do | |
* in Elm. | |
*/ | |
numericOnlyTextBoxes: function (appContainer, selector) { | |
var whitelist = [ | |
8, // backspace | |
45, // minus | |
46, // delete | |
190 // period | |
]; | |
$(appContainer).on('keypress', selector, function (event) { | |
var code = event.keyCode || event.which; | |
var i; | |
for (i = 0; i < whitelist.length; i++) { | |
if (whitelist[i] === code) { | |
return; | |
} | |
} | |
if (isNaN(String.fromCharCode(code))) { | |
event.preventDefault(); | |
} | |
}); | |
}, | |
/** | |
* Prevent a custom list of keys in certain text boxes (a pain to do with Elm, | |
* requiring multiple event handlers). | |
*/ | |
customTextBoxKeyBlacklist: function (appContainer, selector, blacklist) { | |
if (!blacklist || blacklist.length === 0) { | |
throw 'invalid blacklist'; | |
} | |
$(appContainer).on('keypress', selector, function (event) { | |
var code = event.keyCode || event.which; | |
var i; | |
for (i = 0; i < blacklist.length; i++) { | |
if (blacklist[i] === code) { | |
event.preventDefault(); | |
return; | |
} | |
} | |
}); | |
}, | |
/** | |
* Show a confirm box, and send a message back on a specified port | |
* containing an Int if "Okay" was clicked. | |
* | |
* For example, you could have the incoming port: | |
* | |
* deleteRecord : (Int -> msg) -> Sub msg` | |
* | |
* And then in your `update` function call: | |
* | |
* JSCmd.confirm | |
* ( "Are you sure you want to delete this item?" | |
* , { incomingPort = "deleteRecord", id = recordId } | |
* ) | |
* | |
* And in your subscriptions: | |
* | |
* subscriptions model = | |
* deleteRecord (\id -> DeleteRecord id) | |
*/ | |
confirm: function (tuple) { | |
var msg = tuple[0]; | |
var returnInfo = tuple[1]; | |
if (window.confirm(msg)) { | |
var port = this.app.ports[ returnInfo.incomingPort ]; | |
port.send(returnInfo.id); | |
} | |
}, | |
/** | |
* Primarily useful for when select boxes don't select the right item. | |
* This bug in Elm may have been fixed. | |
*/ | |
setValue: function (args) { | |
var selector = args[0]; | |
var value = args[1]; | |
setTimeout(function () { | |
$(selector, this.container).val(value); | |
}, 50) | |
}, | |
/** | |
* Focus an input via CSS selector. The most used feature of this script by far. | |
* This needs to be done all the time for a good UX, and there is no way to do it | |
* in Elm. | |
*/ | |
focus: function (selector) { | |
setTimeout(function () { | |
var elt = $(selector, this.container).first(); | |
if (elt.prop('tagName') === 'SELECT') { | |
elt.focus(); | |
} else { | |
elt.select(); | |
} | |
}, 50) | |
}, | |
/** | |
* Call the jQuery UI highlight effect. This could just as easily be implemented | |
* with a CSS 3 transition entirely in Elm now. | |
*/ | |
highlight: function (selector) { | |
setTimeout(function () { | |
$(selector, this.container).effect('highlight'); | |
}, 50); | |
} | |
} | |
})(jQuery); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment