Merge lp:~bac/juju-gui/autosize-plugin into lp:juju-gui/experimental

Proposed by Brad Crittenden
Status: Needs review
Proposed branch: lp:~bac/juju-gui/autosize-plugin
Merge into: lp:juju-gui/experimental
Diff against target: 339 lines (+289/-0)
5 files modified
Makefile (+2/-0)
app/modules-debug.js (+5/-0)
app/plugins/textarea-autosize.js (+191/-0)
test/index.html (+1/-0)
test/test_textarea_autosize.js (+90/-0)
To merge this branch: bzr merge lp:~bac/juju-gui/autosize-plugin
Reviewer Review Type Date Requested Status
Juju GUI Hackers Pending
Review via email: mp+161685@code.launchpad.net

Description of the change

Add textarea-autosize plugin.

https://codereview.appspot.com/9024045/

To post a comment you must log in.
Revision history for this message
Brad Crittenden (bac) wrote :

Reviewers: mp+161685_code.launchpad.net,

Message:
Please take a look.

Description:
Add textarea-autosize plugin.

https://code.launchpad.net/~bac/juju-gui/autosize-plugin/+merge/161685

(do not edit description out of merge proposal)

Please review this at https://codereview.appspot.com/9024045/

Affected files:
   M Makefile
   A [revision details]
   M app/modules-debug.js
   A app/plugins/textarea-autosize.js
   M test/index.html
   A test/test_textarea_autosize.js

Revision history for this message
Madison Scott-Clary (makyo) wrote :

Code LGTM, didn't QA yet, but can if needed

https://codereview.appspot.com/9024045/diff/1/app/plugins/textarea-autosize.js
File app/plugins/textarea-autosize.js (right):

https://codereview.appspot.com/9024045/diff/1/app/plugins/textarea-autosize.js#newcode46
app/plugins/textarea-autosize.js:46: //textarea.on('input',
this._autoSizeHandler, this);
Remove or add comment as to why this is commented out.

https://codereview.appspot.com/9024045/diff/1/app/plugins/textarea-autosize.js#newcode141
app/plugins/textarea-autosize.js:141: // this.mirrorElement.value =
textarea.value + options.append;
Remove or explain.

https://codereview.appspot.com/9024045/diff/1/app/plugins/textarea-autosize.js#newcode173
app/plugins/textarea-autosize.js:173: // XXX: The original had a very
short timeout to avoid IE wetting
This seems like a safe enough flag to have around, but will defer to
others.

https://codereview.appspot.com/9024045/

Unmerged revisions

633. By Brad Crittenden

lint

632. By Brad Crittenden

Remove describe.only

631. By Brad Crittenden

More tests

630. By Brad Crittenden

wire up autosize tests

629. By Brad Crittenden

Added NS to plugin

628. By Brad Crittenden

Add app/plugins

627. By Brad Crittenden

