Выбор текста Tridion RTF

Я пишу расширение GUI, которое, по сути, переносит выделенный текст в определенный DIV. У меня есть текст, который инкапсулирован с помощью DIV, но немного ударил блок...

Когда пользователь не выбрал конкретный фрагмент текста, я предполагаю, что это намерение обернуть ближайший элемент HTML

htmlSelectedNode = target.editor.getSelectedHTMLElement()

Все это работает нормально, и я передаю элемент HTML в мое расширение. После некоторых манипуляций я применяю HTML, но он вводит новый HTML внутри предыдущего элемента - вместо его замены...

Можно ли "выбрать" элемент HTML - я могу видеть .focus() и .setCapture(), но это, похоже, не делает трюк - я думаю, что идеальным было бы использование той же функциональности, что и применялось при выборе элемента из раскрывающегося списка "Текущий элемент" на панели ленты, но мне не удалось найти метод onclick/select, связанный с этим выпадающим списком.

Просто уточнить... с примером...

если текст был

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

и пользователь вставил курсор между я и s в 'is' Я хочу, чтобы GUI предварительно выбирал ближайший элемент HTML - в этом случае конечный результат был бы...

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

EDIT: Для полноты я включил событие отправки, которое я использую для (повторного) вставки 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 likely not required
                if (htmlSelectedNode.attributes["class"] != null)
                    htmlSelectedNode.removeAttribute("class");

                //TODO: test this - it 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);

Ответ 1

Итак, я нашел выбор CurrentElement и увидел ярко выраженный setSelectedHTMLElement. Не знаю, как я пропустил это, но, к сожалению, здесь ниже... как примечание к комментариям - убедитесь, что метод доступен (если у пользователя есть строка текста, которая не соответствует непосредственно HTMLElement, метод setSelectedHTMLElement сбой и удаление пользовательского выбора (что означает расширение GUI.aspx не может (повторно) вводить новый HTML...

//if there 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 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:');
}

Ответ 2

Это сложно. Вам нужно будет проверить все возможные сценарии. Еще год назад нам пришлось реализовать пользовательскую функциональность "Гиперссылка" как расширение GUI. Проблема была такой же: "Как узнать, что выбрано?", "Что делать, если пользователь выбирает текст и половину html node?" "Что, если выбор - это просто текст?" В основном те же проблемы, с которыми вы сталкиваетесь.

Если я правильно понял, вы хотите обернуть выделенный текст заданным (настраиваемым) div, правильно? Что-то, что вам нужно учитывать (если вы еще этого не сделали): "Что произойдет, если пользователь выберет текст, который уже обернут вашим пользовательским div?", "Что, если он выберет текст, завернутый вашим пользовательским div plus фрагмент текста после или перед div?"

Ну, как я уже говорил, это непросто или, по крайней мере, не прямо. Вот несколько советов о том, что мы сделали. В нашем случае нам пришлось обернуть текст тегом Hyperlink вместо div, но с точки зрения "get/set selected html" это должно помочь:

1st: Инициализировать элемент node и получить выбранный html:

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

2nd: Проверьте, что там чертов:

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

}

Примечание. В нашем случае нам также нужно было проверить изображения и теги span, поскольку элемент привязки будет немного другим, потому что нам нужно получить некоторую информацию от них.

3rd: Задайте элемент var, если выбранный текст был элементом (не выбран дополнительный текст)

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 содержался node плюс необработанный текст до или после, мы использовали диапазоны (читаем немного дальше), принимая во внимание разные поведения браузера:

Ну, примеры здесь действительно не решают вашу проблему, но я надеюсь, что они дадут вам несколько советов о том, как проверять содержимое содержимого 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() (где я предполагаю, что у вас есть код, верно?)

Привет,