Skip to content

Commit

Permalink
Create faq.js
Browse files Browse the repository at this point in the history
  • Loading branch information
mirceapiturca authored Oct 14, 2019
1 parent 778c2a6 commit 46ec120
Showing 1 changed file with 204 additions and 0 deletions.
204 changes: 204 additions & 0 deletions FAQ/assets/faq.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,204 @@
(function FAQ(SD) {
'use strict';

var support = getSupport();
var config = getConfig();
var init = compose(publicAPI, setEvents, getBlocks, getConfig);

SD.faq = {}
SD.faq[config.sectionId] = init();

function publicAPI(config) {
return {
id: config.sectionId,
config: config,
blocks: zipObj(config.blockIds, config.blocks),
init: init
}
}

//**************************


/**
* Click event.
* @param {Object} block Section block elements and methods.
* @return {Object} Section block elements and methods.
*/
function blockEvents(block) {
block.trigger.addEventListener('click', function triggerClick() {
toggle(block);
});

return block;
}

/**
* Toggle block state.
* @param {Object} block Section block elements and methods.
* @return {Object} Section block elements and methods.
*/
function toggle(block) {
block.collapsed ? expand(block) : collapse(block);
return block;
}

/**
* Expand block.
* @param {Object} block Section block elements and methods.
* @return {Object} Section block elements and methods.
*/
function expand(block) {
block.button.setAttribute('aria-expanded', true);
block.panel.removeAttribute('hidden');
animate(block.panel, 'normal');
return block;
}

/**
* Collapse block.
* @param {Object} block Section block elements and methods.
* @return {Object} Section block elements and methods.
*/
function collapse(block) {
block.button.setAttribute('aria-expanded', false);
block.panel.setAttribute('hidden', '');
animate(block.panel, 'reverse');
return block;
}

/**
* Collapse block.
* @param {Object} block Section block elements and methods.
* @return {boolean} Collapsed block state.
*/
function isCollapsed(block) {
return Boolean(block.button.getAttribute('aria-expanded') === 'false');
}

/**
* Collapse block.
* @param {HTMLElement} element Block panel element to animate.
* @param {String} direction Animation direction, normal or reverse.
* @return {undefined} Nothing to return.
*/
function animate(element, direction) {
if (!support.WebAnimations) return;

element.setAttribute('data-is-animating', true);

element.animate([
{ height: 0 },
{ height: element.offsetHeight + 'px' }],

{ duration: 240,
fill: 'both',
easing: 'cubic-bezier(0.4, 0.0, 0.2, 1)',
direction: direction
}

).onfinish = function() {
element.removeAttribute('data-is-animating');
this.cancel();
};
}

//**************************


/**
* Maps all block IDs to exposed block API.
* @param {Object} config Section and section blocks IDs.
* @return {Object} config Section and section blocks IDs.
*/
function getBlocks(config) {
config.blocks = config.blockIds.map(block);
return config;
}

/**
* Create section block API.
* @param {String} blockId Section Liquid block ID.
* @return {Object} block elements and methods.
*/
function block(blockId) {
return {
trigger: document.querySelector('[data-faq-trigger="' + blockId + '"]'),
button: document.querySelector('[data-faq-button="' + blockId + '"]'),
panel: document.querySelector('[data-faq-panel="' + blockId + '"]'),

get collapsed() { return isCollapsed(this) },
select: function select() { return expand(this) },
deselect: function deselect() { return collapse(this) }
}
}

/**
* Adds event listeners to block elements.
* @param {Object} config Section and section blocks IDs.
* @return {Object} config Section and section blocks IDs.
*/
function setEvents(config) {
config.blocks.forEach(blockEvents);
return config;
}

/**
* Pass the Liquid assigned section variabiles.
* @param {String} sectionId Current section ID.
* @return {Object} Section and section blocks IDs.
*/
function getConfig() {
return JSON.parse(document.querySelector('[data-faq-config]').innerHTML);
}

/**
* Feature detection.
* @return {Object} Browser support.
*/
function getSupport() {
return {
WebAnimations: (typeof Element.prototype.animate === 'function')
}
}

//**************************


/**
* Creates a new object out of a list of keys and a list of values.
* Key/value pairing is truncated to the length of the shorter of the two lists.
* @example
* zipObj(['a', 'b', 'c'], [1, 2, 3]); //=> {a: 1, b: 2, c: 3}
* @param {Array} keys The array that will be properties on the output object.
* @param {Array} values The list of values on the output object.
* @return {Object} The object made by pairing up same-indexed elements of `keys` and `values`.
*/
function zipObj(keys, values) {
return keys.reduce(
function zipObj(acc, key, idx) {
acc[key] = values[idx];
return acc;
}, {}
)
}

/**
* Performs right-to-left function composition.
* The rightmost function may have any arity, the remaining functions must be unary.
* @example
* function plus1(n) {return n + 1};
* function plus2(n) {return n + 2};
* compose(plus2,plus1)(1) => 4
* @return {Function} Composed function
*/
function compose() {
var funcs = Array.prototype.slice.call(arguments).reverse();
return function() {
return funcs.slice(1).reduce(function(res, fn) {
return fn(res);
}, funcs[0].apply(undefined, arguments));
};
}

})(window.SectionsDesign = window.SectionsDesign || {});

0 comments on commit 46ec120

Please sign in to comment.