Skip to content
Snippets Groups Projects
Unverified Commit 3dffad0e authored by Scott Berg's avatar Scott Berg Committed by GitHub
Browse files

Merge pull request #3 from saberg3/master

Fetch user data from session URL. Clean up and document code.
parents 03db057c 60c61a16
No related branches found
No related tags found
No related merge requests found
......@@ -12,6 +12,7 @@ You can view a test of this component being used with the myuw-app-bar by openin
- **Login URL (login-url):** The URL to redirect users to on login
- **Logout URL (logout-url):** The Logout URL to redirect users to on logout
- **Session Endpoint (session-endpoint):** The endpoint URL for session info
- **Open Menu Right (open-right):** Include this attribute if you would like the profile menu to open to the right, instead of left
#### Slots
......
......@@ -6,20 +6,28 @@
margin: 0;
}
</style>
<script src="https://unpkg.com/@myuw-web-components/myuw-app-bar@0.1.1"></script>
<link rel="import" href="https://unpkg.com/@myuw-web-components/myuw-app-bar@1.0.0/myuw-app-bar.html">
<link rel="import" href="myuw-profile.html">
</head>
<body>
<myuw-app-bar>
<myuw-app-bar
theme-name="MyUW"
theme-url=""
app-name="Component Test"
app-url=""
background="rgb(197, 5, 12)"
color="white"
>
<myuw-profile
slot="myuw-profile"
login-url="https://wisc.edu/"
logout-url="https://wisc.edu/"
session-endpoint="https://my.wisc.edu/portal/web/session.json"
session-endpoint="http://localhost:3474/session.json"
>
<a href="https://wisc.edu" slot="nav-item">UW Madison Home</a>
<a href="https://wisc.edu" slot="nav-item">STAR</a>
<a href="https://wisc.edu" slot="nav-item">UW Madison Home</a>
<a href="https://wisc.edu" slot="nav-item">STAR</a>
</myuw-profile>
</myuw-app-bar>
</body>
......
#myuw-profile-login {
font-family: 'Roboto', 'Noto', sans-serif;
text-transform: uppercase;
text-decoration: none;
color: white;
padding: 10px 13px;
letter-spacing: 1px;
font-size: 14px;
position: relative;
display: inline-block;
}
#myuw-profile-login.hidden {
display: none;
}
#myuw-profile-circle {
position: relative;
display: inline-block;
width: 40px;
height: 40px;
background: teal;
border-radius: 100%;
display: flex;
justify-content: center;
align-items: center;
cursor: pointer;
}
#myuw-profile-circle-initial {
padding: 0;
margin: 0;
font-weight: 100;
user-select: none;
text-transform: capitalize;
}
#myuw-profile-wrapper {
position: relative;
display: inline-block;
}
#myuw-profile-wrapper.hidden {
display: none;
}
#myuw-profile-nav {
position: absolute;
top: 45px;
right: 0;
background-color:white;
min-width: 320px;
color: black;
list-style: none;
margin: 0;
padding: 0;
font-size: 14px;
transform-origin: top right;
transform: scale(0);
opacity: 0;
transition: all .25s cubic-bezier(0.0, 0.0, 0.2, 1);
-webkit-box-shadow: 0px 0px 7px 0px rgba(50, 50, 50, 0.75);
-moz-box-shadow: 0px 0px 7px 0px rgba(50, 50, 50, 0.75);
box-shadow: 0px 0px 7px 0px rgba(50, 50, 50, 0.75);
}
#myuw-profile-nav.visible {
transform: scale(1);
opacity: 1;
}
#myuw-profile-nav p {
padding: 0;
margin: 0;
}
#myuw-profile-nav a,
#myuw-profile-nav p,
::slotted(a),
::slotted(p){
transition: all .3s ease;
position: relative;
display: block;
padding: 14px 16px;
color: black;
text-decoration: none;
background-color: #f9f9f9;
border-bottom: solid 1px #e5e5e5;
user-select: none;
}
#myuw-profile-nav a:first-child,
#myuw-profile-nav p:first-child {
padding: 14px 16px;
font-weight: bold;
background-color: white;
}
#myuw-profile-nav a:first-child:hover,
#myuw-profile-nav p:first-child:hover {
background-color: white;
}
#myuw-profile-wrapper a:hover,
#myuw-profile-wrapper p:hover,
::slotted(a:hover),
::slotted(p:hover) {
background-color: rgba(158,158,158,0.2);
}
\ No newline at end of file
<!DOCTYPE html>
<template id="myuw-profile-template">
<link href="./myuw-profile.css" rel="stylesheet">
<style>
#myuw-profile-login {
font-family: 'Montserrat', 'Roboto', Arial, sans-serif;
text-transform: uppercase;
text-decoration: none;
color: white;
padding: 10px 13px;
font-weight: bold;
letter-spacing: 0px;
font-size: 14px;
position: relative;
display: inline-block;
}
#myuw-profile-login.hidden {
display: none;
}
#myuw-profile-circle {
position: relative;
display: inline-block;
width: 40px;
height: 40px;
border-radius: 100%;
display: flex;
justify-content: center;
align-items: center;
cursor: pointer;
}
#myuw-profile-circle-initial {
padding: 0;
margin: 0;
font-weight: 500;
font-size: 18px;
font-family: 'Montserrat', 'Roboto', Arial, sans-serif;
user-select: none;
color: white;
text-transform: capitalize;
}
#myuw-profile-wrapper {
position: relative;
display: inline-block;
}
#myuw-profile-wrapper.hidden {
display: none;
}
#myuw-profile-nav {
position: absolute;
top: 45px;
right: 0;
background-color:white;
min-width: 320px;
color: black;
list-style: none;
margin: 0;
padding: 0;
font-size: 14px;
transform-origin: top right;
transform: scale(0);
opacity: 0;
transition: opacity .25s cubic-bezier(0.0, 0.0, 0.2, 1), transform .25s cubic-bezier(0.0, 0.0, 0.2, 1);
-webkit-box-shadow: 0px 0px 7px 0px rgba(50, 50, 50, 0.75);
-moz-box-shadow: 0px 0px 7px 0px rgba(50, 50, 50, 0.75);
box-shadow: 0px 0px 7px 0px rgba(50, 50, 50, 0.75);
}
#myuw-profile-nav.open-right {
left: 0;
right: inherit;
transform-origin: top left;
}
#myuw-profile-nav.visible {
transform: scale(1);
opacity: 1;
}
#myuw-profile-nav p {
padding: 0;
margin: 0;
}
#myuw-profile-nav a,
#myuw-profile-nav p,
::slotted(a),
::slotted(p){
transition: all .3s ease;
position: relative;
font-size: 15px;
font-family: 'Montserrat', 'Roboto', Arial, sans-serif;
display: block;
padding: 14px 16px;
color: black;
text-decoration: none;
background-color: #f9f9f9;
border-bottom: solid 1px #e5e5e5;
user-select: none;
}
#myuw-profile-nav a:first-child,
#myuw-profile-nav p:first-child {
padding: 14px 16px;
font-weight: bold;
background-color: white;
}
#myuw-profile-nav a:first-child:hover,
#myuw-profile-nav p:first-child:hover {
background-color: white;
}
#myuw-profile-nav a:hover,
#myuw-profile-nav p:hover,
::slotted(a:hover),
::slotted(p:hover) {
background-color: rgba(158,158,158,0.2);
}
</style>
<a href="#" id="myuw-profile-login">Login</a>
<a href="#" id="myuw-profile-login" class="hidden">Login</a>
<div id="myuw-profile-wrapper">
<div id="myuw-profile-wrapper" class="hidden">
<div id="myuw-profile-circle">
<p id="myuw-profile-circle-initial">B</p>
</div>
......@@ -19,14 +142,15 @@
</template>
<script>
const testMyUW = {"person":{"firstName":"Bucky","lastName":"Badger","sessionKey":"111111111","displayName":"Bucky Badger","serverName":"prod","userName":"bbadger"}};
// Get the script document
const thisDoc = (document._currentScript || document.currentScript).ownerDocument;
class MyUWProfile extends HTMLElement {
constructor() {
super();
// Get the script document
const thisDoc = (document._currentScript || document.currentScript).ownerDocument;
this['open-right'] = false;
// Create a shadowroot for this element
this.attachShadow({mode: 'open'});
......@@ -38,15 +162,14 @@ class MyUWProfile extends HTMLElement {
this.shadowRoot.appendChild(template.content.cloneNode(true));
}
static get observedAttributes() {return ['login-url', 'logout-url', 'session-endpoint']; }
static get observedAttributes() {return ['login-url', 'logout-url', 'open-right']; }
attributeChangedCallback(name, oldValue, newValue){
// Update the attribute internally
// console.log(`${name} has updated from "${oldValue}" to "${newValue}"`);
this[name] = newValue;
// Update the component
this.updateComponent();
// Update the component with new att value
this.updateAttribute(name);
}
connectedCallback(){
......@@ -54,68 +177,163 @@ class MyUWProfile extends HTMLElement {
this['login-url'] = this.getAttribute('login-url');
this['logout-url'] = this.getAttribute('logout-url');
this['session-endpoint'] = this.getAttribute('session-endpoint');
this['user'] = false;
if(this.getAttribute('open-right') !== null){
this['open-right'] = true;
}
// Get the user info
// If the session endpoint is set, fetch session info
if(this['session-endpoint']){
this['user'] = testMyUW.person;
// this['user'] = false
fetch(this['session-endpoint'])
.then(res => {
// Check if the request was valid
if(res.status === 200){
res.json()
.then( data => {
// If data.person is not set, return.
if(!data.person){ return; }
// Set user data to the component
this.user = data.person;
this.componentReady();
})
} else {
this.componentReady();
}
})
.catch( e => console.log(e) );
} else {
throw 'No session endpoint has been defiend. Please pass the session endpoint URL into the myuw-profile element!';
this['user'] = false;
throw Error('No session endpoint has been defiend. Please set the "session-endpoint" attribute URL into the myuw-profile element!');
}
// Attach onClick to profile button
this.shadowRoot.getElementById('myuw-profile-circle').addEventListener('click', e => {
e.stopPropagation();
this.shadowRoot.getElementById('myuw-profile-nav').classList.toggle('visible');
/*
Add an on click event to the window.
This allows us to close the menu if the user
clicks anywhere but on the menu.
*/
window.addEventListener('click', e => {
let nav = this.shadowRoot.getElementById('myuw-profile-nav');
if(nav.classList.contains('visible')){
nav.classList.remove('visible')
}
});
/*
Add an on click event to the profile nav menu.
We need to do this in order to stop the propagation
of click events on the menu specifically.
If a user clicks on the nav menu, the window on click
event will not fire, and it will not close the nav menu
*/
this.shadowRoot.getElementById('myuw-profile-nav').addEventListener('click', e => {
e.stopPropagation();
});
/*
Add an on click event to profile bubble
// Add onclick to body
window.addEventListener('click', e => {
let nav = this.shadowRoot.getElementById('myuw-profile-nav');
if(nav.classList.contains('visible')){
nav.classList.remove('visible')
}
We need to make sure that we stop propagation on
this event or else the window on click will always fire
and the menu will never open.
*/
this.shadowRoot.getElementById('myuw-profile-circle').addEventListener('click', e => {
e.stopPropagation();
this.shadowRoot.getElementById('myuw-profile-nav').classList.toggle('visible');
});
// Update the component to use the new attributes
this.updateComponent();
this.updateAttribute('login-url');
this.updateAttribute('logout-url');
this.updateAttribute('session-endpoint');
this.updateAttribute('open-right');
}
updateComponent(){
// Set the Login URL
this.shadowRoot.getElementById('myuw-profile-login').setAttribute('href', this['login-url']);
// Update the component with attribute values
updateAttribute(att){
switch(att){
case 'login-url':
this.shadowRoot.getElementById('myuw-profile-login').setAttribute('href', this['login-url']);
break;
// Set the logout URL
this.shadowRoot.getElementById('myuw-profile-logout').setAttribute('href', this['logout-url']);
case 'logout-url':
this.shadowRoot.getElementById('myuw-profile-logout').setAttribute('href', this['logout-url']);
break;
// Show / hide elements based on shib state
if(this.user){
// Hide login button
this.shadowRoot.getElementById('myuw-profile-login').classList.add('hidden');
// Show Profile circle
this.shadowRoot.getElementById('myuw-profile-wrapper').classList.remove('hidden');
case 'open-right':
if(this['open-right']){
this.shadowRoot.getElementById('myuw-profile-nav').classList.add('open-right');
}
break;
}
}
/*
Function to run after the session endpoint
has been hit and the component has all the
data that it needs to render.
If user data was returned from the endpoint,
the profile bubble will show.
If not, the login button will show.
*/
componentReady(){
if(this.user){
// Add user's name to first menu item
this.shadowRoot.getElementById('myuw-profile-nav-user').innerHTML = this.user.firstName;
// Change the letter in the profile circle
this.shadowRoot.getElementById('myuw-profile-circle-initial').innerHTML = this.user.firstName.substring(0,1);
this.setProfileColor();
this.showProfileBubble();
} else {
// Show Login Button
this.shadowRoot.getElementById('myuw-profile-login').classList.remove('hidden');
// Hide profile Circle
this.shadowRoot.getElementById('myuw-profile-wrapper').classList.add('hidden');
this.showLoginButton();
}
}
/*
Programmatically select a profile background
color based on the length of the users first name
and the first letter of their first name
*/
setProfileColor(){
const colors = [
'#093145',
'#107896',
'#829356',
'#00A996',
'#BCA136',
'#744196'
];
const firstName = this.user.firstName.length;
const initial = this.user.firstName.substring(0,1).charCodeAt();
const colorIndex = (initial + firstName) % colors.length;
this.shadowRoot.getElementById('myuw-profile-circle').style.backgroundColor = colors[colorIndex];
}
showLoginButton(){
// Show Login Button
this.shadowRoot.getElementById('myuw-profile-login').classList.remove('hidden');
// Hide profile Circle
this.shadowRoot.getElementById('myuw-profile-wrapper').classList.add('hidden');
}
showProfileBubble(){
// Hide login button
this.shadowRoot.getElementById('myuw-profile-login').classList.add('hidden');
// Show Profile circle
this.shadowRoot.getElementById('myuw-profile-wrapper').classList.remove('hidden');
}
}
window.customElements.define('myuw-profile', MyUWProfile);
</script>
\ No newline at end of file
{"person":{"firstName":"Bucky","lastName":"Badger","sessionKey":"111111111","displayName":"Bucky Badger","serverName":"prod","userName":"bbadger"}}
\ No newline at end of file
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment