mirror of
https://github.com/flynx/pWiki.git
synced 2025-10-28 09:30:07 +00:00
win -> unix
Signed-off-by: Alex A. Naanou <alex.nanou@gmail.com>
This commit is contained in:
parent
2c2257b603
commit
ada5c33665
@ -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, '<')
|
||||
.replace(/>/g, '>') }
|
||||
/*/
|
||||
span.innerText = str
|
||||
return span.innerHTML }
|
||||
//*/
|
||||
// XXX this does not convert <br> 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, '<')
|
||||
.replace(/>/g, '>') }
|
||||
/*/
|
||||
span.innerText = str
|
||||
return span.innerHTML }
|
||||
//*/
|
||||
// XXX this does not convert <br> 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 : */
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user