/* 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);