Chromeのインライン要素のキャレットの位置と選択の高さ


8

スレートまたはProseMirrorを使用してエディターを作成し、インライン要素を使用しているときに、キャレットの位置と選択領域の周りでChromeの奇妙な動作を確認しています。問題1は、下の最初の図に示されています。テキストカーソルの位置が「f」の後ろにある場合、キャレットは画像の上部に表示されます。問題2は2番目の画像にあります。テキストを選択すると、インライン要素と同じ高さの強調表示された領域が表示されます。この動作を制御して、代わりにテキストの位置にキャレットを表示し、テキストの周囲のスペースのみを強調表示する方法はありますか(インライン画像によって行の高さが大きくなっている場合でも) キャレット位置が高すぎます 選択領域が大きすぎます

ここで、Firefoxからの動作を模倣したいと思います。 ここに画像の説明を入力してください ここに画像の説明を入力してください

ここでProseMirrorデモを使用してサンプル画像を作成しました:https ://prosemirror.net/examples/basic/

最小例(おかげで@Kaiido)とJSBin

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

これが他のオペレーティングシステムでどのように動作するかはわかりませんが、私はmacOS Catalinaを使用しています。


2
... だけで最小限の再現可能な例を作成でき<div contenteditable>Test text<img src="https://upload.wikimedia.org/wikipedia/en/9/9b/Yoda_Empire_Strikes_Back.png">Testing</div>ます。現在、それが彼らのやり方です。現在、その周りに仕様はありません。そのため、彼らは自分たちが最善だと思うことを自由に行うことができます。これらのライブラリは絶対に必要ですか、それとも生のソリューションで十分ですか?
カイイド

1
備考:TinyMCEは、キャレットを画像の高さまで伸ばすことを除いて、Chromeでの動作はかなり似ているようです。
V.Volkov

ありがとう@海道、質問に含まれます。
mowwwalker

OSに関連していると思います。MacのChromeで説明したのと同じ動作@ V.Volkovが表示されます。
デケル

回答:


4

flexboxを使用すると、選択の問題を修正できます。私は最初に使用しようとしましたalign-items: flex-endが、奇妙な矢印キーの動作をしていました。align-items: baseline現在のところ機能しているようです。

画像の問題は非常に奇妙です。ChromeはSVG要素をIMG要素とは異なる方法でステップオーバーすることに気付きました。現在のところ、Chromeの最新バージョンはIMGをスキップする前に「待機」しますが、ユーザーは他の文字と同様にSVGをスキップできます(左矢印はsvgに最も近い文字をスキップします)。これは、デフォルトのスタイルが原因である可能性がありますが、わかりません。

調査結果を投稿しようとしていましたが、Firefoxが同じように機能しないことに気付きました。Firefoxは、SVGやFlexboxを使用するときに、非常に奇妙な矢印キーの動作をします。カーソルは画像の上に移動しますが、右矢印キーを押したときのみです。

ただし、Firefoxは通常のIMG要素で問題なく動作します。

要するに、ブラウザに基づいてさまざまな画像要素をレンダリングする必要があります。

// 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私がデフォルトで全幅の画像に使用した多くのエディター。

編集:私のFirefoxソリューションは最新のChromeでも動作するようです。テキストノードをSPAN要素でラップしたので、これはうまくいくと思います。SVG要素はChromeでも動作が異なりますが、SPANでテキストをラップすることで問題のほとんどを解決できるようです。


お見事!!それを基にして、svgをspanwithに入れてみましたが、Chrome contenteditable="false"とFirefoxで動作するようです!jsbin.com/xosasuruni/edit?html,output
mowwwalker

ああdisplay: flex、各要素のテキストが同じ行の一部ではなくなったので、うまくいくとは思いません。いずれかの要素のテキストが長すぎる場合、他のテキストはプッシュされず、次の行に
折り返され

@mowwwalker要素を次の行に折り返すことができますflex-wrap: wrap;
wizardzeb

0

まず、JQueryの例に示すように、ProseMirror DOMを操作しないでください。実際、DOMまたはコンテンツの問題に遭遇する可能性が最も高くなります。ProseMirrorは独自のDOMノードとマークアップスキーマを使用します。ProseMirror DOMを操作したり、プラグインを追加したりする場合は、マークアップ、プラグイン、ノードApisをご覧ください。テキスト配置マークアップコードの簡単な例を添付しました。補足として、Grammarlyや他の人がProseMirrorプラグインを持っていない理由は、DOMのアプローチ/モデルが原因です。私はProseMirrorを追加する必要がありますが非常に良いですが、正直なところ、それはより高度な開発者向けソリューションです。

それはさておき、CSSだけの問題は朗報です。ProseMirrorはすべてのクラスを取り除き、DOM / CSSをリセットするため、ドキュメントをインポートしたり、すべてをカットアンドペーストしたりすると、ほとんどのクラスが失われます。

これを解決する最も簡単な方法は、エディターをdivでラップし、クラスをdivに割り当てて、スタイルと子スタイルをそのクラスに追加することです。ラップする理由は、img、p、hなどのcssセレクターがエディタークラス内のタグにのみ適用されるためです。それがなければ、CSSの衝突が明白になります。

CSS

  1. フレックスボックスはグリッドシステムではないため、インライン画像にはフレックスボックスを使用しないでください。実際、私が思い出すと、フレックスコンテナーの直接の子をインライン化することはできません。
  2. pタグとimgのインラインはテキストを折り返さず、上記の問題が発生します。
  3. カーソルの問題を本当にラップして削除したい場合は、フロートを使用する必要がありますfloat: left;(推奨アプローチ)
  4. 小さなまたは大きなパディングとボーダーボックスを追加して、エッジの折りたたみを支援し、画像とテキストの分離を支援
  5. 発生しているカーソルの問題は、画像ブロック内を上に垂直に配置した場合に修正できますvertical-align: baseline;が、フロートなしでは、テキストではなく画像の高さに一致するカーソルが残るためです。また、フロートを使用しない場合、行の高さが画像と実質的に同じであるため、カーソルが長くなります。青色はセレクターにすぎず、CSSを使用しても変更できます。
<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>

ノード拡張の例

ツールバーとして追加できるテキスト配置のノード拡張の例。はるかに長い投稿ですが、画像のノード/プラグインを作成した場合でも、レンダリングの方法、つまりbase64とurlなどを処理する必要があります。これらはなぜそうしたのかについては完全に理にかなっていますが、追加するだけです。 SEOなどを求める開発者にとっての複雑さ

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)
    }
}


-2

HTMLとcssを少しハックしようとしました。

<!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;
}

ここにjsfiddle https://jsfiddle.net/wtekxavm/1/があります


うーん、要素の配置をハードコードするだけなので、実際には問題を解決しません。答えはTy
mowwwalker

私の作品が気に入ったら、これを答えとして受け入れてください。
Rishabh dev Tyagi

これは、現実的ではないアプローチの厳格さです。
mowwwalker

少なくとも投票してください
Rishabh dev Tyagi

1
ファイ、私はあなたの返答を与えられたので、これは助けや質問に答えようとする試みのようではなく、いくつかの賛成票を手に入れるために、反対票を投じました。
mowwwalker
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.