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 CKEDITOR.plugins.add( 'listblock',
  7 {
  8 	requires : [ 'panel' ],
  9 
 10 	onLoad : function()
 11 	{
 12 		CKEDITOR.ui.panel.prototype.addListBlock = function( name, definition )
 13 		{
 14 			return this.addBlock( name, new CKEDITOR.ui.listBlock( this.getHolderElement(), definition ) );
 15 		};
 16 
 17 		CKEDITOR.ui.listBlock = CKEDITOR.tools.createClass(
 18 			{
 19 				base : CKEDITOR.ui.panel.block,
 20 
 21 				$ : function( blockHolder, blockDefinition )
 22 				{
 23 					blockDefinition = blockDefinition || {};
 24 
 25 					var attribs = blockDefinition.attributes || ( blockDefinition.attributes = {} );
 26 					( this.multiSelect = !!blockDefinition.multiSelect ) &&
 27 						( attribs[ 'aria-multiselectable' ] = true );
 28 					// Provide default role of 'listbox'.
 29 					!attribs.role && ( attribs.role = 'listbox' );
 30 
 31 					// Call the base contructor.
 32 					this.base.apply( this, arguments );
 33 
 34 					var keys = this.keys;
 35 					keys[ 40 ]	= 'next';					// ARROW-DOWN
 36 					keys[ 9 ]	= 'next';					// TAB
 37 					keys[ 38 ]	= 'prev';					// ARROW-UP
 38 					keys[ CKEDITOR.SHIFT + 9 ]	= 'prev';	// SHIFT + TAB
 39 					keys[ 32 ]	= CKEDITOR.env.ie ? 'mouseup' : 'click';					// SPACE
 40 					CKEDITOR.env.ie && ( keys[ 13 ] = 'mouseup' );		// Manage ENTER, since onclick is blocked in IE (#8041).
 41 
 42 					this._.pendingHtml = [];
 43 					this._.items = {};
 44 					this._.groups = {};
 45 				},
 46 
 47 				_ :
 48 				{
 49 					close : function()
 50 					{
 51 						if ( this._.started )
 52 						{
 53 							this._.pendingHtml.push( '</ul>' );
 54 							delete this._.started;
 55 						}
 56 					},
 57 
 58 					getClick : function()
 59 					{
 60 						if ( !this._.click )
 61 						{
 62 							this._.click = CKEDITOR.tools.addFunction( function( value )
 63 								{
 64 									var marked = true;
 65 
 66 									if ( this.multiSelect )
 67 										marked = this.toggle( value );
 68 									else
 69 										this.mark( value );
 70 
 71 									if ( this.onClick )
 72 										this.onClick( value, marked );
 73 								},
 74 								this );
 75 						}
 76 						return this._.click;
 77 					}
 78 				},
 79 
 80 				proto :
 81 				{
 82 					add : function( value, html, title )
 83 					{
 84 						var pendingHtml = this._.pendingHtml,
 85 							id = CKEDITOR.tools.getNextId();
 86 
 87 						if ( !this._.started )
 88 						{
 89 							pendingHtml.push( '<ul role="presentation" class=cke_panel_list>' );
 90 							this._.started = 1;
 91 							this._.size = this._.size || 0;
 92 						}
 93 
 94 						this._.items[ value ] = id;
 95 
 96 						pendingHtml.push(
 97 							'<li id=', id, ' class=cke_panel_listItem role=presentation>' +
 98 								'<a id="', id, '_option" _cke_focus=1 hidefocus=true' +
 99 									' title="', title || value, '"' +
100 									' href="javascript:void(\'', value, '\')" ' +
101 									( CKEDITOR.env.ie ? 'onclick="return false;" onmouseup' : 'onclick' ) +		// #188
102 										'="CKEDITOR.tools.callFunction(', this._.getClick(), ',\'', value, '\'); return false;"',
103 									' role="option">',
104 									html || value,
105 								'</a>' +
106 							'</li>' );
107 					},
108 
109 					startGroup : function( title )
110 					{
111 						this._.close();
112 
113 						var id = CKEDITOR.tools.getNextId();
114 
115 						this._.groups[ title ] = id;
116 
117 						this._.pendingHtml.push( '<h1 role="presentation" id=', id, ' class=cke_panel_grouptitle>', title, '</h1>' );
118 					},
119 
120 					commit : function()
121 					{
122 						this._.close();
123 						this.element.appendHtml( this._.pendingHtml.join( '' ) );
124 						delete this._.size;
125 
126 						this._.pendingHtml = [];
127 					},
128 
129 					toggle : function( value )
130 					{
131 						var isMarked = this.isMarked( value );
132 
133 						if ( isMarked )
134 							this.unmark( value );
135 						else
136 							this.mark( value );
137 
138 						return !isMarked;
139 					},
140 
141 					hideGroup : function( groupTitle )
142 					{
143 						var group = this.element.getDocument().getById( this._.groups[ groupTitle ] ),
144 							list = group && group.getNext();
145 
146 						if ( group )
147 						{
148 							group.setStyle( 'display', 'none' );
149 
150 							if ( list && list.getName() == 'ul' )
151 								list.setStyle( 'display', 'none' );
152 						}
153 					},
154 
155 					hideItem : function( value )
156 					{
157 						this.element.getDocument().getById( this._.items[ value ] ).setStyle( 'display', 'none' );
158 					},
159 
160 					showAll : function()
161 					{
162 						var items = this._.items,
163 							groups = this._.groups,
164 							doc = this.element.getDocument();
165 
166 						for ( var value in items )
167 						{
168 							doc.getById( items[ value ] ).setStyle( 'display', '' );
169 						}
170 
171 						for ( var title in groups )
172 						{
173 							var group = doc.getById( groups[ title ] ),
174 								list = group.getNext();
175 
176 							group.setStyle( 'display', '' );
177 
178 							if ( list && list.getName() == 'ul' )
179 								list.setStyle( 'display', '' );
180 						}
181 					},
182 
183 					mark : function( value )
184 					{
185 						if ( !this.multiSelect )
186 							this.unmarkAll();
187 
188 						var itemId = this._.items[ value ],
189 							item = this.element.getDocument().getById( itemId );
190 						item.addClass( 'cke_selected' );
191 
192 						this.element.getDocument().getById( itemId + '_option' ).setAttribute( 'aria-selected', true );
193 						this.onMark && this.onMark( item );
194 					},
195 
196 					unmark : function( value )
197 					{
198 						var doc = this.element.getDocument(),
199 							itemId = this._.items[ value ],
200 							item = doc.getById( itemId );
201 
202 						item.removeClass( 'cke_selected' );
203 						doc.getById( itemId + '_option' ).removeAttribute( 'aria-selected' );
204 
205 						this.onUnmark && this.onUnmark( item );
206 					},
207 
208 					unmarkAll : function()
209 					{
210 						var items = this._.items,
211 							doc = this.element.getDocument();
212 
213 						for ( var value in items )
214 						{
215 							var itemId = items[ value ];
216 
217 							doc.getById( itemId ).removeClass( 'cke_selected' );
218 							doc.getById( itemId + '_option' ).removeAttribute( 'aria-selected' );
219 						}
220 
221 						this.onUnmark && this.onUnmark();
222 					},
223 
224 					isMarked : function( value )
225 					{
226 						return this.element.getDocument().getById( this._.items[ value ] ).hasClass( 'cke_selected' );
227 					},
228 
229 					focus : function( value )
230 					{
231 						this._.focusIndex = -1;
232 
233 						if ( value )
234 						{
235 							var selected = this.element.getDocument().getById( this._.items[ value ] ).getFirst();
236 
237 							var links = this.element.getElementsByTag( 'a' ),
238 								link,
239 								i = -1;
240 
241 							while ( ( link = links.getItem( ++i ) ) )
242 							{
243 								if ( link.equals( selected ) )
244 								{
245 									this._.focusIndex = i;
246 									break;
247 								}
248 							}
249 
250 							setTimeout( function()
251 								{
252 									selected.focus();
253 								},
254 								0 );
255 						}
256 					}
257 				}
258 			});
259 	}
260 });
261