Selection API Example

This second example illustrates the use of the rich text editing functionality provided by the cueInterface object's selection property:

class TextModification extends HTMLElement {
  constructor() {
    super();

    this.attachShadow({ mode: 'open' });
    this.shadowRoot.innerHTML = `
      <style>
        :host { width: 100%; display: block; } /* Styles the web component tag */
        h1 {
          color: #9c9c9c;
          font-size: 24px;
          font-weight: 300;
        }
        button {
          display: block;
          font-size: 16px;
          font-family: "Hind", Helvetica Neue, Helvetica, Arial, Sans-serif;
          line-height: 32px;
          height: 32px;
          text-align: center;
          border: none;
          border-radius: 3px;
          background-color: #d3d3d3;
          color: #444444;
          cursor: pointer;
          padding: 0 10px;
          margin-bottom: 10px;
        }
        button:disabled {
          background-color: #efefef;
          color: #999999;
          pointer-events: none;
        }
        button:hover {
          background-color: #efefef;
        }
      </style>

      <h1>Text Modification</h1>
      <button class="character-tag">Insert Character Tag</button>
      <button class="macro-tag">Insert Macro Tag</button>
      <button class="em-dash">Insert Em dash</button>
      <button class="queen">Insert ♕</button>
    `;
  }

  connectedCallback() {
    if (this.cueInterface.selection) {
      this.addButtonEventListeners();
      this.selection = this.cueInterface.selection.getCurrentSelection();
      this.cueInterface.selection.addSelectionWatcher(newSelection => {
        this.selection = newSelection;
        this.setButtonStates(!!newSelection);
      });
    }
    this.setButtonStates(!!this.selection);
  }

  addButtonEventListeners() {
    this.addCharacterTagEventListener();
    this.addMacroTagEventListener();
    this.addEmDashEventListener();
    this.addQueenEventListener();
  }

  addCharacterTagEventListener() {
    const button = this.shadowRoot.querySelector('.character-tag');
    $(button).on('click', () => {
      if (this.selection.rangeCount) {
        this.cueInterface.selection.forEachBlockInSelection(this.selection.getRangeAt(0), element => {
          this.cueInterface.selection.replaceElement(element, 'span', 'quote_attrib');
        });
      }

    });
  }

  addMacroTagEventListener() {
    const button = this.shadowRoot.querySelector('.macro-tag');
    $(button).on('click', () => {
      this.cueInterface.selection.replaceSelection('<span class="cci-codes">&lt;extra_leading&gt;</span>', this.selection);
    });
  }

  addEmDashEventListener() {
    const button = this.shadowRoot.querySelector('.em-dash');
    $(button).on('click', () => {
      this.cueInterface.selection.replaceSelection('—', this.selection);
    });
  }

  addQueenEventListener() {
    const button = this.shadowRoot.querySelector('.queen');
    $(button).on('click', () => {
      this.cueInterface.selection.replaceSelection('♕', this.selection);
    });
  }

  setButtonStates(enabled) {
    const buttonSelectors = ['.character-tag', '.macro-tag', '.em-dash', '.queen'];

    _.forEach(buttonSelectors, selector => {
      const button = this.shadowRoot.querySelector(selector);
      $(button).prop('disabled', !enabled);
    });
  }
}
customElements.define('text-modification', TextModification);


class TextModificationIcon extends HTMLElement {
  constructor() {
    super();

    this.attachShadow({ mode: 'open' });
    this.shadowRoot.innerHTML = `
          <style>
            :host { margin: 0; padding: 2px; display: block; } /* Styles the web component icon tag */
            .icon:before {
              font: 16px 'cf';
              font-style: normal;
              font-weight: normal;
              color: #444444;
              content: '\\e8a6';
              -webkit-font-smoothing: antialiased;
              -moz-osx-font-smoothing: grayscale;
            }
            .icon.active:before {
              color: #09ab00;
            }
          </style>

          <span class="icon"></span>
        `;
  }

  connectedCallback() {
    this.activeStateChanged(this.cueInterface.active);
    this.cueInterface.addActiveWatcher(active => {
      this.activeStateChanged(active);
    });
  }

  activeStateChanged(active) {
    const icon = this.shadowRoot.querySelector('.icon');
    if (active) {
      $(icon).addClass('active');
    }
    else {
      $(icon).removeClass('active');
    }
  }
}
customElements.define('text-modification-icon', TextModificationIcon);