zotica 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/exec/zotica +99 -0
- data/exec/zoticaf +52 -0
- data/source/zotica.rb +14 -0
- data/source/zotica/builder.rb +979 -0
- data/source/zotica/parser.rb +543 -0
- data/source/zotica/resource/font.otf +0 -0
- data/source/zotica/resource/font/main.json +1472 -0
- data/source/zotica/resource/font/main.ttf +0 -0
- data/source/zotica/resource/font/math.json +5040 -0
- data/source/zotica/resource/font/math.ttf +0 -0
- data/source/zotica/resource/math.json +652 -0
- data/source/zotica/resource/script/accent.js +42 -0
- data/source/zotica/resource/script/diagram.js +481 -0
- data/source/zotica/resource/script/fence.js +163 -0
- data/source/zotica/resource/script/main.js +172 -0
- data/source/zotica/resource/script/radical.js +43 -0
- data/source/zotica/resource/script/subsuper.js +90 -0
- data/source/zotica/resource/script/tree.js +68 -0
- data/source/zotica/resource/script/underover.js +9 -0
- data/source/zotica/resource/script/wide.js +121 -0
- data/source/zotica/resource/style/math.scss +680 -0
- data/source/zotica/resource/style/times.scss +11 -0
- metadata +117 -0
| @@ -0,0 +1,163 @@ | |
| 1 | 
            +
            //
         | 
| 2 | 
            +
             | 
| 3 | 
            +
             | 
| 4 | 
            +
            class FenceModifier extends Modifier {
         | 
| 5 | 
            +
             | 
| 6 | 
            +
              modify(element) {
         | 
| 7 | 
            +
                let contentElements = this.findChildren(element, "math-cont");
         | 
| 8 | 
            +
                let leftElement = this.findChild(element, "math-left");
         | 
| 9 | 
            +
                let rightElement = this.findChild(element, "math-right");
         | 
| 10 | 
            +
                let centerElement = this.findChild(element, "math-center");
         | 
| 11 | 
            +
                let parentElements = [leftElement, rightElement, centerElement];
         | 
| 12 | 
            +
                let kinds = this.calcKinds(element);
         | 
| 13 | 
            +
                for (let position of [0, 1, 2]) {
         | 
| 14 | 
            +
                  let parentElement = parentElements[position];
         | 
| 15 | 
            +
                  let kind = kinds[position];
         | 
| 16 | 
            +
                  if (position == 2) {
         | 
| 17 | 
            +
                    position = 0;
         | 
| 18 | 
            +
                  }
         | 
| 19 | 
            +
                  if (parentElement && kind != "none") {
         | 
| 20 | 
            +
                    let stretchLevel = this.calcStretchLevel(contentElements, kind, position);
         | 
| 21 | 
            +
                    if (stretchLevel != null) {
         | 
| 22 | 
            +
                      this.modifyStretch(contentElements, parentElement, kind, stretchLevel, position);
         | 
| 23 | 
            +
                    } else {
         | 
| 24 | 
            +
                      this.appendStretch(contentElements, parentElement, kind, position);
         | 
| 25 | 
            +
                    }
         | 
| 26 | 
            +
                  }
         | 
| 27 | 
            +
                }
         | 
| 28 | 
            +
              }
         | 
| 29 | 
            +
             | 
| 30 | 
            +
              modifyStretch(contentElements, parentElement, kind, stretchLevel, position) {
         | 
| 31 | 
            +
                let symbolElement = parentElement.children[0];
         | 
| 32 | 
            +
                let shift = this.calcShift(contentElements, stretchLevel);
         | 
| 33 | 
            +
                symbolElement.textContent = DATA["fence"][kind][position][stretchLevel];
         | 
| 34 | 
            +
                parentElement.style.verticalAlign = "" + shift + "em";
         | 
| 35 | 
            +
              }
         | 
| 36 | 
            +
             | 
| 37 | 
            +
              appendStretch(contentElements, parentElement, kind, position) {
         | 
| 38 | 
            +
                let stretchElement = document.createElement("math-vstretch");
         | 
| 39 | 
            +
                let hasStart = !!DATA["fence"][kind][position]["start"];
         | 
| 40 | 
            +
                let hasEnd = !!DATA["fence"][kind][position]["end"];
         | 
| 41 | 
            +
                let hasMiddle = !!DATA["fence"][kind][position]["middle"];
         | 
| 42 | 
            +
                let startElement = null;
         | 
| 43 | 
            +
                let endElement = null;
         | 
| 44 | 
            +
                let middleElement = null;
         | 
| 45 | 
            +
                if (hasStart) {
         | 
| 46 | 
            +
                  startElement = document.createElement("math-start");
         | 
| 47 | 
            +
                  startElement.textContent = DATA["fence"][kind][position]["start"];
         | 
| 48 | 
            +
                  stretchElement.append(startElement);
         | 
| 49 | 
            +
                }
         | 
| 50 | 
            +
                if (hasMiddle) {
         | 
| 51 | 
            +
                  middleElement = document.createElement("math-middle");
         | 
| 52 | 
            +
                  middleElement.textContent = DATA["fence"][kind][position]["middle"];
         | 
| 53 | 
            +
                  stretchElement.append(middleElement);
         | 
| 54 | 
            +
                }
         | 
| 55 | 
            +
                if (hasEnd) {
         | 
| 56 | 
            +
                  endElement = document.createElement("math-end");
         | 
| 57 | 
            +
                  endElement.textContent = DATA["fence"][kind][position]["end"];
         | 
| 58 | 
            +
                  stretchElement.append(endElement);
         | 
| 59 | 
            +
                }
         | 
| 60 | 
            +
                parentElement.removeChild(parentElement.children[0]);
         | 
| 61 | 
            +
                parentElement.appendChild(stretchElement);
         | 
| 62 | 
            +
                let barSize = (hasMiddle) ? 2 : 1;
         | 
| 63 | 
            +
                let barHeight = this.calcBarHeight(contentElements, startElement, endElement, middleElement);
         | 
| 64 | 
            +
                let stretchShift = this.calcStretchShift(contentElements);
         | 
| 65 | 
            +
                for (let i = 0 ; i < barSize ; i ++) { 
         | 
| 66 | 
            +
                  let barWrapperElement = document.createElement("math-barwrap");
         | 
| 67 | 
            +
                  let barElement = document.createElement("math-bar");
         | 
| 68 | 
            +
                  barElement.textContent = DATA["fence"][kind][position]["bar"];
         | 
| 69 | 
            +
                  barWrapperElement.style.height = "" + barHeight + "em";
         | 
| 70 | 
            +
                  barWrapperElement.append(barElement);
         | 
| 71 | 
            +
                  if (i == 0) {
         | 
| 72 | 
            +
                    stretchElement.insertBefore(barWrapperElement, stretchElement.children[(hasStart) ? 1 : 0]);
         | 
| 73 | 
            +
                  } else {
         | 
| 74 | 
            +
                    stretchElement.insertBefore(barWrapperElement, stretchElement.children[(hasStart) ? 3 : 2]);
         | 
| 75 | 
            +
                  }
         | 
| 76 | 
            +
                }
         | 
| 77 | 
            +
                stretchElement.style.verticalAlign = "" + stretchShift + "em";
         | 
| 78 | 
            +
              }
         | 
| 79 | 
            +
             | 
| 80 | 
            +
              calcKinds(element) {
         | 
| 81 | 
            +
                let leftKind = "paren";
         | 
| 82 | 
            +
                let rightKind = "paren";
         | 
| 83 | 
            +
                let centerKind = "vert";
         | 
| 84 | 
            +
                if (element.getAttribute("data-left")) {
         | 
| 85 | 
            +
                  leftKind = element.getAttribute("data-left");
         | 
| 86 | 
            +
                }
         | 
| 87 | 
            +
                if (element.getAttribute("data-right")) {
         | 
| 88 | 
            +
                  rightKind = element.getAttribute("data-right");
         | 
| 89 | 
            +
                }
         | 
| 90 | 
            +
                if (element.getAttribute("data-center")) {
         | 
| 91 | 
            +
                  centerKind = element.getAttribute("data-center");
         | 
| 92 | 
            +
                }
         | 
| 93 | 
            +
                return [leftKind, rightKind, centerKind];
         | 
| 94 | 
            +
              }
         | 
| 95 | 
            +
             | 
| 96 | 
            +
              calcMaxStretchLevel(kind, position) {
         | 
| 97 | 
            +
                let keys = Object.keys(DATA["fence"][kind][position]);
         | 
| 98 | 
            +
                let maxStretchLevel = 0;
         | 
| 99 | 
            +
                for (let key of keys) {
         | 
| 100 | 
            +
                  if (key.match(/^\d+$/) && parseInt(key) > maxStretchLevel) {
         | 
| 101 | 
            +
                    maxStretchLevel = parseInt(key);
         | 
| 102 | 
            +
                  }
         | 
| 103 | 
            +
                }
         | 
| 104 | 
            +
                return maxStretchLevel;
         | 
| 105 | 
            +
              }
         | 
| 106 | 
            +
             | 
| 107 | 
            +
              calcWholeHeight(elements) {
         | 
| 108 | 
            +
                let upperHeights = [];
         | 
| 109 | 
            +
                let lowerHeights = [];
         | 
| 110 | 
            +
                for (let element of elements) {
         | 
| 111 | 
            +
                  upperHeights.push(this.getUpperHeight(element));
         | 
| 112 | 
            +
                  lowerHeights.push(this.getLowerHeight(element));
         | 
| 113 | 
            +
                }
         | 
| 114 | 
            +
                let maxUpperHeight = Math.max(...upperHeights);
         | 
| 115 | 
            +
                let maxLowerHeight = Math.max(...lowerHeights);
         | 
| 116 | 
            +
                return maxUpperHeight + maxLowerHeight;
         | 
| 117 | 
            +
              }
         | 
| 118 | 
            +
             | 
| 119 | 
            +
              calcStretchLevel(elements, kind, position) {
         | 
| 120 | 
            +
                let heightAbs = this.calcWholeHeight(elements) * 1000;
         | 
| 121 | 
            +
                let maxStretchLevel = this.calcMaxStretchLevel(kind, position);
         | 
| 122 | 
            +
                let stretchLevel = null;
         | 
| 123 | 
            +
                for (let i = 0 ; i <= maxStretchLevel ; i ++) {
         | 
| 124 | 
            +
                  if (heightAbs <= 1059 + 242 * i) {
         | 
| 125 | 
            +
                    stretchLevel = i;
         | 
| 126 | 
            +
                    break;
         | 
| 127 | 
            +
                  }
         | 
| 128 | 
            +
                }
         | 
| 129 | 
            +
                if (stretchLevel == null && !DATA["fence"][kind][position]["bar"]) {
         | 
| 130 | 
            +
                  stretchLevel = maxStretchLevel;
         | 
| 131 | 
            +
                }
         | 
| 132 | 
            +
                return stretchLevel;
         | 
| 133 | 
            +
              }
         | 
| 134 | 
            +
             | 
| 135 | 
            +
              calcShift(elements, stretchLevel) {
         | 
| 136 | 
            +
                let shift = this.calcWholeHeight(elements) / 2 - Math.max(...elements.map((element) => this.getLowerHeight(element)));
         | 
| 137 | 
            +
                if (stretchLevel == 0) {
         | 
| 138 | 
            +
                  shift = 0;
         | 
| 139 | 
            +
                }
         | 
| 140 | 
            +
                return shift;
         | 
| 141 | 
            +
              }
         | 
| 142 | 
            +
             | 
| 143 | 
            +
              calcBarHeight(elements, startElement, endElement, middleElement) {
         | 
| 144 | 
            +
                let wholeHeight = this.calcWholeHeight(elements);
         | 
| 145 | 
            +
                let startHeight = (startElement) ? this.getHeight(startElement) : 0;
         | 
| 146 | 
            +
                let endHeight = (endElement) ? this.getHeight(endElement) : 0;
         | 
| 147 | 
            +
                let middleHeight = (middleElement) ? this.getHeight(middleElement) : 0;
         | 
| 148 | 
            +
                let height = wholeHeight - startHeight - endHeight - middleHeight;
         | 
| 149 | 
            +
                if (middleElement) {
         | 
| 150 | 
            +
                  height = height / 2;
         | 
| 151 | 
            +
                }
         | 
| 152 | 
            +
                if (height < 0) {
         | 
| 153 | 
            +
                  height = 0;
         | 
| 154 | 
            +
                }
         | 
| 155 | 
            +
                return height;
         | 
| 156 | 
            +
              }
         | 
| 157 | 
            +
             | 
| 158 | 
            +
              calcStretchShift(elements) {
         | 
| 159 | 
            +
                let shift = Math.max(...elements.map((element) => this.getUpperHeight(element))) - 0.95;
         | 
| 160 | 
            +
                return shift;
         | 
| 161 | 
            +
              }
         | 
| 162 | 
            +
             | 
| 163 | 
            +
            }
         | 
