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  * @fileOverview The "placeholder" plugin.
  8  *
  9  */
 10 
 11 (function()
 12 {
 13 	var placeholderReplaceRegex = /\[\[[^\]]+\]\]/g;
 14 	CKEDITOR.plugins.add( 'placeholder',
 15 	{
 16 		requires : [ 'dialog' ],
 17 		lang : [ 'bg', 'cs', 'cy', 'da', 'de', 'el', 'en', 'eo', 'et', 'fa', 'fi', 'fr', 'he', 'hr', 'it', 'ku', 'nb', 'nl', 'no', 'pl', 'pt-br', 'sk', 'tr', 'ug', 'uk', 'vi', 'zh-cn' ],
 18 		init : function( editor )
 19 		{
 20 			var lang = editor.lang.placeholder;
 21 
 22 			editor.addCommand( 'createplaceholder', new CKEDITOR.dialogCommand( 'createplaceholder' ) );
 23 			editor.addCommand( 'editplaceholder', new CKEDITOR.dialogCommand( 'editplaceholder' ) );
 24 
 25 			editor.ui.addButton( 'CreatePlaceholder',
 26 			{
 27 				label : lang.toolbar,
 28 				command :'createplaceholder',
 29 				icon : this.path + 'placeholder.gif'
 30 			});
 31 
 32 			if ( editor.addMenuItems )
 33 			{
 34 				editor.addMenuGroup( 'placeholder', 20 );
 35 				editor.addMenuItems(
 36 					{
 37 						editplaceholder :
 38 						{
 39 							label : lang.edit,
 40 							command : 'editplaceholder',
 41 							group : 'placeholder',
 42 							order : 1,
 43 							icon : this.path + 'placeholder.gif'
 44 						}
 45 					} );
 46 
 47 				if ( editor.contextMenu )
 48 				{
 49 					editor.contextMenu.addListener( function( element, selection )
 50 						{
 51 							if ( !element || !element.data( 'cke-placeholder' ) )
 52 								return null;
 53 
 54 							return { editplaceholder : CKEDITOR.TRISTATE_OFF };
 55 						} );
 56 				}
 57 			}
 58 
 59 			editor.on( 'doubleclick', function( evt )
 60 				{
 61 					if ( CKEDITOR.plugins.placeholder.getSelectedPlaceHoder( editor ) )
 62 						evt.data.dialog = 'editplaceholder';
 63 				});
 64 
 65 			editor.addCss(
 66 				'.cke_placeholder' +
 67 				'{' +
 68 					'background-color: #ffff00;' +
 69 					( CKEDITOR.env.gecko ? 'cursor: default;' : '' ) +
 70 				'}'
 71 			);
 72 
 73 			editor.on( 'contentDom', function()
 74 				{
 75 					editor.document.getBody().on( 'resizestart', function( evt )
 76 						{
 77 							if ( editor.getSelection().getSelectedElement().data( 'cke-placeholder' ) )
 78 								evt.data.preventDefault();
 79 						});
 80 				});
 81 
 82 			CKEDITOR.dialog.add( 'createplaceholder', this.path + 'dialogs/placeholder.js' );
 83 			CKEDITOR.dialog.add( 'editplaceholder', this.path + 'dialogs/placeholder.js' );
 84 		},
 85 		afterInit : function( editor )
 86 		{
 87 			var dataProcessor = editor.dataProcessor,
 88 				dataFilter = dataProcessor && dataProcessor.dataFilter,
 89 				htmlFilter = dataProcessor && dataProcessor.htmlFilter;
 90 
 91 			if ( dataFilter )
 92 			{
 93 				dataFilter.addRules(
 94 				{
 95 					text : function( text )
 96 					{
 97 						return text.replace( placeholderReplaceRegex, function( match )
 98 							{
 99 								return CKEDITOR.plugins.placeholder.createPlaceholder( editor, null, match, 1 );
100 							});
101 					}
102 				});
103 			}
104 
105 			if ( htmlFilter )
106 			{
107 				htmlFilter.addRules(
108 				{
109 					elements :
110 					{
111 						'span' : function( element )
112 						{
113 							if ( element.attributes && element.attributes[ 'data-cke-placeholder' ] )
114 								delete element.name;
115 						}
116 					}
117 				});
118 			}
119 		}
120 	});
121 })();
122 
123 CKEDITOR.plugins.placeholder =
124 {
125 	createPlaceholder : function( editor, oldElement, text, isGet )
126 	{
127 		var element = new CKEDITOR.dom.element( 'span', editor.document );
128 		element.setAttributes(
129 			{
130 				contentEditable		: 'false',
131 				'data-cke-placeholder'	: 1,
132 				'class'			: 'cke_placeholder'
133 			}
134 		);
135 
136 		text && element.setText( text );
137 
138 		if ( isGet )
139 			return element.getOuterHtml();
140 
141 		if ( oldElement )
142 		{
143 			if ( CKEDITOR.env.ie )
144 			{
145 				element.insertAfter( oldElement );
146 				// Some time is required for IE before the element is removed.
147 				setTimeout( function()
148 					{
149 						oldElement.remove();
150 						element.focus();
151 					}, 10 );
152 			}
153 			else
154 				element.replace( oldElement );
155 		}
156 		else
157 			editor.insertElement( element );
158 
159 		return null;
160 	},
161 
162 	getSelectedPlaceHoder : function( editor )
163 	{
164 		var range = editor.getSelection().getRanges()[ 0 ];
165 		range.shrink( CKEDITOR.SHRINK_TEXT );
166 		var node = range.startContainer;
167 		while( node && !( node.type == CKEDITOR.NODE_ELEMENT && node.data( 'cke-placeholder' ) ) )
168 			node = node.getParent();
169 		return node;
170 	}
171 };
172