Change Image Slider to Use New Third Party Library

Since Features let us completely control the CSS and JavaScript used to satisfy certain core functionality, we can completely change the nature of how core block types work without having to hack around a lot of tiny JavaScript files. To see this in action, let's swap out the Image Slider block to use a completely different underlying slider library, Owl Carousel. We'll even use some of its advanced animation configuration for a pleasing appearance.

This is going to require a couple different things:

  1. We're going to to install Owl Carousel and its animation dependency, animate.css. We'll do this using npm as we've done elsewhere.
  2. We'll change how we're importing our CSS and JavaScript – we'll have to remove some third party libraries that are a part of the standard Imagery feature suite, since we're replacing them as part of this objective.
  3. We'll import the Owl Carousel CSS and JavaScript into main.scss and main.js.
  4. Finally, we'll have to fork the Image Slider block view template, in order to make it conform to Owl Carousel.
Note: This last step isn't ideal – in a perfect world we'd be able to accomplish this without creating a custom block view template at all. However, we need to provide specific markup to Owl Carousel in order for it to render properly. Additionally, our Image Slider view template uses the default JavaScript Library, "Responsive Slides", and calls it directly. This isn't ideal either, but it's what we're working with. Thankfully, since we can include a block view template directly in our Flintstone theme, we don't have to override this at the core level, nor do we have to teach people that they need to use a Custom template in order to make this work.

Let's get started!

Install Owl Carousel and animate.css

Installing these two libraries via npm should look pretty familiar at this point. Run these commands from within your theme working directory:

npm i owl.carousel
npm i animate.css

Remove Full Includes Imagery JavaScript and CSS; Strip out Image Slider Dependencies

Now, we need to remove the fallback Image Slider JavaScript and SCSS from our main.scss and main.js files. Let's do JavaScript first. The Imagery feature fallback JavaScript included in our main.js looks like this:

import '@concretecms/bedrock/assets/imagery/js/frontend';

Let's open that file. It looks like this:

import 'magnific-popup'
import './frontend/lightbox'
import './frontend/responsive-slides'
import './frontend/gallery'

window.$ = window.jQuery = jQuery

I don't think the final line is relevant, so let's ignore it. It looks like this file includes Magnific Popup, our core lightbox requirements, the Responsive Slides library, and JavaScript that makes our Gallery work. Let's copy out all of these, except Responsive Slides, because we're going to be replacing that with Owl Carousel.

Replacing the original line with the specific imports, and our main.js file now looks like:

import '@concretecms/bedrock/assets/bedrock/js/frontend';

import 'magnific-popup'
import '@concretecms/bedrock/assets/imagery/js/frontend/lightbox'
import '@concretecms/bedrock/assets/imagery/js/frontend/gallery'

// Add Simple Parallax to Hero Image
import simpleParallax from 'simple-parallax-js';

// Add parallax support to all Hero Image blocks
var images = document.querySelectorAll('.ccm-block-hero-image-image');
new simpleParallax(images, {scale: 1.5});

Next, let's do the same for assets/scss/features/_imagery.scss. It looks like this:

// Import base stylesheets
@import "~@concretecms/bedrock/assets/imagery/scss/frontend/frontend";

@import "imagery/hero-image";

So let's open up scss/frontend/frontend.scss and see what it looks like:

    // Lightbox
@import 'lightbox/lightbox';

// Gallery
@import 'gallery/gallery';

// Image Slider Block
@import 'responsive-slides';
@import 'image-slider/image-slider';

// Hero Image
@import 'hero-image';

This looks pretty easy to understand. Since we want to keep gallery, lightbox and Hero Image support, let's copy those lines out, and replace the original import with just them. Now our _imagery.scss file looks like this:

// Bedrock Lightbox
@import '~@concretecms/bedrock/assets/imagery/scss/frontend/lightbox/lightbox';

// Bedrock Gallery
@import '~@concretecms/bedrock/assets/imagery/scss/frontend/gallery/gallery';

// Bedrock Hero Image
@import '~@concretecms/bedrock/assets/imagery/scss/frontend/hero-image';

// Theme customizations
@import "imagery/hero-image";

Import Owl Carousel into CSS and JavaScript Files