| @@ -0,0 +1,172 @@ | |
| 1 | 
            +
            //
         | 
| 2 | 
            +
             | 
| 3 | 
            +
             | 
| 4 | 
            +
            class Modifier {
         | 
| 5 | 
            +
             | 
| 6 | 
            +
              modify() {
         | 
| 7 | 
            +
                console.info("[Zotica] Start");
         | 
| 8 | 
            +
                let startDate = new Date();
         | 
| 9 | 
            +
                let elements = [];
         | 
| 10 | 
            +
                elements.push(...document.querySelectorAll("math-subsup"));
         | 
| 11 | 
            +
                elements.push(...document.querySelectorAll("math-underover"));
         | 
| 12 | 
            +
                elements.push(...document.querySelectorAll("math-rad.mod"));
         | 
| 13 | 
            +
                elements.push(...document.querySelectorAll("math-fence.mod"));
         | 
| 14 | 
            +
                elements.push(...document.querySelectorAll("math-diagram"));
         | 
| 15 | 
            +
                elements.push(...document.querySelectorAll("math-step"));
         | 
| 16 | 
            +
                elements = elements.sort((first, second) => {
         | 
| 17 | 
            +
                  return this.getDepth(second) - this.getDepth(first);
         | 
| 18 | 
            +
                });
         | 
| 19 | 
            +
                elements.forEach((element) => {
         | 
| 20 | 
            +
                  let name = element.localName;
         | 
| 21 | 
            +
                  if (name == "math-subsup") {
         | 
| 22 | 
            +
                    SubsuperModifier.execute(element);
         | 
| 23 | 
            +
                  } else if (name == "math-underover") {
         | 
| 24 | 
            +
                    UnderoverModifier.execute(element);
         | 
| 25 | 
            +
                    if (element.classList.contains("wid") && element.classList.contains("mod")) {
         | 
| 26 | 
            +
                      WideModifier.execute(element);
         | 
| 27 | 
            +
                    }
         | 
| 28 | 
            +
                  } else if (name == "math-rad") {
         | 
| 29 | 
            +
                    RadicalModifier.execute(element);
         | 
| 30 | 
            +
                  } else if (name == "math-fence") {
         | 
| 31 | 
            +
                    FenceModifier.execute(element);
         | 
| 32 | 
            +
                  } else if (name == "math-diagram") {
         | 
| 33 | 
            +
                    DiagramModifier.execute(element);
         | 
| 34 | 
            +
                  } else if (name == "math-step") {
         | 
| 35 | 
            +
                    TreeModifier.execute(element);
         | 
| 36 | 
            +
                  }
         | 
| 37 | 
            +
                });
         | 
| 38 | 
            +
                let finishDate = new Date();
         | 
| 39 | 
            +
                let elapsedTime = ((finishDate - startDate) / 1000).toFixed(4);
         | 
| 40 | 
            +
                console.info("[Zotica] Finish (" + elements.length + " elements, " + elapsedTime + " seconds)");
         | 
| 41 | 
            +
              }
         | 
| 42 | 
            +
             | 
| 43 | 
            +
              modifyDebug() {
         | 
| 44 | 
            +
                document.querySelectorAll("debug").forEach((element) => {
         | 
| 45 | 
            +
                  let modifier = new Modifier();
         | 
| 46 | 
            +
                  modifier.renderDebug(element);
         | 
| 47 | 
            +
                });
         | 
| 48 | 
            +
              }
         | 
| 49 | 
            +
             | 
| 50 | 
            +
              getFontSize(element) {
         | 
| 51 | 
            +
                let fontSizeString = window.getComputedStyle(element).fontSize;
         | 
| 52 | 
            +
                let fontSize = parseFloat(fontSizeString);
         | 
| 53 | 
            +
                return fontSize;
         | 
| 54 | 
            +
              }
         | 
| 55 | 
            +
             | 
| 56 | 
            +
              getWidthPx(element) {
         | 
| 57 | 
            +
                let width = element.getBoundingClientRect().width;
         | 
| 58 | 
            +
                return width;
         | 
| 59 | 
            +
              }
         | 
| 60 | 
            +
             | 
| 61 | 
            +
              getWidth(element, fontElement) {
         | 
| 62 | 
            +
                let width = this.getWidthPx(element) / this.getFontSize(fontElement || element);
         | 
| 63 | 
            +
                return width;
         | 
| 64 | 
            +
              }
         | 
| 65 | 
            +
             | 
| 66 | 
            +
              getHeightPx(element) {
         | 
| 67 | 
            +
                let height = element.getBoundingClientRect().height;
         | 
| 68 | 
            +
                return height;
         | 
| 69 | 
            +
              }
         | 
| 70 | 
            +
             | 
| 71 | 
            +
              getHeight(element, fontElement) {
         | 
| 72 | 
            +
                let height = this.getHeightPx(element) / this.getFontSize(fontElement || element);
         | 
| 73 | 
            +
                return height;
         | 
| 74 | 
            +
              }
         | 
| 75 | 
            +
             | 
| 76 | 
            +
              getLowerHeightPx(element) {
         | 
| 77 | 
            +
                let bottom = element.getBoundingClientRect().bottom + window.pageYOffset;
         | 
| 78 | 
            +
                let locator = document.createElement("math-sys-locator");
         | 
| 79 | 
            +
                element.appendChild(locator);
         | 
| 80 | 
            +
                locator.style.verticalAlign = "baseline";
         | 
| 81 | 
            +
                let baselineBottom = locator.getBoundingClientRect().bottom + window.pageYOffset;
         | 
| 82 | 
            +
                let height = bottom - baselineBottom + this.getFontSize(element) * 0.3;
         | 
| 83 | 
            +
                element.removeChild(locator);
         | 
| 84 | 
            +
                return height;
         | 
| 85 | 
            +
              }
         | 
| 86 | 
            +
             | 
| 87 | 
            +
              getLowerHeight(element, fontElement) {
         | 
| 88 | 
            +
                let height = this.getLowerHeightPx(element) / this.getFontSize(fontElement || element);
         | 
| 89 | 
            +
                return height;
         | 
| 90 | 
            +
              }
         | 
| 91 | 
            +
             | 
| 92 | 
            +
              getUpperHeightPx(element) {
         | 
| 93 | 
            +
                let height = this.getHeightPx(element) - this.getLowerHeightPx(element);
         | 
| 94 | 
            +
                return height;
         | 
| 95 | 
            +
              }
         | 
| 96 | 
            +
             | 
| 97 | 
            +
              getUpperHeight(element, fontElement) {
         | 
| 98 | 
            +
                let height = this.getHeight(element, fontElement) - this.getLowerHeight(element, fontElement);
         | 
| 99 | 
            +
                return height;
         | 
| 100 | 
            +
              }
         | 
| 101 | 
            +
             | 
| 102 | 
            +
              getOffsetLeft(element, fontElement) {
         | 
| 103 | 
            +
                let offset = element.offsetLeft / this.getFontSize(fontElement || element);
         | 
| 104 | 
            +
                return offset;
         | 
| 105 | 
            +
              }
         | 
| 106 | 
            +
             | 
| 107 | 
            +
              getOffsetRight(element, fontElement) {
         | 
| 108 | 
            +
                let offset = (element.offsetParent.offsetWidth - element.offsetLeft - element.offsetWidth) / this.getFontSize(fontElement || element);
         | 
| 109 | 
            +
                return offset;
         | 
| 110 | 
            +
              }
         | 
| 111 | 
            +
             | 
| 112 | 
            +
              getDepth(element) {
         | 
| 113 | 
            +
                let depth = 0;
         | 
| 114 | 
            +
                if (element.zoticaDepth != undefined) {
         | 
| 115 | 
            +
                  depth = element.zoticaDepth;
         | 
| 116 | 
            +
                } else {
         | 
| 117 | 
            +
                  let parent = element.parentNode;
         | 
| 118 | 
            +
                  if (parent) {
         | 
| 119 | 
            +
                    depth = this.getDepth(parent) + 1;
         | 
| 120 | 
            +
                  } else {
         | 
| 121 | 
            +
                    depth = 0;
         | 
| 122 | 
            +
                  }
         | 
| 123 | 
            +
                }
         | 
| 124 | 
            +
                element.zoticaDepth = depth;
         | 
| 125 | 
            +
                return depth;
         | 
| 126 | 
            +
              }  
         | 
| 127 | 
            +
             | 
| 128 | 
            +
              findChild(element, name) {
         | 
| 129 | 
            +
                return Array.from(element.children).find((child) => child.localName == name);
         | 
| 130 | 
            +
              }
         | 
| 131 | 
            +
             | 
| 132 | 
            +
              findChildren(element, name) {
         | 
| 133 | 
            +
                return Array.from(element.children).filter((child) => child.localName == name);
         | 
| 134 | 
            +
              }
         | 
| 135 | 
            +
             | 
| 136 | 
            +
              renderDebug(element) {
         | 
| 137 | 
            +
                let clientRect = element.getBoundingClientRect();
         | 
| 138 | 
            +
                let scrollOffset = window.pageYOffset;
         | 
| 139 | 
            +
                let lowerHeight = this.getLowerHeightPx(element);
         | 
| 140 | 
            +
                let upperHeight = this.getUpperHeightPx(element);
         | 
| 141 | 
            +
                let line = document.createElement("div");
         | 
| 142 | 
            +
                let upperBox = document.createElement("div");
         | 
| 143 | 
            +
                let lowerBox = document.createElement("div");
         | 
| 144 | 
            +
                line.style.position = "absolute";
         | 
| 145 | 
            +
                line.style.borderTop = "1px #FF000088 solid";
         | 
| 146 | 
            +
                line.style.width = "" + clientRect.width + "px";
         | 
| 147 | 
            +
                line.style.height = "1px";
         | 
| 148 | 
            +
                line.style.top = "" + (clientRect.bottom - lowerHeight + scrollOffset) + "px";
         | 
| 149 | 
            +
                line.style.left = "" + clientRect.left + "px";
         | 
| 150 | 
            +
                lowerBox.style.position = "absolute";
         | 
| 151 | 
            +
                lowerBox.style.backgroundColor = "#FFFF0033";
         | 
| 152 | 
            +
                lowerBox.style.width = "" + clientRect.width + "px";
         | 
| 153 | 
            +
                lowerBox.style.height = "" + lowerHeight + "px";
         | 
| 154 | 
            +
                lowerBox.style.top = "" + (clientRect.top + upperHeight + scrollOffset) + "px";
         | 
| 155 | 
            +
                lowerBox.style.left = "" + clientRect.left + "px";
         | 
| 156 | 
            +
                upperBox.style.position = "absolute";
         | 
| 157 | 
            +
                upperBox.style.backgroundColor = "#FF000033";
         | 
| 158 | 
            +
                upperBox.style.width = "" + clientRect.width + "px";
         | 
| 159 | 
            +
                upperBox.style.height = "" + upperHeight + "px";
         | 
| 160 | 
            +
                upperBox.style.top = "" + (clientRect.top + scrollOffset) + "px";
         | 
| 161 | 
            +
                upperBox.style.left = "" + clientRect.left + "px";
         | 
| 162 | 
            +
                document.body.appendChild(line);
         | 
| 163 | 
            +
                document.body.appendChild(lowerBox);
         | 
| 164 | 
            +
                document.body.appendChild(upperBox);
         | 
| 165 | 
            +
              }
         | 
| 166 | 
            +
             | 
| 167 | 
            +
              static execute(element) {
         | 
| 168 | 
            +
                let modifier = new this();
         | 
| 169 | 
            +
                modifier.modify(element);
         | 
| 170 | 
            +
              }
         | 
| 171 | 
            +
             | 
| 172 | 
            +
            }
         | 
