1 /*
  2 Copyright (c) 2003-2012, CKSource - Frederico Knabben. All rights reserved.
  3 For licensing, see LICENSE.html or http://ckeditor.com/license
  4 */
  5 
  6 /**
  7  * @file Forms Plugin
  8  */
  9 
 10 CKEDITOR.plugins.add( 'forms',
 11 {
 12 	requires : [ 'dialog' ],
 13 	init : function( editor )
 14 	{
 15 		var lang = editor.lang;
 16 
 17 		editor.addCss(
 18 			'form' +
 19 			'{' +
 20 				'border: 1px dotted #FF0000;' +
 21 				'padding: 2px;' +
 22 			'}\n' );
 23 
 24 		editor.addCss(
 25 			'img.cke_hidden' +
 26 			'{' +
 27 				'background-image: url(' + CKEDITOR.getUrl( this.path + 'images/hiddenfield.gif' ) + ');' +
 28 				'background-position: center center;' +
 29 				'background-repeat: no-repeat;' +
 30 				'border: 1px solid #a9a9a9;' +
 31 				'width: 16px !important;' +
 32 				'height: 16px !important;' +
 33 			'}' );
 34 
 35 		// All buttons use the same code to register. So, to avoid
 36 		// duplications, let's use this tool function.
 37 		var addButtonCommand = function( buttonName, commandName, dialogFile )
 38 		{
 39 			editor.addCommand( commandName, new CKEDITOR.dialogCommand( commandName ) );
 40 
 41 			editor.ui.addButton( buttonName,
 42 				{
 43 					label : lang.common[ buttonName.charAt(0).toLowerCase() + buttonName.slice(1) ],
 44 					command : commandName
 45 				});
 46 			CKEDITOR.dialog.add( commandName, dialogFile );
 47 		};
 48 
 49 		var dialogPath = this.path + 'dialogs/';
 50 		addButtonCommand( 'Form',			'form',			dialogPath + 'form.js' );
 51 		addButtonCommand( 'Checkbox',		'checkbox',		dialogPath + 'checkbox.js' );
 52 		addButtonCommand( 'Radio',			'radio',		dialogPath + 'radio.js' );
 53 		addButtonCommand( 'TextField',		'textfield',	dialogPath + 'textfield.js' );
 54 		addButtonCommand( 'Textarea',		'textarea',		dialogPath + 'textarea.js' );
 55 		addButtonCommand( 'Select',			'select',		dialogPath + 'select.js' );
 56 		addButtonCommand( 'Button',			'button',		dialogPath + 'button.js' );
 57 		addButtonCommand( 'ImageButton',	'imagebutton',	CKEDITOR.plugins.getPath('image') + 'dialogs/image.js' );
 58 		addButtonCommand( 'HiddenField',	'hiddenfield',	dialogPath + 'hiddenfield.js' );
 59 
 60 		// If the "menu" plugin is loaded, register the menu items.
 61 		if ( editor.addMenuItems )
 62 		{
 63 			editor.addMenuItems(
 64 				{
 65 					form :
 66 					{
 67 						label : lang.form.menu,
 68 						command : 'form',
 69 						group : 'form'
 70 					},
 71 
 72 					checkbox :
 73 					{
 74 						label : lang.checkboxAndRadio.checkboxTitle,
 75 						command : 'checkbox',
 76 						group : 'checkbox'
 77 					},
 78 
 79 					radio :
 80 					{
 81 						label : lang.checkboxAndRadio.radioTitle,
 82 						command : 'radio',
 83 						group : 'radio'
 84 					},
 85 
 86 					textfield :
 87 					{
 88 						label : lang.textfield.title,
 89 						command : 'textfield',
 90 						group : 'textfield'
 91 					},
 92 
 93 					hiddenfield :
 94 					{
 95 						label : lang.hidden.title,
 96 						command : 'hiddenfield',
 97 						group : 'hiddenfield'
 98 					},
 99 
100 					imagebutton :
101 					{
102 						label : lang.image.titleButton,
103 						command : 'imagebutton',
104 						group : 'imagebutton'
105 					},
106 
107 					button :
108 					{
109 						label : lang.button.title,
110 						command : 'button',
111 						group : 'button'
112 					},
113 
114 					select :
115 					{
116 						label : lang.select.title,
117 						command : 'select',
118 						group : 'select'
119 					},
120 
121 					textarea :
122 					{
123 						label : lang.textarea.title,
124 						command : 'textarea',
125 						group : 'textarea'
126 					}
127 				});
128 		}
129 
130 		// If the "contextmenu" plugin is loaded, register the listeners.
131 		if ( editor.contextMenu )
132 		{
133 			editor.contextMenu.addListener( function( element )
134 				{
135 					if ( element && element.hasAscendant( 'form', true ) && !element.isReadOnly() )
136 						return { form : CKEDITOR.TRISTATE_OFF };
137 				});
138 
139 			editor.contextMenu.addListener( function( element )
140 				{
141 					if ( element && !element.isReadOnly() )
142 					{
143 						var name = element.getName();
144 
145 						if ( name == 'select' )
146 							return { select : CKEDITOR.TRISTATE_OFF };
147 
148 						if ( name == 'textarea' )
149 							return { textarea : CKEDITOR.TRISTATE_OFF };
150 
151 						if ( name == 'input' )
152 						{
153 							switch( element.getAttribute( 'type' ) )
154 							{
155 								case 'button' :
156 								case 'submit' :
157 								case 'reset' :
158 									return { button : CKEDITOR.TRISTATE_OFF };
159 
160 								case 'checkbox' :
161 									return { checkbox : CKEDITOR.TRISTATE_OFF };
162 
163 								case 'radio' :
164 									return { radio : CKEDITOR.TRISTATE_OFF };
165 
166 								case 'image' :
167 									return { imagebutton : CKEDITOR.TRISTATE_OFF };
168 
169 								default :
170 									return { textfield : CKEDITOR.TRISTATE_OFF };
171 							}
172 						}
173 
174 						if ( name == 'img' && element.data( 'cke-real-element-type' ) == 'hiddenfield' )
175 							return { hiddenfield : CKEDITOR.TRISTATE_OFF };
176 					}
177 				});
178 		}
179 
180 		editor.on( 'doubleclick', function( evt )
181 			{
182 				var element = evt.data.element;
183 
184 				if ( element.is( 'form' ) )
185 					evt.data.dialog = 'form';
186 				else if ( element.is( 'select' ) )
187 					evt.data.dialog = 'select';
188 				else if ( element.is( 'textarea' ) )
189 					evt.data.dialog = 'textarea';
190 				else if ( element.is( 'img' ) && element.data( 'cke-real-element-type' ) == 'hiddenfield' )
191 					evt.data.dialog = 'hiddenfield';
192 				else if ( element.is( 'input' ) )
193 				{
194 					switch ( element.getAttribute( 'type' ) )
195 					{
196 						case 'button' :
197 						case 'submit' :
198 						case 'reset' :
199 							evt.data.dialog = 'button';
200 							break;
201 						case 'checkbox' :
202 							evt.data.dialog = 'checkbox';
203 							break;
204 						case 'radio' :
205 							evt.data.dialog = 'radio';
206 							break;
207 						case 'image' :
208 							evt.data.dialog = 'imagebutton';
209 							break;
210 						default :
211 							evt.data.dialog = 'textfield';
212 							break;
213 					}
214 				}
215 			});
216 	},
217 
218 	afterInit : function( editor )
219 	{
220 		var dataProcessor = editor.dataProcessor,
221 			htmlFilter = dataProcessor && dataProcessor.htmlFilter,
222 			dataFilter = dataProcessor && dataProcessor.dataFilter;
223 
224 		// Cleanup certain IE form elements default values.
225 		if ( CKEDITOR.env.ie )
226 		{
227 			htmlFilter && htmlFilter.addRules(
228 			{
229 				elements :
230 				{
231 					input : function( input )
232 					{
233 						var attrs = input.attributes,
234 							type = attrs.type;
235 						// Old IEs don't provide type for Text inputs #5522
236 						if ( !type )
237 							attrs.type = 'text';
238 						if ( type == 'checkbox' || type == 'radio' )
239 							attrs.value == 'on' && delete attrs.value;
240 					}
241 				}
242 			} );
243 		}
244 
245 		if ( dataFilter )
246 		{
247 			dataFilter.addRules(
248 			{
249 				elements :
250 				{
251 					input : function( element )
252 					{
253 						if ( element.attributes.type == 'hidden' )
254 							return editor.createFakeParserElement( element, 'cke_hidden', 'hiddenfield' );
255 					}
256 				}
257 			} );
258 		}
259 	},
260 	requires : [ 'image', 'fakeobjects' ]
261 } );
262 
263 if ( CKEDITOR.env.ie )
264 {
265 	CKEDITOR.dom.element.prototype.hasAttribute = CKEDITOR.tools.override( CKEDITOR.dom.element.prototype.hasAttribute,
266 		function( original )
267 		{
268 			return function( name )
269 				{
270 					var $attr = this.$.attributes.getNamedItem( name );
271 
272 					if ( this.getName() == 'input' )
273 					{
274 						switch ( name )
275 						{
276 							case 'class' :
277 								return this.$.className.length > 0;
278 							case 'checked' :
279 								return !!this.$.checked;
280 							case 'value' :
281 								var type = this.getAttribute( 'type' );
282 								return type == 'checkbox' || type == 'radio' ? this.$.value != 'on' : this.$.value;
283 						}
284 					}
285 
286 					return original.apply( this, arguments );
287 				};
288 		});
289 }
290