From b12cdcaf26388bacada79b86d71109375f11a879 Mon Sep 17 00:00:00 2001
From: Christoph Reiter <reiter.christoph@gmail.com>
Date: Mon, 20 Apr 2020 15:45:11 +0200
Subject: [PATCH] Port to scoped elements

---
 packages/auth/package.json         |   7 +-
 packages/auth/src/auth.js          | 498 ++++++++++++++++++++++++++++
 packages/auth/src/index.js         |   3 +
 packages/auth/src/vpu-auth-demo.js |  11 +-
 packages/auth/src/vpu-auth.js      | 500 +----------------------------
 5 files changed, 516 insertions(+), 503 deletions(-)
 create mode 100644 packages/auth/src/auth.js
 create mode 100644 packages/auth/src/index.js

diff --git a/packages/auth/package.json b/packages/auth/package.json
index 75f27bcf..895c3931 100644
--- a/packages/auth/package.json
+++ b/packages/auth/package.json
@@ -1,7 +1,7 @@
 {
   "name": "vpu-auth",
   "version": "1.0.0",
-  "main": "src/vpu-auth.js",
+  "main": "src/index.js",
   "devDependencies": {
     "chai": "^4.2.0",
     "glob": "^7.1.4",
@@ -31,9 +31,10 @@
     "vpu-common": "file:./vendor/common"
   },
   "dependencies": {
+    "@open-wc/scoped-elements": "^1.0.8",
+    "event-target-shim": "^5.0.1",
     "keycloak-js": "^8.0.0",
-    "lit-element": "^2.1.0",
-    "event-target-shim": "^5.0.1"
+    "lit-element": "^2.1.0"
   },
   "scripts": {
     "clean": "rm dist/*",
diff --git a/packages/auth/src/auth.js b/packages/auth/src/auth.js
new file mode 100644
index 00000000..cce2cb76
--- /dev/null
+++ b/packages/auth/src/auth.js
@@ -0,0 +1,498 @@
+import {i18n} from './i18n.js';
+import {html, css} from 'lit-element';
+import {unsafeHTML} from 'lit-html/directives/unsafe-html.js';
+import JSONLD from 'vpu-common/jsonld';
+import * as commonUtils from 'vpu-common/utils';
+import * as commonStyles from 'vpu-common/styles';
+import * as events from 'vpu-common/events.js';
+import 'vpu-common/vpu-icon.js';
+import VPULitElement from 'vpu-common/vpu-lit-element';
+import  {KeycloakWrapper} from './keycloak.js';
+
+
+const LoginStatus = Object.freeze({
+    UNKNOWN: 'unknown',
+    LOGGING_IN: 'logging-in',
+    LOGGED_IN: 'logged-in',
+    LOGGING_OUT: 'logging-out',
+    LOGGED_OUT: 'logged-out',
+});
+
+/**
+ * Keycloak auth web component
+ * https://www.keycloak.org/docs/latest/securing_apps/index.html#_javascript_adapter
+ *
+ * Dispatches an event `vpu-auth-init` and sets some global variables:
+ *   window.VPUAuthSubject: Keycloak username
+ *   window.VPUAuthToken: Keycloak token to send with your requests
+ *   window.VPUAuthTokenParsed: Keycloak token content
+ *   window.VPUUserFullName: Full name of the user
+ *   window.VPUPersonId: Person identifier of the user
+ *   window.VPUPerson: Person json object of the user (optional, enable by setting the `load-person` attribute,
+ *                     which will dispatch a `vpu-auth-person-init` event when loaded)
+ */
+export class Auth extends VPULitElement {
+    constructor() {
+        super();
+        this.lang = 'de';
+        this.forceLogin = false;
+        this.loadPerson = false;
+        this.showProfile = false;
+        this.token = "";
+        this.tokenParsed = null;
+        this.subject = "";
+        this.name = "";
+        this.personId = "";
+        this.tryLogin = false;
+        this.person = null;
+        this.entryPointUrl = commonUtils.getAPiUrl();
+        this.keycloakConfig = null;
+
+        const _getLoginData = () => {
+            const message = {
+                status: this._loginStatus,
+                token: this.token,
+            };
+            return message;
+        };
+
+        this._loginStatus = LoginStatus.UNKNOWN;
+        this._emitter = new events.EventEmitter('vpu-auth-update', 'vpu-auth-update-request');
+        this._emitter.registerCallback(_getLoginData);
+
+        // Create the events
+        this.initEvent = new CustomEvent("vpu-auth-init", { "detail": "KeyCloak init event", bubbles: true, composed: true });
+        this.personInitEvent = new CustomEvent("vpu-auth-person-init", { "detail": "KeyCloak person init event", bubbles: true, composed: true });
+        this.profileEvent = new CustomEvent("vpu-auth-profile", { "detail": "Profile event", bubbles: true, composed: true });
+        this.keycloakDataUpdateEvent = new CustomEvent("vpu-auth-keycloak-data-update", { "detail": "KeyCloak data was updated", bubbles: true, composed: true });
+
+        this.closeDropdown = this.closeDropdown.bind(this);
+        this._onKCChanged = this._onKCChanged.bind(this);
+   }
+
+    _onKCChanged(event) {
+        const kc = event.detail;
+        let newPerson = false;
+
+        if (kc.authenticated) {
+            let tokenChanged = (this.token !== kc.token);
+            this.tokenParsed = kc.tokenParsed;
+            this.name = kc.idTokenParsed.name;
+            this.token = kc.token;
+
+            this.subject = kc.subject;
+            const personId = kc.idTokenParsed.preferred_username;
+            if (personId !== this.personId) {
+                this.person = null;
+                newPerson = true;
+            }
+            this.personId = personId;
+
+            window.VPUAuthSubject = this.subject;
+            window.VPUAuthToken = this.token;
+            window.VPUAuthTokenParsed = this.tokenParsed;
+            window.VPUUserFullName = this.name;
+            window.VPUPersonId = this.personId;
+            window.VPUPerson = this.person;
+
+            this._setLoginStatus(LoginStatus.LOGGED_IN, tokenChanged);
+        } else {
+            if (this._loginStatus === LoginStatus.LOGGED_IN) {
+                this._setLoginStatus(LoginStatus.LOGGING_OUT);
+            }
+            this.name = "";
+            this.token = "";
+            this.tokenParsed = null;
+            this.subject = "";
+            this.personId = "";
+            this.person = null;
+
+            window.VPUAuthSubject = this.subject;
+            window.VPUAuthToken = this.token;
+            window.VPUAuthTokenParsed = this.tokenParsed;
+            window.VPUUserFullName = this.name;
+            window.VPUPersonId = this.personId;
+            window.VPUPerson = this.person;
+
+            this._setLoginStatus(LoginStatus.LOGGED_OUT);
+        }
+
+        const that = this;
+
+        if (newPerson) {
+            this.dispatchEvent(this.initEvent);
+        }
+
+        if (newPerson && this.loadPerson) {
+            JSONLD.initialize(this.entryPointUrl, (jsonld) => {
+                // find the correct api url for the current person
+                // we are fetching the logged-in person directly to respect the REST philosophy
+                // see: https://github.com/api-platform/api-platform/issues/337
+                const apiUrl = jsonld.getApiUrlForEntityName("Person") + '/' + that.personId;
+
+                fetch(apiUrl, {
+                    headers: {
+                        'Content-Type': 'application/ld+json',
+                        'Authorization': 'Bearer ' + that.token,
+                    },
+                })
+                .then(response => response.json())
+                .then((person) => {
+                    that.person = person;
+                    window.VPUPerson = person;
+                    that.dispatchEvent(that.personInitEvent);
+                    this._setLoginStatus(this._loginStatus, true);
+                });
+            }, {}, that.lang);
+        }
+
+        this.dispatchEvent(this.keycloakDataUpdateEvent);
+    }
+
+    _setLoginStatus(status, force) {
+        if (this._loginStatus === status && !force)
+            return;
+
+        this._loginStatus = status;
+        this._emitter.emit();
+    }
+
+    /**
+     * See: https://lit-element.polymer-project.org/guide/properties#initialize
+     */
+    static get properties() {
+        return {
+            lang: { type: String },
+            forceLogin: { type: Boolean, attribute: 'force-login' },
+            tryLogin: { type: Boolean, attribute: 'try-login' },
+            loadPerson: { type: Boolean, attribute: 'load-person' },
+            showProfile: { type: Boolean, attribute: 'show-profile' },
+            entryPointUrl: { type: String, attribute: 'entry-point-url' },
+            keycloakConfig: { type: Object, attribute: 'keycloak-config' },
+            name: { type: String, attribute: false },
+            token: { type: String, attribute: false },
+            subject: { type: String, attribute: false },
+            personId: { type: String, attribute: false },
+            person: { type: Object, attribute: false },
+            _loginStatus: { type: String, attribute: false },
+        };
+    }
+
+    _getScope() {
+        if (this.keycloakConfig !== null) {
+            return this.keycloakConfig.scope || "";
+        }
+        return "";
+    }
+
+    connectedCallback() {
+        super.connectedCallback();
+
+        // Keycloak config
+        let baseURL = commonUtils.setting('keyCloakBaseURL');
+        let realm = commonUtils.setting('keyCloakRealm');
+        let clientId = commonUtils.setting('keyCloakClientId');
+        let silentCheckSsoRedirectUri = '';
+        if (this.keycloakConfig !== null) {
+            baseURL = this.keycloakConfig.url || baseURL;
+            realm = this.keycloakConfig.realm || realm;
+            clientId = this.keycloakConfig.clientId || clientId;
+            silentCheckSsoRedirectUri = this.keycloakConfig.silentCheckSsoRedirectUri || silentCheckSsoRedirectUri;
+        }
+        if (!baseURL || !realm || !clientId) {
+            throw Error("Keycloak config not set");
+        }
+
+        this._kcwrapper = new KeycloakWrapper(baseURL, realm, clientId, silentCheckSsoRedirectUri);
+        this._kcwrapper.addEventListener('changed', this._onKCChanged);
+
+        const handleLogin = async () => {
+            if (this.forceLogin || this._kcwrapper.isLoggingIn()) {
+                this._setLoginStatus(LoginStatus.LOGGING_IN);
+                await this._kcwrapper.login({lang: this.lang, scope: this._getScope()});
+            } else if (this.tryLogin) {
+                this._setLoginStatus(LoginStatus.LOGGING_IN);
+                await this._kcwrapper.tryLogin();
+                if (this._loginStatus === LoginStatus.LOGGING_IN)
+                    this._setLoginStatus(LoginStatus.LOGGED_OUT);
+            } else {
+                this._setLoginStatus(LoginStatus.LOGGED_OUT);
+            }
+        };
+
+        handleLogin();
+
+        this.updateComplete.then(() => {
+            window.onresize = () => {
+                this.updateDropdownWidth();
+            };
+        });
+
+        document.addEventListener('click', this.closeDropdown);
+    }
+
+    /**
+     * Set the dropdown width to almost the width of the web component
+     * We need to set the width manually because a percent width is in relation to the viewport
+     */
+    updateDropdownWidth() {
+        const dropdown = this._("div.dropdown-menu");
+
+        if (!dropdown) {
+            return;
+        }
+
+        dropdown.setAttribute("style", `width: ${this.offsetWidth - 5}px`);
+    }
+
+    disconnectedCallback() {
+        this._kcwrapper.removeEventListener('changed', this._onKCChanged);
+        document.removeEventListener('click', this.closeDropdown);
+        super.disconnectedCallback();
+    }
+
+    onLoginClicked(e) {
+        this._kcwrapper.login({lang: this.lang, scope: this._getScope()});
+        e.preventDefault();
+    }
+
+    onLogoutClicked(e) {
+        // Keycloak will redirect right away without emitting events, so we have
+        // to do this manually here
+        if (this._loginStatus === LoginStatus.LOGGED_IN) {
+            this._setLoginStatus(LoginStatus.LOGGING_OUT);
+        }
+        this._kcwrapper.logout();
+    }
+
+    update(changedProperties) {
+        changedProperties.forEach((oldValue, propName) => {
+            if (propName === "lang") {
+                i18n.changeLanguage(this.lang);
+            }
+        });
+
+        super.update(changedProperties);
+    }
+
+    static get styles() {
+        // language=css
+        return css`
+            ${commonStyles.getThemeCSS()}
+
+            :host {
+                display: inline-block;
+            }
+
+            a {
+                color: currentColor;
+                cursor: pointer;
+                text-decoration: none;
+            }
+
+            img {
+                border-width: var(--vpu-border-width);
+                border-color: var(--vpu-dark);
+                border-style: solid;
+            }
+
+            .dropdown.is-active .dropdown-menu, .dropdown.is-hoverable:hover .dropdown-menu {
+                display: block;
+            }
+
+            .dropdown-menu {
+                display: none;
+                min-width: 8em;
+                padding-top: 4px;
+                position: absolute;
+                z-index: 20;
+                border: solid 1px black;
+                border-radius: var(--vpu-border-radius);
+                overflow: hidden;
+                background-color: white;
+            }
+
+            .dropdown-content {
+                background-color: white;
+                padding-bottom: 0.5rem;
+                padding-top: 0.5rem;
+            }
+
+            .dropdown-content img {
+                max-width: 120px;
+            }
+
+            .menu a {
+                /*padding: 0.3em;*/
+                font-weight: 400;
+                color: #000;
+                display: block;
+                text-decoration: none;
+            }
+
+            .menu a:hover {
+                color: #E4154B;
+            }
+
+            .menu a.selected { color: white; background-color: black; }
+
+            .dropdown-item {
+                color: #4a4a4a;
+                display: block;
+                font-size: 0.875rem;
+                line-height: 1.5;
+                padding: 0.375rem 1rem;
+                position: relative;
+            }
+
+              .dropdown, img.login {
+                cursor: pointer;
+            }
+
+            a.dropdown-item {
+                width: initial !important;
+            }
+
+            .main-button {
+                min-width: 150px;
+            }
+
+            .dropdown-trigger {
+                white-space: nowrap;
+            }
+
+            vpu-icon {
+                height: 1em;
+                width: 1em;
+                vertical-align: -0.1rem;
+            }
+
+            .loginbox svg {
+                width: 1.2em;
+                height: 1.2em;
+                top: 0.15em;
+                position: relative;
+            }
+
+            .loginbox {
+                display: flex;
+
+                align-items: center;
+                padding: 0 0.1em;
+                transition: background-color 0.15s, color 0.15s;
+            }
+
+            .loginbox:hover {
+                background-color: var(--vpu-dark);
+                color: var(--vpu-light);
+                cursor: pointer;
+                transition: none;
+            }
+
+            .loginbox:hover svg path {
+                fill: var(--vpu-light);
+            }
+
+            .loginbox .icon, .authbox {
+                display: inline-block;
+            }
+
+            .loginbox .label {
+                padding-left: 0.2em;
+            }
+        `;
+    }
+
+    setChevron(name) {
+        const chevron = this.shadowRoot.querySelector("#menu-chevron-icon");
+        if (chevron !== null) {
+            chevron.name = name;
+        }
+    }
+
+    onDropdownClick(event) {
+        event.stopPropagation();
+        event.currentTarget.classList.toggle('is-active');
+        this.setChevron(event.currentTarget.classList.contains('is-active') ? 'chevron-up' : 'chevron-down');
+        this.updateDropdownWidth();
+    }
+
+    closeDropdown() {
+        var dropdowns = this.shadowRoot.querySelectorAll('.dropdown');
+        dropdowns.forEach(function (el) {
+            el.classList.remove('is-active');
+        });
+        this.setChevron('chevron-down');
+    }
+
+    onProfileClicked(event) {
+        event.preventDefault();
+        this.dispatchEvent(this.profileEvent);
+    }
+
+    renderLoggedIn() {
+        const imageURL = (this.person && this.person.image) ? this.person.image : null;
+
+        return html`
+            <div class="dropdown" @click="${this.onDropdownClick}">
+                <div class="dropdown-trigger">
+                    <a href="#">
+                        <span>${this.name}</span>
+                        <vpu-icon name="chevron-down" id="menu-chevron-icon"></vpu-icon>
+                    </a>
+                </div>
+                <div class="dropdown-menu" id="dropdown-menu2" role="menu">
+                    <div class="dropdown-content" @blur="${this.closeDropdown}">
+                        ${imageURL ? html`<div class="dropdown-item"><img alt="" src="${imageURL}"></div>` : ''}
+                        <div class="menu">
+                            ${this.showProfile ? html`<a href="#" @click="${this.onProfileClicked}" class="dropdown-item">${i18n.t('profile')}</a>` :''}
+                            <a href="#" @click="${this.onLogoutClicked}" class="dropdown-item">${i18n.t('logout')}</a>
+                        </div>
+                    </div>
+                </div>
+            </div>
+        `;
+    }
+
+    renderLoggedOut() {
+        let loginSVG = `
+        <svg
+           viewBox="0 0 100 100"
+           y="0px"
+           x="0px"
+           id="icon"
+           role="img"
+           version="1.1">
+        <g
+           id="g6">
+            <path
+           style="stroke-width:1.33417916"
+           id="path2"
+           d="m 42.943908,38.894934 5.885859,6.967885 H 5.4215537 c -1.8393311,0 -3.4334181,1.741972 -3.4334181,4.064599 0,2.322628 1.4714649,4.064599 3.4334181,4.064599 H 48.829767 L 42.943908,60.9599 c -1.348843,1.596808 -1.348843,4.064599 0,5.661406 1.348843,1.596808 3.433418,1.596808 4.782261,0 L 61.705085,49.927418 47.726169,33.378693 c -1.348843,-1.596806 -3.433418,-1.596806 -4.782261,0 -1.348843,1.596807 -1.348843,4.064599 0,5.516241 z" />
+            <path
+           id="path4"
+           d="m 50,2.3007812 c -18.777325,0 -35.049449,10.9124408 -42.8261719,26.7246098 H 13.390625 C 20.672112,16.348362 34.336876,7.8007812 50,7.8007812 73.3,7.8007812 92.300781,26.7 92.300781,50 92.300781,73.3 73.3,92.300781 50,92.300781 c -15.673389,0 -29.345175,-8.60579 -36.623047,-21.326172 H 7.1640625 C 14.942553,86.8272 31.242598,97.800781 50.099609,97.800781 76.399609,97.800781 97.900391,76.4 97.900391,50 97.800391,23.7 76.3,2.3007812 50,2.3007812 Z" />
+        </g>
+        </svg>
+        `;
+
+        return html`
+            <a href="#" @click="${this.onLoginClicked}">
+                <div class="loginbox">
+                    <div class="icon">${unsafeHTML(loginSVG)}</div>
+                    <div class="label">${i18n.t('login')}</div>
+                </div>
+            </a>
+        `;
+    }
+
+    render() {
+        commonUtils.initAssetBaseURL('vpu-auth-src');
+        const loggedIn = (this._loginStatus === LoginStatus.LOGGED_IN);
+        return html`
+            <div class="authbox">
+                ${loggedIn ? this.renderLoggedIn() : this.renderLoggedOut()}
+            </div>
+        `;
+    }
+}
\ No newline at end of file
diff --git a/packages/auth/src/index.js b/packages/auth/src/index.js
new file mode 100644
index 00000000..f8748296
--- /dev/null
+++ b/packages/auth/src/index.js
@@ -0,0 +1,3 @@
+import {Auth} from './auth.js';
+
+export {Auth};
\ No newline at end of file
diff --git a/packages/auth/src/vpu-auth-demo.js b/packages/auth/src/vpu-auth-demo.js
index a6dfb89d..e30722e1 100644
--- a/packages/auth/src/vpu-auth-demo.js
+++ b/packages/auth/src/vpu-auth-demo.js
@@ -1,14 +1,21 @@
 import {i18n} from './i18n.js';
 import {html, LitElement} from 'lit-element';
-import './vpu-auth';
+import {ScopedElementsMixin} from '@open-wc/scoped-elements';
+import {Auth} from './auth.js';
 import * as commonUtils from 'vpu-common/utils';
 
-class AuthDemo extends LitElement {
+class AuthDemo extends ScopedElementsMixin(LitElement) {
     constructor() {
         super();
         this.lang = 'de';
     }
 
+    static get scopedElements() {
+        return {
+          'vpu-auth': Auth,
+        };
+    }
+
     static get properties() {
         return {
             lang: { type: String },
diff --git a/packages/auth/src/vpu-auth.js b/packages/auth/src/vpu-auth.js
index b150f73d..c6be6253 100644
--- a/packages/auth/src/vpu-auth.js
+++ b/packages/auth/src/vpu-auth.js
@@ -1,500 +1,4 @@
-import {i18n} from './i18n.js';
-import {html, css} from 'lit-element';
-import {unsafeHTML} from 'lit-html/directives/unsafe-html.js';
-import JSONLD from 'vpu-common/jsonld';
 import * as commonUtils from 'vpu-common/utils';
-import * as commonStyles from 'vpu-common/styles';
-import * as events from 'vpu-common/events.js';
-import 'vpu-common/vpu-icon.js';
-import VPULitElement from 'vpu-common/vpu-lit-element';
-import  {KeycloakWrapper} from './keycloak.js';
+import {Auth} from './auth.js';
 
-
-const LoginStatus = Object.freeze({
-    UNKNOWN: 'unknown',
-    LOGGING_IN: 'logging-in',
-    LOGGED_IN: 'logged-in',
-    LOGGING_OUT: 'logging-out',
-    LOGGED_OUT: 'logged-out',
-});
-
-/**
- * Keycloak auth web component
- * https://www.keycloak.org/docs/latest/securing_apps/index.html#_javascript_adapter
- *
- * Dispatches an event `vpu-auth-init` and sets some global variables:
- *   window.VPUAuthSubject: Keycloak username
- *   window.VPUAuthToken: Keycloak token to send with your requests
- *   window.VPUAuthTokenParsed: Keycloak token content
- *   window.VPUUserFullName: Full name of the user
- *   window.VPUPersonId: Person identifier of the user
- *   window.VPUPerson: Person json object of the user (optional, enable by setting the `load-person` attribute,
- *                     which will dispatch a `vpu-auth-person-init` event when loaded)
- */
-class VPUAuth extends VPULitElement {
-    constructor() {
-        super();
-        this.lang = 'de';
-        this.forceLogin = false;
-        this.loadPerson = false;
-        this.showProfile = false;
-        this.token = "";
-        this.tokenParsed = null;
-        this.subject = "";
-        this.name = "";
-        this.personId = "";
-        this.tryLogin = false;
-        this.person = null;
-        this.entryPointUrl = commonUtils.getAPiUrl();
-        this.keycloakConfig = null;
-
-        const _getLoginData = () => {
-            const message = {
-                status: this._loginStatus,
-                token: this.token,
-            };
-            return message;
-        };
-
-        this._loginStatus = LoginStatus.UNKNOWN;
-        this._emitter = new events.EventEmitter('vpu-auth-update', 'vpu-auth-update-request');
-        this._emitter.registerCallback(_getLoginData);
-
-        // Create the events
-        this.initEvent = new CustomEvent("vpu-auth-init", { "detail": "KeyCloak init event", bubbles: true, composed: true });
-        this.personInitEvent = new CustomEvent("vpu-auth-person-init", { "detail": "KeyCloak person init event", bubbles: true, composed: true });
-        this.profileEvent = new CustomEvent("vpu-auth-profile", { "detail": "Profile event", bubbles: true, composed: true });
-        this.keycloakDataUpdateEvent = new CustomEvent("vpu-auth-keycloak-data-update", { "detail": "KeyCloak data was updated", bubbles: true, composed: true });
-
-        this.closeDropdown = this.closeDropdown.bind(this);
-        this._onKCChanged = this._onKCChanged.bind(this);
-   }
-
-    _onKCChanged(event) {
-        const kc = event.detail;
-        let newPerson = false;
-
-        if (kc.authenticated) {
-            let tokenChanged = (this.token !== kc.token);
-            this.tokenParsed = kc.tokenParsed;
-            this.name = kc.idTokenParsed.name;
-            this.token = kc.token;
-
-            this.subject = kc.subject;
-            const personId = kc.idTokenParsed.preferred_username;
-            if (personId !== this.personId) {
-                this.person = null;
-                newPerson = true;
-            }
-            this.personId = personId;
-
-            window.VPUAuthSubject = this.subject;
-            window.VPUAuthToken = this.token;
-            window.VPUAuthTokenParsed = this.tokenParsed;
-            window.VPUUserFullName = this.name;
-            window.VPUPersonId = this.personId;
-            window.VPUPerson = this.person;
-
-            this._setLoginStatus(LoginStatus.LOGGED_IN, tokenChanged);
-        } else {
-            if (this._loginStatus === LoginStatus.LOGGED_IN) {
-                this._setLoginStatus(LoginStatus.LOGGING_OUT);
-            }
-            this.name = "";
-            this.token = "";
-            this.tokenParsed = null;
-            this.subject = "";
-            this.personId = "";
-            this.person = null;
-
-            window.VPUAuthSubject = this.subject;
-            window.VPUAuthToken = this.token;
-            window.VPUAuthTokenParsed = this.tokenParsed;
-            window.VPUUserFullName = this.name;
-            window.VPUPersonId = this.personId;
-            window.VPUPerson = this.person;
-
-            this._setLoginStatus(LoginStatus.LOGGED_OUT);
-        }
-
-        const that = this;
-
-        if (newPerson) {
-            this.dispatchEvent(this.initEvent);
-        }
-
-        if (newPerson && this.loadPerson) {
-            JSONLD.initialize(this.entryPointUrl, (jsonld) => {
-                // find the correct api url for the current person
-                // we are fetching the logged-in person directly to respect the REST philosophy
-                // see: https://github.com/api-platform/api-platform/issues/337
-                const apiUrl = jsonld.getApiUrlForEntityName("Person") + '/' + that.personId;
-
-                fetch(apiUrl, {
-                    headers: {
-                        'Content-Type': 'application/ld+json',
-                        'Authorization': 'Bearer ' + that.token,
-                    },
-                })
-                .then(response => response.json())
-                .then((person) => {
-                    that.person = person;
-                    window.VPUPerson = person;
-                    that.dispatchEvent(that.personInitEvent);
-                    this._setLoginStatus(this._loginStatus, true);
-                });
-            }, {}, that.lang);
-        }
-
-        this.dispatchEvent(this.keycloakDataUpdateEvent);
-    }
-
-    _setLoginStatus(status, force) {
-        if (this._loginStatus === status && !force)
-            return;
-
-        this._loginStatus = status;
-        this._emitter.emit();
-    }
-
-    /**
-     * See: https://lit-element.polymer-project.org/guide/properties#initialize
-     */
-    static get properties() {
-        return {
-            lang: { type: String },
-            forceLogin: { type: Boolean, attribute: 'force-login' },
-            tryLogin: { type: Boolean, attribute: 'try-login' },
-            loadPerson: { type: Boolean, attribute: 'load-person' },
-            showProfile: { type: Boolean, attribute: 'show-profile' },
-            entryPointUrl: { type: String, attribute: 'entry-point-url' },
-            keycloakConfig: { type: Object, attribute: 'keycloak-config' },
-            name: { type: String, attribute: false },
-            token: { type: String, attribute: false },
-            subject: { type: String, attribute: false },
-            personId: { type: String, attribute: false },
-            person: { type: Object, attribute: false },
-            _loginStatus: { type: String, attribute: false },
-        };
-    }
-
-    _getScope() {
-        if (this.keycloakConfig !== null) {
-            return this.keycloakConfig.scope || "";
-        }
-        return "";
-    }
-
-    connectedCallback() {
-        super.connectedCallback();
-
-        // Keycloak config
-        let baseURL = commonUtils.setting('keyCloakBaseURL');
-        let realm = commonUtils.setting('keyCloakRealm');
-        let clientId = commonUtils.setting('keyCloakClientId');
-        let silentCheckSsoRedirectUri = '';
-        if (this.keycloakConfig !== null) {
-            baseURL = this.keycloakConfig.url || baseURL;
-            realm = this.keycloakConfig.realm || realm;
-            clientId = this.keycloakConfig.clientId || clientId;
-            silentCheckSsoRedirectUri = this.keycloakConfig.silentCheckSsoRedirectUri || silentCheckSsoRedirectUri;
-        }
-        if (!baseURL || !realm || !clientId) {
-            throw Error("Keycloak config not set");
-        }
-
-        this._kcwrapper = new KeycloakWrapper(baseURL, realm, clientId, silentCheckSsoRedirectUri);
-        this._kcwrapper.addEventListener('changed', this._onKCChanged);
-
-        const handleLogin = async () => {
-            if (this.forceLogin || this._kcwrapper.isLoggingIn()) {
-                this._setLoginStatus(LoginStatus.LOGGING_IN);
-                await this._kcwrapper.login({lang: this.lang, scope: this._getScope()});
-            } else if (this.tryLogin) {
-                this._setLoginStatus(LoginStatus.LOGGING_IN);
-                await this._kcwrapper.tryLogin();
-                if (this._loginStatus === LoginStatus.LOGGING_IN)
-                    this._setLoginStatus(LoginStatus.LOGGED_OUT);
-            } else {
-                this._setLoginStatus(LoginStatus.LOGGED_OUT);
-            }
-        };
-
-        handleLogin();
-
-        this.updateComplete.then(() => {
-            window.onresize = () => {
-                this.updateDropdownWidth();
-            };
-        });
-
-        document.addEventListener('click', this.closeDropdown);
-    }
-
-    /**
-     * Set the dropdown width to almost the width of the web component
-     * We need to set the width manually because a percent width is in relation to the viewport
-     */
-    updateDropdownWidth() {
-        const dropdown = this._("div.dropdown-menu");
-
-        if (!dropdown) {
-            return;
-        }
-
-        dropdown.setAttribute("style", `width: ${this.offsetWidth - 5}px`);
-    }
-
-    disconnectedCallback() {
-        this._kcwrapper.removeEventListener('changed', this._onKCChanged);
-        document.removeEventListener('click', this.closeDropdown);
-        super.disconnectedCallback();
-    }
-
-    onLoginClicked(e) {
-        this._kcwrapper.login({lang: this.lang, scope: this._getScope()});
-        e.preventDefault();
-    }
-
-    onLogoutClicked(e) {
-        // Keycloak will redirect right away without emitting events, so we have
-        // to do this manually here
-        if (this._loginStatus === LoginStatus.LOGGED_IN) {
-            this._setLoginStatus(LoginStatus.LOGGING_OUT);
-        }
-        this._kcwrapper.logout();
-    }
-
-    update(changedProperties) {
-        changedProperties.forEach((oldValue, propName) => {
-            if (propName === "lang") {
-                i18n.changeLanguage(this.lang);
-            }
-        });
-
-        super.update(changedProperties);
-    }
-
-    static get styles() {
-        // language=css
-        return css`
-            ${commonStyles.getThemeCSS()}
-
-            :host {
-                display: inline-block;
-            }
-
-            a {
-                color: currentColor;
-                cursor: pointer;
-                text-decoration: none;
-            }
-
-            img {
-                border-width: var(--vpu-border-width);
-                border-color: var(--vpu-dark);
-                border-style: solid;
-            }
-
-            .dropdown.is-active .dropdown-menu, .dropdown.is-hoverable:hover .dropdown-menu {
-                display: block;
-            }
-
-            .dropdown-menu {
-                display: none;
-                min-width: 8em;
-                padding-top: 4px;
-                position: absolute;
-                z-index: 20;
-                border: solid 1px black;
-                border-radius: var(--vpu-border-radius);
-                overflow: hidden;
-                background-color: white;
-            }
-
-            .dropdown-content {
-                background-color: white;
-                padding-bottom: 0.5rem;
-                padding-top: 0.5rem;
-            }
-
-            .dropdown-content img {
-                max-width: 120px;
-            }
-
-            .menu a {
-                /*padding: 0.3em;*/
-                font-weight: 400;
-                color: #000;
-                display: block;
-                text-decoration: none;
-            }
-
-            .menu a:hover {
-                color: #E4154B;
-            }
-
-            .menu a.selected { color: white; background-color: black; }
-
-            .dropdown-item {
-                color: #4a4a4a;
-                display: block;
-                font-size: 0.875rem;
-                line-height: 1.5;
-                padding: 0.375rem 1rem;
-                position: relative;
-            }
-
-              .dropdown, img.login {
-                cursor: pointer;
-            }
-
-            a.dropdown-item {
-                width: initial !important;
-            }
-
-            .main-button {
-                min-width: 150px;
-            }
-
-            .dropdown-trigger {
-                white-space: nowrap;
-            }
-
-            vpu-icon {
-                height: 1em;
-                width: 1em;
-                vertical-align: -0.1rem;
-            }
-
-            .loginbox svg {
-                width: 1.2em;
-                height: 1.2em;
-                top: 0.15em;
-                position: relative;
-            }
-
-            .loginbox {
-                display: flex;
-
-                align-items: center;
-                padding: 0 0.1em;
-                transition: background-color 0.15s, color 0.15s;
-            }
-
-            .loginbox:hover {
-                background-color: var(--vpu-dark);
-                color: var(--vpu-light);
-                cursor: pointer;
-                transition: none;
-            }
-
-            .loginbox:hover svg path {
-                fill: var(--vpu-light);
-            }
-
-            .loginbox .icon, .authbox {
-                display: inline-block;
-            }
-
-            .loginbox .label {
-                padding-left: 0.2em;
-            }
-        `;
-    }
-
-    setChevron(name) {
-        const chevron = this.shadowRoot.querySelector("#menu-chevron-icon");
-        if (chevron !== null) {
-            chevron.name = name;
-        }
-    }
-
-    onDropdownClick(event) {
-        event.stopPropagation();
-        event.currentTarget.classList.toggle('is-active');
-        this.setChevron(event.currentTarget.classList.contains('is-active') ? 'chevron-up' : 'chevron-down');
-        this.updateDropdownWidth();
-    }
-
-    closeDropdown() {
-        var dropdowns = this.shadowRoot.querySelectorAll('.dropdown');
-        dropdowns.forEach(function (el) {
-            el.classList.remove('is-active');
-        });
-        this.setChevron('chevron-down');
-    }
-
-    onProfileClicked(event) {
-        event.preventDefault();
-        this.dispatchEvent(this.profileEvent);
-    }
-
-    renderLoggedIn() {
-        const imageURL = (this.person && this.person.image) ? this.person.image : null;
-
-        return html`
-            <div class="dropdown" @click="${this.onDropdownClick}">
-                <div class="dropdown-trigger">
-                    <a href="#">
-                        <span>${this.name}</span>
-                        <vpu-icon name="chevron-down" id="menu-chevron-icon"></vpu-icon>
-                    </a>
-                </div>
-                <div class="dropdown-menu" id="dropdown-menu2" role="menu">
-                    <div class="dropdown-content" @blur="${this.closeDropdown}">
-                        ${imageURL ? html`<div class="dropdown-item"><img alt="" src="${imageURL}"></div>` : ''}
-                        <div class="menu">
-                            ${this.showProfile ? html`<a href="#" @click="${this.onProfileClicked}" class="dropdown-item">${i18n.t('profile')}</a>` :''}
-                            <a href="#" @click="${this.onLogoutClicked}" class="dropdown-item">${i18n.t('logout')}</a>
-                        </div>
-                    </div>
-                </div>
-            </div>
-        `;
-    }
-
-    renderLoggedOut() {
-        let loginSVG = `
-        <svg
-           viewBox="0 0 100 100"
-           y="0px"
-           x="0px"
-           id="icon"
-           role="img"
-           version="1.1">
-        <g
-           id="g6">
-            <path
-           style="stroke-width:1.33417916"
-           id="path2"
-           d="m 42.943908,38.894934 5.885859,6.967885 H 5.4215537 c -1.8393311,0 -3.4334181,1.741972 -3.4334181,4.064599 0,2.322628 1.4714649,4.064599 3.4334181,4.064599 H 48.829767 L 42.943908,60.9599 c -1.348843,1.596808 -1.348843,4.064599 0,5.661406 1.348843,1.596808 3.433418,1.596808 4.782261,0 L 61.705085,49.927418 47.726169,33.378693 c -1.348843,-1.596806 -3.433418,-1.596806 -4.782261,0 -1.348843,1.596807 -1.348843,4.064599 0,5.516241 z" />
-            <path
-           id="path4"
-           d="m 50,2.3007812 c -18.777325,0 -35.049449,10.9124408 -42.8261719,26.7246098 H 13.390625 C 20.672112,16.348362 34.336876,7.8007812 50,7.8007812 73.3,7.8007812 92.300781,26.7 92.300781,50 92.300781,73.3 73.3,92.300781 50,92.300781 c -15.673389,0 -29.345175,-8.60579 -36.623047,-21.326172 H 7.1640625 C 14.942553,86.8272 31.242598,97.800781 50.099609,97.800781 76.399609,97.800781 97.900391,76.4 97.900391,50 97.800391,23.7 76.3,2.3007812 50,2.3007812 Z" />
-        </g>
-        </svg>
-        `;
-
-        return html`
-            <a href="#" @click="${this.onLoginClicked}">
-                <div class="loginbox">
-                    <div class="icon">${unsafeHTML(loginSVG)}</div>
-                    <div class="label">${i18n.t('login')}</div>
-                </div>
-            </a>
-        `;
-    }
-
-    render() {
-        commonUtils.initAssetBaseURL('vpu-auth-src');
-        const loggedIn = (this._loginStatus === LoginStatus.LOGGED_IN);
-        return html`
-            <div class="authbox">
-                ${loggedIn ? this.renderLoggedIn() : this.renderLoggedOut()}
-            </div>
-        `;
-    }
-}
-
-commonUtils.defineCustomElement('vpu-auth', VPUAuth);
+commonUtils.defineCustomElement('vpu-auth', Auth);
-- 
GitLab