//*******************************************************************
//** TinyCode is a TinyMCE plugin to insert and edit code snippet in TinyMCE editor
//** The code snippet could be recognized and color highlighted by Alex Gorbatchev's SyntaxHighlighter (http://alexgorbatchev.com/SyntaxHighlighter)
//** Author: COMSHARP
//** http://www.comsharp.com
//** Special thanks to Richard Grundy (http://27smiles.com) whose SyntaxHL plugin is the initial blue print of TinyCode 
//*******************************************************************
//** TinyCode 是一个用来在 TinyMCE 中插入和编辑代码片段的 TinyMCE 插件
//** 插入的代码片段可以被 Alex Gorbatchev 的 SyntaxHighlighter (http://alexgorbatchev.com/SyntaxHighlighter) 识别并进行加亮处理
//** 作者：锐商软件
//** http://www.comsharp.com
//** 特别感谢本插件的最初蓝本 SyntaxHL 的作者 Richard Grundy (http://27smiles.com)
//*******************************************************************

(function() 
{
	//--------------------------------
	//- Load the language file | 加载语言文件 ( tinycode 就是该插件的名字 ）
	//--------------------------------
	tinymce.PluginManager.requireLangPack('tinycode');
	
	//********************************
	//** Plugin Initialization | 插件初始化
	//********************************
	tinymce.create('tinymce.plugins.tinycode', 
	{
		//--------------------------------
		//-- Initialization : Executed after the creation of the plugin  |  初始化： 插件被加载后执行该部分初始化代码
		//--------------------------------
		//-- @param ed  {tinymce.Editor} - Editor instance that the plugin is initialized in.      |  参数 ed {tinymce.Editor} - 该插件所在的 TinyMCE 编辑器实例
		//-- @param url {string}         - string url Absolute URL to where the plugin is located. |  参数 url {string}        - 该插件所在的绝对路径
		//--------------------------------
		init : function(ed, url) 
		{
			//--------------------------------
			//-- Register the command so that it can be invoked by using tinyMCE.activeEditor.execCommand('mceTinyCode'), ie when the tool button of this plugin clicked  |  注册 mceTinyCode 命令，也就是点击了该插件按钮后执行的命令
			//--------------------------------
			ed.addCommand('mceTinyCode', function() 
			{
				//--------------------------------
				//-- Check currently selected node for tinycode 'brush:' parameter   |    当前选中内容是不是包含 （<pre class="brush:...">...</pre>） 标志
				//--------------------------------
				if (isBrush()==true)
				{
					//--------------------------------
					//-- Get current node in cursor position  |   获取当前光标所在的位置的节点对象 （<pre class="brush:...">...</pre>），如果是加亮代码段，则将当前节点内容载入，否则不载入
					//--------------------------------
					var currentNode = ed.selection.getNode();
					
					//--------------------------------
					//-- Get current node content and brush parameter  |   获取当前光标所在位置节点（element） 的内容和 brush 的参数
					//--------------------------------
					var currentNodeContent=currentNode.innerHTML;
					var currentNodeParameters=getParameters(currentNode.className);
				
					//--------------------------------
					//-- Whether there is further content after the code snipet or not, if not, we insert <p>&nbsp;</p>  |  当前代码片段后面是否有内容，如果没有，光标在 <pre> 中无法通过按回车键逃出，所以，我们需要强行插入一段 <p>&nbsp;</p> 
					//--------------------------------
					var currentNodeHasSibling=false;
					
					if (currentNode.nextSibling!=null)
					{
						currentNodeHasSibling=true;
					}

					//--------------------------------
					//-- Select entire snippted and limit to element type.   |    整个选中以便在完成后，重新插入的代码可以替换原来旧的
					//--------------------------------
					ed.selection.select(currentNode, currentNode.nodeName); 
					
					//--------------------------------
					//-- Open plugin dialogue window   |   打开插件窗口
					//--------------------------------
					ed.windowManager.open(
					{
						//--------------------------------
						//-- Plugin window path and property   |   插件窗口路径和属性
						//--------------------------------
						file : url + '/dialog.htm',
						width : 500,
						height : 380,
						inline : 1
					}, 
					{
						//--------------------------------
						//-- Plugin more property   |   插件更多属性 （包括要编辑的代码内容，以及代码语言等属性）
						//--------------------------------
						plugin_url : url, 
						replace_content : true,
						editor_content : currentNodeContent,
						editor_options : currentNodeParameters,
						hasSibling : currentNodeHasSibling
					});
				}
				else
				{
					//--------------------------------
					//-- Whether there is further content after the code snipet or not, if not, we insert <p>&nbsp;</p>  |  当前代码片段后面是否有内容，如果没有，光标在 <pre> 中无法通过按回车键逃出，所以，我们需要强行插入一段 <p>&nbsp;</p> 
					//--------------------------------
					var currentNode = ed.selection.getNode();
					var currentNodeHasSibling=false;
					
					if (currentNode.nextSibling!=null)
					{
						currentNodeHasSibling=true;
					}
				
					ed.windowManager.open(
					{
						file : url + '/dialog.htm',
						width : 500,
						height : 380,
						inline : 1
					}, 
					{
						plugin_url : url, // Plugin absolute URL
						replace_content : false,
						hasSibling : currentNodeHasSibling
					});
				}
			});

			//--------------------------------
			//-- Register plugin  button   |    注册插件按钮 （描述，命令名，图标）
			//--------------------------------
			ed.addButton('tinycode', 
			{
				title : 'tinycode.desc',
				cmd : 'mceTinyCode',
				image : url + '/img/tinycode.gif'
			});

			//--------------------------------
			//-- When the code was selected, change the button status   |    当编辑器中被编辑的代码被选中（或者光标置入）的时候，插件按钮状态发生变化  （代码内容的标志  <pre class="brush:...">...</pre>）
			//--------------------------------
			ed.onNodeChange.add(function(ed, cm, n) 
			{
				cm.setActive('tinycode', n.nodeName.toLowerCase() == 'pre' && n.className.indexOf('brush:') != -1);				
			});

			//--------------------------------
			//-- Context menu   |   右键菜单
			//--------------------------------
			if(ed.plugins.contextmenu != undefined)
			{
				ed.plugins.contextmenu.onContextMenu.add(function(sender, menu)
				{
					//--------------------------------
					//-- Check currently selected node for tinycode 'brush:' parameter   |    当前选中内容是不是包含 （<pre class="brush:...">...</pre>） 标志
					//--------------------------------
					if(isBrush()) 
					{
						//--------------------------------
						//-- Define sub menu   |   定义右键子菜单
						//--------------------------------
						var sub_menu = menu.add(
						{
							title : ed.getLang('tinycode.context_menu_edit','Code Highlight - Edit'),
							icon : url + '/img/tinycode.gif',
							
							onclick : function() 
							{ 
								//--------------------------------
								//-- Get current selected node |  当前被选中的内容节点 （光标所在节点）
								//--------------------------------
								var currentNode = ed.selection.getNode();
								
								//--------------------------------
								//-- Get current node content and brush parameter  |   获取当前光标所在位置节点（element） 的内容和 brush 的参数
								//--------------------------------
								var currentNodeContent=currentNode.innerHTML;
								var currentNodeParameters=getParameters(currentNode.className);

								//--------------------------------
								//-- Whether there is further content after the code snipet or not, if not, we insert <p>&nbsp;</p>  |  当前代码片段后面是否有内容，如果没有，光标在 <pre> 中无法通过按回车键逃出，所以，我们需要强行插入一段 <p>&nbsp;</p> 
								//--------------------------------
								var currentNodeHasSibling=false;
								
								if (currentNode.nextSibling!=null)
								{
									currentNodeHasSibling=true;
								}
								
								//--------------------------------
								//-- Select entire snippted and limit to element type.   |    整个选中以便在完成后，重新插入的代码可以替换原来旧的
								//--------------------------------
								ed.selection.select(currentNode, currentNode.nodeName); 
								
								//--------------------------------
								//-- Open the plugin dialogue window when this context menu clicked   |    右键菜单点中后，打开插件对话框窗口
								//--------------------------------
								ed.windowManager.open(
								{
									file : url + '/dialog.htm',
									width : 500,
									height : 380,
									inline : 1
								}, 
								{
									plugin_url : url, 
									replace_content : true,
									editor_content : currentNodeContent,
									editor_options : currentNodeParameters,
									hasSibling : currentNodeHasSibling
								});
							}
						});
					}
					else 
					{
						//--------------------------------
						//-- If current selected node is not code snippet, create new contxt menu to create new snytaxHL element   |   如果当前选中的节点不是待编辑的代码片段，则右键菜单设置为添加新代码片段
						//--------------------------------
						var sub_menu = menu.add(
						{
							title : ed.getLang('tinycode.context_menu_add','Code Highlight - New'),
							icon : url + '/img/tinycode.gif',
							
							onclick : function() 
							{
								//--------------------------------
								//-- Whether there is further content after the code snipet or not, if not, we insert <p>&nbsp;</p>  |  当前代码片段后面是否有内容，如果没有，光标在 <pre> 中无法通过按回车键逃出，所以，我们需要强行插入一段 <p>&nbsp;</p> 
								//--------------------------------
								var currentNode = ed.selection.getNode();
								var currentNodeHasSibling=false;
								
								if (currentNode.nextSibling!=null)
								{
									currentNodeHasSibling=true;
								}
							
								ed.windowManager.open(
								{
									file : url + '/dialog.htm',
									width : 500,
									height : 380,
									inline : 1
								}, 
								{
									plugin_url : url, // Plugin absolute URL
									replace_content : false,
									hasSibling : currentNodeHasSibling
								});
							}
						});
					}
				});
			};
			
			//--------------------------------
			//-- force the enter key in <pre> to be \r\n  instead of <br />  |  将 <pre> 中的回车键变成断行，不要变成 <br />
			//-- force the tab key in <pre> to be \t  |  将 <pre> 中的 tab 键变成 \t
			//--------------------------------
			ed.onKeyDown.add(function( ed, e )
			{
				if ( e.keyCode == 13 && e.shiftKey==false && ed.selection.getNode().nodeName.toLowerCase() === 'pre' )
				{
					ed.selection.setContent(String.fromCharCode(13), {format : 'raw'});
					return tinymce.dom.Event.cancel(e);					
				}

				if ( e.keyCode == 9 && ed.selection.getNode().nodeName.toLowerCase() === 'pre' )
				{
					ed.selection.setContent(String.fromCharCode(9), {format : 'raw'});
					return tinymce.dom.Event.cancel(e);
				}
			})
		},

		//--------------------------------
		//-- Creates control instances based in the incomming name. This method is normally not
		//-- needed since the addButton method of the tinymce.Editor class is a more easy way of adding buttons
		//-- but you sometimes need to create more complex controls like listboxes, split buttons etc then this
		//-- method can be used to create those.
		//--------------------------------
		//-- @param {String} n Name of the control to create.
		//-- @param {tinymce.ControlManager} cm Control manager to use inorder to create new control.
		//-- @return {tinymce.ui.Control} New control instance or null if no control was created.
		//--------------------------------
		createControl : function(n, cm) 
		{
			return null;
		},

		//--------------------------------
		//-- Returns information about the plugin as a name/value array.
		//-- The current keys are longname, author, authorurl, infourl and version.
		//--------------------------------
		//-- @return {Object} Name/value array containing information about the plugin.
		//--------------------------------
		getInfo : function() 
		{
			return {
				longname : 'Tiny Code',
				author : 'xxx',
				authorurl : 'http://www.xxx.com',
				infourl : 'http://www.xxx.com',
				version : "1.0"
			};
		}
		
	});

	//********************************
	//** Check the currently selected node to ensure it is a valid syntaxHighlighter brush.   |    检查当前选中的节点，判断是否带编辑的代码段 （<pre class="brush:...">...</pre>）
	//********************************
	//** @return boolean true if node is valid brush
	//********************************
	function isBrush() 
	{
		var node = tinyMCE.activeEditor.selection.getNode();
		
		if(node.nodeName != null && node.nodeName.toLowerCase() == 'pre' && node.className.indexOf('brush:') != -1)
		{
			return true;
		}
		else
		{
			return false;
		}
	}

	//********************************
	//** Parses Syntax Highlighters parameters within the class attribute and returns them in an associative array.   |    从代码 <pre> 的 class 属性中解析代码段的属性（比如代码语言类型）
	//********************************
	//** @param params string or Syntax Highlighter parameters to parse
	//********************************
	//** @return array
	//********************************
	function getParameters(params) 
	{
		var parsedItems = params.replace(/ /g, '').replace(/;([^;]*)$/, '').split(';');
		var paramArray = new Array();
		
		for(var i = 0; i < parsedItems.length; i++)
		{
			var option = parsedItems[i].split(':');
			paramArray[option[0]] = option[1];
		}
		
		return paramArray;
	}

	//********************************
	//** Register plugin   |    注册插件
	//********************************
	tinymce.PluginManager.add('tinycode', tinymce.plugins.tinycode);
	
})();