How to Make a CSS-Only Carousel

We mentioned a way to make a CSS-only carousel in a recent issue of the newsletter and I thought that a more detailed write up would be interesting and capture some of my thoughts on making one.

So, here’s what we’re making today:

There’s no JavaScript here, whatsoever! No jQuery plugins. No trickiness. Just a couple of new-ish CSS properties that I’ve been experimenting with as well as some basic HTML.

OK to start, we need to focus on the markup. The design includes a left navigation made up of images and a large image gallery on the right that lets us scroll through each image individually. We’ll also need a wrapper to help us organize the layout:

<div class="wrapper">
  <nav class="lil-nav"></nav>
  <div class="gallery"></div>
</div>

Next, we can add images! For this little example, I checked out our list of sites with high quality images that you can use for free and went with Unsplash.

After saving images with the CodePen asset manager, I started adding the URLs to the nav element:

<nav class="lil-nav">
  <a href="#image-1">
    <img class="lil-nav__img" src="..." alt="Yosemite" />
  </a>
  <a href="#image-2">
    <img class="lil-nav__img" src="..." alt="Basketball hoop" />
  </a>
  <!-- more images go here --> 
</nav>

See that the href to each of these links is pointing to an ID? That’s because if we look at the demo again, we want to be able to click an image and then we want to it to hop to the larger version of that image in the gallery to the right.

So, now we can start to add these images to the large gallery, too…

<div class="gallery">
  <img class="gallery__img" id="image-1" src="..." alt="Yosemite" />
  <img class="gallery__img" id="image-2" src="..." alt="Basketball hoop" />
  <!-- more images go here --> 
</div>

Nifty. Next is the fun part: styling this bad boy. We can use a grid layout the parent .wrapper and set some smart defaults for the img element:

img {
  display: block;
  max-width: 100%;
}

.wrapper {
  display: grid;
  grid-template-columns: 1fr 5fr;
  grid-gap: 20px;
}

So far, we have our layout sorted and our links set up. Next, let’s any any overflow that might spill outside our wrapper and make sure that the nav and the gallery are scrollable:

.wrapper {
  display: grid;
  grid-template-columns: 1fr 5fr;
  grid-gap: 10px;
  overflow: hidden;
  height: 100vh; 
}

.gallery {
  overflow: scroll;
}

.lil-nav {
  overflow-y: scroll;
  overflow-x: hidden;
}

We can scroll through each image in the gallery now, but if this was a production website we’d probably want to make sure that folks can scroll passed this carousel a bit more easily. Trent Walton wrote about this very problem several years ago and I think it’s always worth keeping in mind.

Next up, let’s focus on the carousel snap of each image in the gallery. To do that we’ll need to use the scroll-snap-type and scroll-snap-align property like this:

.gallery {
  overflow: scroll;
  scroll-snap-type: x mandatory;
}

.gallery__img {
  scroll-snap-align: start;
  margin-bottom: 10px;
}

Now try scrolling through the gallery on the right-hand side again:

If you want to learn more about these properties I’d highly recommend this piece about practical CSS scroll snapping which digs into the nitty-gritty of these properties.

We have a pretty dang usable carousel! From here, all we have to do is tidy up the design because the gallery image isn’t the full height of the screen. To do that we can use object-fit and give each image a min-height with the vh unit, just like this:

.gallery__img {
  scroll-snap-align: start;
  margin-bottom: 10px;
  min-height: 100vh;
  object-fit: cover;
}

Now the big gallery images will always be the full size of the screen and will scale to take up the width and height. Let’s move on and tackle the style of the little navigation images:

.lil-nav {
  overflow-y: scroll;
  overflow-x: hidden;
}

.lil-nav a {
  height: 200px;
  display: flex;
  margin-bottom: 10px;
}

.lil-nav__img {
  object-fit: cover;
}

At first, I made this little nav act like a carousel too, but it felt really weird. I’m just keeping the default scroll behavior for now. In that demo above, though, try clicking an image. Notice how it jumps to that image in the carousel immediately? It would be nice if we could animate that transition a bit — and we can!

.gallery {
  overflow: scroll;
  scroll-snap-type: x mandatory;
  scroll-behavior: smooth;
}

That scroll-behavior CSS property is super handy for this and so now the whole thing will animate if you click one of the nav items:

Nifty, eh? One more tiny thing we could do here is throw a filter on the nav items to make them black and white and then animate them on hover:

.lil-nav__img {
  object-fit: cover;
  filter: saturate(0);
  transition: 0.3s ease all;
}

.lil-nav__img:hover {
  transform: scale(1.05);
  filter: saturate(1);
}

I’m sure there’s a lot more we could do here but I think this works quite nicely!

We could even throw a tiny bit of JavaScript into the mix to show which image is active, but I reckon that folks know that just from looking at the gallery.

That’s it! We now have a carousel that’s pretty dang good for progressive enhancement and it means we don’t have to load a library of JavaScript or write a bunch more code than we really need to.

Making the carousel responsive…

Let’s go one step further though and make this chap responsive. What we want to do is reverse the order of our grid by moving all of our current styles into a media query that is only activated at larger screens.

You might want to open up this demo in a new tab and decrease/increase the size of the browser to see the changes take place:

If you load this demo on a mobile device you should see how the layout switches between the two modes. This is done by using a single media query on the .wrapper element. Note that we’re using Sass:

$large: 1200px;

.wrapper {
  overflow: hidden;
  height: 100vh;
  display: grid;
  grid-template-rows: 2fr 1fr;
  grid-gap: 10px;

  @media screen and (min-width: $large) {
    grid-template-columns: 1fr 5fr;
    grid-template-rows: auto;
  }
}

Let’s add one on the navigation, too. But this time, we need to tell the navigation to start on the second row so it moves to the bottom of the screen:

.lil-nav {
  overflow-x: scroll;
  overflow-y: hidden;
  display: flex;
  grid-row-start: 2;

  @media screen and (min-width: $large) {
    overflow-y: scroll;
    overflow-x: hidden;
    display: block;
    grid-row-start: auto;
  }
}

With the gallery we need to switch around the scroll-type for larger screens and reverse the overflow property as well:

.gallery {
  overflow-x: scroll;
  overflow-y: hidden;
  scroll-snap-type: x mandatory;
  scroll-behavior: smooth;
  display: flex;

  @media screen and (min-width: $large) {
    display: block;
    overflow-y: scroll;
    overflow-x: hidden;
    scroll-snap-type: y mandatory;
  }
}

That’s the bulk of the changes we’ve had to make and I quite like it! If we wanted to make this production-ready, we would think about accessibility (e.g. we probably don’t want screen readers to read out all the images in both the nav and gallery). Then there’s performance — we might consider lazy-loading so the images are only rendered when they’re needed.

Either way, this is a good start !

The post How to Make a CSS-Only Carousel appeared first on CSS-Tricks.

“The title ‘Front-End Developer’ is obsolete.”

That title is from the opening tweet of a thread from Benjamin De Cock. I wouldn’t go that far, myself. What I like about the term is that ‘Front-End’ literally means the browser, and while the job has been changing quite a lot — and is perhaps fracturing before our eyes — the fact that the job is about doing browser work is still true. We’re browser people. This was a point I tried to make in my “Ooooops I guess we’re full-stack developers now” talk.

I really like Benjamin’s sentiment though. There is a scourge of implementations of things on the web that are both heavier and worse because they re-implement something that the browser offers better and “for free.” Think sliders: scrolling behavior, snap points, fixed/sticky positioning, form controls, animation, etc.

Our industry seems to have acknowledged that backend and frontend developers require very different skills (even though they often use the exact same language), and yet it’s struggling to see there’s too much bundled into the term “front-end developer”.

That’s the tricky part. That’s at the heart of The Great Divide. There’s an awful lot of front-end developers where their job solely focuses on JavaScript. You could call them “JavaScript Engineers” or “JavaScript Developers,” and that feels OK. However, I’m not sure what you call someone who’s a great front-end developer, not particularly focused on JavaScript, but is on other aspects of the front end.

The modern frontend developer is most often than not a “Jack of all trades” mastering JS (or even just a framework) and barely tolerating HTML/CSS as a necessary evil. That’s understandable. I strongly think it’s a different specialization, and it’s too much for a single person.

Yep, it’s OK! The divide isn’t a bad thing; it’s just a thing. Front-end teams need JavaScript specialists and CSS specialists and accessibility specialists and performance specialists and animation specialists and internationalization specialists and, and, and, and. They don’t have to all be separate people. People can be good at multiple things. It’s just exceptionally rare that people are good at everything, even when scoped only to front-end skills.

The post “The title ‘Front-End Developer’ is obsolete.” appeared first on CSS-Tricks.

4 CSS Grid Properties (and One Value) for Most of Your Layout Needs

CSS Grid provides us with a powerful layout system for websites. The CSS-Tricks guide gives you a comprehensive overview of Grid’s properties with layout examples. What we’re going to do here is a reverse approach to show you the smallest possible set of grid properties you need to know to meet most of your layout needs.

These five properties will get you up and running:

  • display (for the grid value)
  • grid-template-columns
  • grid-gap
  • grid-auto-flow
  • grid-column / grid-row

Here’s how simple it is. Let’s assume you want to implement the following layout for small, medium and large screens.

Small and medium-sized screens
Large screen layout

This is the markup we’ll be working with:


<!-- Stuff before -->

<nav class="container-nav">
  <ul>
    <li></li>
    <li></li>
    <li></li>
    <li></li>
    <li></li>
    <li></li>
    <li></li>
    <li></li>
    <li></li>
  </ul>
</nav>

<div class="container-main">
  <section class="item item-type-a"></section>
  <section class="item item-type-b"></section>
  <section class="item item-type-b"></section>
  <section class="item container-inner">
    <section class="item-inner"></section>
    <section class="item-inner"></section>
    <section class="item-inner"></section>
    <section class="item-inner"></section>
    <section class="item-inner"></section>
  </section>
</div>

<!-- Stuff after -->

If we apply a few baseline styles, this is what we get, which is already sufficient for small screens:

Now we can get into the grid properties!

Use display: grid to divide the page into independent layout containers

First, we need to determine which parts of the page should be aligned with grid layouts. It is possible to define a single grid layout for the whole page. However, for websites with a very complex structure (e.g. news websites), handling a large grid quickly becomes complicated to wrangle. In this case, I recommend breaking things down into several, independent grid containers.

Like this:

Where do you draw the line between what is and isn’t a grid? Here’s a personal rule of thumb I follow:

If the layout in a particular part of the page does not fit into the grid of an adjacent or surrounding part of the page, make that part its own grid container.

I have drawn the grid lines into the page section with the class .container-main in the following image You may notice that the section with the .container-inner class from the markup does not fit exactly into the grid of rows.

Here’s another possible layout where the small sections fit into the surrounding grid if a finer line raster is chosen. A separate grid container is not absolutely necessary here.

To kick this off, let’s .container-main into a grid container. This is the basic building block for CSS Grid — turning an element into a grid container with the display property:

.container-main {
  display: grid;         
}

We’ll want to do the same with our other grid containers:

.container-inner {
  display: grid;         
}

.container-nav {
  display: grid;         
}

Use grid-template-columns to define the required columns

Next, we’re going to define the number of columns we need in each grid container and how wide those columns should be. My guideline for the number of columns:  use the smallest common multiple of the maximum number of columns required for the different screen sizes.

How does that work? The .container-main element has a total of two columns on medium-sized screens. If we take that and multiply it by the number of columns on large screens (three), we get a total of six columns.

We can do the same for our navigation, the .container-inner element. There are three columns on medium-sized screens, which we multiple by one column on large screens to get a total of three columns.

The .container-nav element provides no number of columns. In this case, the grid system should automatically adjust the number of columns to the number of menu elements. It’s common to add or remove items in a navigation, and it’d be great if it responded accordingly, which is something grid can help us with a little later on.

OK, so we defined the number of columns for each grid container. Let’s use the grid-template-columns property to set those into place. But, first a couple of minor details:

  • The grid-template-columns property is only used on the grid container. In other words, you won’t find it being used (at least correctly) on a grid item inside the container.
  • The property accepts a bunch of different values that both define the number of columns and how wide they should be. The one we’re interested in here is the fractional (fr) unit. I’d highly suggest checking out Robin’s overview because it’s unique to grid and does an amazing job doing calculations to decide how grid elements fit inside a grid container.

