Assets

Improvements?

Let us know by posting here.

Assets

Assets centralizes shared assets like jQuery, Bootstrap, and various JavaScript and CSS libraries. This registry, extendable by packages and custom code, allows each asset to specify its position (header or footer), supports minification, and enables combining assets to reduce HTTP requests. Developers can assign handles to assets, supporting local or remote access, independent of file names. Themes and packages can prevent automatic asset inclusion. The system also accommodates block custom template auto-loaded assets (view.js, view.css).

Assets refer to CSS and JavaScript files, essential for functionality. For instance, Redactor's functionality needs these files:

  • concrete/js/redactor.js
  • concrete/css/redactor.css
  • concrete/js/file-manager.js
  • concrete/css/file-manager.js
  • concrete/js/sitemap.js
  • concrete/css/sitemap.css

Previously, we'd use $view->addHeaderItem() and $view->addFooterItem(). These are still there but not ideal for dynamic asset requirements.

Asset Framework

The Asset Framework in the \Concrete\Core\Asset namespace allows registering assets, handling minification, versioning, and paths. Grouping assets simplifies their inclusion. To use Redactor's assets:

$this->requireAsset('redactor');

Theme Assets

Themes can include assets. Our bootstrap3 theme comes with bootstrap CSS and JS. To avoid conflicts and duplicate assets, we add to the PageTheme class:

public function registerAssets()
{
    $this->providesAsset('javascript', 'bootstrap/*');
    $this->providesAsset('css', 'bootstrap/*');
    $this->providesAsset('css', 'blocks/form');
    $this->providesAsset('css', 'core/frontend/*');
    $this->requireAsset('javascript', 'jquery');
}

Registering an Asset in Concrete CMS

To use an asset in Concrete CMS, it must be registered, letting the system know how to include it. For instance, registering jQuery (already included in Concrete) involves a simple PHP block:

$al = \Concrete\Core\Asset\AssetList::getInstance();
$al->register('javascript', 'jquery', 'js/jquery.js');
  • Obtain the Asset List class instance using getInstance().
  • Use register() with arguments: asset type ('javascript' or 'css'), handle ('jquery'), path/URL, options array (optional), and \Concrete\Core\Package\Package object or package handle (optional).

Asset Types in Concrete

Supported asset types:

  • css: CSS style sheets.
  • css-inline: Inline style elements.
  • css-localized: TBD
  • javascript: JavaScript files.
  • javascript-inline: Inline JavaScript.
  • javascript-conditional: TBD
  • javascript-localized: TBD

Path Specification

Paths in register() are relative to application/, packages/package_handle/, or concrete/ directories.

Handle Uniqueness

Handles must be unique across asset types, allowing one CSS and one JavaScript file per handle.

Usage Contexts

  • Register assets in application/bootstrap/app.php, package's on_start(), or a block type's on_start() method.
  • For blocks, add registration in the block's on_start() method.
  • For packages, include asset registration in the package controller's on_start() method.

register() Options

Options include position (\Concrete\Core\Asset\Asset::ASSET_POSITION_HEADER or FOOTER), local (default true), version, combine, and minify. Note: combine and minify were removed in Concrete CMS v9 but remain for backward compatibility.

Example with Options

$al->register(
    'javascript', 'mediaelement', 'blocks/audio/mediaelement/mediaelement-and-player.min.js',
    array('version' => '2.16.3', 'minify' => false, 'combine' => true)
);
$al->register(
    'css', 'mediaelement', 'blocks/audio/mediaelement/mediaelementplayer.min.css',
    array('version' => '2.16.3', 'minify' => false, 'combine' => true)
);

Grouping Assets

Asset Groups in Concrete CMS allow bundling related assets for simultaneous inclusion. For instance, grouping Mediaelement.js JavaScript and CSS with jQuery:

$al = \Concrete\Core\Asset\AssetList::getInstance();
$al->registerGroup('mediaelement', array(
    array('css', 'mediaelement'),
    array('javascript', 'jquery'),
    array('javascript', 'mediaelement')
));
  • Use registerGroup() with a unique group handle and an array of asset arrays.
  • Each asset array includes the asset type and handle as registered.

Registered asset groups can then be easily included in pages as needed.

Requiring an Asset

In Concrete CMS, requiring assets or asset groups for pages or blocks is straightforward.

Requiring an Asset Group in Page Controllers

In page type or single page controllers:

public function view() {
    $this->requireAsset('mediaelement');
}

Requiring a Single Asset in Page Controllers

In page type or single page controllers:

public function view() {
    $this->requireAsset('javascript', 'jquery');
}

Requiring an Asset Group in Block "Add" Interface

In block controllers:

public function add() {
    $this->requireAsset('core/filemanager');
}

Requiring an Asset Group for Block Viewing

In block controllers:

public function registerViewAssets($outputContent = '') {
    $this->requireAsset('mediaelement');
}

Requiring or Providing Assets in Themes

Refer to theme documentation for handling core JavaScript/CSS: - Requiring Core JavaScript/CSS in a Theme - Overriding/Providing Core JavaScript/CSS in a Theme

Streamlining Theme Customization with CSS Classes

We've enhanced our theme with a grid, block classes, and assets. Next, we'll customize blocks, areas, and the Rich Text Editor with CSS classes.

Simple Customization

Concrete CMS's custom templates offer alternate block views, but sometimes a custom class suffices. In version 9, you can define these classes in the PageTheme file for a user-friendly selection.

Area-Specific Classes

To add a class to an area:

public function getThemeAreaClasses()
{
    return array(
        'Welcome' => array('templatemo-team')
    );
}

This makes "templatemo-team" available for any "Welcome" area in the Custom Design toolbar.

Block-Specific Classes

To assign classes to blocks:

public function getThemeBlockClasses()
{
    return array(
        'image' => array(
            'img-thumbnail'
        ),
        '*' => array(
            'highlighted'
        )
    );
}

"img-thumbnail" becomes available for Image blocks, and "highlighted" for all blocks.

Editor Classes

Adding editor-specific classes:

public function getThemeEditorClasses()
{
    return array(
        array('title' => t('Orange Button'), 'menuClass' => '', 'spanClass' => 'btn btn-orange'),
        array('title' => t('Green Button'), 'menuClass' => '', 'spanClass' => 'btn btn-green')
    );
}

These classes will appear in the rich text editor, allowing for easy CSS customization without custom templates.

Requiring Core JavaScript or CSS in a Theme

Including core JavaScript and CSS directly in theme templates isn't the best approach. Directly embedding them, like this:

<script type="text/javascript" src="<?=ASSETS_URL_JAVASCRIPT?>/js/jquery.js"></script>
<link rel="stylesheet" media="screen" type="text/css" href="<?=ASSETS_URL_CSS?>/font-awesome.css" />

can cause issues, such as duplications or JavaScript conflicts.

A better method is using Concrete's Assets system, which ensures scripts and stylesheets are never included twice and supports on-the-fly minifying and combining for better performance.

To include core assets like jQuery and Font Awesome in your theme, utilize the requireAsset method in the PageTheme class. For example:

public function registerAssets()
{
    $this->requireAsset('css', 'font-awesome');
    $this->requireAsset('javascript', 'jquery');
}

This approach guarantees that your theme properly loads these assets without duplication, maintaining efficient performance and avoiding conflicts.

Simplifying Core Asset Overrides in Concrete CMS

Overriding Core JavaScript and CSS Libraries

To override core JavaScript and CSS in Concrete CMS:

Via application Directory

  1. Find the file (e.g., concrete/js/jquery.js).
  2. Turn off Overrides Caching in Dashboard > Optimization settings.
  3. Place your new file (e.g., application/js/jquery.js).

Via Asset System

For package-based overrides:

public function on_start()
{
    $al = \AssetList::getInstance();
    $al->register('javascript', 'jquery', '//ajax.googleapis.com/ajax/libs/jquery/2.0/jquery.min.js', array('local' => false, 'version' => '2.0'));
}

Overriding Core Block JavaScript and CSS Libraries

To override block-level assets:

  1. Locate the file (e.g., core/blocks/date_navigation/view.css).
  2. Disable Overrides Caching in Dashboard settings.
  3. Place your new file in the corresponding application/blocks/ folder.

Registering Theme-Provided Assets

For Core Libraries

If your theme includes core libraries (like Bootstrap in Urbanic theme), inform Concrete not to load its own assets. Use Theme::providesAsset in PageTheme class:

public function registerAssets()
{
    $this->requireAsset('css', 'font-awesome');
    $this->requireAsset('javascript', 'jquery');
    $this->providesAsset('javascript', 'bootstrap/*');
    $this->providesAsset('css', 'bootstrap/*');
}

For Block Assets

To declare block assets provided by your theme:

public function registerAssets()
{
    // ... Existing code ...
    $this->providesAsset('css', 'blocks/form');
    $this->providesAsset('css', 'blocks/date_navigation');
    // ... Add more as needed ...
}

Handling Miscellaneous Core CSS

For Bootstrap-based themes:

  • Mark Bootstrap-dependent core CSS as provided.
  • Use wildcards for efficiency:
