var Cyclist = { baselineHelper: { SHOW_BASELINE_CLASS_NAME: 'cyclist-show-baseline', BASELINE_CLASS_NAME: 'cyclist-baseline', setup: function() { var showBaselineElements = document.getElementsByClassName(this.SHOW_BASELINE_CLASS_NAME); for (var i = 0; i < showBaselineElements.length; i++) { var baselineElement = showBaselineElements[i]; var baselineContainer = this.containerForElement(baselineElement); this.showBaseline(baselineContainer); } }, showBaseline: function(container) { container.style.height = "auto"; container.style.width = "100%"; var containerHeightInt = container.clientHeight; var parentHeightInt = container.parentNode.clientHeight; var counter = 0; // Use a counter to limit to 30 children to prevent infinite loops while (containerHeightInt < parentHeightInt && counter < 200) { // Add an element to contain the baseline var baselineElement = document.createElement("p"); this.resetCSS(baselineElement); baselineElement.appendChild(document.createTextNode('\u00A0')); // Draw the baseline on a canvas element var canvas = document.createElement("canvas"); baselineElement.style.position = "relative"; canvas.setAttribute("width", 1); canvas.setAttribute("height", 1); canvas.style.position = "absolute"; canvas.style.left = "0"; canvas.style.bottom = "0"; canvas.style.width = "100%"; canvas.style.height = "1px"; if (canvas && canvas.getContext) { context = canvas.getContext('2d'); context.strokeStyle = "rgba(148, 235, 255, 0.5)"; context.lineWidth = 1; context.strokeRect(0, 0, 1, 1); } baselineElement.appendChild(canvas); container.appendChild(baselineElement); containerHeightInt = container.clientHeight; counter++; } }, // Helpers containerForElement: function(element) { var container = document.createElement("div"); element.appendChild(container); this.makeContainer(container); return container; }, makeContainer: function(element) { var parent = element.parentNode; parent.style.position = "relative"; var height = parent.offsetHeight; var width = parent.offsetWidth; element.classList.add(this.BASELINE_CLASS_NAME); element.setAttribute("width", width); element.setAttribute("height", height); element.style.width = width + "px"; element.style.height = height + "px"; element.style.position = "absolute"; element.style.left = "0"; element.style.top = "0"; }, resetCSS: function(element) { element.style.border = 0; element.style.margin = "0"; element.style.padding = "0"; element.style.outline = "0"; element.style.fontSize = "100%"; element.style.verticalAlign = "baseline"; element.style.background = "transparent"; } }, guidelineHelper: { SHOW_GUIDELINES_CLASS_NAME: 'cyclist-show-guidelines', GUIDELINES_CLASS_NAME: 'cyclist-guidelines', setup: function() { var showGuidelinesElements = document.getElementsByClassName(this.SHOW_GUIDELINES_CLASS_NAME); for (var j = 0; j < showGuidelinesElements.length; j++) { var guidelinesElement = showGuidelinesElements[j]; var guidelinesContainer = this.containerForElement(guidelinesElement); this.showGuidelines(guidelinesContainer); } }, showGuidelines: function(container) { this.fillContainerWithClassName(container, 'cyclist-column'); var cyclistColumns = container.getElementsByClassName('cyclist-column'); for (var i = 0; i < cyclistColumns.length; i++) { var cyclistColmun = cyclistColumns[i]; this.fillContainerWithClassName(cyclistColmun, 'cyclist-unit'); } }, fillContainerWithClassName: function(container, className) { var computedWidth = 0; var containerWidth = container.clientWidth; var counter = 0; // Use a counter to limit to 30 children to prevent infinite loops while (computedWidth < containerWidth && counter < 30) { var element = document.createElement("div"); element.classList.add(className); container.appendChild(element); computedWidth = this.widthForChildElementsWithClassName(container, className); counter++; } }, widthForChildElementsWithClassName: function(parent, className) { var nodeList = parent.getElementsByClassName(className); var calculateWidth = function(initial, element) { var style = window.getComputedStyle(element); var marginRight = parseInt(style.marginRight, 10); var width = element.clientWidth; var totalWidth = width + marginRight; return initial + totalWidth; }; var width = Array.prototype.reduce.call(nodeList, calculateWidth, 0); return width; }, containerForElement: function(element) { var container = document.createElement("div"); element.appendChild(container); container.classList.add(this.GUIDELINES_CLASS_NAME); var height = element.offsetHeight; container.setAttribute("height", height); container.style.height = height + "px"; element.style.position = "relative"; return container; } }, redraw: function() { var classNames = [this.baselineHelper.BASELINE_CLASS_NAME, this.guidelineHelper.GUIDELINES_CLASS_NAME]; for (var i = 0; i < classNames.length; i++) { var className = classNames[i]; var nodeList = document.getElementsByClassName(className); for (var j = nodeList.length - 1; j >= 0; --j) { var element = nodeList[j]; element.parentNode.removeChild(element); } } this.setup(); }, setup: function() { this.baselineHelper.setup(); this.guidelineHelper.setup(); } }; window.addEventListener('load', function () { Cyclist.setup(); }, false);