upfront-editable
Version:
Friendly contenteditable API
251 lines (202 loc) • 9.33 kB
JavaScript
"use strict";
var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
var _typeof = require("@babel/runtime/helpers/typeof");
Object.defineProperty(exports, "__esModule", {
value: true
});
exports["default"] = void 0;
var _classCallCheck2 = _interopRequireDefault(require("@babel/runtime/helpers/classCallCheck"));
var _createClass2 = _interopRequireDefault(require("@babel/runtime/helpers/createClass"));
var _jquery = _interopRequireDefault(require("jquery"));
var nodeType = _interopRequireWildcard(require("./node-type"));
var content = _interopRequireWildcard(require("./content"));
var _highlightText = _interopRequireDefault(require("./highlight-text"));
var _spellcheckService = _interopRequireDefault(require("./plugins/highlighting/spellcheck-service"));
var _whitespaceHighlighting = _interopRequireDefault(require("./plugins/highlighting/whitespace-highlighting"));
var _textHighlighting = _interopRequireDefault(require("./plugins/highlighting/text-highlighting"));
var _matchCollection = _interopRequireDefault(require("./plugins/highlighting/match-collection"));
var _highlightSupport = _interopRequireDefault(require("./highlight-support"));
function _getRequireWildcardCache(nodeInterop) { if (typeof WeakMap !== "function") return null; var cacheBabelInterop = new WeakMap(); var cacheNodeInterop = new WeakMap(); return (_getRequireWildcardCache = function _getRequireWildcardCache(nodeInterop) { return nodeInterop ? cacheNodeInterop : cacheBabelInterop; })(nodeInterop); }
function _interopRequireWildcard(obj, nodeInterop) { if (!nodeInterop && obj && obj.__esModule) { return obj; } if (obj === null || _typeof(obj) !== "object" && typeof obj !== "function") { return { "default": obj }; } var cache = _getRequireWildcardCache(nodeInterop); if (cache && cache.has(obj)) { return cache.get(obj); } var newObj = {}; var hasPropertyDescriptor = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var key in obj) { if (key !== "default" && Object.prototype.hasOwnProperty.call(obj, key)) { var desc = hasPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : null; if (desc && (desc.get || desc.set)) { Object.defineProperty(newObj, key, desc); } else { newObj[key] = obj[key]; } } } newObj["default"] = obj; if (cache) { cache.set(obj, newObj); } return newObj; }
var Highlighting = /*#__PURE__*/function () {
function Highlighting(editable, configuration, spellcheckConfig) {
(0, _classCallCheck2["default"])(this, Highlighting);
this.editable = editable;
this.win = editable.win;
this.focusedEditableHost = undefined;
this.currentlyCheckedEditableHost = undefined;
this.timeout = {};
var defaultConfig = {
checkOnInit: false,
checkOnFocus: false,
checkOnChange: true,
// unbounce rate in ms before calling the spellcheck service after changes
throttle: 1000,
// remove highlights after a change if the cursor is inside a highlight
removeOnCorrection: true,
spellcheck: {
marker: '<span class="highlight-spellcheck"></span>',
throttle: 1000,
spellcheckService: function spellcheckService() {}
},
whitespace: {
marker: '<span class="highlight-whitespace"></span>'
}
};
this.config = _jquery["default"].extend(true, defaultConfig, configuration);
var spellcheckService = this.config.spellcheck.spellcheckService;
var spellcheckMarker = this.config.spellcheck.marker;
var whitespaceMarker = this.config.whitespace.marker;
var spellcheckMarkerNode = _highlightSupport["default"].createMarkerNode(spellcheckMarker, 'spellcheck', this.win);
var whitespaceMarkerNode = _highlightSupport["default"].createMarkerNode(whitespaceMarker, 'spellcheck', this.win);
this.spellcheckService = new _spellcheckService["default"](spellcheckService);
this.spellcheck = new _textHighlighting["default"](spellcheckMarkerNode);
this.whitespace = new _whitespaceHighlighting["default"](whitespaceMarkerNode);
this.setupListeners();
} // Events
// ------
(0, _createClass2["default"])(Highlighting, [{
key: "setupListeners",
value: function setupListeners() {
if (this.config.checkOnFocus) {
this.editable.on('focus', _jquery["default"].proxy(this, 'onFocus'));
this.editable.on('blur', _jquery["default"].proxy(this, 'onBlur'));
}
if (this.config.checkOnChange || this.config.removeOnCorrection) {
this.editable.on('change', _jquery["default"].proxy(this, 'onChange'));
}
if (this.config.checkOnInit) {
this.editable.on('init', _jquery["default"].proxy(this, 'onInit'));
}
}
}, {
key: "onInit",
value: function onInit(editableHost) {
this.highlight(editableHost);
}
}, {
key: "onFocus",
value: function onFocus(editableHost) {
if (this.focusedEditableHost !== editableHost) {
this.focusedEditableHost = editableHost;
this.editableHasChanged(editableHost);
}
}
}, {
key: "onBlur",
value: function onBlur(editableHost) {
if (this.focusedEditableHost === editableHost) {
this.focusedEditableHost = undefined;
}
}
}, {
key: "onChange",
value: function onChange(editableHost) {
if (this.config.checkOnChange) {
this.editableHasChanged(editableHost, this.config.throttle);
}
if (this.config.removeOnCorrection) {
this.removeHighlightsAtCursor(editableHost);
}
} // Manage Highlights
// -----------------
}, {
key: "editableHasChanged",
value: function editableHasChanged(editableHost, throttle) {
var _this = this;
if (this.timeout.id && this.timeout.editableHost === editableHost) {
clearTimeout(this.timeout.id);
}
var timeoutId = setTimeout(function () {
_this.highlight(editableHost);
_this.timeout = {};
}, throttle || 0);
this.timeout = {
id: timeoutId,
editableHost: editableHost
};
}
}, {
key: "highlight",
value: function highlight(editableHost) {
var _this2 = this;
var text = _highlightText["default"].extractText(editableHost); // getSpellcheck
this.spellcheckService.check(text, function (err, misspelledWords) {
if (err) {
return;
} // refresh the text
text = _highlightText["default"].extractText(editableHost);
var matchCollection = new _matchCollection["default"]();
var matches = _this2.spellcheck.findMatches(text, misspelledWords);
matchCollection.addMatches('spellcheck', matches);
matches = _this2.whitespace.findMatches(text);
matchCollection.addMatches('whitespace', matches);
_this2.safeHighlightMatches(editableHost, matchCollection.matches);
});
} // Calls highlightMatches internally but ensures
// that the selection stays the same
}, {
key: "safeHighlightMatches",
value: function safeHighlightMatches(editableHost, matches) {
var _this3 = this;
var selection = this.editable.getSelection(editableHost);
if (selection) {
selection.retainVisibleSelection(function () {
_this3.highlightMatches(editableHost, matches);
});
} else {
this.highlightMatches(editableHost, matches);
}
if (this.editable.dispatcher) {
this.editable.dispatcher.notify('spellcheckUpdated', editableHost);
}
}
}, {
key: "highlightMatches",
value: function highlightMatches(editableHost, matches) {
// Remove old highlights
this.removeHighlights(editableHost); // Create new highlights
if (matches && matches.length > 0) {
// const span = this.createMarkerNode()
_highlightText["default"].highlightMatches(editableHost, matches);
}
}
}, {
key: "removeHighlights",
value: function removeHighlights(editableHost) {
(0, _jquery["default"])(editableHost).find('[data-highlight="spellcheck"]').each(function (index, elem) {
content.unwrap(elem);
});
}
}, {
key: "removeHighlightsAtCursor",
value: function removeHighlightsAtCursor(editableHost) {
var selection = this.editable.getSelection(editableHost);
if (selection && selection.isCursor) {
var elementAtCursor = selection.range.startContainer;
if (elementAtCursor.nodeType === nodeType.textNode) {
elementAtCursor = elementAtCursor.parentNode;
}
var wordId;
do {
if (elementAtCursor === editableHost) return;
var highlightType = elementAtCursor.getAttribute('data-highlight');
if (highlightType === 'spellcheck') {
wordId = elementAtCursor.getAttribute('data-word-id');
break;
}
} while (elementAtCursor = elementAtCursor.parentNode);
if (wordId) {
selection.retainVisibleSelection(function () {
(0, _jquery["default"])(editableHost).find("[data-word-id=".concat(wordId, "]")).each(function (index, elem) {
content.unwrap(elem);
});
});
}
}
}
}]);
return Highlighting;
}();
exports["default"] = Highlighting;
module.exports = exports.default;