We need six equal-width columns in .container-main. We can write that like this:

.container-main {
  display: grid;
  grid-template-columns: 1fr 1fr 1fr 1fr 1fr 1fr;
}

Or, we can turn to the repeat() function to simplify it into something more readable:

.container-main {
  display: grid;
  grid-template-columns: repeat(6, 1fr);
}

Let’s take that knowledge and apply it to our .container-inner element as well, which we decided needs three columns.

.container-inner {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
}

Use grid-gap to add spacing between grid items

By default, grid uses all the space it has in a grid container to fit in grid items. Having elements flush next to one another might be a design requirement, but not for the particular layout we’re making. We want some breathing room between things!

We have the grid-gap property for that. Again, this is a property that’s just for grid containers and what it does is create vertical and horizontal spacing between grid items. It’s actually a shorthand property that combines the vertical spacing powers of grid-row-gap and horizontal spacing powers of grid-column-gap. It’s handy that we’re able to break things out like that but, in times like this where we’re working with the same amount of spacing in each direction, the shorthand grid-gap is much nicer to write.

We want 20px of space between grid items in .container-main, 10px of space in .container-inner, and 5px of space in .container-nav. No problem! All it takes is a one-liner on each grid container.

.container-main{
  display: grid;
  grid-template-columns: repeat(6, 1fr);
  grid-gap: 20px;
}

.container-inner {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  grid-gap: 10px;
}

.container-nav {
  display: grid;
  grid-gap: 5px;
}

Use grid-column and grid-row to determine the size of the individual grid items

Now it is time to put the layout into the shape we want it!

First is the grid-column property, which allows us to extend a grid item across n columns, where n is the number of columns to span. If you’re thinking this sounds an awful lot like the rowspan attribute that lets us extend cells across multiple rows in HTML tables, you wouldn’t be wrong.

It looks like this when we use it on a grid .item in our .container-main element, and on the .inner-item elements in .container-inner:

.item {
  grid-column: span 6;
}

.item-inner {
  grid-column: span 3;
}

What we’re saying here is that each item span six rows in our main container and three rows in our inner container — which is the total number of columns in each container.

An interesting thing about CSS Grid is that we are able to name the lines of the grid. They come with implicit names out of the box but naming them is a powerful way to distinguish between the starting and ending lines for each column on the track.

We can change the number of columns and rows the items should span at different breakpoints:

@media screen and (min-width: 600px) {
  .item-type-b {
    grid-column: span 3;
  }

  .item-inner {
    grid-column: span 1;
  }
}

@media screen and (min-width: 900px) {
  .item {
    grid-column: span 2;
    grid-row: span 2;
  }

  .item-type-b{
    grid-row: span 1;
  }

  .item-inner{
    grid-column: span 3;
  }
}

Using grid-auto-flow to control the placing of the elements

CSS Grid places elements one row after the other. This is why the result in our example looks like this at the moment:

A column-by-column placement can be achieved by setting the grid-auto-flow property to column (row is the default value). Our layout will profit from column-wise placement in two cases. First, it makes our menu items finally appear in a horizontal orientation. Secondly, it brings the elements of the container class into the desired grouping.

The final result

Conclusion: More or less specification?

The grid system allows us to work under the motto, “make as many specifications as necessary, but as few as possible.” We’ve only covered a few of the specifications necessary to turn elements into a CSS grid container and the items inside it into grid items for the sake of showing just how little you need to know to build even complex layouts with CSS Grid.

CSS Grid supports additional use cases where:

  • We want to make even fewer specifications in order to instead rely more on automatic positioning.
  • We want to make even more specifications in order to determine more details of the resulting layout.

If the first case applies, then it’s worth considering the following additional grid options:

  • When creating the grid with grid-template-columns, you can have the grid system automatically determine the width of individual columns with the auto keyword or adapt it to the existing content with the settings min-content, max-content, or fit-content.
  • You can let the grid system automatically determine the number of required columns with the help of repeat, auto-fill, auto-fit, and minmax. Even media queries can become redundant and these tools help make things flexible without adding more media queries.

Here are a couple of articles on the topic that I recommend: Becoming a CSS Grid Ninja! and Auto-Sizing Columns in CSS Grid: auto-fill vs. auto-fit.

If the second case applies, CSS Grid offers even more settings options for you:

  • You can explicitly specify the width of the columns in the unit of your choice (e.g. px or %) using the grid-template-columns property. In addition, the property grid-template-rows is available to define the number and width of rows, should there be a specific number of them. 
  • You can also define specific column or row numbers for positioning as values for grid-column and grid-row (or use the properties grid-column-start, grid-column-end, grid-row-start, or grid-row-end).

And we haven’t even gotten into CSS Grid alignment! Still, the fact that we can accomplish so much without even broaching that topic shows how powerful CSS Grid is.

The post 4 CSS Grid Properties (and One Value) for Most of Your Layout Needs appeared first on CSS-Tricks.

Finding Balance in These Uncertain Times: Remote Work and Sharing Our Struggles

There is a popular saying, which has been used in several memes, among my developer and remote-working friend groups. It goes something like the following:

Government and Doctors: Practice physical distancing during this pandemic.

Remote Workers: I’ve been preparing my whole life for this moment. I got this.

The truth is that we don’t “got this,” at least I know I don’t.

While practicing physical distancing during the COVID-19 pandemic, it is those little moments that you do not think you will miss that suddenly become important.

Every Saturday, I awake around 6 or 6:30 a.m. I go through my normal routine and get dressed for a morning drive into the city. My home is in a quiet area in rural Alabama. I am a Millennial living within a neighborhood of mostly Baby Boomers. For the most part, it is an ideal place for remote work. Few people bother me, and I can tend to my animals and get my work done in peace. However, it is not exactly the most socially invigorating place in the world.

Those Saturday mornings are important. Assuming I have no other social plans for the week, it is my one chance to get out into the world. I stop by the local Co-Op, pick up any feed or seed I need, and chat with the people there about the farming season or the weather — mostly the weather. I drop into Hidden Treasures, a flea market, and talk with a seller who shares an interest in finding old DVDs, VHS tapes, and Laserdiscs. I grab a sandwich at Subway and am greeted by the Indian-American manager who learned my name on my first visit years ago. He asks about my family. I ask how his family is doing.

These fleeting moments are almost forgettable. They are routine. Run-of-the-mill. When they are happening, you do not think about them. However, when they are gone, there is a void remaining that is hard to fill.

Yes, I have been practicing physical distancing for over a decade, at least to some degree. That makes those small moments where I interact with others in person crucial to my mental health.

This Saturday, I will once again head into the city after a hiatus. However, my trip will be different. This time, I will be gathering necessities for myself and some of my elderly neighbors who want to avoid the public for a while. The trip will be quick. Some of the places I normally visit are closed. My Subway meal will be carryout.

Even after a couple of weeks, and feeling like I was prepared for this moment, I am still coming to grips with the world as it is now.

Staying Strong as a Community

The WordPress community, the people, have put up a strong front. Bloggers have written posts on remote work. Developers, designers, and others have willingly shared their knowledge with others. Companies are offering discounts to help ease the burden for those looking to begin a shop or blog online. Yes, our community will get through this, and we will be stronger for it.

However, it is OK for us to share our vulnerabilities during these uncertain times.

Ultimately, this community is not about software. It is about people. The software is the way we connect. It is a tool that we program, design, and evangelize. We do it for ourselves. We do it for millions of others to have a voice online. But, it is always about people.

Sometimes, people need to know that others in our community are struggling. This is a collective pain that we are working through. Remote work does not always mean physical distancing from everything and every one of the outside world. Many of us may have a bit of a head-start on staying put at home for hours on end, but we are also dealing with a new reality every day. Showing strength is good, but sharing our stories of struggle is just as important.

For some of us, that weekly trip into the city plays a vital role in our well-being. Others are dealing with children who would normally be in school or daycare. Kids can be disruptive, even when you have the best-laid plans and every hour of their day mapped out. Even for us remote workers, life is a little out of balance now. It is OK to admit that. If you are running a WordPress business, it is OK for you to provide a little more flexibility for your workers who are at home. Many of them will need it.

It is not time to break down. It is time to find a new balance in our current environments. That may mean starting up a family board game night. It may mean making sure that you set up a video chat with those loved ones you have been too busy to call in several months. Maybe you will start taking a daily walk for better health. It might also be time to set up WordPress blogs for your children as part of their education. Some of these new things may and probably should become routine, especially that last one.

Do not become overwhelmed if you feel like you should be handling this situation better because you have practice at remote work.

Hop over to your personal WordPress blog. You may have to dust that thing off; some of you have not used it in a while. Write about the things you are struggling with. Share them with the community and find support among others. Post about your experiences. Tell us about your tough days and those small wins that are helping you get through this.

For me, it is having my dad call to check in for the third time this week, and it is only Wednesday.

Java Annotated Monthly – March 2020

It’s only two weeks since the last Java Annotated Monthly and we have another huge issue! I’d like to say March’s edition is dedicated to International Women’s Day, and it can be if you like. To be honest, the inclusion of women contributors in this month’s newsletter is, in fact, nothing special or new. It’s the result of several years of hard work identifying new sources of videos and articles, intentionally expanding the people I follow on Twitter, and placing effort into amplifying voices that deserve to be heard. There is still plenty of room for improvement though so I will not relax and say “it’s OK, we’re diverse now”. Because we’re not.

Java News

How to Create an Animated Countdown Timer With HTML, CSS and JavaScript

Have you ever needed a countdown timer on a project? For something like that, it might be natural to reach for a plugin, but it’s actually a lot more straightforward to make one than you might think and only requires the trifecta of HTML, CSS and JavaScript. Let’s make one together!

This is what we’re aiming for:

Here are a few things the timer does that we’ll be covering in this post:

  • Displays the initial time remaining
  • Converts the time value to a MM:SS format
  • Calculates the difference between the initial time remaining and how much time has passed
  • Changes color as the time remaining nears zero
  • Displays the progress of time remaining as an animated ring

OK, that’s what we want, so let’s make it happen!

Step 1: Start with the basic markup and styles

Let’s start with creating a basic template for our timer. We will add an svg with a circle element inside to draw a timer ring that will indicate the passing time and add a span to show the remaining time value. Note that we’re writing the HTML in JavaScript and injecting into the DOM by targeting the #app element. Sure, we could move a lot of it into an HTML file, if that's more your thing.

document.getElementById("app").innerHTML = `
<div class="base-timer">
  <svg class="base-timer__svg" viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg">
    <g class="base-timer__circle">
      <circle class="base-timer__path-elapsed" cx="50" cy="50" r="45" />
    </g>
  </svg>
  <span>
    <!-- Remaining time label -->
  </span>
</div>
`;

Now that we have some markup to work with, let’s style it up a bit so we have a good visual to start with. Specifically, we’re going to:

  • Set the timer’s size
  • Remove the fill and stroke from the circle wrapper element so we get the shape but let the elapsed time show through
  • Set the ring’s width and color
/* Sets the containers height and width */
.base-timer {
  position: relative;
  height: 300px;
  width: 300px;
}

/* Removes SVG styling that would hide the time label */
.base-timer__circle {
  fill: none;
  stroke: none;
}

/* The SVG path that displays the timer's progress */
.base-timer__path-elapsed {
  stroke-width: 7px;
  stroke: grey;
}

Having that done we end up with a basic template that looks like this.

Step 2: Setting up the time label

As you probably noticed, the template includes an empty <span> that’s going to hold the time remaining. We will fill that place with a proper value. We said earlier that the time will be in MM:SS format. To do that we will create a method called formatTimeLeft:

function formatTimeLeft(time) {
  // The largest round integer less than or equal to the result of time divided being by 60.
  const minutes = Math.floor(time / 60);
  
  // Seconds are the remainder of the time divided by 60 (modulus operator)
  let seconds = time % 60;
  
  // If the value of seconds is less than 10, then display seconds with a leading zero
  if (seconds < 10) {
    seconds = `0${seconds}`;
  }

  // The output in MM:SS format
  return `${minutes}:${seconds}`;
}

Then we will use our method in the template:

