[
  {
    "path": ".gitignore",
    "content": "dist/\nnode_modules/\nelm-stuff\nelm.js\npackage-lock.json\n"
  },
  {
    "path": "LICENSE",
    "content": "BSD 3-Clause License\n\nCopyright (c) 2020, Elm Community\nAll rights reserved.\n\nRedistribution and use in source and binary forms, with or without\nmodification, are permitted provided that the following conditions are met:\n\n1. Redistributions of source code must retain the above copyright notice, this\n   list of conditions and the following disclaimer.\n\n2. Redistributions in binary form must reproduce the above copyright notice,\n   this list of conditions and the following disclaimer in the documentation\n   and/or other materials provided with the distribution.\n\n3. Neither the name of the copyright holder nor the names of its\n   contributors may be used to endorse or promote products derived from\n   this software without specific prior written permission.\n\nTHIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\"\nAND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\nIMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE\nDISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE\nFOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\nDAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR\nSERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER\nCAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,\nOR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE\nOF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n"
  },
  {
    "path": "README.md",
    "content": "# Using JS within Elm\n\nElm can interact with JavaScript in three ways:\n\n- [flags](https://guide.elm-lang.org/interop/flags.html)\n- [ports](https://guide.elm-lang.org/interop/ports.html)\n- [custom elements](https://guide.elm-lang.org/interop/custom_elements.html)\n\nNot all browser APIs are covered by an official package yet, so if you are evaluating using Elm in your company, definitely browse through the examples here to get familiar with flags, ports, and custom elements to make sure these interop mechanisms will fully meet your needs. It may be safest to circle back to Elm later if not!\n\n\n## Ports\n\n- [localStorage](/localStorage) — [demo](https://ellie-app.com/8yYddD6HRYJa1)\n- [WebSockets](/websockets) — [demo](https://ellie-app.com/8yYgw7y7sM2a1)\n\n\n## Custom Elements\n\n- [Internationalization](/internationalization) — [demo](https://ellie-app.com/8yYbRQ3Hzrta1)\n- [Pie Chart Widget](https://ellie-app.com/8B2B8fWbvZwa1)\n- [Calendar Widget](https://ellie-app.com/8B8D2Q3WLh7a1)\n- [Project Fluent](https://github.com/wolfadex/fluent-web/)\n\n\n## Do you want to know more?\n\nThe top-level examples presented here are intentionally boiled down to a minimal setup for you to understand the basic ideas and get started quickly. As the web platform is a place with a lot of history and odd API corners there are more involved examples and tutorials to be explored in the [more](/more) section.\n\n* [Everything you need to know to use WebComponents in your Elm app](/more/webcomponents)\n"
  },
  {
    "path": "internationalization/README.md",
    "content": "# Internationalization - [Live Demo](https://ellie-app.com/8yYbRQ3Hzrta1)\n\nThis is a minimal example of how to use the `Intl` library with a custom element.\n\n![Demo](demo.gif)\n\nThe important code lives in `src/Main.elm` and in `index.html` with comments!\n\nCheck out [`wolfadex/fluent-web`](https://github.com/wolfadex/fluent-web/) for a more complete approach, making [Project Fluent](https://projectfluent.org/) available through custom elements.\n\n\n## Building Locally\n\nRun the following commands:\n\n```bash\ngit clone https://github.com/elm-community/js-integration-examples.git\ncd js-integration-examples/internationalization\n\nelm make src/Main.elm --output=elm.js\nopen index.html\n```\n\nSome terminals may not have an `open` command, in which case you should open the index.html file in your browser another way.\n"
  },
  {
    "path": "internationalization/elm.json",
    "content": "{\n    \"type\": \"application\",\n    \"source-directories\": [\n        \"src\"\n    ],\n    \"elm-version\": \"0.19.1\",\n    \"dependencies\": {\n        \"direct\": {\n            \"elm/browser\": \"1.0.2\",\n            \"elm/core\": \"1.0.5\",\n            \"elm/html\": \"1.0.0\",\n            \"elm/json\": \"1.1.3\"\n        },\n        \"indirect\": {\n            \"elm/time\": \"1.0.0\",\n            \"elm/url\": \"1.0.0\",\n            \"elm/virtual-dom\": \"1.0.2\"\n        }\n    },\n    \"test-dependencies\": {\n        \"direct\": {},\n        \"indirect\": {}\n    }\n}\n"
  },
  {
    "path": "internationalization/index.html",
    "content": "<!DOCTYPE HTML>\n<html>\n\n<head>\n  <meta charset=\"UTF-8\">\n  <title>Elm + Intl</title>\n  <script type=\"text/javascript\" src=\"elm.js\"></script>\n</head>\n\n<body>\n  <div id=\"myapp\"></div>\n</body>\n\n<script type=\"text/javascript\">\n\n// Create a function that that formats text as you need. Here we have\n// a function to localize dates:\n//\n//   localizeDate('sr-RS', 12, 5) == \"петак, 1. јун 2012.\"\n//   localizeDate('en-GB', 12, 5) == \"Friday, 1 June 2012\"\n//   localizeDate('en-US', 12, 5) == \"Friday, June 1, 2012\"\n//\nfunction localizeDate(lang, year, month)\n{\n\tconst dateTimeFormat = new Intl.DateTimeFormat(lang, {\n\t\tweekday: 'long',\n\t\tyear: 'numeric',\n\t\tmonth: 'long',\n\t\tday: 'numeric'\n\t});\n\n\treturn dateTimeFormat.format(new Date(year, month));\n}\n\n// Define a Custom Element that uses this function. Here we make it\n// possible to define nodes like this:\n//\n//     <intl-date lang=\"sr-RS\" year=\"2012\" month=\"5\">\n//     <intl-date lang=\"en-GB\" year=\"2012\" month=\"5\">\n//     <intl-date lang=\"en-US\" year=\"2012\" month=\"5\">\n//\n// Check out src/Main.elm to see how you use this on the Elm side.\n//\ncustomElements.define('intl-date',\n\tclass extends HTMLElement {\n\t\t// things required by Custom Elements\n\t\tconstructor() { super(); }\n\t\tconnectedCallback() { this.setTextContent(); }\n\t\tattributeChangedCallback() { this.setTextContent(); }\n\t\tstatic get observedAttributes() { return ['lang','year','month']; }\n\n\t\t// Our function to set the textContent based on attributes.\n\t\tsetTextContent()\n\t\t{\n\t\t\tconst lang = this.getAttribute('lang');\n\t\t\tconst year = this.getAttribute('year');\n\t\t\tconst month = this.getAttribute('month');\n\t\t\tthis.textContent = localizeDate(lang, year, month);\n\t\t}\n\t}\n);\n\n// Start the Elm application that uses the <intl-date> node.\n//\nvar app = Elm.Main.init({\n\tnode: document.getElementById('myapp')\n});\n\n</script>\n\n</html>\n"
  },
  {
    "path": "internationalization/src/Main.elm",
    "content": "module Main exposing (..)\n\nimport Browser\nimport Html exposing (..)\nimport Html.Attributes exposing (..)\nimport Html.Events exposing (..)\nimport Json.Decode as D\n\n\n\n-- MAIN\n\n\nmain : Program () Model Msg\nmain =\n  Browser.element\n    { init = init\n    , view = view\n    , update = update\n    , subscriptions = \\_ -> Sub.none\n    }\n\n\n\n-- MODEL\n\n\ntype alias Model =\n  { language : String\n  }\n\n\ninit : () -> ( Model, Cmd Msg )\ninit _ =\n  ( { language = \"sr-RS\" }\n  , Cmd.none\n  )\n\n\n\n-- UPDATE\n\n\ntype Msg\n  = LanguageChanged String\n\n\nupdate : Msg -> Model -> ( Model, Cmd Msg )\nupdate msg model =\n  case msg of\n    LanguageChanged language ->\n      ( { model | language = language }\n      , Cmd.none\n      )\n\n\n\n-- VIEW\n\n\nview : Model -> Html Msg\nview model =\n  div []\n    [ p [] [ viewDate model.language 2012 5 ]\n    , select\n        [ on \"change\" (D.map LanguageChanged valueDecoder)\n        ]\n        [ option [ value \"sr-RS\" ] [ text \"sr-RS\" ]\n        , option [ value \"en-GB\" ] [ text \"en-GB\" ]\n        , option [ value \"en-US\" ] [ text \"en-US\" ]\n        ]\n    ]\n\n\n-- Use the Custom Element defined in index.html\n--\nviewDate : String -> Int -> Int -> Html msg\nviewDate lang year month =\n  node \"intl-date\"\n    [ attribute \"lang\" lang\n    , attribute \"year\" (String.fromInt year)\n    , attribute \"month\" (String.fromInt month)\n    ]\n    []\n\n\nvalueDecoder : D.Decoder String\nvalueDecoder =\n  D.field \"currentTarget\" (D.field \"value\" D.string)\n"
  },
  {
    "path": "localStorage/README.md",
    "content": "# Local Storage - [Live Demo](https://ellie-app.com/8yYddD6HRYJa1)\n\nThis is a minimal example of how to use `localStorage` through ports.\n\nIt remembers user data across sessions. This data may be lost if the user clears their cookies, so it is safest to think of this as a **cache** rather than normal storage.\n\nAnyway, the important code lives in `src/Main.elm` and in `index.html` with comments!\n\n\n## Building Locally\n\nRun the following commands:\n\n```bash\ngit clone https://github.com/elm-community/js-integration-examples.git\ncd js-integration-examples/localStorage\n\nelm make src/Main.elm --output=elm.js\nopen index.html\n```\n\nSome terminals may not have an `open` command, in which case you should open the index.html file in your browser another way.\n"
  },
  {
    "path": "localStorage/elm.json",
    "content": "{\n    \"type\": \"application\",\n    \"source-directories\": [\n        \"src\"\n    ],\n    \"elm-version\": \"0.19.1\",\n    \"dependencies\": {\n        \"direct\": {\n            \"elm/browser\": \"1.0.2\",\n            \"elm/core\": \"1.0.5\",\n            \"elm/html\": \"1.0.0\",\n            \"elm/json\": \"1.1.3\"\n        },\n        \"indirect\": {\n            \"elm/time\": \"1.0.0\",\n            \"elm/url\": \"1.0.0\",\n            \"elm/virtual-dom\": \"1.0.2\"\n        }\n    },\n    \"test-dependencies\": {\n        \"direct\": {},\n        \"indirect\": {}\n    }\n}\n"
  },
  {
    "path": "localStorage/index.html",
    "content": "<!DOCTYPE HTML>\n<html>\n\n<head>\n  <meta charset=\"UTF-8\">\n  <title>Elm + localStorage</title>\n  <script type=\"text/javascript\" src=\"elm.js\"></script>\n</head>\n\n<body>\n  <div id=\"myapp\"></div>\n</body>\n\n<script type=\"text/javascript\">\n// Extract the stored data from previous sessions.\nvar storedData = localStorage.getItem('myapp-model');\nvar flags = storedData ? JSON.parse(storedData) : null;\n\n// Load the Elm app, passing in the stored data.\nvar app = Elm.Main.init({\n\tnode: document.getElementById('myapp'),\n\tflags: flags\n});\n\n// Listen for commands from the `setStorage` port.\n// Turn the data to a string and put it in localStorage.\napp.ports.setStorage.subscribe(function(state) {\n    localStorage.setItem('myapp-model', JSON.stringify(state));\n});\n</script>\n\n</html>\n"
  },
  {
    "path": "localStorage/src/Main.elm",
    "content": "port module Main exposing (..)\n\nimport Browser\nimport Html exposing (..)\nimport Html.Attributes exposing (..)\nimport Html.Events exposing (..)\nimport Json.Decode as D\nimport Json.Encode as E\n\n\n\n-- MAIN\n\n\nmain : Program E.Value Model Msg\nmain =\n  Browser.element\n    { init = init\n    , view = view\n    , update = updateWithStorage\n    , subscriptions = \\_ -> Sub.none\n    }\n\n\n\n-- MODEL\n\n\ntype alias Model =\n  { name : String\n  , email : String\n  }\n\n\n-- Here we use \"flags\" to load information in from localStorage. The\n-- data comes in as a JS value, so we define a `decoder` at the bottom\n-- of this file to turn it into an Elm value.\n--\n-- Check out index.html to see the corresponding code on the JS side.\n--\ninit : E.Value -> ( Model, Cmd Msg )\ninit flags =\n  (\n    case D.decodeValue decoder flags of\n      Ok model -> model\n      Err _ -> { name = \"\", email = \"\" }\n  ,\n    Cmd.none\n  )\n\n\n\n-- UPDATE\n\n\ntype Msg\n  = NameChanged String\n  | EmailChanged String\n\n\nupdate : Msg -> Model -> ( Model, Cmd Msg )\nupdate msg model =\n  case msg of\n    NameChanged name ->\n      ( { model | name = name }\n      , Cmd.none\n      )\n\n    EmailChanged email ->\n      ( { model | email = email }\n      , Cmd.none\n      )\n\n\n\n-- VIEW\n\n\nview : Model -> Html Msg\nview model =\n  div []\n    [ input\n        [ type_ \"text\"\n        , placeholder \"Name\"\n        , onInput NameChanged\n        , value model.name\n        ]\n        []\n    , input\n        [ type_ \"text\"\n        , placeholder \"Email\"\n        , onInput EmailChanged\n        , value model.email\n        ]\n        []\n    ]\n\n\n\n-- PORTS\n\n\nport setStorage : E.Value -> Cmd msg\n\n\n-- We want to `setStorage` on every update, so this function adds\n-- the setStorage command on each step of the update function.\n--\n-- Check out index.html to see how this is handled on the JS side.\n--\nupdateWithStorage : Msg -> Model -> ( Model, Cmd Msg )\nupdateWithStorage msg oldModel =\n  let\n    ( newModel, cmds ) = update msg oldModel\n  in\n  ( newModel\n  , Cmd.batch [ setStorage (encode newModel), cmds ]\n  )\n\n\n\n-- JSON ENCODE/DECODE\n\n\nencode : Model -> E.Value\nencode model =\n  E.object\n    [ (\"name\", E.string model.name)\n    , (\"email\", E.string model.email)\n    ]\n\n\ndecoder : D.Decoder Model\ndecoder =\n  D.map2 Model\n    (D.field \"name\" D.string)\n    (D.field \"email\" D.string)\n"
  },
  {
    "path": "more/README.md",
    "content": "# More JavaScript Integration Examples\n\nThis section provides more involved interop examples as well as tutorials around JavaScript usage in conjunction with Elm.\n\n* [Everything you need to know to use WebComponents in your Elm app](webcomponents/README.md)\n"
  },
  {
    "path": "more/webcomponents/README.md",
    "content": "# A Guide to Using Elm With Webcomponents\n\nThis document is meant to be a practical guide to the somewhat confusing [web components specs][wc-specs].\n\nMost documentation on web components show the spec and basic usage examples, assuming that you already know the intricate details of why specific parts of the spec exist in the first place and what use case they try to solve. This situation can be daunting even for experienced web developers and even more so for newcomers.\n\nWe try to be as concise as possible, while also providing enough information to get you up and running.\n\n## TL;DR\nIf you are looking for a quick start with Elm, Webcomponents and the setup of choice have a look at\n* [web components setup](#web-components-setup)\n* [the browser support section](#Browser-Support)\n* don't forget to check [the gotchas section](#Gotchas) to learn how to build Webcomponents that play nice with Elm.\n\n## Prerequisites\n\nFirst-off: if you haven't read [the official Elm guide][guide] you should do so before reading on, of particular note is [the interop section][guide-interop] as this is where the usage of [ports][guide-ports] and [custom elements][guide-custom-elements] is motivated.\n\nNow that you're up to date and positive that using web components is the way to solve the problem at hand we'll start off with a quick summary of what web components are, followed by a rundown of the parts of [the spec][wc-specs] you'll most likely interact with when using Elm.\n\nThe remainder of the guide is dedicated to getting your app ready for web components in all the browsers you want/need to support.\n\n## What are web components and what can I do with them?\n\nYou might have heard or read \"just use web components\" as an answer to the question how to integrate a particular JavaScript API or external library with Elm. \n\nTo quote the first paragraph on the [web components specs page][wc-specs]\n\n> These four specifications can __be used on their own__ but combined allow developers to define their own tags (custom element), whose styles are encapsulated and isolated (shadow dom), that can be restamped many times (template), and have a consistent way of being integrated into applications (es module).\n\nI've emphasized the most important information: in order to \"use web components\" you can and should actually pick and choose what part of the spec you need in order to solve your problem.\n\n* You don't need to use Shadow DOM, if you don't need style encapsulation.\n* You don't need to use HTML templates, if you already have a templating solution.\n* You don't need ES Modules, if you have a compile-to-js language like, say, *drumroll* Elm.\n\nYou may find yourself using all of these specs but they aren't usually necessary in conjuction with Elm. If you want to dive deeper into Webcomponents in plain JavaScript the [MDN page about Webcomponents][mdn-wc] is a good place to start.\n\n\n## Web Components Setup\n\nAt the time of writing this article you're probably using some form of build system for your JavaScript assets, by choice, custom or force. A detailed assessment of bundling modern web apps is outside the scope of this guide but you can check out [our minimal ES5 compatible setup](minimal-es5-setup.html) that provides the polyfills necessary to use web components with older browsers like Internet Explorer 11.\n\nThere is more information available in the [browser support section](#browser-support).\n\n\n## Custom Elements And Elm\n\nNote that if at this point you skipped the earlier requests to have a look at the [interop section of the Elm guide][guide-interop] it's a good idea to do so now. \n\nSo we've looked at [the specs][wc-specs] and the most relevant one to Elm is arguably [Custom Elements][wc-custom-elements]. Looking at the examples on that page, defining a custom element is easy enough.\n\n```javascript\nclass MyElement extends HTMLElement {}\ncustomElements.define(\"my-element\", MyElement);\n```\n\nThis defines a new HTML element `<my-element>`. Note that\n* the name *has* to include a hyphen and\n* the class *needs* to extend `HTMLElement`.\n\nThis is what custom elements are about: they let you build your own HTML elements with behavior tailored to your application that are indistinguishable from built-in elements like `<input>` or `<section>`. Which in turn means we can create these kind of elements within Elm without problems.\n\n```elm\nimport Html\n\nelement =\n    Html.node \"my-element\" [] [ Html.text \"Awesome!\" ]\n```\n\nLet's have a look at the anatomy of a custom element. Note that this only covers the part of the API that is most relevant to Elm, we provide links to associated concepts where appropriate.\n\n### Construction ([demo](https://ellie-app.com/8Vw6BbYYpc4a1))\n\nA custom element, just like any other built-in element, can be created declaratively using HTML or imperatively using JavaScript.\n\n```javascript\ncustomElements.define(\"my-element\", class extends HTMLElement {});\n\nconst element = document.createElement(\"my-element\");\n```\n```html\n<!-- Note that custom elements can not be self-closing -->\n<my-element></my-element>\n```\n```elm\nimport Html\n\nmyElement =\n    Html.node \"my-element\" [] []\n```\n\n### Lifecycles ([demo](https://ellie-app.com/8Vw7J3nFNNma1))\n\nThere are lifecycles you can attach clunkily-named callbacks to.\n\n```javascript\ncustomElements.define(\"i-support-lifecycles\", class extends HTMLElement {\n    constructor() {\n        super();\n        // This <i-support-lifecycles> is being initialized, it's not been\n        // added to any document yet but you can initialize your fields but\n        // don't temper with the DOM just yet, do that in `connectedCallback`\n    }\n    adoptedCallback() {\n        // This <i-support-lifecycles> has been moved to a different document\n    }\n    connectedCallback() {\n        // This <i-support-lifecycles> has been added to the DOM\n    }\n    disconnectedCallback() {\n        // This <i-support-lifecycles> has been removed from the DOM\n    }\n});\n```\n\n### Attributes ([demo](https://ellie-app.com/8Vwfz6c5v2wa1))\n\nCustom elements may declare supported attributes via `observedAttributes` - only attribute names returned from this trigger the `attributeChangedCallback` when changed. Note that attributes can only carry `string` values.\n\nThere's also a [discussion on whether to use an attribute or a property](#attributes-vs-properties), if you're not sure which to use.\n\n```javascript\ncustomElements.define(\"twbs-alert\", class extends HTMLElement {\n    static get observedAttributes() {\n        // We need to declare which attributes should be observed,\n        // only these trigger the `attributeChangedCallback`\n        return ['type'];\n    }\n    connectedCallback() {\n        this.classList.add('alert');\n    }\n    attributeChangedCallback(name, oldValue, newValue) {\n        switch (name) {\n            case 'type':\n                this.classList.remove(`alert-${oldValue}`);\n                this.classList.add(`alert-${newValue}`);\n                break;\n        }\n    }\n});\n\nconst element = document.createElement(\"twbs-alert\");\nelement.setAttribute(\"type\", \"info\");\n```\n```html\n<twbs-alert type=\"info\"></twbs-alert>\n```\n```elm\nimport Html\nimport Html.Attributes\n\nalert =\n    Html.node \"twbs-alert\"\n        [ Html.Attributes.attribute \"type\" \"info\"\n        -- or alternatively Html.Attributes.type_ \"info\"\n        ]\n        [ Html.text \"This is a Twitter Bootstrap info box\"\n        ]\n```\n\nIf you need to transfer object data you can use a [property](#Properties).\n\n### Properties ([demo](https://ellie-app.com/8VwjNrnhyKKa1))\n\nCustom elements can declare properties via `get` and `set`, most kinds of JavaScript objects are supported.\n\nThere's also a [discussion on whether to use an attribute or a property](#attributes-vs-properties), if you're not sure which to use.\n\n```javascript\ncustomElements.define(\"atla-trivia\", class extends HTMLElement {\n    constructor() {\n        super();\n        this._meta = null;\n    }\n    set meta(value) {\n        this._meta = value;\n    }\n    get meta() {\n        return this._meta;\n    }\n});\n\nconst element = document.createElement(\"atla-trivia\");\nelement.meta = {\n    teamAvatar: [\"Aang\", \"Katara\", \"Soka\"],\n    seasons: 3,\n};\n```\n```html\n<!-- You can't set properties directly in raw HTML, sorry -->\n```\n\nWith Elm you need to use a JSON encoder provided by the [`elm/json`][elmpkg-elm-json] package.\n\n```elm\nimport Html\nimport Html.Attributes\nimport Json.Encode -- elm install elm/json\n\ntrivia =\n    Html.node \"atla-trivia\"\n        [ Html.Attributes.property \"meta\"\n            (Json.Encode.object\n                [ ( \"teamAvatar\"\n                  , Json.Encode.list Json.Encode.string\n                    [ \"Aang\"\n                    , \"Katara\"\n                    , \"Soka\"\n                    ]\n                  )\n                , ( \"seasons\", Json.Encode.int 3 )\n                ]\n            )\n        ]\n        []\n```\n\n### Attributes vs Properties\nFor Elm projects a good rule of thumb is\n\n> Use properties unless you want your custom elements to be used from hand-written or server-rendered HTML.\n\nThe reasoning being\n* You're interacting with your custom element via JavaScript anyways, so the fact that properties can not be set from raw HTML is usually not an issue\n* You can transfer structured data via properties, not just strings\n* It's easier to use a consistent interaction method with custom elements from Elm - just use `Html.Attributes.property` everywhere\n\nOn the other hand writing custom elements using only attributes might be more suitable for your use case as they can easily be included in static HTML, hand-written or produced by server-side-rendering.\n\n\n### Children ([demo](https://ellie-app.com/8VwmHKFMYCqa1))\nAs we've noted a number of times: custom elements are just like regular HTML elements, this includes the ability to be a root node for a sub-tree, your custom element can have child nodes.\n\n```javascript\ncustomElements.define(\"tree-root\", class extends HTMLElement {});\n\nconst root = document.createElement(\"tree-root\");\nconst span = document.createElement(\"span\");\nspan.innerText = \"A span\";\nconst div = document.createElement(\"div\");\ndiv.innerText = \"A div\";\nconst plainText = document.createTextNode(\"Plain text\");\n\nroot.appendChild(span);\nroot.appendChild(div);\nroot.appendChild(plainText);\n```\n```html\n<tree-root>\n    <span>A span</span>\n    <div>A div</div>\n    Plain text\n</tree-root>\n```\n\nThis is equivalent to the following Elm code. Be sure to read up on [the gotchas](#Gotchas) due to Elm's virtual DOM, though.\n\n```elm\nimport Html\n\nsubTree =\n    Html.node \"tree-root\" []\n        [ Html.span [] [ Html.text \"A span\" ]\n        , Html.div [] [ Html.text \"A div\" ]\n        , Html.text \"Plain Text\"\n        ]\n```\n\n### Listening to Events ([demo](https://ellie-app.com/8Vwpg8T5GDQa1))\nCustom elements support listening to events; this is usually not that useful in conjunction with Elm since you can't imperatively trigger events with it. However, it allows you to employ some nifty tricks like [event delegation][jq-event-delegation] where you use the [DOM's event bubbling phase][mdn-event-bubbling] to listen for events that \"bubble up\" from your custom element's children.\n\n```javascript\ncustomElements.define(\"event-delegator\", class extends HTMLElement {\n    _handleInnerClick(evt) {\n        evt.preventDefault();\n        evt.stopPropagation();\n        alert(`You clicked inside of me`);\n    }\n    connectedCallback() {\n        this.addEventListener(\"click\", this._handleInnerClick)\n    }\n    disconnectedCallback() {\n        this.removeEventListener(\"click\", this._handleInnerClick)\n    }\n});\n\nconst element = document.createElement(\"event-delegator\");\nconst button = document.createElement(\"button\");\nbutton.innerHTML = \"Click Me!\";\n\nelement.appendChild(button);\ndocument.body.appendChild(element);\n```\n```html\n<event-delegator>\n    <button>Click Me!</button>\n</event-delegator>\n```\n\nAs we've seen in [the Children section](#Children) building DOM trees with Elm is a breeze. In this example we see both the power and the potential problems with using custom elements in Elm, they allow you to execute arbitrary JavaScript inside your declarative views. So be aware of the fact that a rogue custom element can compromise Elm's runtime guarantees, have a look at [the Gotchas section](#Gotchas) to learn more.\n\n```elm\nimport Html\n\nroot =\n    Html.node \"event-delegator\" []\n        [ Html.button [ {- no `onClick` here -} ]\n            [ Html.text \"Click Me!\"\n            ]\n        ]\n```\n\n\n### Triggering Events ([demo](https://ellie-app.com/8VvL6ggT5qJa1))\n\nCustom elements [can listen to events](#Listening-to-Events) but they become really useful as soon as they're triggering events themselves. You mainly want to use this as an adapter to give Elm access to [Web APIs][html5-apis] it does not yet support in form of a core package or to embed functionality from external JavaScript libraries.\n\nTo demonstrate this we build a slightly more involved custom element `<copy-to-clipboard>` that lets the user copy text from an Elm app via button click using the [Document.execCommand API][doc-exec-command]. This is a fairly old non-standard API that's widely supported, nonetheless. The [Clipboard API][mdn-clipboard] is the modern successor, in case you don't need support for older browsers.\n\nThe gist is that our element listens for `click` events from its children, copies the value of its `text` attribute to the clipboard and triggers a [`CustomEvent`][mdn-customevent] notifying Elm that the operation has been successful, Elm can also decode event data being passed.\n\n```javascript\ncustomElements.define(\"copy-to-clipboard\", class extends HTMLElement {\n    static get observedAttributes() {\n        return [\"text\"];\n    }\n    _handleClick(evt) {\n        evt.preventDefault();\n        evt.stopPropagation();\n        const text = this.getAttribute(\"text\");\n        this._copy(text);\n        this.dispatchEvent(new CustomEvent(\"clipboard\", {\n            bubbles: true,\n            cancelable: true,\n            detail: {\n                copiedText: text,\n            },\n        }));\n    }\n    _copy(value) {\n        const preSelected =            \n            document.getSelection().rangeCount > 0\n                ? document.getSelection().getRangeAt(0)\n                : false;\n\n        const textarea = document.createElement('textarea');\n        textarea.setAttribute('readonly', '');\n        textarea.style.position = 'absolute';\n        textarea.style.left = '-9999px';\n        textarea.value = value;\n        document.body.appendChild(textarea);\n      \n        textarea.select();\n        document.execCommand('copy');\n        document.body.removeChild(textarea);\n        if (preSelected) {\n            document.getSelection().removeAllRanges();\n            document.getSelection().addRange(preSelected);\n        }\n    }\n    connectedCallback() {\n        this.addEventListener(\"click\", this._handleClick);\n    }\n    disconnectedCallback() {\n        this.removeEventListener(\"click\", this._handleClick);\n    }\n});\n```\n```elm\nmodule Main exposing (main)\n\nimport Browser\nimport Html exposing (Html)\nimport Html.Attributes\nimport Html.Events\nimport Json.Decode exposing (Decoder)\n\n\ntype Msg\n    = CopiedToClipboard String\n\n\ntype alias Model =\n    { copied : Maybe String\n    }\n\n\nclipboardEventDecoder : (String -> msg) -> Decoder msg\nclipboardEventDecoder toMsg =\n    Json.Decode.map (\\copiedTextFromDetail -> toMsg copiedTextFromDetail)\n        (Json.Decode.at [ \"detail\", \"copiedText\" ] Json.Decode.string)\n\n\nview : Model -> Html Msg\nview { copied } =\n    let\n        textToCopy =\n            \"Text from Elm\"\n    in\n    Html.div []\n        [ Html.node \"copy-to-clipboard\"\n            [ Html.Attributes.attribute \"text\" textToCopy\n            , Html.Events.on \"clipboard\" (clipboardEventDecoder CopiedToClipboard)\n            ]\n            [ Html.button []\n                [ Html.text \"Copy \"\n                , Html.text (\"\\\"\" ++ textToCopy ++ \"\\\"\")\n                , Html.text \" to clipboard\"\n                ]\n            ]\n        , case copied of\n            Just _ ->\n                Html.div []\n                    [ Html.div [] [ Html.text \"Copied!\" ]\n                    , Html.textarea\n                        [ Html.Attributes.placeholder \"Try pasting it in here\"\n                        ]\n                        []\n                    ]\n\n            Nothing ->\n                Html.text \"\"\n        ]\n\n\nupdate : Msg -> Model -> Model\nupdate (CopiedToClipboard text) model =\n    { model | copied = Just text }\n\n\nmain : Program () Model Msg\nmain =\n    Browser.sandbox\n        { init = { copied = Nothing }\n        , update = update\n        , view = view\n        }\n\n```\n\n_Note that Internet Explorer needs [a polyfill for CustomEvent][mdn-customevent-polyfill]._\n\nMany Elm apps use this technique to embed libraries like [CodeMirror](https://github.com/ellie-app/ellie/blob/a45637b81e2495ffada12f9a75dd6bb547a69226/assets/src/Ellie/Ui/CodeEditor.js) or [Google Maps](https://package.elm-lang.org/packages/PaackEng/elm-google-maps/latest/).\n\nUntil now all seems hunky-dory in the world of custom elements being embedded with Elm but there are some [gotchas](#Gotchas) you need to be aware of. We'll take a look at these in the next section.\n\n\n## Gotchas\n\nThere are some things to keep in mind when employing custom elements in your Elm app.\n\n### Web Components And Virtual DOM\n\nElm takes full control of the part of the DOM it manages. Like other virtual-dom based libraries it keeps track of the current state of the DOM in the form of an in-memory representation of the tree and assumes that what is currently rendered in the real DOM is a pure derivative from this in-memory representation.\n\nSome libraries are more forgiving than others with unexpected mutations but if you mess with those nodes too much you risk breaking their invariants, which in turn will cause runtime exceptions, even in Elm. What that means in practice is that you should adhere to the following rules for your custom elements to play nice with virtual-dom libraries in general.\n\n* 1) Make sure your custom element cleans up after itself via `disconnectedCallback` as Elm may decide to re-create any part of the DOM without notice.\n* 2) This also means that you should not rely on Elm creating your custom element node exactly x amount of times.\n* 3) If your custom element is supposed to receive child nodes from the outside like [in our little event delegation example](#Listening-to-Events) make sure not to add or remove any children as this may confuse Elm's virtual-dom.\n* 4) If your custom element doesn't expect children from the outside you are free to manage the element's child nodes.\n* 5) If you need both external and self-managed children you can \"hide\" them inside a [Shadow Root][mdn-shadow-dom], Elm won't inspect sub-trees of shadow roots. Note that there are polyfills for the Shadow DOM spec out there that work in older browsers but this API is farely involved so these might slow down the browser significantly and/or have unexpected behavior.\n\n### Customized Built-ins\n\nThe [spec][wc-specs] mentions that you can [extend built-in elements][mdn-customized-builtins], e.g. to make your own `<button>`. [Elm's virtual dom does not support creating these kind of elements](https://github.com/elm/virtual-dom/issues/156). [This guide has a small example](#modern-environments-vs-the-spec) but note that this feature is not widely supported by browsers and it's probably best to avoid it altogether.\n\n\nAnd while we're talking about gotchas...\n\n\n## Browser Support\n\nLooking at our basic example snippets you may have a very valid question. ([demo](https://ellie-app.com/8Vw6BbYYpc4a1))\n\n```javascript\nclass MyElement extends HTMLElement {}\ncustomElements.define(\"my-element\", MyElement);\n```\n\n```elm\nimport Html\n\nmyElement =\n    Html.node \"my-element\" [] [ Html.text \"Awesome!\" ]\n```\n\n> If that's all there is to it why do I even read this guide?\n\nGlad you asked! As is usually the case, there's more than meets the eye.\n\n\n### Older Environments\n\nOur custom element seems to work... until we try to use our `<my-element>` component in Internet Explorer, some ancient mobile browser, a webview - `SyntaxError` or maybe `\"customElements\" is not defined`. Off to the \"browser support\" page; [looks very green and ready for showbiz][wc-home] but we remember [the word \"polyfill\"][wc-polyfills] so that is what catches our eye.\n\nThe gist is that not every browser supports web components out-of-the-box and some implementations are buggy so you need to include a sort-of base library. After we've included [the custom elements polyfill][wc-polyfill-custom-elements] our code agrees to run inside mobile browsers (and webviews?) but Internet Explorer is relentless, as always - `SyntaxError` is the bane of our existence.\n\nIt turns out that Internet Explorer doesn't support the `class` syntax introduced in ES6. Because we know that `class` syntax is actually just syntactic sugar for constructor functions and prototype chaining we begrudgingly rewrite our example component.\n\n```javascript\nfunction MyElement() {}\nMyElement.prototype = Object.create(HTMLElement.prototype);\ncustomElements.define(\"my-element\", MyElement);\n```\n\nInternet Explorer still complains `the custom element constructor did not produce the element being upgraded`, odd. After more research we [come across the magic incantation][so-custom-elements] that makes our component appear in all browsers. Note that the polyfill detects modern browsers automatically now so we at least don't need to [patch the native implementation manually to work with ES5 style classes][wc-polyfill-custom-elements-es5].\n\nThis means that per spec native custom element implementations only work with ES6 classes, keep that in mind!\n\n```html\n<!-- We also need a polyfill for `Reflect` -->\n<script src=\"https://unpkg.com/es6-shim@0.35.5/es6-shim.min.js\"></script>\n<script src=\"https://unpkg.com/@webcomponents/custom-elements\"></script>\n```\n\n```javascript\nfunction MyElement() {\n    return Reflect.construct(HTMLElement, [], this.constructor);\n}\nMyElement.prototype = Object.create(HTMLElement.prototype);\nMyElement.prototype.constructor = MyElement;\nMyElement.prototype.connectedCallback = function () {\n    this.appendChild(document.createTextNode(\"Water!\"));\n};\nObject.setPrototypeOf(MyElement, HTMLElement);\n\ncustomElements.define(\"my-element\", MyElement);\n```\n\nHave a look at the [minimal example setup that works in ECMAScript 5 compliant browsers](minimal-es5-setup.html).\n\nFor cross-browser support you'll need a polyfill for old browsers *and* modern browsers! \n\nAnd that's not even the whole story. There are other approaches like serving different bundles to different browsers like [Angular 8+ differential loading][ng-differential-loading] does. Which also has problems, having two different code base versions of your app run in older and newer browsers respectively can lead to bugs that are very hard track down.\n\n[ng-differential-loading]: https://blog.angular.io/version-8-of-angular-smaller-bundles-cli-apis-and-alignment-with-the-ecosystem-af0261112a27 \n[so-custom-elements]: https://stackoverflow.com/questions/50295703/create-custom-elements-v1-in-es5-not-es6 \n\n\n### Modern Environments vs the Spec\n\nYou may think that targeting only modern browsers frees you from all the hassle. Let's take a look at [the other example][wc-custom-elements] on the web components page.\n\n```javascript\nclass CustomizedButton extends HTMLButtonElement {\n    connectedCallback() {\n        this.style.backgroundColor = \"orange\";\n    }\n}\ncustomElements.define(\"customized-button\", CustomizedButton, { extends: \"button\" });\n```\n```html\n<button is=\"customized-button\">Customized!</button>\n```\n\nIf we open this in Chrome our button is indeed a button with an orange background. Safari does not concur, neither does pre-Chromium Microsoft Edge nor [any Webkit based browser possibly forever][webkit-nope] which includes the iOS browser. `Customized built-in` s as they're called are part of the spec but a non-significant amount of browsers doesn't and probably won't support them anytime soon.\n\nAlthough there is [a polyfill][customized-polyfill] it's probably best to ignore that part of the spec, it's not safe to use as [is documented in this w3c issue][w3c-nope] and layering polyfills upon polyfills onto each other might have consequences.\n\nAlso note that Elm's virtual-dom does not support creating these customized built-ins, see the [gotchas section](#gotchas) for more information.\n\n[customized-polyfill]: https://github.com/ungap/custom-elements-builtin \n[webkit-nope]: https://bugs.webkit.org/show_bug.cgi?id=182671 \n[w3c-nope]: https://github.com/w3c/webcomponents/issues/509 \n\n\n## Conclusion\n\nIn this guide we've discussed the impetus of why webcomponents exist in the first place and what parts of the spec are particularly relevant when working with Elm.\n\nWe've investigated a number usecases with demos where custom elements come in handy to enhance Elm's vocabulary in terms of not yet natively supported web APIs and interop scenarios with external JavaScript libraries.\n\nI hope you now have a fair grasp on these topics so you can confidently incorporate custom elements in your Elm workflow when needed.\n\n\n## Further Reading\n\n* [Mozilla Developer Network Article on Webcomponents][mdn-wc]\n* [https://webcomponents.org][wc-home]\n* [Alex Korban's A Straight Forwared Introduction to Custom Elements](https://korban.net/posts/elm/2018-09-17-introduction-custom-elements-shadow-dom/)\n* [All the Ways To Make a Web Component](https://webcomponents.dev/blog/all-the-ways-to-make-a-web-component/)\n\n\n[doc-exec-command]: https://developer.mozilla.org/en-US/docs/Web/API/Document/execCommand \n[elmpkg-elm-json]: https://package.elm-lang.org/packages/elm/json/latest\n[jq-event-delegation]: https://learn.jquery.com/events/event-delegation/ \n[guide]: https://guide.elm-lang.org\n[guide-interop]: https://guide.elm-lang.org/interop/\n[guide-ports]: https://guide.elm-lang.org/interop/ports.html \n[guide-custom-elements]:https://guide.elm-lang.org/interop/custom_elements.html \n[html5-apis]: https://developer.mozilla.org/en-US/docs/Web/API \n[mdn-clipboard]: https://developer.mozilla.org/en-US/docs/Web/API/Clipboard_API \n[mdn-customevent]: https://developer.mozilla.org/en-US/docs/Web/API/CustomEvent/CustomEvent\n[mdn-customevent-polyfill]: https://developer.mozilla.org/en-US/docs/Web/API/CustomEvent/CustomEvent#Polyfill\n[mdn-customized-builtins]:https://developer.mozilla.org/en-US/docs/Web/Web_Components/Using_custom_elements#Customized_built-in_elements\n[mdn-event-bubbling]: https://developer.mozilla.org/en-US/docs/Learn/JavaScript/Building_blocks/Events#Event_bubbling_and_capture \n[mdn-shadow-dom]: https://developer.mozilla.org/en-US/docs/Web/Web_Components/Using_shadow_DOM\n[mdn-slot]: https://developer.mozilla.org/en-US/docs/Web/HTML/Element/slot \n[mdn-wc]: https://developer.mozilla.org/en-US/docs/Web/Web_Components \n[w3c]: https://www.w3.org/ \n[wc-custom-elements]:https://www.webcomponents.org/specs#the-custom-elements-specification \n[wc-home]: https://www.webcomponents.org/\n[wc-polyfills]: https://www.webcomponents.org/polyfills \n[wc-polyfill-custom-elements]: https://github.com/webcomponents/polyfills/tree/master/packages/custom-elements\n[wc-polyfill-custom-elements-es5]: https://github.com/webcomponents/polyfills/tree/master/packages/custom-elements#es5-vs-es2015 \n[wc-specs]: https://www.webcomponents.org/specs\n"
  },
  {
    "path": "more/webcomponents/minimal-es5-setup.html",
    "content": "<!DOCTYPE html>\r\n<html lang=\"en\">\r\n\r\n<head>\r\n    <meta charset=\"utf-8\">\r\n    <title>Web components example</title>\r\n</head>\r\n\r\n<body>\r\n    <script src=\"https://unpkg.com/es6-shim@0.35.5/es6-shim.min.js\"></script>\r\n    <script src=\"https://unpkg.com/@webcomponents/custom-elements\"></script>\r\n    <script>\r\n\r\n        // Works in IE11+\r\n        function LegacyElement() {\r\n            return Reflect.construct(HTMLElement, [], this.constructor);\r\n        }\r\n        LegacyElement.prototype = Object.create(HTMLElement.prototype);\r\n        LegacyElement.prototype.constructor = LegacyElement;\r\n        LegacyElement.prototype.connectedCallback = function () {\r\n            this.appendChild(document.createTextNode(\"A little rusty!\"));\r\n        };\r\n        Object.setPrototypeOf(LegacyElement, HTMLElement);\r\n\r\n        customElements.define(\"legacy-element\", LegacyElement);\r\n\r\n    </script>\r\n    <script type=\"module\">\r\n\r\n        // Only for modern browsers\r\n        customElements.define(\"modern-element\", class extends HTMLElement {\r\n            connectedCallback() {\r\n                this.appendChild(document.createTextNode(\"Shiny!\"));\r\n            }\r\n        });\r\n\r\n    </script>\r\n    <!-- Note that custom elements can not be self-closing -->\r\n    <legacy-element></legacy-element>\r\n    <modern-element></modern-element>\r\n</body>\r\n\r\n</html>\r\n"
  },
  {
    "path": "websockets/README.md",
    "content": "# WebSockets - [Live Demo](https://ellie-app.com/8yYgw7y7sM2a1)\n\nThis is a minimal example of how to connect to a WebSocket. It connects to `wss://echo.websocket.org` which just repeats whatever you say.\n\n![Demo](demo.gif)\n\nThe important code lives in `src/Main.elm` and in `index.html` with comments!\n\n\n## Building Locally\n\nRun the following commands:\n\n```bash\ngit clone https://github.com/elm-community/js-integration-examples.git\ncd js-integration-examples/websockets\n\nelm make src/Main.elm --output=elm.js\nopen index.html\n```\n\nSome terminals may not have an `open` command, in which case you should open the index.html file in your browser another way.\n"
  },
  {
    "path": "websockets/elm.json",
    "content": "{\n    \"type\": \"application\",\n    \"source-directories\": [\n        \"src\"\n    ],\n    \"elm-version\": \"0.19.1\",\n    \"dependencies\": {\n        \"direct\": {\n            \"elm/browser\": \"1.0.2\",\n            \"elm/core\": \"1.0.5\",\n            \"elm/html\": \"1.0.0\",\n            \"elm/json\": \"1.1.3\"\n        },\n        \"indirect\": {\n            \"elm/time\": \"1.0.0\",\n            \"elm/url\": \"1.0.0\",\n            \"elm/virtual-dom\": \"1.0.2\"\n        }\n    },\n    \"test-dependencies\": {\n        \"direct\": {},\n        \"indirect\": {}\n    }\n}\n"
  },
  {
    "path": "websockets/index.html",
    "content": "<!DOCTYPE HTML>\n<html>\n\n<head>\n  <meta charset=\"UTF-8\">\n  <title>Elm + Websockets</title>\n  <script type=\"text/javascript\" src=\"elm.js\"></script>\n</head>\n\n<body>\n\t<div id=\"myapp\"></div>\n</body>\n\n<script type=\"text/javascript\">\n\n// Start the Elm application.\nvar app = Elm.Main.init({\n\tnode: document.getElementById('myapp')\n});\n\n// Create your WebSocket.\nvar socket = new WebSocket('wss://echo.websocket.org');\n\n// When a command goes to the `sendMessage` port, we pass the message\n// along to the WebSocket.\napp.ports.sendMessage.subscribe(function(message) {\n    socket.send(message);\n});\n\n// When a message comes into our WebSocket, we pass the message along\n// to the `messageReceiver` port.\nsocket.addEventListener(\"message\", function(event) {\n\tapp.ports.messageReceiver.send(event.data);\n});\n\n// If you want to use a JavaScript library to manage your WebSocket\n// connection, replace the code in JS with the alternate implementation.\n</script>\n\n</html>\n"
  },
  {
    "path": "websockets/src/Main.elm",
    "content": "port module Main exposing (..)\n\nimport Browser\nimport Html exposing (..)\nimport Html.Attributes exposing (..)\nimport Html.Events exposing (..)\nimport Json.Decode as D\n\n\n\n-- MAIN\n\n\nmain : Program () Model Msg\nmain =\n  Browser.element\n    { init = init\n    , view = view\n    , update = update\n    , subscriptions = subscriptions\n    }\n\n\n\n\n-- PORTS\n\n\nport sendMessage : String -> Cmd msg\nport messageReceiver : (String -> msg) -> Sub msg\n\n\n\n-- MODEL\n\n\ntype alias Model =\n  { draft : String\n  , messages : List String\n  }\n\n\ninit : () -> ( Model, Cmd Msg )\ninit flags =\n  ( { draft = \"\", messages = [] }\n  , Cmd.none\n  )\n\n\n\n-- UPDATE\n\n\ntype Msg\n  = DraftChanged String\n  | Send\n  | Recv String\n\n\n-- Use the `sendMessage` port when someone presses ENTER or clicks\n-- the \"Send\" button. Check out index.html to see the corresponding\n-- JS where this is piped into a WebSocket.\n--\nupdate : Msg -> Model -> ( Model, Cmd Msg )\nupdate msg model =\n  case msg of\n    DraftChanged draft ->\n      ( { model | draft = draft }\n      , Cmd.none\n      )\n\n    Send ->\n      ( { model | draft = \"\" }\n      , sendMessage model.draft\n      )\n\n    Recv message ->\n      ( { model | messages = model.messages ++ [message] }\n      , Cmd.none\n      )\n\n\n\n-- SUBSCRIPTIONS\n\n\n-- Subscribe to the `messageReceiver` port to hear about messages coming in\n-- from JS. Check out the index.html file to see how this is hooked up to a\n-- WebSocket.\n--\nsubscriptions : Model -> Sub Msg\nsubscriptions _ =\n  messageReceiver Recv\n\n\n\n-- VIEW\n\n\nview : Model -> Html Msg\nview model =\n  div []\n    [ h1 [] [ text \"Echo Chat\" ]\n    , ul []\n        (List.map (\\msg -> li [] [ text msg ]) model.messages)\n    , input\n        [ type_ \"text\"\n        , placeholder \"Draft\"\n        , onInput DraftChanged\n        , on \"keydown\" (ifIsEnter Send)\n        , value model.draft\n        ]\n        []\n    , button [ onClick Send ] [ text \"Send\" ]\n    ]\n\n\n\n-- DETECT ENTER\n\n\nifIsEnter : msg -> D.Decoder msg\nifIsEnter msg =\n  D.field \"key\" D.string\n    |> D.andThen (\\key -> if key == \"Enter\" then D.succeed msg else D.fail \"some other key\")\n"
  }
]