212 lines
7.9 KiB
JavaScript
212 lines
7.9 KiB
JavaScript
// Based off https://code.google.com/p/gaequery/source/browse/trunk/src/static/scripts/jquery.autogrow-textarea.js?r=2
|
|
// Modified by David Beck
|
|
// Mofified by kasimi (c) 2016
|
|
|
|
( function( factory ) {
|
|
// UMD wrapper
|
|
if ( typeof define === 'function' && define.amd ) {
|
|
// AMD
|
|
define( [ 'jquery' ], factory );
|
|
} else if ( typeof exports !== 'undefined' ) {
|
|
// Node/CommonJS
|
|
module.exports = factory( require( 'jquery' ) );
|
|
} else {
|
|
// Browser globals
|
|
factory( jQuery );
|
|
}
|
|
}( function( $ ) {
|
|
|
|
/*
|
|
* Auto-growing textareas; technique ripped from Facebook
|
|
*/
|
|
$.fn.autogrow = function(options) {
|
|
|
|
options = $.extend( {
|
|
vertical: true,
|
|
horizontal: false,
|
|
characterSlop: 0
|
|
}, options);
|
|
|
|
this.filter('textarea,input').each(function() {
|
|
|
|
var $this = $(this),
|
|
borderBox = $this.css( 'box-sizing' ) === 'border-box',
|
|
// minHeight = borderBox ? $this.outerHeight() : $this.height(),
|
|
maxHeight = $this.attr( "maxHeight" ),
|
|
minWidth = typeof( $this.attr( "minWidth" ) ) == "undefined" ? 0 : $this.attr( "minWidth" );
|
|
|
|
if( typeof( maxHeight ) == "undefined" ) maxHeight = 1000000;
|
|
|
|
var shadow = $('<div class="autogrow-shadow"></div>').css( {
|
|
position: 'absolute',
|
|
top: -10000,
|
|
left: -10000,
|
|
fontSize: $this.css('fontSize'),
|
|
fontFamily: $this.css('fontFamily'),
|
|
fontWeight: $this.css('fontWeight'),
|
|
lineHeight: $this.css('lineHeight'),
|
|
paddingLeft: $this.css('paddingLeft'),
|
|
paddingRight: $this.css('paddingRight'),
|
|
paddingTop: $this.css('paddingTop'),
|
|
paddingBottom: $this.css('paddingBottom'),
|
|
borderTop: $this.css('borderTop'),
|
|
borderBottom: $this.css('borderBottom'),
|
|
borderLeft: $this.css('borderLeft'),
|
|
borderRight: $this.css('borderRight'),
|
|
whiteSpace: 'pre-wrap',
|
|
resize: 'none'
|
|
} ).appendTo(document.body);
|
|
|
|
shadow.html( 'a' );
|
|
var characterWidth = shadow.width();
|
|
shadow.html( '' );
|
|
var isTextarea = $this.is('textarea');
|
|
|
|
var update = function( val ) {
|
|
|
|
var times = function(string, number) {
|
|
for (var i = 0, r = ''; i < number; i ++) r += string;
|
|
return r;
|
|
};
|
|
|
|
if( typeof val === 'undefined' ) val = this.value;
|
|
if( val === '' && $(this).attr("placeholder") ) val = $(this).attr("placeholder");
|
|
|
|
if( options.vertical )
|
|
val = val.replace(/&/g, '&')
|
|
.replace(/</g, '<')
|
|
.replace(/>/g, '>')
|
|
.replace(/\n$/, '<br/> ')
|
|
.replace(/\n/g, '<br/>')
|
|
.replace(/ {2,}/g, function(space) { return times(' ', space.length -1) + ' '; });
|
|
else
|
|
val = escapeHtml( val );
|
|
|
|
//if( options.horizontal )
|
|
// val = $.trim( val );
|
|
|
|
// if( $(this).prop( 'tagName' ).toUpperCase() === 'INPUT' )
|
|
// shadow.text(val).css( "width", "auto" );
|
|
// else
|
|
shadow.html( val ).css( "width", "auto" ); // need to use html here otherwise no way to count spaces (with html we can use )
|
|
|
|
if( options.horizontal )
|
|
{
|
|
var slopWidth = options.characterSlop * characterWidth + 2;
|
|
|
|
var newWidth = Math.max( shadow.width() + slopWidth, minWidth );
|
|
var maxWidth = options.maxWidth;
|
|
//if( typeof( maxWidth ) === "undefined" ) maxWidth = $this.parent().width() - 12; // not sure why we were doing this but seems like a bad idea. doesn't work with inline-block parents for one thing, since it is the text area that should be "pushing" them to be wider
|
|
if( maxWidth ) newWidth = Math.min( newWidth, maxWidth );
|
|
// Take scrollbar into account
|
|
if (isTextarea && shadow.get(0).scrollHeight > shadow.height()) {
|
|
newWidth += 20;
|
|
}
|
|
$(this).css( "width", newWidth );
|
|
}
|
|
|
|
if( options.vertical )
|
|
{
|
|
var shadowWidth = $(this).width();
|
|
if( ! borderBox ) shadowWidth = shadowWidth - parseInt($this.css('paddingLeft'),10) - parseInt($this.css('paddingRight'),10);
|
|
shadow.css( "width", shadowWidth );
|
|
var shadowHeight = borderBox ? shadow.outerHeight() : shadow.height();
|
|
|
|
$(this).css( "height", "auto" );
|
|
minHeight = borderBox ? $this.outerHeight() : $this.height();
|
|
|
|
var newHeight = Math.min( Math.max( shadowHeight, minHeight ), maxHeight );
|
|
$(this).css( "height", newHeight );
|
|
$(this).css( "overflow", newHeight == maxHeight ? "auto" : "hidden" );
|
|
}
|
|
};
|
|
|
|
$(this)
|
|
.change(function(){update.call( this );return true;})
|
|
.keyup(function(){update.call( this );return true;})
|
|
.keypress(function( event ) {
|
|
if( event.ctrlKey || event.metaKey ) return;
|
|
|
|
var val = this.value;
|
|
var caretInfo = _getCaretInfo( this );
|
|
|
|
var typedChar = event.which === 13 ? "\n" : String.fromCharCode( event.which );
|
|
var valAfterKeypress = val.slice( 0, caretInfo.start ) + typedChar + val.slice( caretInfo.end );
|
|
update.call( this, valAfterKeypress );
|
|
return true;
|
|
})
|
|
.bind( "update.autogrow", function(){ update.apply(this); } )
|
|
.bind( "remove.autogrow", function() {
|
|
shadow.remove();
|
|
} );
|
|
|
|
update.apply(this);
|
|
|
|
});
|
|
|
|
return this;
|
|
};
|
|
|
|
// comes from https://github.com/madapaja/jquery.selection/blob/master/src/jquery.selection.js
|
|
var _getCaretInfo = function(element){
|
|
var res = {
|
|
text: '',
|
|
start: 0,
|
|
end: 0
|
|
};
|
|
|
|
if (!element.value) {
|
|
/* no value or empty string */
|
|
return res;
|
|
}
|
|
|
|
try {
|
|
if (window.getSelection) {
|
|
/* except IE */
|
|
res.start = element.selectionStart;
|
|
res.end = element.selectionEnd;
|
|
res.text = element.value.slice(res.start, res.end);
|
|
} else if (doc.selection) {
|
|
/* for IE */
|
|
element.focus();
|
|
|
|
var range = doc.selection.createRange(),
|
|
range2 = doc.body.createTextRange();
|
|
|
|
res.text = range.text;
|
|
|
|
try {
|
|
range2.moveToElementText(element);
|
|
range2.setEndPoint('StartToStart', range);
|
|
} catch (e) {
|
|
range2 = element.createTextRange();
|
|
range2.setEndPoint('StartToStart', range);
|
|
}
|
|
|
|
res.start = element.value.length - range2.text.length;
|
|
res.end = res.start + range.text.length;
|
|
}
|
|
} catch (e) {
|
|
/* give up */
|
|
}
|
|
|
|
return res;
|
|
};
|
|
|
|
var entityMap = {
|
|
"&": "&",
|
|
"<": "<",
|
|
">": ">",
|
|
'"': '"',
|
|
"'": ''',
|
|
"/": '/',
|
|
" ": ' '
|
|
};
|
|
|
|
function escapeHtml(string) {
|
|
return String(string).replace(/[&<>"'\/\ ]/g, function (s) {
|
|
return entityMap[s];
|
|
} );
|
|
}
|
|
} ) );
|