Caret-Position und Auswahlhöhe für Inline-Elemente in Chrome

8

Ich möchte einen Editor mit Slate oder ProseMirror erstellen und bei Verwendung eines Inline-Elements ein merkwürdiges Verhalten mit Chrome um die Caret-Position und den Auswahlbereich feststellen . Problem 1 ist im ersten Bild unten dargestellt. Wenn sich die Position des Textcursors hinter dem "f" befindet, wird das Caret oben im Bild angezeigt. Problem 2 befindet sich im zweiten Bild. Wenn Sie den Text auswählen, wird ein hervorgehobener Bereich angezeigt, der so hoch ist wie im inline-Element. Gibt es eine Möglichkeit, dieses Verhalten zu steuern und stattdessen das Caret an der Position des Textes anzuzeigen und nur den Raum um den Text hervorzuheben (auch wenn das Inline-Bild die Zeilenhöhe vergrößert)? Caret Position zu hoch Auswahlbereich zu groß

Ich möchte das Verhalten hier von Firefox nachahmen: Geben Sie hier die Bildbeschreibung ein Geben Sie hier die Bildbeschreibung ein

Beispielbilder wurden mit der ProseMirror-Demo hier erstellt: https://prosemirror.net/examples/basic/

Ein minimales Beispiel (danke @Kaiido) mit JSBin :

<div contenteditable>Test text<img src="https://upload.wikimedia.org/wikipedia/en/9/9b/Yoda_Empire_Strikes_Back.png">Testing</div>

Ich bin mir nicht sicher, wie sich dies unter anderen Betriebssystemen verhält, aber ich verwende macOS Catalina.

mowwwalker
quelle
2
... Sie könnten mit just ein minimal reproduzierbares Beispiel machen <div contenteditable>Test text<img src="https://upload.wikimedia.org/wikipedia/en/9/9b/Yoda_Empire_Strikes_Back.png">Testing</div>. Nun, so machen sie es, es gibt derzeit keine Spezifikationen, so dass sie ziemlich frei sind, das zu tun, was sie für das Beste halten. Benötigen Sie diese Bibliotheken unbedingt oder reicht Ihnen eine Rohlösung?
Kaiido
1
Nur eine Bemerkung: TinyMCE scheint sich in Chrome ziemlich ähnlich zu verhalten, außer dass es das Caret auf die Bildhöhe ausdehnt.
V.Volkov
danke @Kaiido, wird in die Frage aufgenommen.
Mowwwalker
Ich denke, es hängt mit dem Betriebssystem zusammen. Ich sehe das gleiche Verhalten bei V.Volkov, das gerade in Chrome auf dem Mac beschrieben wurde.
Dekel

Antworten:

4

Sie können das Auswahlproblem mithilfe der Flexbox beheben. Ich habe ursprünglich versucht, zu verwenden, align-items: flex-endaber ich bekam ein seltsames Verhalten der Pfeiltasten. align-items: baselinescheint ab sofort zu funktionieren.

Das Bildproblem ist sehr seltsam. Mir ist aufgefallen, dass Chrome SVG-Elemente anders als IMG-Elemente überschreitet. Ab sofort "wartet" die neueste Version von Chrome vor dem Überspringen von IMG, ermöglicht es dem Benutzer jedoch, ein SVG wie jedes andere Zeichen zu überspringen (der linke Pfeil überspringt das Zeichen, das dem SVG am nächsten liegt). Dies kann durch zugrunde liegende Standardstile verursacht werden, aber ich weiß es nicht.

Ich wollte gerade meine Ergebnisse veröffentlichen, stellte jedoch fest, dass Firefox nicht gleich funktionierte. Firefox hat bei Verwendung von SVG und / oder Flexbox ein wirklich seltsames Verhalten der Pfeiltasten. Der Cursor bewegt sich über dem Bild, jedoch nur, wenn Sie die rechte Pfeiltaste drücken.

Firefox funktioniert jedoch problemlos mit einem normalen IMG-Element.

Kurz gesagt, Sie müssen je nach Browser verschiedene Bildelemente rendern.

// chrome contenteditable ads spaces between spans.
// firefox does not, so you have to add them manually.
if (navigator.userAgent.indexOf("Firefox") > 0) {
  Array.from(document.querySelectorAll('#editable span')).forEach(el => {
    el.innerHTML += " "
  })
}
.flexit {
  display: flex;
  align-items: baseline;
  flex-wrap: wrap;
}

span {
 display: inline-block;
 white-space: pre;
}

.img-wrapper, .img-wrapper + span {
display: inline;
}
<!DOCTYPE html>
<html>

