skip to Main Content

I try to integrate to my ELM page a "login with" widget (the one from Telegram https://core.telegram.org/widgets/login)

I try to build the appropriate node, which is of type <script>, but when the page is rendered, the type is replaced by <p>. I guess this is a security feature. But how can I build this node ?

What I want:

<script
    async
    src="https://telegram.org/js/telegram-widget.js?21"
    data-telegram-login="botname"
    data-onauth="onTelegramAuth(user)"
></script>

What I do:

telegram : Html Model
telegram =
    node "script"
        [ attribute "async" ""
        , attribute "src" "https://telegrami.org/js/telegram-widget.js?21"
        , attribute "data-telegram-login" "botname"
        , attribute "data-onauth" "onTelegramAuth(user)"
        ]
        []

What I get:

<p
    async=""
    src="https://telegrami.org/js/telegram-widget.js?21"
    data-telegram-login="botname"
    data-onauth="onTelegramAuth(user)"
></p>

Thank for your help 🙂

2

Answers


  1. This is intentional. Elm doesn’t allow script tags for security reasons. If you want that kind of functionality, wrap it around in a web component and import the web component in Elm. You can listen for Custom Events on Elm side in order to pass data from the web component to Elm and you can set attributes to the web component in order to pass data from Elm to the web component.

    Login or Signup to reply.
  2. Thanks to @pdamoc,
    I’ve managed to make it work like this:

    Web component: telegram-button.js

    export default class TelegramButton extends HTMLElement {
      constructor() {
        const self = super();
    
        self.onauth = (user) => {
          this.dispatchEvent(new CustomEvent('on-telegram-auth', {detail: user}))
        }
    
        return self;
      }
    
      connectedCallback() {
        const script = document.createElement('script');
    
        script.src = 'https://telegram.org/js/telegram-widget.js?21';
        script.async = true;
    
        const attributes = {
            'data-telegram-login': this.getAttribute('data-telegram-login'),
            'data-size': this.getAttribute('data-size'),
            'data-radius': this.getAttribute('data-radius'),
            'data-request-access': this.getAttribute('data-request-access'),
            'data-onauth': 'onTelegramAuth(user)',
        };
    
        for (const [k, v] of Object.entries(attributes)) {
            v !== undefined && script.setAttribute(k, `${v}`);
        }
        this.appendChild(script);
      }
    }
    
    const onTelegramAuth = (user) => {
        const button = document.querySelector("telegram-button")
        button.onauth(user)
    }
    
    if (!window.customElements.get('telegram-button')) {
        window.TelegramButton = TelegramButton
        window.customElements.define('telegram-button', TelegramButton)
        window.onTelegramAuth = onTelegramAuth
    }
    

    Import it inside your index.js

    Then in Elm

    button : Html Msg
    button =
      Html.node "telegram-button"
        [ attribute "data-telegram-login" "MyBot"
        , attribute "data-size" "large"
        , attribute "data-radius" "6"
        , attribute "data-request-access" "write"
        , onTelegramAuthChange OnTelegramAuth
        ] []
    
    onTelegramAuthChange : Msg -> Attribute Msg
    onTelegramAuthChange toMsg =
        telegramDataDecoder
            |> Decode.map toMsg
            |> Html.Events.on "on-telegram-auth"
    
    type alias TelegramAuth =
        { id : Int }
    
    telegramDataDecoder : Decode.Decoder TelegramAuth
    telegramDataDecoder =
        Decode.map TelegramAuth
            (Decode.at ["detail", "id"] Decode.int)
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search