}).bind(this);
this.$editor[0].addEventListener(WCF_CLICK_EVENT, this.WoltLabCaret._handleEditorClick.bind(this));
+ this.$editor[0].addEventListener('mouseup', this.WoltLabCaret._handleEditorMouseUp.bind(this));
this.WoltLabCaret._initInternalRange();
this.caret.end(p);
},
+ _handleEditorMouseUp: function (event) {
+ var anchorNode, sibling;
+
+ var selection = window.getSelection();
+ if (!selection.isCollapsed) return;
+
+ // click occured inside the editor padding
+ if (event.target === this.$editor[0]) {
+ anchorNode = selection.anchorNode;
+ if (anchorNode.nodeType === Node.TEXT_NODE) anchorNode = anchorNode.parentNode;
+
+ // click occured before a `<kbd>` element
+ if (anchorNode.nodeName === 'KBD') {
+ sibling = anchorNode.previousSibling;
+ if (sibling === null || sibling.textContent !== '\u200b') {
+ sibling = document.createTextNode('\u200b');
+ anchorNode.parentNode.insertBefore(sibling, anchorNode);
+ }
+
+ this.caret.before(sibling);
+ }
+ }
+ else if (event.target.nodeName === 'KBD') {
+ var kbd = event.target;
+
+ // check if the user clicked on a `<kbd>` element, but the browser placed the caret to the left
+ anchorNode = selection.anchorNode;
+ if (anchorNode.nodeType === Node.TEXT_NODE) {
+ // check if the first next sibling is the `<kbd>` while skipping all empty text nodes
+ sibling = anchorNode;
+ while (sibling = sibling.nextSibling) {
+ if (sibling.nodeType !== Node.TEXT_NODE || (sibling.textContent !== '' && sibling.textContent !== '\u200b')) {
+ break;
+ }
+ }
+
+ if (sibling === kbd) {
+ if (kbd.childNodes.length === 0 || kbd.childNodes[0].textContent !== '\u200b') {
+ var textNode = document.createTextNode('\u200b');
+ kbd.insertBefore(textNode, kbd.firstChild);
+ }
+
+ var range = document.createRange();
+ range.setStartAfter(kbd.childNodes[0]);
+ range.setEndAfter(kbd.childNodes[0]);
+
+ selection.removeAllRanges();
+ selection.addRange(range);
+ }
+ }
+ }
+ },
+
_addParagraphAfterBlock: function (block) {
var nextElement = block.nextElementSibling;
if (nextElement && (nextElement.nodeName === 'P' || this.utils.isBlockTag(nextElement.nodeName))) {
.inlineCode, /* deprecated, legacy class */
kbd {
+ /* do not use inline-block, it breaks arrow key navigation in Firefox and Internet Explorer 11 */
+
+ /* update: `inline` styling breaks even more things, in particular the caret position is way off */
+ /* this reverts 8d381dc61e8183adcb770457f9fba25c29c00bd2 */
+
+ /* new update: `display: inline` + `box-decoration-break` deliver the proper visual appearance,
+ and the `::after` element in the editor is used to fix the caret position at the end */
+
background-color: rgba(255, 255, 255, 1) !important;
border: 1px solid rgba(196, 196, 196, 1) !important;
border-radius: 2px;
+ box-decoration-break: clone;
+ -webkit-box-decoration-break: clone;
color: rgba(68, 68, 68, 1) !important;
- /* do not use inline-block, it breaks arrow key navigation in Firefox and Internet Explorer 11 */
- /* update: `inline` styling breaks even more things, in particular the caret position is way off */
- /* this reverts 8d381dc61e8183adcb770457f9fba25c29c00bd2 */
- display: inline-block;
+ display: inline;
font-family: Consolas, 'Courier New', monospace;
font-style: normal;
font-weight: normal;
- margin: 1px 2px;
+ margin: 0 2px;
overflow: auto;
padding: 0 4px;
text-decoration: none;
word-break: break-all;
word-wrap: break-word;
}
+
+/* This pseudo element will cause a trailing caret to be displayed inside the element, right after
+ the last character in the `<kbd>`. Without it, browsers may render the caret either on top or
+ slightly after the right border. */
+.redactor-layer kbd::after {
+ content: " ";
+ display: inline-block;
+ pointer-events: none;
+}
+
+/* Similar to the `::after` pseudo element above, but also features an absolute positioning. This
+ has no impact on the visual appearance, but avoids the caret being displayed shifted to the bottom. */
+.redactor-layer kbd::before {
+ content: " ";
+ display: inline-block;
+ pointer-events: none;
+ position: absolute;
+}