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"><extra_leading></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);