Compare commits

...

3 Commits

Author SHA1 Message Date
ada5c33665 win -> unix
Signed-off-by: Alex A. Naanou <alex.nanou@gmail.com>
2025-02-06 15:52:06 +03:00
2c2257b603 notes...
Signed-off-by: Alex A. Naanou <alex.nanou@gmail.com>
2025-02-06 15:51:23 +03:00
0d0fbadc2f ...
Signed-off-by: Alex A. Naanou <alex.nanou@gmail.com>
2025-02-03 13:49:10 +03:00
2 changed files with 267 additions and 266 deletions

View File

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

View File

@ -752,4 +752,4 @@ var setup = function(){
</body> </body>
</html> </html>
<!-- vim:set ts=4 sw=4 : --> <!-- vim:set ts=4 sw=4 nowrap : -->