The JavaScript frontend logic has been developed using CoffeeScript. Coffeescript gets compiled to JavaScript by using gulp tasks. The code is located in the ./src/coffeescript
folder.
A component architecture has been used, where each functionality is split into a separate class following a specific structure. Components get initialized in the main.coffee file by using a factory approach only when their associated element exists on the current page.
Browserify is used to manage module definition and importing, which follows the CommonJS convention used by node.js using the require
and module.exports
commands.
To manage Javascript dependencies npm (node package manager) is used. For a speedier development it is recommended to use yarn, an alternative package manager that uses the npm package repository. This guide assumes you are familiar with package managers. In case you are not, it is recommended that you learn more about them at their respective websites.
The code is divided into two categories:
The main.coffee file is the entry point of the application, where all modules are instantiated using the factory utility defined in utilities/factory.coffee.
The whole code gets minified into a main.js file, which is good for caching purposes. The factory utility ensures that only components needed for the page get instantiated.
# the BannerSearchForm component will be instantiated only
# if the page contains an element with the class '.js-bannerSearchForm'
factory(BannerSearchForm, '.js-bannerSearchForm')
We use js- classes to signify which classes are used as JavaScript hooks.
Another folder called templates contains hogan.js templates which can be then used to render Ajax dependant or other JavaScript views. These files have mustache extension, because hogan is compatible with mustache.js, but it is more lightweight.
template = require '../templates/bookListItem.mustache'
html = template({ data: 'some data' })
In order to work with the factory utility, components need to be structured in the following way:
# file themes/source_unibz/src/coffeescript/modules/Accordion.coffee
$ = require 'jquery'
class Accordion
# a contructor with an @$el parameter is required
# the corresponding to the CSS selector given as second
# argument to the factory utility will assigned to this
# parameter for usage in the code of the module
constructor: (@$el) ->
@$toggler = @$el.find('.js-accordion-toggle')
@$region = @$el.find('.js-accordion-region')
@openClass = 'is-open'
# we initialize event handlers in the last part
# of the constructor
@$toggler.on 'click', $.proxy(@toggleState, this)
# other code and functions
toggleState: (e) ->
if @$el.hasClass @openClass
@$el.removeClass @openClass
@$region.attr('aria-expanded', false)
else
@$el.addClass @openClass
@$region.attr('aria-expanded', true)
module.exports = Accordion
This module can then be imported and initialized in the *main.coffee file as follows:
Accordion = require './modules/Accordion'
$ ->
factory(Accordion, '.js-accordion')
An utility is simply a reusabel function which performs one single functionality and can be defined as follows:
# file themes/source_unibz/src/coffeescript/utilities/readConfigFromHTMLAttrs.coffee
_ = require 'lodash'
$ = require 'jquery'
module.exports = ($el, propertyName) ->
propertyName = 'data-' + propertyName + '-'
_.reduce $el.get(0).attributes, (memo, attr) ->
if attr and attr.name and attr.name.indexOf(propertyName) is 0
memo[attr.name.replace(propertyName, '')] = attr.value
memo
, {}
It is then possible to import and use an utility as a normal function:
readConfigFromHTMLAttrs = require '../utilities/readConfigFromHTMLAttrs'
readConfigFromHTMLAttrs($el, 'filterable-property-label')