Iframe Undo / Redo для execCommand с использованием insertHTML (contenteditable)

Итак, в настоящее время я работаю над маленькой кнопкой, которая просит пользователя ввести ссылку для видео, а затем я беру эту ссылку и превращаю ее в iframe и вставляю в контент с помощью document.execCommand("insertHTML", false, "<iframe width='350' height='551' src='<video_link_entered_by_user>'></iframe>"). Это прекрасно работает, и видео встраивается в contenteditable.

Единственная проблема в том, что если я сделаю Command + Z или нажму undo в Safari, iframe по какой-то причине не будет отменен. Он работает в Firefox, Chrome, Edge и Opera, но по какой-то причине я думаю, что safari не понимает, как это сделать.

Есть ли какое-либо обходное решение для этого, кроме реализации моего собственного стека отмены / повтора? Я просто хочу иметь возможность избавиться от iframe, когда пользователь выбирает undo в сафари, и добавить его обратно, когда пользователь выберет undo. Пожалуйста, помогите и заранее спасибо.

Обновлено:

Вот скрипт JS, чтобы продемонстрировать, о чем я говорю. Если вы запустите это в любом браузере, кроме Safari, и нажмете «Отменить», все заработает. Но не в Safari. http://jsfiddle.net/qg41pd3k/9/

Для меня отмена просто повторно открывает последнюю закрытую вкладку.

LeZuse 22.08.2018 13:42

Как известно, execCommand и contentEditable несовместимы между браузерами, поэтому я бы порекомендовал поискать другое решение, если это возможно. Но поскольку этот вопрос касается обходного пути, возможно, вы могли бы вместо этого вставить изображение-заполнитель в Safari? а потом заменить его на iframe?

LeZuse 22.08.2018 13:51

Кажется, что Safari не может отменить вставку iFrames, однако они вставлены (хотя, как ни странно, вы можете отменить / повторить удаление из них). Когда вы вручную копируете / вставляете iFrame в поле contenteditable, вы также не можете отменить это действие.

aaplmath 22.08.2018 15:52
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
В настоящее время производительность загрузки веб-сайта имеет решающее значение не только для удобства пользователей, но и для ранжирования в...
Безумие обратных вызовов в javascript [JS]
Безумие обратных вызовов в javascript [JS]
Здравствуйте! Юный падаван 🚀. Присоединяйся ко мне, чтобы разобраться в одной из самых запутанных концепций, когда вы начинаете изучать мир...
Система управления парковками с использованием HTML, CSS и JavaScript
Система управления парковками с использованием HTML, CSS и JavaScript
Веб-сайт по управлению парковками был создан с использованием HTML, CSS и JavaScript. Это простой сайт, ничего вычурного. Основная цель -...
JavaScript Вопросы с множественным выбором и ответы
JavaScript Вопросы с множественным выбором и ответы
Если вы ищете платформу, которая предоставляет вам бесплатный тест JavaScript MCQ (Multiple Choice Questions With Answers) для оценки ваших знаний,...
9
3
632
2

Ответы 2

Я думаю, что в Safari это не поддерживается. Проверяя https://developer.mozilla.org/en-US/docs/Web/API/Document/execCommand, метод execCommand возвращает true / false независимо от того, поддерживается / включена команда или нет. В Safari всегда возвращает false (согласно моим тестам).

Я думаю, что единственный обходной путь - это реализовать собственный стек отмены / повтора.

Это неправда. Тогда вы делаете что-то не так, потому что он не всегда возвращает false. Он также не возвращает false, даже когда вы пытаетесь отменить фрейм. Он возвращает true, но ничего не делает. Вероятно, вы не запускаете document.execCommand из контентного компьютера. Вы пробовали мою скрипку?

Yang K 17.08.2018 01:29

Похоже, что insertHTML ломает историю отмен / повторов в вашем случае. Если вы вместо этого используете insertText, он будет работать. Может просто пока не поддерживается.

Disfigure 22.08.2018 14:49

