UNPKG

punchcard-content-types

Version:

Combines with input plugins to create forms with validation. Creates forms for Punchcard CMS.

374 lines (323 loc) 12.8 kB
/* eslint-env browser */ /* global allPlugins, allInputs, allSettings, allIDs, allRepeatables, validate */ (function formRepeatable() { 'use strict'; // Splits the string and pops the last element var splitPop = function splitPop(input, splitter) { var blocks = input.split(splitter); blocks.pop(); blocks = blocks.join(splitter); return blocks; }, updateIndex = function updateIndex(input, index) { var inputString = input; inputString = inputString.split('--'); if (inputString.length > 1) { inputString[1] = index; } else { inputString.push(index); } return inputString.join('--'); }, // Removes add button setAdd = function setAdd(node) { var childNodes = node.querySelectorAll('.form--repeatable'), element = document.createElement('button'); element.type = 'button'; element.textContent = 'Add'; element.id = node.id + '--add'; element.setAttribute('class', 'form--add'); // rule disable as adding 'add' button is required in deleteHandler and addHandler requires to add 'Delete' button element.addEventListener('click', addHandler); // eslint-disable-line no-use-before-define node.insertBefore(element, childNodes[childNodes.length - 1].nextSibling); }, // update index of id to 'index' updateId = function updateId(id, index) { var splitId = id.split('--'), num = splitId[1]; if (!isNaN(num)) { if (index === undefined) { return splitPop(id, '--'); } splitId[1] = index; return splitId.join('--'); } splitId.push(index); return splitId.join('--'); }, // Update Siblings in allInputs updateSiblings = function updateSiblings(id, index) { Object.keys(allInputs[id].siblings).forEach(function siblings(key) { allInputs[id].siblings[key] = updateId(allInputs[id].siblings[key], index); }); }, // Maintains state of allIds and allInputs updateIdsAndInputs = function updateIdsAndInputs(id, oldId, index) { if (allInputs.hasOwnProperty(oldId)) { allInputs[id] = allInputs[oldId]; updateSiblings(id, index); delete allInputs[oldId]; } if (allIDs.hasOwnProperty(oldId)) { allIDs[id] = allIDs[oldId]; delete allIDs[oldId]; } }, // decrement index of htmlfor by 1 decrementHtmlFor = function decrementHtmlFor(node) { var child = node, splitChild = child.getAttribute('for').split('--'), index = splitChild[1]; if (!isNaN(index)) { splitChild[1] = index - 1; child.setAttribute('for', splitChild.join('--')); } }, // decrement index of id by 1 and calls updateIdsAndInputs decrementId = function decrementId(node) { var child = node, splitChild = child.id.split('--'), index = splitChild[1], oldChildId = child.id; if (!isNaN(index)) { splitChild[1] = index - 1; child.id = splitChild.join('--'); updateIdsAndInputs(child.id, oldChildId, index - 1); } }, // decrement index of name by 1 decrementName = function decrementName(node) { var child = node, childName = child.getAttribute('name'); if (childName) { childName = childName.split('--'); if (!isNaN(childName[2])) { childName[2] = childName[2] - 1; child.setAttribute('name', childName.join('--')); } } }, // Updates node updateNode = function updateNode(key) { var child = key; if (child.id && child.id !== '') { decrementId(child); decrementName(child); } else if (child.getAttribute('for') && child.getAttribute('for') !== '') { decrementHtmlFor(child); } }, // Delete node from allIDs and allInputs deleteIdsAndInputs = function deleteIdsAndInputs(nodes) { var childNodes = nodes; Array.prototype.forEach.call(childNodes, function deleteIDandInput(child) { if (allInputs.hasOwnProperty(child.id)) { delete allInputs[child.id]; } if (allIDs.hasOwnProperty(child.id)) { delete allIDs[child.id]; } }); }, // Update values of instance updateInstance = function updateInstance(instance) { var nodeId = instance.id.split('--'), childNodes = instance.querySelectorAll('*'), node = instance; // Decrements id of container if (!isNaN(nodeId[1])) { nodeId[1]--; } node.id = nodeId.join('--'); Array.prototype.forEach.call(childNodes, updateNode); }, // Handles delete events deleteHandler = function deleteHandler(e) { var node = e.currentTarget.parentNode, siblingNode = node.nextElementSibling, containers, parent = node.parentNode, attribute = parent.id; if (allRepeatables[attribute].length === allRepeatables[attribute].max) { setAdd(node.parentNode); } // removes child parent.removeChild(node); allRepeatables[attribute].length--; deleteIdsAndInputs(node.querySelectorAll('*')); // change ids and names of subsequest instances while (siblingNode) { if (siblingNode.getAttribute('class') === 'form--repeatable') { updateInstance(siblingNode); } siblingNode = siblingNode.nextElementSibling; } // remove index if there is just one instance left if (allRepeatables[attribute].length === allRepeatables[attribute].min) { containers = parent.querySelectorAll('.form--repeatable'); Array.prototype.forEach.call(containers, function removeDelete(instance) { instance.removeChild(instance.querySelector('.form--delete')); }); } }, // Create and return delete button newDeleteButton = function newDeleteButton(attribute, index) { var element = document.createElement('button'); element.type = 'button'; element.textContent = 'Delete'; element.id = attribute + '--delete--' + index; element.setAttribute('class', 'form--delete'); element.addEventListener('click', deleteHandler); return element; }, // Add new input to allInputs setIDsAndInputs = function setIDsAndInputs(idMap, index) { Object.keys(idMap).forEach(function setIdandInput(id) { if (allInputs.hasOwnProperty(id)) { allInputs[idMap[id]] = Object.assign({}, allInputs[id]); updateSiblings(id, index); if (!allIDs.hasOwnProperty(idMap[id])) { allIDs[idMap[id]] = document.getElementById(idMap[id]); // Adds validation to new input allIDs[idMap[id]].addEventListener(allInputs[idMap[id]].validation.on, validate); } } }); }, // Adds index to id setId = function setId(node, map, index) { var child = node, idMap = map; if (idMap.hasOwnProperty(child.id)) { child.id = idMap[child.id]; } else { idMap[child.id] = updateIndex(child.id, index); child.id = idMap[child.id]; } }, // Adds index to HTMLFor setHtmlFor = function setHtmlFor(node, map, index) { var child = node, idMap = map, htmlFor = child.getAttribute('for'); if (idMap.hasOwnProperty(htmlFor)) { child.setAttribute('for', idMap[htmlFor]); } else { idMap[htmlFor] = updateIndex(htmlFor, index); child.setAttribute('for', idMap[htmlFor]); } }, // Adds index to name attribute if exists setName = function setName(node, index) { var child = node, childName = child.getAttribute('name'); if (childName) { childName = childName.split('--'); if (childName.length > 2) { childName[2] = index; } else { childName.push(index); } child.setAttribute('name', childName.join('--')); } }, // Clear value of input clearValues = function clearValues(node) { var child = node; if (child.type === 'checkbox' || child.type === 'radio') { child.checked = false; } else if (child.tagName === 'SELECT') { child.selectedIndex = 0; } else if (child.getAttribute('class') !== 'form--delete') { child.value = ''; } }, // Updates attribute of instance and returns the first input newInstance = function newInstance(instance, map, index) { var idMap = map, container = instance, firstInput; // Adds index to id of container container.id = updateIndex(container.id, index); Array.prototype.forEach.call(container.querySelectorAll('.form--alert'), function removeAlert(alert) { container.removeChild(alert); }); Array.prototype.forEach.call(container.querySelectorAll('*'), function cloneAttribute(child) { if (child.id !== '') { setName(child, index); setId(child, idMap, index); clearValues(child); // Sets first input as focus element if (!firstInput) { firstInput = child; } } else if (child.getAttribute('for') && child.getAttribute('for') !== '') { setHtmlFor(child, idMap, index); } }); if (container.querySelector('.form--delete')) { // Adds event listener to delete button container.querySelector('.form--delete').addEventListener('click', deleteHandler); } return firstInput; }, // Adds new container to parent addNewContainer = function addNewContainer(container, newContainer) { var containerSet = container.parentNode.querySelectorAll('.form--repeatable'), lastContainer = containerSet[containerSet.length - 1].nextSibling; container.parentNode.insertBefore(newContainer, lastContainer); }, // Handles add button event addHandler = function addHandler(e) { var firstInput, container = e.currentTarget.parentNode.querySelectorAll('.form--repeatable'), newContainer, attribute = e.currentTarget.parentNode.id, idMap = {}; // Modify name of initial instance and adds delete button if (allRepeatables[attribute].length === allRepeatables[attribute].min) { Array.prototype.forEach.call(container, function addDelete(instance, index) { // Adds new delete button to container instance.appendChild(newDeleteButton(attribute, index)); }); } // Gets updated values first instance container = e.currentTarget.parentNode.querySelector('.form--repeatable'); // deep clones the existing instance newContainer = container.cloneNode(true); // Updates each element in container firstInput = newInstance(newContainer, idMap, allRepeatables[attribute].length); addNewContainer(container, newContainer); setIDsAndInputs(idMap, allRepeatables[attribute].length); // Increments length of attribute allRepeatables[attribute].length++; // Return focus to first input of new instance firstInput.focus(); if (allRepeatables[attribute].length === allRepeatables[attribute].max) { e.currentTarget.parentNode.removeChild(e.currentTarget); } }; window.onload = function windowOnLoad() { // Iterates through every instance of input-plugins Object.keys(allSettings).forEach(function repeatableHandler(input) { var idAdd = input + '--add', addButton; // Adds event listener for existing delete button Array.prototype.forEach.call(document.querySelectorAll('.form--delete'), function addsDeleteEvent(button) { button.addEventListener('click', deleteHandler); }); addButton = document.getElementById(idAdd); if (addButton) { addButton.addEventListener('click', addHandler); } }); }; }());