(function(){
var dom = {}
var style = {}
var pos = {}
// i use this because a plain
collapses vertically sometimes...
var zero_width_space = ''
var height_until_error = 0;
var height_with_error = 0;
var scrollbar_width = 0;
var off = function(){
dom.highlight.style.display = 'none'
}
var on = function(line_num){
pos = dom.textarea.getBoundingClientRect()
var text = dom.textarea.value;
var lines = text.split('\n')
var lines_until_error = lines.slice(0, line_num)
var line_with_error = lines[line_num]
if (lines_until_error.length === 1)
dom.textmeasure.innerHTML = lines_until_error + zero_width_space
else
dom.textmeasure.innerHTML = lines_until_error.join('
' + zero_width_space)
height_until_error = dom.textmeasure.offsetHeight
dom.textmeasure.innerHTML = line_with_error + zero_width_space
height_with_error = dom.textmeasure.offsetHeight
reposition_highlight()
}
var reposition_highlight = function(){
var bounds_bottom = pos.top + pos.height
if (dom.textarea.scrollHeight > dom.textarea.clientHeight) // scrollbar exists
dom.highlight.style.width = pos.width - scrollbar_width + "px"
else
dom.highlight.style.width = pos.width + "px"
dom.highlight.style.left = pos.left + "px"
var y_pos = pos.top + height_until_error - dom.textarea.scrollTop
dom.highlight.style.top = y_pos + dom.html.scrollTop + dom.body.scrollTop + "px"
var height_of_highlight = height_with_error;
// nice clip on bottom
if (y_pos + height_of_highlight > bounds_bottom)
height_of_highlight = Math.max(0, bounds_bottom - y_pos)
// crap clip on top
if (y_pos < pos.top)
height_of_highlight = 0
dom.highlight.style.height = height_of_highlight + "px"
dom.highlight.style.display = 'block'
}
var calc_textarea_style = function(){
var $textarea = $("#shader")
dom.textarea = $textarea[0]
var props = ['lineHeight', 'fontFamily', 'fontSize', 'padding', 'margin', 'borderWidth', 'width']
for (var i=0, p; p=props[i]; i++){
style[p] = $textarea.css(p)
}
}
var calc_scrollbar_width = function() {
var outer = document.createElement("div");
outer.style.visibility = "hidden";
outer.style.width = "100px";
document.body.appendChild(outer);
var width_no_scroll = outer.offsetWidth;
// force scrollbars
outer.style.overflow = "scroll";
var inner = document.createElement("div");
inner.style.width = "100%";
outer.appendChild(inner);
var width_with_scroll = inner.offsetWidth;
outer.parentNode.removeChild(outer);
return width_no_scroll - width_with_scroll;
}
var create_el_textmeasure = function(){
var el = dom.textmeasure = document.createElement('div')
el.id = 'textmeasure'
var s = el.style
for (var key in style)
s[key] = style[key]
s.wordWrap = 'break-word'
s.wordBreak = 'break-all'
s.border = '1px solid red'
s.padding = '0'
s.display = 'block'
s.position = 'absolute'
s.left = "-5000px"
document.body.appendChild(el)
}
var create_el_highlight = function(){
var el = dom.highlight = document.createElement('div')
var s = el.style
for (var key in style)
s[key] = style[key]
s.pointerEvents = 'none'
s.opacity = '0.2'
s.backgroundColor = '#f00'
s.position = 'absolute'
s.lineHeight = '0'
s.fontSize = '0'
s.padding = '0'
s.borderWidth = '0'
s.display = 'block'
document.body.appendChild(el)
}
var init = function(){
dom.html = document.querySelector('html')
dom.body = document.querySelector('body')
calc_textarea_style()
create_el_highlight()
create_el_textmeasure()
scrollbar_width = calc_scrollbar_width()
dom.textarea.addEventListener('scroll', reposition_highlight)
}
// exports
error_highlight = {
init: init,
on: on,
off: off
}
})();
error_highlight.init()