-
Notifications
You must be signed in to change notification settings - Fork 21
Expand file tree
/
Copy pathangular-elastic-input.js
More file actions
148 lines (110 loc) · 4.79 KB
/
Copy pathangular-elastic-input.js
File metadata and controls
148 lines (110 loc) · 4.79 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
/**
* angular-elastic-input
* A directive for AngularJS which automatically resizes the width of input field according to the content, while typing.
* @author: Jacek Pulit <jacek.pulit@gmail.com>
* @license: MIT License
*/
'use strict';
angular.module('puElasticInput', []).directive('puElasticInput', ['$document', '$window', function($document, $window) {
var wrapper = angular.element('<div style="position:fixed; top:-999px; left:0;"></div>');
angular.element($document[0].body).append(wrapper);
function getStyle(oElm, css3Prop){
var strValue = "";
if(window.getComputedStyle){
strValue = getComputedStyle(oElm).getPropertyValue(css3Prop);
} else if (oElm.currentStyle){ //IE
try {
strValue = oElm.currentStyle[css3Prop];
} catch (e) {}
}
return strValue;
}
function getCalculate(parent) {
return parseInt(getStyle(parent, 'width'), 10) - parseInt(getStyle(parent, 'padding-left'), 10) - parseInt(getStyle(parent, 'padding-right'), 10);
}
function getClosest(element, selector) {
var matchesFn;
var matchesArray = ['matches', 'webkitMatchesSelector', 'mozMatchesSelector', 'msMatchesSelector', 'oMatchesSelector'];
matchesArray.some(function (fn) {
if (typeof document.body[fn] === 'function') {
matchesFn = fn;
return true;
}
return false;
});
while (element !== null) {
var parent = element.parentElement;
if (parent !== null && parent[matchesFn](selector)) {
return parent;
}
element = parent;
}
return null;
}
function getClosestWidth(element, selector) {
var parent = getClosest(element[0], selector);
var width = getCalculate(parent);
return width + 'px';
}
function getParentWidth(element) {
var parent = element[0], width;
do {
parent = parent.parentNode;
width = getCalculate(parent);
} while( getStyle(parent, 'display') != 'block' && parent.nodeName.toLowerCase() != 'body' );
return width + 'px';
}
function setMirrorStyle(mirror, element, attrs) {
var style = $window.getComputedStyle(element[0]);
var closestElement = attrs.puElasticInputClosest || null;
var defaultMaxWidth;
if (closestElement) {
defaultMaxWidth = getClosestWidth(element, closestElement);
} else {
defaultMaxWidth = style.maxWidth === 'none' ? getParentWidth(element) : style.maxWidth;
}
element.css('minWidth', attrs.puElasticInputMinwidth || style.minWidth);
element.css('maxWidth', attrs.puElasticInputMaxwidth || defaultMaxWidth);
angular.forEach(['fontFamily', 'fontSize', 'fontWeight', 'fontStyle',
'letterSpacing', 'textTransform', 'wordSpacing'], function(value) {
mirror.css(value, style[value]);
});
mirror.css('paddingLeft', style.textIndent);
if (style.boxSizing === 'border-box') {
angular.forEach(['paddingLeft', 'paddingRight',
'borderLeftStyle', 'borderLeftWidth',
'borderRightStyle', 'borderRightWidth'], function(value) {
mirror.css(value, style[value]);
});
} else if (style.boxSizing === 'padding-box') {
angular.forEach(['paddingLeft', 'paddingRight'], function(value) {
mirror.css(value, style[value]);
});
}
}
return {
restrict: 'A',
link: function postLink(scope, element, attrs) {
// Disable trimming inputs by default
attrs.$set('ngTrim', attrs.ngTrim === 'true' ? 'true' : 'false');
// Initial value of mirror is null character what should trigger initial width update
var mirror = angular.element('<span style="white-space:pre;">�</span>');
setMirrorStyle(mirror, element, attrs);
wrapper.append(mirror);
function update() {
var newValue = element.val() || attrs.placeholder || '';
// If new value is the same value as previous one there is no need to update the styling
if ( mirror.text() == newValue ) return;
mirror.text( newValue );
var delta = parseInt(attrs.puElasticInputWidthDelta) || 1;
element.css('width', mirror.prop('offsetWidth') + delta + 'px');
}
update();
scope.$watch(attrs.ngModel, update);
element.on('keydown keyup focus input propertychange change', update);
scope.$on('$destroy', function() {
mirror.remove();
});
}
};
}]);