Fix FOUC for floated collapsible elements outside the content area
[lhc/web/wiklou.git] / resources / src / jquery / jquery.expandableField.js
1 /**
2 * This plugin provides functionality to expand a text box on focus to double it's current width
3 *
4 * Usage:
5 *
6 * Set options:
7 * $('#textbox').expandableField( { option1: value1, option2: value2 } );
8 * $('#textbox').expandableField( option, value );
9 * Get option:
10 * value = $('#textbox').expandableField( option );
11 * Initialize:
12 * $('#textbox').expandableField();
13 *
14 * Options:
15 */
16 ( function ( $ ) {
17
18 $.expandableField = {
19 /**
20 * Expand the field, make the callback
21 *
22 * @param {jQuery.Event} e Event
23 * @param {Object} context
24 */
25 expandField: function ( e, context ) {
26 context.config.beforeExpand.call( context.data.$field, context );
27 context.data.$field
28 .animate( { width: context.data.expandedWidth }, 'fast', function () {
29 context.config.afterExpand.call( this, context );
30 } );
31 },
32 /**
33 * Condense the field, make the callback
34 *
35 * @param {jQuery.Event} e Event
36 * @param {Object} context
37 */
38 condenseField: function ( e, context ) {
39 context.config.beforeCondense.call( context.data.$field, context );
40 context.data.$field
41 .animate( { width: context.data.condensedWidth }, 'fast', function () {
42 context.config.afterCondense.call( this, context );
43 } );
44 },
45 /**
46 * Sets the value of a property, and updates the widget accordingly
47 *
48 * @param {Object} context
49 * @param {string} property Name of property
50 * @param {Mixed} value Value to set property with
51 */
52 configure: function ( context, property, value ) {
53 // TODO: Validate creation using fallback values
54 context.config[ property ] = value;
55 }
56
57 };
58
59 $.fn.expandableField = function () {
60
61 // Multi-context fields
62 var returnValue,
63 args = arguments;
64
65 $( this ).each( function () {
66 var key, context, timeout;
67
68 /* Construction / Loading */
69
70 context = $( this ).data( 'expandableField-context' );
71
72 // TODO: Do we need to check both null and undefined?
73 if ( context === undefined || context === null ) {
74 context = {
75 config: {
76 // callback function for before collapse
77 beforeCondense: function () {},
78
79 // callback function for before expand
80 beforeExpand: function () {},
81
82 // callback function for after collapse
83 afterCondense: function () {},
84
85 // callback function for after expand
86 afterExpand: function () {},
87
88 // Whether the field should expand to the left or the right -- defaults to left
89 expandToLeft: true
90 }
91 };
92 }
93
94 /* API */
95 // Handle various calling styles
96 if ( args.length > 0 ) {
97 if ( typeof args[ 0 ] === 'object' ) {
98 // Apply set of properties
99 for ( key in args[ 0 ] ) {
100 $.expandableField.configure( context, key, args[ 0 ][ key ] );
101 }
102 } else if ( typeof args[ 0 ] === 'string' ) {
103 if ( args.length > 1 ) {
104 // Set property values
105 $.expandableField.configure( context, args[ 0 ], args[ 1 ] );
106
107 // TODO: Do we need to check both null and undefined?
108 } else if ( returnValue === null || returnValue === undefined ) {
109 // Get property values, but don't give access to internal data - returns only the first
110 returnValue = ( args[ 0 ] in context.config ? undefined : context.config[ args[ 0 ] ] );
111 }
112 }
113 }
114
115 /* Initialization */
116
117 if ( context.data === undefined ) {
118 context.data = {
119 // The width of the field in it's condensed state
120 condensedWidth: $( this ).width(),
121
122 // The width of the field in it's expanded state
123 expandedWidth: $( this ).width() * 2,
124
125 // Reference to the field
126 $field: $( this )
127 };
128
129 $( this )
130 .addClass( 'expandableField' )
131 .focus( function ( e ) {
132 clearTimeout( timeout );
133 $.expandableField.expandField( e, context );
134 } )
135 .blur( function ( e ) {
136 timeout = setTimeout( function () {
137 $.expandableField.condenseField( e, context );
138 }, 250 );
139 } );
140 }
141 // Store the context for next time
142 $( this ).data( 'expandableField-context', context );
143 } );
144 return returnValue !== undefined ? returnValue : $( this );
145 };
146
147 }( jQuery ) );