(function ($) { "use strict"; // Make sure regex patterns are only parsed once var $newLinePattern = /\{n}/g, $spacePattern = /\{s}/g, $tabPattern = /\{t}/g, $whiteSpacePattern = /^(?:\s+)?$/g, $inputTagPattern = //g, $optionClosingTagPattern = />(?:\s+)?<\/option>/g, $htmlAttributeSpacingPattern = /(\s+)([^id][a-z_\-]+="(?:.*?)")/ig; // Just kill form submission $.qs('form').onsubmit = function(e) { e.preventDefault(); e.stopPropagation(); console.log("Form 'submit' event fired."); return false; }; var format = { /** * Format the display of an input element, and align the attributes * on separate lines * * @param {HTMLInputElement} formElement * @return {string} */ input: function (formElement) { // Let's do some ugly DOM manipulation to make the output of the // highlighted have lined up attributes. // For the spacing, we replace normal whitespace characters with // {x} placeholders so the highlighter doesn't mangle them var formElementSpaces = '{s}'.repeat(formElement.tagName.length + 2); var formElementReplace = '{n}' + formElementSpaces; var formElementHTML = formElement.outerHTML .trim() .replace($inputTagPattern, '') .replace($htmlAttributeSpacingPattern, formElementReplace + '$2'); return formElementHTML; }, /** * Format the display of an option element * * @param {HTMLOptionElement} formElement * @return {string} */ option: function (formElement) { var raw = format.generic(formElement); if (hasHtmlChildren(formElement) && formElement.childNodes.length > 0) { return raw; } raw = raw.replace($whiteSpacePattern, ''); return raw.replace($optionClosingTagPattern, ' />'); }, /** * Format the display of elements without specific formatting methods * * @param {HTMLElement} formElement * @return {string} */ generic: function (formElement) { return formElement.outerHTML.trim(); } }; /** * Format the current element * * @param {HTMLElement} formElement * @param {number} i * @return string */ function formatElement (formElement, i) { var elementPrefix = (i > 0) ? '{n}' + '{t}'.repeat(i) : ''; if (formElement.nodeType === 3) { return elementPrefix + formElement.nodeValue; } var tagName = formElement.tagName.toLowerCase(); var formattingMethod = (Object.keys(format).indexOf(tagName) !== -1) ? format[tagName] : format.generic; return elementPrefix + formattingMethod(formElement); } /** * Check whether an element has an other elements as children * * @param {HTMLElement} element * @return {boolean} */ function hasHtmlChildren (element) { var x = 0; var node; var numChildren = element.childNodes.length; if (numChildren === 0) { return false; } for (; x < numChildren; x++) { node = element.childNodes.item(x); // Only count as a child if the node is an element if (node.nodeType === 1) { return true; } } return false; } /** * Recursively format the form elements for better alignment * * @param {HTMLElement} formElement * @param {number} level * @return {string} */ function formatHtml(formElement, level) { level = level || 0; var children = $.toArray(formElement.childNodes); var hasChildren = hasHtmlChildren(formElement); var rawChildren = formElement.innerHTML; var formattedHTML = formatElement(formElement, level); // If there are no children, just return the formatted element if (!hasChildren) { return formattedHTML; } children = children.filter(function (node) { // Discard text nodes if they only contain whitespace if (node.nodeType === 3 && node.nodeValue.match($whiteSpacePattern)) { return false; } // Keep other nodes return true; }); level++; var newChildrenHTML = children.reduce(function (prevHTML, node) { return prevHTML + formatHtml(node, level); }, ''); // Format those closing tags if (level > 0 && hasChildren) { newChildrenHTML += '{n}' + '{t}'.repeat(level - 1); } formattedHTML = formattedHTML.replace(rawChildren, newChildrenHTML); return formattedHTML; } // Get each form field's html and syntax highlight it $.getByClass('form-field').forEach(function(parent) { // Setup up the highligher var hl = new DlHighlight({lang: 'html'}); var labelHTML = formatHtml($.qs('label', parent), 0); var formElements = $.qsa('button, input, datalist, keygen, meter, output, progress, select, textarea', parent); var formElementHTML = ''; formElements.forEach(function (formElement) { formElementHTML += '{n}{n}' + formatHtml(formElement, 0); }); // Join the label markup with the form element markup var formCode = labelHTML + formElementHTML.trim(); // Now replace the placeholders with proper whitespace equvalent markup var highLighted = hl.doItNow(formCode); highLighted = $.replaceMultiple(highLighted, [ [$newLinePattern, '
'], [$spacePattern, ' '], [$tabPattern, ' '.repeat(4)] ]); // Piece together the HTML for the prettier HTML examples var codeElement = document.createElement('code'); codeElement.className = 'DlHighlight html'; codeElement.innerHTML = highLighted; // Append the prettified HTML to the parent element parent.appendChild(codeElement); }); }(doc));