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 CKEDITOR.dialog.add( 'smiley', function( editor )
  7 {
  8 	var config = editor.config,
  9 		images = config.smiley_images,
 10 		columns = config.smiley_columns,
 11 		i;
 12
 13 	/**
 14 	 * Simulate "this" of a dialog for non-dialog events.
 15 	 * @type {CKEDITOR.dialog}
 16 	 */
 17 	var dialog;
 18 	var onClick = function( evt )
 19 	{
 20 		var target = evt.data.getTarget(),
 21 			targetName = target.getName();
 22
 23 		if ( targetName == 'td' )
 24 			target = target.getChild( [ 0, 0 ] );
 25 		else if ( targetName == 'a' )
 26 			target = target.getChild( 0 );
 27 		else if ( targetName != 'img' )
 28 			return;
 29
 30 		var src = target.getAttribute( 'cke_src' ),
 31 			title = target.getAttribute( 'title' );
 32
 33 		var img = editor.document.createElement( 'img',
 34 			{
 35 				attributes :
 36 				{
 37 					src : src,
 38 					_cke_saved_src : src,
 39 					title : title,
 40 					alt : title
 41 				}
 42 			});
 43
 44 		editor.insertElement( img );
 45
 46 		dialog.hide();
 47 	};
 48
 49 	var onKeydown = CKEDITOR.tools.addFunction( function( ev, element )
 50 	{
 51 		ev = new CKEDITOR.dom.event( ev );
 52 		element = new CKEDITOR.dom.element( element );
 53 		var relative, nodeToMove;
 54
 55 		var keystroke = ev.getKeystroke();
 56 		switch ( keystroke )
 57 		{
 58 			// RIGHT-ARROW
 59 			case 39 :
 60 				// relative is TD
 61 				if ( ( relative = element.getParent().getNext() ) )
 62 				{
 63 					nodeToMove = relative.getChild( 0 );
 64 					nodeToMove.focus();
 65 				}
 66 				ev.preventDefault();
 67 				break;
 68 			// LEFT-ARROW
 69 			case 37 :
 70 				// relative is TD
 71 				if ( ( relative = element.getParent().getPrevious() ) )
 72 				{
 73 					nodeToMove = relative.getChild( 0 );
 74 					nodeToMove.focus();
 75 				}
 76 				ev.preventDefault();
 77 				break;
 78 			// UP-ARROW
 79 			case 38 :
 80 				// relative is TR
 81 				if ( ( relative = element.getParent().getParent().getPrevious() ) )
 82 				{
 83 					nodeToMove = relative.getChild( [element.getParent().getIndex(), 0] );
 84 					nodeToMove.focus();
 85 				}
 86 				ev.preventDefault();
 87 				break;
 88 			// DOWN-ARROW
 89 			case 40 :
 90 				// relative is TR
 91 				if ( ( relative = element.getParent().getParent().getNext() ) )
 92 				{
 93 					nodeToMove = relative.getChild( [element.getParent().getIndex(), 0] );
 94 					if ( nodeToMove )
 95 						nodeToMove.focus();
 96 				}
 97 				ev.preventDefault();
 98 				break;
 99 			// ENTER
100 			// SPACE
101 			case 32 :
102 				onClick( { data: ev } );
103 				ev.preventDefault();
104 				break;
105 			// TAB
106 			case 9 :
107 				// relative is TD
108 				if ( ( relative = element.getParent().getNext() ) )
109 				{
110 					nodeToMove = relative.getChild( 0 );
111 					nodeToMove.focus();
112 					ev.preventDefault(true);
113 				}
114 				// relative is TR
115 				else if ( ( relative = element.getParent().getParent().getNext() ) )
116 				{
117 					nodeToMove = relative.getChild( [0, 0] );
118 					if ( nodeToMove )
119 						nodeToMove.focus();
120 					ev.preventDefault(true);
121 				}
122 				break;
123 			// SHIFT + TAB
124 			case CKEDITOR.SHIFT + 9 :
125 				// relative is TD
126 				if ( ( relative = element.getParent().getPrevious() ) )
127 				{
128 					nodeToMove = relative.getChild( 0 );
129 					nodeToMove.focus();
130 					ev.preventDefault(true);
131 				}
132 				// relative is TR
133 				else if ( ( relative = element.getParent().getParent().getPrevious() ) )
134 				{
135 					nodeToMove = relative.getLast().getChild( 0 );
136 					nodeToMove.focus();
137 					ev.preventDefault(true);
138 				}
139 				break;
140 			default :
141 				// Do not stop not handled events.
142 				return;
143 		}
144 	});
145
146 	// Build the HTML for the smiley images table.
147 	var html =
148 	[
149 		'<table cellspacing="2" cellpadding="2"',
150 		CKEDITOR.env.ie && CKEDITOR.env.quirks ? ' style="position:absolute;"' : '',
151 		'><tbody>'
152 	];
153
154 	for ( i = 0 ; i < images.length ; i++ )
155 	{
156 		if ( i % columns === 0 )
157 			html.push( '<tr>' );
158
159 		html.push(
160 			'<td class="cke_dark_background cke_hand cke_centered" style="vertical-align: middle;">' +
161 				'<a href="javascript:void(0)" class="cke_smile" tabindex="-1" onkeydown="CKEDITOR.tools.callFunction( ', onKeydown, ', event, this );">',
162 					'<img class="hand" title="', config.smiley_descriptions[i], '"' +
163 						' cke_src="', CKEDITOR.tools.htmlEncode( config.smiley_path + images[ i ] ), '" alt="', config.smiley_descriptions[i], '"',
164 						' src="', CKEDITOR.tools.htmlEncode( config.smiley_path + images[ i ] ), '"',
165 						// IE BUG: Below is a workaround to an IE image loading bug to ensure the image sizes are correct.
166 						( CKEDITOR.env.ie ? ' onload="this.setAttribute(\'width\', 2); this.removeAttribute(\'width\');" ' : '' ),
167 					'>' +
168 				'</a>',
169  			'</td>' );
170
171 		if ( i % columns == columns - 1 )
172 			html.push( '</tr>' );
173 	}
174
175 	if ( i < columns - 1 )
176 	{
177 		for ( ; i < columns - 1 ; i++ )
178 			html.push( '<td></td>' );
179 		html.push( '</tr>' );
180 	}
181
182 	html.push( '</tbody></table>' );
183
184 	var smileySelector =
185 	{
186 		type : 'html',
187 		html : html.join( '' ),
188 		onLoad : function( event )
189 		{
190 			dialog = event.sender;
191 		},
192 		focus : function()
193  		{
194 			var firstSmile = this.getElement().getChild( [0, 0, 0, 0] );
195 			firstSmile.focus();
196  		},
197 		onClick : onClick,
198 		style : 'width: 100%; height: 100%; border-collapse: separate;'
199 	};
200
201 	return {
202 		title : editor.lang.smiley.title,
203 		minWidth : 270,
204 		minHeight : 120,
205 		contents : [
206 			{
207 				id : 'tab1',
208 				label : '',
209 				title : '',
210 				expand : true,
211 				padding : 0,
212 				elements : [
213 						smileySelector
214 					]
215 			}
216 		],
217 		buttons : [ CKEDITOR.dialog.cancelButton ]
218 	};
219 } );
220