Запретить копирование атрибутов при вводе нового абзаца?

При создании новых абзацев в CKEditor атрибуты (стили, классы) предыдущего абзаца копируются на новый. Есть ли способ предотвратить это?

Например, если я пишу в центральном абзаце и нажимаю Enter для создания нового абзаца, мои пользователи хотят, чтобы новый абзац был простым

без "наследования" чего-либо из предыдущего по умолчанию.


Edit

Мне удалось получить (опасно непроверенную) работу с советами Рейнмара. Вот что я получил; Надеюсь, это поможет кому-то другому. Если вы, ребята, видите вопиющую ошибку здесь, пожалуйста, скажите мне

CKEDITOR.on('instanceCreated', function(e) {
    e.editor.on('key', function(evt) {
        if (evt.data.keyCode === 13) {
            // if we call getStartElement too soon, we get the wrong element
            setTimeout(function () {
                var se = e.editor.getSelection().getStartElement();
                if(se.getName() == "span") {
                    var text = se.getText(); // Store text, we are about to nuke the spans
                    while (se.getName() == "span") { // possible infinite loop danger
                        se = se.getParent();
                    }
                    if (text.length == 0)
                        se.setHtml(" "); // It important that this is not empty
                    else
                        se.setHtml(text);
                }
                debug(se.getHtml());
                se.removeAttribute("class");
                se.removeAttribute("mycustomattr");
                se.removeAttribute("myothercustomattr");
                window.bla = se; // useful for debugging
            }, 10);
        }
    });
}); 

Ответ 1

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

Эти методы будут полезны:

  • editor.on( 'key', function( evt ) { evt.data.key... } )
  • editor.getSelection().getStartElement() - после начала ввода выбор будет помещен во вновь созданный блок (+ встроенные элементы, такие как жирный шрифт, подчеркивание и т.д.).
  • CKEDITOR.dtd.* - наборы элементов могут помочь вам принять решение, какие элементы являются встроенными стилями и должны быть удалены.
  • element.isEmptyInlineRemoveable - вы должны удалить пустые встроенные элементы, в которые был помещен курсор.
  • editor.createRange().setStartAt( block, 0 ).select() - в конце вы должны поместить каретку в правильное место (в начале блока - <p>/<div>/<li>/etc.).

К сожалению, как вы можете видеть, это непростая вещь для написания, так что удачи:)

Ответ 2

У меня была аналогичная проблема с предстоящим CKEditor v4 (текущие ночные часы). Я вставляю абзац с изображениями и пользовательскими классами из своего пользовательского браузера изображений, а CKEditor продолжает копировать классы в абзацы, созданные после изображения.

Мне не понравилась идея события key, за которым последовал вызов setTimeout, поэтому я немного изучил источник и оказался очень простым.

Когда вы нажимаете клавишу ввода, CKEditor выдает команду enter. Все, что вам нужно сделать, - установить событие afterCommandExec и найти вновь созданный пустой элемент:

editor.on('afterCommandExec', function (e) {
    if (e.data.name == 'enter') {
        var el = e.editor.getSelection().getStartElement();

        // when splitting a paragrah before it first character,
        // the second one is selected
        if (el.getHtml() != '<br>') {
            if (el.hasPrevious() && el.getPrevious().getHtml() == '<br>') {
                el = el.getPrevious();
            } else {
                // both paragraphs are non-empty, do nothing
                return;
            }
        }

        // modify el according to your needs
    }
});

Надеюсь, это поможет!

Ответ 3

Это старый пост, но у меня была эта же проблема, и у меня наконец-то было что-то работающее, поэтому я хотел поделиться своим решением. Для тех, кто не знает, зачем нам нужна эта функциональность, вот мое объяснение:

По умолчанию CKEDITOR пытается разрешить пользователю продолжить с тем же стилем при нажатии клавиши ввода, чтобы вставить новые строки. Другими словами, если ваш текст выделен жирным шрифтом и центрирован, и вы нажимаете клавишу ввода, ckeditor реплицирует это стилирование, чтобы новая строка также была выделена жирным шрифтом и центрирована. Это здорово, пока вы не захотите вставить что-то более сложное, например вложенные элементы с атрибутами (например, через плагин). Когда вы нажимаете enter внутри элемента с классом, ckeditor создает новый элемент абзаца с тем же классом, который не будет работать, если этот класс полагается на присутствие родительского элемента (здесь пример, где это становится проблемой: http://jsfiddle.net/B4yGJ/158/).

В решении, которое я придумал, содержится код и предложения от Reinmar и Nenotlep:

// create object of safe classes
var safe_classes = {};
$.each(ckeditor_styles_full, function(i, style) {
    if(style['attributes']) {
        var style_classes = style['attributes'].class;
        var style_element = style['element'];

        if(typeof safe_classes[style_element] != "object") {
            safe_classes[style_element] = [];
        }

        style_classes = style_classes.split(" ");
        $.each(style_classes, function(i, v) {
            if($.inArray(v, safe_classes[style_element]) <= -1) {
                safe_classes[style_element].push(v);
            }
        });
    }
});

$.each(CKEDITOR.instances, function(i, editor) {
    editor.on('key', function(e) {
        if (e.data.keyCode === 13) {
            setTimeout(function () {
                var se = e.editor.getSelection().getStartElement();
                var parent = se.getParent().getName();
                if(parent == "html" || parent == "body") {
                    var se_classes = se.getAttribute('class');
                    var new_classes = [];
                    se.removeAttribute("class");

                    if(se_classes !== null) {
                        se_classes = se_classes.split(" ");
                        $.each(se_classes, function(i, v) {
                            if(typeof safe_classes[se.getName()] != 'undefined') {
                                if($.inArray(v, safe_classes[se.getName()]) > -1) {
                                    se.addClass(v);
                                }
                            }
                        });
                    }
                }
            }, 10);
        }
    });
});

Вот как это работает: во-первых, script сбрасывает список выбранных стилей для имен классов и компилирует их в объект по типу элемента. Затем он выполняет итерацию по всем экземплярам CKEDITOR, привязывая событие к ключу ввода. Затем он проверяет, находится ли элемент, созданный при нажатии ввода, внутри родительского элемента, отличного от HTML или BODY (т.е. Является частью большего дерева элементов). Наконец, если он не находится внутри элемента контейнера, он удаляет все классы из этого элемента, которые не находятся в ранее созданном объекте safe_classes.

2 важных примечания: 1) Вам все равно нужно установить "forceEnterMode: true" 2) Поскольку для параметра forceEnterMode установлено значение true, лучше всего только вставить элементы абзаца. Пример:

<div class="container"><p class="title">Title Text</p><p class="content">Content Goes Here</p></div>

В противном случае, если вы нажмете enter внутри вложенного div, ckeditor продублирует все эти атрибуты div в элемент абзаца.