10

特定の DIV で選択したテキストを本質的にラップする GUI 拡張機能を作成しています。DIV でカプセル化されているテキストがありますが、少しブロックされています...

ユーザーが特定のテキストを選択していない場合、最も近い HTML 要素をラップすることが意図されていると想定しています。

htmlSelectedNode = target.editor.getSelectedHTMLElement()

これはすべて正常に機能しているようで、HTML 要素を拡張機能に渡します。いくつかの操作の後、HTML を適用しますが、新しい HTML を前の要素内に挿入しています - 置き換えるのではなく...

HTML要素を「選択」することは可能ですか - a.focus()と a.setCapture()は見えますが、これらはうまくいかないようです - 「現在の要素」から要素を選択するときに適用されるのと同じ機能を使用するのが理想的だと思います」 リボン バーのドロップダウンですが、このドロップダウンに関連付けられている onclick/select メソッドを見つけることができませんでした。

明確にするために...例を挙げて...

テキストが

    <div class="notrelevant"><p>test1</p><p>this is an example</p></div>

ユーザーが「is」の i と s の間にカーソルを挿入した場合、GUI で最も近い HTML 要素を事前に選択する必要があります。この場合、最終結果は次のようになります...

    <div class="notrelevant"><p>test1</p><div class="INJECTED_CORRECTLY"><p>this is an example</p></div></div>

編集: 完全を期すために、HTML を RTF に (再) 挿入するために使用する送信イベントを含めました (ただし、この時点で選択を操作するのは意味がないと思いますが、「選択」した方がよいでしょう)。上記のテキストは、より「標準的な」既存の Tridion 機能を使用しています...)

   $evt.addEventHandler(popup, "submit",
        function DateHighlighter$execute$onPopupSubmitted(event) {

            var el = event.data.html;
            if (el) {
                if (htmlSelectedNode != null) {
                    var lDocument = htmlSelectedNode.ownerDocument;
                    var lTempContainer = lDocument.createElement("span");

                    try {
                        lTempContainer.innerHTML = el || "";
                    }
                    catch (err) {
                        //assigning a value to innerHTML can be sensitive to browser but the error is fine to be ignored
                    }

                    var parentNode = htmlSelectedNode.parentNode;
                    parentNode.replaceChild(lTempContainer, htmlSelectedNode);

                    //Move to the new element
                    var lTextRange = $dom.createTextRange(lTempContainer);
                    $dom.moveRangeToElement(lTextRange, lTempContainer);
                    //Select and remove the temporary element
                    $dom.selectRange(lTextRange, $dom.getSelection(lDocument));
                    $dom.removeNode(lTempContainer, false);

                }
                else {
                    // Insert new created element (DIV)
                    target.editor.applyHTML(el);
                }

            }
            else {
                //TODO: test this - it's likely not required
                if (htmlSelectedNode.attributes["class"] != null)
                    htmlSelectedNode.removeAttribute("class");

                //TODO: test this - it's likely not required
                if (htmlSelectedNode.attributes["ondblclick"] != null)
                    htmlSelectedNode.removeAttribute("ondblclick");

                //TODO: the node isn't removed - leaves the empty <div>... 
                // - delete the node and then apply the node2.outerHTML? - or follow parentnode pattern above!
                var htmlSelectedNode2 = htmlSelectedNode.innerHTML;
                htmlSelectedNode = htmlSelectedNode2;
            }

            //Refreshes the Design view
            target.editor.setCurrentView("Source");
            target.editor.setCurrentView("RichText");
            target.item.closeActivePopup();
        });
    $evt.addEventHandler(popup, "unload", DateHighlighter$execute$onPopupCanceled);
4

2 に答える 2

7

