Skip to content

Instantly share code, notes, and snippets.

@bitemyapp
Forked from wmakley/elm_handlers.js
Created November 7, 2017 21:36
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save bitemyapp/f413bbfca07f83b0d88e98bb12a01d80 to your computer and use it in GitHub Desktop.
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.
/*
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