Added textarea autosize plugin

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
=== modified file 'Makefile'
--- Makefile 2013-04-30 14:56:08 +0000
+++ Makefile 2013-04-30 19:27:26 +0000
@@ -320,6 +320,7 @@
320 build-debug/juju-ui/subapps \320 build-debug/juju-ui/subapps \
321 build-debug/juju-ui/views \321 build-debug/juju-ui/views \
322 build-debug/juju-ui/widgets \322 build-debug/juju-ui/widgets \
323 build-debug/juju-ui/plugins \
323 build-debug/juju-ui/assets/javascripts \324 build-debug/juju-ui/assets/javascripts \
324 build-debug/juju-ui/templates.js325 build-debug/juju-ui/templates.js
325326
@@ -368,6 +369,7 @@
368 ln -sf "$(PWD)/app/subapps" build-debug/juju-ui/369 ln -sf "$(PWD)/app/subapps" build-debug/juju-ui/
369 ln -sf "$(PWD)/app/views" build-debug/juju-ui/370 ln -sf "$(PWD)/app/views" build-debug/juju-ui/
370 ln -sf "$(PWD)/app/widgets" build-debug/juju-ui/371 ln -sf "$(PWD)/app/widgets" build-debug/juju-ui/
372 ln -sf "$(PWD)/app/plugins" build-debug/juju-ui/
371 ln -sf "$(PWD)/app/assets/javascripts/yui/yui/yui-debug.js" \373 ln -sf "$(PWD)/app/assets/javascripts/yui/yui/yui-debug.js" \
372 build-debug/juju-ui/assets/all-yui.js374 build-debug/juju-ui/assets/all-yui.js
373 ln -sf "$(PWD)/build-shared/juju-ui/templates.js" build-debug/juju-ui/375 ln -sf "$(PWD)/build-shared/juju-ui/templates.js" build-debug/juju-ui/
374376
=== modified file 'app/modules-debug.js'
--- app/modules-debug.js 2013-04-30 15:56:54 +0000
+++ app/modules-debug.js 2013-04-30 19:27:26 +0000
@@ -114,6 +114,11 @@
114 fullpath: '/juju-ui/assets/javascripts/sub-app.js'114 fullpath: '/juju-ui/assets/javascripts/sub-app.js'
115 },115 },
116116
117 // Plugins
118 'textarea-autosize': {
119 fullpath: '/juju-ui/plugins/textarea-autosize.js'
120 },
121
117 // Views122 // Views
118 'juju-landscape': {123 'juju-landscape': {
119 fullpath: '/juju-ui/views/landscape.js'124 fullpath: '/juju-ui/views/landscape.js'
120125
=== added directory 'app/plugins'
=== added file 'app/plugins/textarea-autosize.js'
--- app/plugins/textarea-autosize.js 1970-01-01 00:00:00 +0000
+++ app/plugins/textarea-autosize.js 2013-04-30 19:27:26 +0000
@@ -0,0 +1,191 @@
1'use strict';
2
3/**
4 A plugin for textareas that causes them to automatically resize when users
5 enter additional text. The textarea will expand vertically without adding
6 scrollbars. An enhancement would be to specify a maximum height after which
7 scrollbars are added.
8
9 Usage: Y.all(textareas).plug(Y.Autosize)
10 */
11
12YUI.add('textarea-autosize', function(Y) {
13
14 var ns = Y.namespace('juju.plugins');
15
16 ns.TextareaAutosize = Y.Base.create('textarea-autosize', Y.Plugin.Base, [], {
17
18 active: false,
19 boxOffset: 0,
20 minHeight: undefined,
21 mirrorElement: Y.Node.create(
22 '<textarea data-autosize="true" tabindex="-1" ' +
23 'style="position:absolute; top:-999px; left:0; ' +
24 'right:auto; bottom:auto; border:0; -moz-box-sizing:content-box; ' +
25 '-webkit-box-sizing:content-box; box-sizing:content-box; ' +
26 'word-wrap:break-word; height:0 !important; ' +
27 'min-height:0 !important; overflow:hidden;"/>'),
28
29 stylesToMirror: [
30 'fontFamily',
31 'fontSize',
32 'fontWeight',
33 'fontStyle',
34 'letterSpacing',
35 'textTransform',
36 'wordSpacing',
37 'textIndent',
38 'lineHeight'
39 ],
40
41 /**
42 @method initializer
43 */
44 initializer: function() {
45 var textarea = this.get('host');
46 //textarea.on('input', this._autoSizeHandler, this);
47 textarea.on('keydown', this._autoSizeHandler, this);
48 textarea.on('valuechange', this._autoSizeHandler, this);
49 this.minHeight = this._getMinHeight();
50 this._initMirror();
51 },
52
53 /**
54 Get the minimum height for the textarea.
55 @method _getMinHeight
56 @private
57 @return {Int} the min height.
58 */
59 _getMinHeight: function() {
60 var borderBox = 'border-box',
61 textarea = this.get('host'),
62 // XXX bac: is clientHeight what we want here?
63 height = textarea.get('clientHeight');
64
65 if (textarea.getStyle('box-sizing') === borderBox ||
66 textarea.getStyle('-moz-box-sizing') === borderBox ||
67 textarea.getStyle('-webkit-box-sizing') === borderBox) {
68 // XXX: scrollHeight is the same as outerHeight?
69 this.boxOffset = textarea.get('scrollHeight') - height;
70 }
71
72 return Math.max(
73 this._toInt(textarea.getStyle('minHeight')) - this.boxOffset,
74 height);
75 },
76
77 /**
78 Handle input events for the textarea and perform the resizing if
79 required.
80
81 @method _autoSizeHandler
82 @private
83 */
84 _autoSizeHandler: function(evt) {
85 this._adjust();
86 },
87
88 /**
89 Initialize the invisible mirrorElement.
90
91 @method _initMirror
92 @private
93 */
94 _initMirror: function() {
95 var textarea = this.get('host');
96 if (!this.mirrorElement.ancestor('body')) {
97 Y.one('body').append(this.mirrorElement);
98 this.mirrorElement.set('value', '\n\n\n');
99 this.mirrorElement.set('scrollTop', 9e4);
100 }
101
102 this.mirrorElement.set('className', textarea.get('className'));
103 Y.Array.each(this.stylesToMirror, function(v) {
104 this.mirrorElement.setStyle(v, textarea.getStyle(v));
105 }, this);
106 },
107
108 /**
109 Helper to convert strings to a base 10 int.
110
111 @method _toInt
112 @private
113 @param {String} v String to be parsed.
114 @return {Int} integer value or 'NaN'.
115 */
116 _toInt: function(s) {
117 return parseInt(s, 10);
118 },
119
120 /**
121 Adjust the textarea based on user input. This method is called on every
122 keystroke so it needs to be speedy.
123
124 XXX bac: the original JQuery version mentioned trying to use bare
125 Javascript. The conversion uses lots of YUI because it was the most
126 straightforward. Does this need to be reverted to bare JS?
127
128 @method _adjust
129 @private
130 */
131 _adjust: function() {
132 var height,
133 overflow,
134 original;
135
136 // the active flag keeps IE from tripping all over itself. Otherwise
137 // actions in the adjust function will cause IE to call adjust again.
138 if (!this.active) {
139 var textarea = this.get('host');
140 this.active = true;
141 // this.mirrorElement.value = textarea.value + options.append;
142 this.mirrorElement.set('value', textarea.get('value'));
143 this.mirrorElement.setStyle('overflowY',
144 textarea.getStyle('overflowY'));
145 original = this._toInt(textarea.getStyle('height'));
146
147 // Update the width in case the original textarea width has changed
148 // A floor of 0 is needed because IE8 returns a negative
149 // value for hidden textareas, raising an error.
150 this.mirrorElement.setStyle('width',
151 Math.max(textarea.getStyle('width'), 0));
152
153 // Get the height of the mirror.
154 height = this._toInt(this.mirrorElement.get('scrollHeight'));
155 var maxHeight = this._toInt(textarea.getStyle('maxHeight'));
156 // Opera returns '-1px' when max-height is set to 'none'.
157 maxHeight = maxHeight && maxHeight > 0 ? maxHeight : 9e4;
158 if (height > maxHeight) {
159 height = maxHeight;
160 overflow = 'scroll';
161 } else if (height < this.minHeight) {
162 height = this.minHeight;
163 }
164 height += this.boxOffset;
165 textarea.setStyle('overflowY', overflow || 'hidden');
166
167 if (original !== height) {
168 // XXX: all of this code assumes sizes are in px in the
169 // CSS. Will break if specified in other units.
170 textarea.setStyle('height', height + 'px');
171 }
172 }
173 // XXX: The original had a very short timeout to avoid IE wetting
174 // itself. Unsure if it is still needed.
175 this.active = false;
176 }
177 },{
178
179 NS: 'TextareaAutosize'
180 }
181 );
182},
183
184'0.1.0', {
185 requires: [
186 'node',
187 'event',
188 'base-build',
189 'plugin'
190 ]
191});
0192
=== modified file 'test/index.html'
--- test/index.html 2013-04-25 20:03:36 +0000
+++ test/index.html 2013-04-30 19:27:26 +0000
@@ -75,6 +75,7 @@
75 <script src="test_sub_app.js"></script>75 <script src="test_sub_app.js"></script>
76 <script src="test_tabview.js"></script>76 <script src="test_tabview.js"></script>
77 <script src="test_templates.js"></script>77 <script src="test_templates.js"></script>
78 <script src="test_textarea_autosize.js"></script>
78 <script src="test_topology.js"></script>79 <script src="test_topology.js"></script>
79 <script src="test_topology_relation.js"></script>80 <script src="test_topology_relation.js"></script>
80 <script src="test_unit_view.js"></script>81 <script src="test_unit_view.js"></script>
8182
=== added file 'test/test_textarea_autosize.js'
--- test/test_textarea_autosize.js 1970-01-01 00:00:00 +0000
+++ test/test_textarea_autosize.js 2013-04-30 19:27:26 +0000
@@ -0,0 +1,90 @@
1'use strict';
2
3describe('textarea autosize plugin', function() {
4 var Y, container, textarea;
5
6 before(function(done) {
7 Y = YUI(GlobalConfig).use([
8 'textarea-autosize',
9 'node-event-simulate'],
10 function(Y) {
11 done();
12 });
13 });
14
15 beforeEach(function() {
16 container = Y.Node.create('<div id="container"></div>');
17 textarea = Y.Node.create('<textarea class="autosize"></textarea>');
18 container.append(textarea);
19 Y.one(document.body).prepend(container);
20 });
21
22 afterEach(function() {
23 textarea.remove().destroy(true);
24 container.remove().destroy(true);
25 });
26
27 var setAndTrigger = function(textarea, v) {
28 textarea.set('value', v);
29 textarea.focus();
30 textarea.simulate('keydown', {keyCode: 83});
31 };
32
33 it('plugs into a textarea', function() {
34 var node = Y.one('textarea.autosize');
35 node.plug(Y.juju.plugins.TextareaAutosize);
36 assert.isDefined(node.TextareaAutosize);
37 });
38
39 it('plugs into lots of textareas', function() {
40 var textarea2 = Y.Node.create('<textarea class="autosize"></textarea>');
41 var textarea3 = Y.Node.create('<textarea></textarea>');
42 container.append(textarea2);
43 container.append(textarea3);
44 var nodes = Y.all('textarea');
45 nodes.plug(Y.juju.plugins.TextareaAutosize);
46 assert.isDefined(textarea.TextareaAutosize);
47 assert.isDefined(textarea2.TextareaAutosize);
48 assert.isDefined(textarea3.TextareaAutosize);
49 });
50
51 it('plugs into lots of textareas, but selectively', function() {
52 var textarea2 = Y.Node.create('<textarea class="autosize"></textarea>');
53 var textarea3 = Y.Node.create('<textarea></textarea>');
54 container.append(textarea2);
55 container.append(textarea3);
56 // Textareas with autosize class.
57 var nodes = Y.all('textarea.autosize');
58 nodes.plug(Y.juju.plugins.TextareaAutosize);
59 assert.isDefined(textarea.TextareaAutosize);
60 assert.isDefined(textarea2.TextareaAutosize);
61 assert.isUndefined(textarea3.TextareaAutosize);
62 });
63
64 it('calculates the minHeight', function() {
65 var node = Y.one('textarea.autosize');
66 node.plug(Y.juju.plugins.TextareaAutosize);
67 var original = textarea.TextareaAutosize._getMinHeight();
68 setAndTrigger(textarea, 'how\nnow\nbrown\ncow\nand\nstuff');
69 var bigger = textarea.TextareaAutosize._getMinHeight();
70 // The size should have grown.
71 assert.isTrue(bigger > original);
72 setAndTrigger(textarea, 'one line');
73 var smaller = textarea.TextareaAutosize._getMinHeight();
74 assert.isTrue(smaller < bigger);
75 });
76
77 it('sets the height on the textarea', function() {
78 var node = Y.one('textarea.autosize');
79 node.plug(Y.juju.plugins.TextareaAutosize);
80 var original = parseInt(textarea.getStyle('height'), 10);
81 setAndTrigger(textarea, 'how\nnow\nbrown\ncow\nand\nstuff');
82 var bigger = parseInt(textarea.getStyle('height'), 10);
83 // The height should have grown...
84 assert.isTrue(bigger > original);
85 setAndTrigger(textarea, 'one line');
86 var smaller = parseInt(textarea.getStyle('height'), 10);
87 // ..and then shrunk.
88 assert.isTrue(smaller < bigger);
89 });
90});

Subscribers

People subscribed via source and target branches