forked from brandonaaron/jquery-expandable
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
eb78b89
commit 5511f87
Showing
2 changed files
with
88 additions
and
80 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,101 +1,109 @@ | ||
/*! Copyright (c) 2013 Brandon Aaron (http://brandonaaron.net) | ||
* Licensed under the MIT License (LICENSE.txt). | ||
* | ||
* Version 1.1.1 | ||
* Version 1.1.2 | ||
* | ||
* Contributions by: | ||
* - Karl Swedberg | ||
* - Pistos | ||
*/ | ||
|
||
(function($) { | ||
|
||
$.fn.extend({ | ||
expandable: function(givenOptions) { | ||
var options = $.extend({ | ||
duration: 'normal', | ||
interval: 750, | ||
within: 1, | ||
by: 2, | ||
maxRows: false, | ||
init: false | ||
}, givenOptions); | ||
(function (factory) { | ||
if (typeof define === 'function' && define.amd) { | ||
// AMD. Register as an anonymous module. | ||
define(['jquery'], factory); | ||
} else { | ||
// Browser globals | ||
factory(jQuery); | ||
} | ||
}(function ($) { | ||
|
||
return this.filter('textarea').each(function() { | ||
var $this = $(this).css({ display: 'block', overflow: 'hidden' }), | ||
minHeight = $this.height(), | ||
heightDiff = this.offsetHeight - minHeight, | ||
rowSize = ( parseInt($this.css('lineHeight'), 10) || parseInt($this.css('fontSize'), 10) ), | ||
// $mirror is used for determining the height of the text within the textarea | ||
// it isn't perfect but is pretty close | ||
// white-space rules from: http://petesbloggerama.blogspot.com/2007/02/firefox-ie-word-wrap-word-break-tables.html | ||
$mirror = $('<div style="position:absolute;top:-999px;left:-999px;border-color:#000;border-style:solid;overflow-x:hidden;visibility:hidden;z-index:0;white-space: pre-wrap;white-space:-moz-pre-wrap;white-space:-pre-wrap;white-space:-o-pre-wrap;word-wrap:break-word;" />').appendTo('body'), | ||
maxHeight = false, | ||
interval; | ||
$.fn.extend({ | ||
expandable: function(givenOptions) { | ||
var options = $.extend({ | ||
duration: 'normal', | ||
interval: 750, | ||
within: 1, | ||
by: 2, | ||
maxRows: false, | ||
init: false | ||
}, givenOptions); | ||
|
||
if ( options.maxRows ) { | ||
maxHeight = options.maxRows * rowSize; | ||
} | ||
return this.filter('textarea').each(function() { | ||
var $this = $(this).css({ display: 'block', overflow: 'hidden' }), | ||
minHeight = $this.height(), | ||
heightDiff = this.offsetHeight - minHeight, | ||
rowSize = ( parseInt($this.css('lineHeight'), 10) || parseInt($this.css('fontSize'), 10) ), | ||
// $mirror is used for determining the height of the text within the textarea | ||
// it isn't perfect but is pretty close | ||
// white-space rules from: http://petesbloggerama.blogspot.com/2007/02/firefox-ie-word-wrap-word-break-tables.html | ||
$mirror = $('<div style="position:absolute;top:-999px;left:-999px;border-color:#000;border-style:solid;overflow-x:hidden;visibility:hidden;z-index:0;white-space: pre-wrap;white-space:-moz-pre-wrap;white-space:-pre-wrap;white-space:-o-pre-wrap;word-wrap:break-word;" />').appendTo('body'), | ||
maxHeight = false, | ||
interval; | ||
|
||
// copy styles from textarea to mirror to mirror the textarea as best possible | ||
$.each('borderTopWidth borderRightWidth borderBottomWidth borderLeftWidth paddingTop paddingRight paddingBottom paddingLeft fontSize fontFamily fontWeight fontStyle fontStretch fontVariant wordSpacing lineHeight width'.split(' '), function(i,prop) { | ||
$mirror.css(prop, $this.css(prop)); | ||
}); | ||
if ( options.maxRows ) { | ||
maxHeight = options.maxRows * rowSize; | ||
} | ||
|
||
// setup events | ||
$this | ||
.bind('keypress', function(event) { if ( event.keyCode == '13' ) check(); }) | ||
.bind('focus blur', function(event) { | ||
if ( event.type == 'blur' ) clearInterval( interval ); | ||
if ( event.type == 'focus' ) interval = setInterval(check, options.interval); | ||
// copy styles from textarea to mirror to mirror the textarea as best possible | ||
$.each('borderTopWidth borderRightWidth borderBottomWidth borderLeftWidth paddingTop paddingRight paddingBottom paddingLeft fontSize fontFamily fontWeight fontStyle fontStretch fontVariant wordSpacing lineHeight width'.split(' '), function(i,prop) { | ||
$mirror.css(prop, $this.css(prop)); | ||
}); | ||
|
||
function check() { | ||
var text = $this.val(), newHeight, height, usedHeight, usedRows, availableRows; | ||
// copy textarea value to the $mirror | ||
// encode any html passed in and replace new lines with a <br> | ||
// the is to try and normalize browser behavior | ||
$mirror.html( encodeHTML(text).replace(/\n/g, ' <br>') ); | ||
// setup events | ||
$this | ||
.bind('keypress', function(event) { if ( event.keyCode == '13' ) check(); }) | ||
.bind('focus blur', function(event) { | ||
if ( event.type == 'blur' ) clearInterval( interval ); | ||
if ( event.type == 'focus' ) interval = setInterval(check, options.interval); | ||
}); | ||
|
||
height = $this[0].offsetHeight - heightDiff; | ||
usedHeight = $mirror[0].offsetHeight - heightDiff; | ||
usedRows = Math.floor(usedHeight / rowSize); | ||
availableRows = Math.floor((height / rowSize) - usedRows); | ||
function check() { | ||
var text = $this.val(), newHeight, height, usedHeight, usedRows, availableRows; | ||
// copy textarea value to the $mirror | ||
// encode any html passed in and replace new lines with a <br> | ||
// the is to try and normalize browser behavior | ||
$mirror.html( encodeHTML(text).replace(/\n/g, ' <br>') ); | ||
|
||
if ( maxHeight && usedHeight >= maxHeight ) { | ||
$this.css({ display: 'auto', overflow: 'auto' }); | ||
return; | ||
} | ||
height = $this[0].offsetHeight - heightDiff; | ||
usedHeight = $mirror[0].offsetHeight - heightDiff; | ||
usedRows = Math.floor(usedHeight / rowSize); | ||
availableRows = Math.floor((height / rowSize) - usedRows); | ||
|
||
// adjust height if needed by either growing or shrinking the text area to within the specified bounds | ||
if ( availableRows <= options.within ) { | ||
newHeight = rowSize * (usedRows + Math.max(availableRows, 0) + options.by); | ||
if ( maxHeight ) { | ||
newHeight = Math.min(newHeight, maxHeight); | ||
if ( maxHeight && usedHeight >= maxHeight ) { | ||
$this.css({ display: 'auto', overflow: 'auto' }); | ||
return; | ||
} | ||
$this.stop().animate({ height: newHeight }, options.duration); | ||
} else if ( availableRows > options.by + options.within ) { | ||
newHeight = Math.max( height - (rowSize * (availableRows - (options.by + options.within))), minHeight ); | ||
$this.stop().animate({ height: newHeight }, options.duration); | ||
} | ||
}; | ||
if ( options.init ) check(); | ||
}).end(); | ||
} | ||
}); | ||
|
||
function encodeHTML(text) { | ||
var characters = { | ||
'<' : '<', | ||
'>' : '>', | ||
'&' : '&', | ||
'"' : '"', | ||
'\'': ''', | ||
'/' : '/' | ||
}; | ||
return (text + '').replace(/[<>&"'\/]/g, function(c) { | ||
return characters[c]; | ||
// adjust height if needed by either growing or shrinking the text area to within the specified bounds | ||
if ( availableRows <= options.within ) { | ||
newHeight = rowSize * (usedRows + Math.max(availableRows, 0) + options.by); | ||
if ( maxHeight ) { | ||
newHeight = Math.min(newHeight, maxHeight); | ||
} | ||
$this.stop().animate({ height: newHeight }, options.duration); | ||
} else if ( availableRows > options.by + options.within ) { | ||
newHeight = Math.max( height - (rowSize * (availableRows - (options.by + options.within))), minHeight ); | ||
$this.stop().animate({ height: newHeight }, options.duration); | ||
} | ||
}; | ||
if ( options.init ) check(); | ||
}).end(); | ||
} | ||
}); | ||
} | ||
|
||
})(jQuery); | ||
function encodeHTML(text) { | ||
var characters = { | ||
'<' : '<', | ||
'>' : '>', | ||
'&' : '&', | ||
'"' : '"', | ||
'\'': ''', | ||
'/' : '/' | ||
}; | ||
return (text + '').replace(/[<>&"'\/]/g, function(c) { | ||
return characters[c]; | ||
}); | ||
} | ||
|
||
})); |