How to change the position of the div after file upload? - javascript

I want to reposition my browse button when the user uploaded a file. This is the sample of how it should really look before and after uploading the file:
Before:
After:
I change the content of my button "Browse file" to "Replace File"
This is my html code.
<div id="uploadModal" class="upload-modal">
<div class="modal-content">
<h2 style="font-size: 24px;">Choose file</h2>
<p>
Choose the csv file containing the data you want to create a forecast for.
</p>
<div class="browse-file">
<div id="filename"></div>
<input type="file" id="file-upload" multiple required />
<label for="file-upload">Browse file</label>
</div>
<div class="options">
<button class="cancel"><h4>Cancel</h4></button>
<button class="proceed"><h4>Proceed</h4></button>
</div>
</div>
</div>
Here is my CSS
.upload-modal {
display: none;
position: fixed;
padding-top: 100px;
left: 0;
top: 0;
width: 100%;
height: 100%;
background-color: rgba(0, 34, 2, 0.3);
}
input[type="file"] {
position: absolute;
opacity: 0;
z-index: -1;
}
input + label {
padding: 10px 24px;
background: #D4E8CF;
border-radius: 100px;
position: static;
width: 119px;
height: 40px;
border: none;
cursor: pointer;
z-index: 1;
}
#filename{
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
max-width: 100px;
justify-content: left;
align-items: flex-start;
}
What's happening here is that my button moves according to the length of the file so I added max-width but no luck. Thanks!
EDIT: I added css for upload-modal

I'm not sure you need to use absolute positioning for what you want.
You could set div#upload-modal or div.modal-content to position: relative;
and then position the button element with left: or right: or use float: right;
https://developer.mozilla.org/en-US/docs/Web/CSS/position
https://developer.mozilla.org/en-US/docs/Web/CSS/float

This alternate version uses CSS's Flexbox and JavaScript's Event Listeners.
It probably doesn't do precisely what you want but should come close enough that reading through the comments a few times and playing around with the code should make clear how you can get to where you want to go using just a few lines of JavaScript to grab the file name and show it on the screen.
MDN (linked above) is a great place to get more clarity about any particular front-end feature that you're interested in using. Happy coding!
// Unnamed function runs as soon as the DOM elements are ready
window.addEventListener('DOMContentLoaded', () => {
// Identifies some of the DOM elements
const
filenameSpan = document.getElementById("filename-span"),
fileInput = document.getElementById("file-input"),
chooseBtn = document.getElementById("choose-btn");
// When the input changes (when a file is chosen), calls `updateDisplay`
fileInput.addEventListener("change", updateDisplay);
// Defines `updateDisplay`
function updateDisplay(){
// Puts first fiename in span and "unhides" it
const filename = fileInput.files[0]?.name;
filenameSpan.textContent = filename || "(choose file)";
filenameSpan.classList.remove("hidden");
};
});
*{
margin: 0;
}
#container{
width: 18rem; /* "rem" unit is the base character height */
padding: 2rem;
border-radius: 1.5rem;
background-color: lightgrey;
}
#header{
margin-bottom: 2rem;
}
#chooser{
/* flex w/ space-around makes choose-btn shift right when filename appears */
display: flex;
justify-content: space-around;
margin-bottom: 4rem;
}
#options{
text-align: right;
}
#filename-span{
padding: 1rem 0;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
max-width: 6rem;
}
button{ /* the "options" buttons */
border: none;
font-weight: bold;
color: darkgreen;
background-color: lightgrey;
}
#choose-btn{
/* Not a true "button" element -- the "label" for file-input */
padding: 1rem 1.5rem;
background-color: darkseagreen;
border-radius: 2rem;
border: none;
font-weight: bold;
}
.hidden{ /* Uses a class so all styling happens thru CSS */
display: none;
}
<div id="container">
<div id="header">
<h2>Choose file</h2>
<p> Choose the csv file containing the data you want to create a forecast for</p>
</div>
<div id="chooser">
<!-- The span and input elements are initially "hidden" via CSS -->
<span id="filename-span" class="hidden"></span>
<label id="choose-btn">
<!-- input element is inside its stylable & clickable label -->
Browse File
<input id="file-input" type="file" class="hidden" />
</label>
</div>
<div id="options">
<button id="cancel-btn">Cancel</button>
<button id="proceed-btn">Proceed</button>
</div>
</div>

Related

Need help to hover different background images in wordpress HTML code

