JavaScript

The Framework uses RequireJS to load in only the JavaScript needed for the page in question. When building new elements or modules which are to be enhanced using JavaScript, the functionality should therefore be included using RequireJS.

  1. Set the data-app attribute on the init.js script tag within the page to the URL that the JavaScript files are located (do not include any trailing slashes). This URL should be the full path to the folder location, but should remain protocol agnostic:

    <script id="js-init" src="[ CDN Folder Path ]/js/init.js" data-app="="//:[ Site domain ]/..."></script>
  2. Load the JavaScript for the module by setting the data-module attribute on the element to which the JavaScript will be applied to app/[module], where [module] is the name given to the JavaScript file for your module without the .js file extension:

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

As an example, if you are using v.4.9.0 of the Framework, with your JavaScript files stored at www.aviva.co.uk/project/library/js, and your module file is called project-module.js, your js-init setup would be:

<script id="js-init" src="//cdn.aviva.com/static/core/v.4.9.0/js/init.js " data-app="//www.aviva.co.uk/project/library/js"></script>

With the call to the module being:

<div class="..." data-module="app/project-module">...</div>

Considerations when writing blocks

Multi-language support

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

A very example of this could be a button added to a page by JS, whose text content may need to be presented in a number of different languages if the component is used globally.

Accessibility

Always consider best practices with regard to accessibility, and, wherever possible, make use of ARIA attributes to help users with assistive technologies to better navigate the page/application. See the Aviva Standards accessibility standards page for more information.

Writing JavaScript blocks

Use RequireJS to define the block, loading in any JavaScript files that the block is dependent on. Check the list of core JavaScript files at the bottom of this page so that files are not loaded multiple times from different locations. For example:

define( [ 'jquery', 'utility' ], function run( $, util ) { // Set up define call for RequireJS
	'use strict'; // Always use strict mode

	var block = { // Define the js module block
		init : function( el ) { // Create the init function to run on load
			// Your module code goes in here, for example:
			this.create( $( el ) );
		},

		create : function( element ) { // Additional functions can be also created
			// Creation code
		}
	};

	return { // Finally, return your block, initialising the instance of its use
		initInstance: function( el ) {
			block.init( el );
		}
	};
});

Important note: The init function for the block will be called for every instance of the element/module that occurs within the page on load, so precautions should be taken to ensure that this 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, for example .js-module, which is only added by the JavaScript.

Running RequireJS again

If additional content is generated or loaded in to your page by JavaScript and contains element or modules which themselves get enhanced via JavaScript (for example, 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 document's body element:

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

As of Framework v.4.6.0, it is possible to run moduleScan without the jQuery dependency. To do this, set up the following JavaScript function:

var trigger = function( targetEl, eventName ) {
	var event = document.createEvent( 'Event' );
	event.initEvent( eventName, true, true );
	targetEl.dispatchEvent( event );
};

moduleScan can then be run using the following command where needed:

trigger( document.body, 'moduleScan' );

Extending the RequireJS config

v.4.X.X

If you need to extend the RequireJS config setup by v4 of the Framework, use the following code:

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

Place this config extension in a separate file and load it in before the Framework's init.js script.

Important note: There are several caveats to using this process:

  • Do not 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, (eg. paths), then when the Framework config and the extension config are merged, the Framework's values will take priority. This means that if you tried to add a custom path for jquery, it would be overwritten by the Framework's value.
  • If you are adding a config property that uses an array type (eg. deps), then the Framework's config value will be concatenated with the extension config.
  • If you are adding a callback property, this will be wrapped within the Framework's own callback function; the Framework function will run first, and then call any additional callbacks.

v.3.X.X and earlier

If you need to extend the RequireJS config setup by v3 or earlier of the Framework, use the following code:

<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 run( $ ) {
			// ...
		});
	});
</script>

Important note: Be careful not the overwrite any existing config settings, as this can and will break components.

CORS on RequireJS modules

The crossorigin attribute on img, video or script tags enables you to configure the CORS request for an element's fetched data.

From v.4.12.0 it is possbile to include custom attributes to modules by extending the RequireJs config. This can be used to include a crossorigin attribute to handle the CORS request.

<script>
    window.requireExtend = {
        moduleAttributes : {
            'app/yourModule' : {
                crossorigin : 'anonymous',
                //... Any other attribute e.g. integrity
            },
            'app/' : { // This would set the attributes to all modules where the module name starts with 'app/'
                crossorigin : 'anonymous',
                //... Any other attribute e.g. integrity
            }
        }
    };
</script>

Working programmatically with RequireJS

Sometimes you may want more flexibility than using Framework blocks; in this situation, working directly with RequireJS is the recommended approach.

To do this, wait for the RequireJS config to be load asynchronously and to fire its callback, which will emit the requireready event on document. This is set up as follows:

<script>
	document.addEventListener( 'requireready', function onRequireReady() {
		require( [ 'jquery', 'app/custom-module' ], function run( $, customModule ) {
			// When Require JS has loaded and run, do something...
		});
	});
</script>

Loading JavaScript that not compatible with RequireJS

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

  1. Set the data-app attribute on the init.js script tag within the page as detailed above.
  2. Add in each required script under the init.js 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>
  3. If one of the files has a dependency on another, the file is modified so that the original code is wrapped by an AMD loader function. For example, to ensure that 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
    }));

