Вставка таблицы в содержимое редактируемого div
У меня есть fiddle, показывающий, что делает мой код. Используя javascript/jquery, я пытаюсь вставить таблицу в редактируемый контент div в текущей позиции каретки. Я использую библиотеку Tim Down Rangy для этого. Я делаю это со следующим javascript.
var range = getFirstRange();
var el = document.createElement("table");
var tableHtml = "";
for (var a = 0; a <= tableY; a++) {
if(a%2==0){
tableHtml += '<tr class="zebra">';
}
else{
tableHtml += '<tr>';
}
for (var b = 0; b <= tableX; b++) {
tableHtml += '<td> </td>';
}
tableHtml += '</tr>';
}
$(el).html(tableHtml);
range.insertNode(el);
rangy.getSelection().setSingleRange(range);
На всякий случай здесь помогает функция getFirstRange.
function getFirstRange() {
var sel = rangy.getSelection();
return sel.rangeCount ? sel.getRangeAt(0) : null;
}
Мне нужно сделать допустимый html везде, где находится эта таблица. например, если каретка находится в середине ссылки, я пытаюсь избежать следующего html.
<p>some text <a href="#">text
<table>
<tr>
<td>table content</td>
</tr>
</table>
text</a> more text</p>
Я бы хотел, чтобы это выглядело так.
<p>some text <a href="#">text</a></p>
<table>
<tr>
<td>table content</td>
</tr>
</table>
<p><a href="#">text</a> more text</p>
Ответы
Ответ 1
Если вы хотите отбросить новый node сразу после выбранного node (s), который не может его корректно содержать, замените это:
range.insertNode(el);
С чем-то , например:
var badNodes = {a: 1, p: 1};
// starting with the node at the beginning of the range,
// iterate to the "left" until we find a node that isn't
// a text node
var n = range.startContainer;
var tag = n.nodeName;
while (tag == '#text') {
n = n.parentNode;
tag = n.nodeName;
}
// if the node we landed on isn't one of our bad nodes ...
if (badNodes[tag.toLowerCase()]) {
// that we refuse to insert 'el' into, continue iterating to the
// "left" until we find a node we're willing to place 'el' after.
while (badNodes[n.parentNode.nodeName.toLowerCase()]) {
n = n.parentNode;
tag = n.nodeName;
}
n.parentNode.insertBefore(el, n.nextSibling);
} else {
range.insertNode(el);
}
Смотрите мою вилку для скрипки: http://jsfiddle.net/zntwL/29/
ОБНОВЛЕНИЕ (я думаю, это то, что вы хотите)
Если вы хотите разбить недействительный node (s) и отбросить новый node, используйте вместо этого следующее:
var badNodes = {a: 1, p: 1};
// starting with the node at the beginning of the range,
// iterate to the "left" until we find a node that isn't
// a text node
var n = range.startContainer;
var tag = n.nodeName;
while (tag == '#text') {
n = n.parentNode;
tag = n.nodeName;
}
// if the node we landed on is one of our "bad" nodes ...
if (badNodes[tag.toLowerCase()]) {
// continue iterating to the "left" until we find a "good" node
while (badNodes[n.parentNode.nodeName.toLowerCase()]) {
n = n.parentNode;
tag = n.nodeName;
}
// remove everything from our "good" node from the start of the
// range to the end of the node. this causes all bad nodes to be
// severed and auto-closed and auto-opened as necessary at the cut.
range.setEndAfter(n);
var clipped = range.extractContents();
// drop 'el' in after the break (right where we want it)
n.parentNode.insertBefore(el, n.nextSibling);
// and re-attach the clipped portion of the "good" node, which
// includes the auto-opened "bad" nodes.
el.parentNode.insertBefore(clipped, el.nextSibling);
} else {
range.insertNode(el);
}
http://jsfiddle.net/zntwL/31/
Ваше окончательное решение может нуждаться в некоторой настройке. Возможно, вам придется обнаруживать #text-узлы по-разному, чтобы быть совместимыми с кросс-браузером. И вы захотите его модулировать и соответствующим образом заполнить массив badNodes
. Но, я думаю, что общая идея.
Ответ 2
Что-то вроде
var parentNode = range.commonAncestorContainer;
parentNode.inertNode(el);
чтобы заменить ваш
range.insertNode(el);
Возможно, вам придется настроить его, чтобы получить таблицу точно там, где вы хотите ее во всех случаях, но по крайней мере она никогда не появится в середине элемента.
Ответ 3
Как разработчик приложений для iPhone, я нашел следующее, что работает для меня на редактируемый контент
function TableOfContentForSubHeading1() {
var level = 0;
document.getElementById("content").innerHTML =
document.getElementById("content").innerHTML.replace(/<h([\d])>([^<]+)<\/h([\d])>/gi, function (str, openLevel, titleText, closeLevel) {
if (openLevel != closeLevel) {
return str;
}
if (openLevel > level) {
toc += (new Array(openLevel - level + 1)).join("<ol>");
} else if (openLevel < level) {
toc += (new Array(level - openLevel + 1)).join("</ol>");
}
level = parseInt(openLevel);
var anchor = titleText.replace(/ /g, "_");
toc += "<li><a href=\"#" + anchor + "\">" + titleText + "</a></li>";
return "<h" + openLevel + "><a name=\"" + anchor + "\">" + titleText + "</a></h" + closeLevel + ">";
});
if (level) {
toc += (new Array(level + 1)).join("</ol>");
}
document.getElementById("content").innerHTML += toc;
}
Надеюсь, что это сработает.
Ответ 4
Ниже я сделал некоторые улучшения в том случае, если заголовки включают ссылку или идентификатор CLASS.
<script>
window.onload = function () {
var toc = "";
var level = 0;
document.getElementById("contents").innerHTML =
document.getElementById("contents").innerHTML.replace(/<h([\d])([^<]+)>([^<]+)<\/h([\d])>/gi,
function (str, openLevel, classHeading, titleText, closeLevel) {
if (openLevel != closeLevel) {
return str;
}
if (openLevel > level) {
toc += (new Array(openLevel - level + 1)).join("<ul>");
} else if (openLevel < level) {
toc += (new Array(level - openLevel + 1)).join("</ul>");
}
level = parseInt(openLevel);
var anchor = titleText.replace(/ /g, "_");
toc += "<li><a href=\"#" + anchor + "\">" + titleText
+ "</a></li>";
return "<h" + openLevel + classHeading +"><a name=\"" + anchor + "\">"
+ titleText + "</a></h" + closeLevel + ">";
}
);
if (level) {
toc += (new Array(level + 1)).join("</ul>");
}
document.getElementById("toc").innerHTML += toc;
};
</script>
Я добавил дополнительный параметр функции замены:
([^<]+)
named classHeading и добавление его в функцию возврата
return "<h" + openLevel + classHeading + ....
Так что сохраненный класс сохраняется.