diff --git a/src/index.js b/src/index.js index 70fd8e5..9100ac7 100644 --- a/src/index.js +++ b/src/index.js @@ -1,186 +1,114 @@ -/** - * Build styles - */ -import './index.css'; -import { IconMarker } from '@codexteam/icons' - -/** - * Marker Tool for the Editor.js - * - * Allows to wrap inline fragment and style it somehow. - */ - export default class Marker { - /** - * Class name for term-tag - * - * @type {string} - */ - static get CSS() { - return 'cdx-marker'; - }; - - /** - * @param {{api: object}} - Editor.js API - */ - constructor({api}) { - this.api = api; +export default class Marker { - /** - * Toolbar Button - * - * @type {HTMLElement|null} - */ - this.button = null; + static get isInline() { + return true; + } - /** - * Tag represented the term - * - * @type {string} - */ - this.tag = 'MARK'; + get state() { + return this._state; + } - /** - * CSS classes - */ - this.iconClasses = { - base: this.api.styles.inlineToolButton, - active: this.api.styles.inlineToolButtonActive - }; + set state(state) { + this._state = state; + + this.button.classList.toggle(this.api.styles.inlineToolButtonActive, state); } - /** - * Specifies Tool as Inline Toolbar Tool - * - * @return {boolean} - */ - static get isInline() { - return true; + constructor({api}) { + this.api = api; + this.button = null; + this._state = false; + + this.tag = 'MARK'; + this.class = 'cdx-marker'; } - /** - * Create button element for Toolbar - * - * @return {HTMLElement} - */ render() { this.button = document.createElement('button'); this.button.type = 'button'; - this.button.classList.add(this.iconClasses.base); - this.button.innerHTML = this.toolboxIcon; + this.button.innerHTML = ''; + this.button.classList.add(this.api.styles.inlineToolButton); return this.button; } - /** - * Wrap/Unwrap selected fragment - * - * @param {Range} range - selected fragment - */ surround(range) { - if (!range) { + if (this.state) { + this.unwrap(range); return; } - let termWrapper = this.api.selection.findParentTag(this.tag, Marker.CSS); - - /** - * If start or end of selection is in the highlighted block - */ - if (termWrapper) { - this.unwrap(termWrapper); - } else { - this.wrap(range); - } + this.wrap(range); } - /** - * Wrap selection with term-tag - * - * @param {Range} range - selected fragment - */ wrap(range) { - /** - * Create a wrapper for highlighting - */ - let marker = document.createElement(this.tag); - - marker.classList.add(Marker.CSS); - - /** - * SurroundContent throws an error if the Range splits a non-Text node with only one of its boundary points - * @see {@link https://developer.mozilla.org/en-US/docs/Web/API/Range/surroundContents} - * - * // range.surroundContents(span); - */ - marker.appendChild(range.extractContents()); - range.insertNode(marker); - - /** - * Expand (add) selection to highlighted block - */ - this.api.selection.expandToTag(marker); + const selectedText = range.extractContents(); + const mark = document.createElement(this.tag); + + mark.classList.add(this.class); + mark.appendChild(selectedText); + range.insertNode(mark); + + this.api.selection.expandToTag(mark); } - /** - * Unwrap term-tag - * - * @param {HTMLElement} termWrapper - term wrapper tag - */ - unwrap(termWrapper) { - /** - * Expand selection to all term-tag - */ - this.api.selection.expandToTag(termWrapper); - - let sel = window.getSelection(); - let range = sel.getRangeAt(0); - - let unwrappedContent = range.extractContents(); - - /** - * Remove empty term-tag - */ - termWrapper.parentNode.removeChild(termWrapper); - - /** - * Insert extracted content - */ - range.insertNode(unwrappedContent); - - /** - * Restore selection - */ - sel.removeAllRanges(); - sel.addRange(range); + unwrap(range) { + const mark = this.api.selection.findParentTag(this.tag, this.class); + const text = range.extractContents(); + + mark.remove(); + + range.insertNode(text); } - /** - * Check and change Term's state for current selection - */ + checkState() { - const termTag = this.api.selection.findParentTag(this.tag, Marker.CSS); + const mark = this.api.selection.findParentTag(this.tag); - this.button.classList.toggle(this.iconClasses.active, !!termTag); + this.state = !!mark; + + if (this.state) { + this.showActions(mark); + } else { + this.hideActions(); + } } - /** - * Get Tool icon's SVG - * @return {string} - */ - get toolboxIcon() { - return IconMarker; + renderActions() { + this.colorPicker = document.createElement('input'); + this.colorPicker.type = 'color'; + this.colorPicker.value = '#f5f1cc'; + this.colorPicker.hidden = true; + + return this.colorPicker; } - /** - * Sanitizer rule - * @return {{mark: {class: string}}} - */ - static get sanitize() { - return { - mark: { - class: Marker.CSS - } + showActions(mark) { + const {backgroundColor} = mark.style; + this.colorPicker.value = backgroundColor ? this.convertToHex(backgroundColor) : '#f5f1cc'; + + this.colorPicker.onchange = () => { + mark.style.backgroundColor = this.colorPicker.value; }; + this.colorPicker.hidden = false; + } + + hideActions() { + this.colorPicker.onchange = null; + this.colorPicker.hidden = true; } -} + convertToHex(color) { + const rgb = color.match(/(\d+)/g); + + let hexr = parseInt(rgb[0]).toString(16); + let hexg = parseInt(rgb[1]).toString(16); + let hexb = parseInt(rgb[2]).toString(16); + + hexr = hexr.length === 1 ? '0' + hexr : hexr; + hexg = hexg.length === 1 ? '0' + hexg : hexg; + hexb = hexb.length === 1 ? '0' + hexb : hexb; + + return '#' + hexr + hexg + hexb; + } +} \ No newline at end of file