document.getElementById("app").innerHTML = `
<div class="base-timer">
  <svg class="base-timer__svg" viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg">
    <g class="base-timer__circle">
      <circle class="base-timer__path-elapsed" cx="50" cy="50" r="45"></circle>
    </g>
  </svg>
  <span id="base-timer-label" class="base-timer__label">
    ${formatTime(timeLeft)}
  </span>
</div>
`

To show the value inside the ring we need to update our styles a bit.

.base-timer__label {
  position: absolute;
  
  /* Size should match the parent container */
  width: 300px;
  height: 300px;
  
  /* Keep the label aligned to the top */
  top: 0;
  
  /* Create a flexible box that centers content vertically and horizontally */
  display: flex;
  align-items: center;
  justify-content: center;

  /* Sort of an arbitrary number; adjust to your liking */
  font-size: 48px;
}

OK, we are ready to play with the timeLeft  value, but the value doesn’t exist yet. Let’s create it and set the initial value to our time limit.

// Start with an initial value of 20 seconds
const TIME_LIMIT = 20;

// Initially, no time has passed, but this will count up
// and subtract from the TIME_LIMIT
let timePassed = 0;
let timeLeft = TIME_LIMIT;

And we are one step closer.

Right on! Now we have a timer that starts at 20 seconds… but it doesn't do any counting just yet. Let’s bring it to life so it counts down to zero seconds.

Step 3: Counting down

Let’s think about what we need to count down the time. Right now, we have a timeLimit value that represents our initial time, and a timePassed value that indicates how much time has passed once the countdown starts.

What we need to do is increase the value of timePassed by one unit per second and recompute the timeLeft value based on the new timePassed value. We can achieve that using the setInterval function.

Let’s implement a method called startTimer that will:

  • Set counter interval
  • Increment the timePassed value each second
  • Recompute the new value of timeLeft
  • Update the label value in the template

We also need to keep the reference to that interval object to clear it when needed — that’s why we will create a timerInterval variable.

let timerInterval = null;

document.getElementById("app").innerHTML = `...`

function startTimer() {
  timerInterval = setInterval(() => {
    
    // The amount of time passed increments by one
    timePassed = timePassed += 1;
    timeLeft = TIME_LIMIT - timePassed;
    
    // The time left label is updated
    document.getElementById("base-timer-label").innerHTML = formatTime(timeLeft);
  }, 1000);
}

We have a method that starts the timer but we do not call it anywhere. Let’s start our timer immediately on load.

document.getElementById("app").innerHTML = `...`
startTimer();

That’s it! Our timer will now count down the time. While that’s great and all, it would be nicer if we could add some color to the ring around the time label and change the color at different time values.

Step 4: Cover the timer ring with another ring

To visualize time passing, we need to add a second layer to our ring that handles the animation. What we’re doing is essentially stacking a new green ring on top of the original gray ring so that the green ring animates to reveal the gray ring as time passes, like a progress bar.

Let’s first add a path element in our SVG element.

document.getElementById("app").innerHTML = `
<div class="base-timer">
  <svg class="base-timer__svg" viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg">
    <g class="base-timer__circle">
      <circle class="base-timer__path-elapsed" cx="50" cy="50" r="45"></circle>
      <path
        id="base-timer-path-remaining"
        stroke-dasharray="283"
        class="base-timer__path-remaining ${remainingPathColor}"
        d="
          M 50, 50
          m -45, 0
          a 45,45 0 1,0 90,0
          a 45,45 0 1,0 -90,0
        "
      ></path>
    </g>
  </svg>
  <span id="base-timer-label" class="base-timer__label">
    ${formatTime(timeLeft)}
  </span>
</div>
`;

Next, let’s create an initial color for the remaining time path.

const COLOR_CODES = {
  info: {
    color: "green"
  }
};

let remainingPathColor = COLOR_CODES.info.color;

Finally, let’s add few styles to make the circular path look like our original gray ring. The important thing here is to make sure the stroke-width is the same size as the original ring and that the duration of the transition is set to one second so that it animates smoothly and corresponds with the time remaining in the time label.

.base-timer__path-remaining {
  /* Just as thick as the original ring */
  stroke-width: 7px;

  /* Rounds the line endings to create a seamless circle */
  stroke-linecap: round;

  /* Makes sure the animation starts at the top of the circle */
  transform: rotate(90deg);
  transform-origin: center;

  /* One second aligns with the speed of the countdown timer */
  transition: 1s linear all;

  /* Allows the ring to change color when the color value updates */
  stroke: currentColor;
}

.base-timer__svg {
  /* Flips the svg and makes the animation to move left-to-right */
  transform: scaleX(-1);
}

This will output a stroke that covers the timer ring like it should, but it doesn’t animate just yet to reveal the timer ring as time passes.

To animate the length of the remaining time line we are going to use the stroke-dasharray property. Chris explains how it’s used to create the illusion of an element “drawing” itself. And there’s more detail about the property and examples of it in the CSS-Tricks almanac.

Step 5: Animate the progress ring

Let’s see how our ring will look like with different stroke-dasharray values:

What we can see is that the value of stroke-dasharray is actually cutting our remaining time ring into equal-length sections, where the length is the time remaining value. That is happening when we set the value of stroke-dasharray to a single-digit number (i.e. 1-9).

The name dasharray suggests that we can set multiple values as an array. Let’s see how it will behave if we set two numbers instead of one; in this case, those values are 10 and 30.

stroke-dasharray: 10 30

That sets the first section (remaining time) length to 10 and the second section (passed time) to 30. We can use that in our timer with a little trick. What we need initially is for the ring to cover the full length of the circle, meaning the remaining time equals the length of our ring.

What’s that length? Get out your old geometry textbook, because we can calculate the length an arc with some math:

Length = 2πr = 2 * π * 45 = 282,6

That’s the value we want to use when the ring initially mounted. Let’s see how it looks.

stroke-dasharray: 283 283

That works!

OK, the first value in the array is our remaining time, and the second marks how much time has passed. What we need to do now is to manipulate the first value. Let’s see below what we can expect when we change the first value.

We will create two methods, one responsible for calculating what fraction of the initial time is left, and one responsible for calculating the stroke-dasharray value and updating the <path> element that represents our remaining time.

// Divides time left by the defined time limit.
function calculateTimeFraction() {
  return timeLeft / TIME_LIMIT;
}
    
// Update the dasharray value as time passes, starting with 283
function setCircleDasharray() {
  const circleDasharray = `${(
    calculateTimeFraction() * FULL_DASH_ARRAY
  ).toFixed(0)} 283`;
  document
    .getElementById("base-timer-path-remaining")
    .setAttribute("stroke-dasharray", circleDasharray);
}

We also need to update our path each second that passes. That means we need to call the newly created setCircleDasharray method inside our timerInterval.

function startTimer() {
  timerInterval = setInterval(() => {
    timePassed = timePassed += 1;
    timeLeft = TIME_LIMIT - timePassed;
    document.getElementById("base-timer-label").innerHTML = formatTime(timeLeft);
    
    setCircleDasharray();
  }, 1000);
}

Now we can see things moving!

Woohoo, it works… but… look closely, especially at the end. It looks like our animation is lagging by one second. When we reach 0 a small piece of the ring is still visible.

This is due to the animation’s duration being set to one second. When the value of remaining time is set to zero, it still takes one second to actually animate the ring to zero. We can get rid of that by reducing the length of the ring gradually during the countdown. We do that in our calculateTimeFraction method.

function calculateTimeFraction() {
  const rawTimeFraction = timeLeft / TIME_LIMIT;
  return rawTimeFraction - (1 / TIME_LIMIT) * (1 - rawTimeFraction);
}

There we go!

Oops… there is one more thing. We said we wanted to change the color of the progress indicator when when the time remaining reaches certain points — sort of like letting the user know that time is almost up.

Step 6: Change the progress color at certain points of time

First, we need to add two thresholds that will indicate when we should change to the warning and alert states and add colors for each of that states. We’re starting with green, then go to orange as a warning, followed by red when time is nearly up.

// Warning occurs at 10s
const WARNING_THRESHOLD = 10;
// Alert occurs at 5s
const ALERT_THRESHOLD = 5;

const COLOR_CODES = {
  info: {
    color: "green"
  },
  warning: {
    color: "orange",
    threshold: WARNING_THRESHOLD
  },
  alert: {
    color: "red",
    threshold: ALERT_THRESHOLD
  }
};

Now, let’s create a method that’s responsible for checking if the threshold exceeded and changing the progress color when that happens.

function setRemainingPathColor(timeLeft) {
  const { alert, warning, info } = COLOR_CODES;

  // If the remaining time is less than or equal to 5, remove the "warning" class and apply the "alert" class.
  if (timeLeft <= alert.threshold) {
    document
      .getElementById("base-timer-path-remaining")
      .classList.remove(warning.color);
    document
      .getElementById("base-timer-path-remaining")
      .classList.add(alert.color);

  // If the remaining time is less than or equal to 10, remove the base color and apply the "warning" class.
  } else if (timeLeft <= warning.threshold) {
    document
      .getElementById("base-timer-path-remaining")
      .classList.remove(info.color);
    document
      .getElementById("base-timer-path-remaining")
      .classList.add(warning.color);
  }
}

So, we’re basically removing one CSS class when the timer reaches a point and adding another one in its place. We’re going to need to define those classes.

.base-timer__path-remaining.green {
  color: rgb(65, 184, 131);
}

.base-timer__path-remaining.orange {
  color: orange;
}

.base-timer__path-remaining.red {
  color: red;
}

Voilà, there we have it. Here’s the demo again with everything put together.

The post How to Create an Animated Countdown Timer With HTML, CSS and JavaScript appeared first on CSS-Tricks.

Gutenberg Can Tackle the Problems the Fields API Tried to Solve

The Fields API.

Never heard of it? That’s OK. Outside of the inner development community, it is not widely known. The average WordPress user does not need to know about it. Before understanding how the Fields API fits into Gutenberg’s future, you must first understand what it is and the problems it was meant to fix.

The Fields API was a proposed solution to one of WordPress’ biggest problems: to build form fields in the admin and save data from those fields, developers need to know multiple APIs, depending on the specific admin screen.

Want to build a plugin settings screen? Use the Settings API.

Need some theme options? Build them with the Customize API.

Have some fields to output on the user screen? Here are two hooks and a mess of HTML table markup; sorry, no official API.

Those are just a few examples, but the truth of it comes down to this: to show something as basic as a text field to end-users, WordPress developers need to know how to do this in a variety of ways based on competing or even missing APIs.

There are historical reasons for this. New features were bolted on top of WordPress over time. In the mad rush to continue shipping features with each major update, few people stepped back and asked the fundamental question about the technical debt that would pile up over the past 16 years. Shipping end-user features helped the platform grow, but developers had to learn all-new functions and methods each time.

Adding to the technical burden, when the Gutenberg project launched, it introduced a new system in a different programming language.

The Fields API would have created a standardized system for outputting form fields and saving field data. It would work with all the existing admin screens and any new features added in the future. Developers could learn a single system and be able to build plugins that worked with practically any area of WordPress.

In 2014, Scott Kingsley Clark took over the Metadata UI Project. The initial idea was to create an API for adding custom fields (meta box fields) on the post-editing screen. Eventually, Clark and those working on the project realized the problem that needed solving was larger than meta boxes. WordPress needed an API that worked across the board. After a year, the project was relaunched as the Fields API.

After years of working on the code behind the project, Clark became burned out. He stepped down as the project’s lead in 2018. With no buy-in from the decision-makers for the WordPress project, there was little hope of it making it into core. At that point, the project was all but dead.

Gutenberg’s development was in full swing. Developers were gearing up for relearning how to add the same basic text fields and other form elements in whole new ways.

The Fields API, had it made it into WordPress before the block editor, could have alleviated the need for developers to learn a new system. However, that’s not where we’re at today. The Fields API never made it past the gatekeepers, and developers have one more thing to stay knowledgeable on.

The question is: how do we address this going forward?

How the Gutenberg Project Can Solve the Fields API Problem

What many don’t understand is that the Gutenberg project is larger than the content editor. The first iteration, Phase 1, of the project was to create a new editing experience. Phase 2 will create new admin screens for site editing using the same components for the editor. Custom text fields, select dropdowns, color options, or one of many other field types all run through the same reusable, component-based system.

