Итак, в настоящее время я работаю над маленькой кнопкой, которая просит пользователя ввести ссылку для видео, а затем я беру эту ссылку и превращаю ее в 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/
Как известно, execCommand и contentEditable несовместимы между браузерами, поэтому я бы порекомендовал поискать другое решение, если это возможно. Но поскольку этот вопрос касается обходного пути, возможно, вы могли бы вместо этого вставить изображение-заполнитель в Safari? а потом заменить его на iframe?
Кажется, что Safari не может отменить вставку iFrames, однако они вставлены (хотя, как ни странно, вы можете отменить / повторить удаление из них). Когда вы вручную копируете / вставляете iFrame в поле contenteditable, вы также не можете отменить это действие.



![Безумие обратных вызовов в javascript [JS]](https://i.imgur.com/WsjO6zJb.png)


Я думаю, что в Safari это не поддерживается. Проверяя https://developer.mozilla.org/en-US/docs/Web/API/Document/execCommand, метод execCommand возвращает true / false независимо от того, поддерживается / включена команда или нет. В Safari всегда возвращает false (согласно моим тестам).
Я думаю, что единственный обходной путь - это реализовать собственный стек отмены / повтора.
Это неправда. Тогда вы делаете что-то не так, потому что он не всегда возвращает false. Он также не возвращает false, даже когда вы пытаетесь отменить фрейм. Он возвращает true, но ничего не делает. Вероятно, вы не запускаете document.execCommand из контентного компьютера. Вы пробовали мою скрипку?
Похоже, что insertHTML ломает историю отмен / повторов в вашем случае. Если вы вместо этого используете insertText, он будет работать. Может просто пока не поддерживается.
@Disfigure На самом деле, отмена / повтор отлично работает с insertHTML в большинстве случаев. Например, установка div вместо iFrame в Safari работает без сбоев.
@aaplmath, что я имел в виду, конечно, он не прерывается с другими тегами, но для случая использования OP, iframe, похоже, нарушает историю отмены / повтора.
Я сделал небольшое решение для кеширования, чтобы эмулировать то же поведение и заставить его работать в Safari.
ctrl+Z или cmd+Zctrl+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. Спасибо за попытку помочь :)
Подождите, позвольте мне перефразировать это. когда я нажимаю «добавить видео», а затем нажимаю «отменить», это не работает. Однако, если я добавляю видео, затем удаляю его, а затем нажимаю «Отменить», он вставляет видео обратно в контент. Итак, я бы сказал, это не работает так, как ожидалось. Ваше здоровье!
Для меня отмена просто повторно открывает последнюю закрытую вкладку.