upfront-editable
Version:
Friendly contenteditable API
186 lines (159 loc) • 6.85 kB
JavaScript
;
var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
var _typeof = require("@babel/runtime/helpers/typeof");
Object.defineProperty(exports, "__esModule", {
value: true
});
exports["default"] = createDefaultBehavior;
var parser = _interopRequireWildcard(require("./parser"));
var content = _interopRequireWildcard(require("./content"));
var _log = _interopRequireDefault(require("./util/log"));
var block = _interopRequireWildcard(require("./block"));
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 Behavior module defines the behavior triggered in response to the Editable.JS
* events (see {{#crossLink "Editable"}}{{/crossLink}}).
* The behavior can be overwritten by a user with Editable.init() or on
* Editable.add() per element.
*
* @module core
* @submodule behavior
*/
function createDefaultBehavior(editable) {
var document = editable.win.document;
/**
* Factory for the default behavior.
* Provides default behavior of the Editable.JS API.
*
* @static
*/
return {
focus: function focus(element) {
// Add a <br> element if the editable is empty to force it to have height
// E.g. Firefox does not render empty block elements and most browsers do
// not render empty inline elements.
if (!parser.isVoid(element)) return;
var br = document.createElement('br');
br.setAttribute('data-editable', 'remove');
element.appendChild(br);
},
blur: function blur(element) {
content.cleanInternals(element);
},
selection: function selection(element, _selection) {
(0, _log["default"])(_selection ? 'Default selection behavior' : 'Default selection empty behavior');
},
cursor: function cursor(element, _cursor) {
(0, _log["default"])(_cursor ? 'Default cursor behavior' : 'Default cursor empty behavior');
},
newline: function newline(element, cursor) {
if (cursor.isAtTextEnd()) {
var trailingBr = document.createElement('br');
trailingBr.setAttribute('data-editable', 'remove');
cursor.insertBefore(trailingBr);
} else {
cursor.insertBefore(document.createElement('br'));
}
cursor.setVisibleSelection();
},
insert: function insert(element, direction, cursor) {
var parent = element.parentNode;
var newElement = element.cloneNode(false);
if (newElement.id) newElement.removeAttribute('id');
switch (direction) {
case 'before':
parent.insertBefore(newElement, element);
element.focus();
break;
case 'after':
parent.insertBefore(newElement, element.nextSibling);
newElement.focus();
break;
}
},
split: function split(element, before, after, cursor) {
var newNode = element.cloneNode(false);
newNode.appendChild(before);
var parent = element.parentNode;
parent.insertBefore(newNode, element);
while (element.firstChild) {
element.removeChild(element.firstChild);
}
element.appendChild(after);
content.tidyHtml(newNode);
content.tidyHtml(element);
element.focus();
},
merge: function merge(element, direction, cursor) {
var container, merger;
switch (direction) {
case 'before':
container = block.previous(element);
merger = element;
break;
case 'after':
container = element;
merger = block.next(element);
break;
}
if (!(container && merger)) return;
cursor = container.childNodes.length > 0 ? editable.appendTo(container, merger.innerHTML) : editable.prependTo(container, merger.innerHTML); // remove merged node
merger.remove();
cursor.save();
content.tidyHtml(container);
cursor.restore();
cursor.setVisibleSelection();
},
empty: function empty(element) {
(0, _log["default"])('Default empty behavior');
},
"switch": function _switch(element, direction, cursor) {
switch (direction) {
case 'before':
var previous = block.previous(element);
if (previous) {
cursor.moveAtTextEnd(previous);
cursor.setVisibleSelection();
}
break;
case 'after':
var next = block.next(element);
if (next) {
cursor.moveAtBeginning(next);
cursor.setVisibleSelection();
}
break;
}
},
move: function move(element, selection, direction) {
(0, _log["default"])('Default move behavior');
},
paste: function paste(element, blocks, cursor) {
if (blocks.length === 0) return;
cursor.insertBefore(blocks.shift());
if (blocks.length === 0) return cursor.setVisibleSelection();
var parent = element.parentNode;
var currentElement = element;
blocks.forEach(function (str) {
var newElement = element.cloneNode(false);
if (newElement.id) newElement.removeAttribute('id');
var fragment = content.createFragmentFromString(str);
newElement.appendChild(fragment);
parent.insertBefore(newElement, currentElement.nextSibling);
currentElement = newElement;
}); // focus last element
editable.createCursorAtEnd(currentElement).setVisibleSelection();
},
clipboard: function clipboard(element, action, cursor) {
(0, _log["default"])('Default clipboard behavior');
},
toggleBold: function toggleBold(selection) {
selection.toggleBold();
},
toggleEmphasis: function toggleEmphasis(selection) {
selection.toggleEmphasis();
}
};
}
module.exports = exports.default;