-
Notifications
You must be signed in to change notification settings - Fork 1
Expand file tree
/
Copy pathflext-uncompressed.js
More file actions
264 lines (253 loc) · 9.45 KB
/
flext-uncompressed.js
File metadata and controls
264 lines (253 loc) · 9.45 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
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
/*
* Flext - A Mootools Based Flexible TextArea Class
* version 1.1 - for mootools 1.2
* by Graham McNicoll
*
* Copyright 2008-2009 - Education.com
* License: MIT-style license.
*
* Features:
* - Grows text areas when needed
* - Can set a max height to grow to
* - Grows parents if they have a fixed height
* - Ghost text replacement
* - Text input emulation (enter can submit form, instead of new line)
* - Restore the old height, if the value = '' (@ledil patch)
*
* Usage:
*
* include the source somewhere on your page. Textareas must have the class name: 'flext'
* for the class to watch them. Use additional class names to trigger features.
*
* 'growme' - grow the text area
* 'maxheight-[num]' - the max height to grow in pixels (replaces [num] )
* 'stopenter' - stop the enter key
* 'entersubmits' - submit the form when enter is pressed
* 'replaceghosttext' - tries to use the ghosted text features
* 'growparents' - grow the parent elements if needed
*
* if replaceghosttext is on, then you need to add two more attributes to the textarea.
* 'ghosttext' contains a copy of the original ghost text (needed for matching initial conditions),
* and 'ghostclass' which contains a class name to remove when the ghosting is removed (which
* is used to remove ghosting color).
*
* Examples:
*
* A simple growing text area: -
*
* <textarea name='mytext' class='flext growme maxheight-200' ></textarea>
*
* It will find this text area by the class name, 'flext', and the 'growme'
* class will tell it to grow until the max size, as given by the 'maxheight-[num]'
* class (integer, in pixels).
*
* Textarea which will grow the parent elements (if needed) -
*
* <textarea name='mytext' class='flext growme growparents maxheight-200' ></textarea>
*
* This is the same as above, except it will also grow any parent elements which
* have fixed heights when the textarea expands ('growparents').
*
*
* Adv. example:
*
* <textarea name='mytext' class='flext growme stopenter entersubmits replaceghosttext ghost-text growparents maxheight-60' ghosttext='enter something here' ghostclass='ghost-text'>
* enter something here
* </textarea>
*
* This example not only grows, but simulates a text input, in that 'enter'
* will not be passed to the textarea ('stopenter') instead it will submit
* the form ('entersubmits'). It also has ghosted text replacement and class
* changing. When this textarea receives focus, it will remove the default
* text (ghosttext property), and remove the class as specified by the
* ghostclass property. Use of these features as currently coded requires
* non valid xhtml, so dont use it if you require valid markup. (its on my list to fix)
*
* You can also instantiate this class manually, by leaving off the 'flext' class from
* any textareas, and instantiate a new class usual with the first variable being the
* textarea element, and the second the options object.
*/
var Flext = new Class({
Implements: Options,
options: {
aniTime: 300, //int (ms) - grow animation time
maxHeight: 0, //int (pixels) - one way to set a max height, if you dont set it via the class.
defaultMaxHeight: 1000, //int (pixels) - if not otherwise set, this is the max height
parentDepth: 6, //int - how many levels up should to check the parent el's height.
//trigger classes:
growClass: 'growme', //string (class name)- grow the text area
enterStoppedClass: 'stopenter', //string (class name)- stop the enter key
enterSubmitsClass: 'entersubmits', //string (class name)- submit the form when enter is pressed
replaceGhostTextClass: 'replaceghosttext', //string (class name)- tries to use the ghosted text features
growParentsClass: 'growparents', //string (class name)- grow the parent elements if needed
//other attributes:
ghostTextAttr: 'ghosttext',
ghostClassAttr: 'ghostclass'
},
initialize: function(el, options) {
this.setOptions(options);
this.el = $(el); //the textarea element.
//by default, we will do nothing to the text area unless it has the class...
this.autoGrow = el.hasClass(this.options.growClass);
this.stopEnter = el.hasClass(this.options.enterStoppedClass);
this.enterSubmits = el.hasClass(this.options.enterSubmitsClass);
this.useGhostText = el.hasClass(this.options.replaceGhostTextClass);
this.growParents = el.hasClass(this.options.growParentsClass);
//initialize, and add events:
if(this.autoGrow) {
this.origHeight = this.getOrigHeight();
this.resizer = new Fx.Tween(this.el, {duration: this.options.aniTime});
this.getMaxSize();
this.reachedMax = false;
this.startSize = this.origSize = this.el.getSize().y;
this.vertPadding = this.el.getStyle('padding-top').toInt()+this.el.getStyle('padding-bottom').toInt()+this.el.getStyle('border-top').toInt()+this.el.getStyle('border-bottom').toInt();
this.el.setStyle('overflow', 'hidden');
this.el.addEvents({
'keyup': function(e) {
this.checkSize(e);
}.bind(this),
'change': function(e) {
this.checkSize(e);
}.bind(this),
'click': function(e) {
this.checkSize(e);
}.bind(this)
});
//get inital state:
this.checkSize();
}
//watch this text area: keydown
if(this.stopEnter) {
this.el.addEvent('keydown', function(e) {
if(e.key == 'enter') {
e.stop();
if(this.enterSubmits) {
this.submitForm();
}
}
}.bind(this));
}
//replace ghost text:
if(this.useGhostText) {
this.ghostText = this.el.get(this.options.ghostTextAttr);
this.ghostClass = this.el.get(this.options.ghostClassAttr);
if(this.ghostText) {
//initial states: if populated with something else, remove the class:
if(this.el.value != this.ghostText) {
this.el.removeClass(this.ghostClass);
}
//add events to watch for ghosting:
this.el.addEvents({
//remove the ghosted text when the text area receives focus
'focus': function(e) {
if(this.el.value == this.ghostText) {
this.el.set('value', '');
if(this.ghostClass) {
this.el.removeClass(this.ghostClass);
}
}
}.bind(this),
//put the ghost text back if blur'ed and its empty
'blur': function(e) {
if(this.el.value == '') {
this.el.set('value', this.ghostText);
this.resizer.start('height', this.origHeight);
if(this.ghostClass) {
this.el.addClass(this.ghostClass);
}
}
}.bind(this)
});
}
}
},
getOrigHeight: function() {
var padds = this.el.getStyle('padding');
var padds_top = padds.split(' ')[0].split('px')[0];
var padds_bottom = padds.split(' ')[2].split('px')[0];
var border_top = this.el.getStyle('border-top').split('px')[0];
var border_bottom = this.el.getStyle('border-bottom').split('px')[0];
return this.el.getCoordinates().height-parseInt(padds_top)-parseInt(padds_bottom)-parseInt(border_top)-parseInt(border_bottom);
},
getMaxSize: function() {
this.maxSize = this.options.maxHeight;
if(this.maxSize == 0) {
var testmax = this.el.className.match(/maxheight-(\d*)/);
if(testmax) {
this.maxSize = testmax[1];
}
else {
this.maxSize = this.options.defaultMaxHeight; //if one forgets to set a max height via options or class, use a reasonable number.
}
}
},
checkSize: function(e) {
var theSize = this.el.getSize();
var theScrollSize = this.el.getScrollSize();
if(navigator.userAgent.toLowerCase().indexOf('chrome') > -1) { var checksize = (theScrollSize.y); }
else var checksize = (theScrollSize.y+this.vertPadding);
if(checksize > theSize.y) {
//we are scrolling, so grow:
this.resizeIt(theSize, theScrollSize);
}
},
resizeIt: function(theSize, scrollSize) {
var newSize = scrollSize.y;
if((scrollSize.y+this.vertPadding) > this.maxSize && !this.reachedMax) {
//we've reached the max size, grow to max size and make textarea scrollable again:
newSize = this.maxSize;
this.el.setStyle('overflow', '');
this.resizer.start('height', newSize);
if(this.growParents) {
var increasedSize = newSize - this.startSize;
this.resizeParents(this.el, 0, increasedSize);
}
//remember that we've reached the max size:
this.reachedMax = true;
}
if(!this.reachedMax) {
//grow the text area:
var increasedSize = newSize - this.startSize;
if(increasedSize < 0) increasedSize = 0;
this.startSize = newSize;
this.resizer.start('height', newSize);
//resize parent objects if needed:
if(this.growParents) {
this.resizeParents(this.el, 0, increasedSize);
}
}
},
resizeParents: function(el, num, incSize) {
if(num < this.options.parentDepth) {
var newel = el.getParent();
if(newel) {
if(newel.style.height && newel.style.height != '' ) {
if(newel.retrieve('flextAdjusted')) {
var newheight = (newel.getStyle('height').toInt()+incSize);
} else {
newel.store('flextAdjusted', true); //when resizing parents, the first time we enlarge them we have to include vertical padding
var newheight = (newel.getStyle('height').toInt()+incSize+this.vertPadding);
}
newel.setStyle('height', newheight);
}
return this.resizeParents(newel, (num+1), incSize);
}
return true;
} else {
return true;
}
},
submitForm: function() {
var thisForm = this.el.getParent('form');
if(thisForm) {
var formName = thisForm.get('name');
document[formName].submit();
}
}
});
//watch the text areas:
window.addEvent('domready', function() {
$$('textarea.flext').each(function(el, i) {
new Flext(el);
});
});