<head>
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width">
  <title>JS Bin</title>
</head>

<body>
  <h1>chrome</h1>
  <div contenteditable="true" class="flexit">
    <span>test</span><svg width="200" height="200" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">       
  <image href="https://mdn.mozillademos.org/files/6457/mdn_logo_only_color.png" height="200" width="200"/>
    </svg><span>Here</span><span>is</span><span>a</span><span>longer</span><span>sentence.</span><span>Notice</span><span>I</span><span>wrapped</span><span>each</span><span>word</span><span>in</span><span>a</span><span>span.</span><span>This</span><span>makes</span><span>the</span><span>text</span><span>appear</span><span>like</span><span>it</span><span>is</span><span>inline.</span>
  </div>

  <h1>firefox</h1>
  <div contenteditable="true" id="editable">
    <span>test</span><span class="img-wrapper"><img src="https://mdn.mozillademos.org/files/6457/mdn_logo_only_color.png" height="200" width="200" /></span><span>test</span><span>Here</span><span>is</span><span>a</span><span>longer</span><span>sentence.</span><span>Notice</span><span>I</span><span>wrapped</span><span>each</span><span>word</span><span>in</span><span>a</span><span>span.</span><span>This</span><span>makes</span><span>the</span><span>text</span><span>appear</span><span>like</span><span>it</span><span>is</span><span>inline.</span>


  </div>
</body>

</html>

PS Viele Editoren habe ich standardmäßig für Bilder in voller Breite verwendet.

Bearbeiten: Ich habe gerade festgestellt, dass meine Firefox-Lösung anscheinend auch in der neuesten Version von Chrome funktioniert. Ich denke, das funktioniert, weil ich die Textknoten in SPAN-Elemente eingeschlossen habe. Das SVG-Element funktioniert in Chrome immer noch anders, aber das Umschließen von Text in SPAN scheint die meisten Probleme zu lösen.

wizardzeb
quelle
Tolle Arbeit!! Der Aufbau aus , dass, versuchte ich das svg in einem Putting spanmit contenteditable="false"und das scheint die Arbeit an Chrome und Firefox! jsbin.com/xosasuruni/edit?html,output
mowwwalker
Ah, ich denke nicht, dass display: flexes funktionieren wird, da jetzt der Text in jedem Element nicht Teil derselben Zeile ist. Wenn der Text in einem der Elemente zu lang ist, wird der andere Text nicht
verschoben
@mowwwalker Sie können Elemente in die nächste Zeile flex-wrap: wrap;
einbinden lassen
0

Bearbeiten Sie zunächst nicht das ProseMirror-DOM wie im JQuery-Beispiel gezeigt. Tatsächlich werden Sie höchstwahrscheinlich auf DOM- oder Inhaltsprobleme stoßen. ProseMirror verwendet einen eigenen DOM-Knoten und ein eigenes Markup-Schema. Wenn Sie das ProseMirror-DOM bearbeiten oder ein Plugin hinzufügen möchten, schauen Sie sich die Markup-, Plugin- und Node-Apis an. Ich habe ein einfaches Beispiel für Textausrichtungs-Markup-Code angehängt. Nebenbei bemerkt, der Grund, warum Grammarly und andere keine ProseMirror-Plugins haben, ist der DOM-Ansatz / die DOM-Modelle. Ich sollte hinzufügen, dass ProseMirror sehr gut ist, aber um ehrlich zu sein, ist es eher eine fortschrittliche Entwicklerlösung.

Abgesehen davon sind die guten Nachrichten die Probleme, die Sie haben, ein reines CSS. ProseMirror entfernt alle Klassen und setzt das DOM / CSS zurück. Wenn Sie also ein Dokument importieren oder alle / die meisten ausschneiden und einfügen, sind Ihre Klassen verschwunden.

Der einfachste Lösungsansatz besteht darin, den Editor in ein Div zu verpacken und dem Div eine Klasse zuzuweisen und dieser Klasse dann Stile und untergeordnete Stile hinzuzufügen. Der Grund für den Wrap ist, dass die CSS-Selektoren wie img, p, h usw. nur für die Tags innerhalb der Editor-Klasse gelten. Ohne das kommt es zu offensichtlichen CSS-Konflikten.

