Skip to content

Instantly share code, notes, and snippets.

@typeofweb
Last active December 26, 2015 12:49
Show Gist options
  • Save typeofweb/7153571 to your computer and use it in GitHub Desktop.
Save typeofweb/7153571 to your computer and use it in GitHub Desktop.
/*
*
* Works nicely with the following styles:
* textarea {
* resize: none;
* transition: height 0.1s;
* }
*
* Usage: <textarea autoexpand></textarea>
*/
'use strict';
angular.module('app')
.directive('autoexpand', ['$timeout', function ($timeout) {
return function (scope, element) {
var maxHeight = element.css('max-height') || 1e9;
var $shadow = $('<div/>');
$shadow.appendTo('body');
$shadow.css({
'white-space': 'pre-wrap',
'font-family': element.css('font-family'),
'font-size': element.css('font-size'),
'padding': element.css('padding'),
'word-wrap': 'break-word',
'line-height': element.css('line-height'),
top: -1000,
left: -1000,
'position': 'absolute'
});
var update = function () {
var val = element.val().replace('\n', '<br>');
$shadow.html(val);
$shadow.width(element.width());
$timeout(function () {
var height = $shadow.outerHeight() + 15;
if (height > maxHeight) {
height = maxHeight;
}
element.css({height: height});
}, 0);
};
element.bind('change keyup keydown keypress ', update);
scope.$on('$destroy', function () {
$shadow.remove();
});
};
}]);
'use strict';
describe('Autoexpand directive', function () {
var $scope, $compile;
beforeEach(module('app'));
beforeEach(inject(function (_$rootScope_, _$compile_) {
$scope = _$rootScope_;
$compile = _$compile_;
}));
describe('textarea', function () {
var compileTa = function (markup, scope) {
var $el = $compile(markup)(scope);
scope.$digest();
return $el;
};
var shadow;
afterEach(function () {
shadow.remove();
});
it('should copy text to the shadow element', function () {
var ta = compileTa('<textarea autoexpand>text</textarea>', $scope);
shadow = angular.element('body').find('div').last();
ta.trigger('keypress');
expect(shadow.text()).toEqual('text');
ta.text('lol wut xD');
ta.trigger('keypress');
expect(shadow.text()).toEqual('lol wut xD');
});
it('should replace \\n with <br>', function () {
var ta = compileTa('<textarea autoexpand>text1\ntext2</textarea>', $scope);
shadow = angular.element('body').find('div').last();
ta.trigger('keypress');
expect(shadow.html()).toEqual('text1<br>text2');
});
it('should increase height of the textarea while typing', inject(function ($timeout) {
var ta = compileTa('<textarea autoexpand>t\nt\nt\nt\nt\nt\nt\n</textarea>', $scope);
ta.appendTo('body');
ta.css({
'width': '10px'
});
shadow = angular.element('body').find('div').last();
ta.trigger('keypress');
$timeout.flush();
expect(shadow.width()).toBe(10);
var oldHeight = ta.height();
expect(oldHeight).toBe(shadow.height() + 15);
ta.html('a\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\na');
ta.trigger('keypress');
$timeout.flush();
var newHeight = ta.height();
expect(newHeight).not.toEqual(oldHeight);
expect(newHeight).toBe(shadow.height() + 15);
}));
});
});
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment