JavaScript

The framework uses RequireJS to only load in the JavaScript appropriate for the page. When building new elements/modules that are to be enhanced using JavaScript the functionality should be included using RequireJS. This is achieved by setting the data-app attribute on the init.js script tag within the page, to the URL that the JavaScript files are located (not including a trailing slash).

<script id="js-init" src="[ CDN Folder Path ]/js/init.js" data-app="..."></script>

This url should be the full path to the folder location but should remain protocol agnostic for example:

<script id="js-init" src="[ CDN Folder Path ]/js/init.js" data-app="//:[ Site domain ]/library/js"></script>

To load the JavaScript for the element/module set the data-module attribute on the element/module to "app/[JavaScript block name]". The 'JavaScript block name' is the name given to the JavaScript file for your element/module without the '.js' file extension.

<div class="..." data-module="app/[JavaScript block name]">...</div>

Writing JavaScript blocks

Define the block, loading in any JavaScript files that the block is dependent on. Check our list of core JavaScript files so that these are not loaded multiple times from having the same file hosted in two locations.

define( [ 'jquery', 'utility' ], function( $, util ) {
	'use strict';

	var block = {
		init : function ( el ) {
			this.create( $( el ) );
		},

		create : function ( element ) {
			// Creation code
		}
	};

	return {
		initInstance: function ( el ) {
			block.init( el );
		}
	};
});

Note: The init function for the block will be called for every instance of the element/module that occurs within the page onload. Precautions should be taken to ensure that any code does not get applied multiple times to the same element/module. This could be achieved by simply checking for a particular class being present on the element/module eg. js-module that is only added by the JavaScript.

Running RequireJS again

If content is generated or loaded in by some JavaScript and contains element/modules that themselves get enhanced via JavaScript, eg. a modal window that loads in some show/hide sections from another page, RequireJS will need to be run again to pick up the newly added elements. This is achieved by triggering the moduleScan event on the documents body element for example:

$( 'body' ).trigger( 'moduleScan' );

Extending the RequireJS config

v.4.X.X

If you need to extend the requireJS config setup by Framework please use the following code.

<script>
	window.requireExtend = {
		paths : {
			//... custom paths
		},
		// ...
	};
</script>
<script async id="js-init" src="[ CDN Folder Path ]/js/init.js"></script>

It is recommended to place this config extension in a seperate file which must be loaded before the Frameworks 'init.js' script.

There are a couple of caveats:

  • You are not able to overwrite the 'baseUrl' or 'skipDataMain' config properties. These are required by Framework to work correctly.
  • If you are adding a config property that uses an object type, ie. 'paths', then when the Framework config and the extension config are merged, the Frameworks values will take priority. This means that if you tried to add a custom path for 'jquery', it would be overwritten by the Frameworks value.
  • If you are adding a config property that uses an array type, ie. 'deps', then the Frameworks config value will be concatinated with the extension config.
  • If you are adding a 'callback' property, then this is wrapped with the Frameworks callback function which will run first an then call your callback.

v.3.X.X and earlier

If you need to extend the requireJS config setup by Framework please use the following code.

Note: Be careful not the overwrite any existing config settings as this can/will break components.

<script>
	document.addEventListener( 'requireready', function onRequireReady() {
		// Your custom require config which will be merged with the frameworks config
		require.config({
			// ...
		});

		// Then you can use require as normal for more flexibility
		require( [ 'jquery' ], function ( $ ) {
			// ...
		});
	});
</script>

Working programmatically with RequireJS

Sometimes you may want more flexibility than using Framework blocks. And in this situation working directly with RequireJS is the recommended approach. To do this we have to wait for the RequireJS config to be loaded and run. This can be done as follows:

<script>
	document.addEventListener( 'requireready', function onRequireReady() {
		require( [ 'jquery', 'app/custom-module' ], function ( $, customModule ) {
			// ...
		});
	});
</script>

As RequireJS is loaded asyncronously, we need to wait for it's callback to fire which emits a 'requireready' event on 'document'.

Using jQuery validate and unobtrusive

From v.3.0.0, jQuery validate and unobtrusive are now available to load from the framework for use with your blocks of JavaScript. To load them add them to your define block like this:

define( [ 'jquery', 'jquery.validate' ], function( $ ) {
	...
});
define( [ 'jquery', 'jquery.validate.unobtrusive' ], function( $ ) {
	...
});

From v.4.0.0 jQuery validate and unobtrusive are now configured to display errors correctly with the default markup for form components.

For this to work there are certain elements that MUST be in the markup, and the markup MUST be correct as per the framework documentation.

Updating unobtrusive settings

If you need to update the unobtrusive defaults then do so like this - however, this is typically a hammer and nut solution, and a better approach would be to update the validator settings instead.

require( [ 'jquery', 'jquery.validate.unobtrusive' ], function ( $, unobtrusive ) {
	var $form = $('form');

	unobtrusive.options.errorClass = 'my-custom-error';

	unobtrusive
		// Remove validation
		.destroy( $form )
		// Reparse the document to apply new unobtrusive defaults
		.parse( document );
});

Updating validator settings

require( [ 'jquery', 'jquery.validate.unobtrusive' ], function ( $, unobtrusive ) {
	var $form = $( 'form' );
	var validator = $form.data( 'validator' );

	if ( validator ) {
		validator.settings.errorClass = 'my-custom-error';
	}
});

Validator error placement

There may be an occassion where error placement doesn't work as expected for a certain form field, to do work around this you may need to modify jquery.validate's settings.

Below shows how to change the error placement for a certain element in your form.

require( [ 'jquery', 'jquery.unobtrusive' ], function () {
	var $form = $( 'form' );
	var validator = $form.data( 'validator' );

	if ( validator ) {
		validator.settings.errorPlacement = function errorPlacement( error, $element ) {
			// Position the error message in a custom location for 'my-element'
			if ( $element.attr( 'id' ) === 'my-element' ) {
				$( '#my-element-error-container' ).append( error );
				// Otherwise use the default errorPlacement handler
			} else {
				$.validator.defaults.errorPlacement.apply( this, arguments );
			}
		};
	}
});

Loading JavaScript that not compatible with RequireJS

If when migrating to the Framework there are a number of pieces of JavaScript that are required for page functionality but it is not viable to rewrite into the new module format we suggest trying this solution.

  • Set the data-app attribute on the init.js script tag within the page as detailed above.
  • Add in each required script under the script tag in the following format:

    <script id="js-init" src="[ CDN Folder Path ]/js/init.js" data-app="/website/scripts"></script>
    <span data-module="app/jquery.validate.min" ></span>
  • If one of the files has a dependency on another the file is modified so that the original code is wrapped by and AMD loader function. For example ensuring jQuery is loaded before the JavaScript is run:

    (function ( factory ) {
    	if ( typeof define === 'function' && define.amd ) {
    		// AMD. Register as an anonymous module depending on jQuery.
    		define( 'app/faq-manager', [ 'jquery' ], factory );
    	} else {
    		// No AMD. Register plugin with global jQuery object.
    		factory( jQuery );
    	}
    }(function ( $ ) {
    	// The original JavaScript goes here
    }));

Considerations when writing blocks

Multi-language support

If there is content being added via the JavaScript that contains text, consider making it configurable so that if required the text can be changed to better suit the usage or language.

Accessibility

Wherever possible make use of ARIA attributes to help users with assistive technologies to better navigate the site/application.

Core JavaScript files

Modernizr

The framework uses Modernizr v3.6.0 (v3.3.1 prior to v4.0.0 of framwork) to aid in detecting browser capabilities. The build currently tests for:

  • borderimage
  • cssanimations
  • csscalc
  • cssgradients
  • csstransforms
  • csstransforms3d
  • csstransitions
  • flexbox
  • formvalidation
  • inputtypes
  • objectfit
  • smil
  • svg
  • touchevents

