Last active
August 30, 2016 17:17
-
-
Save garyfeng/f63021954cdb67ac7cb5d40425345131 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// sample code for calculating the caret cursor position in CKEditor | |
// including functions to deal with cross-browser inconsistencies for end-of-the-line | |
// A hack to get text from HTML | |
// http://stackoverflow.com/questions/5002111/javascript-how-to-strip-html-tags-from-string | |
var html2text = function (html) { | |
// testing the idea of using .toString() with a replacement trick | |
// knowing that .textContent doesn't preserve the newlines, let's replace </p> with 2 newline chars | |
// This is ignoring all other HTML/CSS markups, such as <br>, tables, etc. | |
// console.log(html); | |
// but first, we have to remove the dangling '<p></p>' at the end of a selection. | |
// other wise moving the cursor to the begiining of a new line will give you incorrect pos reading | |
// it's basically 2+, because the empty </p> is turned into \n\n. | |
// This is only applicable to "<p></p>" inserted by CKEditor; user created newlines (e.g. | |
// when the user hits enter keys) are like "<p><br/></p>", and textContent ignores <br>s. We | |
// are ok there. | |
html = html.replace(/<p><\/p>/gi, ""); | |
// now we can do our trick | |
html = html.replace(/<\/p>/gi, "\n\n<\/p>"); | |
// create the div if it's not there | |
var el = document.getElementById("divHTML2Text"); | |
if (el === null) { | |
el = document.createElement("div"); | |
el.setAttribute("id", "divHTML2Text"); | |
el.setAttribute("style", "{display:hidden; white-space: pre-line;}"); | |
} | |
// clear the element | |
el.innerHTML = ""; | |
try { | |
// in the case html is not valid | |
el.innerHTML = html; | |
} catch (e) { | |
console.log("Error in html2text(): invalid HTML input"); | |
return ""; | |
} | |
// can't use el.textContent because it doesn't preserve newline as \n | |
// but innerText trims spaces ;< We solve this problem by | |
// replacing spaces with non-breaking spaces in the incoming HTML. | |
// @@@@@ NOTE: Firefox doesn't support innerText @@@@@@@@ | |
// see this for a great summary of the state of affair as of 2015 | |
// http://perfectionkills.com/the-poor-misunderstood-innerText/ | |
// and we probably don't want to polyfill, like | |
// https://github.com/duckinator/innerText-polyfill/blob/master/innertext.js | |
// So we will use .textContent instead, with the newline replacement trick above. | |
//return el.innerText; | |
return el.textContent; | |
} | |
// A hack to get a docment fragment to HTML | |
var frag2html = function (frag) { | |
// create the div if it's not there | |
var el = document.getElementById("divHTML2Text"); | |
if (el === null) { | |
el = document.createElement("div"); | |
el.setAttribute("id", "divHTML2Text"); | |
el.setAttribute("style", "{display:hidden}"); | |
} | |
// clear the element | |
el.innerHTML = ""; | |
try { | |
// in the case html is not valid | |
el.appendChild(frag.cloneNode(true)); | |
} catch (e) { | |
console.log("Error in frag2html(): invalid document fragment"); | |
return ""; | |
} | |
return el.innerHTML; | |
} | |
var selection2string = function (editor) { | |
// avoid using DOM manipulations | |
// return editor.getSelection().getNative().toString() | |
return editor.getSelection().getSelectedText(); | |
}; | |
var getSelectionInfo = function (editor) { | |
// get the current selection, return a selInfo object | |
// RonMorrill: Initialize this for cases when we need to return an empty selection | |
var selInfo = { | |
textSelected: "", | |
startPos: 0, | |
endPos: 0 | |
}, | |
textSelected = ""; | |
// get current selection in DOM | |
// var editor = CKEDITOR.instances.editor1 | |
var sel = editor.getSelection().getNative(); | |
// jgrant. check for no selection. | |
// RonMorrill: improve check and return something that won't cause calling code to crash | |
if (sel == null || sel.rangeCount === 0) { | |
return selInfo; | |
} | |
// get range | |
var ran = sel.getRangeAt(0); | |
// get html | |
// make sure we replace white spaces with non-break spaces | |
var html = frag2html(ran.cloneContents()).replace(/ /g, ' '); | |
// Calculate the text position of the two ends. | |
// note that html2text() returns "\n\n" for line breaks, | |
// but range.toString() reutrns "\n" only. | |
// So we must go through html2text() for all range contents for consistency. | |
// first select the beginning of the text | |
var firstnode = editor.document.$.body.childNodes[0]; | |
var firstOffset = 0; | |
// Count characters before to the left of the selection. | |
var leftrange = editor.document.$.createRange(); | |
leftrange.setStart(firstnode, firstOffset); | |
leftrange.setEnd(ran.startContainer, ran.startOffset); | |
textSelected = html2text(frag2html(leftrange.cloneContents()).replace(/ /g, ' ')); | |
selInfo.startPos = textSelected.length; | |
// if (logConfig.logKeyVerbose) selInfo.leftText = textSelected; | |
// this includes "\n\n" that we need to take out | |
if (ran.startOffset !== 0 && textSelected.endsWith("\n\n")) { | |
selInfo.startPos -= 2; | |
} | |
// Count characters before to the right of the selection. | |
var rightrange = editor.document.$.createRange(); | |
rightrange.setStart(firstnode, firstOffset); | |
rightrange.setEnd(ran.endContainer, ran.endOffset); | |
textSelected = html2text(frag2html(rightrange.cloneContents()).replace(/ /g, ' ')); | |
// if (logConfig.logKeyVerbose) selInfo.rightText = textSelected; | |
selInfo.endPos = textSelected.length; | |
// this includes "\n\n" that we need to take out | |
if (ran.endOffset !== 0 && textSelected.endsWith("\n\n")) { | |
selInfo.endPos -= 2; | |
} | |
selInfo.lenSelected = selInfo.endPos - selInfo.startPos; | |
// selected contents | |
// if (logConfig.logKeyVerbose) selInfo.htmlSelected = html; | |
// textSelected turned out to be more complex. In the following example | |
// "startPos":13,"endPos":20,"htmlSelected":"<p>t</p><p>Se</p>","textSelected":"t\n\nSe\n\n" | |
// we see that the lenSelected = 7, but the text has an extra "\n\n" because html2text automatically | |
// closes off the </p>, which gets translated as "\n\n". We have to take it out. | |
textSelected = html2text(html); | |
// if endOffset is 0, then delete the last 2 characters, which are "\n\n" | |
selInfo.textSelected = ran.endOffset != 0 && textSelected.endsWith("\n\n") ? textSelected.substring(0, textSelected.length - 2) : textSelected; | |
//selInfo.textSelected = textSelected; | |
selInfo.isCollapsed = sel.isCollapsed; | |
return selInfo; | |
}; | |
// example code ... may not be valid | |
var editor = CKEDITOR.instances.editor1 | |
var sel = getSelectionInfo(editor); | |
var extendedInfo = {}; | |
extendedInfo.selectedText = sel.textSelected || ""; | |
extendedInfo.startPos = sel.startPos; | |
extendedInfo.endPos = sel.endPos; | |
// when nothing is selected, startPos == endPos |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
removed references to
config
.