I have discovered some usefull attributes of CKEDITOR selection object (get via editor.getSelection()
):
e.getSelection().getRanges()[0].startOffset
e.getSelection().getRanges()[0].endOffset
This returns the start and end position of the selected text - but only in relation to startContainer (element) and endContainer (element). I would like to get the absolute position in relation to the whole document or something else to identify the selected html (some intern id of the start or end element?). I would like to read this attributes on the server side and modify the selected html there. Is there some universal way to move the information about position of the selected text from the client side to the server side?
Thanks a lot.
I found a good and elegant solution:
textselector.js (marks selection - inserts bookmars into CKEDITOR)
function selectText(irtId, startIdSelectionId, endIdSelectionId) {
var editor = CKEDITOR.instances[irtId];
if (editor.getSelection().getRanges()[0].collapsed) {
document.getElementById(startIdSelectionId).value = "";
document.getElementById(endIdSelectionId).value = "";
} else {
var bookmarks = editor.getSelection().createBookmarks(true);
var startId = bookmarks[0].startNode;
var endId = bookmarks[0].endNode;
document.getElementById(startIdSelectionId).value = startId;
document.getElementById(endIdSelectionId).value = endId;
}
return true;
}
Action on the serverside (identifying conflicts - tag-crossing, repairs elements if necessary - divides into 2 parts and insert span):
/**
* prida span na oznacene html osestreni nezadoucich pripadu: prazdny
* select, kolize s jinym spanem
*/
public void spanSelectedHtml() {
// parsovani celeho dokumentu
Document doc = Jsoup.parse(value);
// osetreni chybovych stavu
// - prazdny select
if (startIdSelection.isEmpty() || endIdSelection.isEmpty()) {
return;
}
// nalezeni znacek
Element es = doc.getElementById(startIdSelection);
Element ee = doc.getElementById(endIdSelection);
// - konflikt s jinou znackou
// bude doplneno
// oprava okoli znacek v pripade nutnosti
repairIfNecessary(es, ee);
// vytvoreni span tagu s nalezitymi atributy
Element span = doc.createElement("span");
span.attr("property", clicked.getUrl());
span.attr("class", clicked.getStyleClass());
// nahrazeni prvni znacky span tagem
es.replaceWith(span);
// pripojeni vsech nasledujicich uzlu az do koncove znacky
while (span.nextSibling() != ee) {
span.appendChild(span.nextSibling());
}
// odstraneni koncove znacky
ee.remove();
// aktualizace hodnoty textove komponenty
value = doc.toString();
}
/**
* oprava okoli elementu v pripade nutnosti - pri zjisteni unikatniho rodice
*
* @param e1 prvni element
* @param e2 druhy element
*/
private void repairIfNecessary(Element e1, Element e2) {
while (hasUniqueParent(e1, e2)) { // unikatni rodice e1?
repairElement(e1);
}
while (hasUniqueParent(e2, e1)) { // unikatni rodice e2?
repairElement(e2);
}
}
/**
* oprava okoli elementu: rozdeleni na dve casti a vymazani rodice,
* zachovani atributu
*
* @param e element s okolim na opravu
*/
private void repairElement(Element e) {
// "problemovy rodic", ktereho je treba rozdelit
Element p = e.parent();
// 1. cast - pred znackou
if (e.previousSibling() != null) { // osetreni null
Element n = p.clone().empty(); // vkladany element musi byt formalne stejny
p.prependChild(n); // umisteni elementu na zacatek - jako 1. dite
while (n.nextSibling() != e) { // dokud se nedostanu ke znacce, pridavam uzly
n.appendChild(n.nextSibling());
}
}
// 2. cast - za znackou
if (e.nextSibling() != null) { // osetreni null
Element n = p.clone().empty(); // vkladany element musi byt formalne stejny
p.appendChild(n); // umisteni elementu na konec - jako posledni dite
while (n.previousSibling() != e) { // dokud se nedostanu ke znacce, pridavam uzly
n.prependChild(n.previousSibling());
}
}
p.unwrap(); // vymazani puvodniho "problemoveho rodice"
}
/**
* ma testovaci element rodice, ktereho kontrolni element nema?
*
* @param e testovaci element
* @param c kontrolni element
* @return testovaci element ma unikatniho rodice (takoveho, ktery kontrolni
* element nema)
*/
private boolean hasUniqueParent(Element e, Element c) {
if (e.parents().isEmpty() || c.parents().isEmpty()) { // test na null
return false;
}
for (Element pe : e.parents()) {
if (!c.parents().contains(pe)) {
return true; // unikatni rodic
}
}
return false; // bez unikatniho rodice
}