Now, let's import Owl Carousel into our stylesheets and JavaScript file. Following the directions on their website for a basic implementation, here's how we import the CSS:

// Owl Carousel
@import "~animate.css/animate";
@import "~owl.carousel/dist/assets/owl.carousel";
@import "~owl.carousel/dist/assets/owl.theme.default";

Remember to remove the .css extension in order to force SASS to place the entire file contents inline into the built CSS file.

The whole file now looks like this:

// Bedrock Lightbox
@import '~@concretecms/bedrock/assets/imagery/scss/frontend/lightbox/lightbox';

// Bedrock Gallery
@import '~@concretecms/bedrock/assets/imagery/scss/frontend/gallery/gallery';

// Bedrock Hero Image
@import '~@concretecms/bedrock/assets/imagery/scss/frontend/hero-image';

// Owl Carousel
@import "~animate.css/animate";
@import "~owl.carousel/dist/assets/owl.carousel";
@import "~owl.carousel/dist/assets/owl.theme.default";

// Theme customizations
@import "imagery/hero-image";

Now, let's add the JavaScript to main.js. This is the JavaScript we will add (per the Owl Carousel documentation). We'll import the library:

import 'owl.carousel'

And we'll activate it on any tags with the class owl-carousel. We'll also add some nice animations just to prove that this type of rich custom display is possible within a Concrete theme built on Bedrock:

$(".owl-carousel").owlCarousel({
    autoHeight: true,
    animateOut: 'slideOutDown',
    animateIn: 'flipInX',
    items: 1,
    margin: 30,
    stagePadding: 30,
    smartSpeed: 450
});

The entire main.js file now looks like this:

import '@concretecms/bedrock/assets/bedrock/js/frontend';

import 'magnific-popup'
import '@concretecms/bedrock/assets/imagery/js/frontend/lightbox'
import '@concretecms/bedrock/assets/imagery/js/frontend/gallery'

// Add Owl Carousel
import 'owl.carousel'
$(".owl-carousel").owlCarousel({
    autoHeight: true,
    animateOut: 'slideOutDown',
    animateIn: 'flipInX',
    items: 1,
    margin: 30,
    stagePadding: 30,
    smartSpeed: 450
});

// Add Simple Parallax to Hero Image
import simpleParallax from 'simple-parallax-js';

// Add parallax support to all Hero Image blocks
var images = document.querySelectorAll('.ccm-block-hero-image-image');
new simpleParallax(images, {scale: 1.5});

Add a Custom View Template for the Image Slider

Finally, let's swap out the default view used for the Image Slider block for a custom view. We can do this in such a way that this only happens when using the Flintstone theme, which is smart, because all of this custom logic is after all wrapped up in our theme.

Create an empty file at application/themes/flintstone/blocks/image_slide/view.php, and copy the following content into it:

<?php
defined('C5_EXECUTE') or die("Access Denied.");
$c = Page::getCurrentPage();
if ($c && $c->isEditMode()) {
$loc = Localization::getInstance();
$loc->pushActiveContext(Localization::CONTEXT_UI); ?>
<div class="ccm-edit-mode-disabled-item"><?=t('Image Slider disabled in edit mode.'); ?></div>
<?php
$loc->popActiveContext();
} else {
?>

<div class="owl-carousel owl-theme">
    <?php
    foreach ($rows as $row) { ?>
        <div class="item">
            <?php
            $f = File::getByID($row['fID']); ?>
            <?php if (is_object($f)) { ?>
                <img class="img-responsive" src="<?=$f->getURL()?>">
            <?php } ?>
        </div>
        <?php
    } ?>

</div>
<?php
} ?>

How did I determine what to put in this file? I copied concrete/blocks/image_slider/view.php in order to get the base markup of the Image Slider block, and then I modified it for use with Owl Carousel, per their documentation. I also stripped out a lot of things that didn't work with Owl Carousel or were unnecessary for this demo.

The Result

So how does the whole thing look? It's definitely different than the standard Concrete Image Slider!

#

Conclusion

Hopefully this has been a useful dive into the new Concrete Features system. We hope that Features makes it easier to build nicely designed, custom themes without having to micromanage the assets that come in as part of working with Concrete block types.