win -> unix

Signed-off-by: Alex A. Naanou <alex.nanou@gmail.com>
This commit is contained in:
Alex A. Naanou 2025-02-06 15:52:06 +03:00
parent 2c2257b603
commit ada5c33665

View File

@ -1,266 +1,266 @@
/********************************************************************** /**********************************************************************
* *
* *
* *
**********************************************************************/ **********************************************************************/
// XXX add something like .closeToViewport(..) // XXX add something like .closeToViewport(..)
Element.prototype.visibleInViewport = function(partial=false){ Element.prototype.visibleInViewport = function(partial=false){
var { top, left, bottom, right } = this.getBoundingClientRect() var { top, left, bottom, right } = this.getBoundingClientRect()
var { innerHeight, innerWidth } = window var { innerHeight, innerWidth } = window
return partial return partial
? ((top > 0 ? ((top > 0
&& top < innerHeight) && top < innerHeight)
|| (bottom > 0 || (bottom > 0
&& bottom < innerHeight)) && bottom < innerHeight))
&& ((left > 0 && ((left > 0
&& left < innerWidth) && left < innerWidth)
|| (right > 0 || (right > 0
&& right < innerWidth)) && right < innerWidth))
: (top >= 0 : (top >= 0
&& left >= 0 && left >= 0
&& bottom <= innerHeight && bottom <= innerHeight
&& right <= innerWidth) } && right <= innerWidth) }
//--------------------------------------------------------------------- //---------------------------------------------------------------------
// XXX should these be here??? // XXX should these be here???
HTMLElement.encode = function(str){ HTMLElement.encode = function(str){
var span = document.createElement('span') var span = document.createElement('span')
// XXX // XXX
return str return str
.replace(/&/g, '&amp;') .replace(/&/g, '&amp;')
.replace(/</g, '&lt;') .replace(/</g, '&lt;')
.replace(/>/g, '&gt;') } .replace(/>/g, '&gt;') }
/*/ /*/
span.innerText = str span.innerText = str
return span.innerHTML } return span.innerHTML }
//*/ //*/
// XXX this does not convert <br> back to \n... // XXX this does not convert <br> back to \n...
HTMLElement.decode = function(str){ HTMLElement.decode = function(str){
var span = document.createElement('span') var span = document.createElement('span')
// XXX // XXX
return str return str
.replace(/&lt;/g, '<') .replace(/&lt;/g, '<')
.replace(/&gt;/g, '>') .replace(/&gt;/g, '>')
.replace(/&amp;/g, '&') } .replace(/&amp;/g, '&') }
/*/ /*/
span.innerHTML = str span.innerHTML = str
return span.innerText } return span.innerText }
//*/ //*/
//--------------------------------------------------------------------- //---------------------------------------------------------------------
HTMLTextAreaElement.prototype.updateSize = function(){ HTMLTextAreaElement.prototype.updateSize = function(){
// NOTE: this is set to 0px to negate the effects of external/inherited // NOTE: this is set to 0px to negate the effects of external/inherited
// height settings... // height settings...
this.style.height = '0px' this.style.height = '0px'
this.style.height = this.scrollHeight + 'px' this.style.height = this.scrollHeight + 'px'
return this } return this }
HTMLTextAreaElement.prototype.autoUpdateSize = function(){ HTMLTextAreaElement.prototype.autoUpdateSize = function(){
var that = this var that = this
this.addEventListener('input', this.addEventListener('input',
function(evt){ function(evt){
that.updateSize() }) that.updateSize() })
return this } return this }
var cloneAsOffscreenSpan = function(elem){ var cloneAsOffscreenSpan = function(elem){
var style = getComputedStyle(elem) var style = getComputedStyle(elem)
var s = {} var s = {}
for(var i=0; i < style.length; i++){ for(var i=0; i < style.length; i++){
var k = style[i] var k = style[i]
if(k.startsWith('font') if(k.startsWith('font')
|| k.startsWith('line') || k.startsWith('line')
|| k.startsWith('white-space')){ || k.startsWith('white-space')){
s[k] = style[k] } } s[k] = style[k] } }
var span = document.createElement('span') var span = document.createElement('span')
Object.assign(span.style, { Object.assign(span.style, {
...s, ...s,
position: 'fixed', position: 'fixed',
display: 'block', display: 'block',
/* DEBUG... /* DEBUG...
top: '0px', top: '0px',
left: '0px', left: '0px',
/*/ /*/
top: '-100%', top: '-100%',
left: '-100%', left: '-100%',
//*/ //*/
width: style.width, width: style.width,
height: style.height, height: style.height,
padding: style.padding, padding: style.padding,
boxSizing: style.boxSizing, boxSizing: style.boxSizing,
whiteSpace: style.whiteSpace, whiteSpace: style.whiteSpace,
outline: 'solid 1px red', outline: 'solid 1px red',
pointerEvents: 'none', pointerEvents: 'none',
}) })
return span } return span }
HTMLTextAreaElement.prototype.getTextGeometry = function(func){ HTMLTextAreaElement.prototype.getTextGeometry = function(func){
var offset = this.selectionStart var offset = this.selectionStart
var text = this.value var text = this.value
// get the relevant styles... // get the relevant styles...
var style = getComputedStyle(this) var style = getComputedStyle(this)
var paddingV = parseFloat(style.paddingTop) + parseFloat(style.paddingBottom) var paddingV = parseFloat(style.paddingTop) + parseFloat(style.paddingBottom)
var caret = document.createElement('span') var caret = document.createElement('span')
caret.innerText = '|' caret.innerText = '|'
caret.style.margin = '0px' caret.style.margin = '0px'
caret.style.padding = '0px' caret.style.padding = '0px'
var span = cloneAsOffscreenSpan(this) var span = cloneAsOffscreenSpan(this)
span.append( span.append(
text.slice(0, offset), text.slice(0, offset),
caret, caret,
// NOTE: wee need the rest of the text for the caret to be typeset // NOTE: wee need the rest of the text for the caret to be typeset
// to the correct line... // to the correct line...
text.slice(offset)) text.slice(offset))
document.body.append(span) document.body.append(span)
var res = { var res = {
length: text.length, length: text.length,
lines: Math.floor( lines: Math.floor(
(this.offsetHeight - paddingV) (this.offsetHeight - paddingV)
/ caret.offsetHeight), / caret.offsetHeight),
line: Math.floor(caret.offsetTop / caret.offsetHeight), line: Math.floor(caret.offsetTop / caret.offsetHeight),
caretHeight: caret.offsetHeight, caretHeight: caret.offsetHeight,
offset: offset, offset: offset,
offsetLeft: caret.offsetLeft, offsetLeft: caret.offsetLeft,
offsetTop: caret.offsetTop, offsetTop: caret.offsetTop,
} }
if(typeof(func) == 'function'){ if(typeof(func) == 'function'){
res = func(res, span) } res = func(res, span) }
span.remove() span.remove()
return res } return res }
HTMLTextAreaElement.prototype.getTextOffsetAt = function(x, y){ HTMLTextAreaElement.prototype.getTextOffsetAt = function(x, y){
var that = this var that = this
var text = this.value var text = this.value
// cleanup cached span... // cleanup cached span...
this.__getTextOffsetAt_timeout this.__getTextOffsetAt_timeout
&& clearTimeout(this.__getTextOffsetAt_timeout) && clearTimeout(this.__getTextOffsetAt_timeout)
this.__getTextOffsetAt_timeout = setTimeout(function(){ this.__getTextOffsetAt_timeout = setTimeout(function(){
delete that.__getTextOffsetAt_timeout delete that.__getTextOffsetAt_timeout
that.__getTextOffsetAt_clone.remove() that.__getTextOffsetAt_clone.remove()
delete that.__getTextOffsetAt_clone }, 50) delete that.__getTextOffsetAt_clone }, 50)
// create/get clone span... // create/get clone span...
if(this.__getTextOffsetAt_clone == null){ if(this.__getTextOffsetAt_clone == null){
var span = var span =
this.__getTextOffsetAt_clone = this.__getTextOffsetAt_clone =
cloneAsOffscreenSpan(this) cloneAsOffscreenSpan(this)
span.append(text) span.append(text)
document.body.append(span) document.body.append(span)
} else { } else {
var span = this.__getTextOffsetAt_clone } var span = this.__getTextOffsetAt_clone }
var r = document.createRange() var r = document.createRange()
var t = span.firstChild var t = span.firstChild
var clone = span.getBoundingClientRect() var clone = span.getBoundingClientRect()
var target = this.getBoundingClientRect() var target = this.getBoundingClientRect()
var ox = x - target.x var ox = x - target.x
var oy = y - target.y var oy = y - target.y
var rect, prev var rect, prev
var cursor_line var cursor_line
var col var col
for(var i=0; i <= t.length; i++){ for(var i=0; i <= t.length; i++){
r.setStart(t, i) r.setStart(t, i)
r.setEnd(t, i) r.setEnd(t, i)
prev = rect prev = rect
rect = r.getBoundingClientRect() rect = r.getBoundingClientRect()
// line change... // line change...
if(prev && prev.y != rect.y){ if(prev && prev.y != rect.y){
// went off the cursor line // went off the cursor line
if(cursor_line if(cursor_line
// cursor above block // cursor above block
|| oy <= prev.y - clone.y){ || oy <= prev.y - clone.y){
// end of prev line... // end of prev line...
return col return col
?? i - 1 } ?? i - 1 }
// reset col // reset col
col = undefined } col = undefined }
// cursor line... // cursor line...
cursor_line = cursor_line =
oy >= rect.y - clone.y oy >= rect.y - clone.y
&& oy <= rect.bottom - clone.y && oy <= rect.bottom - clone.y
// cursor col -- set once per line... // cursor col -- set once per line...
if(col == null if(col == null
&& ox <= rect.x - clone.x){ && ox <= rect.x - clone.x){
col = (ox > 0 col = (ox > 0
|| i == 0) ? || i == 0) ?
i i
: i - 1 : i - 1
if(cursor_line){ if(cursor_line){
return col } } } return col } } }
// below or right of the block -> return last col or last char... // below or right of the block -> return last col or last char...
return col return col
?? i } ?? i }
// calculate number of lines in text area (both wrapped and actual lines) // calculate number of lines in text area (both wrapped and actual lines)
Object.defineProperty(HTMLTextAreaElement.prototype, 'heightLines', { Object.defineProperty(HTMLTextAreaElement.prototype, 'heightLines', {
enumerable: false, enumerable: false,
get: function(){ get: function(){
var style = getComputedStyle(this) var style = getComputedStyle(this)
return Math.floor( return Math.floor(
(this.scrollHeight (this.scrollHeight
- parseFloat(style.paddingTop) - parseFloat(style.paddingTop)
- parseFloat(style.paddingBottom)) - parseFloat(style.paddingBottom))
/ (parseFloat(style.lineHeight) / (parseFloat(style.lineHeight)
|| parseFloat(style.fontSize))) }, }) || parseFloat(style.fontSize))) }, })
Object.defineProperty(HTMLTextAreaElement.prototype, 'lines', { Object.defineProperty(HTMLTextAreaElement.prototype, 'lines', {
enumerable: false, enumerable: false,
get: function(){ get: function(){
return this.value return this.value
.split(/\n/g) .split(/\n/g)
.length }, }) .length }, })
// XXX this does not account for wrapping... // XXX this does not account for wrapping...
Object.defineProperty(HTMLTextAreaElement.prototype, 'caretLine', { Object.defineProperty(HTMLTextAreaElement.prototype, 'caretLine', {
enumerable: false, enumerable: false,
get: function(){ get: function(){
var offset = this.selectionStart var offset = this.selectionStart
return offset != null ? return offset != null ?
this.value this.value
.slice(0, offset) .slice(0, offset)
.split(/\n/g) .split(/\n/g)
.length .length
: undefined }, }) : undefined }, })
Object.defineProperty(HTMLTextAreaElement.prototype, 'caretOffset', { Object.defineProperty(HTMLTextAreaElement.prototype, 'caretOffset', {
enumerable: false, enumerable: false,
get: function(){ get: function(){
var offset = this.selectionStart var offset = this.selectionStart
var r = document.createRange() var r = document.createRange()
r.setStart(this, offset) r.setStart(this, offset)
r.setEnd(this, offset) r.setEnd(this, offset)
var rect = r.getBoundingClientRect() var rect = r.getBoundingClientRect()
return { return {
top: rect.top, top: rect.top,
left: rect.left, left: rect.left,
} }, } },
}) })
/********************************************************************** /**********************************************************************
* vim:set ts=4 sw=4 : */ * vim:set ts=4 sw=4 : */