That sounds remarkably similar to the Fields API. At the end of the day, the Fields API is simply a standardized method of reusing components to output form fields and save data, regardless of the screen in WordPress.

WordPress needs to be rebuilt from the ground up. Gutenberg provides us the opportunity to rewrite every admin page in WordPress using a standardized system for handling form fields.

From a technical standpoint, Gutenberg has dozens of components. These include a text control, button, checkbox, and much more. It covers the majority of use cases plugin and theme authors need for form fields. These things are not tied directly to the block system. They are simply components that can be used anywhere.

The next step would be setting the foundational layer for other admin screens. It will not be easy. There will be backward-compatibility mountains that the Fields API could have climbed for us years ago.

Given WordPress’ history, developers will likely continue using competing APIs for fields on various admin pages. And, if we’re still at that point in five years, the Gutenberg project will have failed for not going as far as it could have.

For success, the Gutenberg project needs to have a wider vision and a longer-term roadmap that addresses the issues of fields on every screen. Otherwise, projects with easier-to-learn APIs will be more enticing to developers.

The idea of Gutenberg-ifying the entirety of the WordPress admin will be off-putting to many, but WordPress has to solve its form fields issue at some point. It might as well reuse the components that will be seeing active development for years to come.

One Way to Break Users Out of the Habit of Reloading Too Much

Page reloads are a thing. Sometimes we refresh a page when we think it’s unresponsive, or believe that new content is available. Sometimes we’re just mad at the dang site and rage-refresh to let it know we’re displeased.

Wouldn’t be nice to know when a user refreshes the page? Not just that, but how many times? That data can help us trigger some sort of behavior after a certain number of reloads.

A sports site is a good example. If I want to check the score of a game that’s in progress but the scores aren't live-updated, then I might find myself refreshing a bunch.

Our goal is to break users out of that habit. We’ll use our page-refresh-counting powers to let folks know that refreshes are unnecessary, thanks to real-time score updates. And if they reload more than three times? We’ll kick ‘em out of their session. That’ll show them.

Here’s a simple demo of that concept.

Let’s re-create it together. But before we get going, there are few questions we need to answer before we start coding:

  • How can we persist the number of times user reloaded the site? We need a place to keep the number of times user reloaded the site (reloadCount), this place needs to persist that value between the reloads — localStorage sounds like a good solution.
  • How do we detect if user reloaded the site or just came back after few hours? If we store the reloadCount in localStorage it will persist the value between the reloads, but it will keep that value until we remove programmatically or clear the browser storage. It means that if we come back after few hours the site will still remember last reloadCount and may perform logout after first refresh without warning. We want to avoid that and allow user to reload the site two times each time the user comes back after some period of time. That last sentence holds the answer to the question. We need to store the time when the user left the site and then when the site loads again check when that happened. If that time period wasn’t long enough, we activate the reload counting logic.
  • How do we know when the user leaves the site? To store that time, we use beforeunload window event and store that value in localStorage.

OK, now that we have the answers, let’s dive into the code.

Step 1: We’ve gotta store the last reload time

We will store the time of last reload using a beforeunload window event. We need two things: (1) an event listener that will listen to the event and fire the appropriate method, and (2) our beforeUnloadHandler method.

First, let’s create a function called initializeReloadCount that will set our event listener using the addEventListener method on the window object.

function initializeReloadCount() {
  window.addEventListener("beforeunload", beforeUnloadHandler)
}

Then we create a second method that will be fired before we leave the site. This method will save the time the refresh happens in localStorage.

function beforeUnloadHandler() {
  localStorage.setItem("lastUnloadAt", Math.floor(Date.now() / 1000))
  window.removeEventListener("beforeunload", beforeUnloadHandler);
}

Step 2: We need a way to handle and store the reload count

Now that we have the time when the site was last closed, we can proceed and implement logic that’s responsible for detecting and counting how many times the site was reloaded. We need a variable to hold our reloadCount and tell us how many times user reloaded the site.

let reloadCount = null

Then, in our initializeReloadCount function, we need to do two things:

  1. Check if we already have a reloadCount value stored in our localStorage, and if so, get that value and save it in our reloadCount. If the value doesn’t exist, it means that the user loaded the site for the first time (or at least did not reload it). In that case, we set the reloadCount to zero and save that value to localStorage.
  2. Detect if the site was reloaded or the user came back to the site after longer period of time. This is the place where we need our lastUnloadAt value. To detect if the site was actually reloaded, we need to compare the time when the site gets loaded (the current time) with the lastUnloadAt value. If those two happened within, say, five seconds (which is totally arbitrary), that means the user reloaded the site and we should run reload count logic. If the time period between those two events is longer, we reset the reloadCount value.

With that, let’s create a new function called checkReload and keep that logic there.

function checkReload() {
  if (localStorage.getItem("reloadCount")) {
    reloadCount = parseInt(localStorage.getItem("reloadCount"))
  } else {
    reloadCount = 0
    localStorage.setItem("reloadCount", reloadCount)
  }
  if (
    Math.floor(Date.now() / 1000) - localStorage.getItem("lastUnloadAt") <
    5
  ) {
    onReloadDetected()
  } else {
    reloadCount = 0;
    localStorage.setItem("reloadCount", reloadCount)
  }
}

The last function we need in this step is a method responsible for what happens when we confirm that the user reloaded the site. We call that function onReloadDetected, and inside it, we increment the value of reloadCount. If the user refreshed the site third time, we drop the bomb and call our logout logic.

function onReloadDetected() {
  reloadCount = reloadCount + 1
  localStorage.setItem("reloadCount", reloadCount)
  if (reloadCount === 3) {
    logout()
  }
}

Step 3: “Dear user, why you didn’t listen?!”

In this step, we implement the logic responsible for the situation when the user reloads the site to the point of breaching our three-limit threshold, despite our clear warnings to stop doing it.

When that happens, we call our API to log the user out, then we clean up all properties related to the reload count logic. That will allow the user to come back and have a clean account of reloads. We can also redirect the user somewhere useful, like the login screen. (But wouldn’t it be funny to send them here instead?)

function logout(params) {
  // logout API call
  resetReloadCount()
}

function resetReloadCount() {
  window.removeEventListener("beforeunload", beforeUnloadHandler)
  localStorage.removeItem("lastUnloadAt")
  localStorage.removeItem("reloadCount");
}

Bonus: Let’s re-Vue it!

Now that we have the logic implemented, let’s see how can move that logic to a Vue site based on this example:

First, we need to move all of our variables into our component’s data, which is where all reactive props live.

