From 5b2f6d6fd45986d19f1f6648d3c98ca142b0a39c Mon Sep 17 00:00:00 2001 From: Christian Harke Date: Tue, 25 Jul 2017 14:28:27 +0200 Subject: [PATCH 1/2] Use MutationObserver --- lib/react-contenteditable.js | 19 +++++++++++++++++-- src/react-contenteditable.js | 15 +++++++++++++-- 2 files changed, 30 insertions(+), 4 deletions(-) diff --git a/lib/react-contenteditable.js b/lib/react-contenteditable.js index dc8480c..19e3688 100644 --- a/lib/react-contenteditable.js +++ b/lib/react-contenteditable.js @@ -22,6 +22,8 @@ function _possibleConstructorReturn(self, call) { if (!self) { throw new Referen function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; } +var OBSERVER_CONFIG = { childList: true, subtree: true, characterData: true }; + var ContentEditable = function (_React$Component) { _inherits(ContentEditable, _React$Component); @@ -48,12 +50,21 @@ var ContentEditable = function (_React$Component) { ref: function ref(e) { return _this2.htmlEl = e; }, - onInput: this.emitChange, onBlur: this.props.onBlur || this.emitChange, contentEditable: !this.props.disabled, dangerouslySetInnerHTML: { __html: html } }), this.props.children); } + }, { + key: 'componentDidMount', + value: function componentDidMount() { + var _this3 = this; + + this.observer = new MutationObserver(function (mutations) { + mutations.forEach(_this3.emitChange); + }); + this.observer.observe(this.htmlEl, OBSERVER_CONFIG); + } }, { key: 'shouldComponentUpdate', value: function shouldComponentUpdate(nextProps) { @@ -79,13 +90,17 @@ var ContentEditable = function (_React$Component) { this.htmlEl.innerHTML = this.props.html; } } + }, { + key: 'componentWillUnmount', + value: function componentWillUnmount() { + this.observer.disconnect(); + } }, { key: 'emitChange', value: function emitChange(evt) { if (!this.htmlEl) return; var html = this.htmlEl.innerHTML; if (this.props.onChange && html !== this.lastHtml) { - evt.target = { value: html }; this.props.onChange(evt); } this.lastHtml = html; diff --git a/src/react-contenteditable.js b/src/react-contenteditable.js index fde368b..20afc62 100644 --- a/src/react-contenteditable.js +++ b/src/react-contenteditable.js @@ -1,5 +1,7 @@ import React from 'react'; +const OBSERVER_CONFIG = { childList: true, subtree: true, characterData: true }; + export default class ContentEditable extends React.Component { constructor() { super(); @@ -14,7 +16,6 @@ export default class ContentEditable extends React.Component { { ...props, ref: (e) => this.htmlEl = e, - onInput: this.emitChange, onBlur: this.props.onBlur || this.emitChange, contentEditable: !this.props.disabled, dangerouslySetInnerHTML: {__html: html} @@ -22,6 +23,13 @@ export default class ContentEditable extends React.Component { this.props.children); } + componentDidMount() { + this.observer = new MutationObserver((mutations) => { + mutations.forEach(this.emitChange); + }); + this.observer.observe(this.htmlEl, OBSERVER_CONFIG); + } + shouldComponentUpdate(nextProps) { // We need not rerender if the change of props simply reflects the user's // edits. Rerendering in this case would make the cursor/caret jump. @@ -46,11 +54,14 @@ export default class ContentEditable extends React.Component { } } + componentWillUnmount() { + this.observer.disconnect(); + } + emitChange(evt) { if (!this.htmlEl) return; var html = this.htmlEl.innerHTML; if (this.props.onChange && html !== this.lastHtml) { - evt.target = { value: html }; this.props.onChange(evt); } this.lastHtml = html; From c4782519f33248b60042616c49495b3eb0bba869 Mon Sep 17 00:00:00 2001 From: Christian Harke Date: Wed, 26 Jul 2017 10:17:50 +0200 Subject: [PATCH 2/2] Pass the html to onChange --- lib/react-contenteditable.js | 1 + src/react-contenteditable.js | 1 + 2 files changed, 2 insertions(+) diff --git a/lib/react-contenteditable.js b/lib/react-contenteditable.js index 19e3688..77c6f19 100644 --- a/lib/react-contenteditable.js +++ b/lib/react-contenteditable.js @@ -101,6 +101,7 @@ var ContentEditable = function (_React$Component) { if (!this.htmlEl) return; var html = this.htmlEl.innerHTML; if (this.props.onChange && html !== this.lastHtml) { + evt.target.value = html; this.props.onChange(evt); } this.lastHtml = html; diff --git a/src/react-contenteditable.js b/src/react-contenteditable.js index 20afc62..1ecbe30 100644 --- a/src/react-contenteditable.js +++ b/src/react-contenteditable.js @@ -62,6 +62,7 @@ export default class ContentEditable extends React.Component { if (!this.htmlEl) return; var html = this.htmlEl.innerHTML; if (this.props.onChange && html !== this.lastHtml) { + evt.target.value = html; this.props.onChange(evt); } this.lastHtml = html;