$this->providesAsset('css', 'core/frontend/*');

This setup ensures your theme correctly handles Concrete's core and block assets, avoiding duplication and potential conflicts.

Using CSS Selectors for Page Types and Templates in Concrete CMS

The Page::getPageWrapperClass() function, crucial for UI elements, outputs CSS classes that theme developers can utilize for specific styling. The mandatory ccm-page class is essential for panels, while other classes represent the page type and template. For instance:

<div class="ccm-page page-type-blog page-template-full">
...
</div>

Here, page-type-blog and page-template-full are dynamic classes based on the page type and template.

Different pages yield distinct classes. For example:

<div class="ccm-page page-type-portfolio-project page-template-left-sidebar">
</div>

In Concrete CMS, underscores in handles (like portfolio_project) are converted to dashes in class names.

This feature is useful for advanced theming. For instance, the following CSS targets the sidebar on the blog entry page:

div.ccm-page.page-type-blog-entry div.col-sidebar {
    padding-top: 40px;
}

Asset Groups

Wherever possible, you should use requireAsset() with a single asset group, rather than individual assets. There are certain exceptions (like requiring the jQuery JavaScript library) but in general most Concrete CMS functionality has already been separated into semantic groups, which will include all the CSS and JavaScript necessary.

  • ace
  • core/account (Feature: account)
  • core/app
  • core/app/editable-fields
  • core/colorpicker (Feature: cms)
  • core/conversation (Feature: conversations)
  • core/file-manager (Feature: cms)
  • core/gathering
  • core/groups (Feature: cms)
  • core/imageeditor
  • core/legacy
  • core/lightbox (Feature: imagery)
  • core/rating (Feature: cms)
  • core/sitemap (Feature: cms)
  • core/style-customizer (Feature: cms)
  • core/topics (Feature: taxonomy)
  • core/translator
  • dashboard (Feature: cms)
  • dropzone
  • dynatree
  • font-awesome
  • jquery/fileupload (Feature: cms)
  • jquery/ui (Feature: cms)
  • jquery/visualize
  • redactor
  • responsive-slides (Feature: imagery)
  • select2
  • swfobject

Individual Assets

Individual JavaScript Files

  • ace
  • awesome-rating (Feature: cms)
  • backbone
  • backstretch
  • bootstrap-editable
  • bootstrap/alert
  • bootstrap/button
  • bootstrap/dropdown
  • bootstrap/popover
  • bootstrap/tooltip
  • bootstrap/transition
  • core/account (Feature: account)
  • core/app
  • core/conversation (Feature: conversations)
  • core/events (Feature: cms)
  • core/file-manager (Feature: cms)
  • core/frontend/parallax-image
  • core/gathering
  • core/groups (Feature: cms)
  • core/imageeditor
  • core/imageeditor_locale
  • core/legacy
  • core/lightbox (Feature: imagery)
  • core/lightbox/launcher
  • core/localization
  • core/sitemap (Feature: cms)
  • core/style-customizer (Feature: cms)
  • core/topics (Feature: taxonomy)
  • core/translator
  • dashboard (Feature: cms)
  • dropzone
  • dynatree
  • dynatree_locale
  • html5-shiv
  • jquery
  • jquery/fileupload
  • jquery/form
  • jquery/textcounter
  • jquery/touch-punch
  • jquery/tristate
  • jquery/ui (Feature: cms)
  • jquery/visualize
  • kinetic
  • picturefill
  • redactor
  • redactor_locale
  • respond
  • responsive-slides (Feature: imagery)
  • select2
  • select2_locale
  • spectrum
  • swfobject
  • underscore

Individual CSS Files

  • awesome-rating (Feature: cms)
  • bootstrap
  • bootstrap/alert
  • bootstrap/button
  • bootstrap/dropdown
  • bootstrap/popover
  • bootstrap/tooltip
  • bootstrap/transition
  • core/account (Feature: account)
  • core/app
  • core/app/editable-fields
  • core/conversation (Feature: conversations)
  • core/file-manager (Feature: cms)
  • core/frontend/captcha
  • core/frontend/errors
  • core/frontend/pagination (Feature: bedrock)
  • core/gathering/base
  • core/gathering/display
  • core/imageeditor
  • core/legacy
  • core/lightbox (Feature: imagery)
  • core/sitemap (Feature: cms)
  • core/style-customizer (Feature: cms)
  • core/topics (Feature: taxonomy)
  • core/translator
  • dropzone
  • dynatree
  • font-awesome
  • jquery/ui (Feature: cms)
  • jquery/visualize
  • redactor
  • responsive-slides (Feature: imagery)
  • select2
  • spectrum

Asset Links