1 /*
  2 Copyright (c) 2003-2009, CKSource - Frederico Knabben. All rights reserved.
  3 For licensing, see LICENSE.html or http://ckeditor.com/license
  4 */
  5
  6 (function()
  7 {
  8 	CKEDITOR.plugins.add( 'stylescombo',
  9 	{
 10 		requires : [ 'richcombo', 'styles' ],
 11
 12 		init : function( editor )
 13 		{
 14 			var config = editor.config,
 15 				lang = editor.lang.stylesCombo,
 16 				pluginPath = this.path,
 17 				styles,
 18 				saveRanges;
 19
 20 			editor.ui.addRichCombo( 'Styles',
 21 				{
 22 					label : lang.label,
 23 					title : lang.panelTitle,
 24 					className : 'cke_styles',
 25 					multiSelect : true,
 26
 27 					panel :
 28 					{
 29 						css : [ config.contentsCss, editor.skinPath + 'editor.css' ]
 30 					},
 31
 32 					init : function()
 33 					{
 34 						var combo = this,
 35 							stylesSet = config.stylesCombo_stylesSet.split( ':', 2 ),
 36 							stylesSetPath = stylesSet[ 1 ] || CKEDITOR.getUrl( pluginPath + 'styles/' + stylesSet[ 0 ] + '.js' ) ;
 37
 38 						stylesSet = stylesSet[ 0 ];
 39
 40 						CKEDITOR.loadStylesSet( stylesSet, stylesSetPath, function( stylesDefinitions )
 41 							{
 42 								var style,
 43 									styleName,
 44 									stylesList = [];
 45
 46 								styles = {};
 47
 48 								// Put all styles into an Array.
 49 								for ( var i = 0 ; i < stylesDefinitions.length ; i++ )
 50 								{
 51 									var styleDefinition = stylesDefinitions[ i ];
 52
 53 									styleName = styleDefinition.name;
 54
 55 									style = styles[ styleName ] = new CKEDITOR.style( styleDefinition );
 56 									style._name = styleName;
 57
 58 									stylesList.push( style );
 59 								}
 60
 61 								// Sorts the Array, so the styles get grouped
 62 								// by type.
 63 								stylesList.sort( sortStyles );
 64
 65 								// Loop over the Array, adding all items to the
 66 								// combo.
 67 								var lastType;
 68 								for ( var i = 0 ; i < stylesList.length ; i++ )
 69 								{
 70 									style = stylesList[ i ];
 71 									styleName = style._name;
 72
 73 									var type = style.type;
 74
 75 									if ( type != lastType )
 76 									{
 77 										combo.startGroup( lang[ 'panelTitle' + String( type ) ] );
 78 										lastType = type;
 79 									}
 80
 81 									combo.add(
 82 										styleName,
 83 										style.type == CKEDITOR.STYLE_OBJECT ? styleName : buildPreview( style._.definition ),
 84 										styleName );
 85 								}
 86
 87 								combo.commit();
 88
 89 								combo.onOpen();
 90 							});
 91 					},
 92
 93 					onClick : function( value )
 94 					{
 95 						editor.focus();
 96
 97 						var style = styles[ value ],
 98 							selection = editor.getSelection();
 99
100 						if ( saveRanges )
101 						{
102 							selection.selectRanges( saveRanges );
103 							saveRanges = false;
104 						}
105
106 						if ( style.type == CKEDITOR.STYLE_OBJECT )
107 						{
108 							var element = selection.getSelectedElement();
109 							if ( element )
110 								style.applyToObject( element );
111
112 							return;
113 						}
114
115 						var elementPath = new CKEDITOR.dom.elementPath( selection.getStartElement() );
116
117 						if ( style.type == CKEDITOR.STYLE_INLINE && style.checkActive( elementPath ) )
118 							style.remove( editor.document );
119 						else
120 							style.apply( editor.document );
121 					},
122
123 					onRender : function()
124 					{
125 						editor.on( 'selectionChange', function( ev )
126 							{
127 								var currentValue = this.getValue();
128
129 								var elementPath = ev.data.path;
130 									elements = elementPath.elements;
131
132 								// For each element into the elements path.
133 								for ( var i = 0, element ; i < elements.length ; i++ )
134 								{
135 									element = elements[i];
136
137 									// Check if the element is removable by any of
138 									// the styles.
139 									for ( var value in styles )
140 									{
141 										if ( styles[ value ].checkElementRemovable( element, true ) )
142 										{
143 											if ( value != currentValue )
144 												this.setValue( value );
145 											return;
146 										}
147 									}
148 								}
149
150 								// If no styles match, just empty it.
151 								this.setValue( '' );
152 							},
153 							this);
154 					},
155
156 					onOpen : function()
157 					{
158 						editor.focus();
159
160 						var selection = editor.getSelection();
161
162 						if ( CKEDITOR.env.ie && selection )
163 							saveRanges = selection.getRanges();
164
165 						var elementPath,
166 							element = selection.getSelectedElement(),
167 							elementName = element && element.getName(),
168 							isInline = elementName &&
169 								!CKEDITOR.dtd.$block[ elementName ] &&
170 								!CKEDITOR.dtd.$listItem[ elementName ] &&
171 								!CKEDITOR.dtd.$tableContent[ elementName ];
172
173 						var counter = [ 0, 0, 0, 0 ];
174
175 						if ( !element || isInline )
176 							elementPath = new CKEDITOR.dom.elementPath( selection.getStartElement() );
177
178 						this.showAll();
179 						this.unmarkAll();
180
181 						for ( var name in styles )
182 						{
183 							var style = styles[ name ]
184 								type = style.type;
185
186 							if ( type == CKEDITOR.STYLE_OBJECT )
187 							{
188 								if ( element && style.element == elementName )
189 								{
190 									if ( style.checkElementRemovable( element, true ) )
191 										this.mark( name );
192
193 									counter[ type ]++;
194 								}
195 								else
196 									this.hideItem( name );
197 							}
198 							else
199 							{
200 								if ( elementPath )
201 								{
202 									if ( style.checkActive( elementPath ) )
203 										this.mark( name );
204
205 									counter[ type ]++;
206
207 								}
208 								else
209 									this.hideItem( name );
210 							}
211 						}
212
213 						if ( !counter[ CKEDITOR.STYLE_BLOCK ] )
214 							this.hideGroup( lang[ 'panelTitle' + String( CKEDITOR.STYLE_BLOCK ) ] );
215
216 						if ( !counter[ CKEDITOR.STYLE_INLINE ] )
217 							this.hideGroup( lang[ 'panelTitle' + String( CKEDITOR.STYLE_INLINE ) ] );
218
219 						if ( !counter[ CKEDITOR.STYLE_OBJECT ] )
220 							this.hideGroup( lang[ 'panelTitle' + String( CKEDITOR.STYLE_OBJECT ) ] );
221 					},
222
223 					onClose : function()
224 					{
225 						saveRanges = null;
226 					}
227 				});
228 		}
229 	});
230
231 	var stylesSets = {};
232
233 	CKEDITOR.addStylesSet = function( name, styles )
234 	{
235 		stylesSets[ name ] = styles;
236 	};
237
238 	CKEDITOR.loadStylesSet = function( name, url, callback )
239 	{
240 		var stylesSet = stylesSets[ name ];
241
242 		if ( stylesSet )
243 			return callback( stylesSets );
244
245 		CKEDITOR.scriptLoader.load( url, function()
246 			{
247 				callback( stylesSets[ name ] );
248 			});
249 	};
250
251 	function buildPreview( styleDefinition )
252 	{
253 		var html = [];
254
255 		var elementName = styleDefinition.element;
256
257 		// Avoid <bdo> in the preview.
258 		if ( elementName == 'bdo' )
259 			elementName = 'span';
260
261 		html = [ '<', elementName ];
262
263 		// Assign all defined attributes.
264 		var attribs	= styleDefinition.attributes;
265 		if ( attribs )
266 		{
267 			for ( var att in attribs )
268 			{
269 				html.push( ' ', att, '="', attribs[ att ], '"' );
270 			}
271 		}
272
273 		// Assign the style attribute.
274 		var cssStyle = CKEDITOR.style.getStyleText( styleDefinition );
275 		if ( cssStyle )
276 			html.push( ' style="', cssStyle, '"' );
277
278 		html.push( '>', styleDefinition.name, '</', elementName, '>' );
279
280 		return html.join( '' );
281 	}
282
283 	function sortStyles( styleA, styleB )
284 	{
285 		var typeA = styleA.type,
286 			typeB = styleB.type;
287
288 		return typeA == typeB ? 0 :
289 			typeA == CKEDITOR.STYLE_OBJECT ? -1 :
290 			typeB == CKEDITOR.STYLE_OBJECT ? 1 :
291 			typeB == CKEDITOR.STYLE_BLOCK ? 1 :
292 			-1;
293 	}
294 })();
295
296 CKEDITOR.config.stylesCombo_stylesSet = 'default';
297