Fullscreen Distraction-Free Learning

TLDR;

The whole code is available in a gist here: https://gist.github.com/actual-saurabh/a59beef775b61c33629aa0824061de9c

Requirements

Basic CSS and JS (jQuery) skills are needed to customise this recipe for some themes. Some basic understanding of WordPress APIs may be needed for additional customisation.

This has been tested successfully with many standard themes and should work well, as it is, for such themes.

The code here would work even if there’s no LifterLMS on your site, without any problems, to create a distraction free reading mode.

A note on Fullscreen API

Browsers don’t allow fullscreen without a user interaction. So, the fullscreen mode cannot persist between lessons. This means that a student would have to click a button on every screen to go into fullscreen mode. There is no way around it. See: https://developer.mozilla.org/en-US/docs/Web/API/Fullscreen_API

Goal

  • Add a fullscreen button to content.
  • Clicking this button should make the content fullscreen.
  • All headers, footers and sidebars would be hidden.
  • If a course syllabus is present on the page, add a slidein/ slideout syllabus.

Here’s a preview of what to expect from this recipe

LifterLMS Focus Mode Preview

Instructions

Planning

  • Using js, we are going to add an element with class llms-focus-control. Clicking it will start/stop the focus mode.
  • When the screen is in focus mode, we’ll add a class llms-is-focused to the body tag. This will help in styling everything on the page specifically for focus mode.
  • In focus mode, we’ll make the content area (.content-area in standard themes) fullscreen.
  • In focus mode, if there’s a course syllabus widget (.widget_course_syllabus) on the page, we’ll add a wrapper (.llms-focus-syllabus-wrapper) to the content area to which we’ll move the course syllabus from the sidebar.
  • To .llms-focus-syllabus-wrapper, we’ll also add a button (.llms-focus-syllabus-toggle)that slides the syllabus in and out of view.
  • When exiting focus mode, we’ll move the course syllabus back to where it was.

Add focus mode button

We do this by creating a new empty div, adding a class and optionally, a title:

// create a new empty div for the focus mode control button.
var $focusControl = $( '<div />' );

// add a class for styling.
$focusControl.addClass( 'llms-focus-control' );

// add a title (that'll show up in a tooltip on hover).
$focusControl.attr( 'title', 'Focus Mode' );

Then, we append this new button to the content area:

// select the main content area.
var $contentArea = $( '.content-area' );

// we're ready for the show, add focus mode button to content area.
$contentArea.append( $focusControl ); 

Next, we style this button to look like a plain square and fix it at the bottom right corner of the content area. You can obviously style this differently or add hover effects, etc.

.llms-focus-control{
	width: 40px;
	height: 40px;
	border: 4px solid #232323;
	position: fixed;
	bottom: 4px;
	right: 4px;
	cursor: pointer;
}

Finally, we add a toggle to this button to call functions to start and stop focus mode. We haven’t written the functions yet. We’ll do that in the next step.

// add the ability to start/stop focus mode to the button.
$focusControl.toggle(
    function(){
        llmsFocusStart();
    },
    function(){
        llmsFocusStop();
    }
);

Add full screen functionality

We start with defining the llmsFocusStart() function. In this function, as outlined in planning, we want to:

  1. Add llms-is-focused class to the body.
  2. Make the content area occupy the full screen.
  3. Move the course syllabus appropriately.

For 2 and 3, we’ll create new functions called llmsOpenFullScreen() and llmsSyllabusFullScreen(), respectively.

/**
 * Start Focus mode
 */
function llmsFocusStart(){
    $( 'body' ).addClass( 'llms-is-focused' );
    llmsOpenFullScreen();
    llmsSyllabusFullScreen();
}

We style the content area to take up the whole screen. This way the focus mode works with or without the Fullscreen API. We do that because the page may contain videos. Videos also use the Fullscreen API and could interfere with our functions.

body.llms-is-focused .content-area {
	background: #fff none;
	padding:0;
	overflow-y:scroll;
	position:fixed;
	width:100%;
	height:100%;
	top:0;
	left:0;
	bottom:0;
	right: 0;
	z-index: 9999999999; /* really high z-index to place this on top, adjust for popovers, alerts, etc */
	margin:0;
}

Using .llms-is-focused, we can style everything on the page in a similar manner.

Next, we define llmsOpenFullScreen() using the Fullscreen API:

/**
 * Opens fullscreen mode
 */
