js truncate

by AntowaKartowa

HTML

<div class="container">
  <div class="block">
    <label class="heading">Enter result limitations</label>
    <div class="subblock">
      <label for="width" class="left">Width</label>
      <input type="number" name="width" id="width" class="width" max="999" min="0" value="300">
      <span>px</span>
    </div>
    <div class="subblock">
      <label for="rows" class="left">Rows</label>
      <input type="number" name="rows" id="rows" class="rows" max="20" min="0" value="3">
    </div>
  </div>

  <div class="block">
    <label for="input" class="heading">Enter text</label>
    <textarea name="input" id="input" cols="40" rows="5" class="input">Lorem ipsum dolor sit amet, consectetur adipisicing elit. Totam veniam nulla, quam nobis facere corporis autem ullam ratione, explicabo ab officia rem, repellendus facilis. Dignissimos ad, dolore odit aliquam voluptatem.</textarea>
    <button class="truncate">Truncate</button>
  </div>

  <div class="block">
    <label for="output" class="heading">Result</label>
    <div id="output" class="output">
    </div>
  </div>
</div>

CSS

body {
  padding: 0 20px;
  background-color: #fff;
}

.container {
  width: 400px;
  padding: 20px 50px 50px;
  margin: 50px auto;
  background-color: cornsilk;
}

.block,
.subblock,
.heading,
.truncate,
.input {
  display: block;
  margin-bottom: 8px;
}

.heading {
  margin-bottom: 10px;
}

.block {
  margin-top: 30px;
}

.left {
  display: inline-block;
  width: 70px;
}

.width,
.rows {
  width: 50px;
}

.input {
  padding: 0;
  font-family: Helvetica, Arial, sans-serif;
  font-size: 12px;
  line-height: 1.3em;
  background-color: aliceblue;
  border-color: transparent;
  outline: none;
}

.output {
  position: relative;
  width: 300px;
  padding: 0;
  font-family: Helvetica, Arial, sans-serif;
  font-size: 12px;
  line-height: 1.3em;
  max-height: 3.9em;
  background-color: mistyrose;
}

#measure {
  position: absolute;
  top: 0;
  opcity: 0;
  z-index: -1;
}

JavaScript

class Truncate {
	constructor({width, rows, input, button, output}) {
  	if (!this._isDOMElement(output)) throw new Error("Output parameter should be link to DOM element");

    this._outputEl = output;
    this._width = 300;
    this.__width = parseInt(width.value, 10) || 300;
    this._rows = 3;
    this.__rows = parseInt(rows.value, 10) || 3;
    this._text = "";
    this.__text = input.value;
    
    this._markedup = "";
    this._breaksOffset = [];
    
    width.addEventListener("blur", this._widthBlurHandler.bind(this));
    rows.addEventListener("blur", this._rowsBlurHandler.bind(this));
    ["change", "blur"].forEach(e => input.addEventListener(e, this._textChangeHandler.bind(this)));
    button.addEventListener("click", this.calcTruncation.bind(this));
  }
  
    
  _isDOMElement(o) {
    if (typeof HTMLElement === "object") {
    	return o instanceof HTMLElement;
    } else {
    	return o && typeof o === "object" 
      	&& o !== null 
        && o.nodeType === 1 
        && typeof o.nodeName === "string"
    }
  }
  
  _widthBlurHandler(e) {
  	e = e || window.event;
    this.updateWidth(e.target.value);
  }
  
  updateWidth(width=300) {
  	this.__width = parseInt(width, 10);
  }
  
  _rowsBlurHandler(e) {
  	e = e || window.event;
    this.updateRows(e.target.value);
  }
  
  updateRows(rows=3) {
  	this.__rows = parseInt(rows, 10);
  }
  
  _textChangeHandler(e) {
  	e = e || window.event;
    this.updateText(e.target.value);
  }
  
  updateText(text) {
  	this.__text = text;
  }
  
  _isPropsChanged() {
  	return this._isTextChanged() || this._isSizeChanged();
  }
  
  _isTextChanged() {
  	return this.__text !== this._text;
  }
  
  _isSizeChanged() {
  	return this.__width !== this._width || this.__rows !== this._rows;
  }
  
  _isNoMeasures() {
   return !this._mHeight || !this._m2Width;
  }
  
  calcTruncation(ev, text, width, rows) {
  	text && this.updateText(text);
  	width && this.updateWidth(width || this.__width);
    rows &&...