Triggering a refresh

Sometimes you may want to force content to refresh, for example if elements need to be redrawn after being hidden and then shown again. Using jQuery, you can run this by calling:

$( window ).trigger( 'refresh' );

As of Framework v.4.6.0, it is possible to trigger a refresh without the jQuery dependency. To do this, set up the following:

var trigger = function( targetEl, eventName ) {
	var event = document.createEvent( 'Event' );
	event.initEvent( eventName, true, true );
	targetEl.dispatchEvent( event );
};

This can then be run using the following command where needed:

trigger( window, 'refresh' );

Important note: At this time, both the native and jQuery versions of the trigger should be used so that both Framework components which do not have a jQuery dependency and those which still do will be correctly refreshed. This will mean ensuring that jQuery has been included in your define call for RequireJS at the start of your module block (as described in the Writing JavaScript blocks section above), with the refresh call as follows:

trigger( window, 'refresh' );
$( window ).trigger('refresh' );

Using jQuery validate and unobtrusive

From Framework v.3.0.0, jQuery validate and unobtrusive are available for use with your blocks of JavaScript. Load them by adding them to your define block as follows:

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

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

For validate and unobtrusive to work, there are certain elements which 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 as follows:

require( [ 'jquery', 'jquery.validate.unobtrusive' ], function run( $, 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 );
});

Important note: this is typically a blunt approach, so a better method whenever possible would be to update the validator settings instead:

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

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

Validator error placement

There may be occasions where error placement does not work as expected for a certain form field; to work around this, you may need to modify jquery.validate's settings, for example:

require( [ 'jquery', 'jquery.unobtrusive' ], function run( $, unobtrusive ) {
	var $form = $( 'form' ),
		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 );
			}
		};
	}
});

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.4.0 (v.3.3.1 prior to release v.4.9.0)  
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
  • widget.js
  • position.js
  • disable-selection.js
  • form-reset-mixin.js
  • labels.js
  • tabbable.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 - 1.7.0 - https://github.com/Pikaday/Pikaday
(Updated to 1.8.0 in v.4.9.0)
 
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  
vendor/highcharts7/highcharts Highcharts - v7.0.2 - https://www.highcharts.com CSS available from [cdn path]/css/vendor/highcharts7/...
vendor/highcharts7/modules/... Highcharts modules - for v7.0.2 - https://www.highcharts.com
  • accessibility
  • annotations
  • annotations-advanced
  • arrow-symbols
  • boost
  • boost-canvas
  • broken-axis
  • bullet
  • current-date-indicator
  • cylinder
  • data
  • debugger
  • draggable-points
  • drag-panes
  • drilldown
  • export-data
  • exporting
  • full-screen
  • funnel
  • gantt
  • grid-axis
  • heatmap
  • histogram-bellcurve
  • item-series
  • networkgraph
  • no-data-to-display
  • offline-support
  • oldie
  • oldie-polyfills
  • overlapping-datalabels
  • parallel-coordinates
  • pareto
  • pathfinder
  • pattern-fill
  • price-indicator
  • sankey
  • series-label
  • soild-gauge
  • sonification
  • static-scale
  • stock
  • stock-tools
  • steamgraph
  • sunburst
  • tilemap
  • timeline
  • treegrid
  • treemap
  • variable-pie
  • variwide
  • vector
  • venn
  • windbarb
  • wordcloud
  • xrange
vendor/highcharts7/indicators/... Highcharts indicators - for v7.0.2 - https://www.highcharts.com
  • acceleration-bands
  • accumulation-disruption
  • ao
  • apo
  • aroon
  • aroon-oscillator
  • atr
  • bollinger-bands
  • cci
  • chaikin
  • cmf
  • dema
  • dpo
  • ema
  • ichimoku-kinko-hyo
  • indicators
  • indicators-all
  • keltner-channels
  • macd
  • mfi
  • momentum
  • natr
  • pivot-points
  • ppo
  • price-channel
  • price-envelopes
  • psar
  • regressions
  • roc
  • rsi
  • stochastic
  • supertrend
  • tema
  • trix
  • volume-by-price
  • vwap
  • williams-r
  • wma
  • zigzag
vendor/highcharts7/lib/... Highcharts lib - for v7.0.2 - https://www.highcharts.com
  • canvg
  • jspdf
  • rebcolor
  • svg2pdf
vendor/highcharts7/themes/... Highcharts themes - for v7.0.2 - https://www.highcharts.com
  • avocado
  • dark-blue
  • dark-green
  • dark-unica
  • gray
  • grid
  • grid-light
  • sand-signika
  • skies
  • sunset
vendor/highcharts7/highstock Highstock - v7.0.2 - https://www.highcharts.com  
vendor/highcharts7/highcharts-3d Highcharts 3D - v7.0.2 - https://www.highcharts.com CSS available from [cdn path]/css/vendor/highcharts7/...
vendor/highcharts7/highcharts-more Highcharts More - v7.0.2 - https://www.highcharts.com CSS available from [cdn path]/css/vendor/highcharts7/...
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
  • 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/Pikaday/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.