I want exactly like this website: https://www.petzl.com/INT/en
I have displayed background video, 3 texts, by hovering on them the images are changing + links to access them.
But by hovering the text, petzl.com website have activated different images on hover, sometimes different images are appearing on hover.
Can I achieve the different images by css or need to have js or anything? Also need to have span/div elements to appear in one line.
My website link: beta.edgerope.com
Please find code below:
Below is the code, I have added as HTML shortcode in the page and in the background video is displayed
<style>
.image{
height: 800px;
width: 100%;
display: grid;
place-content:center;
justify-content:middle;
color: white;
font-size:30px;
background-color: #;
background-position: center;
background-size: cover;
}
.training{
display:inline-block;
padding-top: 50px;
padding-right: 1500px;
padding-bottom: 50px;
padding-left: 1px;
}
.image>div {
display: inline-block;
width: 100px;
}
.image>div img {
position: absolute;
left: 0;
top: 0;
width: 100%;
height: 100%;
object-fit: cover;
opacity: 0;
z-index: 0;
display: inline-block;
}
.image>div span {
position: relative;
z-index: 1;
cursor: pointer;
display: inline-block;
}
.image>div span:hover+img {
opacity: 1;
display: inline-block;
}
.div{
dipslay
}
</style>
<div class="image">
<div class="services">
<span class="services" onclick="window.location=''">Services</span>
<img src="https://www.petzl.com/sfc/servlet.shepherd/version/download/0686800000D6sSCAAZ">
</div>
<div class="Training">
<span class="training" onclick="window.location='beta.edgerope.com/courses'">Training</span>
<img src="https://beta.edgerope.com/wp-content/uploads/2022/08/1-1-1536x864.jpg"> </div>
<div class="shop">
<span class="shop" onclick="window.location='beta.edgerope.com/shop'">Shop</span>
<img src="https://www.petzl.com/sfc/servlet.shepherd/version/download/0686800000D6sSCAAZ"> </div>
</div>
:
There are many ways to acomplish this, and you should be able to do this with pure css and html.
I've made an example that uses css pseudo elements in order to display the correct image when hovering the sections/links. Also changed up to use a tags instead of using onclick="window.location" as you did.
Here you can change/set the default image in the #hero selector
<style>
/* Styling for the default hero */
#hero {
height: 800px;
width: 100%;
display: flex;
color: black;
background-color: #000;
}
/* Wrapper for all the sections */
.hero-sections {
width: 100%;
height: 100%;
position: relative; /* Allows to change the z-index, and */
z-index: 1;
display: flex;
flex-direction: row;
justify-content: center;
align-items: center;
gap: 2rem;
}
/* Container for the image */
.hero-image::after {
content: "";
position: absolute;
left: 0;
top: 0;
width: 100%;
height: 100%;
z-index: -1; /* Allows the image to appear behind the text */
pointer-events: none; /* Prevent image to show when hovering the ::after element*/
background-image: var(
--bg-url
); /* Uses the images set by the html (css variable) */
opacity: 0; /* Hides the image when it's not active */
transition: opacity 0.5s; /* Adds a fade transition to the opacity*/
}
/* Styles when the the user hovers or has focus on the buttons/links */
.hero-image:is(:hover, :focus-within)::after {
opacity: 1; /* Change the opacity when the text is active/in hover */
}
/* Styles the buttons/links */
.hero-cta {
color: white;
text-decoration: none;
font-size: 2rem;
}
</style>
<div id="hero">
<div class="hero-sections">
<div
class="services hero-image"
style="
--bg-url: url(https://www.petzl.com/sfc/servlet.shepherd/version/download/0686800000D6sSCAAZ);
"
>
<a class="hero-cta" href="#">Services</a>
</div>
<div
class="training hero-image"
style="
--bg-url: url(https://beta.edgerope.com/wp-content/uploads/2022/08/1-1-1536x864.jpg);
"
>
<a class="hero-cta" href="beta.edgerope.com/courses">Training</a>
</div>
<div
class="shop hero-image"
style="
--bg-url: url(https://www.petzl.com/sfc/servlet.shepherd/version/download/0686800000D6sSCAAZ);
"
>
<a class="hero-cta" href="beta.edgerope.com/shop">Shop</a>
</div>
</div>
</div>
If you would like to go more advanced here I would recommend implementing some javascript handling mouseenter and mouseleave. As you said you used Wordpress you could also use the .hover() from jQuery.

How to align the content shown in the image using JavaScript along with redirecting to another page

I am bit troubled in aligning the content as shown in the image. Along with that I need to redirect to page 1 by clicking on content section and redirect to page 2 by clicking the icon separately. How can I solve it using javascript?
These things can be achieved without the use of JavaScript besides the point that it's generally bad practice to manipulate DOM with JavaScript as much can be done with css rules, animations, basic html.
To align the icon first you should try these css rules applied on icon element:
.your-icon {
top: 0;
right: 0;
}
Assuming your icon in html is declared like this:
<img src="foo.img" class="your-icon">
Although it depends on current rules applied (e.g. you should use other rule set if flex is enabled on parent element). Perhaps spacing with fixed values between content section is involved that is pushing the icon out of the way (padding, margin rules applied?).
As for navigation html href is good enough
.a {
/* width:400px; */
height: 300px;
border: 1px solid;
}
.b {
width: 100%;
float: left;
/* border:1px solid red; */
}
.c {
width: 70%;
/* border:1px solid; */
float: left;
/* display:flex; */
float: left;
}
.c div{padding: 5px;}
.d {
border: 1px solid;
}
.box {
width: 29%;
float: left;
border: 1px solid;
height: 100%;
}
.rTable {
display: block;
width: 100%;
}
.rTableHeading,
.rTableBody,
.rTableFoot,
.rTableRow {
clear: both;
}
.rTableHead,
.rTableFoot {
/* background-color: #DDD; */
font-weight: bold;
}
.rTableCell,
.rTableHead {
/* border: 1px solid #999999; */
float: left;
height: 17px;
overflow: hidden;
padding: 5px;
width: 20%;
}
.rTable:after {
visibility: hidden;
display: block;
font-size: 0;
content: " ";
clear: both;
height: 0;
}
<div class='a'>
<div class='b'>
<div class='c'>
<div>Name</div>
<div>Address</div>
<div>PIN</div>
</div>
<div class='box'>ICON</div>
</div>
<div class='d'>
<div class="rTable">
<div class="rTableRow">
<div class="rTableHead"><strong>Time</strong></div>
<div class="rTableHead"><span style="font-weight: bold;">Duration</span></div>
<div class="rTableHead"><strong>Amount</strong></div>
<div class="rTableHead"><strong>Position</strong></div>
</div>
<div class="rTableRow">
<div class="rTableCell">5</div>
<div class="rTableCell">2</div>
<div class="rTableCell">3</div>
<div class="rTableCell">4</div>
</div>
</div>
</div>
</div>

How do I reuse an HTML element on the same page using jQuery?

I created a div element called main-middle-column-container in my HTML and styled it with CSS. Basically, main-middle-column-container will create a twitter-like message box that will have a name, date/time, and the message.
I want to reuse main-middle-column-container and all the code inside of it with jQuery so that when new data comes in, it will use a fresh main-middle-column-container as a template to add in the new values (like how twitter would work). When new data comes in, #username, date/time, and This is a random message. #random will be replaced with the incoming data or leave the elements empty and have the new data fill it in.
I thought about using $('.main-middle-column-container').clone().appendTo('.main-middle-column-wrapper'); but that will keep double cloning it (1 box -> 2 box -> 4 box -> 8 box...) instead of cloning it once. I also have an issue of getting rid of main-middle-column-container before I receive any data because I don't want an empty box on the website I am trying to create. I want main-middle-column-container to be created right when I get some kind of data/message.
CSS and HTML (message box)
.main-middle-column-wrapper{
display: flex;
flex-direction: column;
width: 49%;
}
.main-middle-column-container{
width: 100%;
}
.main-middle-column{
font-family: "Helvetica Neue", Helvetica, Arial ,sans-serif;
font-size: 14px;
height: auto;
width: 100%;
background-color: white;
padding: 9px 12px;
z-index: -2;
box-shadow: 0 0 2px 0 lightgray;
position: relative;
}
.main-middle-column:hover{
background-color: hsl(200, 23%, 96%);
}
.tweet-pic-wrapper{
position: absolute;
top: 5px;
}
.tweet-pic-container{
position: relative;
height: 48px;
width: 48px;
border: 3px solid transparent;
border-radius: 100%;
overflow: hidden;
z-index: 1;
display: inline-block;
}
.tweet-pic{
position: absolute;
margin: 0 auto;
height: 100%;
left: -6px;
width: auto;
}
.title-account-time{
margin-left: 55px;
}
.msg-title{
font-weight: bold;
}
.msg-acc-name{
color: #657786;
}
.msg-acc-name:hover{
cursor: pointer;
}
.msg-date{
color: #657786;
margin-top: 1px;
}
.tweet-msg{
margin-left: 55px;
margin-top: 5px;
}
<div class="main-middle-column-wrapper">
<div class="main-middle-column-container">
<div class="main-middle-column">
<div class="tweet-pic-wrapper">
<div class="tweet-pic-container">
<img src="Picture of the Moon.jpeg" class="tweet-pic" alt="Picture of the moon.">
</div>
</div>
<div class="title-account-time">
<span class="msg-title">My Twitter</span>
<span class="msg-acc-name">#username</span>
<div class="msg-date">date/time</div>
</div>
<div class="tweet-msg">
This is a random message. #random
</div>
</div>
</div>
</div>
I think i have a solution for you, you can create a 'template' and retrieve that template with jquery.
If you put this in your main html file
<script id="hidden-template" type="text/x-custom-template">
<div class="main-middle-column-wrapper">
<div class="main-middle-column-container">
<div class="main-middle-column">
<div class="tweet-pic-wrapper">
<div class="tweet-pic-container">
<img src="Picture of the Moon.jpeg" class="tweet-pic" alt="Picture of the moon.">
</div>
</div>
<div class="title-account-time">
<span class="msg-title">My Twitter</span>
<span class="msg-acc-name">#username</span>
<div class="msg-date">date/time</div>
</div>
<div class="tweet-msg">
this is a story all about how my life got flipped turned upside down and id like to take a minute and just sit right there id like to tell you how i became a prince in a town called belair.
</div>
</div>
</div>
</div>
</script>
You can get the content with jquery like this
var template = $('#hidden-template').html();
Now you have your html 'template' in your javascipt, now your can create more than one of these elements.
$('#target').append(template);
Or you can use a better/simpler method with plain javascript
const card = ({ img_alt, img_src, title, username, date, msg }) => `
<div class="main-middle-column-wrapper">
<div class="main-middle-column-container">
<div class="main-middle-column">
<div class="tweet-pic-wrapper">
<div class="tweet-pic-container">
<img src="${img_src}" class="tweet-pic" alt="${img_alt}">
</div>
</div>
<div class="title-account-time">
<span class="msg-title">${title}</span>
<span class="msg-acc-name">#${username}</span>
<div class="msg-date">${date}</div>
</div>
<div class="tweet-msg">${msg}</div>
</div>
</div>
</div>
`;
You can use this as a function to create your elements dynamically with all kinds of data.
Create a function that returns a Template Literal with the desired HTML markup structure. Map your tweets and insert them into a target parent:
const tweets = [
{
_id: 321,
pic: "https://placehold.it/80x80/0bf",
title: "My Twitter",
name: "#username",
date: "2020-01-18",
msg: "this is a story"
},
{
_id: 231,
pic: "https://placehold.it/80x80/f0b",
title: "My alter Twitter",
name: "#user",
date: "2020-01-19",
msg: "Again, another story"
}
];
const newTweet = tweet => `<div class="main-middle-column">
<div class="tweet-pic-wrapper">
<div class="tweet-pic-container">
<img src="${tweet.pic}" class="tweet-pic" alt="${tweet.title}">
</div>
</div>
<div class="title-account-time">
<span class="msg-title">${tweet.title}</span>
<span class="msg-acc-name">${tweet.name}</span>
<div class="msg-date">${tweet.date}</div>
</div>
<div class="tweet-msg">${tweet.msg}</div>
</div>`;
const populateNewTweets = (tweets, parent) => {
if (!tweets.length) return;
$('<div>', {
class: 'main-middle-column-container',
appendTo: parent,
append: tweets.map(newTweet)
});
};
populateNewTweets(tweets, '.main-middle-column-wrapper');
.main-middle-column-wrapper{
display: flex;
flex-direction: column;
width: 49%;
}
.main-middle-column-container{
width: 100%;
}
.main-middle-column{
font-family: "Helvetica Neue", Helvetica, Arial ,sans-serif;
font-size: 14px;
height: auto;
width: 100%;
background-color: white;
padding: 9px 12px;
z-index: -2;
box-shadow: 0 0 2px 0 lightgray;
position: relative;
}
.main-middle-column:hover{
background-color: hsl(200, 23%, 96%);
}
.tweet-pic-wrapper{
position: absolute;
top: 5px;
}
.tweet-pic-container{
position: relative;
height: 48px;
width: 48px;
border: 3px solid transparent;
border-radius: 100%;
overflow: hidden;
z-index: 1;
display: inline-block;
}
.tweet-pic{
position: absolute;
margin: 0 auto;
height: 100%;
left: -6px;
width: auto;
}
.title-account-time{
margin-left: 55px;
}
.msg-title{
font-weight: bold;
}
.msg-acc-name{
color: #657786;
}
.msg-acc-name:hover{
cursor: pointer;
}
.msg-date{
color: #657786;
margin-top: 1px;
}
.tweet-msg{
margin-left: 55px;
margin-top: 5px;
}
<div class="main-middle-column-wrapper"></div>
<script src="https://code.jquery.com/jquery-3.4.1.min.js"></script>
The best solution to this would be to use some kind of templating engine, for example Mustache. If that however is out of the question, the solution to your problem would be something like this:
jQuery(document).ready(function() {
/* this should store the container templates clone in a variable */
mainMiddleContainerTemplate = jQuery(".main-middle-column-container").get(0).clone();
/* this should remove every main middle container from the view, in case
you have multiple containers that are not templates, consider adding
an additional class to your template container */
jQuery(".main-middle-column-container").remove();
});
function addNewContainer(containerData) {
var newContainer = mainMiddleContainerTemplate.clone();
/** add and replace all the data needed on the newContainer **/
newContainer.find('.message-title').html(containerData.title);
newContainer.find('.msg-acc-name').html(containerData.accountName);
....
jQuery(".main-middle-container-wrapper").append(newContainer);
}
But still, I would advice you, to use a templating engine for these kinds of stuff.
$('.main-middle-column-container').first().clone().appendTo('.main-middle-column-wrapper');
The key is to select only one element to be cloned. First is as good as any other.

Is there a way to jump from a section into another section with Vanilla JavaScript?

I have two sections one over the other.
What I want to do is that when I click the button, the first section display: none with a small transition and the second one appears. I need to do that with vanilla JavaScript as I'm learning it.
My goal is to be able to create a login when the password is entered, the person is moved to the second section. (this is just for Front end, nothing backend).
Here is the code below:
*{
margin: 0;
padding: 0;
box-sizing: border-box;
}
/* Login Background */
#first{
position: absolute;
width: 100%;
height: 100vh;
background-color: #464159;
z-index: 1;
}
/* Login */
.login-container{
position: absolute;
top: 50%;
right: 50%;
transform: translate(50%, -100%);
display: flex;
align-items: center;
justify-content: center;
}
.logo{
justify-content: center;
margin-right: 20px;
}
.logo img{
width: 180px;
height: auto;
}
.user{
display: flex;
flex-direction: column;
}
.w8u{
color: white;
font-size: 15px;
margin: 0 0 10px 0;
}
.submit{
flex: 1;
margin: 30px 0 0 10px;
}
/* Menu */
#second{
position: absolute;
width: 100%;
height: 100vh;
background-color: orangered;
z-index: -1;
}
<body>
<section id="first">
<div class="login-container">
<!-- Logo User -->
<div class="logo">
<img src="w-logo.jpg" alt="User">
</div>
<!-- User Name -->
<div class="user">
<div class="w8u">
<h3>User</h3>
</div>
<div>
<input class="input" type="password" placeholder="Enter your password" required>
</div>
</div>
<!-- Submit Button -->
<button id="btn-submit" class="submit" type="submit" onclick="">GO!</button>
</section>
<section id="second">
</section>
<script src="app.js"></script>
</body>
Yes, you can change CSS of elements using JavaScript:
function login(){
document.getElementById("first").style.display="none";
document.getElementById("second").style.display="block";
}
*{
margin: 0;
padding: 0;
box-sizing: border-box;
}
/* Login Background */
#first{
position: absolute;
width: 100%;
height: 100vh;
background-color: #464159;
z-index: 1;
}
/* Login */
.login-container{
position: absolute;
top: 50%;
right: 50%;
transform: translate(50%, -100%);
display: flex;
align-items: center;
justify-content: center;
}
.logo{
justify-content: center;
margin-right: 20px;
}
.logo img{
width: 180px;
height: auto;
}
.user{
display: flex;
flex-direction: column;
}
.w8u{
color: white;
font-size: 15px;
margin: 0 0 10px 0;
}
.submit{
flex: 1;
margin: 30px 0 0 10px;
}
/* Menu */
#second{
position: absolute;
width: 100%;
height: 100vh;
background-color: orangered;
z-index: -1;
}
<body>
<section id="first">
<div class="login-container">
<!-- Logo User -->
<div class="logo">
<img src="w-logo.jpg" alt="User">
</div>
<!-- User Name -->
<div class="user">
<div class="w8u">
<h3>User</h3>
</div>
<div>
<input class="input" type="password" placeholder="Enter your password" required>
</div>
</div>
<!-- Submit Button -->
<button id="btn-submit" class="submit" type="submit" onclick="login()">GO!</button>
</section>
<section id="second">
Section 2
</section>
<script>
</script>
</body>
Short Answer:
You can solve your issue by using a common pattern of styling transitions and toggling classes in JavaScript.
/* Get Screen Container */
let context = document.querySelector("main.screen-container");
/* Helper Methods */
// Utility
const ele = context.querySelector.bind(context),
eles = context.querySelectorAll.bind(context);
// Action
const showScreen = inactiveScreen => {
const screens = eles(".screen");
screens.forEach(screen => screen.classList.remove("active-screen"));
inactiveScreen.classList.add("active-screen");
}
// Elements
const login_button = ele("#loginBtn"),
logout_button = ele("#logoutBtn"),
login_screen = ele("#login"),
loggedIn_screen = ele("#loggedIn");
// Add Event Listeners and Handlers
login_button.addEventListener("click", () => showScreen(loggedIn_screen));
logout_button.addEventListener("click", () => showScreen(login_screen));
.full-width-full-height {
width: 100%;
height: 100%;
}
.no-overflow {
overflow: hidden;
}
.inputs-container {
display: flex;
flex-direction: column;
justify-content: center;
height: 200px;
padding: 5px;
border: 5px black solid;
}
.inputs-container.inputs {
padding: 10px;
}
.screen#login {
display: flex;
justify-content: center;
}
.screen#loggedIn {
background: rgba(0,0,0,.5);
border: 5px solid rgba(0,0,0,.3);
text-align: center;
}
highlight {
color: rgb(0,100,0);
text-shadow: 3px 3px 10px rgb(0,200,0);
}
.screen-container {
height: 100%;
width: 100%;
overflow: hidden;
padding: 0px;
margin: 0px;
}
main section {
position: absolute;
height: 0px;
width: 0px;
opacity: 0;
transition: all .3s ease-in-out;
}
main section.active-screen {
height: 100%;
width: 100%;
opacity: 1;
}
<body class="full-width-full-height no-overflow">
<main class="screen-container full-width-full-height">
<section id="login" class="screen active-screen">
<div class="inputs-container">
<div class="inputs"><label>Username:</label><input type="text" id="username" placeholder="admin" /></div>
<div class="inputs"><label>Password:</label><input type="password" id="password" /></div>
<button id="loginBtn">login</button>
</div>
</section>
<section id="loggedIn" class="screen">
<h3>User Successfully <highlight>Logged In</highlight></h3>
<button id="logoutBtn">logout</button>
</section>
</main>
</body>
Explanation of Answer:
In your question you're asking for help in the following:
Using Sections as Different Screens in an Application
Change Screens on an Event such as click
Transition between Screens when the Screen Changes
Something like this isn't an atypical need and, in fact, just looking at the above you can see the resemblance between what you're looking for and common things like a carousel or tab navigation.
Since this is the case there is a pretty common pattern when designing markup based around these types of requirements and this pattern is used in frameworks like BootStrap, DataTables, JQuery, etc.
The Mark-Up Pattern:
Create a Container
Provide a class to define this type of container ( screen-container )
Create Visual Elements
In your case Section Elements dubbed Screens
Provide a class to define these specific elements
In your case something like screen
You will likely also want to provide an ID for each of these Visual Elements based on their Content.
In your case something like login and loggedIn
Create a class that will serve as the active Visual Element
In your case something like active-screen
Incorporating the above you end up with a basic outline:
<main class="screen-container">
<section id="login" class="screen active-screen"></section>
<section id="loggedIn" class="screen"></section>
</main>
Example:
html, body, main, .screen-container {
height: 100%;
width: 100%;
}
.screen-container
.screen {
padding: 3px;
background: rgba(24,24,24, .3);
border: 3px solid black;
width: 100px;
height: 100px;
}
.screen-container
.screen.active-screen {
border-color: green;
}
<main class="screen-container">
<section id="login" class="screen active-screen">login</section>
<section id="loggedIn" class="screen">logged in</section>
</main>
Styling:
In your initial question you say that you want to use the display property to hide and show your screens, however, you also state that you would like to have the screens transition from one to another.
Transitioning is definitely possible through the aptly named CSS transition property ( More info on MDN ).
The problem is that the display property is not able to be animated. If an element is configured to display: none; the page is immediately repainted with that element removed.
This means that you need to use a different property, and we typically would use opacity or visibility. Here are the differences between these three:
display: none;
immediately collapses the element
removes the element from view.
There's no transition allowed.
visibility: hidden;
Does not collapse the element
The space it occupied is blank.
removes the element from view
Transitions are allowed
The element will still pop out of sight.
opacity: 0;
Does not collapse the element
The space it occupied is blank.
removes the element from view
Transitions are allowed.
The element will fade until it is not visible.
Here is an example of the different way these properties affect the layout of the page:
const context = document.querySelector("#examples");
const ele = context.querySelector.bind(context),
hide = section => section.classList.toggle("hide"),
onClickHide = (btn, section) => btn.addEventListener("click", () => hide(section));
opacity = ele(".opacity"),
opacity_button = ele("#oBtn"),
visibility = ele(".visibility"),
visibility_button = ele("#vBtn"),
display = ele(".display"),
display_button = ele("#dBtn"),
toggle_button = ele("#tBtn");
onClickHide(opacity_button, opacity);
onClickHide(visibility_button, visibility);
onClickHide(display_button, display);
toggle_button
.addEventListener("click", function() {
hide(opacity);
hide(visibility);
hide(display);
});
html,
body,
#examples {
width: 100%;
height: 100%;
box-sizing: content-box;
margin: 0px;
padding: 0px;
}
#examples section {
display: flex;
flex-direction: column;
width: 100px;
height: 100px;
border: 5px solid black;
margin: 5px;
transition: all .5s ease-in-out;
}
#examples section.hide {
border-radius: 100px;
}
#examples section.opacity {
background-color: blue;
color: white;
}
#examples section.opacity.hide {
opacity: 0;
}
#examples section.visibility {
background-color: purple;
color: white;
}
#examples section.visibility.hide {
visibility: hidden;
}
#examples section.display {
display: block;
background-color: red;
color: white;
}
#examples section.display.hide {
color: black;
display: none;
}
<main id="examples">
<section class="opacity">opacity <button id="oBtn">hide</button></section>
<hr />
<section class="visibility">visibility <button id="vBtn">hide</button></section>
<hr />
<section class="display">display <button id="dBtn">hide</button></section>
<hr/>
<button id="tBtn">Toggle All</button>
</main>
Note: In the above there are actually two properties transitioning - opacity, visibility, or display - and border-radius. You should notice firstly how in the display example the border-radius change isn't seen at all, and secondly how the display example is the only one that collapses the element so that it no longer takes up space.
Applying Transitions:
By combining opacity: 0; with height: 0px; width: 0px; we can remove the element visually from the page while also removing any impact it has on other elements - meaning that it won't take up space and is transitionable.
setInterval(function() {
const screens = [
document.querySelector(".screen.active-screen"),
document.querySelector(".screen:not(.active-screen)")
];
screens[0].classList.toggle("active-screen");
screens[0].ontransitionend = () => {
screens[1].classList.toggle("active-screen");
screens[0].ontransitionend = undefined;
}
}, 1000)
html,
body,
main,
.screen-container {
height: 100%;
width: 100%;
}
.screen-container .screen {
transition: all .3s ease-in-out;
opacity: 0;
height: 0px;
width: 0px;
}
.screen-container .screen.active-screen {
background: rgba(24, 24, 24, .3);
border: 3px solid black;
padding: 3px;
border-color: green;
width: 100px;
height: 100px;
opacity: 1;
}
<main class="screen-container">
<section id="login" class="screen active-screen">login</section>
<section id="loggedIn" class="screen">logged in</section>
</main>
JavaScript
The final piece of the puzzle is the JavaScript mechanics of the Screens.
Any Programmer wants to make the switch as easy as possible, and this is done typically by providing a function that allows for quick reassignment of the class active-screen by removing it from the current active screen and applying it to the desired visual element.
One thing to take into account is that you want your queries for elements to be as specific as possible. Meaning that instead of document.querySelector you want to provide the smallest context of where to find your Visual Elements. a.e.
/* Get Screen Container */
let context = document.querySelector("main.screen-container");
/* Helper Methods */
// Utility
const ele = context.querySelector.bind(context),
eles = context.querySelectorAll.bind(context);
This prevents code collision where other code in your Application's JavaScript, Styling, or Mark-Up may utilize a screen or active-screen class that isn't relevant to what you're doing here.
Note: This is actually a problem in BootStrap currently. It searches for the active class in it's Tab architecture. This is such a generic class name that other libraries utilize it and it can cause a giant headache to get things to work properly. Writing explicit patching because you didn't think through your design fully is something I'd just as soon spare you from, so try to keep interactivity with other code in mind.
Lastly we write our function ( showScreen ) that allow for quick, easy switching between screens:
// Action
const showScreen = inactiveScreen => {
const screens = eles(".screen");
screens.forEach(screen => screen.classList.remove("active-screen"));
inactiveScreen.classList.add("active-screen");
}
And believe it or not, that's pretty much it!
All that's left to do is apply this functionality to your button click events and it works just as it should:
Result:
/* Get Screen Container */
let context = document.querySelector("main.screen-container");
/* Helper Methods */
// Utility
const ele = context.querySelector.bind(context),
eles = context.querySelectorAll.bind(context);
// Action
const showScreen = inactiveScreen => {
const screens = eles(".screen");
screens.forEach(screen => screen.classList.remove("active-screen"));
inactiveScreen.classList.add("active-screen");
}
// Elements
const login_button = ele("#loginBtn"),
logout_button = ele("#logoutBtn"),
login_screen = ele("#login"),
loggedIn_screen = ele("#loggedIn");
// Add Event Listeners and Handlers
login_button.addEventListener("click", () => showScreen(loggedIn_screen));
logout_button.addEventListener("click", () => showScreen(login_screen));
.full-width-full-height {
width: 100%;
height: 100%;
}
.no-overflow {
overflow: hidden;
}
.inputs-container {
display: flex;
flex-direction: column;
justify-content: center;
height: 200px;
padding: 5px;
border: 5px black solid;
}
.inputs-container.inputs {
padding: 10px;
}
.screen#login {
display: flex;
justify-content: center;
}
.screen#loggedIn {
background: rgba(0,0,0,.5);
border: 5px solid rgba(0,0,0,.3);
text-align: center;
}
highlight {
color: rgb(0,100,0);
text-shadow: 3px 3px 10px rgb(0,200,0);
}
.screen-container {
height: 100%;
width: 100%;
overflow: hidden;
padding: 0px;
margin: 0px;
}
main section {
position: absolute;
height: 0px;
width: 0px;
opacity: 0;
transition: all .3s ease-in-out;
}
main section.active-screen {
height: 100%;
width: 100%;
opacity: 1;
}
<body class="full-width-full-height no-overflow">
<main class="screen-container full-width-full-height">
<section id="login" class="screen active-screen">
<div class="inputs-container">
<div class="inputs"><label>Username:</label><input type="text" id="username" placeholder="admin" /></div>
<div class="inputs"><label>Password:</label><input type="password" id="password" /></div>
<button id="loginBtn">login</button>
</div>
</section>
<section id="loggedIn" class="screen">
<h3>User Successfully <highlight>Logged In</highlight></h3>
<button id="logoutBtn">logout</button>
</section>
</main>
</body>
Conclusion:
I hope this helps and gives you some insight into how this pattern is used! It's not a difficult thing to learn, but it's incredibly useful!
Good luck and Happy Coding!

