├── .gitignore ├── modd.conf ├── src ├── JsonDateDecode.elm ├── Native │ └── JsonDateDecode.js └── Main.elm ├── bower.json ├── elm-package.json ├── index.html ├── Makefile ├── LICENSE.md └── README.md /.gitignore: -------------------------------------------------------------------------------- 1 | bower_components 2 | dist 3 | elm-stuff 4 | elm.js 5 | pages 6 | -------------------------------------------------------------------------------- /modd.conf: -------------------------------------------------------------------------------- 1 | src/*.elm src/Native/*.js { 2 | prep: make 3 | } 4 | 5 | elm.js index.html { 6 | daemon: devd -oL . 7 | } 8 | 9 | -------------------------------------------------------------------------------- /src/JsonDateDecode.elm: -------------------------------------------------------------------------------- 1 | module JsonDateDecode exposing (toDate, toJson) 2 | 3 | import Date exposing (Date) 4 | import Json.Decode 5 | import Native.JsonDateDecode 6 | 7 | 8 | {-| Try to interpret a Json.Decode.Value as a Date. Json.Decode does not provide 9 | for this so we roll our own. 10 | -} 11 | toDate : Json.Decode.Value -> Result String Date 12 | toDate = 13 | Native.JsonDateDecode.toDate 14 | 15 | toJson : Date -> String 16 | toJson = 17 | Native.JsonDateDecode.toJson 18 | 19 | -------------------------------------------------------------------------------- /src/Native/JsonDateDecode.js: -------------------------------------------------------------------------------- 1 | var _user$project$Native_JsonDateDecode = function() { 2 | function toDate(value) { 3 | if (value instanceof Date) { 4 | return _elm_lang$core$Result$Ok(value); 5 | } else { 6 | return _elm_lang$core$Result$Err("not a date value"); 7 | } 8 | } 9 | 10 | function toJson(date) { 11 | return date.toJSON(); 12 | } 13 | 14 | return { 15 | toDate: toDate, 16 | toJson: toJson, 17 | } 18 | }(); 19 | -------------------------------------------------------------------------------- /bower.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "elm-polymer-calendar", 3 | "homepage": "https://github.com/fredcy/elm-polymer-calendar", 4 | "authors": [ 5 | "Fred Yankowski " 6 | ], 7 | "description": "Using a Polymer component with Elm", 8 | "main": "index.html", 9 | "license": "MIT", 10 | "ignore": [ 11 | "**/.*", 12 | "node_modules", 13 | "bower_components", 14 | "test", 15 | "tests" 16 | ], 17 | "dependencies": { 18 | "paper-date-picker": "polymer-paper-datepicker#^1.2.0" 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /elm-package.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": "1.0.0", 3 | "summary": "helpful summary of your project, less than 80 characters", 4 | "repository": "https://github.com/user/project.git", 5 | "license": "BSD3", 6 | "source-directories": [ 7 | "src" 8 | ], 9 | "native-modules": true, 10 | "exposed-modules": [], 11 | "dependencies": { 12 | "elm-lang/core": "4.0.5 <= v < 5.0.0", 13 | "elm-lang/html": "1.1.0 <= v < 2.0.0", 14 | "mgold/elm-date-format": "1.1.5 <= v < 2.0.0" 15 | }, 16 | "elm-version": "0.17.1 <= v < 0.18.0" 17 | } 18 | -------------------------------------------------------------------------------- /index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Elm • Polymer 6 | 7 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 20 | 21 | 22 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | default: build 2 | 3 | setup: 4 | bower install 5 | 6 | build: elm.js 7 | 8 | elm.js: src/Main.elm src/JsonDateDecode.elm src/Native/JsonDateDecode.js 9 | elm make src/Main.elm --yes --output=elm.js 10 | 11 | DISTDIR = pages 12 | 13 | dist: 14 | -@mkdir $(DISTDIR) 15 | vulcanize index.html -o $(DISTDIR)/index.html 16 | cp elm.js $(DISTDIR) 17 | # copy over dependencies that vulcanize misses 18 | rsync -R bower_components/moment/min/moment.min.js $(DISTDIR) 19 | rsync -R bower_components/moment/min/moment-with-locales.min.js $(DISTDIR) 20 | rsync -R bower_components/web-animations-js/web-animations-next-lite.min.js $(DISTDIR) 21 | rsync -R bower_components/webcomponentsjs/webcomponents-lite.min.js $(DISTDIR) 22 | rsync -R bower_components/web-animations-js/web-animations-next-lite.min.js.map $(DISTDIR) 23 | 24 | before-dist: 25 | git clone -b gh-pages git@github.com:fredcy/elm-polymer-calendar.git $(DISTDIR) 26 | cd $(DISTDIR) && git rm -rf . 27 | 28 | after-dist: 29 | cd $(DISTDIR) && git add . && git commit -m 'rebuild pages' && git push 30 | -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2016 Fred Yankowski 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # elm-polymer-calendar 2 | 3 | This demonstrates how to incorporate a Polymer web component into an Elm application. 4 | In particular, it uses a `polymer-paper-date-picker` component from https://github.com/bendavis78/paper-date-picker to present a calendar and update the Elm model based on the user's choices of calendar date. 5 | 6 | ## Toolchain setup 7 | 8 | ``` 9 | npm install -g elm 10 | npm install -g bower 11 | npm install -g vulcanize 12 | ``` 13 | 14 | ## Installation 15 | 16 | ```shell 17 | git clone git@github.com:fredcy/elm-polymer-calendar.git 18 | cd elm-polymer-calendar 19 | bower install 20 | make 21 | ``` 22 | 23 | ## Serving 24 | ``` 25 | cd elm-polymer-calendar 26 | python3 -m http.server 27 | ``` 28 | 29 | Browse http://localhost:8000/ 30 | 31 | ## Discussion 32 | 33 | The calendar component generates a JS `date-changed` event each time the user selects a date. 34 | The `onValueChanged` function in Main.elm sets up an Elm Html event attribute that ultimately creates a `DateChanged` message. 35 | The Elm Json.Decode functions do not provide a way to decode the JS `Date` value in that event, 36 | so the message carries the value as a Json.Decode.Value which is later converted to an Elm `Date` value via custom native code in `JsonDateDecode.toDate`. 37 | 38 | Running `make dist` will generate a "dist" directory with the minimal static web content needed to deploy the application. 39 | 40 | ## Credit 41 | 42 | This started as a direct copy of a gist by Peter Damoc (@pdamoc) and relates to 43 | [a discussion on the elm-discuss list](https://groups.google.com/forum/#!topic/elm-discuss/8Q2xwRh6UYc) 44 | 45 | -------------------------------------------------------------------------------- /src/Main.elm: -------------------------------------------------------------------------------- 1 | module Main exposing (..) 2 | 3 | import Html exposing (..) 4 | import Html.App as App 5 | import Html.Attributes exposing (..) 6 | import Html.Events exposing (..) 7 | import Task 8 | import Date exposing (Date) 9 | import Time exposing (Time) 10 | import Json.Decode as Json 11 | import Date.Format 12 | import String 13 | import JsonDateDecode 14 | 15 | 16 | main : Program Never 17 | main = 18 | App.program 19 | { init = init 20 | , view = view 21 | , update = \msg m -> ( update msg m, Cmd.none ) 22 | , subscriptions = \_ -> Sub.none 23 | } 24 | 25 | 26 | 27 | -- MODEL 28 | 29 | 30 | type alias Model = 31 | Date 32 | 33 | 34 | init : ( Model, Cmd Msg ) 35 | init = 36 | ( Date.fromTime 0, nowCmd UpdateDate ) 37 | 38 | 39 | 40 | -- UPDATE 41 | 42 | 43 | type Msg 44 | = UpdateDate Date 45 | | AddADay 46 | | Add30Days 47 | | DateChanged Date 48 | 49 | 50 | nowCmd : (Date -> a) -> Cmd a 51 | nowCmd tagger = 52 | Task.perform (\_ -> tagger (Date.fromTime 0)) tagger Date.now 53 | 54 | 55 | addTime : Time -> Date -> Date 56 | addTime time date = 57 | Date.toTime date 58 | |> (+) time 59 | |> Date.fromTime 60 | 61 | 62 | day : Time 63 | day = 64 | 24 * Time.hour 65 | 66 | 67 | update : Msg -> Model -> Model 68 | update msg model = 69 | case Debug.log "msg" msg of 70 | UpdateDate newTime -> 71 | newTime 72 | 73 | AddADay -> 74 | addTime day model 75 | 76 | Add30Days -> 77 | addTime (30 * day) model 78 | 79 | DateChanged date -> 80 | date 81 | 82 | 83 | detailValue : Json.Decoder Json.Value 84 | detailValue = 85 | Json.at [ "detail", "value" ] Json.value 86 | 87 | 88 | dateValue : Json.Decoder Date 89 | dateValue = 90 | Json.customDecoder detailValue JsonDateDecode.toDate 91 | 92 | 93 | view : Model -> Html Msg 94 | view model = 95 | let 96 | -- convert date to String in ISO8601 format 97 | dateString = 98 | JsonDateDecode.toJson model 99 | in 100 | div [] 101 | [ button [ onClick AddADay ] [ text "Add a Day" ] 102 | , button [ onClick Add30Days ] [ text "Add 30 Days" ] 103 | , Html.p [] [ Html.text (toString model) ] 104 | , datePicker 105 | [ attribute "date" dateString 106 | , on "date-changed" (dateValue |> Json.map DateChanged) 107 | ] 108 | [] 109 | ] 110 | 111 | 112 | datePicker : List (Attribute a) -> List (Html a) -> Html a 113 | datePicker = 114 | Html.node "paper-date-picker" 115 | --------------------------------------------------------------------------------