function llmsOpenFullScreen() {

    // Get the native dom object from jQuery object
    elem = $( '.site' )[0];

    // Standard, for most browsers
    if ( elem.requestFullscreen ) {
        elem.requestFullscreen();
    } else if ( elem.mozRequestFullScreen ) {
        // Firefox
        elem.mozRequestFullScreen();
    } else if ( elem.webkitRequestFullscreen ) {
        // Chrome, Safari and Opera
        elem.webkitRequestFullscreen();
    } else if ( elem.msRequestFullscreen ) {
        // IE/Edge
        elem.msRequestFullscreen();
    }
}

Note

Notice that instead of the content area, we make the .site fullscreen. This is to account for the video’s usage of the Fullscreen API.

As planned, we also need to create the elements for moving the syllabus:

// create a special container for the syllabus widget on fullscreen mode.
var $fullScreenSyllabusWrapper = $( '<div />' );

// add a class for styling.
$fullScreenSyllabusWrapper.addClass( 'llms-focus-syllabus-wrapper' );

// create a button that'll show/hide syllabus on fullscreen.
var $fullScreenSyllabusToggle = $( '<div/ >' );

// add a class for styling.
$fullScreenSyllabusToggle.addClass( 'llms-focus-syllabus-toggle' );

// append button to fullscreen syllabus wrapper.
$fullScreenSyllabusWrapper.append( $fullScreenSyllabusToggle );

Obviously, we also need to style them:

.llms-focus-syllabus-toggle{
	position: fixed;
	width: 40px;
	height: 40px;
	right: 0px;
	top: 0px;
	background: #fff none;
}

.llms-focus-syllabus-toggle:before{
	content: "\2630";
	font-size: 30px;
	text-align: center;
	line-height: 40px;
	width: 100%;
	display: block;
}

.llms-focus-syllabus-wrapper{
	position: fixed;
	top: 0px;
	right: -30%;
	width: 30%;
	height: 100%;
	overflow-y: scroll;
	background: #fff none;
	padding: 20px;
	cursor: pointer;
}

Now, we define the llmsSyllabusFullScreen() function that’ll move the syllabus appropriately:

Moving an element and bringing it back

We’re going to move the course syllabus from the sidebar when we enter focus mode and put it back when we exit focus mode. The best way to make that happen is to mark where the syllabus was to start with using a placeholder. Now, when we move the syllabus around, we can use the placeholder as a marker to accurately place it back when we need.

// select the syllabus widget.
var $syllabus = $( '.widget-area .widget_course_syllabus' );

// create a hidden placeholder to be used as a marker for the syllabus widget's original position.
var $placeHolder = $( '<span style="display: none;" />' );

In the actual function, we return early if there’s no syllabus. Otherwise,

  • We insert our hidden placeholder right after the syllabus.
  • We append the container, toggle button and the syllabus.
  • Finally, add the toggling functionality to the toggle button.
/**
 * Adjusts syllabus widget for fullscreen
 */
function llmsSyllabusFullScreen(){

    // Don't do anything if there's no syllabus widget
    if( $syllabus.length < 1 ){
        return;
    }

    // Insert the hidden placeHolder just after the syllabus widget.
    $placeHolder.insertAfter( $syllabus );

    // Add a special container for syllabus, only for fullscreen mode.
    $contentArea.append( $fullScreenSyllabusWrapper );

    // Move the syllabus widget from sidebar to this newly added container.
    $fullScreenSyllabusWrapper.append( $syllabus );

    // Add the ability to show/hide syllabus to the toggle button.
    $fullScreenSyllabusToggle.toggle(
        function(e){
            e.preventDefault();

            // animate the syllabus to slide in from the left
            $fullScreenSyllabusWrapper.animate({ right: 0 }, 500 );

            // move the button itself to the left to accomodate the syllabus.
            $(this).animate( { right: $fullScreenSyllabusWrapper.css( 'width' ) }, 500 );

            /*
             * Increase 500 for faster animation, decrease for slower.
             */

        },
        function(e){
            e.preventDefault();

            // animate the syllabus out of the screen towards the right
            $fullScreenSyllabusWrapper.animate( { right: '-' + $fullScreenSyllabusWrapper.css( 'width' ) }, 500 );

            // back to the right edge for the button
            $(this).animate({ right: 0 }, 500);
        }
    );
}

Add exit functionality

Just as we defined the llmsFocusStart() function, we define a llmsFocusStop()function which’ll remove the focus class, exit fullscreen and place the syllabus back:

/**
 * Stop Focus mode
 */
function llmsFocusStop(){
    llmsSyllabusExitFullScreen();
    llmsCloseFullScreen();
    $( 'body' ).removeClass( 'llms-is-focused' );
}

Placing the syllabus widget back into the sidebar is easy because of our placeholder. Once the syllabus is back, we also remove the wrapper (with the toggle button).