| @@ -0,0 +1,43 @@ | |
| 1 | 
            +
            //
         | 
| 2 | 
            +
             | 
| 3 | 
            +
             | 
| 4 | 
            +
            class RadicalModifier extends Modifier {
         | 
| 5 | 
            +
             | 
| 6 | 
            +
              modify(element) {
         | 
| 7 | 
            +
                let squareElement = this.findChild(element, "math-sqrt");
         | 
| 8 | 
            +
                let indexElement = this.findChild(element, "math-index");
         | 
| 9 | 
            +
                let surdElement = this.findChild(squareElement, "math-surd");
         | 
| 10 | 
            +
                let contentElement = this.findChild(squareElement, "math-cont");
         | 
| 11 | 
            +
                let surdSymbolElement = surdElement.children[0];
         | 
| 12 | 
            +
                let stretchLevel = this.calcStretchLevel(contentElement);
         | 
| 13 | 
            +
                surdSymbolElement.textContent = DATA["radical"][stretchLevel];
         | 
| 14 | 
            +
                if (indexElement) {
         | 
| 15 | 
            +
                  this.modifyIndex(element, indexElement);
         | 
| 16 | 
            +
                }
         | 
| 17 | 
            +
              }
         | 
| 18 | 
            +
             | 
| 19 | 
            +
              modifyIndex(element, indexElement) {
         | 
| 20 | 
            +
                let width = this.getWidth(indexElement);
         | 
| 21 | 
            +
                let fontRatio = this.getFontSize(element) / this.getFontSize(indexElement);
         | 
| 22 | 
            +
                if (width / fontRatio < 0.5) {
         | 
| 23 | 
            +
                  let margin = 0.5 * fontRatio - width;
         | 
| 24 | 
            +
                  indexElement.style.marginLeft = "" + margin + "em";
         | 
| 25 | 
            +
                }
         | 
| 26 | 
            +
              }
         | 
| 27 | 
            +
             | 
| 28 | 
            +
              calcStretchLevel(element) {
         | 
| 29 | 
            +
                let heightAbs = this.getHeight(element) * 1000;
         | 
| 30 | 
            +
                let stretchLevel = null;
         | 
| 31 | 
            +
                for (let i = 0 ; i <= 3 ; i ++) {
         | 
| 32 | 
            +
                  if (heightAbs <= DATA["radical"]["height"][i]) {
         | 
| 33 | 
            +
                    stretchLevel = i;
         | 
| 34 | 
            +
                    break;
         | 
| 35 | 
            +
                  }
         | 
| 36 | 
            +
                }
         | 
| 37 | 
            +
                if (stretchLevel == null) {
         | 
| 38 | 
            +
                  stretchLevel = 3;
         | 
| 39 | 
            +
                }
         | 
| 40 | 
            +
                return stretchLevel;
         | 
| 41 | 
            +
              }
         | 
| 42 | 
            +
             | 
| 43 | 
            +
            }
         | 
