medium-editor
Version:
Medium.com WYSIWYG editor clone.
129 lines (103 loc) • 4.67 kB
JavaScript
(function () {
'use strict';
var Placeholder = MediumEditor.Extension.extend({
name: 'placeholder',
/* Placeholder Options */
/* text: [string]
* Text to display in the placeholder
*/
text: 'Type your text',
/* hideOnClick: [boolean]
* Should we hide the placeholder on click (true) or when user starts typing (false)
*/
hideOnClick: true,
init: function () {
MediumEditor.Extension.prototype.init.apply(this, arguments);
this.initPlaceholders();
this.attachEventHandlers();
},
initPlaceholders: function () {
this.getEditorElements().forEach(this.initElement, this);
},
handleAddElement: function (event, editable) {
this.initElement(editable);
},
initElement: function (el) {
if (!el.getAttribute('data-placeholder')) {
el.setAttribute('data-placeholder', this.text);
}
this.updatePlaceholder(el);
},
destroy: function () {
this.getEditorElements().forEach(this.cleanupElement, this);
},
handleRemoveElement: function (event, editable) {
this.cleanupElement(editable);
},
cleanupElement: function (el) {
if (el.getAttribute('data-placeholder') === this.text) {
el.removeAttribute('data-placeholder');
}
},
showPlaceholder: function (el) {
if (el) {
// https://github.com/yabwe/medium-editor/issues/234
// In firefox, styling the placeholder with an absolutely positioned
// pseudo element causes the cursor to appear in a bad location
// when the element is completely empty, so apply a different class to
// style it with a relatively positioned pseudo element
if (MediumEditor.util.isFF && el.childNodes.length === 0) {
el.classList.add('medium-editor-placeholder-relative');
el.classList.remove('medium-editor-placeholder');
} else {
el.classList.add('medium-editor-placeholder');
el.classList.remove('medium-editor-placeholder-relative');
}
}
},
hidePlaceholder: function (el) {
if (el) {
el.classList.remove('medium-editor-placeholder');
el.classList.remove('medium-editor-placeholder-relative');
}
},
updatePlaceholder: function (el, dontShow) {
// If the element has content, hide the placeholder
if (el.querySelector('img, blockquote, ul, ol, table') || (el.textContent.replace(/^\s+|\s+$/g, '') !== '')) {
return this.hidePlaceholder(el);
}
if (!dontShow) {
this.showPlaceholder(el);
}
},
attachEventHandlers: function () {
if (this.hideOnClick) {
// For the 'hideOnClick' option, the placeholder should always be hidden on focus
this.subscribe('focus', this.handleFocus.bind(this));
}
// If the editor has content, it should always hide the placeholder
this.subscribe('editableInput', this.handleInput.bind(this));
// When the editor loses focus, check if the placeholder should be visible
this.subscribe('blur', this.handleBlur.bind(this));
// Need to know when elements are added/removed from the editor
this.subscribe('addElement', this.handleAddElement.bind(this));
this.subscribe('removeElement', this.handleRemoveElement.bind(this));
},
handleInput: function (event, element) {
// If the placeholder should be hidden on focus and the
// element has focus, don't show the placeholder
var dontShow = this.hideOnClick && (element === this.base.getFocusedElement());
// Editor's content has changed, check if the placeholder should be hidden
this.updatePlaceholder(element, dontShow);
},
handleFocus: function (event, element) {
// Editor has focus, hide the placeholder
this.hidePlaceholder(element);
},
handleBlur: function (event, element) {
// Editor has lost focus, check if the placeholder should be shown
this.updatePlaceholder(element);
}
});
MediumEditor.extensions.placeholder = Placeholder;
}());