/**
 * Adjusts syllabus widget on fullscreen exit.
 */
function llmsSyllabusExitFullScreen(){

    // Don't do anything if there's no syllabus widget.
    if( $syllabus.length < 1 ){
        return;
    }

    // move syllabus widget just before the placeholder.
    $syllabus.insertBefore( $placeHolder );

    // now that syllabus is back, we don't need the placeholder.
    $placeHolder.remove();

    // we also don't need the special container.
    $fullScreenSyllabusWrapper.remove();
}

Exiting fullscreen is simpler than entering it:

/**
 * Closes fullscreen mode
 */
function llmsCloseFullScreen() {

    // Standard, for most browsers
    if ( document.exitFullscreen ) {
        document.exitFullscreen();
    } else if ( document.mozCancelFullScreen ) {
        // Firefox
        document.mozCancelFullScreen();
    } else if ( document.webkitExitFullscreen ) {
        // Chrome, Safari and Opera
        document.webkitExitFullscreen();
    } else if ( document.msExitFullscreen ) {
        // IE/Edge
        document.msExitFullscreen();
    }
}

Note

While, requestFullScreen is called on an element, exitFullScreen is called on the document as per the Fullscreen API

That’s it. All the javascript and css is ready. Next step is to implement the recipe.

Implementation

Wrap the finished javascript in a document ready event as per jQuery conventions. See https://gist.github.com/actual-saurabh/a59beef775b61c33629aa0824061de9c#file-llms-focus-mode-js for what that looks like.

Using Child Theme or Plugin

Now, you can create and bundle the files (say llms-focus-mode.js and llms-focus-mode.css into your child theme, LifterLMS customizations plugin or your own plugin. See: https://lifterlms.com/docs/how-do-i-add-custom-code-to-lifterlms-or-lifterlms-launchpad/. Then, you can enqueue them:

wp_enqueue_script( 'llms-focus-mode', 'url/to/llms-focus-mode.js', array('jquery') );
wp_enqueue_style( 'llms-focus-mode', 'url/to/llms-focus-mode.css' );

Using Dirty Snippets

Otherwise, you could use a snippets plugin: https://wordpress.org/plugins/code-snippets/. Also see: https://www.wpbeginner.com/plugins/how-to-easily-add-custom-code-in-wordpress-without-breaking-your-site/.

Create a new snippet to directly echo the css and js inline:

<?php

add_action( 'wp_footer', 'llms_focus_mode_js' );

function llms_focus_mode_js () {
	?>
	<script>
		// all the js here
	</script>
	<?php
}

add_action( 'wp_head', 'llms_focus_mode_css' );

function llms_focus_mode_css() {
	?>
	<style>
		// all the css here
	</style>
	<?php
}

Loading only on Lessons, Courses, etc

This recipe will load the focus mode on every page on your site. If you only want to display it on lessons, quizzes, etc, you can add a check for the post type (https://github.com/gocodebox/lifterlms/blob/master/includes/class.llms.post-types.php) before enqueuing or echoing the scripts and styles. Also see: https://developer.wordpress.org/reference/functions/is_singular/

<?php

add_action( 'wp_footer', 'llms_focus_mode_js' );

function llms_focus_mode_js () {
 	if( ! is_singular ( array( 'lesson', 'llms_quiz' ) ) ){
		return;
	}
	?>
	<script>
		// all the js here
	</script>
	<?php
}

add_action( 'wp_head', 'llms_focus_mode_css' );

function llms_focus_mode_css() {
	if( ! is_singular ( array( 'lesson', 'llms_quiz' ) ) ){
        	return;
	}
	?>
	<style>
		// all the css here
	</style>
	<?php
}

Mobile Display

It works beautifully on mobile screens as well. However, for best results, you would need to add a bit of css for narrow screens.

@media (max-width: 480px){
	.llms-focus-syllabus-wrapper{
		right: -70%;
		width: 70%;
	}
}

Conclusion

Hopefully this recipe turns out to be useful in your next theme or LifterLMS site. Let us know in the comments if you do use it to build something. Feel free to ask any questions too.

Want the functionality, but don’t know code?

Contact your developer or one of the experts here https://lifterlms.com/experts/ with a link to this recipe.

Are you a developer who needs help?

If you are or your client is a premium LifterLMS customer, you can get support from the development team. Otherwise, you could get help from the community on Slack.

1 thought on “Fullscreen Distraction-Free Learning”

  1. Pingback: Improving Course Navigation User Experience [Part 1]: Establishing UX Patterns - Make LifterLMS

Leave a Comment

Your email address will not be published. Required fields are marked *