Files available to use with RequireJS

v.4.X.X

block Description Functions / Variables
jquery jQuery v3.3.1  
utility Core utility functions smallTag
mediumTag
largeTag
urlRegExp
getBreakpoint()
makeId( prefix )
processInPageLinks( selector, callback )
debounce( func, wait, immediate )
vendor/jquery/mousewheel jQuery Mousewheel - v3.1.13  
vendor/jquery/jquery-ui jQuery UI - v1.12.1 Includes: widget.js, position.js, data.js, disable-selection.js, focusable.js, form-reset-mixin.js, keycode.js, labels.js, scroll-parent.js, tabbable.js, unique-id.js, widgets/autocomplete.js, widgets/menu.js, widgets/mouse.js
vendor/jquery/mCustomScrollbar jQuery custom scrollbar - v3.1.5  
moment Moment - v2.22.1 Includes all locales
vendor/pikaday Pikaday - https://github.com/dbushell/Pikaday  
vendor/numeral Numeral.js - v2.0.6 - http://numeraljs.com  
vendor/highcharts/highcharts Highcharts - v6.1.0 - https://www.highcharts.com  
vendor/highcharts/highcharts/modules/... Highcharts modules - for v6.1.0 - https://www.highcharts.com
  • accessibility
  • annotations
  • boost
  • boost-canvas
  • broken-axis
  • bullet
  • data
  • drag-panes
  • drilldown
  • export-data
  • exporting
  • funnel
  • gantt
  • grid-axis
  • heatmap
  • histogram-bellcurve
  • item-series
  • no-data-to-display
  • offline-support
  • oldie
  • overlapping-datalabels
  • parallel-coordinates
  • pareto
  • pattern-fill
  • sankey
  • series-label
  • soild-gauge
  • static-scale
  • stock
  • steamgraph
  • sunburst
  • tilemap
  • treemap
  • variable-pie
  • variwide
  • vector
  • windbarb
  • wordcloud
  • xrange
vendor/highcharts/highstock Highstock - v6.1.0 - https://www.highcharts.com  
jquery.validate jQuery validate v1.17.0 - https://jqueryvalidation.org  
jquery.validate.unobtrusive jQuery validate v3.2.7

Includes default error placement to match the frameworks markup.

When loading unobtrusive do not load jQuery validate as well.

jquery.validate.unobtrusive-ajax jQuery validate v3.2.4

Includes default error placement to match the frameworks markup.

When loading unobtrusive-ajax do not load jQuery validate as well.

v.3.X.X and earlier

block Description Functions / Variables
jquery jQuery v2.2.2  
utility Core utility functions smallTag
mediumTag
largeTag
urlRegExp
getBreakpoint()
makeId( prefix )
processInPageLinks( selector, callback )
debounce( func, wait, immediate )
vendor/jquery/easing.1.3 Extend jQuery's standard easing functions (Removed in beta v1.0.5)
vendor/jquery/mousewheel jQuery Mousewheel - v3.1.13  
vendor/jquery/jquery-ui jQuery UI - v1.12.0 Includes: widget.js, position.js, data.js, disable-selection.js, focusable.js, form-reset-mixin.js, jquery-1-7.js, keycode.js, labels.js, scroll-parent.js, tabbable.js, unique-id.js, widgets/autocomplete.js, widgets/menu.js, widgets/mouse.js
vendor/jquery/mCustomScrollbar jQuery custom scrollbar - v3.1.3  
moment Moment - v2.14.1 Includes all locales
vendor/pikaday Pikaday - https://github.com/dbushell/Pikaday  
jquery.validate jQuery validate v1.17.0 - https://jqueryvalidation.org Available from v3.0.0
jquery.validate.unobtrusive jQuery validate v3.2.7

Available from v3.0.0

When loading unobtrusive do not load jQuery validate as well.

jquery.validate.unobtrusive-ajax jQuery validate v3.2.4

Available from v3.0.0

When loading unobtrusive-ajax do not load jQuery validate as well.