| @@ -0,0 +1,90 @@ | |
| 1 | 
            +
            //
         | 
| 2 | 
            +
             | 
| 3 | 
            +
             | 
| 4 | 
            +
            class SubsuperModifier extends Modifier {
         | 
| 5 | 
            +
             | 
| 6 | 
            +
              modify(element) {
         | 
| 7 | 
            +
                let baseElement = this.findChild(element, "math-base");
         | 
| 8 | 
            +
                let subElement = this.findChild(element, "math-sub");
         | 
| 9 | 
            +
                let superElement = this.findChild(element, "math-sup");
         | 
| 10 | 
            +
                let leftSubElement = this.findChild(element, "math-lsub");
         | 
| 11 | 
            +
                let leftSuperElement = this.findChild(element, "math-lsup");
         | 
| 12 | 
            +
                this.modifySide(element, baseElement, subElement, superElement, "right");
         | 
| 13 | 
            +
                this.modifySide(element, baseElement, leftSubElement, leftSuperElement, "left");
         | 
| 14 | 
            +
              }
         | 
| 15 | 
            +
             | 
| 16 | 
            +
              modifySide(element, baseElement, subElement, superElement, side) {
         | 
| 17 | 
            +
                let bothShifts = this.calcBothShifts(baseElement, subElement, superElement);
         | 
| 18 | 
            +
                let subShift = bothShifts.sub;
         | 
| 19 | 
            +
                let superShift = bothShifts.super;
         | 
| 20 | 
            +
                let subMargin = 0;
         | 
| 21 | 
            +
                let superMargin = (subElement) ? -this.getWidth(subElement) : 0;
         | 
| 22 | 
            +
                let subWidth = (subElement) ? this.getWidth(subElement) : 0;
         | 
| 23 | 
            +
                let superWidth = (superElement) ? this.getWidth(superElement) : 0;
         | 
| 24 | 
            +
                if (side == "right" && element.classList.contains("int")) {
         | 
| 25 | 
            +
                  let slope = (element.classList.contains("inl")) ? 0.3 : 0.6
         | 
| 26 | 
            +
                  subWidth -= slope;
         | 
| 27 | 
            +
                  subMargin -= slope;
         | 
| 28 | 
            +
                  if (subElement) {
         | 
| 29 | 
            +
                    superMargin += slope;
         | 
| 30 | 
            +
                  }
         | 
| 31 | 
            +
                }
         | 
| 32 | 
            +
                if (subElement) {
         | 
| 33 | 
            +
                  subElement.style.verticalAlign = "" + subShift + "em";
         | 
| 34 | 
            +
                  subElement.style.marginLeft = "" + subMargin + "em";
         | 
| 35 | 
            +
                }
         | 
| 36 | 
            +
                if (superElement) {
         | 
| 37 | 
            +
                  superElement.style.verticalAlign = "" + superShift + "em";
         | 
| 38 | 
            +
                  superElement.style.marginLeft = "" + superMargin + "em";
         | 
| 39 | 
            +
                }
         | 
| 40 | 
            +
                if (side == "right" && superElement && subWidth > superWidth) {
         | 
| 41 | 
            +
                  superElement.style.width = "" + subWidth + "em";
         | 
| 42 | 
            +
                }
         | 
| 43 | 
            +
                if (side == "left" && subElement && superWidth > subWidth) {
         | 
| 44 | 
            +
                  subElement.style.width = "" + superWidth + "em";
         | 
| 45 | 
            +
                }
         | 
| 46 | 
            +
              }
         | 
| 47 | 
            +
             | 
| 48 | 
            +
              calcBothShifts(baseElement, subElement, superElement) {
         | 
| 49 | 
            +
                let subShift = (subElement) ? this.calcSubShift(baseElement, subElement) : 0;
         | 
| 50 | 
            +
                let superShift = (superElement) ? this.calcSuperShift(baseElement, superElement) : 0;
         | 
| 51 | 
            +
                if (subElement && superElement) {
         | 
| 52 | 
            +
                  let subHeight = this.getHeight(subElement);
         | 
| 53 | 
            +
                  let gap = -subShift + superShift - subHeight;
         | 
| 54 | 
            +
                  if (gap < 0.2) {
         | 
| 55 | 
            +
                    subShift -= (0.2 - gap) / 2;
         | 
| 56 | 
            +
                    superShift += (0.2 - gap) / 2;
         | 
| 57 | 
            +
                  }
         | 
| 58 | 
            +
                }
         | 
| 59 | 
            +
                return {sub: subShift, super: superShift};
         | 
| 60 | 
            +
              }
         | 
| 61 | 
            +
             | 
| 62 | 
            +
              calcSubShift(baseElement, subElement) {
         | 
| 63 | 
            +
                let fontRatio = this.getFontSize(baseElement) / this.getFontSize(subElement);
         | 
| 64 | 
            +
                let height = this.getLowerHeight(baseElement);
         | 
| 65 | 
            +
                if (height < 0.4875) {
         | 
| 66 | 
            +
                  height = 0.4875;
         | 
| 67 | 
            +
                }
         | 
| 68 | 
            +
                let shiftConst = -0.25;
         | 
| 69 | 
            +
                if (baseElement.parentNode.classList.contains("int") && !baseElement.parentNode.classList.contains("inl")) {
         | 
| 70 | 
            +
                  shiftConst = -0.15;
         | 
| 71 | 
            +
                }
         | 
| 72 | 
            +
                let shift = (height + shiftConst) * fontRatio;
         | 
| 73 | 
            +
                return -shift;
         | 
| 74 | 
            +
              }
         | 
| 75 | 
            +
             | 
| 76 | 
            +
              calcSuperShift(baseElement, superElement) {
         | 
| 77 | 
            +
                let fontRatio = this.getFontSize(baseElement) / this.getFontSize(superElement);
         | 
| 78 | 
            +
                let height = this.getUpperHeight(baseElement);
         | 
| 79 | 
            +
                if (height < 0.5125) {
         | 
| 80 | 
            +
                  height = 0.5125;
         | 
| 81 | 
            +
                }
         | 
| 82 | 
            +
                let shiftConst = -0.2;
         | 
| 83 | 
            +
                if (baseElement.parentNode.classList.contains("int") && !baseElement.parentNode.classList.contains("inl")) {
         | 
| 84 | 
            +
                  shiftConst = -0.1;
         | 
| 85 | 
            +
                }
         | 
| 86 | 
            +
                let shift = (height + shiftConst) * fontRatio;
         | 
| 87 | 
            +
                return shift;
         | 
| 88 | 
            +
              }
         | 
| 89 | 
            +
             | 
| 90 | 
            +
            }
         |