upfront-editable
Version:
Friendly contenteditable API
126 lines (98 loc) • 4.92 kB
JavaScript
;
var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
var _typeof = require("@babel/runtime/helpers/typeof");
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.insertRangeBoundaryMarker = insertRangeBoundaryMarker;
exports.setRangeBoundary = setRangeBoundary;
exports.save = save;
exports.restore = restore;
var _rangy = _interopRequireDefault(require("rangy"));
var _error = _interopRequireDefault(require("./util/error"));
var nodeType = _interopRequireWildcard(require("./node-type"));
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; }
/**
* Inspired by the Selection save and restore module for Rangy by Tim Down
* Saves and restores ranges using invisible marker elements in the DOM.
*/
var boundaryMarkerId = 0; // (U+FEFF) zero width no-break space
var markerTextChar = "\uFEFF";
function insertRangeBoundaryMarker(range, atStart) {
var container = range.commonAncestorContainer; // If ownerDocument is null the commonAncestorContainer is window.document
if (container.ownerDocument === null || container.ownerDocument === undefined) {
(0, _error["default"])('Cannot save range: range is emtpy');
} // Clone the Range and collapse to the appropriate boundary point
var boundaryRange = range.cloneRange();
boundaryRange.collapse(atStart); // Create the marker element containing a single
// invisible character using DOM methods and insert it
var doc = container.ownerDocument.defaultView.document;
var markerEl = doc.createElement('span');
markerEl.id = "editable-range-boundary-".concat(++boundaryMarkerId);
markerEl.setAttribute('data-editable', 'remove');
markerEl.style.lineHeight = '0';
markerEl.style.display = 'none';
markerEl.appendChild(doc.createTextNode(markerTextChar));
boundaryRange.insertNode(markerEl);
return markerEl;
}
function setRangeBoundary(host, range, markerId, atStart) {
var markerEl = getMarker(host, markerId);
if (!markerEl) return console.log('Marker element has been removed. Cannot restore selection.');
range[atStart ? 'setStartBefore' : 'setEndBefore'](markerEl);
markerEl.remove();
}
function save(range) {
var rangeInfo, startEl, endEl; // insert markers
if (range.collapsed) {
endEl = insertRangeBoundaryMarker(range, false);
rangeInfo = {
markerId: endEl.id,
collapsed: true
};
} else {
endEl = insertRangeBoundaryMarker(range, false);
startEl = insertRangeBoundaryMarker(range, true);
rangeInfo = {
startMarkerId: startEl.id,
endMarkerId: endEl.id,
collapsed: false
};
} // Adjust each range's boundaries to lie between its markers
if (range.collapsed) {
range.collapseBefore(endEl);
} else {
range.setEndBefore(endEl);
range.setStartAfter(startEl);
}
return rangeInfo;
}
function restore(host, rangeInfo) {
if (rangeInfo.restored) return;
var range = _rangy["default"].createRange();
if (rangeInfo.collapsed) {
var markerEl = getMarker(host, rangeInfo.markerId);
if (markerEl) {
markerEl.style.display = 'inline';
var previousNode = markerEl.previousSibling; // Workaround for rangy issue 17
if (previousNode && previousNode.nodeType === nodeType.textNode) {
markerEl.remove();
range.collapseToPoint(previousNode, previousNode.length);
} else {
range.collapseBefore(markerEl);
markerEl.remove();
}
} else {
console.log('Marker element has been removed. Cannot restore selection.');
}
} else {
setRangeBoundary(host, range, rangeInfo.startMarkerId, true);
setRangeBoundary(host, range, rangeInfo.endMarkerId, false);
}
range.normalizeBoundaries();
return range;
}
function getMarker(host, id) {
return host.querySelector("#".concat(id));
}