Compare commits

..

No commits in common. "ada5c336654868c5dea6a663611e758cd1d79814" and "ea9e521e91c84f69989b12b3a6a030897cc6242a" have entirely different histories.

2 changed files with 266 additions and 267 deletions

View File

@ -1,266 +1,265 @@
/********************************************************************** /**********************************************************************
* *
* *
* *
**********************************************************************/ **********************************************************************/
// 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 : */

View File

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