CSS

  1. Verwenden Sie Flexbox nicht für Inline-Bilder, da Flexbox kein Rastersystem ist. Wenn ich mich recht erinnere, können Sie keine direkten Kinder des Flex-Containers inline.
  2. Inline auf p-Tags und img wird keinen Text umbrechen und Sie werden mit den oben aufgeführten Problemen enden.
  3. Wenn Sie das Cursorproblem, das Sie haben, wirklich umbrechen und entfernen möchten, müssen Sie Floats verwenden, z. B. float: left;(empfohlener Ansatz)
  4. Fügen Sie kleine oder große Polster und Rahmenboxen hinzu, um das Zusammenfallen von Kanten zu erleichtern und um Bild und Text voneinander zu trennen
  5. Das Cursorproblem besteht darin, dass Sie innerhalb des Bildblocks, der vertikal nach oben ausgerichtet ist und mit dem Sie das Problem beheben können, vertical-align: baseline;jedoch ohne Gleitkommazahlen, immer noch einen Cursor haben, der der Höhe des Bildes und nicht dem Text entspricht. Wenn Sie keine Floats verwenden, wird der Cursor verlängert, da die Linienhöhe praktisch der Höhe des Bildes entspricht. Die blaue Farbe ist nur eine Auswahl, die Sie auch mit CSS ändern.
<html>
    <div class="editor">
        <!--        <editor></editor>-->
    </div>
</html>

<style>
    .editor {
        position: relative;
        display: block;
        padding: 10px;
    }

    .editor p {
        font-weight: 400;
        font-size: 1rem;
        font-family: Roboto, Arial, serif;
        color: #777777;
        display: inline;
        vertical-align: baseline;
    }

    .editor img {
        width: 50px;
        float: left;
        padding: 20px;
    }

</style>

Beispiel für eine Knotenerweiterung

Beispiel für eine Knotenerweiterung für die Textausrichtung, die als Symbolleiste hinzugefügt werden kann. Viel längerer Beitrag, aber selbst wenn Sie einen Knoten / ein Plugin für Bilder erstellt haben, müssen Sie sich mit der Art und Weise auseinandersetzen, in der es rendert, dh base64 versus url usw., was übrigens durchaus Sinn macht, warum sie das getan haben, aber fügen Sie einfach hinzu Komplexität für Entwickler, die nach SEO usw. suchen

export default class Paragraph extends Node {
    get name() {
        return 'paragraph';
    }

    get defaultOptions() {
        return {
            textAlign: ['left', 'center', 'right'],
        }
    }

    inputRules({ type }) {
        return [
            markInputRule(/(?:\*\*|__)([^*_]+)(?:\*\*|__)$/, type),
        ]
    }

    get schema() {
        return {
            attrs: {
                textAlign: {
                    default: 'left'
                }
            },
            content: 'inline*',
            group: 'block',
            draggable: false,
            inclusive: false,
            defining : true,
            parseDOM: [
                {
                    tag: 'p',
                    style: 'text-align',
                    getAttrs: value => value
                }
            ],

            toDOM: (node) => [ 'p', {
                style: 'text-align:' + node.attrs.textAlign,
                class: `type--base type--std text-` + node.attrs.textAlign
            }, 0 ]

        };
    }

    commands ({ type }) {
        return (attrs) => updateMark(type, attrs)
    }
}
Nolan
quelle
-2

Ich habe versucht, einen kleinen Hack mit HTML und CSS zu machen.

<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width">
<title>JS Bin</title>
</head>
<body>

<div contenteditable><p class="new1" contenteditable>Hello</p><div contenteditable> 
<img src="https://upload.wikimedia.org/wikipedia/en/9/9b/Yoda_Empire_Strikes_Back.png"></div> 
<p class="new2">Testing</p>
</div>
</body>
</html>

// CSS

.new2{


font-size:30px;
margin-top:-35px;
margin-left:252px;
padding-left:79px;
}


img{
margin-left:75px;
padding-left:5px;
padding-right:5px;
margin-top:-300px;
}

.new1{
text-overflow:hidden;
padding-top:260px;
margin-bottom:-20px;
font-size:30px;
padding-right:10px;
}

Hier ist jsfiddle https://jsfiddle.net/wtekxavm/1/

Rishabh dev Tyagi
quelle
Hmm, löst das Problem nicht wirklich, da es nur die Positionierung der Elemente fest codiert. Ty für die Antwort
mowwwalker
Bitte akzeptieren Sie dies als Antwort, wenn Ihnen meine Arbeit gefallen hat.
Rishabh dev Tyagi
Dies ist ein zu starrer Ansatz, um praktisch zu sein.
Mowwwalker
Bitte stimmen Sie mindestens ab
Rishabh dev Tyagi
1
Zu Ihrer Information, ich habe abgelehnt, weil dies angesichts Ihrer Antworten kein Versuch ist, zu helfen oder die Frage zu beantworten, sondern sich ein paar positive Stimmen zu schnappen.
Mowwwalker