@Disfigure На самом деле, отмена / повтор отлично работает с insertHTML в большинстве случаев. Например, установка div вместо iFrame в Safari работает без сбоев.

aaplmath 22.08.2018 15:53

@aaplmath, что я имел в виду, конечно, он не прерывается с другими тегами, но для случая использования OP, iframe, похоже, нарушает историю отмены / повтора.

Disfigure 22.08.2018 16:27

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

  • Добавить кнопку видео
  • Кнопки отмены / возврата
  • ctrl+Z или cmd+Z
  • ctrl+Y или cmd+Y

Надеюсь, этот образец кода вам поможет.

Можно добавить некоторую оптимизацию, например, функцию устранения неполадок, и увеличить лимит кеша.

$(document).ready(function () {
    var $document = $(document);
    var $editor = $('#editor');
    var $redo = $('#redo');
    var $undo = $('#undo');
    var $addVideo = $('#add-video');

    var CACHE_LIMIT = 1000;
    var cache = [];
    var position = 0;
    var zKeyCode = 90;
    var yKeyCode = 89;
    
    var editorKeydownEventHandler = function (event) {
        var ctrl = (event.ctrlKey || event.metaKey);

        if (ctrl && event.keyCode === zKeyCode) {
            event.preventDefault();
            event.stopPropagation();
            undo();
        }
        else if (ctrl && event.keyCode === yKeyCode) {
            event.preventDefault();
            event.stopPropagation();
            redo();
        }
    };

    var editorInputEventHandler = function (event) {
        if (cache.length >= CACHE_LIMIT) {
            cache = cache.slice(1);
        }

        cache.push($editor.html());
        position++;
    };

    var redoClickEventHandler = function (event) {
        redo();
    };


    var undoClickEventHandler = function (event) {
        undo();
    };

    var addVideoClickEventHandler = function (event) {
        addVideo();
    };

    var redo = () => {
        if (cache[position + 1]) {
            position++;
            $editor.html(cache[position]);
        }
    };

    var undo = () => {
        console.info('undo');
        if (cache[position - 1]) {
            position--;
            $editor.html(cache[position]);
        }
    };

    var addVideo = function () {
        document.execCommand("insertHTML", false, "<iframe src='https://www.youtube.com/embed/9P6rdqiybaw' height='100' width='100'></iframe>")
    };

    $document.bind('keydown', editorKeydownEventHandler);
    $editor.bind('input', editorInputEventHandler);
    $redo.click(redoClickEventHandler);
    $undo.click(undoClickEventHandler);
    $addVideo.click(addVideoClickEventHandler);
});
<!DOCTYPE html>
<html lang = "en">
<head>
    <meta charset = "UTF-8">
    <title>Title</title>
</head>
<body>
     <div id = "editor" contenteditable = "true">
         Lorem ipsum dolor sit amet, consectetur adipisicing elit. At culpa exercitationem itaque maxime porro reiciendis repudiandae veniam vero! Alias at doloremque exercitationem fugiat ipsum natus nihil numquam provident sint, voluptatibus.
     </div>
     <button id = "add-video">add video</button>
     <button id = "undo">undo</button>
     <button id = "redo">redo</button>
     <script
             src = "https://code.jquery.com/jquery-3.3.1.min.js"
             crossorigin = "anonymous"></script>
     <script src = "index.js"></script>
</body>
</html>

Извини, дружище, это не работает. Когда я пытаюсь отменить / повторить, iframe все еще существует в contenteditable. Спасибо за попытку помочь :)

Yang K 23.08.2018 03:20

Подождите, позвольте мне перефразировать это. когда я нажимаю «добавить видео», а затем нажимаю «отменить», это не работает. Однако, если я добавляю видео, затем удаляю его, а затем нажимаю «Отменить», он вставляет видео обратно в контент. Итак, я бы сказал, это не работает так, как ожидалось. Ваше здоровье!

Yang K 23.08.2018 03:23

Другие вопросы по теме