1/*
2 * FCKeditor - The text editor for Internet - http://www.fckeditor.net
3 * Copyright (C) 2003-2007 Frederico Caldeira Knabben
4 *
5 * == BEGIN LICENSE ==
6 *
7 * Licensed under the terms of any of the following licenses at your
8 * choice:
9 *
10 *  - GNU General Public License Version 2 or later (the "GPL")
11 *    http://www.gnu.org/licenses/gpl.html
12 *
13 *  - GNU Lesser General Public License Version 2.1 or later (the "LGPL")
14 *    http://www.gnu.org/licenses/lgpl.html
15 *
16 *  - Mozilla Public License Version 1.1 or later (the "MPL")
17 *    http://www.mozilla.org/MPL/MPL-1.1.html
18 *
19 * == END LICENSE ==
20 *
21 * FCKSpecialCombo Class: represents a special combo.
22 */
23
24var FCKSpecialCombo = function( caption, fieldWidth, panelWidth, panelMaxHeight, parentWindow )
25{
26	// Default properties values.
27	this.FieldWidth		= fieldWidth || 100 ;
28	this.PanelWidth		= panelWidth || 150 ;
29	this.PanelMaxHeight	= panelMaxHeight || 150 ;
30	this.Label			= ' ' ;
31	this.Caption		= caption ;
32	this.Tooltip		= caption ;
33	this.Style			= FCK_TOOLBARITEM_ICONTEXT ;
34
35	this.Enabled = true ;
36
37	this.Items = new Object() ;
38
39	this._Panel = new FCKPanel( parentWindow || window ) ;
40	this._Panel.AppendStyleSheet( FCKConfig.SkinPath + 'fck_editor.css' ) ;
41	this._PanelBox = this._Panel.MainNode.appendChild( this._Panel.Document.createElement( 'DIV' ) ) ;
42	this._PanelBox.className = 'SC_Panel' ;
43	this._PanelBox.style.width = this.PanelWidth + 'px' ;
44
45	this._PanelBox.innerHTML = '<table cellpadding="0" cellspacing="0" width="100%" style="TABLE-LAYOUT: fixed"><tr><td nowrap></td></tr></table>' ;
46
47	this._ItemsHolderEl = this._PanelBox.getElementsByTagName('TD')[0] ;
48
49	if ( FCK.IECleanup )
50		FCK.IECleanup.AddItem( this, FCKSpecialCombo_Cleanup ) ;
51
52//	this._Panel.StyleSheet = FCKConfig.SkinPath + 'fck_contextmenu.css' ;
53//	this._Panel.Create() ;
54//	this._Panel.PanelDiv.className += ' SC_Panel' ;
55//	this._Panel.PanelDiv.innerHTML = '<table cellpadding="0" cellspacing="0" width="100%" style="TABLE-LAYOUT: fixed"><tr><td nowrap></td></tr></table>' ;
56//	this._ItemsHolderEl = this._Panel.PanelDiv.getElementsByTagName('TD')[0] ;
57}
58
59function FCKSpecialCombo_ItemOnMouseOver()
60{
61	this.className += ' SC_ItemOver' ;
62}
63
64function FCKSpecialCombo_ItemOnMouseOut()
65{
66	this.className = this.originalClass ;
67}
68
69function FCKSpecialCombo_ItemOnClick( ev, specialCombo, itemId )
70{
71	this.className = this.originalClass ;
72
73	specialCombo._Panel.Hide() ;
74
75	specialCombo.SetLabel( this.FCKItemLabel ) ;
76
77	if ( typeof( specialCombo.OnSelect ) == 'function' )
78		specialCombo.OnSelect( itemId, this ) ;
79}
80
81FCKSpecialCombo.prototype.ClearItems = function ()
82{
83	if ( this.Items )
84	{
85		for ( var key in this.Items )
86			this.Items[key] = null ;
87	}
88
89	var itemsholder = this._ItemsHolderEl ;
90	while ( itemsholder.firstChild )
91		itemsholder.removeChild( itemsholder.firstChild ) ;
92}
93
94FCKSpecialCombo.prototype.AddItem = function( id, html, label, bgColor )
95{
96	// <div class="SC_Item" onmouseover="this.className='SC_Item SC_ItemOver';" onmouseout="this.className='SC_Item';"><b>Bold 1</b></div>
97	var oDiv = this._ItemsHolderEl.appendChild( this._Panel.Document.createElement( 'DIV' ) ) ;
98	oDiv.className = oDiv.originalClass = 'SC_Item' ;
99	oDiv.innerHTML = html ;
100	oDiv.FCKItemLabel = label || id ;
101	oDiv.Selected = false ;
102
103	// In IE, the width must be set so the borders are shown correctly when the content overflows.
104	if ( FCKBrowserInfo.IsIE )
105		oDiv.style.width = '100%' ;
106
107	if ( bgColor )
108		oDiv.style.backgroundColor = bgColor ;
109
110	FCKTools.AddEventListenerEx( oDiv, 'mouseover', FCKSpecialCombo_ItemOnMouseOver ) ;
111	FCKTools.AddEventListenerEx( oDiv, 'mouseout', FCKSpecialCombo_ItemOnMouseOut ) ;
112	FCKTools.AddEventListenerEx( oDiv, 'click', FCKSpecialCombo_ItemOnClick, [ this, id ] ) ;
113
114	this.Items[ id.toString().toLowerCase() ] = oDiv ;
115
116	return oDiv ;
117}
118
119FCKSpecialCombo.prototype.SelectItem = function( item )
120{
121	if ( typeof item == 'string' )
122		item = this.Items[ item.toString().toLowerCase() ] ;
123
124	if ( item )
125	{
126		item.className = item.originalClass = 'SC_ItemSelected' ;
127		item.Selected = true ;
128	}
129}
130
131FCKSpecialCombo.prototype.SelectItemByLabel = function( itemLabel, setLabel )
132{
133	for ( var id in this.Items )
134	{
135		var oDiv = this.Items[id] ;
136
137		if ( oDiv.FCKItemLabel == itemLabel )
138		{
139			oDiv.className = oDiv.originalClass = 'SC_ItemSelected' ;
140			oDiv.Selected = true ;
141
142			if ( setLabel )
143				this.SetLabel( itemLabel ) ;
144		}
145	}
146}
147
148FCKSpecialCombo.prototype.DeselectAll = function( clearLabel )
149{
150	for ( var i in this.Items )
151	{
152		if ( !this.Items[i] ) continue;
153		this.Items[i].className = this.Items[i].originalClass = 'SC_Item' ;
154		this.Items[i].Selected = false ;
155	}
156
157	if ( clearLabel )
158		this.SetLabel( '' ) ;
159}
160
161FCKSpecialCombo.prototype.SetLabelById = function( id )
162{
163	id = id ? id.toString().toLowerCase() : '' ;
164
165	var oDiv = this.Items[ id ] ;
166	this.SetLabel( oDiv ? oDiv.FCKItemLabel : '' ) ;
167}
168
169FCKSpecialCombo.prototype.SetLabel = function( text )
170{
171	text = ( !text || text.length == 0 ) ? '&nbsp;' : text ;
172
173	if ( text == this.Label )
174		return ;
175
176	this.Label = text ;
177
178	var labelEl = this._LabelEl ;
179	if ( labelEl )
180	{
181		labelEl.innerHTML = text ;
182
183		// It may happen that the label is some HTML, including tags. This
184		// would be a problem because when the user click on those tags, the
185		// combo will get the selection from the editing area. So we must
186		// disable any kind of selection here.
187		FCKTools.DisableSelection( labelEl ) ;
188	}
189}
190
191FCKSpecialCombo.prototype.SetEnabled = function( isEnabled )
192{
193	this.Enabled = isEnabled ;
194
195	this._OuterTable.className = isEnabled ? '' : 'SC_FieldDisabled' ;
196}
197
198FCKSpecialCombo.prototype.Create = function( targetElement )
199{
200	var oDoc = FCKTools.GetElementDocument( targetElement ) ;
201	var eOuterTable = this._OuterTable = targetElement.appendChild( oDoc.createElement( 'TABLE' ) ) ;
202	eOuterTable.cellPadding = 0 ;
203	eOuterTable.cellSpacing = 0 ;
204
205	eOuterTable.insertRow(-1) ;
206
207	var sClass ;
208	var bShowLabel ;
209
210	switch ( this.Style )
211	{
212		case FCK_TOOLBARITEM_ONLYICON :
213			sClass = 'TB_ButtonType_Icon' ;
214			bShowLabel = false;
215			break ;
216		case FCK_TOOLBARITEM_ONLYTEXT :
217			sClass = 'TB_ButtonType_Text' ;
218			bShowLabel = false;
219			break ;
220		case FCK_TOOLBARITEM_ICONTEXT :
221			bShowLabel = true;
222			break ;
223	}
224
225	if ( this.Caption && this.Caption.length > 0 && bShowLabel )
226	{
227		var oCaptionCell = eOuterTable.rows[0].insertCell(-1) ;
228		oCaptionCell.innerHTML = this.Caption ;
229		oCaptionCell.className = 'SC_FieldCaption' ;
230	}
231
232	// Create the main DIV element.
233	var oField = FCKTools.AppendElement( eOuterTable.rows[0].insertCell(-1), 'div' ) ;
234	if ( bShowLabel )
235	{
236		oField.className = 'SC_Field' ;
237		oField.style.width = this.FieldWidth + 'px' ;
238		oField.innerHTML = '<table width="100%" cellpadding="0" cellspacing="0" style="TABLE-LAYOUT: fixed;"><tbody><tr><td class="SC_FieldLabel"><label>&nbsp;</label></td><td class="SC_FieldButton">&nbsp;</td></tr></tbody></table>' ;
239
240		this._LabelEl = oField.getElementsByTagName('label')[0] ;		// Memory Leak
241		this._LabelEl.innerHTML = this.Label ;
242	}
243	else
244	{
245		oField.className = 'TB_Button_Off' ;
246		//oField.innerHTML = '<span className="SC_FieldCaption">' + this.Caption + '<table cellpadding="0" cellspacing="0" style="TABLE-LAYOUT: fixed;"><tbody><tr><td class="SC_FieldButton" style="border-left: none;">&nbsp;</td></tr></tbody></table>' ;
247		//oField.innerHTML = '<table cellpadding="0" cellspacing="0" style="TABLE-LAYOUT: fixed;"><tbody><tr><td class="SC_FieldButton" style="border-left: none;">&nbsp;</td></tr></tbody></table>' ;
248
249		// Gets the correct CSS class to use for the specified style (param).
250		oField.innerHTML = '<table title="' + this.Tooltip + '" class="' + sClass + '" cellspacing="0" cellpadding="0" border="0">' +
251				'<tr>' +
252					//'<td class="TB_Icon"><img src="' + FCKConfig.SkinPath + 'toolbar/' + this.Command.Name.toLowerCase() + '.gif" width="21" height="21"></td>' +
253					'<td><img class="TB_Button_Padding" src="' + FCK_SPACER_PATH + '" /></td>' +
254					'<td class="TB_Text">' + this.Caption + '</td>' +
255					'<td><img class="TB_Button_Padding" src="' + FCK_SPACER_PATH + '" /></td>' +
256					'<td class="TB_ButtonArrow"><img src="' + FCKConfig.SkinPath + 'images/toolbar.buttonarrow.gif" width="5" height="3"></td>' +
257					'<td><img class="TB_Button_Padding" src="' + FCK_SPACER_PATH + '" /></td>' +
258				'</tr>' +
259			'</table>' ;
260	}
261
262
263	// Events Handlers
264
265	FCKTools.AddEventListenerEx( oField, 'mouseover', FCKSpecialCombo_OnMouseOver, this ) ;
266	FCKTools.AddEventListenerEx( oField, 'mouseout', FCKSpecialCombo_OnMouseOut, this ) ;
267	FCKTools.AddEventListenerEx( oField, 'click', FCKSpecialCombo_OnClick, this ) ;
268
269	FCKTools.DisableSelection( this._Panel.Document.body ) ;
270}
271
272function FCKSpecialCombo_Cleanup()
273{
274	this._LabelEl = null ;
275	this._OuterTable = null ;
276	this._ItemsHolderEl = null ;
277	this._PanelBox = null ;
278
279	if ( this.Items )
280	{
281		for ( var key in this.Items )
282			this.Items[key] = null ;
283	}
284}
285
286function FCKSpecialCombo_OnMouseOver( ev, specialCombo )
287{
288	if ( specialCombo.Enabled )
289	{
290		switch ( specialCombo.Style )
291		{
292			case FCK_TOOLBARITEM_ONLYICON :
293				this.className = 'TB_Button_On_Over';
294				break ;
295			case FCK_TOOLBARITEM_ONLYTEXT :
296				this.className = 'TB_Button_On_Over';
297				break ;
298			case FCK_TOOLBARITEM_ICONTEXT :
299				this.className = 'SC_Field SC_FieldOver' ;
300				break ;
301		}
302	}
303}
304
305function FCKSpecialCombo_OnMouseOut( ev, specialCombo )
306{
307	switch ( specialCombo.Style )
308	{
309		case FCK_TOOLBARITEM_ONLYICON :
310			this.className = 'TB_Button_Off';
311			break ;
312		case FCK_TOOLBARITEM_ONLYTEXT :
313			this.className = 'TB_Button_Off';
314			break ;
315		case FCK_TOOLBARITEM_ICONTEXT :
316			this.className='SC_Field' ;
317			break ;
318	}
319}
320
321function FCKSpecialCombo_OnClick( e, specialCombo )
322{
323	// For Mozilla we must stop the event propagation to avoid it hiding
324	// the panel because of a click outside of it.
325//	if ( e )
326//	{
327//		e.stopPropagation() ;
328//		FCKPanelEventHandlers.OnDocumentClick( e ) ;
329//	}
330
331	if ( specialCombo.Enabled )
332	{
333		var oPanel			= specialCombo._Panel ;
334		var oPanelBox		= specialCombo._PanelBox ;
335		var oItemsHolder	= specialCombo._ItemsHolderEl ;
336		var iMaxHeight		= specialCombo.PanelMaxHeight ;
337
338		if ( specialCombo.OnBeforeClick )
339			specialCombo.OnBeforeClick( specialCombo ) ;
340
341		// This is a tricky thing. We must call the "Load" function, otherwise
342		// it will not be possible to retrieve "oItemsHolder.offsetHeight" (IE only).
343		if ( FCKBrowserInfo.IsIE )
344			oPanel.Preload( 0, this.offsetHeight, this ) ;
345
346		if ( oItemsHolder.offsetHeight > iMaxHeight )
347//		{
348			oPanelBox.style.height = iMaxHeight + 'px' ;
349
350//			if ( FCKBrowserInfo.IsGecko )
351//				oPanelBox.style.overflow = '-moz-scrollbars-vertical' ;
352//		}
353		else
354			oPanelBox.style.height = '' ;
355
356//		oPanel.PanelDiv.style.width = specialCombo.PanelWidth + 'px' ;
357
358		oPanel.Show( 0, this.offsetHeight, this ) ;
359	}
360
361//	return false ;
362}
363
364/*
365Sample Combo Field HTML output:
366
367<div class="SC_Field" style="width: 80px;">
368	<table width="100%" cellpadding="0" cellspacing="0" style="table-layout: fixed;">
369		<tbody>
370			<tr>
371				<td class="SC_FieldLabel"><label>&nbsp;</label></td>
372				<td class="SC_FieldButton">&nbsp;</td>
373			</tr>
374		</tbody>
375	</table>
376</div>
377*/
378