11cb0ef41Sopenharmony_ci'use strict' 21cb0ef41Sopenharmony_civar align = require('wide-align') 31cb0ef41Sopenharmony_civar validate = require('aproba') 41cb0ef41Sopenharmony_civar wideTruncate = require('./wide-truncate') 51cb0ef41Sopenharmony_civar error = require('./error') 61cb0ef41Sopenharmony_civar TemplateItem = require('./template-item') 71cb0ef41Sopenharmony_ci 81cb0ef41Sopenharmony_cifunction renderValueWithValues (values) { 91cb0ef41Sopenharmony_ci return function (item) { 101cb0ef41Sopenharmony_ci return renderValue(item, values) 111cb0ef41Sopenharmony_ci } 121cb0ef41Sopenharmony_ci} 131cb0ef41Sopenharmony_ci 141cb0ef41Sopenharmony_civar renderTemplate = module.exports = function (width, template, values) { 151cb0ef41Sopenharmony_ci var items = prepareItems(width, template, values) 161cb0ef41Sopenharmony_ci var rendered = items.map(renderValueWithValues(values)).join('') 171cb0ef41Sopenharmony_ci return align.left(wideTruncate(rendered, width), width) 181cb0ef41Sopenharmony_ci} 191cb0ef41Sopenharmony_ci 201cb0ef41Sopenharmony_cifunction preType (item) { 211cb0ef41Sopenharmony_ci var cappedTypeName = item.type[0].toUpperCase() + item.type.slice(1) 221cb0ef41Sopenharmony_ci return 'pre' + cappedTypeName 231cb0ef41Sopenharmony_ci} 241cb0ef41Sopenharmony_ci 251cb0ef41Sopenharmony_cifunction postType (item) { 261cb0ef41Sopenharmony_ci var cappedTypeName = item.type[0].toUpperCase() + item.type.slice(1) 271cb0ef41Sopenharmony_ci return 'post' + cappedTypeName 281cb0ef41Sopenharmony_ci} 291cb0ef41Sopenharmony_ci 301cb0ef41Sopenharmony_cifunction hasPreOrPost (item, values) { 311cb0ef41Sopenharmony_ci if (!item.type) { 321cb0ef41Sopenharmony_ci return 331cb0ef41Sopenharmony_ci } 341cb0ef41Sopenharmony_ci return values[preType(item)] || values[postType(item)] 351cb0ef41Sopenharmony_ci} 361cb0ef41Sopenharmony_ci 371cb0ef41Sopenharmony_cifunction generatePreAndPost (baseItem, parentValues) { 381cb0ef41Sopenharmony_ci var item = Object.assign({}, baseItem) 391cb0ef41Sopenharmony_ci var values = Object.create(parentValues) 401cb0ef41Sopenharmony_ci var template = [] 411cb0ef41Sopenharmony_ci var pre = preType(item) 421cb0ef41Sopenharmony_ci var post = postType(item) 431cb0ef41Sopenharmony_ci if (values[pre]) { 441cb0ef41Sopenharmony_ci template.push({ value: values[pre] }) 451cb0ef41Sopenharmony_ci values[pre] = null 461cb0ef41Sopenharmony_ci } 471cb0ef41Sopenharmony_ci item.minLength = null 481cb0ef41Sopenharmony_ci item.length = null 491cb0ef41Sopenharmony_ci item.maxLength = null 501cb0ef41Sopenharmony_ci template.push(item) 511cb0ef41Sopenharmony_ci values[item.type] = values[item.type] 521cb0ef41Sopenharmony_ci if (values[post]) { 531cb0ef41Sopenharmony_ci template.push({ value: values[post] }) 541cb0ef41Sopenharmony_ci values[post] = null 551cb0ef41Sopenharmony_ci } 561cb0ef41Sopenharmony_ci return function ($1, $2, length) { 571cb0ef41Sopenharmony_ci return renderTemplate(length, template, values) 581cb0ef41Sopenharmony_ci } 591cb0ef41Sopenharmony_ci} 601cb0ef41Sopenharmony_ci 611cb0ef41Sopenharmony_cifunction prepareItems (width, template, values) { 621cb0ef41Sopenharmony_ci function cloneAndObjectify (item, index, arr) { 631cb0ef41Sopenharmony_ci var cloned = new TemplateItem(item, width) 641cb0ef41Sopenharmony_ci var type = cloned.type 651cb0ef41Sopenharmony_ci if (cloned.value == null) { 661cb0ef41Sopenharmony_ci if (!(type in values)) { 671cb0ef41Sopenharmony_ci if (cloned.default == null) { 681cb0ef41Sopenharmony_ci throw new error.MissingTemplateValue(cloned, values) 691cb0ef41Sopenharmony_ci } else { 701cb0ef41Sopenharmony_ci cloned.value = cloned.default 711cb0ef41Sopenharmony_ci } 721cb0ef41Sopenharmony_ci } else { 731cb0ef41Sopenharmony_ci cloned.value = values[type] 741cb0ef41Sopenharmony_ci } 751cb0ef41Sopenharmony_ci } 761cb0ef41Sopenharmony_ci if (cloned.value == null || cloned.value === '') { 771cb0ef41Sopenharmony_ci return null 781cb0ef41Sopenharmony_ci } 791cb0ef41Sopenharmony_ci cloned.index = index 801cb0ef41Sopenharmony_ci cloned.first = index === 0 811cb0ef41Sopenharmony_ci cloned.last = index === arr.length - 1 821cb0ef41Sopenharmony_ci if (hasPreOrPost(cloned, values)) { 831cb0ef41Sopenharmony_ci cloned.value = generatePreAndPost(cloned, values) 841cb0ef41Sopenharmony_ci } 851cb0ef41Sopenharmony_ci return cloned 861cb0ef41Sopenharmony_ci } 871cb0ef41Sopenharmony_ci 881cb0ef41Sopenharmony_ci var output = template.map(cloneAndObjectify).filter(function (item) { 891cb0ef41Sopenharmony_ci return item != null 901cb0ef41Sopenharmony_ci }) 911cb0ef41Sopenharmony_ci 921cb0ef41Sopenharmony_ci var remainingSpace = width 931cb0ef41Sopenharmony_ci var variableCount = output.length 941cb0ef41Sopenharmony_ci 951cb0ef41Sopenharmony_ci function consumeSpace (length) { 961cb0ef41Sopenharmony_ci if (length > remainingSpace) { 971cb0ef41Sopenharmony_ci length = remainingSpace 981cb0ef41Sopenharmony_ci } 991cb0ef41Sopenharmony_ci remainingSpace -= length 1001cb0ef41Sopenharmony_ci } 1011cb0ef41Sopenharmony_ci 1021cb0ef41Sopenharmony_ci function finishSizing (item, length) { 1031cb0ef41Sopenharmony_ci if (item.finished) { 1041cb0ef41Sopenharmony_ci throw new error.Internal('Tried to finish template item that was already finished') 1051cb0ef41Sopenharmony_ci } 1061cb0ef41Sopenharmony_ci if (length === Infinity) { 1071cb0ef41Sopenharmony_ci throw new error.Internal('Length of template item cannot be infinity') 1081cb0ef41Sopenharmony_ci } 1091cb0ef41Sopenharmony_ci if (length != null) { 1101cb0ef41Sopenharmony_ci item.length = length 1111cb0ef41Sopenharmony_ci } 1121cb0ef41Sopenharmony_ci item.minLength = null 1131cb0ef41Sopenharmony_ci item.maxLength = null 1141cb0ef41Sopenharmony_ci --variableCount 1151cb0ef41Sopenharmony_ci item.finished = true 1161cb0ef41Sopenharmony_ci if (item.length == null) { 1171cb0ef41Sopenharmony_ci item.length = item.getBaseLength() 1181cb0ef41Sopenharmony_ci } 1191cb0ef41Sopenharmony_ci if (item.length == null) { 1201cb0ef41Sopenharmony_ci throw new error.Internal('Finished template items must have a length') 1211cb0ef41Sopenharmony_ci } 1221cb0ef41Sopenharmony_ci consumeSpace(item.getLength()) 1231cb0ef41Sopenharmony_ci } 1241cb0ef41Sopenharmony_ci 1251cb0ef41Sopenharmony_ci output.forEach(function (item) { 1261cb0ef41Sopenharmony_ci if (!item.kerning) { 1271cb0ef41Sopenharmony_ci return 1281cb0ef41Sopenharmony_ci } 1291cb0ef41Sopenharmony_ci var prevPadRight = item.first ? 0 : output[item.index - 1].padRight 1301cb0ef41Sopenharmony_ci if (!item.first && prevPadRight < item.kerning) { 1311cb0ef41Sopenharmony_ci item.padLeft = item.kerning - prevPadRight 1321cb0ef41Sopenharmony_ci } 1331cb0ef41Sopenharmony_ci if (!item.last) { 1341cb0ef41Sopenharmony_ci item.padRight = item.kerning 1351cb0ef41Sopenharmony_ci } 1361cb0ef41Sopenharmony_ci }) 1371cb0ef41Sopenharmony_ci 1381cb0ef41Sopenharmony_ci // Finish any that have a fixed (literal or intuited) length 1391cb0ef41Sopenharmony_ci output.forEach(function (item) { 1401cb0ef41Sopenharmony_ci if (item.getBaseLength() == null) { 1411cb0ef41Sopenharmony_ci return 1421cb0ef41Sopenharmony_ci } 1431cb0ef41Sopenharmony_ci finishSizing(item) 1441cb0ef41Sopenharmony_ci }) 1451cb0ef41Sopenharmony_ci 1461cb0ef41Sopenharmony_ci var resized = 0 1471cb0ef41Sopenharmony_ci var resizing 1481cb0ef41Sopenharmony_ci var hunkSize 1491cb0ef41Sopenharmony_ci do { 1501cb0ef41Sopenharmony_ci resizing = false 1511cb0ef41Sopenharmony_ci hunkSize = Math.round(remainingSpace / variableCount) 1521cb0ef41Sopenharmony_ci output.forEach(function (item) { 1531cb0ef41Sopenharmony_ci if (item.finished) { 1541cb0ef41Sopenharmony_ci return 1551cb0ef41Sopenharmony_ci } 1561cb0ef41Sopenharmony_ci if (!item.maxLength) { 1571cb0ef41Sopenharmony_ci return 1581cb0ef41Sopenharmony_ci } 1591cb0ef41Sopenharmony_ci if (item.getMaxLength() < hunkSize) { 1601cb0ef41Sopenharmony_ci finishSizing(item, item.maxLength) 1611cb0ef41Sopenharmony_ci resizing = true 1621cb0ef41Sopenharmony_ci } 1631cb0ef41Sopenharmony_ci }) 1641cb0ef41Sopenharmony_ci } while (resizing && resized++ < output.length) 1651cb0ef41Sopenharmony_ci if (resizing) { 1661cb0ef41Sopenharmony_ci throw new error.Internal('Resize loop iterated too many times while determining maxLength') 1671cb0ef41Sopenharmony_ci } 1681cb0ef41Sopenharmony_ci 1691cb0ef41Sopenharmony_ci resized = 0 1701cb0ef41Sopenharmony_ci do { 1711cb0ef41Sopenharmony_ci resizing = false 1721cb0ef41Sopenharmony_ci hunkSize = Math.round(remainingSpace / variableCount) 1731cb0ef41Sopenharmony_ci output.forEach(function (item) { 1741cb0ef41Sopenharmony_ci if (item.finished) { 1751cb0ef41Sopenharmony_ci return 1761cb0ef41Sopenharmony_ci } 1771cb0ef41Sopenharmony_ci if (!item.minLength) { 1781cb0ef41Sopenharmony_ci return 1791cb0ef41Sopenharmony_ci } 1801cb0ef41Sopenharmony_ci if (item.getMinLength() >= hunkSize) { 1811cb0ef41Sopenharmony_ci finishSizing(item, item.minLength) 1821cb0ef41Sopenharmony_ci resizing = true 1831cb0ef41Sopenharmony_ci } 1841cb0ef41Sopenharmony_ci }) 1851cb0ef41Sopenharmony_ci } while (resizing && resized++ < output.length) 1861cb0ef41Sopenharmony_ci if (resizing) { 1871cb0ef41Sopenharmony_ci throw new error.Internal('Resize loop iterated too many times while determining minLength') 1881cb0ef41Sopenharmony_ci } 1891cb0ef41Sopenharmony_ci 1901cb0ef41Sopenharmony_ci hunkSize = Math.round(remainingSpace / variableCount) 1911cb0ef41Sopenharmony_ci output.forEach(function (item) { 1921cb0ef41Sopenharmony_ci if (item.finished) { 1931cb0ef41Sopenharmony_ci return 1941cb0ef41Sopenharmony_ci } 1951cb0ef41Sopenharmony_ci finishSizing(item, hunkSize) 1961cb0ef41Sopenharmony_ci }) 1971cb0ef41Sopenharmony_ci 1981cb0ef41Sopenharmony_ci return output 1991cb0ef41Sopenharmony_ci} 2001cb0ef41Sopenharmony_ci 2011cb0ef41Sopenharmony_cifunction renderFunction (item, values, length) { 2021cb0ef41Sopenharmony_ci validate('OON', arguments) 2031cb0ef41Sopenharmony_ci if (item.type) { 2041cb0ef41Sopenharmony_ci return item.value(values, values[item.type + 'Theme'] || {}, length) 2051cb0ef41Sopenharmony_ci } else { 2061cb0ef41Sopenharmony_ci return item.value(values, {}, length) 2071cb0ef41Sopenharmony_ci } 2081cb0ef41Sopenharmony_ci} 2091cb0ef41Sopenharmony_ci 2101cb0ef41Sopenharmony_cifunction renderValue (item, values) { 2111cb0ef41Sopenharmony_ci var length = item.getBaseLength() 2121cb0ef41Sopenharmony_ci var value = typeof item.value === 'function' ? renderFunction(item, values, length) : item.value 2131cb0ef41Sopenharmony_ci if (value == null || value === '') { 2141cb0ef41Sopenharmony_ci return '' 2151cb0ef41Sopenharmony_ci } 2161cb0ef41Sopenharmony_ci var alignWith = align[item.align] || align.left 2171cb0ef41Sopenharmony_ci var leftPadding = item.padLeft ? align.left('', item.padLeft) : '' 2181cb0ef41Sopenharmony_ci var rightPadding = item.padRight ? align.right('', item.padRight) : '' 2191cb0ef41Sopenharmony_ci var truncated = wideTruncate(String(value), length) 2201cb0ef41Sopenharmony_ci var aligned = alignWith(truncated, length) 2211cb0ef41Sopenharmony_ci return leftPadding + aligned + rightPadding 2221cb0ef41Sopenharmony_ci} 223