export default {
  data() {
    return {
      reloadCount: 0,
      warningMessages: [...]
    }
  },

Then we move all our functions to methods.

// ...
  methods: {
    beforeUnloadHandler() {...},
    checkReload() {...},
    logout() {...},
    onReloadDetected() {...},
    resetReloadCount() {...},
    initializeReloadCount() {...}
  }
// ...

Since we are using Vue and its reactivity system, we can drop all direct DOM manipulations (e.g. document.getElementById("app").innerHTML) and depend on our warningMessages data property. To display the proper warning message we need to add a computed property that will re-calculate each time our reloadCount is changed so that we can return a string from our warningMessages.

computed: {
  warningMessage() {
    return this.warningMessages[this.reloadCount];
  }
},

Then we can access our computed property directly in the component’s template.

<template>
  <div id="app">
    <p>{{ warningMessage }}</p>
  </div>
</template>

Last thing we need to do is find a proper place to activate the reload prevention logic. Vue comes with component lifecycle hooks that are exactly what we need, specifically the created hook. Let’s drop that in.

// ...
  created() {
    this.initializeReloadCount();
  },
// ...

Nice.

Wrapping up

And there it is, the logic that checks and counts how many times a page has been refreshed. I hope you enjoyed the ride and you find this solution useful or at least inspiring to do something better. 🙂

The post One Way to Break Users Out of the Habit of Reloading Too Much appeared first on CSS-Tricks.

Detecting Inactive Users

Most of the time you don’t really care about whether a user is actively engaged or temporarily inactive on your application. Inactive, meaning, perhaps they got up to get a drink of water, or more likely, changed tabs to do something else for a bit. There are situations, though, when tracking the user activity and detecting inactive-ness might be handy.

Let’s think about few examples when you just might need that functionality:

  • tracking article reading time
  • auto saving form or document
  • auto pausing game
  • hiding video player controls
  • auto logging out users for security reasons

I recently encountered a feature that involved that last example, auto logging out inactive users for security reasons.

Why should we care about auto logout?

Many applications give users access to some amount of their personal data. Depending on the purpose of the application, the amount and the value of that data may be different. It may only be user’s name, but it may also be more sensitive data, like medical records, financial records, etc.

There are chances that some users may forget to log out and leave the session open. How many times has it happened to you? Maybe your phone suddenly rang, or you needed to leave immediately, leaving the browser on. Leaving a user session open is dangerous as someone else may use that session to extract sensitive data.

One way to fight this issue involves tracking if the user has interacted with the app within a certain period of time, then trigger logout if that time is exceeded. You may want to show a popover, or perhaps a timer that warns the user that logout is about to happen. Or you may just logout immediately when inactive user is detected.

Going one level down, what we want to do is count the time that’s passed from the user’s last interaction. If that time period is longer than our threshold, we want to fire our inactivity handler. If the user performs an action before the threshold is breached, we reset the counter and start counting again.

This article will show how we can implement such an activity tracking logic based on this example.

Step 1: Implement tracking logic

Let’s implement two functions. The first will be responsible for resetting our timer each time the user interacts with the app, and the second will handle situation when the user becomes inactive:

  • resetUserActivityTimeout - This will be our method that’s responsible for clearing the existing timeout and starting a new one each time the user interacts with the application.
  • inactiveUserAction - This will be our method that is fired when the user activity timeout runs out.
let userActivityTimeout = null;

function resetUserActivityTimeout() {
  clearTimeout(userActivityTimeout);
  userActivityTimeout = setTimeout(() => {
    inactiveUserAction();
  }, INACTIVE_USER_TIME_THRESHOLD);
}

function inactiveUserAction() {
  // logout logic
}

OK, so we have methods responsible for tracking the activity but we do not use them anywhere yet.

Step 2: Tracking activation

Now we need to implement methods that are responsible for activating the tracking. In those methods, we add event listeners that will call our resetUserActivityTimeout method when the event is detected. You can listen on as many events as you want, but for simplicity, we will restrict that list to a few of the most common ones.

function activateActivityTracker() {
  window.addEventListener("mousemove", resetUserActivityTimeout);
  window.addEventListener("scroll", resetUserActivityTimeout);
  window.addEventListener("keydown", resetUserActivityTimeout);
  window.addEventListener("resize", resetUserActivityTimeout);
}

That’s it. Our user tracking is ready. The only thing we need to do is to call the activateActivityTracker on our page load.

We can leave it like this, but if you look closer, there is a serious performance issue with the code we just committed. Each time the user interacts with the app, the whole logic runs. That’s good, but look closer. There are some types of events that are fired an enormous amount of times when the user interacts with the page, even if it isn’t necessary for our tracking. Let’s look at mousemove event. Even if you move your mouse just a touch, mousemove event will be fired dozens of times. This is a real performance killer. We can deal with that issue by introducing a throttler that will allow the user activity logic to be fired only once per specified time period.

Let’s do that now.

Step 3: Improve performance

First, we need to add one more variable that will keep reference to our throttler timeout.

let userActivityThrottlerTimeout = null

Then, we create a method that will create our throttler. In that method, we check if the throttler timeout already exists, and if it doesn’t, we create one that will fire the resetUserActivityTimeout after specific period of time. That is the period for which all user activity will not trigger the tracking logic again. After that time the throttler timeout is cleared allowing the next interaction to reset the activity tracker.

userActivityThrottler() {
  if (!userActivityThrottlerTimeout) {
    userActivityThrottlerTimeout = setTimeout(() => {
      resetUserActivityTimeout();

      clearTimeout(userActivityThrottlerTimeout);
      userActivityThrottlerTimeout = null;
    }, USER_ACTIVITY_THROTTLER_TIME);
  }
}

We just created a new method that should be fired on user interaction, so we need to remember to change the event handlers from resetUserActivityTimeout to userActivityThrottler in our activate logic.

activateActivityTracker() {
  window.addEventListener("mousemove", userActivityThrottler);
  // ...
}

Bonus: Let’s reVue it!

Now that we have our activity tracking logic implemented let’s see how can move that logic to an application build with Vue. We will base the explanation on this example.

First we need to move all variables into our component’s data, that is the place where all reactive props live.

export default {
  data() {
    return {
      isInactive: false,
      userActivityThrottlerTimeout: null,
      userActivityTimeout: null
    };
  },
// ...

Then we move all our functions to methods:

// ...
  methods: {
    activateActivityTracker() {...},
    resetUserActivityTimeout() {...},
    userActivityThrottler() {...},
    inactiveUserAction() {...}
  },
// ...

Since we are using Vue and it’s reactive system, we can drop all direct DOM manipulations i.(i.e. document.getElementById("app").innerHTML) and depend on our isInactive data property. We can access the data property directly in our component’s template like below.

<template>
  <div id="app">
    <p>User is inactive = {{ isInactive }}</p>
  </div>
</template>

Last thing we need to do is to find a proper place to activate the tracking logic. Vue comes with component lifecycle hooks which are exactly what we need — specifically the beforeMount hook. So let’s put it there.

// ...
  beforeMount() {
    this.activateActivityTracker();
  },
// ...

There is one more thing we can do. Since we are using timeouts and register event listeners on window, it is always a good practice to clean up a little bit after ourselves. We can do that in another lifecycle hook, beforeDestroy. Let’s remove all listeners that we registered and clear all timeouts when the component’s lifecycle comes to an end.

// ...
  beforeDestroy() {
    window.removeEventListener("mousemove", this.userActivityThrottler);
    window.removeEventListener("scroll", this.userActivityThrottler);
    window.removeEventListener("keydown", this.userActivityThrottler);
    window.removeEventListener("resize", this.userActivityThrottler);
  
    clearTimeout(this.userActivityTimeout);
    clearTimeout(this.userActivityThrottlerTimeout);
  }
// ...

That’s a wrap!

This example concentrates purely on detecting user interaction with the application, reacting to it and firing a method when no interaction is detected within specific period of time. I wanted this example to be as universal as possible, so that’s why I leave the implementation of what should happened when an inactive user it detected to you.

I hope you will find this solution useful in your project!

The post Detecting Inactive Users appeared first on CSS-Tricks.

Making a Chart? Try Using Mobx State Tree to Power the Data

Who loves charts? Everyone, right? There are lots of ways to create them, including a number of libraries. There’s D3.js, Chart.js, amCharts, Highcharts, and Chartist, to name only a few of many, many options.

But we don’t necessary need a chart library to create charts. Take Mobx-state-tree (MST), an intuitive alternative to Redux for managing state in React. We can build an interactive custom chart with simple SVG elements, using MST to manage and manipulate data for the chart. If you've attempted to build charts using something like D3.js in the past, I think you’ll find this approach more intuitive. Even if you're an experienced D3.js developer, I still think you'll be interested to see how powerful MST can be as a data architecture for visualizations.

Here’s an example of MST being used to power a chart:

This example uses D3's scale functions but the chart itself is rendered simply using SVG elements within JSX. I don’t know of any chart library that has an option for flashing hamster points so this is a great example of why it’s great to build your own charts — and it’s not as hard as you might think!

I’ve been building charts with D3 for over 10 years and, while I love how powerful it is, I’ve always found that my code can end up being unwieldy and hard to maintain, especially when working with complex visualizations. MST has changed all that completely by providing an elegant way to separate the data handling from the rendering. My hope for this article is that it will encourage you to give it a spin.

Getting familiar with MST model

First of all, let’s cover a quick overview of what a MST model looks like. This isn’t an in-depth tutorial on all things MST. I only want to show the basics because, really, that’s all you need about 90% of the time.

Below is a Sandbox with the code for a simple to-do list built in MST. Take a quick look and then I’ve explain what each section does.

First of all, the shape of the object is defined with typed definitions of the attribute of the model. In plain English, this means an instance of the to-do model must have a title, which must be a string and will default to having a “done” attribute of false.

.model("Todo", {
  title: types.string,
  done: false //this is equivalent to types.boolean that defaults to false
})

Next, we have the view and action functions. View functions are ways to access calculated values based on data within the model without making any changes to the data held by the model. You can think of them as read-only functions.

.views(self => ({
  outstandingTodoCount() {
    return self.todos.length - self.todos.filter(t => t.done).length;
  }
}))

Action functions, on the other hand, allow us to safely update the data. This is always done in the background in a non-mutable way.

.actions(self => ({
  addTodo(title) {
    self.todos.push({
      id: Math.random(),
      title
    });
  }
}));

Finally, we create a new instance of the store:

const todoStore = TodoStore.create({
  todos: [
    {
      title: "foo",
      done: false
    }
  ]
});

To show the store in action, I’ve added a couple of console logs to show the output of outStandingTodoCount() before and after triggering the toggle function of the first instance of a Todo.

console.log(todoStore.outstandingTodoCount()); // outputs: 1
todoStore.todos[0].toggle();
console.log(todoStore.outstandingTodoCount()); // outputs: 0

As you can see, MST gives us a data structure that allows us to easily access and manipulate data. More importantly, it’s structure is very intuitive and the code is easy to read at a glance — not a reducer in sight!

Let’s make a React chart component

OK, so now that we have a bit of background on what MST looks like, let’s use it to create a store that manages data for a chart. We’ll will start with the chart JSX, though, because it’s much easier to build the store once you know what data is needed.

Let’s look at the JSX which renders the chart.

The first thing to note is that we are using styled-components to organize our CSS. If that’s new to you, Cliff Hall has a great post that shows it in use with a React app.

First of all, we are rendering the dropdown that will change the chart axes. This is a fairly simple HTML dropdown wrapped in a styled component. The thing to note is that this is a controlled input, with the state set using the selectedAxes value from our model (we’ll look at this later).

<select
  onChange={e =>
    model.setSelectedAxes(parseInt(e.target.value, 10))
  }
  defaultValue={model.selectedAxes}
>

Next, we have the chart itself. I’ve split up the axes and points in to their own components, which live in a separate file. This really helps keep the code maintainable by keeping each file nice and small. Additionally, it means we can reuse the axes if we want to, say, have a line chart instead of points. This really pays off when working on large projects with multiple types of chart. It also makes it easy to test the components in isolation, both programmatically and manually within a living style guide.

{model.ready ? (
  <div>
    <Axes
      yTicks={model.getYAxis()}
      xTicks={model.getXAxis()}
      xLabel={xAxisLabels[model.selectedAxes]}
      yLabel={yAxisLabels[model.selectedAxes]}
    ></Axes>
    <Points points={model.getPoints()}></Points>
  </div>
) : (
  <Loading></Loading>
)}

Try commenting out the axes and points components in the Sandbox above to see how they work independently of each other.

Lastly, we’ll wrap the component with an observer function. This means that any changes in the model will trigger a re-render.

export default observer(HeartrateChart);

Let’s take a look at the Axes component:

As you can see, we have an XAxis and a YAxis. Each has a label and a set of tick marks. We go into how the marks are created later, but here you should note that each axis is made up of a set of ticks, generated by mapping over an array of objects with a label and either an x or y value, depending on which axis we are rendering.

Try changing some of the attribute values for the elements and see what happens… or breaks! For example, change the line element in the YAxis to the following:

<line x1={30} x2="95%" y1={0} y2={y} />

The best way to learn how to build visuals with SVG is simply to experiment and break things. 🙂

OK, that’s half of the chart. Now we’ll look at the Points component.

Each point on the chart is composed of two things: an SVG image and a circle element. The image is the animal icon and the circle provides the pulse animation that is visible when mousing over the icon.

Try commenting out the image element and then the circle element to see what happens.

This time the model has to provide an array of point objects which gives us four properties: x and y values used to position the point on the graph, a label for the point (the name of the animal) and pulse, which is the duration of the pulse animation for each animal icon. Hopefully this all seems intuitive and logical.

Again, try fiddling with attribute values to see what changes and breaks. You can try setting the y attribute of the image to 0. Trust me, this is a much less intimidating way to learn than reading the W3C specification for an SVG image element!

Hopefully this gives you an understanding and feel for how we are rendering the chart in React. Now, it’s just a case of creating a model with the appropriate actions to generate the points and ticks data we need to loop over in JSX.

Creating our store

Here is the complete code for the store:

I’ll break down the code into the three parts mentioned earlier:

  1. Defining the attributes of the model
  2. Defining the actions
  3. Defining the views

Defining the attributes of the model

Everything we define here is accessible externally as a property of the instance of the model and — if using an observable wrapped component — any changes to these properties will trigger a re-render.

.model('ChartModel', {
  animals: types.array(AnimalModel),
  paddingAndMargins: types.frozen({
    paddingX: 30,
    paddingRight: 0,
    marginX: 30,
    marginY: 30,
    marginTop: 30,
    chartHeight: 500
  }),
  ready: false, // means a types.boolean that defaults to false
  selectedAxes: 0 // means a types.number that defaults to 0
})

Each animal has four data points: name (Creature), longevity (Longevity__Years_), weight (Mass__grams_), and resting heart rate (Resting_Heart_Rate__BPM_).

const AnimalModel = types.model('AnimalModel', {
  Creature: types.string,
  Longevity__Years_: types.number,
  Mass__grams_: types.number,
  Resting_Heart_Rate__BPM_: types.number
});

Defining the actions

We only have two actions. The first (setSelectedAxes ) is called when changing the dropdown menu, which updates the selectedAxes attribute which, in turn, dictates what data gets used to render the axes.

setSelectedAxes(val) {
  self.selectedAxes = val;
},

The setUpScales action requires a bit more explanation. This function is called just after the chart component mounts, within a useEffect hook function, or after the window is resized. It accepts an object with the width of the DOM that contains the element. This allows us to set up the scale functions for each axis to fill the full available width. I will explain the scale functions shortly.

In order to set up scale functions, we need to calculate the maximum value for each data type, so the first thing we do is loop over the animals to calculate these maximum and minimum values. We can use zero as the minimum value for any scale we want to start at zero.

// ...
self.animals.forEach(
  ({
    Creature,
    Longevity__Years_,
    Mass__grams_,
    Resting_Heart_Rate__BPM_,
    ...rest
  }) => {
    maxHeartrate = Math.max(
      maxHeartrate,
      parseInt(Resting_Heart_Rate__BPM_, 10)
    );
    maxLongevity = Math.max(
      maxLongevity,
      parseInt(Longevity__Years_, 10)
    );
    maxWeight = Math.max(maxWeight, parseInt(Mass__grams_, 10));
    minWeight =
      minWeight === 0
        ? parseInt(Mass__grams_, 10)
        : Math.min(minWeight, parseInt(Mass__grams_, 10));
  }
);
// ...

Now to set up the scale functions! Here, we’ll be using the scaleLinear and scaleLog functions from D3.js. When setting these up, we specify the domain, which is the minimum and maximum input the functions can expect, and the range, which is the maximum and minimum output.

For example, when I call self.heartScaleY with the maxHeartrate value, the output will be equal to marginTop. That makes sense because this will be at the very top of the chart. For the longevity attribute, we need to have two scale functions since this data will appear on either the x- or the y-axis, depending on which dropdown option is chosen.

self.heartScaleY = scaleLinear()
  .domain([maxHeartrate, minHeartrate])
  .range([marginTop, chartHeight - marginY - marginTop]);
self.longevityScaleX = scaleLinear()
  .domain([minLongevity, maxLongevity])
  .range([paddingX + marginY, width - marginX - paddingX - paddingRight]);
self.longevityScaleY = scaleLinear()
  .domain([maxLongevity, minLongevity])
  .range([marginTop, chartHeight - marginY - marginTop]);
self.weightScaleX = scaleLog()
  .base(2)
  .domain([minWeight, maxWeight])
  .range([paddingX + marginY, width - marginX - paddingX - paddingRight]);

Finally, we set self.ready to be true since the chart is ready to render.

Defining the views

We have two sets of functions for the views. The first set outputs the data needed to render the axis ticks (I said we’d get there!) and the second set outputs the data needed to render the points. We’ll take a look at the tick functions first.

There are only two tick functions that are called from the React app: getXAxis and getYAxis. These simply return the output of other view functions depending on the value of self.selectedAxes.

getXAxis() {
  switch (self.selectedAxes) {
    case 0:
      return self.longevityXAxis;
      break;
    case 1:
    case 2:
      return self.weightXAxis;
      break;
  }
},
getYAxis() {
  switch (self.selectedAxes) {
    case 0:
    case 1:
      return self.heartYAxis;
      break;
    case 2:
      return self.longevityYAxis;
      break;
  }
},

If we take a look at the Axis functions themselves we can see they use a ticks method of the scale function. This returns an array of numbers suitable for an axis. We then map over the values to return the data we need for our axis component.

heartYAxis() {
  return self.heartScaleY.ticks(10).map(val => ({
    label: val,
    y: self.heartScaleY(val)
  }));
}
// ...

Try changing the value of the parameter for the ticks function to 5 and see how it affects the chart: self.heartScaleY.ticks(5).

Now we have the view functions to return the data needed for the Points component.

If we take a look at longevityHeartratePoints (which returns the point data for the “Longevity vs. Heart” rate chart), we can see that we are looping over the array of animals and using the appropriate scale functions to get the x and y positions for the point. For the pulse attribute, we use some maths to convert the beats per minute value of the heart rate into a value representing the duration of a single heartbeat in milliseconds.

longevityHeartratePoints() {
  return self.animals.map(
    ({ Creature, Longevity__Years_, Resting_Heart_Rate__BPM_ }) => ({
      y: self.heartScaleY(Resting_Heart_Rate__BPM_),
      x: self.longevityScaleX(Longevity__Years_),
      pulse: Math.round(1000 / (Resting_Heart_Rate__BPM_ / 60)),
      label: Creature
    })
  );
},

At the end of the store.js file, we need to create a Store model and then instantiate it with the raw data for the animal objects. It is a common pattern to attach all models to a parent Store model which can then be accessed through a provider at top level if needed.

const Store = types.model('Store', {
  chartModel: ChartModel
});
const store = Store.create({
  chartModel: { animals: data }
});
export default store;

And that is it! Here’s our demo once again:


This is by no means the only way to organize data to build charts in JSX, but I have found it to be incredibly effective. I’ve have used this structure and stack in the wild to build a library of custom charts for a big corporate client and was blown away with how nicely MST worked for this purpose. I hope you have the same experience!

The post Making a Chart? Try Using Mobx State Tree to Power the Data appeared first on CSS-Tricks.

CRUD operations on a db record not using the ID in hibernate

Hi all,
I have an application which saves data (books details like book title, author and location) to a mySql db and performs CRUD operations.
I thought I'd use hibernate to take care of the ORM side of things and everything was OK when it came to create a record, but for RUD operations I had an issue.
If I'm a user, I'm likely to be willing to find a book by its author, title or location, certainly not by its ID and yet as far as I can see, hibernate uses IDs for these kind of operations.
I dug a bit further and eventually resorted to Criteria objects which apparently allow you do perform operations creating your own criteria, see below for the update functionality:

 public void update() {
        // code to modify a book
        Session session = sessionFactory.openSession();
        String searchTerm = "Jack";
        session.beginTransaction();
        Criteria criteria = session.createCriteria(Book.class);
        Book uniqueResult = (Book) criteria.add(Restrictions.eq("author", searchTerm)).uniqueResult();
        uniqueResult.setTitle("Amended plus one");
        session.update(uniqueResult);
        session.getTransaction().commit();
        session.close();        
    }

The problem is that criteria have been deprecated and I can't find a good alternative to that, which now makes me question my choice to use hibernate in the first place. What do you guys think? I wouldn't mind using hibernate but I find hard to believe that to find a record I have to use an ID and not the author, title or whatever else, unless of course you can get the ID of the record from the searchTerm like author etc but I couldn't find a way, all the examples online relied on an ID to be passed on to the query, which I find very odd.
If you fancy looking at the application, it can be found here https://github.com/Antobbo/book-storage/tree/master/src/main/java/com/test (it's not a big project, lol)

Loop Through records in a dataset table

For this particular sub I type the customer id in a text box and then click the button, then I'm trying to get the relative information pertaining to that id.
Not sure what I am doing wrong.

Comes back with an error message of

system.data.sqlclient.sqlexception
Recursive common table expression '[customers]' does not contain a top-level UNION ALL operator.

Private Sub FillByCustomerIDToolStripButton_Click(ByVal sender As Object, ByVal e As EventArgs) Handles FillByCustomerIDToolStripButton.Click

        Try

            Dim customerID As Integer = CInt(CustomerIDToolStripTxtBox.Text)

            ' LOAD THE CUSTOMERS TABLE WITH THE SELECTED CUSTOMER.
            Dim id = Me.CustomersTableAdapter.FillByCustomerID(Me.DatabaseDataSet.customers, customerID)
            If Me.DatabaseDataSet.customers.Count > 0 Then

                For Each row As DataRow In DatabaseDataSet.customers.Rows
                    Dim i = row(id)

                    CustomerIDTextBox.Text = Me.CustomersTableAdapter.FillByCustomerID(Me.DatabaseDataSet.customers, customerID)
                    NameTextBox.Text = Me.CustomersTableAdapter.GetDataBy(customerID).Rows(i)(1).ToString

                Next

                ' LOAD THE INVOICES TABLE WITH THE CUSTOMER'S INVOICES.
                Me.InvoicesTableAdapter.FillByCustomerID(Me.DatabaseDataSet.invoices, customerID)

            Else

                MessageBox.Show("No Customer was found with that ID.", "No Customer Found.", MessageBoxButtons.OK, MessageBoxIcon.Error)

            End If

        Catch ex As Exception

            MessageBox.Show(ex.Message, ex.GetType.ToString)

        End Try

    End Sub

Reusable Popovers to Add a Little Pop

A popover is a transient view that shows up on top of a content on the screen when a user clicks on a control button or within a defined area. For example, clicking on an info icon on a specific list item to get the item details. Typically, a popover includes an arrow pointing to the location from which it emerged.

Popovers are great for situations when we want to show a temporary context to get user’s attention when interacting with a specific element on the screen. They provide additional context and instruction for users without having to clutter up a screen. Users can simply close them by clicking the same way they were opened or outside the popover.

We’re going to look at a library called popper.js that allows us to create reusable popover components in the Vue framework. Popovers are the perfect type of component for a component-based system like Vue because they can be contained, encapsulated components that are maintained on their own, but used anywhere throughout an app.

Let’s dig in and get started.

But first: What’s the difference between a popover and tooltip?

Was the name "popover" throwing you for a loop? The truth is that popovers are a lot like tooltips, which are another common UI pattern for displaying additional context in a contained element. There are differences between them, though, so let’s briefly spell them out so we have a solid handle on what we’re building.

Tooltips Popovers
Tooltips are meant to be exactly that, a hint or tip on what a tool or other interaction does. They are meant to clarify or help you use the content that they hover over, not add additional content. Popovers, on the other hand, can be much more verbose, they can include a header and many lines of text in the body.
Tooltips are typically only visible on hover, for that reason if you need to be able to read the content while interacting with other parts of the page then a tooltip will not work. Popovers are typically dismissible, whether by click on other parts of the page or second clicking the popover target (depending on implementation), for that reason you can set up a popover to allow you to interact with other elements on the page while still being able to read it's content.

Popovers are most appropriate on larger screens and we’re most likely to encounter them in use cases such as:

Looking at those use cases, we can glean some requirements that make a good popover:

  1. Reusability: A popover should allow to pass a custom content to the popover.
  2. Dismissibility: A popover should be dismissible by clicking outside of the popover and escape button.
  3. Positioning: A popover should reposition itself when the screen edge is reached.
  4. Interaction: A popover should allow to interact with the content in the popover.

I created an example to refer to as we go through the process of creating a component.

View Demo

OK, now that we’ve got a baseline understanding of popovers and what we’re building, let’s get into the step-by-step details for creating them using popper.js.

Step 1: Create the BasePopover component

Let’s start by creating a component that will be responsible for initializing and positioning the popover. We’ll call this component BasePopover.vue and, in the component template, we’ll render two elements:

  • Popover content: This is the element that will be responsible for rendering the content within the popover. For now we use a slot that will allow us to pass the content from the parent component responsible for rendering our popover (Requirement #1: Reusability).
  • Popover overlay: This is the element responsible for covering the content under the popover and preventing user from interacting with the elements outside the popover. It also allows us to close the popover when clicked (Requirement #2: Dismissibility).
// BasePopover.vue
<template>
  <div>
    <div
      ref="basePopoverContent"
      class="base-popover"
    >
      <slot />
    </div>
    <div
      ref="basePopoverOverlay"
      class="base-popover__overlay"
    />
  </div>
</template>

In the script section of the component:

  • we import popper.js (the library that takes care of the popover positioning), then
  • we receive the popoverOptions props, and finally
  • we set initial popperInstance to null (because initially we do not have any popover).

Let’s describe what the popoverOptions object contains:

  • popoverReference: This is an object in relation to which the popover will be positioned (usually element that triggers the popover).
  • placement: This is a popper.js placement option that specifies the where the popover is displayed in relation to the popover reference element (the thing it is attached to)
  • offset: This is a popper.js offset modifier that allows us to adjust popover position by passing x- and y-coordinates.
import Popper from "popper.js"

export default {
  name: "BasePopover",

  props: {
    popoverOptions: {
      type: Object,
      required: true
    }
  },

  data() {
    return {
      popperInstance: null
    }
  }
}

Why do we need that? The popper.js library allows us to position the element in relation to another element with ease. It also does the magic when the popover gets to the edge of the screen an reposition it to be always in user’s viewport (Requirement #3: Positioning)

Step 2: Initialize popper.js

Now that we have a BasePopover component skeleton, we will add few methods that will be responsible for positioning and showing the popover.

In the initPopper method, we will start by creating a modifiers object that will be used to create a Popper instance. We set the options received from the parent component (placement and offset) to the corresponding fields in the modifiers object. All those fields are optional, which is why we first need to check for their existence.

Then, we initialize a new Popper instance by passing:

  • the popoverReference node (the element to which the popover is pointing: popoverReference ref)
  • the popper content node (the element containing the popover content: basePopoverContent ref)
  • the options object

We also set the preventOverflow option to prevent the popover from being positioned outside of the viewport. After initialization we set the popper instance to our popperInstance data property to have access to methods and properties provided by popper.js in the future.

methods: {
...
  initPopper() {
    const modifiers = {}
    const { popoverReference, offset, placement } = this.popoverOptions
  
    if (offset) {
      modifiers.offset = {
        offset
      }
    }
  
    if (placement) {
      modifiers.placement = placement
    }
  
    this.popperInstance = new Popper(
      popoverReference,
      this.$refs.basePopoverContent,
      {
        placement,
        modifiers: {
          ...modifiers,
          preventOverflow: {
            boundariesElement: "viewport"
          }
        }
      }
    )
  }
...
}

Now that we have our initPopper method ready, we need a place to invoke it. The best place for that is in the mounted lifecycle hook.

mounted() {
  this.initPopper()
  this.updateOverlayPosition()
}

As you can see, we are calling one more method in the mounted hook: the updateOverlayPosition method. This method is a safeguard used to reposition our overlay in case we have any other elements on the page that have absolute positioning (e.g. NavBar, SideBar). The method is making sure the overlay is always covering the full screen and prevent user from interacting with any element except the popover and overlay itself.

methods: {
...
  updateOverlayPosition() {
    const overlayElement = this.$refs.basePopoverOverlay;
    const overlayPosition = overlayElement.getBoundingClientRect();
  
    overlayElement.style.transform = <code>translate(-${overlayPosition.x}px, -${
      overlayPosition.y
    }px)`;
  }
...
}

Step 3: Destroy Popper

We have our popper initialized but now we need a way to remove and dispose it when it gets closed. There’s no need to have it in the DOM at that point.

We want to close the popover when we click anywhere outside of it. We can do that by adding a click listener to the overlay because we made sure that the overlay is always covering the whole screen under our popover

<template>
...
  <div
    ref="basePopoverOverlay"
    class="base-popover__overlay"
    @click.stop="destroyPopover"
  />
...
</template>

Let’s create a method responsible for destroying the popover. In that method we first check if the popperInstance actually exist and if it does we call popper destroy method that makes sure the popper instance is destroyed. After that we clean our popperInstance data property by setting it to null and emit a closePopover event that will be handled in the component responsible for rendering the popover.

methods: {
...
  destroyPopover() {
      if (this.popperInstance) {
        this.popperInstance.destroy();
        this.popperInstance = null;
        this.$emit("closePopover");
      }
    }
...
}

Step 4: Render BasePopover component

OK, we have our popover ready to be rendered. We do that in our parent component, which will be responsible for managing the visibility of the popover and passing the content to it.

In the template, we need to have an element responsible for triggering our popover (popoverReference) and the BasePopover component. The BasePopover component receives a popoverOptions property that will tell the component how we want to display it and isPopoverVisible property bound to v-if directive that will be responsible for showing and hiding the popover.

<template>
  <div>
    <img
      ref="popoverReference"
      width="25%"
      src="./assets/logo.png"
    >
    <BasePopover
      v-if="isPopoverVisible"
      :popover-options="popoverOptions"
    >
      <div class="custom-content">
        <img width="25%" src="./assets/logo.png">
        Vue is Awesome!
      </div>
    </BasePopover>
  </div>
</template>

In the script section of the component, we import our BasePopover component, set the isPopoverVisible flag initially to false and popoverOptions object that will be used to configure popover on init.

data() {
  return {
    isPopoverVisible: false,
    popoverOptions: {
      popoverReference: null,
      placement: "top",
      offset: "0,0"
    }
  };
}

We set popoverReference property to null initially because the element that will be the popover trigger does not exist when our parent component is created. We get that fixed in the mounted lifecycle hook when the component (and the popover reference) gets rendered.

mounted() {
  this.popoverOptions.popoverReference = this.$refs.popoverReference;
}

Now let’s create two methods, openPopover and closePopover that will be responsible for showing and hiding our popover by setting proper value on the isPopoverVisible property.

methods: {
  closePopover() {
    this.isPopoverVisible = false;
  },
  openPopover() {
    this.isPopoverVisible = true;
  }
}

The last thing we need to do in this step is to attach those methods to appropriate elements in our template. We attach the openPopover method to click event on our trigger element and closePopover method to closePopover event emitted from the BasePopover component when the popover gets destroyed by clicking on the popover overlay.

<template>
  <div>
    <img
      ...
      @click="openPopover"
    >
    <BasePopover
      ...
      @closePopover="closePopover"
    >
      ...
    </BasePopover>
  </div>
</template>

Having this in place, we have our popover showing up when we click on the trigger element and disappearing when we click outside of the popover.

Step 5: Create BasePopoverContent component

It does not look like a popover though. Sure, it renders content passed to the BasePopover component, but it does so without the usual popover wrapper and an arrow pointing to the trigger element. We could have included the wrapper component in the BasePopover component, but this would made it less reusable and couple the popover to a specific template implementation. Our solution allows us to render any template in the popover. We also want to make sure that the component is responsible only for positioning and showing the content.

To make it look like a popover, let’s create a BasePopoverContent component. We need to render two elements in the template:

  • an arrow element having a popper.js x-arrow selector needed for the popper.js to properly position the arrow
  • content wrapper that expose a slot element in which our content will be rendered
<template>
  <div class="base-popover-content">
    <div class="base-popover-content__arrow" x-arrow/>
    <div class="base-popover-content__body">
      <slot/>
    </div>
  </div>
</template>

Now let’s use our wrapper component in the parent component where we use BasePopover

<template>
  <div>
    <img
      ref="popoverReference"
      width="25%"
      src="./assets/logo.png"
      @click="openPopover"
    >
    <BasePopover
      v-if="isPopoverVisible"
      :popover-options="popoverOptions"
      @closePopover="closePopover"
    >
      <BasePopoverContent>
        <div class="custom-content">
          <img width="25%" src="./assets/logo.png">
          Vue is Awesome!
        </div>
      </BasePopoverContent>
    </BasePopover>
  </div>
</template>

And, there we go!

You can see the popover animating in and out in the example above. We’ve left animation out of this article for the sake of brevity, but you can check out other popper.js examples for inspiration.

You can see the animation code and working example here.

Let’s look at our requirements and see if we didn’t missed anything:

Pass? Requirement Explanation
Pass Reusability We used a slot in the BasePopover component that decouples the popover implementation from the content template. This allows us to pass any content to the component.
Fail Dismissibility We made it possible to close the popover when clicking outside of it. We still need to make sure we can dismiss the popover by pressing the ESC on the keyboard.
Pass Positioning That’s where popper.js solved an issue for us. It not only gave us positioning superpowers, but also takes care of repositioning the popover when it reaches the edge of the viewport.
Fail Interaction We have a popover popping in and out, but we do not have any interactions with the popover content yet. As for now, it looks more like a tooltip than popover and could actually be used as a tooltip when it comes to showing and hiding the element. Tooltips are usually shown on hover, so that’s the only change we’d have to make.

Darn, we failed interaction requirement. Adding the interaction is a matter of creating a component (or components) that will be placed in the BasePopoverContent slot. In the example, I created a very simple component with a header and text showing a few Vue style guide rules. By clicking on the buttons, we can interact with the popover content and change the rules, when you get to the last rule the button changes its purpose and serve as a close button for the popover. It’s a lot like the new user welcome screens we see in apps.

We also need to fully meet the dismissibility requirement. We want to hit ESC on the keyboard to close the popover in addition to clicking anywhere outside it. For kicks, we’ll also add an event that proceeds to the next Vue style guide rule when pressing Enter.

We can handle that in the component responsible for rendering the popover content using Vue event key modifiers. To make the events work we need to make sure that the popover is focused when mounted. To do that we add a tabindex attribute to the popover content and a ref that will allow us to access the element in the mounted hook and call focus method on it.

// VueTourPopoverContent.vue

<template>
  <div
    class="vue-tour-popover-content"
    ref="vueTourPopoverContent"
    tabindex="-1"
    @keydown.enter="proceedToNextStep"
    @keydown.esc="closePopover"
  >
...
</template
...
<script>
export default {
...
  mounted() {
    this.$refs.vueTourPopoverContent.focus();
  }
...
}
</script>

Wrapping up

And there we have it: a fully functional popover component we can use anywhere in our app. Here are a few things we learned along the way:

  • Use a popover to expose a small amount of information or functionality. Remember that the content will disappear when user is finished with it.
  • Consider using popovers instead of temporary views like sidebars. Popovers leave more space for content and are only temporary.
  • Enable a closure behavior that makes sense based on the popover’s function. A popover should be visible only when needed. If it allows user to make a choice, close the popover as soon as the user makes a decision.
  • Position popovers onscreen with care. A popover’s arrow should always point directly to the element that triggered it and should never cover the trigger element.
  • Display one popover on screen at a time. More than one steals attention.
  • Take care of the popover size. Prevent making it too big but bear in mind that proper use of padding can make things look nice and clean.

If you don't want to dig too deep into the code and you just need the component as it is, you can try out the npm package version of the component.

Hopefully you will find this component useful in your project!

The post Reusable Popovers to Add a Little Pop appeared first on CSS-Tricks.

Extending Spring Boot’s Zuul Proxy to Record Requests and Responses

An easy way to capture the incoming requests to your server and replay them can be very useful. For example, if you lack an automation team, or simply want to be quick about it, you can record the REST requests of a scenario and play them again after every push to GIT. You can also use the recorded requests to simulate many users. Or, you can analyze the requests to learn useful statistics, etc. You get the idea.

OK, so how can we do it the easy way? First, we’ll exploit spring boot Zuul gateway filters feature – this gateway can activate custom filters for every request and every response. A handler must simply extend ZuulFilter and provide information of:

Multi-Line Truncation with Pure CSS

Truncating a single line of text if is fairly straightforward. Truncating multiple lines is a bit harder. Using just CSS (no JavaScript or server-side dancing) is nice for the simplicity. It's gotten a little easier lately since Firefox (since version 68) has started supporting the ultra-bizarre -webkit-line-clamp soup method, which makes browser support for that pretty OK.

There is another way though, which is very clever and something I'd call a bonafide CSS trick. We somehow failed to cover it properly in our canonical post on line clamping, so I'll cover it here then add it to that post. I first saw this trick on the now-dead Mobify blog, and more recently covered by Natalia Onischuk on HackingUI.

The trick uses line height for measuring

Here's a big part of the trick. Imagine an element has a line-height of 1.4rem and you want to make sure it only shows a maximum of three lines of text. If you set the max-height to 1.4rem * 3, you've done it!

I'm not the worlds biggest fan of united line-height, but alas, it's necessary here to do the math. I'm also not the biggest fan of setting it over and over on elements, so let's set a variable we can use later, and then use it to set a global line-height.

html {
  --lh: 1.4rem;
  line-height: var(--lh);
}

Set that max height

The truncation happens just like this:

.truncate-overflow {
  --max-lines: 3;
  max-height: calc(var(--lh) * var(--max-lines));
  overflow: hidden;
}

You actually could leave it like this. That might be good enough if you don't care about the ellipsis.

The rest of the trick comes in when you want to display that ellipsis stuff

An ellipsis ("...") signifies that text has been truncated and continues longer than what it displayed. Using it is probably a pretty good practice when truncating text so the content doesn't come to an abrupt, awkward end. (Well, the content itself might be awkward anyway, but hey, you tried.)

If you set position: relative on the element, you can absolutely position the ellipsis in the bottom-right corner.

.truncate-overflow::before {
  content: "...";
  position: absolute;
  bottom: 0;
  right: 0;
}

I was very tempted to, instead of setting the bottom, to set the top and use top: calc(var(--lh) * (var(--max-lines) - 1)). My thinking there was that you might as well place the ellipsis at the exact point you need it. If the text is too short, the hidden overflow will cut it off. The problem with that is that it doesn't deal with the "exactly max lines lines" problem. The ellipsis will show when the text matches the max lines — not only when it exceeds that space.

We'll have to get trickier!

Note that this "setting stuff in the bottom-right" thing is pretty specific to left-to-right languages. I'm going to make the demo with CSS logical properties like inset-inline-end instead of right in hopes to make it more friendly to different languages and flow scenarios.

Another limitation is that the ellipsis doesn't attach itself to the final word since it's absolutely placed. We're not going to fix that as well.

Let's cover up the ellipsis when the text is too short

This is the second part of the trick. If we position the absolute at the bottom/end of the text all the time, that's fine. But if the text is exactly equal to the --max-lines value or less, we want to hide it.

The trick there is to make a little box that is the same background as what is behind it and set it on top of the ellipsis to cover it. We can do that with the other pseudo-element:

.truncate-overflow::after {
  content: "";
  position: absolute;
  right: 0; /* note: not using bottom */
  width: 1rem;
  height: 1rem;
  background: white;
}

Another trick we're using here is not setting a bottom (inset-block-end) property. This places the box at the bottom of the content rather than the bottom of the relative parent, which is very useful.

Let me make the boxes red so you can see them in these three different examples:

The top example has more than three lines, so we see the ellipsis. The second example only has two lines, so the red box shows that the ellipsis will be covered up (but imagine a white box instead). The last example shows that this system works even when the content is exactly the same as the value of --max-lines.

Demo

See the Pen
Pure CSS multi-line truncation
by Chris Coyier (@chriscoyier)
on CodePen.

I usedwanted to use CSS logical properties here, as the browser support has gotten pretty good. If you're supporting any version of IE, you'll have to use the bottom and right.

This browser support data is from Caniuse, which has more detail. A number indicates that browser supports the feature at that version and up.

Desktop

ChromeOperaFirefoxIEEdgeSafari
6962*41No7612.1

Mobile / Tablet

iOS SafariOpera MobileOpera MiniAndroidAndroid ChromeAndroid Firefox
12.2-12.346*No677567

The post Multi-Line Truncation with Pure CSS appeared first on CSS-Tricks.

A Peek at New Methods Coming to Promises

Promises are one of the most celebrated features introduced to JavaScript. Having a native asynchronous artifact baked right into the language has opened up a new era, changing not only how we write code but also setting up the base for other freat APIs — like fetch!

Let's step back a moment to recap the features we gained when they were initially released and what new bells and whistles we’re getting next.

New to the concept of Promises? I highly recommend Jake Archibald’s article as a primer.

Features we have today

Let’s take a quick look at some of the things we can currently do with promises. When JavaScript introduced them, it gave us an API to execute asynchronous actions and react to their succesful return or failure, a way to create an association around some data or result which value we still don't know.

Here are the Promises features we have today.

Handling promises

Every time an async method returns a promise — like when we use fetch — we can pipe then() to execute actions when the promise is fulfilled, and catch() to respond to a promise being rejected.

fetch('//resource.to/some/data')
  .then(result => console.log('we got it', result.json()))
  .catch(error => console.error('something went wrong', error))

The classic use case is calling data from an API and either loading the data when it returns or displaying an error message if the data couldn’t be located.

In addition, in its initial release we got two methods to handle groups of Promises.

Resolving and rejecting collections of promises

A promise can be fulfilled when it was successfully resolved, rejected when it was resolved with an error, and pending while there’s no resolution. A promise is considered settled when it has been resolved, disregarding the result.

As such, there are two methods we have to help with the behavior of handling a group of promises depending on the combination of states we obtain.

Promise.all is one or those methods. It fulfills only if all promises were resolved successfully, returning an array with the result for each one. If one of the promises fails, Promise.all will go to catch returning the reason of the error.

Promise.all([
    fetch('//resource.to/some/data'),
    fetch('//resource.to/more/data')
  ])
  .then(results => console.log('We got an array of results', results)
  .catch(error => console.error('One of the promises failed', error)

In this case, Promise.all will short-circuit and go to catch as soon as one of the members of the collections throws an error, or settle when all promises are fulfilled.

Check out this short writing about promises states by Domenic Denicola for a more detailed explanation about the wording and concepts about them.

We also have Promise.race, which immediately resolves to the first promise it gets back, whether it was fulfilled or rejected. After the first promise gets resolved, the remaining ones are ignored.

Promise.race([
    fetch('//resource.to/some/data'),
    fetch('//resource.to/other/data')
  ])
  .then(result => console.log('The first promise was resolved', result))
  .catch(reason => console.error('One of the promises failed because', reason))

The new kids on the block

OK, we’re going to turn our attention to new promise features we can look forward to.

Promise.allSettled

The next proposed introduction to the family is Promise.allSettled which, as the name indicates, only moves on when the entire collection members in the array are no longer in a pending status, whether they were rejected or fulfilled.

Promise.allSettled([
    fetch('//resource.to/some/data'),
    fetch('//resource.to/more/data'),
    fetch('//resource.to/even/more/data')
  ])
  .then(results => {
    const fulfilled = results.filter(r => r.status === 'fulfilled')
    const rejected = results.filter(r => r.status === 'rejected')
  })

Notice how this is different from Promise.all in that we will never enter in the catch statement. This is really good if we are waiting for sets of data that will go to different parts of a web application but want to provide more specific messages or execute different actions for each outcome.

Promise.any

The next new method is Promise.any, which lets us react to any fulfilled promise in a collection, but only short-circuit when all of them failed.

Promise.any([
    fetch('//resource.to/some/data'),
    fetch('//resource.to/more/data'),
    fetch('//resource.to/even/more/data')
  ])
  .then(result => console.log('a batch of data has arrived', result))
  .catch(() => console.error('all promises failed'))

This is sort of like Promise.race except that Promise.race short-circuits on the first resolution. So, if the first promise in the set resolves with an error, Promise.race moves ahead. Promise.any will continue waiting for the rest of the items in the array to resolve before moving forward.

Demo

Some of these are much easier to understand with a visual, so I put together a little playground that shows the differences between the new and existing methods.

Wrap-up

Though they are still in proposal stage, there are community scripts that emulate the new methods we covered in this post. Things like Bluebird’s any and reflect are good polyfills while we wait for browser support to improve.

They also show how the community is already using these kind of asynchronous patterns, but having them built-in will open the possibilities for new patterns in data fetching and asynchronous resolution for web applications.

Besides then and catch you can pipe finally to a promise, Sarah Drasner wrote a detailed piece about it that you can check out.

If you want to know more about the upcoming Promise combinators, the V8 blog just published a short explanation with links to the official spec and proposals.

Get Lat Lng from Google Geocoding API

I have been trying to get Lat Lng from this code using the same call to Google Geocoding API, but I have not found a way.
Any suggestion would be greatly appreciated!

/*!
 * geotext v1.0
 *
 * https://github.com/Frizzled/geotext
 *
 * Copyright (c) 2014 Vladimir Loscutoff
 * Released under the MIT license
 */
var GeoText = (function ($, gMaps, undefined) {
    'use strict';

    function GeoText(vars) {
        this.vars = { // Settings
            'name' : 'default',
            'delimiter' : ', '
        };
        this.data = { // Settings
            'success' : false
        };

        // Merge settings
        if (vars !== undefined) { this.vars = $.extend(this.vars, vars); }

        this.init();
    }

    GeoText.prototype.init = function() {
        var that = this;
        if (navigator.geolocation) {
            navigator.geolocation.getCurrentPosition(
                function (location) {
                    var point = new gMaps.LatLng(location.coords.latitude, location.coords.longitude);
                    new gMaps.Geocoder().geocode({'latLng': point}, function (res, status) {
                        if(status === gMaps.GeocoderStatus.OK && res[0] !== undefined) {
                            that.setLocation(res[0]);
                        }
                    });
                }
            );
        }
    };

    GeoText.prototype.setLocation = function(location) {
        var that = this;
        that.data.success = true;
        $.each(location.address_components, function(k,v1) {
            $.each(v1.types, function(k2, v2) { 
                that.data[v2]=v1.short_name;
                that.data[v2+'_long']=v1.long_name;
            });
        });
        that.applyText();
    };

    GeoText.prototype.applyText = function() {
        var that = this;
        var geoFields = $('[class*=geotext]');
        $.each(geoFields, function(key, field) {
            var $field = $(field);
            var delimiter = $field.data('geotext-delimiter') || that.vars.delimiter;
            var text = that.parseField($field, delimiter);
            if (text) {
                // Check for leading or following text
                if ($field.data('geotext-text-before')) { text = $field.data('geotext-text-before') + text; }
                if ($field.data('geotext-text-after')) { text = text + $field.data('geotext-text-after'); }

                if ($field.is('input')) {
                    $field.val(text).change();
                } else {
                    $field.html(text);
                }
            }
        }); 
    };

    GeoText.prototype.parseField = function(field, delimiter) {
        var that = this;

        // Get rules
        var getRules = /geotext\[(.*)\]/.exec(field.attr('class'));
        if (!getRules) { return false; }
        var str = getRules[1];
        var rules = str.split(/\[|,|\]/);
        $.each (rules, function(key, rule) {
            rules[key] = rule.replace(" ", "");
            if (rules[key] === '') { delete rules[key]; }
        });

        // Generate text
        var text = '';
        $.each (rules, function(key, rule) {
            try {
                switch (rule) {
                    case "address": text += that.data.street_number +' '+ that.data.route; break;
                    case "street": text += that.data.route; break;
                    case "street-long": text += that.data.route_long; break;
                    case "city": text += that.data.locality; break;
                    case "city-state": text += that.data.locality +delimiter+ that.data.administrative_area_level_1; break;
                    case "city-state-zip": text += that.data.locality +delimiter+ that.data.administrative_area_level_1 + ' ' + that.data.postal_code; break;
                    case "state": text += that.data.administrative_area_level_1; break;
                    case "state-long": text += that.data.administrative_area_level_1_long; break;
                    case "zip": text += that.data.postal_code; break;
                    case "county": text += that.data.administrative_area_level_2; break;
                    case "country": text += that.data.country; break;
                    case "country-long": text += that.data.country_long; break;
                    case "lat":  location.coords.latitude; break;
                }
                if (rules[(key+1)] !== undefined) { text += delimiter; }
            } catch (ignore) {}
        });

        return text;
    };

    return GeoText;
})(jQuery, google.maps);

Submit button is not functioning (VB.net and Microsoft Access)

Hi. Im doing a login form with decryption. So i did a modification to my login code for decryption. Before i did the decryption, the login form is functioning well. But after i edit it to insert decryption code it suddenly cannot connect to database. Im still a begginer in vb.net so maybe there is something that Im missing because there is no error in the code so I dont know where did I do wrong.

Here i put decryption code(just in case) and my login code
Decryption Code

 Private Function Decrypt(ByVal cipherText As String) As String
        'Firstly the encrypted text i.e. cipher text is converted into bytes and then similar to the encryption process here too we will generate Key and IV using the derived bytes and the symmetric key.
        'Using MemoryStream and CryptoStream the cipher text is decrypted and written to byte array and finally the byte array is converted to Base64String and returned, which is the decrypted original text.
        Dim EncryptionKey As String = "ABCDEFGHIJKLMNOPQRSTUVWXYZ123456789"
        Dim cipherBytes As Byte() = Convert.FromBase64String(cipherText)
        Using encryptor As Aes = Aes.Create()
            Dim pdb As New Rfc2898DeriveBytes(EncryptionKey, New Byte() {&H49, &H76, &H61, &H6E, &H20, &H4D, _
             &H65, &H64, &H76, &H65, &H64, &H65, _
             &H76})
            encryptor.Key = pdb.GetBytes(32)
            encryptor.IV = pdb.GetBytes(16)
            Using ms As New MemoryStream()
                Using cs As New CryptoStream(ms, encryptor.CreateDecryptor(), CryptoStreamMode.Write)
                    cs.Write(cipherBytes, 0, cipherBytes.Length)
                    cs.Close()
                End Using
                cipherText = Encoding.Unicode.GetString(ms.ToArray())
            End Using
        End Using
        Return cipherText

Login Code**

 Private Sub SubmitButton4_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles SubmitButton4.Click
        'Check if username or password is empty
        If PasswordTextBox1.Text = "" Or UsernameTextBox2.Text = "" Then
            MessageBox.Show("Please fill-up all fields!", "Authentication Error", MessageBoxButtons.OK, MessageBoxIcon.Error)

            'Clear all fields
            PasswordTextBox1.Text = ""
            UsernameTextBox2.Text = ""

            'Focus on Username field
            UsernameTextBox2.Focus()

        Else
            'Connect to DB
            Dim conn As New System.Data.OleDb.OleDbConnection()
            conn.ConnectionString = "Provider=Microsoft.ACE.OLEDB.12.0;Data Source=" + "C:\Users\user1\Documents\Visual Studio 2010\Projects\Crypto\Crypto\crypto.accdb"

            Try
                'Open Database Connection
                conn.Open()
                Dim sql As String = "SELECT * FROM registration WHERE Username='" & UsernameTextBox2.Text & "' AND Password = '" & PasswordTextBox1.Text & "'"
                Dim cmd As OleDbCommand = New OleDbCommand(sql, conn)
                Dim sqlRead As OleDbDataReader = cmd.ExecuteReader()
                Dim Password As String = ""
                Dim IsExist As Boolean = False

                If sqlRead.Read() Then
                    If (Decrypt(Password).Equals(PasswordTextBox1.Text)) Then

                        MessageBox.Show("Login Success", "Success", MessageBoxButtons.OK, MessageBoxIcon.Information)
                        'Clear all fields
                        PasswordTextBox1.Clear()
                        UsernameTextBox2.Clear()

                        'Focus on Username field
                        UsernameTextBox2.Focus()
                        Me.Hide()
                        Mainpage.Show()

                    Else
                        ' If user enter wrong username or password
                        MessageBox.Show("Sorry, wrong username or password", "Authentication Failure", MessageBoxButtons.OK, MessageBoxIcon.Error)

                        'Clear all fields
                        PasswordTextBox1.Text = ""
                        UsernameTextBox2.Text = ""

                        'Focus on Username field
                        UsernameTextBox2.Focus()
                    End If
                End If
            Catch ex As Exception
                MessageBox.Show("Failed to connect to Database", "Database Connection Error", MessageBoxButtons.OK, MessageBoxIcon.Error)
            End Try
        End If
    End Sub