web-dev-qa-db-ja.com

contenteditable要素にリンクを挿入します

私は単純なブログシステムに取り組んでおり、ユーザーがテキストをフォーマットできるようにcontenteditableを使用しています。

これまで、すべてが魅力のように機能します。

次に必要なのは、ユーザーがテキストにハイパーリンクを追加できることです。

ユーザーはテキスト(の一部)を選択し、リンクボタンをクリックする必要があります。その後、ポップアップが開き、ユーザーはリンクアドレスを入力する必要があります。

ユーザーが[同意する]ボタンをクリックしたときに、コンテンツ編集で選択したテキストへのリンクを追加したいと思います。

これを行う方法がわからないので、どうすればこの機能を実装できますか?

私のサイト: http://82.170.147.49/blog/3/alpha-release

私のサイトのjsFiddle: http://jsfiddle.net/qhN9j/

18
PeeHaa

document.execCommand()は、すべての主要なブラウザでこれを行います。

document.execCommand("CreateLink", false, "http://stackoverflow.com/");

リンクダイアログが表示されている間、選択を保持するには、次の機能を使用できます。

function saveSelection() {
    if (window.getSelection) {
        sel = window.getSelection();
        if (sel.getRangeAt && sel.rangeCount) {
            var ranges = [];
            for (var i = 0, len = sel.rangeCount; i < len; ++i) {
                ranges.Push(sel.getRangeAt(i));
            }
            return ranges;
        }
    } else if (document.selection && document.selection.createRange) {
        return document.selection.createRange();
    }
    return null;
}

function restoreSelection(savedSel) {
    if (savedSel) {
        if (window.getSelection) {
            sel = window.getSelection();
            sel.removeAllRanges();
            for (var i = 0, len = savedSel.length; i < len; ++i) {
                sel.addRange(savedSel[i]);
            }
        } else if (document.selection && savedSel.select) {
            savedSel.select();
        }
    }
}

jsFiddleの例: http://jsfiddle.net/JRKwH/1/

