@atlaskit/editor-plugin-placeholder-text
Version:
placeholder text plugin for @atlaskit/editor-core
84 lines (82 loc) • 2.85 kB
JavaScript
import { getBrowserInfo } from '@atlaskit/editor-common/browser';
import { ZERO_WIDTH_SPACE } from '@atlaskit/editor-common/whitespace';
import { Selection } from '@atlaskit/editor-prosemirror/state';
const serializePlaceholderNode = node => {
const element = document.createElement('span');
const browser = getBrowserInfo();
element.classList.add('pm-placeholder');
// the inline node api test suite requires the following class name
element.classList.add('placeholderView-content-wrap');
element.innerText = ZERO_WIDTH_SPACE;
const elementChildren = document.createElement('span');
elementChildren.classList.add('pm-placeholder__text');
elementChildren.dataset.placeholder = node.attrs.text;
elementChildren.setAttribute('contenteditable', 'false');
element.appendChild(elementChildren);
if (browser.safari) {
element.appendChild(document.createTextNode(ZERO_WIDTH_SPACE));
} else {
element.appendChild(document.createElement('wbr'));
}
return element;
};
export class PlaceholderTextNodeView {
constructor(node, view, getPos) {
this.node = node;
this.view = view;
this.getPos = getPos;
this.dom = serializePlaceholderNode(this.node);
this.getPos = getPos;
}
stopEvent(e) {
if (e.type === 'mousedown' && typeof this.getPos === 'function') {
e.preventDefault();
const {
view
} = this;
const startNodePosition = this.getPos();
if (typeof startNodePosition !== 'number') {
return false;
}
const tr = view.state.tr;
tr.setSelection(Selection.near(tr.doc.resolve(startNodePosition)));
view.dispatch(tr);
if (!view.hasFocus()) {
window.requestAnimationFrame(() => {
view.focus();
});
}
return true;
}
return false;
}
ignoreMutation(record) {
if (typeof this.getPos !== 'function' || record.type !== 'selection') {
return true;
}
const {
view,
node
} = this;
const placeholderStartPosition = this.getPos();
if (typeof placeholderStartPosition !== 'number') {
return false;
}
const placeholderEndPosition = placeholderStartPosition + node.nodeSize;
const selection = view.state.selection;
// when the selection is set right after the placeholder.
// we should let ProseMirror deal with this edge-case
if (selection.from === placeholderEndPosition) {
return false;
}
const isSelectionAtPlaceholder = selection.from === placeholderStartPosition;
const isSelectionAfterlaceholder = selection.from > placeholderEndPosition;
if (isSelectionAtPlaceholder || isSelectionAfterlaceholder) {
const tr = view.state.tr;
tr.setSelection(Selection.near(tr.doc.resolve(placeholderEndPosition)));
view.dispatch(tr);
return true;
}
return true;
}
}