それで、私はCurrentElement選択を見つけて、明白に明らかなsetSelectedHTMLElement. どうやって見逃したのかわかりませんが、残念ながら以下です...コメントにあるように-メソッドが利用可能であることを確認してください(ユーザーがHTMLElementと直接同等ではないテキストの文字列を選択している場合、setSelectedHTMLElementメソッドは失敗して削除されますユーザーの選択 (したがって、GUI 拡張機能 .aspx は新しい HTML を (再) 挿入できないことを意味します...

//if there's no tagname then the setSelected will fail and remove the (non-element based) select the user has done
if (htmlSelectedNode.nodeName && htmlSelectedNode.nodeName != '#text') { 
    //unlikely to get #text here as it's the htmlSelectedNode.commonAncestorContainer.nodeName
    $log.message(logt + 'selecting the htmlSelectedNode.nodeName:' + htmlSelectedNode.nodeName);
    target.editor.setSelectedHTMLElement(htmlSelectedNode);
}
else {
    $log.message(logt + 'no htmlSelectedNode.nodeName - user probably selected incomplete element:');
}
于 2012-10-01T17:28:20.887 に答える
2

これはトリッキーなものです。考えられるすべてのシナリオを確認する必要があります。1年前、GUI拡張機能としてカスタムの「ハイパーリンク」機能を実装する必要がありました。問題は同じでした:「何が選択されているかをどうやって知ることができますか?」、「ユーザーがテキストとhtmlノードの半分を選択した場合はどうなりますか?」「選択が単なるテキストの場合はどうなりますか?」基本的にあなたが直面しているのと同じ問題。

私が正しく理解していれば、選択したテキストを特定の(カスタム)divでラップしたいですよね?(まだ行っていない場合)同様に考慮する必要があるのは、「ユーザーがカスタムdivで既にラップされているテキストを選択した場合はどうなりますか?」、「カスタムdivでラップされたテキストを選択した場合はどうなりますか?」 divの後または前にテキストのチャンク?」

さて、私が前に述べたように、簡単ではありません、または少なくとも、簡単ではありません。これが私たちがしたことに関するいくつかのヒントです。私たちの場合、divの代わりにハイパーリンクタグでテキストをラップする必要がありましたが、「get /setselectedhtml」の観点からは次のようになります。

1番目:要素ノードを初期化し、選択したhtmlを取得します。

var element = null;
var htmlSelectedNode = target.editor.getSelectedHTMLElement() || {};

2番目:地獄が何であるかを確認してください:

    if (htmlSelectedNode != null && htmlSelectedNode.tagName != null && htmlSelectedNode.tagName == "A") { //In your case you might wanna check if it is a div, instead
    ...
    ...

}

注:この場合、画像とスパンタグもチェックする必要がありました。これらから情報を取得する必要があるため、アンカー要素が少し異なるためです。

3番目:選択したテキストが要素の場合は要素変数を設定します(余分なテキストは選択されていません)

element = htmlSelectedNode;


var selectedText = "";
    // Chrome & Firefox
            if (htmlSelectedNode != null && htmlSelectedNode.startContainer != null && htmlSelectedNode.startOffset != null) {

                selectedText = htmlSelectedNode.toString();

            }
            // IE Range
            else if (htmlSelectedNode != null && htmlSelectedNode.htmlText != null && htmlSelectedNode.text != null) {
                selectedText = htmlSelectedNode.text;
            }
            // IE DIV
            else if (htmlSelectedNode != null && (htmlSelectedNode.tagName == "DIV" || htmlSelectedNode.tagName == "P") && htmlSelectedNode.innerText != null) {
                selectedText = htmlSelectedNode.innerText;
            }

4番目:htmlSelectedNodeにノードと生のテキストが前後に含まれている場合は、ブラウザーのさまざまな動作を考慮して、範囲を使用しました(もう少し詳しく説明します)。

さて、ここでの例は実際にはあなたの問題を解決しませんが、xhtmlコンテンツで何かをチェックする方法についてのいくつかのヒントをあなたに与えることを願っています。基本的に、選択を有効なxhtml要素にするように注意する必要があります。

要素にすでにリンクタグが含まれている場合のxhtmlの処理方法に関するその他の例を次に示します。

// If there is a link, delete it
if (htmlSelectedNode != null) {
    var lDocument = htmlSelectedNode.ownerDocument;
    var lTempContainer = lDocument.createElement("span");

    try {
        lTempContainer.innerHTML = el || "";
    }
    catch (err) {
        //assigning a value to innerHTML might fail -> ignore it then
    }

    var parentNode = htmlSelectedNode.parentNode;
    parentNode.replaceChild(lTempContainer, htmlSelectedNode);

    //move to new element
    var lTextRange = $dom.createTextRange(lTempContainer);
    $dom.moveRangeToElement(lTextRange, lTempContainer);
    //select and remove temp element
    $dom.selectRange(lTextRange, $dom.getSelection(lDocument));
    $dom.removeNode(lTempContainer, false);

}

HTMLをRTFに戻し、[ソース/デザイン]タブを更新する方法:

// Insert new created link
target.editor.applyHTML(el); //el == element


//Refreshes the Design view
target.editor.setCurrentView("Source");
target.editor.setCurrentView("RichText");

繰り返しになりますが、これは問題の解決策ではないことはわかっていますが、いくつかの例を使用して新しいアプローチを試すことができると思います。さらにサポートが必要な場合は、JSファイル全体、または少なくとも_execute()メソッドを共有してください(コードがあると思いますよね?)

よろしく、

于 2012-10-02T16:37:14.130 に答える