[〜#〜]更新[〜#〜]

作成されたリンク(作成された場合)を取得するのは難しいです。あなたは私自身を使うことができます Rangy ライブラリ:

var sel = rangy.getSelection();
if (sel.rangeCount) {
    var links = sel.getRangeAt(0).getNodes([1], function(el) {
        return el.nodeName.toLowerCase() == "a";
    });
    alert(links.length);
}

...または次のようなもの:

function getLinksInSelection() {
    var selectedLinks = [];
    var range, containerEl, links, linkRange;
    if (window.getSelection) {
        sel = window.getSelection();
        if (sel.getRangeAt && sel.rangeCount) {
            linkRange = document.createRange();
            for (var r = 0; r < sel.rangeCount; ++r) {
                range = sel.getRangeAt(r);
                containerEl = range.commonAncestorContainer;
                if (containerEl.nodeType != 1) {
                    containerEl = containerEl.parentNode;
                }
                if (containerEl.nodeName.toLowerCase() == "a") {
                    selectedLinks.Push(containerEl);
                } else {
                    links = containerEl.getElementsByTagName("a");
                    for (var i = 0; i < links.length; ++i) {
                        linkRange.selectNodeContents(links[i]);
                        if (linkRange.compareBoundaryPoints(range.END_TO_START, range) < 1 && linkRange.compareBoundaryPoints(range.START_TO_END, range) > -1) {
                            selectedLinks.Push(links[i]);
                        }
                    }
                }
            }
            linkRange.detach();
        }
    } else if (document.selection && document.selection.type != "Control") {
        range = document.selection.createRange();
        containerEl = range.parentElement();
        if (containerEl.nodeName.toLowerCase() == "a") {
            selectedLinks.Push(containerEl);
        } else {
            links = containerEl.getElementsByTagName("a");
            linkRange = document.body.createTextRange();
            for (var i = 0; i < links.length; ++i) {
                linkRange.moveToElementText(links[i]);
                if (linkRange.compareEndPoints("StartToEnd", range) > -1 && linkRange.compareEndPoints("EndToStart", range) < 1) {
                    selectedLinks.Push(links[i]);
                } 
            }
        }
    }
    return selectedLinks;
}

jsFiddle: http://jsfiddle.net/JRKwH/3/

58
Tim Down

アルフレッドが言ったように、特に基本的な機能のために、すでに十分に開発されたエディターがあります。必要な数の機能を使用するように制限できます。

ゼロから開発する際の難しい部分は、すべてのブラウザーの動作がわずかに異なることです。次のshould IE以外のほとんどのブラウザで、正しい方向に移動できます。

var selected = document.getSelection();
document.execCommand("insertHTML",false,"<a href='"+href+"'>"+selected+"</a>");
7
clmarquart

見栄えの良い答え:

_function link() {
  if (window.getSelection().toString()) {
    var a = document.createElement('a');
    a.href = 'http://www.google.com';
    a.title = 'GOOGLE';
    window.getSelection().getRangeAt(0).surroundContents(a);
  }
}_
_select some of text then click link button!
<button onclick='link()'>link text to google</button>_

このメソッドはどこにでも適用でき、要素がcontenteidtableである必要はありません。

他の要素と同様に、新しいA要素に任意のイベントまたは属性を追加できます。

window.getSelection().toString()は、テキストが実際に選択されているかどうかを確認します。 Chromeでうまく機能し、テストするIEはありませんが、とにかくそれをチェックする他の方法があります。しかし、重要な部分であるsurroundContents()はIE9で利用できます。 MDNによって提案されたように。

最後に、contenteditable divの代わりにiFrameを使用することをお勧めします。これにより、選択を保持する心配がなくなります。

6
Ali

編集ExeccommandのIEでは不可能です。'href 'に引用符を挿入できないため、範囲:の純粋なJavaScriptで行う必要があります。

// 1つのIFRAMEのDIV

// Get the frame
var iframe = document.getElementById('myframe');

// Selection object in the frame
theSelection = iframe.contentWindow.getSelection();

// position of the selection to insert
theRange = theSelection.getRangeAt(0);

// get content inside the original selection (and delete content in)
var fragment = theRange.extractContents();

// Create a new link in frame
var newLink = iframe.contentWindow.document.createElement('a');

// Create a text element with the fragment to put in the link
var theText = document.createTextNode(fragment.textContent);

// URL 
theLink.href = '#';

// Title
theLink.title = 'title';

// Attribute 'onclick'
theLink.setAttribute('onclick', thelink);

// Target
theLink.target = '_blank';

// Add the text in the link
theLink.appendChild(theText);

// Insert the link at the range
theRange.insertNode(newLink);

//フレームなしのDIV

// Selection object in the window
theSelection = window.getSelection();

// begin of the selection to insert
theRange = theSelection.getRangeAt(0);

// get content inside the original selection (and delete content in)
var fragment = theRange.extractContents();

// Create a new link in the document
var newLink = document.createElement('a');

// Create a text element with the fragment to put in the link
var theText = document.createTextNode(fragment.textContent);

// URL 
theLink.href = '#';

// Title
theLink.title = 'title';

// Attribute 'onclick'
theLink.setAttribute('onclick', thelink);

// Target
theLink.target = '_blank';

// Add the text in the link
theLink.appendChild(theText);

// Insert the link at the range
theRange.insertNode(newLink);
2
antibug

私はそれをこのようにします:

  1. (おそらく一意の)初期の偽のhref属性を使用してリンクを作成し、それを識別します。
  2. document.querySelector('a[href=<unique-href>]')を使用してその要素をフェッチします。
  3. これで、作成された要素への参照があり、好きなようにそれを使用できます。

これの利点は、Selectionをまったく操作する必要がないことです。

0
Erik Aigner