How to show HTML video overlays with VideoJS in fullscreen?

I have a quiz video overlay that shows up nicely when the videojs player is in standard mode: https://jsfiddle.net/c4nxdf38/
However, when entering fullscreen it disappears (probably behind the video).
I found an obsolete solution which specifies the z-index of the overlay to the maximum. It is not working in the latest Chrome and Firefox.
I found another solution to do the fullscreen with the parent, not the videoplayer itself, but it's not working with the videojs player setup.
Then I found a promising solution how to make overlay elements appear on fullscreen by setting position:absolute; and tried to implement it without success: https://jsfiddle.net/5Lqfyzh4/
HTML from my last attempt (see fiddle):
<div id="main-container">
<div id="overlays-wrap">
<div class="overlay-item" data-overlayid="59" data-time="41">
<p class="vo-question">
Welche Zahl ist die Summe bei 3 + 50 = 53?
</p>
<div class="vtask-choices-wrap">
<div class="vtask-choice-item">
<input class="vtask-choice" type="radio" name="quiz" id="59-a1" value="1" data-correct="0">
<label class="radio-tile" for="59-a1">
<span class="radio-tile-label">
3
</span>
</label>
</div>
<div class="vtask-choice-item">
<input class="vtask-choice" type="radio" name="quiz" id="59-a2" data-correct="0">
<label class="radio-tile" for="59-a2">
<span class="radio-tile-label">
50
</span>
</label>
</div>
<div class="vtask-choice-item">
<input class="vtask-choice" type="radio" name="quiz" id="59-a3" value="3" data-correct="1">
<label class="radio-tile" for="59-a3">
<span class="radio-tile-label">
53
</span>
</label>
</div>
</div> <!-- vtask-choices-wrap -->
<a class="buttonb vtask-btn-continue">Continue</a>
</div> <!-- overlay-item -->
</div>
<div id="videowrapper">
<video id="videoplay" class="video-js vjs-default-skin" controls preload="metadata" width="854" height="480" poster="" autoplay="true">
<source src="http://vjs.zencdn.net/v/oceans.mp4" type="video/mp4">
</video>
</div>
</div>
Javascript:
$(document).ready(function() {
var options = {
playbackRates: [1, 1.5, 2],
muted: true,
};
video = videojs('videoplay', options);
video.ready(function() {
/*
this.on('fullscreenchange',function() {
console.log('fullscreen event');
});
*/
}); // end video.ready
// OVERLAY PREPARE
// $('#overlays-wrap, .overlay-item').hide();
// OVERLAY INTERACTION
$('.radio-tile').click( function() {
// only show if not yet submitted, prevents submit then click again on radio-tile which would show the vtask-btn-continue
var submitted = $(this).closest('.overlay-item').hasClass('overlay-submitted');
if(!submitted)
{
$(this).parent().parent().next('.vtask-btn-continue').css('visibility', 'visible');
// make sure we check the radio button
$(this).prev('.vtask-choice').prop('checked', true);
}
});
$('.vtask-btn-continue').click( function() {
// hide continue button
$(this).css('visibility', 'hidden');
var overlay = $(this).closest('.overlay-item'); // $(this).parent()
overlay.hide();
});
}); // END ready
CSS:
#overlays-wrap {
position: absolute;
width: 100%;
height: 100%;
max-height:460px;
left: 0;
top: 0;
z-index: 2147483647;
}
.overlay-item {
position: absolute;
top: 0;
color: #FFF;
font-size: 20px;
background-color: rgba(0, 0, 0, 0.85);
width: 100%;
height: 100%;
padding: 0;
z-index: 2147483647;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
backface-visibility: hidden;
}
.overlay-item .vo-question {
margin: 10px 0 40px 0;
width: 80%;
text-align: center;
line-height: 1.5;
}
.vtask-choices-wrap {
display: flex;
flex-direction: row;
align-items: flex-start;
justify-content: space-evenly;
width: 100%;
max-width: 1000px;
min-height: 10rem;
}
.vtask-choice-item .vtask-choice {
opacity: 0;
position: absolute;
top: 0;
left: 0;
}
.radio-tile {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
width: 100%;
height: 100%;
border: 2px solid #079ad9;
border-radius: 5px;
padding: 1rem;
transition: transform 300ms ease;
background: rgba(0,0,0,0.5);
z-index: 500;
cursor: pointer;
font-size: 18px;
text-align: center;
}
.vtask-btn-continue {
color: #FFFFFF!important;
border-color: #2B78C5;
border-bottom-color: #2a65a0;
text-decoration: none;
text-shadow: none;
color: #FFF;
background: #39F;
margin-top: 40px;
padding: 10px 20px;
font-family: Arial,sans-serif;
font-size: 16px;
}
/* FIX according https://stackoverflow.com/a/13388579/1066234 */
#videoplay {
position: absolute;
left: 0px;
top: 0px;
min-height: 100%;
min-width: 100%;
z-index: 9997;
}
#overlays-wrap {
position: absolute;
left: 0px;
top: 0px;
height: 100%;
width: 100%;
z-index: 9998;
}
#main_container {
float: left;
position: relative;
left:0;
top:0;
}
Interestingly, with the videojs plugin at https://github.com/brightcove/videojs-overlay the fullscreen overlays seem to work even on fullscreen. But I cannot figure out how it is doing it. – Demo: http://www.xfaktor.com/overlay/overlay_kroger.html – I have more complex HTML for my overlays and cannot use this plugin.
What is the solution for this video/videojs problem?
Probably it would be best if you can help, having the starting point of this fiddle (my recent implementation): https://jsfiddle.net/w5f7mk19/ Thanks!
The problem appears to be, that this library wraps the video in an additional div, and makes that div fullscreen - but your #overlays-wrap element is outside of that element, and I don’t think z-index is supposed to change anything about that(?).
Putting the overlay directly into #videowrapper in the source code doesn’t do the trick - the player library takes #videoplay, creates the wrapper div and puts the id on that. (It changes the id of the video element itself to #videoplay_html5_api, so no conflict in that regard.) The new div #videoplay becomes fullscreen, but #overlays-wrap still only is a sibling in the DOM, so outside of the fullscreen element.
But if you move #overlays-wrap into #videoplay after the player has initialized, it seems to work:
video = videojs('videoplay', options); // wraps video element into div#videoplay
$('#overlays-wrap').appendTo($('#videoplay')); // append #overlays-wrap to div#videoplay
https://jsfiddle.net/pw89cjqe/

Categories