//
class FenceModifier extends Modifier {
modify(element) { let contentElements = this.findChildren(element, "math-cont"); let leftElement = this.findChild(element, "math-left"); let rightElement = this.findChild(element, "math-right"); let centerElement = this.findChild(element, "math-center"); let parentElements = [leftElement, rightElement, centerElement]; let kinds = this.calcKinds(element); for (let position of [0, 1, 2]) { let parentElement = parentElements[position]; let kind = kinds[position]; if (position == 2) { position = 0; } if (parentElement && kind != "none") { let stretchLevel = this.calcStretchLevel(contentElements, kind, position); if (stretchLevel != null) { this.modifyStretch(contentElements, parentElement, kind, stretchLevel, position); } else { this.appendStretch(contentElements, parentElement, kind, position); } } } } modifyStretch(contentElements, parentElement, kind, stretchLevel, position) { let symbolElement = parentElement.children[0]; let shift = this.calcShift(contentElements, stretchLevel); symbolElement.textContent = DATA["fence"][kind][position][stretchLevel]; parentElement.style.verticalAlign = "" + shift + "em"; } appendStretch(contentElements, parentElement, kind, position) { let stretchElement = document.createElement("math-vstretch"); let hasStart = !!DATA["fence"][kind][position]["start"]; let hasEnd = !!DATA["fence"][kind][position]["end"]; let hasMiddle = !!DATA["fence"][kind][position]["middle"]; let startElement = null; let endElement = null; let middleElement = null; if (hasStart) { startElement = document.createElement("math-start"); startElement.textContent = DATA["fence"][kind][position]["start"]; stretchElement.append(startElement); } if (hasMiddle) { middleElement = document.createElement("math-middle"); middleElement.textContent = DATA["fence"][kind][position]["middle"]; stretchElement.append(middleElement); } if (hasEnd) { endElement = document.createElement("math-end"); endElement.textContent = DATA["fence"][kind][position]["end"]; stretchElement.append(endElement); } parentElement.removeChild(parentElement.children[0]); parentElement.appendChild(stretchElement); let barSize = (hasMiddle) ? 2 : 1; let barHeight = this.calcBarHeight(contentElements, startElement, endElement, middleElement); let stretchShift = this.calcStretchShift(contentElements); for (let i = 0 ; i < barSize ; i ++) { let barWrapperElement = document.createElement("math-barwrap"); let barElement = document.createElement("math-bar"); barElement.textContent = DATA["fence"][kind][position]["bar"]; barWrapperElement.style.height = "" + barHeight + "em"; barWrapperElement.append(barElement); if (i == 0) { stretchElement.insertBefore(barWrapperElement, stretchElement.children[(hasStart) ? 1 : 0]); } else { stretchElement.insertBefore(barWrapperElement, stretchElement.children[(hasStart) ? 3 : 2]); } } stretchElement.style.verticalAlign = "" + stretchShift + "em"; } calcKinds(element) { let leftKind = "paren"; let rightKind = "paren"; let centerKind = "vert"; if (element.getAttribute("data-left")) { leftKind = element.getAttribute("data-left"); } if (element.getAttribute("data-right")) { rightKind = element.getAttribute("data-right"); } if (element.getAttribute("data-center")) { centerKind = element.getAttribute("data-center"); } return [leftKind, rightKind, centerKind]; } calcMaxStretchLevel(kind, position) { let keys = Object.keys(DATA["fence"][kind][position]); let maxStretchLevel = 0; for (let key of keys) { if (key.match(/^\d+$/) && parseInt(key) > maxStretchLevel) { maxStretchLevel = parseInt(key); } } return maxStretchLevel; } calcWholeHeight(elements) { let upperHeights = []; let lowerHeights = []; for (let element of elements) { upperHeights.push(this.getUpperHeight(element)); lowerHeights.push(this.getLowerHeight(element)); } let maxUpperHeight = Math.max(...upperHeights); let maxLowerHeight = Math.max(...lowerHeights); return maxUpperHeight + maxLowerHeight; } calcStretchLevel(elements, kind, position) { let heightAbs = this.calcWholeHeight(elements) * 1000; let maxStretchLevel = this.calcMaxStretchLevel(kind, position); let stretchLevel = null; for (let i = 0 ; i <= maxStretchLevel ; i ++) { if (heightAbs <= 1059 + 242 * i) { stretchLevel = i; break; } } if (stretchLevel == null && !DATA["fence"][kind][position]["bar"]) { stretchLevel = maxStretchLevel; } return stretchLevel; } calcShift(elements, stretchLevel) { let shift = this.calcWholeHeight(elements) / 2 - Math.max(...elements.map((element) => this.getLowerHeight(element))); if (stretchLevel == 0) { shift = 0; } return shift; } calcBarHeight(elements, startElement, endElement, middleElement) { let wholeHeight = this.calcWholeHeight(elements); let startHeight = (startElement) ? this.getHeight(startElement) : 0; let endHeight = (endElement) ? this.getHeight(endElement) : 0; let middleHeight = (middleElement) ? this.getHeight(middleElement) : 0; let height = wholeHeight - startHeight - endHeight - middleHeight; if (middleElement) { height = height / 2; } if (height < 0) { height = 0; } return height; } calcStretchShift(elements) { let shift = Math.max(...elements.map((element) => this.getUpperHeight(element))) - 0.95; return shift; }
}