What do you want to learn?
Leverged
jhuang@tampa.cgsinc.com
Skip to main content
Pluralsight uses cookies.Learn more about your privacy
HTML5 Fundamentals
by Craig Shoemaker
In HTML5 Fundamentals, you will learn all about the new and updated markup along with the associated JavaScript APIs that make up the modern web.
Start CourseBookmarkAdd to Channel
Table of contents
Description
Transcript
Exercise files
Discussion
Learning Check
Recommended
Course Overview
Course Overview
Hello and welcome to HTML5 Fundamentals. This is Craig Shoemaker, and I'm glad you're here. As for me, I've worked as a professional developer for over 15 years specializing in the web. I've produced a number of courses here on Pluralsight, written for CODE Magazine and MSDN Magazine, and also for Wiley Publishing. Further, I'm a former ASP.NET MVP and the host of Polymorphic Podcast. And I've been both skydiving and bungee jumping, and I can tell you skydiving is more fun! HTML5 is a big and broad topic that has evolved much over the years. In this course, you'll learn about the intersection of new markup and JavaScript APIs that make up what we now know and love as HTML5. To help grant perspective, you'll learn about the history of HTML5 and what that means for the future. You'll learn about different areas of the API such as selection, media, canvas, forms, and drag and drop. You'll learn how you can get reliable information regarding browser support and how to easily detect if specific features are available in your user's browsers. And since we live in an ever-changing environment, you'll also learn about polyfills and fallbacks and how they can help you work with not yet implemented features today. So I look forward to spending this time with you during the next six modules to learn all about HTML5. So let's dive in together and learn all about HTML5.
Introduction
Introduction
Well hello and welcome to HTML5 Fundamentals. This is Craig Shoemaker, and I'm excited about what you're about to learn in this course. HTML5 has had quite a journey over the last few years, and so during our time together, I'm going to help you see how using HTML5 can make a huge impact on your web application development. To start things off, I'd like to show you a demo of the application that we'll use where you can see the code and see the results of all that you'll be doing here in HTML5. The website that's before you represents the code that's available for download with this course. And every page of the site has all that you need at your fingertips in order to understand exactly what's going on. So the home page here has sections here for every single module that exists in the course. And when you go into a specific area, we'll go into Finding Parts of the Page, you'll notice that you can see a preview of the markup that we'll be working with, as well as the markup itself. So instead of having to inspect element or view source of the page, you can go to the Markup tab and see the markup of the page that we're working with, as well as with any CSS and, of course, the most important parts, any JavaScript. So each one of these pages will have all the code that you'll be learning about available running within the website that you can download as part of this course. Now as we work with each page, I'll open up the Developer Tools, and as we work with each command, you'll be able to see the result here in the console, and it's interactive as well so you can see the results right here on the page. So even though I'm running full-screen, this is just a basic regular everyday website. But it's all tailored specifically for your learning here in HTML5 Fundamentals. So now let's talk in depth about what you'll be learning in each one of the modules of the course.
Overview and Prerequisites
As for an overview of the course, the introduction to this course is quite meaty and packed with information relevant to you right away. We'll briefly cover some history and how it relates to you today. And then move on to getting you acquainted with the HTML elements and JavaScript APIs associated with HTML5. By the end of this module, you should have a solid grasp as to what HTML5 is and how it can help you in your everyday development. Next, we'll dig in to the details and delve in to the APIs responsible for making easy-to-find parts of the page. This is the selection API. By the end of this module, you'll have a solid foundation set for what it takes to work with the document object module or the DOM. Now no web application is complete without the ability to gather data from the user. So in the next module, you'll learn all about the special features available in HTML5 built specifically for web forms. And in the Music and Video module, you'll learn how to use the native browser support to host media in your web page. Next, you'll learn about the browser's native drawing context, which is called the canvas. And here you'll learn to draw and control elements on the page and even go so far as to build dynamic charts all in JavaScript. And in the final module, you'll learn to begin to take pages truly interactive by learning about the drag and drop API and see how to implement a drag and drop module specifically for jQuery. Now that you've had an idea of where we're headed, let's move on to a few prerequisites for this course. Now for prerequisites, there really aren't many. First, it helps if you have some familiarity with HTML in one form or another. If you're brand-new to web development, don't worry, I'll take it slow. But it does help if you know what an HTML element is going into this course. Next, while experience with JavaScript is not required, for this course there's a fair amount of JavaScript used with HTML5 APIs. So some familiarity will help. But what you need to know really are the very basics like knowing what a variable is and what functions are. The sample application uses Node.js to automatically launch the website in a browser. Some of the APIs covered later in the course have a security restriction that requires files to be served from a server rather than the file system, so I'll use a very, very simple Node.js setup to make it easy for you to launch the sample app into a browser window. If we're looking at the Node.js website, go to nodejs.org. And when you go to the Downloads page, you'll see that there's a Windows installer and a Mac installer. You can download it, install Node.js, and as we begin working with the sample application, I'll show you how to get everything set up. Lastly, in the forms module, we interface with the Bootstrap layout framework. But this interaction is very brief, and you don't really need to know Bootstrap in order to understand this part of the course module. And in the section on drag and drop, I show you how to create a module for jQuery that interfaces with drag and drop. But, again, you don't really need to know jQuery in order to understand this. I'll just show you how to works together. Well if you've got Node.js installed, then I think we're pretty much ready to go. So now I want to start talking about how you begin to think about HTML5.
What Is HTML5?
The Wikipedia definition of HTML5 is a markup language used for structuring and presenting content on the World Wide Web. Well I'm sure that clears everything up for you nicely, doesn't it? Simply put, HTML is a way of describing the structure of content rendered on a web page. Take a look at this code for a moment. By scanning the HTML elements in this document, you get a general idea of the content on the page from the header to the main content to the page and all the way down. Now in earlier versions of HTML, the containers weren't so specialized. Before HTML5, all we had to work with was general containers, and this was a problem for search engines. By only having the generic elements to work with, elements like a div, which stands for division, or a span, which is a container used for smaller amounts of content, search engines couldn't be as accurate as they would like to in trying to figure out the most important parts of the page to index. So a big part of HTML5 is the addition of containers or HTML elements that are very specific about the purpose and intent of the content it's describing. So, what is HTML5? HTML5 is the combination of new HTML elements and sometimes new attributes to existing elements plus new JavaScript APIs implemented in the browser, and there're a lot of them. And all of that together is what's considered HTML5. But some people even today say that HTML5 doesn't exist. Well to unpack that bold statement, let's take a short step back and quickly review the history of HTML5.
History of HTML5
It's time for a very short history lesson on the legacy of HTML and HTML5. And along the way, I think we'll get a clear picture of the difference between HTML and HTML5. The purpose of this brief explanation is not to provide a detailed account of the drama and intrigue that surrounds what we now know as HTML5, but rather as a high-level overview of what will help you recognize the relevant and main players in the formation of HTML5 because a few of these names will come up from time to time. Now back in the early 90s, Tim Berners-Lee publishes the proposal for hypertext markup language or HTML, along with the first browser and first server software. Now speaking of the first server, This is a picture of the first-ever web server. There's so much to love about this image, particularly the warning sticker that someone obviously tried to scrape off. So that's the birth of the web. Next, things needed to formalize a little bit. After a number of years of evolution, the direction and development of HTML as formalized in the foundation of the World Wide Web consortium or W3C. This is the birth of the first HTML specification. Interestingly, this is mainly a formalization of what HTML is already rather than the description of new features, which is a bit different than what we have today. So as development continued, one of the first major changes to HTML emerged in the form of HTML4. HTML4 was a really big deal in the world of web development because this was the first time it was possible to build animation and true interactivity into a web application. Now things get a little interesting. After the rise of HTML4, the W3C began work on the next version of HTML, which is mean to alleviate many of the shortcomings encountered after years of working with HTML in the real world. The next iteration was known as XHTML. This turned out to be a bit of a mistake. The whole aim of XHTML was to make HTML more strict and, therefore, harder for people and machines to work with, which should have been the first sign that we were headed down the wrong path. Well, we all have good intentions, but in the end the loser here was the end user. So something big had to happen next. A line was drawn in the sand. One camp at the W3C wanted to continue to evolve HTML, and the other wanted to leave HTML behind for favor of the stricter XHTML flavor of the markup. So then the HTML working group, known as the HTML WG, was formed to champion moving beyond HTML. But this proved to be a short-lived endeavor. Upset by the direction the W3C and the HTML WG was headed, an independent group calling themselves the web hypertext application technology working group (yeah, I know, big old acronym there) was what we call the WHATWG (yeah) was formed with the express intent of continuing to push HTML forward. Now what's interesting is that the most significant differences between these groups is really found in their culture. While the specifications emerging from the W3C is determined by consensus, the working group spec is driven by a single editor. This allows the WHATWG to make advancements in HTML much faster than at the W3C. And that is a very good thing. This difference still persists today, and it helps push the web forward, while at the same time ensuring quality and standardization of the spec. So now we arrive at the advent of HTML5. The HTML working group is largely disbanded, and the W3C and what the WHATWG decide to do is work and collaborate on what we now think of as HTML5. They're still working independently but continue close collaboration as a specification evolves. And again at the WHATWG, you have a more nimble and fluid environment where advances come a little more fluidly, while the spec at the W3C is treated with a little more academic rigor. So in one sense, you get the best of both worlds. So once everyone is in large part playing nice together, the WHATWG announces that it will no longer work on named versions of HTML. So this means instead of planning for HTML6 or HTML7, the HTML spec is now a living standard. This move makes a lot of sense if you think about it. With HTML5, you have a set of functionality that exists in the specification but is implemented at different times and at different levels of completeness by the different browser vendors. So to say whether or not your application could "use HTML5" is a bit of a misnomer. You could often use parts but not all of the APIs. So to sidestep this issue entirely, HTML continues to evolve as a living standard. This means that as new features are developed, they're added to the spec. And then hopefully soon after are implemented by the browser vendors. So you may hear people say that HTML5 no longer exists. And so when they say this, what they mean is that the latest and greatest version of HTML is simply not numbered. It's found in the living standard. Now while all this is true, I still do often talk about the HTML5 elements and new APIs as HTML5 simply out of a force of habit. So it's a bit futile to try and figure out exactly what is and is not in HTML5. What I want you to be concerned about are the different resources that are available to you that give you the tools that you need to find out what's best for your application and your situation. And one of those resources is platform.html5.org.
HTML5 Platform
So here we are platform.html5.org. And as you can see here, there're a number of different advancements and APIs that are considered under the umbrella of HTML5. And you'll also notice some familiar names here. So we have icons and links over to the W3C and also to the WHATWG. And there're other standards bodies as well that make up specifications that are considered a part of HTML5. So if you want to get a good idea of what's in HTML5 or the living standard, you can always come to platform.html5.org. But let's not stop there because what I've got prepared for you next is a roundup of many of the different advancements that are a part of HTML5, and that's coming up next.
Standards Bodies
So like I said, there're a number of different standards bodies involved in creating the specification for what we know as HTML or HTML5. But there're three big players that you need to be concerned with. And the first one is the W3C. The second one is the WHATWG. And so we've covered these two. These are the two organizations that spend a lot of time trying to figure out what sort of functionality should be built directly into the browser. And the third one is ECMAScript. Now this is the organization that's responsible for the evolution of JavaScript. So when we're talking about new JavaScript features, we're talking about specifications that emerge from the ECMAScript standards body.
What, Why, and When
As the web platform or HTML5 continues to evolve, you'll need to make decisions about what to use and when to use it because as you saw in the timeline earlier in the course, HTML is a continually growing and evolving ecosystem. So you need a framework to help you figure out how to answer some of these questions. The first thing that you need to ask yourself is What? What advancements to the web platform are applicable to you? And there're a lot. I mean, a lot available within the browser now. So you need to be able to figure out what are your application's needs and what APIs are available that you can take advantage of. Next, you need to be able to figure out how to match the functionality to the business needs or the needs of the application that you're building. So what sorts of needs are you trying to meet? And then at that point, you can ask yourself the question of When? Are the APIs ready? Is the browser support there for you? Is everything that you need available in order for you to take that next step to build your application using these advancements? So let's take a look at What. Let's take a look at what APIs are available inside the browser.
What: Structural Elements: Part 1
There are a number of new elements in JavaScript APIs that are introduced in HTML5. And the elements include some feature-rich elements that allow you to draw on the page like canvas down to a little more mundane functionality like giving the browser a hint of where to conduct hyphenation in a long word. Let's take a few moments to review each new element. Now the point behind many of these elements is not necessarily to add any new distinctive behavior to the page itself, but rather to describe content within the page to a search engine. For instance, let's take the main element. The main element is used to wrap, well, the main content of the page. The point of an element like this is to tell a search engine that the most important information regarding search relevance is in this element. By way of contrast, navigation links in the header, copyright information, and other such secondary content would not be in the main element. Inside the main element, you may very well find the article element. And as the name of the element hints, the content that goes inside the article element represents a way to group together information signaling to the search engine that the content inside is really important as opposed to content that might be surrounding it. This is just getting even more specific than what's found in the main element. And, in fact, you can often have more than one article element on the page. Here, you might find a literal magazine article or maybe a blog post or any markup that makes up the primary content of the page. Now like I noted previously, this is one of the elements that doesn't change the look or the behavior of any of the content in the browser, but it gives what we call semantic meaning to the content. So if you wrap your content inside an article element, the search engine will know that this information is the most important content on the page in relevance to the search request. Now in contrast to the content found in article, you may have some side content that you want to feature on a page. So the aside element is used to flag content that might be important, but maybe not as necessary as the rest of the content on the page. The best way to think about this is like a sidebar in a printed magazine. So while this information may be important, it's not crucial to what's being displayed on the page. Now sometimes you might have content that's best grouped together in a logical way, and that's the purpose of the section element. Section is a bit like the div element. You use it to group related content, but the grouping is for a logical group rather than for visual purposes, which is often how a div is used. And all of this content is often framed by a header or footer. The header and footer are such a common construct that the associated elements are tailor-made to create a logical bucket for this content. By surrounding appropriate content with these tags, you can signal to a search engine the purpose for the markup inside these areas. Now one of the most common elements found inside a header or footer is the nav element. The nav element is a logical container for site navigation. This is explicitly reserved for links that point to locations a part of the origin web page. So, in other words, you would have links to the Contact, About Us, and Events pages of the website, but you wouldn't add in links to other domains from inside the nav structure. You can certainly still add those links inside the header and footer, but you just don't include them inside a nav element itself. So if we take all the elements I've described so far, you can begin to see the logical skeleton of a typical web page. From this view, you get an idea of how a search engine can easily locate appropriate parts of the page. So that covers high-level structural elements. So next let's turn our attention to some of the more specialized new elements found in HTML5.
Structural Elements: Part 2
The time element helps you semantically identify a point in time. Here, you can specify just a time, just a date, or a specific datetime. In addition to formalizing time data, the element includes the optional pubdate attribute. A single web page may only have one time element with the pubdate attribute present. And when it does, it acts as the timestamp for the publication date of the web page. Now images are another aspect of the page that get more formal attention. The figure and figcaption elements are meant to provide semantic meaning to search engines for images and diagrams. Now as you can associate a caption with an image, the search engine has a better idea of what's in the image as the caption is logically linked to the figure as you see here in the code sample. So now let's turn our attention to a familiar UI concept found on many pages. You've probably seen it a hundred times. You load a web page and click on the title. And underneath that, it expands to show some more detail. Well this is how the details and summary elements work. This is a no-JavaScript way of adding just a little bit of interactivity to the page. And I'll show you an example of the details and summary in action in just a bit. But just know that not all HTML5 features are implemented at the same rate. Here now in 2016, not all browsers have implemented this simple bit of functionality. But don't worry. In a little bit, I'm going to show you how you can reliably find out what elements are implemented in which browsers so you can make the best decision for your application. Now I've talked about search quite a bit so far. And the next element can help you refine markup returned as the result of a search. The mark element is intended to be used to wrap text in search results to highlight the matched term. While you could certainly accomplish the very same thing with a span element and some specialized CSS, the mark element, once again, provides semantic meaning to the matched term. Now, speaking of individual words, not all words on a web page go from left to right. The next element is called bdi, which stands for bidirectional isolated element. Basically this is what you want to use for content when you need to change the horizontal direction from the surrounding text. So, for instance, let's say you have some Hebrew text that you want to show in the midst of an English paragraph, well the browser supports that just fine. The next element is a little bit special. If you have a really long word, I mean a really long word, then the wbr or wordbreak element can come in very handy. This element tells the browser where to hyphenate a word when wrapping is required. You won't use this often, but it does come in handy when you need it. Oh, and by the way, the correct pronunciation of this Shakespearean word is honorificabilitudinitatibus or something like that. So next up is the output element. So this element is really a bit curious. The point of this element is to have a semantic tag to contain the results of some sort of calculation. So you could think of a calculator, and you would use this element to show the result of the calculations for that application. So, sure, you could use many other elements for that same purpose. But this gives semantic meaning to the output of the calculation. Now this next element may be considered new, but it doesn't really get much attention these days. The purpose behind the embed element is to be a host container for external plugins. While this may have been an important feature a few years back, the current state of web development is pushing towards using as many native APIs as possible. So don't expect to use the embed element much anytime soon. Well, this wraps up our survey of structure elements. Now let's take a look at a few elements that not only wrap content on the page but also include robust JavaScript APIs.
Elements with APIs
If you want to draw on the page, then you'll use the canvas element for that job. Now I'll go into depth on canvas during the Drawing Shapes, Charts, and More module. The audio and video elements are largely the same thing with the obvious exception that the video element plays video and the audio element plays sound. The code sample as shown here demonstrates how you can add a source and track elements to the video tag on a page in order to define the supported media and options. Together we'll dive in to more details in the module that focuses in on native media. But for now, just know that these elements have become much more practical since the rise of mobile devices and the decline of Flash. Now the final section of elements are often used in forms and for visualizing data.
Form Elements
The meter element is intended to visually demonstrate the value between a threshold of values. You could use it to represent remaining battery power, product ratings, and so on. A related element is the progress element. This is a native element that gives you the opportunity to depict how far along you are in an application's process. This is a welcome addition as in the past we were left to having to implement progress bars manually in JavaScript. Now, the next element is a fairly specialized one. I'm not sure if you're like me or not, but I remember my first day of statistics class and the panic I felt the first time I saw the formula for standard deviation. It looked like a strange and foreign language. Well the math element allows you to define equations and formulas and allows you to render them on the page as you might expect them to look in a textbook, something like this. And the final element is the datalist element. With this element, you have the opportunity to define a list of elements that are shown as options in an input field. You see this in action during the module on forms, but this single element makes it super easy to provide users with an editable drop-down list. So to back up just a bit, out of the new elements available in HTML5, the first demo that I have prepared for you uses each element here that's not grayed out. So we'll get to that demo in a moment. But before we do, I want to review with you some of the JavaScript APIs that you'll encounter as you dive in to HTML5 development.
New APIs - Graphics and Typography
One of the interesting things about web development and HTML5 is the fact that much of the advancements on the web platform are found in JavaScript APIs rather than to HTML itself. In this section, I'll give you a brief survey of just some of the APIs added to the web platform and associated with the advent of HTML5. In fact for detailed descriptions and links to in-depth examples, make sure you spend some time at platform.html5.org. So among the new APIs, let's begin with graphics and typography. As I mentioned in the section on HTML elements, HTML canvas is a combination of both HTML and the JavaScript API. There's a whole module dedicated to the canvas coming up, so for now I'll just say that the canvas is a very powerful feature that gives you full control to draw on an HTML page. Now in the past, animation on web pages has generally been done either in JavaScript or VS CSS animations. The Web Animations API looks to be an effective means to better mix the use of JavaScript techniques and CSS animations when doing animations on a page. The next group of APIs are related by interactions, events, and messaging.
Interaction, Events, and Messaging
This group can make a big difference in the functionality in user experience of your applications. The first is Battery Status. As many applications are tailor-made to run on mobile devices, the Battery Status API allows your application to be aware of the amount of juice left on the device. This gives you the opportunity to adjust how your application behaves at differing levels of power. The Clipboard API and Events gives you programmatic access to the clipboard. Now before this API, we had to use Flash fallback implementations in order to have access to the clipboard. Now this is native functionality in the browser. In some cases, you may find that you want to send a message from a page on site A to a page on site B. The Cross Document Messaging API will allow you to do just that. When dealing with mobile devices, sometimes you want your applications to be able to respond to changes in the orientation of the device or screen. These APIs give you the events to respond to to recognize movement. And whether you're building a game, a kiosk app, or you just want a clean user experience, the Fullscreen API gives you and the control to make your app fill the entire client screen. Being able to find your user's location is possible via the Geolocation API. This API uses a number of different approaches to attempt to find the user's device using Wi-Fi, cellular, and GPS positioning. When looking to allow your application to record audio and video and take pictures, the Media Capture API grants you programmatic access to native devices to capture media. The Notification API gives you the ability to create toast-like pop-up notifications on the desktop. And for mobile devices, you can get access to touch events so you can respond to different types of gestures in your application. The last API in this group is a way to control the vibration capabilities of the device. Now the next section groups together APIs that deal with storage and files.
Storage and Files
When it comes to storing data on the client, there're a number of different APIs available to you. Blob URLs, the File API, and the File Reader are all related HTML5 technologies. Let's start with the File Reader and work backwards. The File Reader class provides a way for you to read in-browser file data that can come in a few different forms. The File class and Blob URLs expose the same set of functions or more formally show the same interface. But instances of the File class represent actual files in the browser's file system. And blobs represent data in chunks of bites. So blobs are a very low-level way of representing data in the browser. On the other hand, the IndexedDB API is a sophisticated object where document database is implemented entirely in the browser. If you have large sets of data that you need to store and query on the client, then IndexedDB is a great candidate. If your needs are a little bit more basic, then Local Storage may be a better fit. With Local Storage, you have the option to store data for long periods of time or just for the session. And sessions are determined by the lifespan of a browser tab. And each flavor of the API uses the same interface, so working with local storage is very easy. Now there's a lot more to come on local storage in an upcoming module. So next, let's look at APIs that facilitate real-time communication.
Real Time Communications
When dealing with real-time communication, the first API is called Push. Now as the name suggest, this API gives you the opportunity to push data from the server to the client. And it gives you a lot of flexibility. Data can be pushed to the browser even when it's running in the background on the computer. And this greatly improves performance of applications that need real-time data from the server. The next two APIs, Server-Sent Events and Web Sockets, are similar in nature to Push but are distinct technologies. Both address the need for the client to receive messages directly from the server. But they achieve it in different ways. Server-Sent Events work with a one-way channel of communication from the server to the client. And messages are sent via HTTP, which means there's no specialized server technology required. On the other hand, Sockets facilitate two-way communications and work under custom communications protocol. Now if any of this sounds confusing, no worries. Make sure to check out my Advanced HTML5 course here in Pluralsight where I spend an entire module discussing Web Sockets. Next up, let's talk about how HTML might look if you could customize the names and meanings of the very HTML tags.
Web Components
Now web components is an umbrella term for a handful of technologies that enable web developers to take control over the markup created for a website. Using custom elements gives you the chance to change a series of nested generic elements like a div and a span and turn that into custom named elements that better represent the meaning and intent of the markup. Here, let's take a look at an example. Consider this set of markup. There's a handful of div elements used as containers for layout structures, as well as layout for the data itself. This kind of markup can be a bit hard to read especially when you compare it to the equivalent of how you might achieve the same results using Custom Elements. Here, you can at a glance understand the meaning and intent of each element. And this is the benefit of Custom Elements. Now notice how the entirety of the comments section is wrapped in the comment element, and every bit of content of a comment is enclosed in a comment element. This customization of elements begins to provide encapsulation of not only content but also the underlying DOM elements that make up this custom element. So when we're talking about creating hard boundaries around the DOM tree, what we're really talking about is the Shadow DOM. And as strange as the name sounds, the Shadow DOM is simply a way to encapsulate element trees in the DOM. What this means is that you can apply CSS and JavaScript to elements contained in the Shadow DOM, and it won't leak out to affect the rest of the page. This is the heart of web components, that you have Custom Elements with a self-contained structure, style, and JavaScript logic. The last in the group is Templates. Different forms of templates have been around for many years through the use of one JavaScript library or another. This advancement makes templates a first-class citizen in the browser. Now if you're not familiar with templates, this is a way to create a pattern of HTML and easily fill it with data before displaying it on the screen. Well we've covered a lot of ground up to this point. There're just three more sections left of JavaScript APIs that I want to introduce you to. And the next one is Performance Optimization and Analysis APIs.
Performance Analysis
Whenever we're measuring performance, using a stopwatch is not going to cut it. The High Resolution Time API gives you the opportunity to measure time with sub-millisecond accuracy. This is great for measuring operations and calculations. But if you really want to measure things like page load time, then us the Navigation Timing API. With this API, you can find out how the user navigated to your page and are able to respond to custom events related to the page load lifecycle. Have you ever wanted your page to behave differently when it wasn't the active tab in the browser? Say pause music or video perhaps? Well, if so, the Page Visibility API will allow you to respond to changes in the page's visibility based on the tab state. Now the accuracy provided by High Resolution Time pays off when you use the User Timing API. Here, you have a simple interface available to create timing boundaries inside your code giving you an easy way to measure at a high resolution how your application performs. And, finally, we have Web Workers where you have a chance to get huge performance gains by using different threads in the browser. When you create a web worker, the execution context is in an entirely separate thread in the browser. These extra threads are completely independent of the UI thread so you can crunch some serious numbers in the background, and the user will never know what's happening behind the scenes. Well the next category deals with security and privacy.
Security and Privacy
One of the most basic attacks on a website is the cross-site scripting attack where foreign scripts are introduced into a page that compromises the security of a web application. To mitigate these attacks, the Content Security Policy allows you to create a whitelist for sources of a page including scripts and styles. The Referrer Policy gives you tighter control over the amount of data that's transmitted through the HTTP referrer. And, lastly, the Web Cryptography API provides a way to encrypt and decrypt data entirely on the client. Now for the final category, everybody's favorite, the miscellaneous items.
Miscellaneous APIs
These updates don't fit naturally into any previous categories, so let's just take a look at them one at a time. For script elements, there're two new Boolean attributes available. The async feature allows a script to run in an asynchronous manner so that it won't block the execution of the page. And defer slices it a little bit differently. The attribute ensures that the script execution is deferred to after the page load. Next is the contentEditable attribute, which allows any element to be switched into an edit mode so that virtually any part of your page can be an editor. The Drag and Drop API makes it easy to implement drag and drop behaviors with a native browser API. Now there's more coming on that in this course. The History API allows you to take control of the browser's location by giving you a chance to make changes to it without requiring a trip back to the server. Further, you can also make changes to the actual browser history by using additions to the History API. Now the native addition of Promises is a huge win for web developers. By having a native Promises API available, you can easily write asynchronous code in a clean and clear manner. And, finally, we arrive at Service Workers. A relative newcomer to the HTML5 family of APIs, the Service Workers have replaced the previous Application Cache API. The intent around Application Cache was that you could create an offline web application by maintaining a list of all the files needed to run while offline. But that implementation proved to be too brittle in just about every browser. Therefore, the Service Workers API was created to address many of the shortcomings of the Application Cache with an entirely new API and implementation. So if you need your website to work offline, you're looking for Service Workers. Wow! We've covered a lot of ground in a short period of time. And, remember, this is many but not all of the APIs that fall under the HTML5 umbrella. So taking a step back for a moment, I want to summarize for you again that HTML5 really is new HTML elements and in some cases new attributes to existing elements plus new JavaScript APIs and in some cases enhancements of existing ones, but in the end, you have this growing ecosystem of what is really a web platform giving you more and more capability and reliability built into the native platform of the web. These are exciting times. But there're still two more parts to the What, Why, and When equation to discuss. So let's briefly touch on Why.
Why
Once you know what's available, then you need to probe the needs of your users and your applications to see which technologies fit for your circumstances. Now, obviously, this is a decision that only you can make. But as an example, you may find that you need to improve the performance of your application, which may lead you towards some of the timing APIs to instrument your code to find bottlenecks. From there, perhaps you realize that some of the lookup data is taking too long to fetch from the server, so you realize that you can cache the data on the client in an IndexedDB datastore, and then from there create a wrapper around the native API using new features of the Promises API. And it can go on and on from there, and every situation is different. But at this point, you want to find the right tool for the job, and the web platform or HTML5 has much to offer. So once you've nailed down what problem you're trying to solve, and you have some HTML5 APIs that you're considering implementing in your applications, the next issue is to deal with browser support. And this is a big deal. So let's talk about how to know when an API is considered ready to use and what to do if you need it before browser support is widespread.
When
As with many things in life, timing is everything. To fully appreciate the browser support conundrum, it's best if you understand the nature of how enhancements are made to browsers. Advancements on the web is not a linear endeavor. New features are proposed, and the spec is written. From there, browser makers have to make a decision of how many resources to allocate towards implementing a new feature. And just as with any development team, and this is true even for open source projects, developer resources are limited, so new features can only come so fast. Now, each development team independently selects what projects to work on. So different aspects of HTML APIs are implemented at different rates among each browser. And this is why the classic browser support disparity exists. So let's take a look at an example. Earlier in this module, I introduced you to the Shadow DOM. And this is the support profile from caniuse.com from spring 2016. At the moment, Chrome, Opera, and Android browsers are the only ones with a comprehensive implementation. Now I'm sure Microsoft Edge will eventually support it, and Firefox and WebKit have people on it. But this just illustrates that the implementations are progressively rolled out through the browsers depending on the focus and attention of the respective development teams. So when is HTML5 considered done? When you can take for granted all the features that are just there? Well you really can't. Since new features are worked on at different rates with a continually evolving living standard, you're best to think of the web as based on a continually evolving platform. Now there're some ways that you can deal with all this uncertainty, which lie in feature detection and the use of fallbacks and polyfills, which we'll discuss in short order. But for now, let's crack open the code editor and take a look at some of the basic differences between HTML4 and HTML5.
HTML4 vs. HTML5
Now that you have a lot of context to work with, let's turn our attention to some code. What we'll do is quickly review an HTML4 page and then look at the equivalent page written in HTML5. And I'll note some of the main differences along the way. So let's start the discussion off with a very basic page. You'll notice here that I have a page that is a home listing, and I've got the address, a picture of the home, a description, some features, and that's about it. Not a lot of content. But what we do have here is just about all the building blocks that we need to discuss just about any web page. So now let's take a look at the code that's required to make this page. And we begin with an HTML4 page. And the first thing you'll notice is I'm declaring a DOCTYPE. Now this is set as a Transitional DOCTYPE. And this is important because we want to give a clue to the browsers of how to interpret this page as it encounters the markup. Being a good XHTML citizen, I went ahead and put in a namespace, again, so the browser knows how to interpret the markup, and what sort of rules to enforce as it's interpreting the page. Further down, there's a little style that's being applied to the page. And I'm setting the content type to text/css. And also the same thing with JavaScript, the content type is being set to text/javascript. And then I have the basic construction of the page. So I have a container here for the header. And I can collapse the navigation area. I have a container for the main content. And, lastly, as I scroll down to the bottom of the page, I have some scripts that reference jQuery, Bootstrap, highlight.js, and the application itself. Setting all of them to type equals text/javascript. So if you're familiar with web development, all of this should look pretty familiar to you. So now let's take a look at the same page writing a little bit different using HTML5, and let's discuss some of the differences. Now when we take a look at the HTML5 page in the browser, it's basically the same thing except we'll notice a few changes that are actually quite considerable. So I've got my picture and my describe, but when I come down here to the features, if you remember in HTML4, those features were there, but they were just kind of sitting there in the middle of the content. Here, I have this set as an aside, and I have summary and details set up. So I can expand and collapse this information. And, again, this is a no-JavaScript approach to building this type of interaction. This is all done with HTML5 elements. As I come down here, you'll notice I've got a video. Now since HTML5 supports native video, I can go ahead and embed this video into the page. And everything looks and works great, as well as having a pubdate set down at the bottom of the page. So, again, for the most part, things are much the same. We've got it lighting up a little bit with the summary and the details. And we've got the video. So now let's take a look at the underlying markup so we can talk about some of the differences that you'll see there. Now here inside the code, you'll notice on line 1, we still have DOCTYPE, but it's just HTML. That's all there is. We don't need to create a traditional DOCTYPE or a standards DOCTYPE or anything like that. This just says HTML. And this flags to the browser that it can interpret this page as an HTML5 page. And that does two things. Number one, it gives you the ability to access all the new elements and JavaScript APIs on the page. And, number two, it does away with some of the very strict rules that were in force with XHTML. Now I'm setting the language for the page, and then you'll see some best practices used in this page that you want to pay close attention to. So here I'm saying that the character set for the page is utf-8. And then the http-equiv, x-ua-compatible, content set to ie=edge only has relevance for Internet Explorer and basically is telling Internet Explorer to try and use the latest version possible. Down here on line 7, this is important for mobile devices. Here it's saying you want the width of the page to be device width and setting the initial zoom level or the initial scale to 1. Now as we come down the page a little bit, again, we've got style and script elements. But you'll notice the type attribute is missing from style and script. So pretty much for styling a page, CSS has exclusively been the only language we've used for a very long time. So CSS is the default language used for the style element, so you no longer have to add it. For scripts, JavaScript has been the de facto standard for a very long time. There was once a day where you might add interactivity to page using VBScript, but that was a very long time ago, and you won't see that anymore these days. So JavaScript is the default language. So when you're doing inline scripts, you do not need the type element. Now when we talk about loading scripts in from external sources, down here I'm bringing in scripts using an extra request so the type argument is required. But it's only required when you're referencing external JavaScript. Let's go back up to the top of the page for a moment. Now if we take a look at the contents of the page, you'll notice that many of the elements are quite different. So within the body of the page, first, we have the main element. And with the main element, you can have one and only one main element on each HTML5 page. Inside of that, we have the header for the page itself. And then inside the header, we have nav. Now the nav element as you may recall from the slides said that any links or navigation found within that element point to a location within the website itself. So we're not linking to external sites from here. So we're saying this is the navigation for the site here itself. And that's very important for search engines. So that makes up most of the header, which is the navigation. And now we have an article on the page. Now the article wraps up the primary content for the page. This does not have the same restrictions as the main element. You can have more than one article on the page. And, in fact, a very practical application might be, let's say, you're building a website for an actual magazine. You may have more than one article on the page, but this gives a heavier weight to the content found in these elements, especially when it comes to search indexing. Now something else that you might find interesting is that inside the article, I also have an h1 element. Now before you could have one and only one h1 element on the page in order to achieve high search engine rankings. But now since elements have a semantic meaning to their parent, you could have an h1 inside the header and inside the article and perhaps even inside the footer. So now you're not stuck with saying that this is the heading, the main heading for the entire page. So depending on the container that it's in, you can say that this is the main heading for that specific container. And so in this instance, this is the main header of the article. Now next we have a section, and sections are used to create logical groupings of content that's on the page. Now before HTML5 we would just use divs everywhere. And divs are great. And often the practical application between a div and a section, they're basically the same thing. But what you want to do is use divs when you need to change the appearance of something on the page. So if you need a container to attach some style rules to, then you'd use a div. Now you use a section when you want to create a logical group between elements. But it doesn't have any sort of change on the final UI. So, here I'm creating a section, and inside that section, I have an anchor tag. Now what's interesting about this anchor tag is that before in previous versions of HTML, you could not have a block level element wrapped by an anchor. Now what do I mean by that? Well if we go back to our page, you'll notice that this whole image along with the caption is a link. And that is established by one single anchor tag. So that anchor wraps around the image and the caption, which provides a link for the whole thing. So now you can use anchors to provide links to block level items, as well as inline items. So you'll also see the use of the figure and figcaption elements here to wrap up the image on the page. And as we come down, you can see that I'm going to use the aside element for the features. Now as I showed you in the demo, there's some interaction that's available by using the details and summary elements. And I'm sending the element open by default by adding the open attribute here to the element. Now this highlights something that's different in HTML5 as well. Now from your experience with XHTML, you probably know that previously we'd have to provide a value for this attribute. So it could be true or as IntelliSense is showing us, it could be open. Each attribute had to have a value, but here that's not the case. We can just set the details element and add the attribute of open, and that's perfectly valid code in order to open up that content on the page by default. Scrolling down a bit further on the page, here we encounter the video element. And here you just see the same thing where we have attributes that don't require values within the element. So I'm saying to display the controls on the page, to loop the media when it gets to the end, and then preload. Preloads does take a value because there're predefined values that you can add in to the preload attribute. So you can do automatically preloaded or just preload the metadata or don't preload anything at all with none. And the poster is the image that shows in place of the video before you start playing it. And then, of course, the dimensions. And we'll talk about video and audio in an upcoming module in depth. So now let's talk about the time element. So here the time is set, and also added is the pubdate attribute, which tells the browser this is the publication date for the document itself. And then I give a value for the datetime, which provides the date, the time, and all the way down to the time zone offset. And then, finally, we're saying this semantically is the footer of the page, which includes some more links to information about me. And so now if you take a look at the overall skeleton of the page, inside the body, we have a main element with a header, an article, and a footer. And so when a search engine looks at this page, it has a very good idea of what to consider important and not important when it comes to relating to search terms. Now that you've had an introduction to the code, let's talk about how you might get started building one of your first HTML5 pages.
Getting Started with HTML5 Pages
So what's the best way to get started writing an HTML5 page? Well you could just code it by hand, and the syntax is actually pretty simple, but it might do you well to get acquainted with the HTML5 boilerplate. The idea here is that there is structure, element, and values that are needed for just about every HTML5 page. And the boilerplate makes it super simple to get started on that page. So let's take a look at html5boilerplate.com. So here we are at the website. And as you can tell, it's billed as the web's most popular front-end template. So once you get here, you can download the latest build or get a custom build. And we'll look at both of those. So as we scroll down a little bit, you can see what's included with the boilerplate. So you can see it comes with analytics and icons and packages with jQuery and Modernizr. But the most important part is the fact that it normalizes CSS. What normalize.css does is that it takes many of the style related inconsistencies among browsers and resets them to common values or normalizes them. To give an example of why this is important, let's say you're relatively positioning an element inside the body of a page. Every browser will have the same default settings applied to the body element after applying the normalize.css. This ensures that your element will show up in the same spot on the page no matter what browser you're using at the time. And this is a huge help because then you know everything will be consistent among the different browsers. And as we scroll down, you get an idea of some of the big names that are using the HTML5 boilerplate. Now let's take a look at the package to see what comes when you download the default version of HTML5 boilerplate. When you open up the accompanying zip file, you see a series of files and folders. So like I said before, one of the first things that you get is normalize.css. And, again, these are the rules applied to create consistency among different browsers for all of the base elements on the page. To take it just a step further, main.css applies some basic styling to the page. And like it says here, it has some opinionated defaults. And all of this is set to give you a solid baseline for you to begin styling your documents. The doc folder includes a number of different markdown documents that you can read that help you learn how to use the boilerplate better. And then some images and some JavaScript files. The real meat of it, though, is in index.html. Now this has many of the same elements as I showed you in my introduction to HTML5 page, but it has a few other things that can make your life a bit easier. So it has some checks for Internet Explorer and also gives you a chance to show an upgrade message to anyone who might be using a very outdated version of IE. Line 25 also shows you an approach where you can include scripts on your page but also use a CDN. A CDN is a content delivery network, and this gives you an opportunity to link to files that already may be downloaded into your user's cache. Now in case there's no access to the internet available, then that's what this script block does. So it looks to see if jQuery is already found. And if not, then it'll go to the local version. And if not, it'll go to the local version associated with this page and load it up. And then it gives you a placeholder to begin working with plugins and a place to start your application using main.js. If you're interested in using these, make user to check out the documentation. Here I just wanted to give you the basic overview of how to work with the HTML5 boilerplate. Lastly, you have a script section which allows you to integrate in with Google analytics. You just want to make sure to change this value to your site Id before you deploy this up to your web server. So using HTML5 boilerplate is an easy way to get started using a well-crafted template for HTML5. But it doesn't stop there because you can also customize this page by using Initializr. Now just a moment ago, we looked at the default download available with HTML5 boilerplate. However, if you come over to Get a custom build, that takes you over to initializr.com. Initializr.com integrates with HTML5 boilerplate but gives you an opportunity to customize your build along the way so you can choose to go with the classic HTML5 boilerplate, or you can choose the responsive option. And this'll give you a template that's more suited to work with responsive websites. Or you can choose to opt in to the Bootstrap layout framework. So by clicking on any one of these buttons gives you a chance to predefine some of the values down here. And here you can choose what sort of HTML and CSS template you want, what types of HTML5 polyfills you'd like to have included, how you'd like to have jQuery bundled in the download, and then optional items about using IE classes, like you saw in the demo where it showed a place to put up a warning message if people are using a very old version of Internet Explorer. Also other old browser warnings, Google Analytics, and on and on. So once you choose the different options that you want available, click to download, and you can begin using this and building your HTML5 pages.
Detecting Features
If you recall from our previous discussion of how features are rolled out at different rates to browsers, you'll see why being able to know what each browser is capable of is very important to everyday development. You previously saw me use caniuse.com in one of the slides, and this is one of the most reliable sources of information on browser support available on the web. The data is open source and available on GitHub. So the community can add resources and issues, and browser vendors can update their data saying what they're supporting. Let's take a look at caniuse.com right now. So here we are on the home page. And the idea is you can come to this page and type in an HTML5 feature and find out what it's browser support is. Now previously we had talked about the Shadow DOM. So here is the page for Shadow DOM, and you notice it lists all the major browsers. And you'll find that red means there's no implementation, green means there is an implementation. And if there's partial support, they'll note that with a light green color. If you look at the top upper right corner, it gives you percentages that allow you to have a feel of what sort of support there is globally, as well as narrowing it down to the country that you're currently in. As we scroll down on the page, you'll notice there's a place for notes, known issues, resources, and feedback. So you see here that Microsoft has it under consideration and Firefox and WebKit currently have it under development. Now there's no known issues at the time. But resources is an excellent place for you to go to learn about some of these new APIs. The links here are invaluable in order to find your way back to the original spec, as well as to locate tutorials and articles that explain the API available other places on the web. And the Feedback tab allows you to make comments and corrections to the people who maintain the website. So like I said, all of this data is all available through GitHub. So the community does a great job to make sure the data stays up to date, and the browser vendors are conscientious to keep the stats updated with their latest development efforts. So Can I Use is a great tool for you to get a general idea of what APIs work with what browsers. But when it comes to writing code and allowing your application to know whether or not it can use a certain feature, that's when you want to use Modernizr. Modernizr is a lightweight JavaScript library that takes care of all of the heavy lifting when it comes to feature detection. Want to know if the current browser supports a particular feature? Just ask Modernizr. From Modernizr's website, you get an even better idea of what it is and what it does for you. So here on the home page, you can see that it responds to your user's browser's features. So if you go to the Download tab, you'll notice there're a number of different features that it supports detection upon inside the browser. So to use Modernizr, you want to reference it in your page. And as the page loads, Modernizr inspects the user's browser and reports back what it's capabilities are. So, for instance, if you wanted to, say, use canvas, you could come over here and click on Examples. And it shows you some CSS you can use to display elements with or without canvas. And in JavaScript, you simply use the Boolean value, Modernizr.canvas. And then from there you can run your own custom code to decide what to do if support exists or not. Now through the Download tab, you can select specific elements that you want to use. In development, you can use the full build. But when you're using it in production, it's a good idea to select only the features that you're looking for in order to bring the file size down a bit. The documentation is extensive. And Modernizr is a must-have for developing HTML5 applications. So, remember, when you're building your apps, you want to go with feature detection rather than browser detection, and Modernizr with plugins that allow you to integrate your own feature detection has everything that you need.
Fallbacks and Polyfills
So the big question at this point is what do you do if you're developing an application and you really need a certain API, and it's not supported by all browsers, or maybe it's not supported by some at all. The second line of defense is to turn to fallbacks and polyfills. As the name suggests, a fallback is an implementation that you can fall back to that's usually done by a third party with a different API than what you might find natively implemented in the browser. An example here is a popular library called Q which provides an implementation for Promises, which is an API that's used to deal with asynchronous processing. And it was available far before any browser supported Promises natively. Now the API, the functions in your code calls, was different than what was spec-ed out for the native browser implementation, but you generally got the same functionality. And that's the hope of a fallback, to provide similar functionality as a native feature but maybe just with a different API. A polyfill, on the other hand, is meant to replicate the exact same interface, as well as functionality as how the native implementation would be built in to the browser. The benefit to using a polyfill is that once browser support is ubiquitous, the idea is that you can simply remove the polyfill from your application, and the functionality will remain unchanged, although I'd still recommend some rigorous testing during this time. Now there's a website that can help you out a lot when you're trying to find fallbacks and polyfills, and that's HTML5PLEASE. HTML5PLEASE is a good website that gives you a pretty good handle on what's available as far as APIs and which one needs to be used with a fallback or a polyfill. So here's the home page. And as it says, use the shiny and new responsibly. So let's take a look at a new API like video. So there's three different classifications. You have use, caution, and avoid. So in this case, it says use with polyfill, and it gives you a description of how you can use the API and what you might want to consider if you're going to use it in a production scenario. Oftentimes, it's perfectly acceptable to use it with modern browsers, but if you want to use it with older browsers, then you might have to use a polyfill. Now let's take a look at another one that's classified as caution, and that's IndexedDB. Here, this is marked as caution with fallback because not all the browsers have completely implemented the API. Here at the bottom, you'll see that there're some recommended polyfills. So armed with this information, you should have everything that you need in order to have the widest browser reach possible for the implementation of this feature. Let's take a look at one last one, and that is WebSQL. This is marked as avoid. The WebSQL API is officially deprecated and is not being worked on in any browser. So this is certainly an API that if you're going to use, you need to know exactly why you're using it and what the dangers are should you rely upon it. So HTML5PLEASE gives you a good look at the state and availability of a number of different HTML5 APIs, as well as a listing of what fallbacks and polyfills might be needed in order to work with them.
Summary
Well now that you've become acquainted with HTML5 as a whole, you're ready to move on and begin working with code by using the selection API. And this is where you'll learn to use a native API to find different parts of the page. But in this module, you've learned about the collection of APIs, markup and attributes, that make up what's new in HTML5. You've learned about the different standards bodies that have brought HTML5 to life and how and why different features are implemented in the browsers at different rates. You also learned that it's easy to get started. And if you need something that's not available yet, there's a chance that there's a fallback or a polyfill available for just about any missing functionality. I'll see you in the next module where we dig in to the Selection API.
Finding Parts of the Page
Introduction
In this module, you'll learn all about the Selection API that's now available within HTML5. In the past, traditional DOM selection left something to be desired. The API is limited, and it lacks some of the basic functions needed to be truly useful. In fact, the meteoric success of libraries like jQuery initially came from the need to be able to select against the DOM in an easy, reliable, and speedy fashion. Well, in HTML5, there's a host of new selectors that make it not only easy to work with the DOM but also super-fast. So let's begin working with the Selection API. But, first, I want to show you how to set up the sample code for this course.
Sample Setup
As you download and unzip the files for this course, you'll be presented with the files and folders that you see here. So this is all of the files that are required in order to run the sample application. Now what we need to do is use Node.js in order to install the dependencies. Now there's just one dependency for this sample application, and that's a personal web server. And the purpose for the personal web server is that some of the APIs like canvas and drag and drop want a server context to execute in order to operate correctly. Now if you're on Windows, you can do this very easily by double-clicking the Install command. And once that's done, double-click start, and that will launch the website in the browser for you. But if you like to do it manually or you're on Mac or Linux, we'll do it here in the command line. So the first thing that we want to do is type npm install. Once that's installed all of the dependencies, you'll notice that now there's a node_modules folder available in the directory. And now all we need to do is type npm start. And this launches the application for us in the browser. So now let's move on to working with finding parts of the page.
getElementsByClassName
Let's begin working with the Selection API. Here we are back at the sample application, and I'll do two things. The first thing is press F11 to go full-screen. And then I'll press F12 in order to open up the developer tools. So the console over here on the right is where we'll be doing all the work against the page. Now just to review, we've got a couple of different aspects of each demo page. So here's the content. This shows you how all the code that's in the background will display upon the screen. So we've got an image and some text and some items that we can select against. Here's the markup that's used in order to build this page. And so we'll be taking a look at this as we go through and select different items of the page. There's no custom CSS for this example, and if you want to look at all of the JavaScript that's involved in this demonstration, it's all here in the sample application for you. But for now, let's go back to Content, and let's start working with the first API member. One of the first new members available in the Selection API is getElementsByClassName. So here I'll look for any item that has a class name of img-responsive. And so you notice it returns an array of elements that match that selection. So here's the coded-homes-logo, the home itself, and then down at the bottom, there's a little headshot that I have in the footer. So each one of these items, if we look at the markup, there's an image, and it has a class of img-responsive. And the same thing is true for the image of the home. So here you can see home.jpg. And inside this class list, it has img-responsive applied to it. So previously before the changes to the Selection API, it was very difficult to get items just by their class name using what was just built into the browser. So getElementsByClassName works great if you're looking for elements simply by their class name. But if your needs are a little more robust, and you want to use, say, a CSS3 selector, then querySelector is the member you want to use. We'll look at that next.
querySelector and querySelectorAll
Now sometimes the elements that you want to select against the page aren't simply available through a class name or a tag name, and your needs are a little more sophisticated. So let's return back to the markup for a second. And, again, you'll notice that each one of the images has a class of img-responsive applied to it. So before we used getElementsByClassName, but there's another member that we could use to get the same type of result. This is querySelector. Now what querySelector takes in is a CSS3 selector. So before when we called getElementsByClassName, and we simply passed in the name of the class, here we can achieve the same result by passing in a selector, and in this case, it'll simply be dot (.) and then img-responsive. So what's returned from this is a single item, and this returns the first match that it finds in the document. Now if we want to find all matches to that selector, we can use querySelectorAll. And notice that I'll pass in an identical selector, so .img-responsive. Now by calling querySelectorAll, I get back once again an array of all the matches to my selector. So to make the point, let's clear this off, and let's use a selector that's a little more complicated than what we've been using so far. In this case, what I'd like to do is look at my example-container. So if you notice here, there's a div that contains everything, and this is my example-container. I'd like to go down to the list items, and I'd like to pull out the very first list item here. So we'll do that with this selector. So what this selector is saying is that look at the element with an Id of example-container. And that's delineated by the pound sign. Then I'll say inside of that example-container, look for a list item, and I want to find the first child. So as I execute that, you'll notice that it returns a single item, and that matches the first item in the list. Now notice from these brackets here, you'll see that it returned an array even though there's a single result. And that's because querySelectorAll always returns an array of results. And if there's no match, it simply returns an empty array, whereas by contrast, querySelector simply returns the first matched item from your selector.
querySelectorAll Returns a NodeList
Now in a previous exercise, I showed you how querySelectorAll returns an array of elements. Now that's not exactly accurate, and I wanted to save that discussion until right now. So, for instance, if we take a look at querySelectorAll, and we'll look at the example-container list items, you'll see that what is returned from this command is what appears to be an array of elements. But, in fact, it's not. It's actually a node list. So let's try this one more time. So here we're taking the result of querySelectorAll and setting it to the item's variable. And now when we call toString against items, you can see that it returns a type of NodeList. This is important because as you try to iterate through the return value of querySelectorAll, it's technically not an array, and so it doesn't have the same capability and functionality that you might be used to with an array. So, for instance, you can't take a NodeList and simply iterate over it using the foreach function. So with that in mind, let me show you a few different ways that you can iterate through a NodeList.
Iterating NodeList: for loop
There's at least two different ways that you can iterate over a NodeList. The first way is using a standard for loop, and another way is using the foreach method off of the array prototype. And so I'll show you the two different methods here. So let's start off by setting a value of items equal to all of the list items found in our example-container. I've got this set aside from the last clip, so here we'll just execute querySelectorAll against example-container looking for all of the list items and set that equal to the items variable. Now what we can do is build up a for loop that will allow us to iterate through each one of the items in the NodeList. So here we have a standard for loop. And so as we iterate through each item, we'll log out the innerText to the console. So these are the items that we'll be working with. So if you come down here, you can see everything from the master suite down to the shower enclosures are all the items that we'll be iterating through on this loop. So this gives you an easy and familiar way to iterate through the NodeList. Now the next approach is to use the foreach method off of the array prototype.
Iterating NodeList: forEach loop
Another way that you can execute iteration over a NodeList is to use the foreach method off of the array prototype. So the first thing that we'll do here is set aside access to that method. Now with that defined, we can go ahead and get access to the items once again. And now you can use the foreach method in order to iterate over the NodeList. You simply need to call forEach.call, and then the first argument is the list of items that you want to iterate over, and the second argument is the anonymous function that you use to execute as you're iterating through each item. And from here, we can just log out the innerText of each item. So the result is the same, but what I've shown you here are two different ways to approach iteration over a NodeList. So next let's look at maintaining results either through a live result or a static result.
Live Result from getElementsByClassName
Now once you make a selection against an element on the page, depending on whether or now you have a live connection to it or a static connection to it will determine how it behaves as it changes throughout the lifecycle of the page. So, for instance, if we were to take a look at the example-container and get access to the unordered list element, and so that would be the parent element of each one of these list items, and then change the number of list items inside that unordered list, when you're working with a live result, you'll be able to recognize that change programmatically as it happens. So let's take a look at what this looks like. So the first thing that we'll do is set aside a selection of the unordered list itself. So here I'm using querySelector rather than querySelectorAll because I want to get the first result that matches the selector. Now there's only one unordered list inside the example-container, but I want to show you how to use both API members in different contexts. Next, let's select all the list items so that we can see how many we're working with as we make changes to the page. And so here, we'll change the approach a little bit and use getElementsByClassName. And if you recall, each one of the list items has the class name of feature applied to it. So now let's take a look at how many items are in that result. So it returned 6 list items. Now let's add an item to the collection. So here I've created a new item by calling document.createElement, and we'll add the feature className to this item, and give it an innerText of new live feature. Out of habit, I put a parenthesis there. We want that without the parenthesis. So, next, we'll append that item to the list. Now watch as I press Enter, look over at the list of features, and you'll see it appear in that list. There it is. And now when I do a console.log on the items.length, you'll notice that it returns 7 even through the selection that I made for it by calling getElementsByClassName was done in advance before I'd made any changes by adding a new item to the unordered list. So the distinction that you want to keep in mind here is that calling getElementsByClassName will return to you a live result, whereas if you try to access even the same elements by using querySelectorAll, then you'll end up with a static result. Let's take a look at that next.
Static Result from querySelectorAll
This demonstration is basically almost exactly the same as what we just did except instead of using getElementsByClassName, we'll be using querySelectorAll in order to access the items. So, first, let's get reference to the list. Next, let's get reference to the items. And, again, here instead of calling getElementsByClassName, we'll call querySelectorAll. And in this case, since we're not going against a class name, we'll pass in a selector. And so here instead of looking for the unordered list like we are above, we'll look for the list items, and that will give us access to all the items. So let's take a look at the number of items right now. So here we have 6 items in the list. Now let's add a new item to the list, and this is the same code as we had before. So as we come down, you can see that new static feature is added to the list. But when we log out the number of items, you see that it still returns 6. And, again, that's because querySelectorAll returns a static result, whereas getElementsByClassName returns a live result. So this is an important distinction to keep in mind as you're building your pages. If you need to have a hook or a place where you can access elements, and you need to maintain a live result for those elements, then you'll probably want to add a class name and access them through getElementsByClassName. Otherwise, you can access any other element any way you want using querySelector or querySelectorAll using CSS3 selectors.
Summary
Excellent! You've done a great job learning about the Selection API. And in the next module, we'll turn our attention towards reviewing some of the advancements in web forms. Here we'll cover validation, new elements, and more. Let's go ahead and summarize this module. In this module, you learned about the native DOM Selection API and how you can easily find any element on the page. The new API members are both fast and flexible by providing a number of different functions that allow you to locate elements using CSS3 selectors. Now it's on to user input. I'll see you in the next module.
Working with User Input
Introduction
Hello and welcome back to HTML5 Fundamentals. In this module, we turn our attention toward working with user input. User input forms are a significant aspect of web applications. So let's take a look at now what's available in the browser. Now as I stated previously, new functionality found in HTML5 comes in the form of new elements, new attributes of existing elements, and new JavaScript APIs. And we'll see each of these emerge in this module.
New Elements Overview
So let's begin by taking a look at the new HTML5 form elements. New elements are meant to help people as they enter specific types of data into web forms. Rendered in Chrome as a colored rectangle as you see in the top left here, when you click on the rectangle, a color picker appears that allows you to select from a set of predefined colors. Beyond that, it gives you the opportunity to define some custom colors. You can easily access the value of the color picker the via the element's value attribute. The datalist element is interesting. By itself, this element doesn't render anything on the page, but when it's associated with an input element, then the items in the datalist appear as predefined options for a textbox. This makes it easy for you to provide some default options for an input element but still have a freely editable textbox. The datetime type provides a date picker, which allows you to easily select a date value. Now each browser renders the picker a little bit differently, but all supporting browsers give you a chance to easily cycle through months and days. In similar fashion, the datetime-local input type gives your users the chance to easily select date and time in their local time zone. And then there's the email type. On the desktop, you don't really notice much of a difference. In fact, it renders like any other textbox. However, on a mobile device, if supported, the keyboard changes to an optimized version making it easier to enter in an email address.
New Elements Overview (continued)
The URL type behaves in the same way. It's a bit uninspiring on the desktop, but as you look at it on a mobile device, you're presented with a custom keyboard layout specifically tailored for entering in web addresses. And the same goes for the telephone type. The month input type does have a custom visualization on desktop, as well as on mobile devices. The number type renders some handy spinners at the side in order to go through values and has a custom keyboard layout for mobile. The range control renders out a slider, as well as giving you control over the start, stop, and step values. We'll work more with the range element later on in this module. Circling back to user input types that deal with points in time, the week input type allows you to select a single week of a given year. And getting a bit more granular, the time type allows you to select a specific time and comes with a custom mobile visualization if supported. And, finally, we have the search input type. This renders what is essentially a regular textbox but is accompanied by a small x on the right-hand side that allows you to easily clear the value in the box. So there it is. That's your tour of all the new input elements available in HTML5. And that brings us to a closely held preset about application input. Never trust input, or in this context, never trust user input, which takes us directly to a discussion about forms validation in HTML5. So, next, let's take a look at what sort of validation support is available native within the browser.
Validation Rules Overview
As stated in the last clip, the last thing that you want to do is trust data that comes into your application blindly. Validating and sanitizing input values protects your application from hackers, vandals, and data values that could, otherwise, possibly compromise your system. With HTML5, you now have a number of different validation rules and APIs available to help you easily vet data on the client before you send it off to the server. But remember that client-side messages can be spoofed or even outright high-jacked. So, yes, you can do much on the client, but be careful of what you let into the inner sanctum of your application. Enough with warnings. Let's take a look at the validation support available in the browser. The value missing rule evaluates to true if an element that has the required attribute has an empty value. This is perfect when you want to make sure users are submitting a value, say, for usernames, passwords, or email addresses. The type mismatch validation rule evaluates to true when the value in the input element does not match the type defined by the element's type value. For instance, in the code sample in the slide, the form is set up to accept a URL. But the value is simply the string hi. Since the string hi does not match the form of a URL, the type mismatch rule is broken. You'll use this in places where you want to make sure data entered adheres to the defined type like not putting a street address in an email address field. In similar fashion, the pattern mismatch evaluates to true when the value of the input element doesn't match the regular expression provided in the pattern attribute. This is a powerful feature as it gives you full control to define the pattern of how you want values to adhere to your business rules. The practical applications for the pattern attribute are endless from validation of social security numbers to IP addresses, even to determining if the specific words have a particular casing. You have the full power of the JavaScript regular expression engine at your disposal here. The too long rule evaluates to true when an element's value length is longer than the maxlength value. Here you can enforce a check for usernames that are too many characters and so on. When working with sliders, there're a few validation rules that will apply to the range element. The range underflow rule returns true when the range's value is smaller than the minimum allowed value as defined by the main attribute. On the flip side is the range overflow rule, which returns true when the value is greater than the max value of the range element. The last one that applies to the range element is the step mismatch, which evaluates to true when the value of the range is not a value that's possible in light of the step value defined in the range. So here if you want to control the volume of a media player with a slider, and you wanted to change the volume in 5-dB increments but ended up with a value of 9 somehow, then you have step mismatch. The final rule is the valid rule. This one evaluates to true when all other validation rules return false. This is how you know you have a valid form on the page. Let's dive in a bit and see how these rules work in context of an HTML5 web page.
New Elements: Demo
So now let's go with a demonstration of the new input type elements, and I'll show you how some of the new attributes affect them as well. So in this clip, I'll give you a demonstration of how they behave in the browser, and then coming up, I'll show you the markup that's required in order to make it all happen. So if I were to reload this page, one of the first things that you'll notice is that the search box automatically gets focus. Now this is done with the autofocus attribute and is achieved completely without any JavaScript whatsoever. Now there's a rule for autofocus that says you can only have one input type with the autofocus attribute at a time. But this is a great way to improve the user experience of the forms that you build because whether you're building a search form, a login form, or a signup form, once the page is loaded, you can already have that primary input element in focus. Next, let's look at contact info. Now these have a few special features applied to them. Now these have a CSS class applied to them to show that they're required. This isn't anything necessarily specific to HTML5 but does make it a lot easier for people to see which elements are required. Now when I go and type some input into these form elements, what you'll notice here is that these elements get this reddish-pink outline, and this is the native forms validation kicking in because this is set as a required field and also has a pattern applied to it, saying that you need a first and a last name. So here I'll enter my name. So that fulfilled the validation rules and returned the element back to the normal visual state. Now if I were to come down and try and submit this form, you'll notice that the browser is telling me Please fill out this field. And, again, this is because email address is set as required. However, if I give it something that's not quite an email address and try to submit it again, I get another message from the browser telling me that the input isn't quite right. And that message came from the browser's native validation support. I didn't specifically set that message, and that's because this is set to an email type. So now when I type in a valid email address and try to submit the form, you'll notice that it passed validation for the email type and now it's going on to telephone number. Now you might notice in the background of the phone number box is the text of phone number. And this is what's called a placeholder. Now in the past, we may have had to use some JavaScript libraries to achieve this same type of functionality where there's text in the background of the input box, but as you start typing, it goes away. But this is all done through the placeholder attribute. And so you can tell each one of your input elements what text you want to appear in the background giving users a hint of what type of information needs to go into the box. So you don't have to clutter up your layout with labels plus input boxes. Of course, you could do both. You could do one or the other. It's completely up to you. But the placeholder gives you that chance to show that text in the background of an input element. So here I'll type in a phone number. So that passes validation for the phone number. For web address since this is an input type of URL, I can type in my URL. Now as we move down to Preferences, we have number of bedrooms. This is set up as a number input type, so there're spin buttons rendered on the side of this input element. So I can begin by going up and down with the mouse cursor on these buttons. Or if I want to, I can use the up key on the keyboard or the down key in order to change the values in that input box. What I can't do, though, is type in text. I'm typing on my keyboard text characters, but obviously nothing is showing up because alpha characters are not valid for an input type of number. So for number of bedrooms, we'll say that we need 4. Next is the input type of range. So this renders as a slider in the browser so I have control of saying how many days I need until I'm ready to move. Now what doesn't come by default is the display of the preview of the value for the range input element. And I'll show you the JavaScript that you need in order to report out that value. But here I'm taking advantage of a minimum and maximum value, so the minimum is 0 and the maximum is 120. And then a step value of 10. So this only moves in increments of 10. Now for directional preference, this is just a regular input type of text, but it's associated to a data list. So I could type in anything that I want here, so gibberish. Of if you'll notice, there's this down arrow that's rendered on the right, and if I click on that, I have different predefined options that I can select from. So this is the data list being associated with this input box so that you have those options available. But at the same time, you have a free form textbox where users can enter in any type of data that they like. Below that, we have the color picker. So as I click on this box, I have access to a standard color picker. I can choose basic colors, create custom colors, and have full control of the colors directly within the browser. Now we'll move down to the input elements under Available Date. The first one renders in Chrome with a lot of control over here on the right. So we have an X where we can clear the value. We have the spin buttons where we can go up or down. And we have the drop-down here that allows us to select a month. So this is the input type of month. Getting a little more granular as we go down, you'll notice that there's the same amount of control over here on the right-hand side, and this is the input type of week, which allows you to select a particular week of the year. And, finally, there's an input type of datetime-local, which allows you to select a date and time in the local time zone. Now let's take a look at the markup and the CSS classes required in order to build this page.
New Elements: Markup
Let's begin by taking a look at the markup for these elements. One of the first things that you'll notice about this form is that it has the novalidate attribute applied to it. This is perfect for forms like search forms where you want to skip any validation rules as you submit the form. Now let's take a look at the input elements. The first one is the search box, and you'll notice that it has the type of search and also autofocus applied to it so that way when the page loads, this input element will get the cursor's focus. And, again, we need to make sure that there's only one element on the page that has the autofocus attribute applied to it. Next, let's take a look at the input elements used to gather contact information. Here for first and last name, it's a type input of text. And I have a placeholder set for first and last name. The required attribute is applied to this element, which allows it to opt in to the browser's native validation rules. So this element is required, and the pattern that I've given it here says that it needs some text, some more space, and then some more text. So that ensures at least two validation rules will be applied to this input element by saying that it's required and that it has to adhere to the pattern that's been passed to it. Next we have an input type of email. So, again, I have a placeholder and required. But what really makes this special is that I have the type set to email. So any value that's submitted in this input element needs to match the pattern for an email. Now, of course, I could've done this through a regular expression by adding the pattern attribute to this element. But I'll rest on the fact that the browser makers can do a better job of enforcing what an email address is than any regular expression that I could write. And so the same is true for a telephone number and URL. Each get a placeholder, but right now telephone is the only one that's set to required. Now let's take a look at the number of bedrooms. Here the input element is set to number, and I have minimum and maximum values applied to this element. So in this case, users won't be able to enter in a value above 6 or below 1. Next, let's go down to the range input element. Now the input type is set to range, and it also has a minimum and maximum value. Now as I pointed out in the demonstration, the step value is set to 10, so you can only move the slider in increments of 10. And, of course, you can give it a default value by setting the value equal to 30. Now the span here for move-value is what gets its value as you change the value on the slider. So let's take a look at the JavaScript required in order to give it its value. So here I'm accessing the element by Id, and that's the span that we just looked at. And then calling document.getElementById for the slider, which has the value of move-range. Then I'm adding in an event listener for when the value changes. And when it recognizes the change, this anonymous function is run, and the innerText of the moveValue span is set to the value of the slider. Now you won't need to do this all the time. I just wanted to stop and show you how you could report out the value of the slider if it's necessary. Let's return back to the markup. Next, we have the direction-data. So notice here I have the input type = text, but the list attribute is set to direction-data. The datalist underneath it has all the options for direction-data. But this is still an input type = text to get a free form editing experience through this textbox. But as I show you on the demo, if you click on the down arrow, you have predefined options. So this is great if you want to offer suggestions to your users but if you want to give them the opportunity to provide their own answer. So datalist associates with an input element through the list attribute. For the color input type, you just need to set it to color, and you can give it an initial value of an RGB color or a hex color as you see that I've done here. And, finally, the date-based input types are set up this way. You can see that I have an input type of month, and when you give it a default value, you need to give it in the value of year-month. For the week, you give it an initial value of the capital letter W and the week number of the year. And for datetime-local, the default value is set for the year-the month-the day, a capital T for time, and then you can give it time all the way down to the seconds. Now there's one last aspect that we still need to discuss, and that's the style used to provide validation clues to the elements underneath the contact information. So let's look once again here that name, email, and telephone number are all set to required. The CSS used to give those visual hints is right here. So you notice that input elements that are set as required get a red border here through this rule. So this gives the clue to the user that these elements are required and that they must provide a value. Now when we bring those input elements into focus, I'm setting the color to red and the border color also to red so that users get an idea that as they're filling this form, this is critical information. But these rules here only apply if the data that's in that input element is invalid. We'll talk more about validity states later on in this module, but for now you just need to know that if the data is invalid in that input element, the style will be applied. And the same goes for input:focus:invalid:focus. So if the cursor is focused on an input element that has invalid data, then these styles will be applied. So the border color is red, and then there's a light shadow that displays around the input element. Now that you've been able to see what the input elements look like in Chrome, as well as the markup styles and JavaScript used in order to build this page, let's take a look at how these elements look in other browsers so that you can see what your users will see if they use another browser besides Chrome.
New Elements in Different Browsers
Now let's take a look at the same page in some different browsers. So here we have everyone's favorite browser, IE 11. So let me refresh the page here, and you'll notice that autofocus works. So we have the search bar getting autofocused. As we come down, you can see that the placeholder is working for a number of different elements. And if I go to submit this, I get the message kicking in saying that I have required fields. So it's respecting the required field attribute that's set on each one of those textboxes. So I'll add in some values here. And as I tab through each field, I get the native message popping up showing me that each field is required. As I come down to take a look at the number input element, you'll notice that there's no spin button. As I try to type in some text, you'll notice it just goes away as I exit the box. The slider here's kind of nice because it shows you the step increments visually and gives you a preview of the value as you change the value on the range element. Datalist is supported. But the color picker is not. And the date pickers are also not available within IE 11. Well let's take a look at Edge. Let's start off by refreshing the page, and you'll notice that autofocus does work with Edge. This has the same capability for required fields. So if I click Save, I'll get the confirmation saying that I need to add in data to the required elements. For number of bedrooms, if I type in text, what's interesting here is that the placeholder moves along to give you a hint that you're probably not entering in the right type of data. So I can clear this out and now add in, say, 4. But there's still no spin button. But the number type will still only accept number values. Now the same type of slider is available for the range input. And, again, in Edge, there's still no color picker for the time being. And for the date input type ranges, we still have some nice visualizations available for month, week, and datetime-local. Next, let's move along to Firefox. So as I refresh, you'll notice that autofocus works and that's great. I'll try to submit the form, and you'll notice that I have the native validation popping in. This is applying the class a little bit differently than it did in Edge or Explorer. Here if I try to type in text to the number type, it shows that it's invalid, but I do have spin buttons here so I can clear this off and start going through the values. Now, remember, the max value on this element was 6, so I'm not able to go up or down with the spin buttons any more than that. And I'm also using the keyboard here, and that spins through them as well. The range type is a little more of a traditional look than what we saw in Internet Explorer and Edge. And as we take a look here, we've got color picker supported but still no date picker's available here within Firefox. Let's look at one more browser. Let's take a look at Opera. As I refresh the page, you'll see that Opera does support autofocus. And here I have the native validation messages showing up for each of these items. If I try to type in some text to the numeric box in Opera, nothing shows up. It's not until you start entering in some numerical values that you get to see the values showing up within the box. The range type in Opera is actually quite nice. It's a simple slider here. And datalist shows up here within Opera. We've got the color picker and essentially the same rendering of the date pickers as what we saw in Chrome. So now let's take a look at implementing some forms using some of the native validation support.
Building Interactivity with CSS Pseudo Classes
In this next section, I'll show you how to use pseudo classes to add interactivity to your forms without using any JavaScript whatsoever. So in this next demo, I'd like to show you how to use CSS pseudo classes in order to build validation messages into the forms. Now what's cool about this is that all of the interactivity that you see in this demo is achieved without using any JavaScript whatsoever. It's all done completely through CSS. So if we go to our JavaScript tab, you see that there's nothing to run. So the way this form works is that there's some validation rules that are applied to the input elements, and as we work with the form, you'll notice different parts of it change based off the values put into the elements. So for username, let's go ahead and add in a value here. So you notice once I put in a valid value, the helper message that I had below the box goes away. So I'll do the same thing for email. And so that helper message is now gone. Now usually we would do something like this with JavaScript. But here we can do it all with CSS selectors. So let's take a look at the markup that makes up this page. So the first element is this input type of text for the username. Now I've set it to be required and also have a pattern and maxlength. So each one of these together enforces a validation rule saying that it must have a value. It must be alpha characters only. It must be at least 5 characters and cannot be any greater than 30 characters. Now I could have consolidated the pattern and maxlength into a single regular expression. But what I'm trying to show you here is how you can mix and match different validation rules in order for you to build exactly what you need for your input elements. Below it I have the helper text, and this is inside a div that has a class of invalid applied to it. So as we get into the CSS, you'll see how the selectors turn this on and off, but this is the text that's associated with that input element. Now let's take a look at the email. So here I have input type of email, which says that the value inside this box has to fulfil the pattern of an email address. And it's set to required. It's helper text is in a div which is right next to that input element. And it has the required message here. So that's the makeup of the HTML. So let's take a look at the CSS that makes it all happen. So, first, you'll notice I'm using the input type of the pseudo class of valid and then using the adjacent sibling selector to say look for the element next to it that has the CSS class of invalid applied to it. So, when all of this is true, when you have an input element that is in a valid state, this selector will look for an element right next to it that has the invalid class applied to it and set the visibility to hidden. Now visibility: hidden is important here because if you do display none, which is often what we do to make elements disappear, then it won't take up any space in the layout flow of the page. So instead by saying visibility: hidden, the same amount of space that it would take up on the page is preserved, but the element simply disappears from being rendered. Now for input elements that are in a valid state, the border bottom is set to transparent. For input elements that are in an invalid state, then what the selector will do is, again, find the input element that's right next to it, so its sibling, and look for the element that has the invalid class applied to it, and set its visibility to visible. So now when that input element is invalid, it shows the helper text that's right next to it. For required input elements, it's showing a solid red border on the bottom of the element. And, lastly, the helper text is styled with a light gray color here. So those elements that have the invalid class applied to it are colored with a light gray color. Now you'll notice something interesting. Remember when I said that when input elements are in a valid state, that border bottom should be set to transparent. Well you'll notice if we go back to the demo that these items are in a valid state. But when we look at the border bottom, it's still being displayed. And that's because the order of these rules are very important. Remember, this is cascading stylesheets. So as the browser encounters these rules, whichever one is interpreted last gets the highest precedent. So input:valid needs to be the bottom one on the list. So let's make that change now and see what happens to the page. So when we reload the page, and take a look at the CSS that's applied now, you'll notice that the pseudo class of input:valid is the last rule to show up in the stylesheet. So, when we go to use the form, here we'll start to add in username. So now the helper text and the border at the bottom of the input element goes away. So you can add a lot of interactivity to your web forms by just using CSS selectors. But what's really important is that you make sure to put them in the appropriate order. Now let's move on to working with some more native validation within the browser.
Custom Validation Messages: Demo and Markup
This next demo shows you how you can create some custom validation messages using the built-in validation rules. So you notice if I go to submit this form, I get some custom validation messages that show up underneath the input elements. Now the validation rules that you see applied to the username text box are the same that you saw applied in the last demo. So here I'll try to put in something that's just a few numeric characters. And when I do that, you'll notice that here I get a custom validation message saying that it needs to be a series of alpha characters with a minimum of 5 and a maximum of 30. So even if I add in a few more numeric characters, I still get that same validation rule firing because it doesn't adhere to the rule that's applied to the input element. So now I'll do something that passes the validation. So then once I tab off of that, the validation message goes away. And same for email address. Here an email address is required. If I add something, say, with a special character that's not allowed, here it says, Special characters are not allowed, and I can go and fix that. I'll turn this into an @. And now all validation rules pass, and I can submit the form. Now let's take a look at the markup required in order to build this page. So here I have an input element of text, and this is the same one you saw in the last few demos. So I have a pattern that only wants alpha characters with a minimum of 5 and a maximum of 30, and it's set as required. Now down here, I have a container that has the class of validation-messages applied to it. So the data-rule value will match the rule that's being broken for validation. So here for valueMissing, I have the text The username is required. For patternMismatch, I have the text Must be a series of alpha characters only (min 5, max 30). So as the validation happens, it'll take a look at the validation rule that is broken, and it'll be able to locate the element by name in order to show the correct validation message. Down here for email, this is set as required, so there's a valueMissing message that I have available, as well as typeMismatch to say that special characters are not allowed. Now let's look at the JavaScript required in order to build in this type of interactivity.
Custom Validation Massages: JavaScript
So here's the overview for this code sample, and let's start at the bottom and work our way up. So what will happen is as you click on the Login button, it will run the validate function. So we'll take a look at validate in just a moment. But I'll turn your attention here to the inputElements and what's being selected on the page are all the inputElements that are not buttons. And then once we do that, we'll loop through each one of them and hook up validate for onblur and validationFail for oninvalid. So essentially what happens is that as you're tabbing through the form, it will validate as you go off of each one of the inputElements. And once the invalid event is raised, then it will call validationFail. Now let's head up to the top. So the first thing that I'm doing is creating an array called ruleNames and then setting aside the forEach method off of Array.prototype. Now the reason that I'm doing that is because what I want to do is look at each one of the ruleElements, so each span that has a data-rule applied to it, and I'll go through each one of those and grab the ruleName out of the data-rule attribute of those elements. So as I spin through each one of those, I'll add each one in to the ruleName's array by pushing it in here. So what this does is fills up the array here called ruleNames with each one of the ruleNames that are defined in the HTML. Now with that set up, let's take a look at the validate function. So, again, remember, validate runs when you click on the Login button, as well as when you blur off of each one of the inputElements. So the first order of business here is to find the validation-messages and the span is inside of those. Now the reason that we're looking for these is because as this loop indicates, we'll hide each one on the form. So essentially all the validation-messages are being hidden upfront. And then as we go and check validity for the form, we can turn on the validation message that's appropriate for each broken rule. So calling checkValidity validates the form. And then if anyone of the inputElements is invalid, then it will call the validationFail function. So as we look in here, this is associated to an input element by way of the oninvalid event handler. And so we'll look at the element in question. e.currentTarget is our way to access that. And then we'll also set aside the validity state by looking at element.validity. So if validity.valid evaluates to false, then we'll go through each one of the rule names and call the checkRule function passing in the validity, the ruleName, and this element. And then I'm calling e.preventDefault here just to make sure no other actions happen on the form as we're checking validity. So, finally, the implementation for the checkRule function is right here. So we'll take a look at the validity state passing in the ruleName. So if the ruleName that we're looping through exists in the validity state, then we can go through by calling element, nextElementSibling, querySelectorAll, and using the selector of data-rule and passing in the ruleName. Then we have all the rules that we need to show on the page, and then we can loop through each one of those and remove the hide class. And that will show all the custom validation messages based off the invalid elements.
Custom Validation Rules: Demo, Markup, and JavaScript
For this next demo, I'd like to show you how you can implement some custom validation rules. So this form is the same form that we used in the last demo except one small difference here. I'll add in a username. And then for email address, I have a specific validation rule, and I'm actually poking a little bit of fun at my wife right now, so I'll just do craig@aol.com, and we'll say, Oh, I'm sorry, AOL email addresses are not allowed on this form. So if I go back and edit this up to just say anything else, really, that passes the validation. So I know that validating against AOL email address is not something that you're going to do, but it makes the point. So, again, like I said, this is basically the same demo as we had before, just a little bit of extra logic. So the markup and the CSS are identical to the last demonstration. And so now let's take a look at the JavaScript in some finer detail. So this is the overview of the code that's required. And let's start from the bottom this time and work our way up. So what we're looking at to do is when the Login button is clicked, the validate function is called. And that gets called also each time one of the inputElements is set to blur. So when you lose focus on each one of the inputElements, the validate function is called. When we take a look at validate, it'll go through and find each one of the validation-messages and immediately hide them. So that's why we're looping through each one of these and removing the hide class from the classList, and then calling the function validateAgainstCustomRules. And then at the end of all that, we'll checkValidity on the entire form. So let's take a look at validateAgainstCustomRules. This simply calls validateAgainstPattern. I built it this way so that you could obviously not validate against AOL email addresses but any pattern that's useful to you. So we'll start off by passing in the element itself, so calling document.getElementById. And the Id for that input element is email. Then we pass in the regular expression where if it matches the regular expression that you pass in, then validation is broken. And then also the ruleName. So now let's look at validateAgainstPattern. So here we'll take a look at the element and its value and see if it matches the pattern that's passed in. If that's true, we'll call element.setCustomValidity and call it invalid. Now this is important because now that we've put it in an invalid state, the pseudo classes can kick in and help style the form the way we want to. And then from there, we can go to the element, look at the nextElementSibling, run querySelector against it, and look for the specific ruleName that's been passed in here. And then go to the classList and remove the hide class, which essentially shows that validation message on the page. Now if the pattern does not match, then we call element.setCustomValidity. And here you want to pass in an empty string in order to clear out all the validation states. So the key takeaway to this demo is that if you need to set a custom validity state for an element, you use that by calling setCustomValidity and pass in invalid. And if you need to clear it, you call setCustomValidity and you pass in an empty string. Now let's take this one step further and refine the UI a little bit by integrating in with the Bootstrap layout framework.
Bootstrap Module: Demo and Markup
Next, I'd like to show you how to create a JavaScript module that uses Bootstrap in order to create a clean user experience. Now if you haven't had a chance to dig in to Bootstrap, don't worry about it. We're not getting to deep into it here. But I highly suggest you check out Scott Allen's course on Bootstrap here on Pluralsight. So the way this form works is that, first, if we look down at the bottom of the form, there's a message that says The form is:, and we'll find out soon whether or not it's valid or invalid. So right now without any values on the form, it reports that the form is invalid. You'll notice that there's a validation message that shows up at the top of the textbox for username saying that the username is required, and it must be a series of alpha-numeric characters only. So this is a lot like the validation messages that you say in previous demos. Here I'm just using a Bootstrap popover in order to give it a more refined UI. The other thing that you'll notice is that I'm only showing one validation message on the page at a time, even though as you can tell by the red underlines of the input elements that there're more than one broken rule. And this just goes back to the fact that I'm trying not to clutter up the UI with a bunch of different validation messages. I'm just trying to lead the user through what they need to do in order to submit the form. So if I come in and add a valid username, then that goes away. And if I try to log in again, well, I get another validation message that says that email is required. And now once I try to validate, you notice that the message down at the bottom shows that it is valid. Let's take a look at the markup required in order to build this page. So the first thing that you'll notice is that we're bringing in Bootstrap. So up in the header of the page, you need to point to the CSS file and also to the JavaScript file. Here I have it installed as part of my web app, but if you want to, you can go to getbootstrap.com/getting-started, and come down to use the Bootstrap CDN links, and integrate these into your page without having to install it within the web app, particularly if you're just working on testing. As for the markup itself, you'll notice how I have a form with the Id of email-form, and we'll use that Id in order to access the form and tell it to validate. So for my input elements, the three parts of it that are most important for this demo are title, which the Bootstrap popover module will use this value as the title for the popover, and then data-content gets wired up to the description for the popover. Now this is something in HTML5 that we haven't discussed yet. But using data- and some arbitrary value, so here we have content, we also have role, you can add in data into your elements on the page. This can make working with the DOM much easier because having the opportunity to associate data with certain input elements can make manipulating the UI much, much easier. So these data- attributes give me a chance to add in this data and associate it specifically with this DOM element. And then when we're working with JavaScript, as we access that element, we have access to its data as well. For the email input type, again, we're looking at title, data-content, and data-role. Now data-role is important because the ValidationModule will look on the page for any element that has this attribute. So anything that has the role of validate will get hooked in to the ValidationModule. And in the same way, our button at the bottom of the page has the data-role of trigger-validation, so you can set any element on the page to kick off the validation by giving it data-role of trigger-validation. Now let's take a look at the JavaScript.
Bootstrap Module: JavaScript
Now the intent of creating a JavaScript module is still that when you're trying to use it on your page, you don't have to write a lot of code. Now Bootstrap uses jQuery. And if you're unfamiliar with jQuery, I highly recommend you check out my jQuery Fundamentals course here on Pluralsight. I'm going to break this down really easy for you. You notice here we're starting with the dollar sign ($). And this is the window into jQuery. So by calling $ and passing in a selector, we're telling jQuery, Find all of the elements on the page given this selector. This works very much like how you learned about querySelectorAll in the selection module. So for any element that has the data- rule of trigger-validation, when you click on it, it will go into the validator module, and it will validate whatever form you give it. Here I'm passing in the Id of email-form. Now, if validate returns true, then you can do something on the page. Here I'm just setting the text of my validation message to Valid, or if it's invalid, I'm setting the text to Invalid. So I can validate the entire form on the page with just these few simple lines of code. Now let's take a look at the ValidationModule itself. The first thing that I want to do is find all of the elements on the page that are set up to be validated. So here by calling jQuery and passing in the selector of role-validate, I have all the elements that need to be validated. Next, I initialize the Bootstrap popover and sending the placement to top so that the popover shows at the top of the input element. Then as each one of those elements fires the invalid event, the first thing that I want to do is find the very first input element that's invalid on the page. So here I'm using querySelector. Now if you remember querySelector, that will return the very first match that it finds. So I'm looking for an input element that is invalid, and that gives me the firstInvalidElement. From there what I can do is use jQuery to show the popover for that element. Now when focus is taken off that input element or the blur event fires, then I can take a look at the specific input element and tell the popover to hide. And then to validate the form, what I'll do is take the formSelector and pass that into the validate function. Now I want to make this kind of flexible. So if you pass in an Id, I want it to work. And if you pass in a selector, I want it to work. So here this test looks to see if the number sign (#) exists within the formSelector, and if it doesn't, then that means we're passing in an Id. So at this point, I'll add in a # to create a selector. And then once I have that, I can call querySelector passing in that formSelector and then call checkValidity. And ultimately this module returns the validate function back up to the caller. So then as we take ValidationModule, we can new that up and then use it as we attempt to validate the page. Well now you're effectively working with a little bit of jQuery, a little bit of Bootstrap, and a lot of HTML5 validation. Let's go ahead and wrap up this module.
Summary
So to wrap up this module, you saw how new element types and attributes were supported in the browser, as well as how native and custom validation all worked without any extra JavaScript modules or libraries. Now that we're done working with user input, the next module teaches you how to support music and video without browser plugins. I'll see you there.
Music & Video (without Plugins)
Introduction
Welcome to the Music and Video module of HTML5 Fundamentals. In this module, you'll learn how to add media support to your applications using the native media players. We'll take a look at what's included in the media APIs and how to work with them, plus I'll show an overview of browser support for the different media types. HTML5 media consists of at least three parts. First, the native media element. This is the audio or video tag used in your HTML markup to host a media file. Next are the different media types. There are scores of options available to you when it comes to encoding and packaging media. So I'll briefly cover how these are supported by the major browsers of the day. Lastly, there's the Speech API. Have you ever wanted your application to respond to speech? Well, this is the API to do it. Now the Speech API is out of the scope for this fundamentals course. But as we move on, let's go ahead and touch on browser support and media types.
Audio Formats
This slide charts the different media types that are supported in different browsers by the audio element. The WAV format is supported across the board except for Internet Explorer. MP3 and MP4 work in all but Chromium, which is the open source baseline for Chrome, but Chrome itself obviously fully supports both formats. And, lastly, OGG is a little less supported, where Edge and Internet Explorer and Safari Desktop do not have support. In the end, most audio formats on the web are found in MP3 as support is widespread, and it features an acceptable balance between file size and quality. Alright, now let's look at video formats.
Video Formats
For video, here supports gets a little more patchy. Notice how the legend at the bottom left has indicators for partial and pending support. Now partial support means that it may be supported in one operating system but maybe not another. And pending means that it may be available in preview builds of the browser. So first up is Theora, which for now is not supported in Edge and is partially supported in Internet Explorer and Safari Desktop. Next is H.264 or one of the formats that we know as MP4 Video. The only unsupported one here is Chromium. But, remember, very few people actually use Chromium as their actual browser. Then HEVC, another MP4 format. This is newer and while it currently isn't supported across the board, it's likely to come. VP8 or Google's WebM format is partially supported by Edge and Safari Desktop while IE will likely never support it. And, finally, the successor to VP8, VP9 is pending on Edge and not supported in IE or Safari. When encoding and packaging video, many different factors come into play. But at the moment, the H.264 format enjoys the most widespread browser support. One last thing, as you host video from your web server, the content types are very important. If you do not serve the video files with the matching content type, then the browsers will not know how to process the video. The content type values will vary depending on your video format. So make sure to check the documentation for each format you intend to use. Well now that you have an idea of the formats that are supported by which browsers, let's take a look at the basics of working with the audio and video elements.
Basic Controls
So let's start off by talking about some of the basics of the media element. So if we come up to Media and select the Basics demo, you'll be able to see the code that I'm working with here. Now as we look down at the video, it doesn't really look like much special. We just basically have a picture, and there's nothing really there for audio. Well the video and audio elements are here, but the controls are not turned on yet. So let's switch over to the code and make a few changes. So here you can see that I have a video and an audio element on the page. And they're loaded with a number of different sources. So here I have an MP4, an OGG Vorbis, and a WebM format each for the video. Down for audio, I have an MP3, OGG as well, and WAV. Now according to this comment up at the top, we want to serve the MP4 first so that the iPad can pick that up. And that's just done to ensure that your media is served in the most reliable fashion. Now let's go over here to the video element, and we'll add controls. And do the same thing with the audio element. Now when we refresh the page, you can see that each one of the video and audio elements now have controls associated with them. So for video, I can come and press Play, and the video's displayed. There's some volume control. And I can also mute the sound, as well as there being a time tracker here. And also I can go full-screen on that video. For audio (music playing), there's the scrubber, the Play and Pause button, mute, and volume control, And the time tracker. So by adding the controls attribute to the media element, it displays the controls on the page so that you can work with it. Now the reason it's optional is because you might want to have a situation to where you're controlling all of the different aspects of the media whether it's playing or pausing, volume, speed, any of those. I have a demo coming up that shows you exactly how to do that. But in the meantime, let's take a look at a few more attributes that you can use with these elements.
Basic Controls (continued)
One attribute that can help out is the loop attribute. So if I simply set loop to each one of these elements, now when it gets to the end of the timeline, it will automatically restart. So let's go to our video, and we'll take it right up to the end, press Play, and then it restarted automatically. The same of course will work for audio. And the nice thing about this attribute if we take a look at the code again is that there's no value that you need to give for these arguments. So we can simply place controls loop onto the video element, and that will work just fine. There is a preload attribute you can use, and this comes with the values of auto, metadata, and none. So depending on how you have your server set up, you can automatically begin to preload the video as the browser loads, or you can just bring in the metadata, or tell it not to preload it at all. And this works also with the audio element. Another attribute that is specialized only for the video element is the poster attribute. Without the poster attribute, the video element will show the first frame of the video as a preview. However, with poster what I can do is show a specialized image in place of the first frame. So here I have this labelled as Kitchen and can set up the video this way. So that covers the basics of the media element. Now let's take a look at what it takes in order to control the element completely through JavaScript.
Scripted Controls
This next demo shows you how you can take full control of the media element using JavaScript. So you'll notice here I have a video that's set up with a poster so you have the first image there that shows that it's of the kitchen. But the controls are completely turned off. So if I come over and try and work with the video element itself, there's no scrubber at the bottom. All the controls are turned off. Now I do have it set up so that as you click on the video, it will go ahead and play. And when you click on it again, it'll stop. And I have a custom scrubber down here at the bottom. So you'll notice that as I play and pause the video, that tracks with the video timeline. So here as I go, it advances. And when I press Pause, that stops it there on the timeline. Over on the right-hand side, there's a custom visualization for the time. You can see the full duration of the video is 14 seconds, and I'm 6 seconds into it. But I can go back on the scrubber here as well. And you'll notice that the frame of the video updated based off the location of the custom scrubber. And that is a range element in HTML. So if I hit Play again, I can fast forward, or I can go all the way to the beginning or to the end of the video. Let's go back to the beginning for a moment. I'll press Play. And then if I press the Stop button, you'll notice that it goes all the way back to the very beginning of the video and stops the playing of the video. Beyond just the video itself, I can have access to control the audio as well, bring the volume up. There's not much volume here in this video, but this does control it. And I can even mute and unmute the audio as well. And if I bring the video all the way back to the beginning and play, I can control the speed. And here with this scrubber, you'll notice that the playback goes even faster. So this gives you an idea of all of the control that you have available through JavaScript to control the media element. So now let's take a look at the code used in order to make this demo. Now there's a little bit of code required in order to build the custom control with a media element. So we'll start off by getting access to each one of the UI elements that are needed in order to power the control over that media element. So you'll notice here the first one here, I'm using document.getElementById for each one of these items in order to find the UI element on the page. So I'm looking for the video itself, a span for the remaining time, a span for the total time, the Play and Pause button, the Stop button, the Rewind, Begin, End, and Fast Forward buttons. There's a range element for volume. There's a button for mute. And then a range element for the scrubber, as well as playback rate. Now when it comes to changing the playback rate, I have a variable here called TIME_STEP, which means that it will change the playback rate by 5-second increments. And then I have the default value for the volume set here to 0. Now there're a couple of helper functions that we'd use as we're working with UI elements. So, first, let's look at formatTime. The media element will report all time information in just seconds. But in order to make it a little bit more user friendly, what I'd like to do is show the actual time in minutes, as well as seconds. So this function takes in the total number of seconds and rounds off the value. Then it figures out based off the number of seconds how many minutes are in the total number of seconds. So dividing seconds by 60 gives us the minutes, and then we can find the remaining seconds by taking those minutes, multiplying them by 60, and taking that value and subtracting it from the total number of seconds. Once we have the seconds value, if it's under 10, we'll pad it with a 0, and then it can return the full minutes and seconds up to the caller. So that's the function for formatting time. Next, let's look at playOrPause. This button as it's implemented in the demo is a toggle button. So when you press the button, you'll either be playing the video or pausing the video. So within this function, we first want to look at the video to see if it's paused or if the video has ended. If either one of those evaluates to true, then what that means is that the video's not playing, so we want to go to video.play in order to start playing the video. From there, we can update the button's innerText. And here we'll be setting it to Pause because that will be the inverse action of what we'll do once we begin playing the video. Alternatively, if it's not paused, and it's not ended, and it's playing, so then we can call video.pause, and then update the button text to tell it to play so when it's clicked on again, it can begin playing the video. So now we can use this function in a couple of different contexts. The first thing that we'll do is add an event listener to the video itself. So every time you click on the video, it will call the playOrPauseVideo function. Next, we'll also add that to the playPause button. This will give you the toggle capability when you press on the Play button. Now the implementation for Stop is actually quite interesting. There's no native functionality built in to stop the media element. So the way that you do that, you go to the media element, and here, of course, it's set as a video, but this would work just exactly the same way for audio. You call video.pause and set the currentTime = 0. So we're setting it all the way back to the very beginning of the video. Then I go to the playPause button and set it's label to Play. And then clean up everything else as well. So the video's playbackRate is set to 1. This is the playback speed. And then our custom scrubber for playbackRate, that's also set to 1. So now we have a few other buttons. We've got begin, rewind, fastForward, and end. For the begin button, when you click on this button, it'll set the current time all the way back to 0. So this essentially starts the video from the very beginning allowing it to keep playing. Rewind sets the video back just by a little bit. So here we're using our TIME_STEP to say that the currentTime is set to 5 seconds earlier than whatever the current time is. fastForward is basically the same thing except we're setting it to the TIME_STEP by incrementing it, so going forward in the timeline by the time increment. And, of course, the end button will take us all the way down to the end of the video, and we can get that by looking at the video's duration, just setting the video's currentTime to the duration. And, of course, since we're at the end of the video, it stopped playing, so we can update the playPause button to say Play. When we want to take control of the volume, here we can simply take the value from our volume scrubber and pass that into the volume property of the video itself, and that will set the volume. You'll notice that the volume input element has a minimum value of 0, a maximum value of 1, and a step increment of 0.1. So this ensures that the correct values get set into the video volume. Next, the mute button has a little bit of logic in here. So if the video is not muted, what we want to do is set aside the volume. That way when you go to unmute the video, we can set it back to whatever volume value it was before. So then we can toggle the muted state of the video. And then if we're looking to mute the video, we can set the volume.value to 0 and update the mute button's label. Otherwise, we can set the volume to whatever the value was that we set aside earlier and then update the label to Mute. Now for the video scrubber, here all we need to do is pass in the value of the scrubber into the video's currentTime. The scrubber has a minimum value of 0, a maximum value of 14, and a step value of 1. So these values come from the fact that the video is 14 seconds long, and we want the step to go in 1-second increments. PlaybackRate will change the speed of the video. So here we can take the value from this range element and set it equal to the video's playbackRate. The playbackRate input element has a minimum value of 1, a maximum value of 4, and a step increment of 1. So basically this makes it that we can play our video four times as fast as the normal rate. And then the last two events that we'll hook into are the video's play and timeupdate events. So as the video begins playing, we'll take the video duration, format that time, and set it equal to the innerText. So now we have the video duration in minutes and seconds that we can display on the screen. As the video is playing, the timeupdate event will fire, and we can take the currentTime of the video, format that as time, and set that equal to the remainingTime span. And then we can take the video's currentTime and update our scrubber value so that it tracks with the progress that's happening within the video. So by handling each one of these events, you have an opportunity to work with different parts of the media element's API in order to take full control using JavaScript. Now there's one last thing I want to point out before we move on, and that's the signature for addEventListener. Each time we've set up an event listener, the third argument here is a Boolean value where I'm always passing in false. The reasons for this are a little bit outdated. It has to do with event bubbling versus event capturing. It's a bit out of the scope of what this discussion is about. All you need to know is that you want to pass in a false value here just to make sure older browsers play nice with your code. In newer browsers, false is the default value. And this part of the API has been deprecated, so eventually we won't need to worry about it at all. But for now, just pass in false. Now let's take a look at the code that's required in order to create dynamic videos. So once one video is done, how do we automatically start the next one?
Dynamic Content
This next video demonstrates for you how you can build dynamic content. Now, of course, this works just as well as for audio as it does for video, but if I come through here and I start playing this video and kind of skip down to the end, you'll notice that as this video ends, it automatically starts the next clip that I have set up. So you could use this to build in ads or a playlist or any way that you want to stream different media elements together. So if I come over here to Markup, you'll notice that I have a single video element. Now I have some data- values here as well. So the firstfile is set to kitchen, and the secondfile is set to view. So those are the file names that I'll swap out as the video ends. And then I have some source elements. So I have an MP4, a WebM, and OGG formats all available for the same video. Now there's no CSS for this sample, so now we can go over and take a look at the JavaScript. The overall strategy for this approach is to look at the ended event of the video. And once that video is done, then go in and load up the next video. So starting at the top, here I'll set aside the implementation of forEach so we can use that on some different elements, and then use document.getElementById to access the video. Then I need the file names of the firstFileName and the secondFileName, so I'll use video.getAttribute in order to get to the data-firstfile and data-secondfile. Once all that's set up, then I can go in and call addEventListener listening for the ended event. So once that first video ends, then I can get all the sources that are associated with that video. So here I'm keeping it general, getElementsByTagName, and pulling out the sources. So here I'm going to the video element itself by using the this keyword and calling getElementsByTagName and pulling up the sources. So this brings the child source elements of the video and sets them equal to the sources variable. So now I want to go into the sources, look at the very first one here at index 0, and if the secondFileName is not found within that source, then I want to go through each one of the sources and replace the firstFileName with the secondFileName. So now each one of the source elements has been updated to have the secondFileName. Then I tell the media element to load, and then tell it to play. And it begins playing the second clip automatically.
Summary
Well make sure to stick with me for the next module on drawing shapes and more. But to summarize what we've learned here, we've talked all about music and video. Now this is all native support available without any plugins and accompanied by a very rich API. We've had the opportunity to take control of speed, volume, placement within the media, and even be able to automatically load media in any order that we want. Well thanks again for joining me. Let's move on to the next module on drawing with the browser's canvas.
Drawing Shapes, Charts, and More
Introduction
Drawing Shapes, Charts, and more. In this module, you'll learn the basics of the Canvas API, and together we'll cover what you can and can't do and a little bit about what you should and shouldn't do when it comes to using the canvas. You'll learn how to draw paths and shapes, use transformations, learn to manipulate the canvas with state management, create dynamic charts, and even extract a thumbnail image from a running video. Now before we begin discussing the canvas, let's contrast two different types of images. The first is a vector image. When you think of vector images, you can think of the type of image often associated with Adobe Illustrator where the image is made up of a set of instructions of how to draw the image. And this is all rendered on the fly when the image is displayed. Vectors are often used to form relatively simple shapes or compositions of shapes that make a larger image. One of the benefits of a vector image is that you can scale the image to any size that you want without losing resolution. Here you can see how the smaller image is just as crisp as the larger one. Now another type of image that you encounter is a raster image. Raster images are like JPEGs or PNGs or GIFs. These are images with a set dimension where every pixel within the defined space of the image has a designated color. Raster images have many advantages. In fact, the web is built on these types of images. But one of the drawbacks is that as you increase the size of the raster as shown here on the right, you begin to see that the image loses fidelity as the dimensions are stretched beyond the original intent of the image. So rasters, though, are great for pictures where you need to have explicit control over the color of each pixel in the image. Now when you think of HTML5 canvas, we're talking about rasterized images supported within the dynamic drawing surface.
What Is Canvas?
So a canvas is just that, a drawing surface similar to what an artist might have along with a paintbrush or a pen. You can draw shapes, apply colors, and even manipulate images on the canvas. And the rasterized nature of the canvas gives you a pixel-by-pixel control of that drawing surface. So how does it work? Well the canvas is the marriage between the HTML element and the canvas API. So let's talk about some fundamentals. There's an underlying grid system used by the canvas, and it may be a little bit different than what you remember from your high school math class. Here you want to more along the lines of cascading stylesheets. Positive values are found in the southern and eastern axes of the grid, while negative values are found in the northern and western axes of the grid. So if you were to render out a canvas in the browser, position 0, 0 rests at the top left corner of the canvas. Here the canvas is shown as being rendered at the top left corner of the browser, but, of course, you can place the canvas anywhere on the page that you wish. This is just to give you a mental model of how the canvas operates. To give you an idea of how to use the canvas, let's draw a simple triangle together.
Drawing Basics Part One
Here's the final result of what we hope to achieve. The first step is to begin with a blank canvas and gain access to the drawing context. Now the code I'm showing you here in the slides is a bit abbreviated. But I want you to get a feel for how the API works before diving in to the details. From the context, the first command to call is beginPath. What this does is tells the canvas, Be aware of what's coming next as it needs to keep track of all the coordinates being fed into the drawing context. The next step is to locate the starting position of the context to begin drawing. By calling moveTo, the drawing position on the context is set to an X position of 75 and a Y position of 50. Now that the starting position is established, the next command is lineTo. The call to lineTo creates a line from the starting position to a given destination. In this case, it's a straight line down as the X value remains the same, but the Y value is changed to 100. Now at the moment, the drawing context is only beginning to give instructions of where to draw lines. The actual line is not being drawn yet. And, in fact, in this case, a line won't be drawn at all, but the shape will be filled with a solid color. That command will come in a moment. The next operation is to give instructions to create a horizontal line at the bottom of the triangle. By calling lineTo again between 25 and 100, the left-most point of the triangle is established. The last step is to fill the shape with color. The call to fill does two important steps. First, it takes the last point in the path and connects it to the first point. This is really useful because it makes it easy to automatically close a path. And then as the function indicates, it also fills the now-closed shape with a color. In this instance, the default color of black is used. So that's the basics of working with the canvas. You begin drawing with the context. You give it one instruction at a time, and once you know how to appropriately apply the tools, you can do some amazing things.
Drawing Basics Part Two
So the first demo that I'd like to share with you is the same thing that you saw in the slides, but I want you to see it working within the browser. Now we have a blank canvas that we're working with at the moment, but we'll change that here in just a few minutes. If you take a look at the markup for this demo, it's simply a canvas element. It's got the Id of canvas and then some dimensions. So there's not really a lot going on here as far as markup. There's no CSS. And when we take a look at the JavaScript, there're four different approaches that I'd like to show you in working with some of the basics. So here we have the basic shape. And, again, this is what you saw as I was explaining on the slides. Now if we take a look at the content, here this is the shape that it builds after we run that JavaScript. Let's go back and take a look at that one more time. So once we make sure that we have canvas, then we can get the 2D context and begin creating a path. Then move to the first point, which is at 75, 50. Then create a line to the next point, which is at 75, 100. And then create a line to 25, 100. Once all that's done, we can call fill, and that fills the shape and gives it the default color, which in this case is black. So now let's look at something that's a little more of a styled shape. So this you can think of a little bit more like a Tetris block. If we take a look at how this runs, you can see that we've got this blue L shape with a gray outline around it. So in the last demo, I showed you how we can use the native API in order to detect canvas, but here I'm using Modernizr in order to tell me. It's just a little bit cleaner and even a little bit more reliable than writing that code for myself. So Modernizr.canvas, if that evaluates to true, then I can go and get the canvas's 2D context and begin working with that drawing context. Now we want to start off by beginning a path and then move to the starting point, which is 100, 100, and then lineTo these different points in order to trace the outline of the object itself. Then I can call context.closePath and then give it some color. So here I set the fillStyle to this blue color. And then tell the shape to fill. Now I want to give it an outline, so I set the line width to 6 and tell the lineJoin that I want it to be round. Now if we look back over at the shape, you can see that in this area right here in the corners, it's kind of rounded, and so that's what that command does. It tells us that as the lines join together, we want it to be rounded off. I can give it the stroke style of my gray color, and then context.stroke strokes the shape there on the canvas. Now that's a real basic shape. But now let's take a look at something that's a little more involved than dealing with the rectangle API.
Drawing Rectangles
This next demo shows you how to work with the fillRect function in order to create a number of different types of shapes and effects. So notice that I've created two squares here, and so I'm kind of doing that on purpose to show you that you will use fillRect to create squares. You can just pass it the same dimensions in order to create a square. So I've got a red square here. That's a full transparency. Then I have this blue square that's set at half transparency. And then I have this section here in the middle where there's a green outline, and the middle of that square has been cleared out. And that's accomplished by using the clearRect function. Let's take a look at the code. So I'm grabbing reference to my canvas and then taking a look at Modernizr.canvas to make sure it's supported. Getting reference to the context. And the first thing that I want to do is set my fillStyle. Now I'm doing this because as I call fillRect in the next statement, it needs to know what to color it. So here I'm passing in an RGB value. Before you saw me using hexadecimal values. You have the option of doing one or the other. So this is rgb(500,0,0). That gives me a nice red color. And then I can create that rectangle by giving it the X and Y coordinates that I want it to start off with, as well as the height and width of the rectangle. So in this case, it's a square because it's 100, 100. Now by calling fillRect, it creates a red square because just previous to that command, I called fillStyle passing in the correct color. So now what I want to do is create another box. This time I want a blue box with transparency. So now I'm setting the fillStyle to RGBA with an alpha channel and setting it to 0.5, so 0, 0, 500 gives me a blue color, 0.5 says that I want it to be halfway transparent. And then I can call fillRect giving me a different position here for the X and Y coordinates but the same width and height so I have the same dimensions for that square. So by calling fillRect, it will take the style that was applied right before it and create a rectangle for me. Now in the middle, I have this box that has a green outline, and it cleared out the contents of that box. And so to accomplish that, I want to call clearRect. So, again, it's the same set of arguments. I've got my X and Y coordinates of where I want that rectangle to appear. I've got my dimensions. So in this case, I have my height and width of 20. And I'm clearing out the rectangle in that spot. But to finish up of what I showed you in the beginning, I want to create a green outline around the area that I cleared out. So I set strokeStyle equal to RGB and a color that maps to the green shade. I set my lineWidth to 6, and then do strokeRect, which strokes the outside of a rectangle. And you'll notice that I have the very same arguments that I passed in for clearRect--115, 115 for the X and Y coordinates, and then a height and width of 20 each. So when we take a look at the end result, we've got the red box. We've got the blue box with the alpha channel. We've got a cleared out box. And then we have a rectangle with a green stroke around it.
Order of Operations
Now one of the things I want you to be aware of is in the order of operations does affect how the commands are applied. As this diagram depicts, if you apply a fill first and the stroke the path, the stroke is distributed along the boundary line where half the width of the stroke is inside the shape, and the remaining half is outside the shape. Alternatively, if you stroke the shape first and then apply the fill, the entirety of the shape is filled with the given color effectively making the stroke half the thickness of what it might be otherwise. So if you're creating shapes that need to have identical strokes, make sure the stroke and fill order of operations is the same among your different shapes.
Arcs, Text, and Gradients
This next demo will show you how to work with gradients, arcs, and text. So what you see here is the final result of the code that I'll take you through. So the markup is all the same. So let's start off by taking a look at the JavaScript. So after some basic ceremony, the first thing that I want to do is create that first gradient. Now the way that this image is created, I have two circles and two different gradients going different directions to give it that sort of pushed in look and feel to the image. So I want to start off by creating this first gradient. And you do that by calling context.createRadialGradient. And then by passing in the X and Y start coordinates. So here it's 160 and 120, the radius of the start circle, which is 0, and then the X and Y of the end of the gradient, and, finally, the radius of the end circle. So by providing all these values, the canvas gets instructions about how it will apply the gradient. And then I can add in the colors. So by adding in a color stop here of a light gray and then another color stop of a little bit darker gray, this gives it the range of colors that it will grade between. Now you'll notice that the first argument here that I've given is 0 and then 1. So the values for the color stops will be between 0 and 1 inclusively. So if I wanted to add something in between these two colors to basically fade between a third color in between, I would give it a value of something like 0.5 or 0.75 or something in between 0 and 1. But once I have that gradient, then what I can do is apply it to a shape on the canvas. So the next thing is to create the first circle, the base circle. So it'll switch gears a little bit and set the lineWidth to 0, the strokeStyle to black, which is the color for the hexadecimal value, and then tell it the fillStyle that I want is g1 or that first gradient that I've created. Then I can call context.beginPath and then tell the context to draw an arc. Now I'm drawing a circle, so this is an arc that starts at 180 of the X and Y coordinates, the radius is 160, and the start angle is 0, and then in order to create a full circle, I take Pi times 2. The last argument here is anticlockwise. This doesn't really matter in this case since I'm creating a full circle. But here you can tell it whether to go clockwise or counterclockwise. Once the instructions for that arc have been in place, I can call context.fill, and at this point the circle is drawn with the gradient. So now all I need to do is go and repeat the same process for the next circle. So here I create a new radial gradient with a few small dimensions, add in some color stops, and then create an arc that's a little bit smaller than the first one. And, of course, this arc goes all the way around creating a circle. Call context.fill, and then I have the second circle drawn within the context. Lastly, I'd like to put some text on this little button that I'm creating. So I can set fillStyle to white, the hexadecimal value for white, and then set the font to 280 px with an Arial font face, and then call fillText. So the first argument here is the text that you want to have rendered, and then the X and Y coordinates for where it should be placed upon the screen. So by creating those two circles, those two gradients, and the text, we end up with the shape that looks something like this. Now something I want you to notice as we're going through all of the different commands that are required in order to make this image, and that is what we're not doing is building up some sort of object model and giving commands and stringing together different building blocks in order to create something on the screen. In fact, what we're doing is giving linear instructions to the canvas to do one thing and then do the next and do the next. So if it helps you to think about it this way, you can think of a painter that uses a single paintbrush, and then another type of paintbrush, and then maybe other tools along the way in order to create something on their canvas. And that's very much like what you're doing here. This can end up simplifying development a lot because by having the canvas implemented this way, you know that only the immediate commands that are around what you're doing are what will be applied to the canvas. Well now let's move on to dealing with some effects like translate and working with state.
Effects: Scale and Rotation
Next I'd like to show you how you can scale the canvas. So beginning right here, you can see that I've drawn an image onto the canvas, and it's at the standard scale. It's at its full size. Now let's switch over to the JavaScript, see what it takes to get this image on the canvas, and also how we can change the scaling of the canvas itself. So after the initial ceremony, we get the context and then create a new image. Now what I want to be able to do is make sure to draw the image on the canvas once that image has been loaded. So here I'll handle the onload event. Once the image has been loaded from the server or the file system in this case, then I can call context.drawImage, pass in the instance of the image, and then I have the X, Y coordinates that I want place the image on. For this example, I'd like it draw in the upper left-hand corner so I'll give it X, Y coordinates of 0, 0. Now that all happens once the image loads. So in order to give the image object a source so it knows what image to load, I have to give it a path here, so img/home.jpg works just fine. So that's all it takes to load the image on the canvas. But then I have some options available in order to scale the canvas. So, first, let's go back to the canvas and see what it looks like as I've scaled it to half of its original size. So as we switch back to the content itself, you'll notice there's the very same image but at half the size. So here the image has been drawn on to a canvas that has been scaled down to half the size. The way I accomplish that is by calling context.scale and passing in 0.5, 0.5. So whatever values that you pass in to the scale method, that's essentially the zoom level that we'll use in order to scale the canvas. Let's try a different one. Let's pass in 2, 2 in order to zoom in to double the size. Now as we take a look at the result, the canvas has been zoomed in to twice the size, and the image shows up as two times its original dimensions. Now those arguments that you pass in the scale don't need to be equal. In fact, if I refresh the page with different values going into the scale method, you can see that I have kind of a squished home image here. So if we take a look at how the code has changed, come down here and you can see that I'm passing in 0.25 and 0.5 to scale, so it scales the X coordinate at 25% and the Y coordinate at 50% giving me the result that you see here. Next, let's take a look at rotation. Now I went ahead and refreshed the page and applied the code for rotation so you can see that this is the final result. So I have an image on the canvas, but the entire canvas has been rotated by a certain amount. So if we go back to the script, let's skip that helper function at the top just for a moment, and you'll notice that here I'm doing the very same thing in order to load the image on the page. However, down here at the bottom, I'm calling context.rotate. Now the value that it takes in for rotate is radians. So here's being rotated by 0.2 radians. However, if you want to work with degrees, all you need is a simple helper function that will convert radians to degrees. So if we take a look at that helper function up here at the top, degreesToRadians, here you pass in the degrees that you want, and then you multiply that by Pi divided by 180, and that will return the radians that the rotate function needs. So let's take a look at what it would look like if we wanted to rotate the canvas by -15 degrees. Here I've refreshed the page and run the code in order to rotate by -15 degrees. So the code here is just calling context.rotate calling degreesToRadians and passing in whatever value you want in order to rotate the canvas. Now let's talk about translating the canvas and saving and restoring state to the canvas.
Effects: Translate
Working with the canvas requires a lot of code. Here what I've done is I've rendered an image onto the canvas and then used the canvas APIs in order to write out the text of beautiful homes onto the image. So let's take a look at the JavaScript for that just for a moment. So I'll start off by loading in the image in the same way as what I did before. So I give it a source of img/home.jpg. And then once it loads, then we can come in and draw that image to the canvas. And then I have a number of different commands that are responsible for drawing the text onto the canvas. So fillStyle is set to white, strokeStyle is set to black, lineWidth is 6. And then once I've got those general settings set up in the canvas, then I can apply the text of Beautiful Homes by setting the font size, calling strokeText, fillText, and then doing the same thing for In Your Area. Here I'm changing the font size a little bit, changing the dimensions of the X, Y coordinates of where I want to stroke and fill the text. And that's the code required in order to render the image and put the text out on the page. But let's say that I want that to show up in a different spot. Let's say, for instance, I want that same image and that same text to show up at 50 px down and 50 px over on the canvas. Now, rather than trying to update all these different values that I have here, there's a shortcut that I can use, which is called translate. Let's refresh the page and take a look at how things change once we start using the translate command. Now once the page is reloaded, you'll notice that the image itself has moved down and over by 50 px. So by using the translate command, what I've done is I've told the canvas that I want my new starting point to be whatever dimensions you give it. So in this case, it's 50 px over on the X axis and 50 px down on the Y axis making the new starting point right here. But the key to this, the value of using translate means that all the other code that I needed to place that text on the image remains unchanged. It essentially repositions the 0, 0 position or the relative point of reference so that as I apply commands to the canvas, I don't have to create a series of adjustments by running some math trying to decide where I want everything to show up. Let's take a look at the code, and you can see how this has changed. So essentially the only thing that's different about this now is this line here, context.translate. So I've moved the point of reference 50 px over on the X axis and 50 px down on the Y axis. And so all of the code can remain unchanged, yet I'm still drawing the image in a different spot on the canvas. So translate can really be your friend because you may have certain dimensions and positions that you already have figured out, but you want that to show up on different parts of the canvas. And all you need to do is call canvas.translate to change the base point of reference for the canvas itself.
State Management
One of the features of the canvas API that can really save you a lot of time is state management. Now here I've brought you back to the same demo that I create earlier when I created the rectangles except with some slight variation. You'll notice I've got the red box, I've got the blue box, and the clear rectangle with a green outline. But in between the steps of creating that blue box, what I did was save the state of the canvas. So once I saved that state, then I can make changes like calling translate and scale and a few other things, create that box, and then restore back to the previous state of the canvas, and then create the green box. So the whole point of state management on canvas is that what you can do is take a snapshot of the canvas, make some changes, and then revert back to a previous state. And it's stackable too, so if you save state on the canvas multiple times, each time you call restore on the canvas, it'll back you up to the last snapshot on that stack. So, again, this code is exactly the same as what you saw before with just a few minor changes. So you'll see here I've got a place to build up that red box, but then I'm calling context.save. At this point, I've created a snapshot on the canvas, and then all the code that's between these comment blocks, they call the translate, rotate, scale, and then even adding that blue box, that's all done in isolation on the canvas. So I can call all of those commands and then come down here to context.restore, and now the canvas is reset to this state before any of those commands are done. So now when I call clearRect, even though I called translate and scale previously, those are essentially undone because I've gone back to a previous state of the canvas. And, again, they're stackable. So if you call context.save many times, each time you call context.restore, it'll go back to the last one in the stack. Now let's talk about animation on the canvas.
Animation Basics
Now working with the power and capability of canvas just would not be as fun if you didn't have the opportunity to animate the canvas itself. Now I'll show you a couple of different approaches to animation. This one is fairly basic and simple. But this'll kind of get you started in what it takes in order to animate on the canvas. So you'll see here what I had happen was a line that's drawn down the canvas, and then a notification that lets you know when the animation is complete. So adding to the markup, I just have a div here for the result in order to put the message there saying that the animation is complete. And everything is done within the JavaScript. So the actual work for drawing on the canvas is done within this draw function. We'll come back to that in a moment. But you can see here as we detect whether or not canvas is supported, then I create a variable called frame and set that equal to setInterval where the interval calls the draw function every 25 msec. And so once the animation is done, I can clear this interval. But by calling setInterval, that's how I'm getting the animation happening on the canvas. So as we come up to the draw function, the first thing that I'm looking to do is to see if the value I've set aside for X is less than or equal to the canvas width. So once we go outside the bounds of the canvas width, I want to stop the animation. So if we're animating on the canvas, what I'm doing first is calling clearRect. So this is kind of a brute force way of handling this. Each frame starts off with a blank slate. I'll show you another approach where you can add to the canvas, but to keep things simple here, I'm just going with clearRect, and then I'll draw the line on it each time. So I'll set the strokeStyle to the red color, my lineWidth to 8, and then beginPath and moveTo the 0, 0 position on the canvas. So I'm starting at the upper left-hand corner. And then I'm calling lineTo(x +=10, y +=10). So this moves the line down the screen by 10 px each time. And then calling context.stroke. Now, remember, this is getting called every 25 msec, so this'll get called again soon. And then you evaluate the new value for X and go all the way down until it's done. So once the line is done drawing within the boundaries of the canvas, then I can call clearInterval by passing in my frame variable, and that will stop the animation. And then I can notify the application that the animation is complete. And here I'm just setting a label's innerText equal to Animation Complete. Now, of course, in your code, you could have it call other things, start other animation, and on and on. But this is a very basic way of setting up animation on the canvas.
Clipping Introduction
Clipping during image manipulation involves taking a certain area of an image and restricting rendering to that specific area. Here you can see a circular mask or a clip area and how it's applied over the image. By creating this clip area, changes made to the image inside the circle are rendered while changes that fall outside are disregarded. This is the same concept when you use clipping in canvas except the same rules apply to the entire canvas rather than just a single image. The following demo uses images, as well as shapes on the canvas to demonstrate how the clip feature works in detail.
Clipping Circle
Just as I showed you in the slides, the first demo that I have available for you here shows how to apply a circular clip area to the canvas. So the thing I want you to pay attention to right now is the order in which everything is done, and I'll move things around a little bit so you can kind of see how the order affects the way the canvas interprets the commands. So starting from the top here, I have beginPath. I create an arc. And then I call context.clip in order to create a clip area in the canvas. Now the way the clipping works is that you need to create your clip area first and then apply commands to it in order to have the clipping work correctly. So here I've created the clip, and then I create a new image, and then draw that image onto the canvas. Now you notice I've stroked my image with an outline, and I have a lineWidth of 15. But, in fact, the lineWidth that you're seeing here is much smaller. It's about half a size smaller than that 15 lineWidth because, remember, when you stroke path, half of it falls on the inside of the path, half of it falls on the outside of the path. But some of that outline is falling outside the clip area so you're not seeing it. So let' me update this code a little bit, and I'll rearrange things a bit, you can kind of see how things change. So I've moved things around a little bit, and you'll notice here I'm starting off by creating the image first, and then coming down after this, calling beginPath, and creating the circle clip area. So let's execute this. And you'll notice that nothing's different. Now the reason nothing changed is because although I have my instructions for beginPath and creating a clip here at the bottom, because of this callback, all of this code is running after the clip has been established. So essentially the order of operations is the same as what you saw before. Let's update this one more time, and then I'll call the clip after the image has been loaded. We'll see how that changes things. Now things start to look a little bit different. So notice again the code here in the onload function. So the image is loaded and then drawn on to the canvas. I begin to create a lineWidth and strokeStyle and try to stroke something, but that's all called before beginPath has been called. And then I call beginPath and build an arc and try to clip it. And so nothing happens at this point. So if more code executed after context.clip, then it would only show inside the clip are. But this is meant just to illustrate the fact that you need to create your clip area first and then the commands that come after that are applied to the canvas. Let me go ahead and reset this back to the way it should be. So just as I've pointed out in a number of different ways, the way and the order in which you add commands to the canvas make a big difference. So here we are back to calling beginPath, creating my arc, and clipping that circle so that once the image is loaded, it loads into that clip area. So, of course, you're not limited to using circles. So let's take a look at how you might clip with a rectangle.
Clipping Rectangle
This next demonstration shows you how you can use a clip area with a rectangle, as well as with the circle. So no surprise when I call beginPath and create a rectangle and clip that area. Once the image has loaded and it's drawn on to the canvas, the clip area is in this case a square but using the rectangle API. Now just to drive home the point that once you apply extra commands to the canvas after you've called a clip, what it'll do is discard any information that's outside of that clip area. So let me update this code one more time, and you can see what happens if I draw another rectangle after I've drawn the image and after the clip area has been established. So what's changed here is really not much. I've added two lines of code down here at the bottom. So you can see I've added fillStyle. I gave it an alpha transparency so you can see that as I create that rectangle, you can see it on top of the image. And then I called fillRect. Now the arguments that I've given here are what's significant. So I said start at position 0, 0, so it's starting up here at the top. And then I've given it the dimensions of 100 px by 100 px tall so it's essentially a square. So once that's rendered onto the canvas, you'll only see a part of it because it falls within the clip area. So let's take a look at this without the call to clip. So here I've commented out context.clip. And now you can see that I have my full image. I've got my full stroke. And I have my full box that's all rendered onto the canvas. But since there's no clip area, it's not restricted to a certain part of the canvas. So, next, let's investigate how you can reset clip areas once you've applied them since they have so much power over the canvas.
Clear Clipping Areas
Now sometimes you'll apply a clip to the canvas that you want to have available only for a certain amount of time because it's pretty powerful in the way it restricts the way that you render out to the canvas. So I'll show you the code here in a second, but in this demo I've created sort of this weird shape on the canvas. And then after I created my clip area of this strange triangular shape, then I created a rectangle or square and applied it. And you'll notice that only a certain part of it is showing up, and that's the part within the weird triangle shape. But then what I do is remove the clip area and render out another box within the canvas. And this shows up unrestricted by the clip area. So there's a special way that you need to use in order to reset clip areas. So let's take a look at the code here. I start off by giving a fillStyle, and I set up the strokeStyle and lineWidth and everything for my shape. And then I'm calling context.save. At that point, I can call beginPath, and then I draw out my strange triangle shape, call closePath. I stroke it and then call context.clip. After I call context.clip, then I can call fillRect. And this is kind of a big box. So it's starting at the 0, 0 position. It's 215 by 215. But all that renders out on the canvas is what shows up in my clip area. Now you would think that in order to reset your clip area, you could do something like this. You could call context.rect, and you start at the 0, 0 position giving it the full width and height of the canvas, so basically opening it up to the entire dimension of the canvas, and then calling clip. Unfortunately, that does not work. The way that you reset a clip area is by using a technique that you learned previously, and that's through state management. So, remember, I called context.save at the top before I created my clip area. Now what I can do is come down and say context.restore, and that essentially removes the clip area. So when this call to fillRect is done at position 200, 200 giving it a height and width of 50 px, when that command is run, it renders outside the clip area because context.restore has removed the clipping that's been applied to the canvas. So you can see how state management quickly becomes something that's really valuable as you work with the canvas because once you apply a clip to the canvas, any of that information that falls outside of the boundary will be discarded. Well, so far, the clipping's been pretty simple and basic. Now let's talk about creating a clip area that's with some noncontiguous areas.
Clipping Non-contiguous Areas
Now so far every clip area that I've shown you has been a circle or a rectangle or even some weird triangle shape. But it's all been one shape. So what I'd like to show you now is how you can create a clip area that's noncontiguous. And the point is you can clip on the canvas using any sort of shape or geometry that you want. So I've executed the code here, and you can see how this runs without any calls to clip. So I have a large box that I have rendered out onto the canvas here. I've stroked a couple of areas on the canvas, and then, lastly, I've created another box here at the end that's roughly the same size as my stroke areas. So now I'll uncomment out the call to context.clip, and we'll see how things change. So notice with the clip area defined, now I have what seemingly looks like three different boxes on the canvas, and two of them are outlined. The key here is I'm creating two different types of rectangles before I call the clip function. And so essentially what happens even though I have that large box in the background, I'm slicing through two little windows on the canvas. So once those commands are applied, the only thing that shows up is the stroke and the background color. And I'm getting that last box on the canvas because once I call context.restore, that removes the clip area, and then I can do a fillRect or anything that I want afterwards. So the main takeaway to this demonstration is the fact that your clip areas can be anything. If you need it to be a simple shape, you can do that. Or you can punch holes in the canvas and clip any way that you want. So let's put everything that you've learned all together right now and create a magnifier on an image.
Demo: Magnifying Glass
Now by bringing together everything that we've learned so far, we can create something that's a big more interactive. So here on my image, if I click on the image, I have a magnifier, and it zooms in on a certain part of the image. And if I click, it goes away. So to create this, we'll strokes paths, we'll use clipping areas, we'll use state management, a number of the different things that you've seen so far in order to create this sample. Now the code's a little bit longer than usual, so I'll drop down to my text editor, and we can take a look at it there. The basic structure for the way this is set up is pretty simple actually. So the first thing to do is initialize the canvas with some of the basics. This draws the image out on the canvas and sets aside the image data so that we have it later when we want to add it into the magnified area. But when the canvas is clipped, it looks to see if it's been magnified. If it's already magnified, then it reinitializes the entire canvas. Otherwise, it calls the function to magnify that area of the canvas. Well, let's take a look at the init function first. The first thing the init function is concerned about is loading the image onto the page. So here it has the img.src, home.jpg, and then I'm setting up a flag to say that isMagnified is equal to false. Once that image loads, then it can draw onto the context. But then I can go to canvas and call toDataURL. Now this is important because what this will do is give me basically a string representation of all the data of my image so that when I go to magnify it, I don't have to load the image in from a server or the file system or anywhere else. It all exists within memory here. So the init function will be called when the canvas first loads, as well as when we click on it to remove the magnifier in order to reset up everything to its initial state. Now let's look at magnify. Now to start things off, the first thing I'm doing is calling context.save. And so that ensures that anything that I'm doing within this command to magnify is all done basically within its own logical container. Then I want to set up some defaults. I'll set up the lineWidth, the shadowColor, and some basic settings for the shadow itself. So as I'm creating the circle around the magnifying class and also the handle, I want both of those areas to have the same shadow settings, so I set that up ahead of time. Then I'll call context.save again because what I want to do is create the glass area of the magnifying glass next. So by calling beginPath and moving to a certain area within the canvas, then I can draw that circle. I'll give it a lineCap of round, lineWidth of 30. Then I'll call context.save again, and I can begin creating the handle for the magnifying glass. So by calling beginPath and moveTo(230, 230), that puts me in the correct position to draw the handle on the canvas. I want lineCap set to round so that the handle looks like it's rounded. And then give it a pretty big width, so here I have 30. And then I can lineTo(285, 285), which gives me a diagonal line, which will represent the handle. Calling stroke on that will render out the handle onto the canvas. Next, I want to create another path. So I create a circle for the glass of the magnifying glass. And then once that's set, then I can create a clip area. Now since I've clipped the canvas, I can go ahead and render in the image. So here I create the magnified version of this image and set the source equal to dataUrl. So this is the text-based data that's been set aside for that image. So I don't have to load it again from anywhere else. I can add that into the source for my image. I can scale that up to 150% and draw the image on the canvas. Now since I'm using the clip area, I don't need to worry about any extra settings. All I need to do is draw the image on the canvas. Then to clean things up, I call context.restore. That removes the clipping area. And then I can stroke the arc around the glass part of the magnifying glass by creating an arc and calling stroke. And then I call context.restore to restore the canvas back to its original state before I started applying any settings to it. I flip the bit on magnified to say that isMagnified equals to true. And so now when we go and click on the canvas, if it's magnified, it reinitializes it. Otherwise, it'll apply the logic to magnify the canvas. So that wraps up clipping. Now we can continue doing interesting things by building some charts using the canvas.
Demo: Static Chart
Now when you work with the canvas, you have a pixel by pixel level of control over drawing on the canvas. Now this is a good thing because it gives you a lot of precision. So you can decide how you want to draw very specific parts of the canvas. But at the same time if you want to create something that's maybe a little more elaborate, well, that can take a lot of instructions and a lot of JavaScript. So here you can see I have a chart that I've rendered out onto the screen, and I've plotted some points on the chart. Now the chart background is a background that I created in Photoshop. I wouldn't call this elaborate necessarily, but I've got some gridlines. I've got labels for different areas. I've got a gradient in the background. And in order to build this in JavaScript, it would take a fair amount of code. So in order to sidestep all that complexity, what I've done is just created this image here within Photoshop and then only worried about plotting the data points using JavaScript on the canvas. So let's take a look at the code. First, I'm getting access to the canvas itself and then setting aside a variable for the drawing context. So the key here is once I've loaded the background image, I can handle the onload function and then begin drawing on the canvas. So you notice here I start off with drawImage, and this draws the image data onto the canvas. And then I can begin drawing a path by calling beginPath. So I'll start off by moving to the beginning point of the data that needs to be plotted by calling moveTo 70, and then 105. And then have all of these lineTos that correspond to the data points. Now, of course, this data for you might come from a database. It might come in from an Ajax call. It might be in some other form. Here I'm just hard-coding it. But I'm calling lineTo for each one of the data points. And then once I'm done, I can call stroke, and that will make the line appear on the canvas. So all this runs during the onload function. And here down at the bottom, I'm giving the image element its source. So as everything executes, it loads the image and draws the data points onto the canvas.
Demo: Dynamic Chart
This next example builds upon the last one where well still use a background image for the canvas for the chart. But what this does is it simulates a service or some data coming in at different intervals that you're drawing on the canvas. So instead of clearing out all of the information that's on the canvas during each one of the frames like we did with the animation sample, here what's happening is a segment by segment piece of the data plots is being added to the canvas at a time. There's a little bit more code for this demo, so I'll drop into the code editor so we can look at that piece by piece. Now since I want this to be a stand-alone sample, what I've done here, I've set up the demo with an array of data objects. So here I have month and performance. So this could be, say, charting a stock for a stock ticker. So I have the chart data here. And then I'll set aside variables for the canvas, the context, and the index. So the index will keep track of the item that we'll looking at based off the data array. Now most of the work will be done here in the drawSegment function. So I'm keeping track of the data points by having x1 and y1 and x2 and y2. So this is basically the start and stop points of each one of the segments on the chart. So as this function executes, I'll go into the chart data, take out the month and performance points based off of the index. That'll be the start position. And then the end position is accessed by taking the index + 1, and then I'll have month and performance for the end point. So for each one of these segments, I'll call beginPath, move to the starting point, and then create a line to the ending point, and then call stroke. Then I'll update the index so that next time drawSegment is called, I'll be looking at the next data pinot in the array. So now let's look down at how this is called. So here's the standard ceremony of ensuring canvas, of making sure we have the context, and everything that we need. And so I'll load in the background image. Here I'm setting the source. And once the image is loaded, I'll draw it into the context by calling drawImage. Then I'll call drawSegment the first time. Now the formatting of the line is set up here by setting the strokeStyle, the lineWidth, and the lineCap. Now like I said, the first segment will be drawn as the background image is loaded. But then I'll set up some animation. And this is just here to simulate a call being made out to an Ajax service or use of web sockets or some other method of getting data into the page. But here I'll just setInterval for every 750 msec and drawSegment. Now I'll go ahead and clear out the interval once we reach outside the bounds of the chartData. So this cancels the animation once it's done. But the main point for you is that you can continually update the canvas, just like I'm doing here, by going to beginPath, moveTo, lineTo, and then stroke as many times as I need in order to plot the data points on the canvas.
Demo: Video Thumbnails
In this last demo that I have prepared for you, I'd like to show you the amount of flexibility that you have available in the canvas. So the way this works is I have a video element on the page. And as I press Play on the element, I can click this button and extract out a thumbnail from the video. So what's going on behind the scenes is that as the video is playing, I'm passing the video element into a function that extracts out the frame's image data and passes that into the canvas. And so once I have that data, I can render in the canvas. And so even though you can do all kinds of drawing within the canvas, here you could see how you're not left to do all the work on your own. You can load in images directly or even from a video. Let's take a look at the code that makes this all happen. So starting off, I'm just setting aside some variables for different elements on the page. So here I have the video itself, and then also the canvas. Of course we'll need access to the drawing context of the canvas so I've created this variable here. And then also I have the buttons and a container for the thumbnails. Now most of the work is done down in this function called getThumb. But before we get there, let's take a look at the width and the height. So I want all of the dimensions to be uniform. So the video.width, the canvas.width, and the video.offsetWidth setting equal to 320. And the unit of measure here is pixels. Doing the same thing for height, so the video.height, canvas.height, and the video.offsetHeight is set to 180. So now as we run the function for getThumb, I access the drawing context of the canvas and call the drawImage function. Now by passing in the video as the first argument here, the current frame of the video is the source of the data for drawImage. Now I want to draw it on the canvas at the 0, 0 position, and I'll pass in the width and height that I've already set aside. Now I can create a new image, and then I can set the source of that image as what comes out of toDataURL. Now here I'm passing in the content type of image/PNG. And so that is set as the source of the image. I'll scale down the image just a little bit by setting the width to 60 and then append each one of those thumbnail images into my container by calling thumbs.appendChild. So all that's left to do is to wire up the button in order to call getThumb. So here I'm calling addEventListener, looking for the click on the button, and so when you click on the button, it'll run the getThumb function. So once again, as the video plays, we call Get Thumbnail, and it writes the image data from the video into the canvas.
Summary
Now that you've had a chance to learn all about canvas, make sure you join me for the next module that discusses HTML5 drag and drop. Well here we've been talking about drawing shapes, charts, and more, and that's all done through the canvas found in HTML5. You saw how it's a raster drawing context where you have control on a pixel by pixel basis of what you can draw within that context. And you can apply different effects from translation to scale. You have the full ability to manipulate what's drawn on the canvas. Well, alright, let's move on to the next module where we talk about drag and drop.
Drag and Drop
Introduction
Welcome back to HTML5 Fundamentals. This is Craig Shoemaker, and thanks for joining me for this module on drag and drop. In this module, you'll learn the basics of drag and drop, learn about the event pipeline and restrictions of drag and drop operations, and learn how the browsers deal with the drag and drop data internally. Now the drag and drop functionality is driven passed off of events, so let's dive in to each one of these events now.
Events Overview
So how does drag and drop work? Well first you need to define a drag source and a drop target. Once the elements on the page are marked as draggable, then you may drag them around onto elements. But the number one rule that you need to keep in mind about this API is that you must cancel the default behavior on drop targets in order to allow the drop action to execute. Now this might seem a little counterintuitive at first, but the reasoning behind this implementation is to keep pages secure. So while you can drag elements all around the page whenever you like, in order to handle a drop action, you must explicitly tell the drop target to accept the draggable action by preventing the default behavior and appropriately handling the drop events. Now there're a number of different events associated with the drag and drop API. At first glance, the events may seem a bit unruly. There're no less than seven different events, and a number of them are required for you to handle in order to implement drag and drop behavior. Events are either associated with the drag source or the drop target. The drag source is the element you click on and drag on in order to initiate a drag operation. The drop target is the element you drag the source over and eventually drop onto. This slide depicts how the events are associated with either the source or the target. Now let's take a look at them individually.
Events in Detail
As you click on an element and begin to drag it, the dragstart event fires. Then as an element is being dragged, the drag event fires. Once an element is dropped on the target, then all drop target events are fired. And then, finally, the dragend event fires on the drag source. Now an important thing to note here is that the drag event continuously fires as the drag is happening on the element. And you'll see this in more detail once we arrive at the events demo. Alternatively, on the same operation, there are events that fire on the drop target. As the source element enters the boundary of the target, the dragenter event fires. Then as the source is over the target, the dragover event fires. Now much like the drag event on the source, the dragover event continually fires as the source is being dragged over the target. Now if you drag the source off the target, then the dragleave event fires. But if you drag the source over to the target and then drop it, the dragenter, dragover, and drop events all fire. Let's see it in action now by checking out the demoes.
Basics: Demo and Markup
The first demo here for drag and drop shows you just the very basics of getting everything set up. So the way this works is I can take this image here, and I can drag it all around the screen. And you notice that it has the icon there for saying that it can't be dropped until I bring it into the drop target. And once I let go, it drops into the drop target. So I can't drag it back or take it anywhere. This is just the very basics of getting drag and drop set up. So let me show you the markup, the CSS that's involved. And then in the next clip, we'll go through the JavaScript itself. The markup is very basic. I have two divs. Inside of the source div, I have an image. Now, images and links are automatically set up to be draggable within the browser. But here I'm just being explicit because I want to show you this attribute here where draggable is being set to true. So any time that you want to make an element on the page draggable, you need to add the draggable attribute and set it equal to true. Now I have some Id's set up here, and this data-role will come into play in a later demo. But for right now all we need are the Id's and the element that I want to drag to have the draggable attribute set to true. Now let's look at the CSS. The styles that I have here are simply to serve the purposes of the demo and aren't necessarily required for your application except for maybe a few things I'll show you here at the bottom. But here I'm just saying that any one of my elements that I'm setting up as a drop target, so data-role of drop target, gets styled as a box and has a specific width and height. Here with the over class, I'm setting the background color to a light yellow so that you can see which elements you can drag over. For elements that are being dragged, here I have some vendor-specific styles that are meant to support older versions of the browsers. And, finally, for the elements that are being dragged, I set the opacity to 25% again to just give a visual indication of what the element is when you're dragging it across the screen. Now let's drop down into the editor so we can take a look at the code that's used in order to set up a very basic drag and drop demo.
Basics: JavaScript
Let's start off looking at this demo from the bird's eye view. I want you to get an overview of how this code works before I dig in to the details. So you'll notice first that I have a drag source just like we talked about on the slides. So here's the drag source, and then also a drop target. For the source, I can add an event listener for the dragstart event, which we'll call the dragStart function. And in there, it'll set everything up that's required in order to handle the drag and drop operation. Then from the target, you'll notice there're three events that are handled. There's drop, dragenter, and dragover. The only event that has any sort of functionality applied to it is the dropped function. Everything else is canceled because, remember, as I told you in the slides that some of these events need to have the default functionality canceled in order to allow a drop action to occur. And that's for security. You don't want everything opened up by default. You want to be able to explicitly say, These are the areas of the page where you can allow dropping to happen.
Basics: JavaScript (continued)
Well let's take a look at dragStart. Now as the comment explains, IE doesn't support the data type of text/plain. So when the dragStart happens, we're going to take a look at a e.dataTransfer, and then we're going to try and set some data into the dataTransfer object. So for any other browser except for Internet Explorer, we'll be able to do that through the text/plain content type. And here we're just pulling out the value of the Id of the drag source. So e.target.id is pointing to the source. It's a little confusing here. Make sure you don't get this target confused with the drop target. That's totally different. Here, this is the event target's Id. So we grab the Id of the element that we're dragging and pass that into the dataTransfer object. And there's just some plain text that we're sending in to setData. So if it's Internet Explorer, then we use the content type of just Text. That capital T is very important. But now either way, we're able to support all the browsers. So now this dataTransfer object will take the Id of the element that we're dragging and send it over to the drop target. Well before we get there, let's take a look at the cancel function. Cancel really does live up to its name. It looks to make sure that e.preventDefault and stopPropagation exist and calls them in turn if they do, and then returns false. So this stops everything that's happening on the element that it's pointing to, which is exactly what we want in order to allow a drop operation to happen. So dragenter and dragover are automatically cancelled. But then we'll also do that when an element is dropped on to the drop target as well. So let's take a look at the dropped function. So here within dropped, the first thing that we'll do is cancel all operations allowing the drop to happen. And then we'll go back into that dataTransfer object, and this time instead of calling setData, we'll call getData making sure to pass in the same content type that we used to set the data. So here we're using text/plain or Text with a capital T for Internet Explorer. Either way, we get the Id that we're working with, and then we can call e.target. Again, this does apply to the drop target. It's the target of the event. e.target.appendChild, and then I can do document.querySelector and then pass in the Id. So this gets referenced to the element itself and appends it as a child to the drop target. So essentially what's happening is I'm able to take the element and move it from the source into the target all with this one line of code. So that's the very basics of working with drag and drop. So now let's take it a little bit further, and I'll show you how to use role selectors in order to generalize things a little bit so you can expand the functionality of your drag and drop operations.
Role Selectors: Demo and Code
This next demo adds a little bit more flexibility to the drag and drop operations by generalizing things just a bit. So you notice here what I can do is drag the image over to this drop target. But then I can also take it, and I can't drag it up here, and I can't drag it down here, but I can put it back to where it came from, so I can swap back and forth between these two divs. So by using role selectors and many other different techniques, but here I'll show you how to use a data-attribute in order to set up the drop targets, and you can take the source back and forth between the two. Let's go back to the code editor and take a look at the code. Once again, starting with the bird's eye view of this demo, you can see that I'm setting up targets, meaning more than one target, and then also the drag sources. Now the key here is I'm setting up the drop target through the data- attribute of data-role. So if you remember from the markup, the div had data-role="drag-drop-target" applied to that development. So by calling querySelectorAll, I get each one of those elements and have it set to the targets. Now I showed you earlier on in the course how you can use array.prototype.forEach and set that aside into a variable in order to do an iteration over the element list that comes back from querySelectorAll. Well here's a shortcut. So by using the brackets representing the array class, this is basically shorthand for that exact same syntax. So here off of array calling forEach and calling it on the targets, I can iterate through each one of the targets, setting an event listener for drop, dragenter, and dragover. Now this is the same thing as the last time I showed you. We're automatically cancelling dragenter and dragover and handling drop. For sources, I'm doing querySelectorAll for everything that is draggable set to true, iterating over each one, and adding an event listener for dragStart. Now let's take a look at the functions that provide implementation for each one of the events. Now sourceContainerId comes into play because what I want to be able to do is to only allow dropping on an element that's different from the source container. So here for dragStart, I'm doing the same thing you saw previously, setting the data using the content type of text/plain or Text equal to the target's Id. And then I'll also look at the parent element's Id and just set that aside. That'll come into play in a dropped function. Before we get there, let's take a quick look at cancel. This is the same as what you saw before. It's basically just stopping everything, calling preventDefault, stopPropagation, and returning false. So now once dropped executes, then we can take a look at the Id that's coming in. Well take a look at this Id, and if it doesn't equal the sourceContainerId, then we know that we're dropping into a different container and can continue on with the drop operation. So here I'm calling getData using the content type that we needed before, and then can call e.target.appendChild passing in the Id of the element that was dragged and getting reference to it through document.querySelector. Basically, the implementation of what you saw from this demo and the previous demo was nearly identical except for the fact that by adding the data- attributes and using querySelectorAll in order to set up the events for each one of the elements, I greatly increased the flexibility of my drag and drop application because now I can set anything to a drop target and anything as draggable. So, next, let's take a visual tour of the seven different events that are involved with drag and drop.
Events: Demo and Markup
This next demo is a bit of a visual tour of the different events that are involved in a drag and drop operation. So I'll start off just by dragging this around a little bit. I won't drop it into the drop target. But I'll just drag it around a bit, and you can see the events that begin to fire as we're moving the image around. So I'll take this and drag it around and just set it down there for a moment. So starting at the very top, you'll notice that from the source element, the dragstart event first fired. And then the drag event on the source fired. And that continued to fire as I was dragging the element around on the page. Now in turn for the target, you'll notice that dragenter fired, and then dragover continued to fire as I was dragging it around on the page. So both the source and the target have events that continue to fire allowing you to keep track of what's going on during the drag and drop operation. As we look down the list, you'll notice here that the dragleave event fired, and that's because I took the image, brought it over on top of the target, didn't drop it, and then brought it out again. So that's how dragleave fires. And then dragenter and dragover just continue to fire a lot. And then, finally, at the very end, you'll notice that the drop event fired on the target, and then dragend fired on the source. So the source will get the beginning and the last event that fires in the chain during a drag and drop operation. Now I'll show you the code for this demo, but I'm going to go through it fairly quickly because it's basically built on the last demo that we did, and I'm just logging out labels to the console for each one of the events as they fire.
Events: JavaScript
So for this demo once again looking at the bird's eye view of everything that's happening, I have targets and sources, and I'm setting up event listeners for each one of the events that are possible when doing drag and drop. So drop, dragenter, dragover, dragleave all for the targets, and then dragstart, drag, and dragend for the sources. So for dragStart, I'm doing the exact same thing I did in the last demo, basically the biggest thing here is getting the Id, setting it into the dataTransfer object, and setting aside the sourceContainerId. Cancel is exactly the same as you've seen in each one of the other demoes. And for dragend, I'm simply logging out to the console that it is fired. That's the same thing for drag. Dropped again has the same implementation that you've seen in the past. I'm getting the data out of the dataTransfer object using the getData function, taking that Id, and appending the element to the target, that's the drop target, by using document.querySelector and passing in the Id. dragEnter cancels and then logs out to the console. That dragEnter is fired. dragOver also cancels and then logs out to the console. And dragLeave just simply logs out to the console. But the source element has left the drop target. So the main purpose of this demo is to give you an opportunity to see the different events as they fire and really get a feel for the fact that there are those events that continually do fire on the source and the target so that you can keep track of what's going on during the drag and drop process.
Effects: Demo and Markup
When it comes to drag and drop, security and control are one of the most important things that you want to keep in mind because you're opening up your web page to different types of input and different types of interaction. So one part of the API is the effectAllowed. So let me just show you here for a moment. I have two elements here on the page, one which is a drag source and the other which is a drop target. Now down here in this bottom label, it'll show you the effect reported in dragEnd because depending on how you have the settings configured, you'll be able to allow certain types of drag and drop operations to happen based off of the configuration. So notice down here, I have the source set to copy and the target also set to copy. So when I drag this element, as I bring it over the drop target, you'll notice that the mouse icon changes into a copy type of icon, and it shows that it allows me to be able to do a drop. So if I let go, the drop count is incremented by 1, and you can see down in the label, the effect reported in dragEnd is copy. Now if I make these so that they don't match, so I'm going to set the source to move and the target to copy, we'll leave that as copy, and I try to drag this over here, you'll see that there's a blocking icon for the mouse cursor. And when I try to drop it, I let go, you'll notice that the count does not increment because that drag and drop operation was not allowed because the effects that I have enforced on the source and on the target don't match. So if I move this over to move and drag and drop, now the count increments, and you can see in dragEnd the effect that's been reported is move. Now you have a little bfit of flexibility here. So let's say that I want to be able to allow a link and also a move, I can switch the source over to link and move. Now the target is set to move. So when I do that, that works. But if I have it over as copy and link, and I have the target set as move, obviously that doesn't work. So by enforcing these effects, you get greater control over what types of interactions you will allow for different aspects of your page. Now as we take a look at the markup for this demo, really what's important here are just a few elements. So I have an element right here that shows you the count of the drag and drop operations. There's an element that is titled msg that shows you the effect at the end of the drag and drop operation. And then I have a number of input elements that carry the values for each one of the effects. So this just maps to each effect. So I have one here for copy, move, link, none, copyLink, linkMove, and all for the source element. And for the drop element, there're radio buttons for copy, move, link, and none. There're no specialized styles for this. So now we can go into the code editor and take a look at the JavaScript.
Effects: JavaScript
Now just as I've done with my other drag and drop demoes, I'm starting off here with an overview so you can see everything kind of all at once. Now I have a source and I have a target. And so let's start by taking a look at the events that are associated with the source. So the first one is dragStart. Here, what I want to start off by doing is getting access to the element that's clicked. So the radio button that's chosen. So I can do that by going into document.querySelector, looking for the input with the name allowed, and finding the element that's checked. So by running this selector, I have the checked element or the selected radio button. And from there, I can go into the value and pull out what's selected there and set that equal to effectAllowed. Now some older browsers, particularly older versions of Firefox, have a requirement that you have to set something into the dataTransfer object. So here you'll notice that I'm calling setData, and I'm passing in an empty string. So this is just to help with compatibility with some of those older browsers. So that's dragStart. So now let's take a look at dragEnd. Now once the drag and drop operation is complete, dragEnd will fire. And so I can take a look at the dataTransfer object, the dropEffect that's been set there, and set that equal to the innerText of the span that I have to report up what effect has been chosen. So now let's take a look at the events associated with the source. Now, of course, dragEnter is just immediately cancelled, and the implementation for that is exactly the same as what you've seen in all of the other demoes, so that's cancelled. And we'll use that in the different event handlers for the source as well. So, for instance, for dragOver, I'm immediately cancelling the default behavior allowing the drag and drop operation to execute. And here I'm looking for the radio button that's been selected associated with the source. So here you can see I'm looking for the input with a name of effect. I'm looking for the checked item there. Once I have that element, I can take its value and set that equal to dropEffect. So really this is the key here--e.dataTransfer.dropEffect, and if you look up here to dragStart, you'll see that I have e.dataTransfer.effectAllowed. Now normally you'll set these explicitly by setting the string of whatever effect you want to have set. This demo is built to show you how you can mix and match different effects and what the outcomes are from there. But normally when you're building a drag and drop interaction, you'll set the value for effectAllowed and dropEffect explicitly. So going back down, we're setting the dropEffect and then updating the UI here because what we want to be able to do is take the classList and add the over class. So as you drag something over this target, we want to add a class that updates the background color to show that you can drop something here on this element. So next let's take a look at dragLeave. Here if you drag something over the target and then take it off, really all we need to do here is just take off that over class. So it removes the background color from the element showing that you're not going to drop anything on the target. And so, finally, for dropped, we'll cancel the default behavior and then increment the count. So we'll do that by looking for the element that has the Id of count. I can grab the innerText, and now I have the value of that count. I can increment it and then set it back equal to the innerText. And, of course, if you've dropped something on the target, then we can remove that over class because we want to take the background color off the element showing that the drag and drop operation is complete. You've had a chance to see the different effects associated with drag and drop operations. Now let's take a look at different dataTransfer types that you have available to you.
Types: Demo and Markup
Now the best way to understand dataTransfer types is to see them in action. So I'll take this image here and drop it into the drop target. And you'll notice what's being reported back. There's a couple of different types. We've got the text/plain, text/uri-list, and text/html. So text/plain just returns the content. So here this happens to be the image source. You can see the home.jpg. The uri-list essentially is the same thing here, but it's any URIs that are associated with the data that's dropped. So in this case, it's the source for the image. And the it also has the HTML. So here it's rendered within the drop target. But you notice that the CSS classes applied to this image end up showing up here on the drop target as well. That's the image. Let's try something else. Let's take this link and drop it into the drop target. So here the plain text is the href value for that link. The uri-list--there's only one right now, but if there were more than one associated with the contents of the draggable item, it would show up in this list. And then, of course, the HTML as it's rendered here is just CodedHomes. Let's try one more thing. Let's just try some arbitrary text. So I'll select this and drop it down in here. So here we've got the plain text, and it's got that text selection that I've created. And as it renders out the HTML, you'll notice that the styles that are applied to the selected text end up coming through and being rendered into the drop target. So by having all this information available to you as elements are being dropped into the targets, you can use the source HTML, you can use the URIs that are passed in, and it gives you a lot of information about what is being dropped into the targets. Now let me show you the JavaScript that you can use in order to interrogate this information and use it in your applications.
Types: JavaScript
The real meat of this demo is found in the dropped handler, but I'll take you through the other functions just real quick, although they'll be really familiar to you. So, of course, cancel is exactly the same as you've seen in the other demoes. dragLeave will remove the over class that is added to the element when something is dragged over it. So here you see that with dragOver cancelling the default behavior and then adding the over class as we're over the target. The dropped handler is where we'll be able to look at the dataTransfer types and really find out a lot of information. So we can get to the types by looking at the arguments that're passed in to the handler here, so e.dataTransfer.types. And I'm setting that aside into the types variable. So if the length is greater than 0, then I'll take a look at the item in the 0 index position and see if that's set equal to Text. Now, remember, this is the IE implementation. And so if I have that, then I can call getData, and that just returns Text. There's no different types of data types when you're working in Internet Explorer. We'll just grab what's there set into the dataTransfer object. However, if we're working with a more modern browser, then we can take a look at each one of the types and iterate over each one. So for each one of the types, we can go to the dataTransfer object and call getData based off the type that we're passing in. So, remember, that's plain text, HTML, and uri-list. So once I have that type, I can call getData and get the content of the type. And here I'm just adding it into the innerHTML of a paragraph. But in your applications, you can find use for the HTML, the plain text content, and the uri-list as needed. And the last little bit that's a part of this demo is just to clear my drop target, so here I'm calling preventDefault, and then setting the target's innerHTML to blank.
File System: Demo and Markup
This demo shows you how you can drag files from the file system into the browser and what kind of information you have available during that operation. So let me take these three selected files and drop them in over here into the drop target. And you'll notice for each one I have information on the type of file, its name, its size, a modified date even all the way down to the time zone. Now once again, this is very much like the last demo that you saw, it's just a different source coming in to the drop target. Well, let's take a look at the code.
File System: JavaScript
What's interesting about this implementation is that since we're dragging files in from the file system, there's no drag source to find here. So all I have is my target, and I have a little bit of code that clears out the target. But here there's just no source. So I'm starting out by handling dragenter, dragover, dragleave, and drop on the target. So dragEnter cancels the default implementation. dragOver sets the dataTransfer effect to copy so that when you're dragging the files over the drop target, you get a copy icon, and then updates the CSS class so it has the over class changing the background of the drop target. dragLeave simply removes the CSS class. So in case we decide not do that drop, the background color is updated. And, of course, dropped is where all of the implementation actually happens. So I'm cancelling and then getting reference to the dataTransfer types. So for each one of them here in this case, it's the type of Files. I'm looking for files that are coming in from the file system. Now if the dataTransfer type of Files exists, then there'll be a collection of files available off of the dataTransfer object. I can iterate through each one of those. And for each one of the files, I can report out the type, the name, the size, and the last modified date. And then to finally clean things up, I can remove the over class from the target. But for your implementation, you'd probably take this information and maybe upload some files, fill out a list, or whatever your application calls for. Well this wraps up the drag and drop module. Let's finish up with just a quick summary.
Summary
In this module, you've learned all about the drag and drop capabilities found native in the browser through HTML5. You've learned about the events and the event pipeline required in order to handle drag and drop operations, how to build sources and targets so that you can control which parts of your page are draggable and droppable. You saw how you can handle different dataTransfer types and set effects on different elements of the page and how to work with the file system by dragging files directly from your computer onto the browser. Well thanks again for spending time with me on this course. Again, this is Craig Shoemaker. I hope that you've learned much. Now, please don't stop here. There's so much more available on Pluralsight for you to learn about HTML5. A really good next step is my HTML5 Advanced Topics course, as well as my HTML5 Line of Business Apps course, along with all the other great course content here on Pluralsight. Well thanks again, and I hope to talk to you again soon.
Course author
Craig Shoemaker
Craig Shoemaker is a developer, instructor, writer, podcaster, and technical evangelist of all things awesome.
Course info
LevelBeginner
Rating
(602)
My rating
Duration3h 47m
Released3 Mar 2017
Share course