How to apply rounded borders to highlight/selection
They are actually using round edged rectangles to cover the end of highlights in sentences which are smaller than the preceding or succeeding lines (just as I said in point 2). Check this out yourself:
- You cannot inspect element directly from the iframe. So click somewhere else and navigate to the iframe. I did it using chromes' built in source code inspector.
- Then use this image to find out the position of line highlighted in the image.
- That
<div>
contains all the "selection" highlights. They just put round edged, background-colored rectangles below the text using absolute, top and left!!!** - The next
<div>
holds similar background-colored<div>
s, only they are for highlighting focused word, similar words, etc...
This is actually the content of the iframe. See the #document
at the top?
See the expanded view. The small space above having the code is actually the highlighted section.
This is not a very good idea for a simple website though. They really needed to parse and stuff with the words and letters, since it is supposed to be a high-end code editor, so cant blame them for spending a comparatively little time to 'round'ening the edges a little.
Not perfect but it's working:
http://jsfiddle.net/coma/9p2CT/
Remove the real selection
::selection {
background-color: transparent;
}
Add some styles
span.highlight {
background: #ADD6FF;
}
span.begin {
border-top-left-radius: 5px;
border-bottom-left-radius: 5px;
}
span.end {
border-top-right-radius: 5px;
border-bottom-right-radius: 5px;
}
pre.merge-end > span:last-child {
border-bottom-right-radius: 0;
}
pre.merge-end + pre > span:last-child {
border-top-right-radius: 0;
}
pre.merge-begin > span:first-child {
border-bottom-left-radius: 0;
}
pre.merge-begin + pre > span:first-child {
border-top-left-radius: 0;
}
Wrap every character in a node element
var format = function () {
var before = -1;
var html = $.trim(editor.text())
.split("\n")
.reverse()
.map(function (line) {
var a = line.length === before ? 'merge-end' : '';
before = line.length;
return '<pre class="' + a + '"><span>' + line.split('').join('</span><span>') + '</span></pre>';
})
.reverse()
.join('');
editor.html(html);
};
Get the selected nodes and highlight them, take care of their parents
var getSelectedNodes = function () {
var i;
var nodes = [];
var selection = rangy.getSelection();
for (i = 0; i < selection.rangeCount; ++i) {
selection
.getRangeAt(i)
.getNodes()
.forEach(function (node) {
if ($(node).is('span')) {
nodes.push(node);
}
});
}
return nodes;
};
var highlight = function (nodes, beforeNode) {
var currentNode = $(nodes.shift()).addClass('highlight');
var currentParent = currentNode.parent();
if (beforeNode) {
var beforeParent = beforeNode.parent();
if (currentParent.get(0) !== beforeParent.get(0)) {
currentNode.addClass('begin');
beforeNode.addClass('end');
beforeParent.addClass('merge-begin');
}
} else {
currentNode.addClass('begin');
}
if (nodes.length) {
highlight(nodes, currentNode);
} else {
currentNode.addClass('end');
}
};
format();
$(document).on('mouseup', function () {
$('.highlight').removeClass('highlight begin end');
highlight(getSelectedNodes());
});
Thanks to Tim Down for Rangy!
I can assure you this has nothing to do with html, css border radius or highlighting. The proof?
- The whole selection appears as a single block with multiple edges and veritices and is not symmetric. There is no way to have multiple edged shape directly in html, without using SVG or Canvas. (well, that's a possibility open for discussion)
- If it is not a single block, but indeed multiple lines highlighted or marked with some kind of HTML or CSS or JS, then there cant be an outward facing curve like this:
(there are always possibilities. For example you could cover the selection using a white rectangle with a border-radius, but this appears to be highly inefficient and unlikely... So...)
Summary, they must be using the Canvas property and whole lot of codes to 'underlay' an interactive selection procedure. There are numerous different types of highlighting appearing in the editor, like 'same word highlighting', 'selected highlighting', 'out of focus highlighting', etc... For all these to happen efficiently, I can't find a better alternative than canvas.
Don't be mad at me for posting this. But I didn't want to see my 4 hours of research as a waste. At least I got an observation and that's that.
UPDATE :
Though I thought covering the selection using a white rectangle with a border-radius at the end, is a rather inefficient and unnecessary way. Microsoft doesn't think so.
They are using the curved edged rectangles to cover up the end of highlights to give that effect. They are using absolutely positioned, round-edged <div>
s to give the effect of highlighting. And at the end of that <div>
, they overlay an image of a rounded rectangle.
And kudos to them, they have done a great job with it.