Simplified select/caret menus
by kthornbloom
HTML
<div class="editable" spellcheck="false" contenteditable="true">
<h1>Editor Test</h1>
<ul>
<li>Fix moving menu on close</li>
<li>Account for line height where your caret is</li>
<li>make formating menu vs insert menu</li>
</ul>Lorem ipsum dolor sit amet, consectetur adipisicing elit. Maxime at minus <b>ratione</b> fugit mollitia debitis architecto omnis autem. Exercitationem cumque aspernatur ipsa omnis quisquam repudiandae ipsam iusto quidem sequi eveniet.Lorem ipsum dolor sit amet, consectetur adipisicing elit. Maxime at minus ratione fugit mollitia debitis architecto omnis autem. Exercitationem cumque aspernatur ipsa omnis quisquam repudiandae ipsam iusto quidem sequi eveniet.Lorem ipsum dolor sit amet, consectetur adipisicing elit. Maxime at minus ratione fugit mollitia debitis architecto omnis autem. Exercitationem cumque aspernatur ipsa omnis quisquam repudiandae ipsam iusto quidem sequi eveniet.Lorem ipsum dolor sit amet, consectetur adipisicing elit. Maxime at minus <a href="#">Here's some</a> <b>HTML</b> <i>to</i> <u>play with</u>. ratione fugit mollitia debitis architecto omnis autem. Exercitationem cumque aspernatur ipsa omnis quisquam repudiandae ipsam iusto quidem sequi eveniet.Lorem ipsum dolor sit amet, consectetur adipisicing elit. Maxime at minus ratione fugit mollitia debitis architecto omnis autem. Exercitationem cumque aspernatur ipsa omnis quisquam repudiandae ipsam iusto quidem sequi eveniet.Lorem ipsum dolor sit amet, consectetur adipisicing elit. Maxime at minus ratione fugit mollitia debitis architecto omnis autem. Exercitationem cumque aspernatur ipsa omnis quisquam repudiandae ipsam iusto quidem sequi eveniet.Lorem ipsum dolor sit amet, consectetur adipisicing elit. Maxime at minus ratione fugit mollitia debitis architecto omnis autem. Exercitationem cumque aspernatur ipsa omnis quisquam repudiandae ipsam iusto quidem sequi eveniet. <b>Test</b>.</div>
CSS
body {
padding:30px;
font-family:sans-serif;
}
.editable {
padding:30px;
outline:none;
background:#efefef;
font-size:13px;
line-height:1.8em;
}
.circle-menu-wrap {
position:absolute;
margin:15px;
display:inline-block;
width:0;
height:0;
transition:.5s cubic-bezier(0, 0, 0, 1);
}
.circle-menu-wrap a:link, .circle-menu-wrap a:visited {
display:block;
width:40px;
height:40px;
line-height:40px;
border-radius:18px;
text-align:center;
text-decoration:none;
background:#8DAB45;
color:#fff;
position:absolute;
left:50%;
top:50%;
margin:-20px 0 0 -20px;
transform-origin:center;
transform:rotate(0deg) translate(0px) rotate(0deg) scale(.95);
transition:1s cubic-bezier(0, 0, 0, 1.3), rotate;
font-weight: bold;
font-size: 0px;
}
.circle-menu-trigger {
position:absolute;
background:#8DAB45;
color:#585858;
line-height:40px;
border-radius:20px;
text-align:center;
text-decoration:none;
font-weight:bold;
width:40px;
height:40px;
left:50%;
top:50%;
margin:-20px 0 0 -20px;
transition:1s ease-out;
}
.circle-menu-trigger:hover {
cursor:pointer;
}
.rotate, .rotate:hover {
transform: rotate(-45deg) scale(.9);
}
JavaScript
jQuery.fn.reverse = [].reverse;
// Function to paste html at the caret
function pasteHtmlAtCaret(html, selectPastedContent) {
var sel, range;
if (window.getSelection) {
// IE9 and non-IE
sel = window.getSelection();
if (sel.getRangeAt && sel.rangeCount) {
range = sel.getRangeAt(0);
range.deleteContents();
var el = document.createElement("div");
el.innerHTML = html;
var frag = document.createDocumentFragment(),
node, lastNode;
while ((node = el.firstChild)) {
lastNode = frag.appendChild(node);
}
var firstNode = frag.firstChild;
range.insertNode(frag);
// Preserve the selection
if (lastNode) {
range = range.cloneRange();
range.setStartAfter(lastNode);
if (selectPastedContent) {
range.setStartBefore(firstNode);
} else {
range.collapse(true);
}
sel.removeAllRanges();
sel.addRange(range);
}
}
} else if ((sel = document.selection) && sel.type != "Control") {
// IE < 9
var originalRange = sel.createRange();
originalRange.collapse(true);
sel.createRange().pasteHTML(html);
if (selectPastedContent) {
range = sel.createRange();
range.setEndPoint("StartToStart", originalRange);
range.select();
}
}
}
// Function to return selected HTML
function getSelectionHtml() {
var html = "";
if (typeof window.getSelection != "undefined") {
var sel = window.getSelection();
if (sel.rangeCount) {
var container = document.createElement("div");
for (var i = 0, len = sel.rangeCount; i < len; ++i) {
container.appendChild(sel.getRangeAt(i).cloneContents());
}
...