upfront-editable
Version:
Friendly contenteditable API
164 lines (136 loc) • 6.38 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 _rangy = _interopRequireDefault(require("rangy"));
var parser = _interopRequireWildcard(require("./parser"));
var _rangeContainer = _interopRequireDefault(require("./range-container"));
var _cursor = _interopRequireDefault(require("./cursor"));
var _selection = _interopRequireDefault(require("./selection"));
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; }
/**
* The SelectionWatcher module watches for selection changes inside
* of editable blocks.
*
* @module core
* @submodule selectionWatcher
*/
var SelectionWatcher = /*#__PURE__*/function () {
function SelectionWatcher(dispatcher, win) {
(0, _classCallCheck2["default"])(this, SelectionWatcher);
this.dispatcher = dispatcher;
this.win = win || window;
this.rangySelection = undefined;
this.currentSelection = undefined;
this.currentRange = undefined;
}
/**
* Updates the internal selection pointer to the current rangy selection.
* Returns true if no exception occurred.
*/
(0, _createClass2["default"])(SelectionWatcher, [{
key: "syncSelection",
value: function syncSelection() {
// it is possible that rangy has a problem with the nativeSelection
try {
this.rangySelection = _rangy["default"].getSelection(this.win);
} catch (err) {
return false;
}
return true;
}
/**
* Return a RangeContainer if the current selection is within an editable
* otherwise return an empty RangeContainer
*/
}, {
key: "getRangeContainer",
value: function getRangeContainer() {
var successfulSync = this.syncSelection(); // rangeCount is 0 or 1 in all browsers except firefox
// firefox can work with multiple ranges
// (on a mac hold down the command key to select multiple ranges)
if (this.rangySelection.rangeCount && successfulSync) {
var range = this.rangySelection.getRangeAt(0);
var hostNode = parser.getHost(range.commonAncestorContainer);
if (hostNode) return new _rangeContainer["default"](hostNode, range);
} // return an empty range container
return new _rangeContainer["default"]();
}
/**
* Gets a fresh RangeContainer with the current selection or cursor.
*
* @return RangeContainer instance
*/
}, {
key: "getFreshRange",
value: function getFreshRange() {
return this.getRangeContainer();
}
/**
* Gets a fresh RangeContainer with the current selection or cursor.
*
* @return Either a Cursor or Selection instance or undefined if
* there is neither a selection or cursor.
*/
}, {
key: "getFreshSelection",
value: function getFreshSelection() {
var range = this.getRangeContainer();
return range.isCursor ? range.getCursor(this.win) : range.getSelection(this.win);
}
/**
* Get the selection set by the last selectionChanged event.
* Sometimes the event does not fire fast enough and the selection
* you get is not the one the user sees.
* In those cases use #getFreshSelection()
*
* @return Either a Cursor or Selection instance or undefined if
* there is neither a selection or cursor.
*/
}, {
key: "getSelection",
value: function getSelection() {
return this.currentSelection;
}
}, {
key: "forceCursor",
value: function forceCursor() {
var range = this.getRangeContainer();
return range.forceCursor();
}
}, {
key: "selectionChanged",
value: function selectionChanged() {
var newRange = this.getRangeContainer();
if (newRange.isDifferentFrom(this.currentRange)) {
var lastSelection = this.currentSelection;
this.currentRange = newRange; // empty selection or cursor
if (lastSelection) {
if (lastSelection.isCursor && !this.currentRange.isCursor) {
this.dispatcher.notify('cursor', lastSelection.host);
} else if (lastSelection.isSelection && !this.currentRange.isSelection) {
this.dispatcher.notify('selection', lastSelection.host);
}
} // set new selection or cursor and fire event
if (this.currentRange.isCursor) {
this.currentSelection = new _cursor["default"](this.currentRange.host, this.currentRange.range);
this.dispatcher.notify('cursor', this.currentSelection.host, this.currentSelection);
} else if (this.currentRange.isSelection) {
this.currentSelection = new _selection["default"](this.currentRange.host, this.currentRange.range);
this.dispatcher.notify('selection', this.currentSelection.host, this.currentSelection);
} else {
this.currentSelection = undefined;
}
}
}
}]);
return SelectionWatcher;
}();
exports["default"] = SelectionWatcher;
module.exports = exports.default;