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