瀏覽代碼

Updated the SCEditor code to version 1.3.6 - custom changes need update

Signed-off-by: emanuele <[email protected]>
emanuele 12 年之前
父節點
當前提交
db5b583d63
共有 2 個文件被更改,包括 951 次插入463 次删除
  1. 322 246
      Themes/default/scripts/jquery.sceditor.bbcode.js
  2. 629 217
      Themes/default/scripts/jquery.sceditor.js

+ 322 - 246
Themes/default/scripts/jquery.sceditor.bbcode.js

@@ -1,11 +1,15 @@
 /**
- * SCEditor BBCode Plugin v1.3.4
- * http://www.samclarke.com/2011/07/sceditor/ 
+ * SCEditor BBCode Plugin
+ * http://www.samclarke.com/2011/07/sceditor/
  *
  * Copyright (C) 2011-2012, Sam Clarke (samclarke.com)
  *
  * SCEditor is licensed under the MIT license:
  *	http://www.opensource.org/licenses/mit-license.php
+ *
+ * @author Sam Clarke
+ * @version 1.3.6
+ * @requires jQuery
  */
 
 // ==ClosureCompiler==
@@ -18,6 +22,14 @@
 (function($) {
 	'use strict';
 
+	/**
+	 * BBCode plugin for SCEditor
+	 *
+	 * @param {Element} el The textarea to be converted
+	 * @return {Object} options
+	 * @class sceditorBBCodePlugin
+	 * @name jQuery.sceditorBBCodePlugin
+	 */
 	$.sceditorBBCodePlugin = function(element, options) {
 		var base = this;
 
@@ -32,6 +44,7 @@
 			formatString,
 			getStyle,
 			wrapInDivs,
+			isEmpty,
 			mergeTextModeCommands;
 
 		base.bbcodes = $.sceditorBBCodePlugin.bbcodes;
@@ -49,7 +62,7 @@
 		 * @private
 		 */
 		var stylesToBbcodes = {};
-		
+
 		/**
 		 * Allowed children of specific HTML tags. Empty array if no
 		 * children other than text nodes are allowed
@@ -66,10 +79,12 @@
 
 		/**
 		 * Initializer
+		 * @private
+		 * @name sceditorBBCodePlugin.init
 		 */
 		init = function() {
 			$.data(element, "sceditorbbcode", base);
-			
+
 			base.options = $.extend({}, $.sceditor.defaultOptions, options);
 
 			// build the BBCode cache
@@ -83,10 +98,8 @@
 				})
 			));
 		};
-		
+
 		mergeTextModeCommands = function() {
-			// TODO: use selection as display text if is one.
-			// TODO: add translations of the prompts
 			var merge = {
 				bold: { txtExec: ["[b]", "[/b]"] },
 				italic: { txtExec: ["[i]", "[/i]"] },
@@ -98,149 +111,95 @@
 				center: { txtExec: ["[center]", "[/center]"] },
 				right: { txtExec: ["[right]", "[/right]"] },
 				justify: { txtExec: ["[justify]", "[/justify]"] },
-				bulletlist: { txtExec: ["[list]\n[li]", "[/li]\n[li][/li]\n[/list]"] },
-				orderedlist: { txtExec: ["[list type=decimal]\n[li]", "[/li]\n[li][/li]\n[/list]"] },
 				ftp: { txtExec: ["[ftp]", "[/ftp]"] },
 				tt: { txtExec: ["[tt]", "[/tt]"] },
 				glow: { txtExec: ["[glow=red,2,300]", "[/glow]"] },
 				shadow: { txtExec: ["[shadow=red,left]", "[/shadow]"] },
 				pre: { txtExec: ["[pre]", "[/pre]"] },
-				font: {
-					txtExec: function (caller) {
-						var	editor  = this,
-							fonts   = editor.options.fonts.split(","),
-							content = $("<div />"),
-							clickFunc = function (e) {
-								editor.textEditorInsertText("[font=" + $(this).data('sceditor-font') + "]", "[/font]");
-								editor.closeDropDown(true);
-								e.preventDefault();
-							};
-
-						for (var i=0; i < fonts.length; i++) {
-							content.append(
-								$('<a class="sceditor-font-option" href="#"><font face="' + fonts[i] + '">' + fonts[i] + '</font></a>')
-									.data('sceditor-font', fonts[i])
-									.click(clickFunc));
+				// @todo: check tooltip
+				font: { txtExec: function(caller) {
+					var editor = this;
+
+					$.sceditor.command.get('font')._dropDown(
+						editor,
+						caller,
+						function(fontName) {
+							editor.insertText("[font="+fontName+"]", "[/font]");
 						}
-
-						editor.createDropDown(caller, "font-picker", content);
-					},
-					tooltip: "Font Name"
-				},
-				size: {
-					txtExec: function (caller) {
-						var sizes = [0, 8, 10, 12, 14, 18, 24, 36];
-						var	editor    = this,
-							content   = $("<div />"),
-							clickFunc = function (e) {
-								editor.textEditorInsertText("[size=" + sizes[$(this).data('sceditor-fontsize')] + "pt]", "[/size]");
-								editor.closeDropDown(true);
-								e.preventDefault();
-							};
-
-						for (var i=1; i<= 7; i++) {
-							content.append(
-								$('<a class="sceditor-fontsize-option" style="line-height:' + sizes[i] + 'pt" href="#"><font size="' + i + '">' + sizes[i] + 'pt</font></a>')
-									.data('sceditor-fontsize', i)
-									.click(clickFunc));
+					);
+				} },
+				// @todo: check overlapping
+				size: { txtExec: function(caller) {
+					var editor = this;
+
+					$.sceditor.command.get('size')._dropDown(
+						editor,
+						caller,
+						function(fontSize) {
+							editor.insertText("[size="+fontSize+"]", "[/size]");
 						}
-
-						editor.createDropDown(caller, "fontsize-picker", content);
-					},
-					tooltip: "Font Size"
-				},
-				color: {
-					txtExec: function (caller) {
-						var	editor			= this,
-							genColor		= {r: 255, g: 255, b: 255},
-							content			= $("<div />"),
-							colorColumns	= this.options.colors?this.options.colors.split("|"):new Array(21),
-							// IE is slow at string concation so use an array
-							html			= [],
-							htmlIndex		= 0;
-
-						for (var i=0; i < colorColumns.length; ++i) {
-							var colors = (typeof colorColumns[i] !== "undefined")?colorColumns[i].split(","):new Array(21);
-
-							html[htmlIndex++] = '<div class="sceditor-color-column">';
-
-							for (var x=0; x < colors.length; ++x) {
-								// use pre defined colour if can otherwise use the generated color
-								var color = (typeof colors[x] !== "undefined")?colors[x]:"#" + genColor.r.toString(16) + genColor.g.toString(16) + genColor.b.toString(16);
-
-								html[htmlIndex++] = '<a href="#" class="sceditor-color-option" style="background-color: '+color+'" data-color="'+color+'"></a>';
-
-								// calculate the next generated color
-								if(x%5===0)
-									genColor = {r: genColor.r, g: genColor.g-51, b: 255};
-								else
-									genColor = {r: genColor.r, g: genColor.g, b: genColor.b-51};
-							}
-
-							html[htmlIndex++] = '</div>';
-
-							// calculate the next generated color
-							if(i%5===0)
-								genColor = {r: genColor.r-51, g: 255, b: 255};
-							else
-								genColor = {r: genColor.r, g: 255, b: 255};
+					);
+				} },
+				color: { txtExec: function(caller) {
+					var editor = this;
+
+					$.sceditor.command.get('color')._dropDown(
+						editor,
+						caller,
+						function(color) {
+							editor.insertText("[color="+color+"]", "[/color]");
 						}
-
-						content.append(html.join(''))
-							.find('a')
-							.click(function (e) {
-								editor.textEditorInsertText("[color=" + $(this).attr('data-color') + "]", "[/color]");
-								editor.closeDropDown(true);
-								e.preventDefault();
-							});
-
-						editor.createDropDown(caller, "color-picker", content);
-					},
-					tooltip: "Font Color"
-				},
+					);
+				} },
+				bulletlist: { txtExec: ["[list]\n[li]", "[/li]\n[li][/li]\n[/list]"] },
+				orderedlist: { txtExec: ["[list type=decimal]\n[li]", "[/li]\n[li][/li]\n[/list]"] },
 				table: { txtExec: ["[table]\n[tr]\n[td]", "[/td]\n[/tr]\n[/table]"] },
 				horizontalrule: { txtExec: ["[hr]"] },
 				code: { txtExec: ["[code]", "[/code]"] },
-				image: { txtExec: function() {
-					var url = prompt(this._("Enter the images URL:"));
-					
+				image: { txtExec: function(caller, selected) {
+					var url = prompt(this._("Enter the image URL:"), selected);
+
 					if(url)
-						this.textEditorInsertText("[img]" + url + "[/img]");
+						this.insertText("[img]" + url + "[/img]");
 				} },
-				email: { txtExec: function() {
-					var	email	= prompt(this._("Enter the e-mail address:"), "@"),
-						text	= prompt(this._("Enter the displayed text:"), email) || email;
-					
+				email: { txtExec: function(caller, selected) {
+					var	display = selected && selected.indexOf('@') > -1 ? null : selected,
+						email	= prompt(this._("Enter the e-mail address:"), (display ? '' : selected)),
+						text	= prompt(this._("Enter the displayed text:"), display || email) || email;
+
 					if(email)
-						this.textEditorInsertText("[email=" + email + "]" + text + "[/email]");
+						this.insertText("[email=" + email + "]" + text + "[/email]");
 				} },
-				link: { txtExec: function() {
-					var	url	= prompt(this._("Enter the links URL:"), "http://"),
-						text	= prompt(this._("Enter the displayed text:"), url) || url;
-					
+				link: { txtExec: function(caller, selected) {
+					var	display = selected && selected.indexOf('http://') > -1 ? null : selected,
+						url	= prompt(this._("Enter URL:"), (display ? 'http://' : selected)),
+						text	= prompt(this._("Enter the displayed text:"), display || url) || url;
+
 					if(url)
-						this.textEditorInsertText("[url=" + url + "]" + text + "[/url]");
+						this.insertText("[url=" + url + "]" + text + "[/url]");
 				} },
 				quote: { txtExec: ["[quote]", "[/quote]"] },
-				youtube: { txtExec: function() {
-					var url = prompt(this._("Enter the YouTube video URL or ID:"));
-					
-					if(url)
-					{
-						if(url.indexOf("://") > -1)
-							url = url.replace(/^[^v]+v.(.{11}).*/,"$1");
-						
-						this.textEditorInsertText("[youtube]" + url + "[/youtube]");
-					}
-				} }
+				youtube: { txtExec: function(caller) {
+					var editor = this;
+
+					$.sceditor.command.get('youtube')._dropDown(
+						editor,
+						caller,
+						function(id) {
+							editor.insertText("[youtube]" + id + "[/youtube]");
+						}
+					);
+				} },
+				rtl: { txtExec: ["[rtl]", "[/rtl]"] },
+				ltr: { txtExec: ["[ltr]", "[/ltr]"] }
 			};
 
 			return $.extend(true, {}, merge, $.sceditor.commands);
 		};
-		
+
 		/**
 		 * Populates tagsToBbcodes and stylesToBbcodes to enable faster lookups
-		 * 
+		 *
 		 * @private
 		 */
 		buildBbcodeCache = function() {
@@ -262,59 +221,80 @@
 					});
 			});
 		};
-		
+
 		getStyle = function(element, property) {
 			var	name = $.camelCase(property),
-				$elm;
+				$elm, ret, dir;
 
 			// add exception for align
 			if("text-align" === property)
 			{
 				$elm = $(element);
-				
+
 				if($elm.parent().css(property) !== $elm.css(property) &&
 					$elm.css('display') === "block" && !$elm.is('hr') && !$elm.is('th'))
-					return $elm.css(property);
+					ret = $elm.css(property);
+
+				// IE changes text-align to the same as direction so skip unless overried by user
+				dir = element.style.direction;
+				if(dir && ((/right/i.test(ret) && dir === 'rtl') || (/left/i.test(ret) && dir === 'ltr')))
+					return null;
+
+				return ret;
 			}
-			
+
 			if(element.style)
 				return element.style[name];
-			
+
 			return null;
 		};
 
+		isEmpty = function(element) {
+			var	childNodes = element.childNodes,
+				i = childNodes.length;
+
+			if(element.nodeValue)
+				return false;
+
+			if(childNodes.length === 0 || (childNodes.length === 1 && (/br/i.test(childNodes[0].nodeName) || isEmpty(childNodes[0]))))
+				return true;
+
+			while(i--)
+				if(!isEmpty(childNodes[i]))
+					return false;
+
+			return true;
+		};
+
 		/**
 		 * Checks if any bbcode styles match the elements styles
-		 * 
+		 *
 		 * @private
 		 * @return string Content with any matching bbcode tags wrapped around it.
+		 * @Private
 		 */
 		handleStyles = function(element, content, blockLevel) {
-			var	elementPropVal,
-				tag = element[0].nodeName.toLowerCase();
+			var	elementPropVal;
 
 			// convert blockLevel to boolean
 			blockLevel = !!blockLevel;
-			
+
 			if(!stylesToBbcodes[blockLevel])
 				return content;
-			
+
 			$.each(stylesToBbcodes[blockLevel], function(property, bbcodes) {
 				elementPropVal = getStyle(element[0], property);
-				if(elementPropVal == null || elementPropVal === "")
-					return;
 
 				// if the parent has the same style use that instead of this one
 				// so you dont end up with [i]parent[i]child[/i][/i]
-				if(getStyle(element.parent()[0], property) === elementPropVal)
+				if(!elementPropVal || getStyle(element.parent()[0], property) === elementPropVal)
 					return;
 
 				$.each(bbcodes, function(bbcode, values) {
-					if((element[0].childNodes.length === 0 || element[0].childNodes[0].nodeName.toLowerCase() === "br") &&
-						!base.bbcodes[bbcode].allowsEmpty)
+					if(!/\S|\u00A0/.test(content) && !base.bbcodes[bbcode].allowsEmpty && isEmpty(element[0]))
 						return;
-					
-					if(values === null || $.inArray(elementPropVal.toString(), values) > -1) {
+
+					if(!values || $.inArray(elementPropVal.toString(), values) > -1) {
 						if($.isFunction(base.bbcodes[bbcode].format))
 							content = base.bbcodes[bbcode].format.call(base, element, content);
 						else
@@ -328,41 +308,37 @@
 
 		/**
 		 * Handles a HTML tag and finds any matching bbcodes
-		 * 
+		 *
 		 * @private
 		 * @param	jQuery element	element		The element to convert
 		 * @param	string			content		The Tags text content
 		 * @param	bool			blockLevel	If to convert block level tags
 		 * @return	string	Content with any matching bbcode tags wrapped around it.
+		 * @Private
 		 */
 		handleTags = function(element, content, blockLevel) {
 			var tag = element[0].nodeName.toLowerCase();
-			
+
 			// convert blockLevel to boolean
 			blockLevel = !!blockLevel;
 
 			if(tagsToBbcodes[tag] && tagsToBbcodes[tag][blockLevel]) {
 				// loop all bbcodes for this tag
 				$.each(tagsToBbcodes[tag][blockLevel], function(bbcode, bbcodeAttribs) {
-					if(!base.bbcodes[bbcode].allowsEmpty &&
-						(element[0].childNodes.length === 0 || (element[0].childNodes[0].nodeName.toLowerCase() === "br" && element[0].childNodes.length === 1))						)
+					if(!/\S|\u00A0/.test(content) && !base.bbcodes[bbcode].allowsEmpty && isEmpty(element[0]))
 						return;
-					
+
 					// if the bbcode requires any attributes then check this has
 					// all needed
-					if(bbcodeAttribs !== null) {
+					if(bbcodeAttribs) {
 						var runBbcode = false;
 
 						// loop all the bbcode attribs
 						$.each(bbcodeAttribs, function(attrib, values)
 						{
-							// check if has the bbcodes attrib
-							if(element.attr(attrib) == null)
-								return;
-
 							// if the element has the bbcodes attribute and the bbcode attribute
 							// has values check one of the values matches
-							if(values !== null && $.inArray(element.attr(attrib), values) < 0)
+							if(!element.attr(attrib) || (values && $.inArray(element.attr(attrib), values) < 0))
 								return;
 
 							// break this loop as we have matched this bbcode
@@ -380,21 +356,17 @@
 						content = formatString(base.bbcodes[bbcode].format, content);
 				});
 			}
-			
+
 			// add newline after paragraph elements p and div (WebKit uses divs) and br tags
 			if(blockLevel && /^(br|div|p)$/.test(tag))
 			{
-				var parentChildren = element[0].parentNode.childNodes;
-
-				// if it's a <p><br /></p> the paragraph will put the newline so skip the br
-				if(!("br" === tag && parentChildren.length === 1) &&
-					!("br" === tag && parentChildren[parentChildren.length-1] === element[0])) {
+				// Only treat divs/p as a newline if their last child was not a new line.
+				if(!(/^(div|p)$/i.test(tag) && element[0].lastChild && element[0].lastChild.nodeName.toLowerCase() === "br"))
 					content += "\n";
-				}
 
 				// needed for browsers that enter textnode then when return is pressed put the rest in a div, i.e.:
 				// text<div>line 2</div>
-				if("br" !== tag && !$.sceditor.dom.isInline(element.parent()[0]) && element[0].previousSibling &&
+				if("br" !== tag && !$.sceditor.dom.isInline(element[0].parentNode) && element[0].previousSibling &&
 					element[0].previousSibling.nodeType === 3) {
 					content = "\n" + content;
 				}
@@ -408,13 +380,14 @@
 		 * {0}, {1}, {2}, ect. with the params provided
 		 * @private
 		 * @return string
+		 * @Private
 		 */
 		formatString = function() {
 			var args = arguments;
 			return args[0].replace(/\{(\d+)\}/g, function(str, p1) {
-				return typeof args[p1-0+1] !== "undefined"? 
-						args[p1-0+1] :
-						'{' + p1 + '}';
+				return typeof args[p1-0+1] !== "undefined" ?
+					args[p1-0+1] :
+					'{' + p1 + '}';
 			});
 		};
 
@@ -422,31 +395,34 @@
 		 * Removes any leading or trailing quotes ('")
 		 *
 		 * @return string
+		 * @memberOf jQuery.sceditorBBCodePlugin.prototype
 		 */
 		base.stripQuotes = function(str) {
-			return str.replace(/^["']+/, "").replace(/["']+$/, "");
+			return str.replace(/^(["'])(.*?)\1$/, "$2");
 		};
 
 		/**
 		 * Converts HTML to BBCode
 		 * @param string	html	Html string, this function ignores this, it works off domBody
 		 * @param HtmlElement	domBody	Editors dom body object to convert
-		 * @return string BBCode which has been converted from HTML 
+		 * @return string BBCode which has been converted from HTML
+		 * @memberOf jQuery.sceditorBBCodePlugin.prototype
 		 */
 		base.getHtmlHandler = function(html, domBody) {
 			$.sceditor.dom.removeWhiteSpace(domBody[0]);
-			
+
 			return $.trim(base.elementToBbcode(domBody));
 		};
 
 		/**
 		 * Converts a HTML dom element to BBCode starting from
 		 * the innermost element and working backwards
-		 * 
+		 *
 		 * @private
 		 * @param HtmlElement	element		The element to convert to BBCode
 		 * @param array			vChildren	Valid child tags allowed
 		 * @return string BBCode
+		 * @memberOf jQuery.sceditorBBCodePlugin.prototype
 		 */
 		base.elementToBbcode = function($element) {
 			return (function toBBCode(node, vChildren) {
@@ -458,7 +434,7 @@
 						tag		= node.nodeName.toLowerCase(),
 						vChild		= validChildren[tag],
 						isValidChild	= true;
-					
+
 					if(typeof vChildren === 'object')
 					{
 						isValidChild = $.inArray(tag, vChildren) > -1;
@@ -469,7 +445,7 @@
 						if(!isValidChild)
 							vChild = vChildren;
 					}
-					
+
 					// 3 is text element
 					if(node.nodeType !== 3)
 					{
@@ -480,7 +456,7 @@
 						// don't loop inside iframes
 						if(tag !== 'iframe')
 							curTag = toBBCode(node, vChild);
-						
+
 						if(isValidChild)
 						{
 							// code tags should skip most styles
@@ -489,11 +465,11 @@
 								// handle inline bbcodes
 								curTag = handleStyles($node, curTag);
 								curTag = handleTags($node, curTag);
-								
+
 								// handle blocklevel bbcodes
 								curTag = handleStyles($node, curTag, true);
 							}
-							
+
 							ret += handleTags($node, curTag, true);
 						}
 						else
@@ -509,39 +485,44 @@
 					else if(!node.wholeText)
 						ret += node.nodeValue;
 				}, false, true);
-				
+
 				return ret;
 			}($element.get(0)));
 		};
 
 		/**
 		 * Converts BBCode to HTML
-		 * 
+		 *
 		 * @param {String} text
-		 * @param {Bool} isPaste
+		 * @param {Bool} isFragment
 		 * @return {String} HTML
+		 * @memberOf jQuery.sceditorBBCodePlugin.prototype
 		 */
-		base.getTextHandler = function(text, isPaste) {
+		base.getTextHandler = function(text, isFragment) {
+
 			var	oldText, replaceBBCodeFunc,
-				bbcodeRegex = /\[([^\[\s=]*?)(?:([\s=][^\[]*?))?\]((?:[\s\S(?!=\[\\\1)](?!\[\1))*?)\[\/(\1)\]/g,
+// Previous				bbcodeRegex = /\[([^\[\s=]*?)(?:([\s=][^\[]*?))?\]((?:[\s\S(?!=\[\\\1)](?!\[\1))*?)\[\/(\1)\]/g,
+				bbcodeRegex = /\[([^\[\s=]+)(?:([\s=][^\[\]]+))?\]((?:[\s\S](?!\[\1))*?)\[\/(\1)\]/g,
 				atribsRegex = /(\S+)=((?:(?:(["'])(?:\\\3|[^\3])*?\3))|(?:[^'"\s]+))/g;
 
 			replaceBBCodeFunc = function(str, bbcode, attrs, content)
 			{
 				var	attrsMap = {},
 					matches;
-					
+
+				bbcode = bbcode.toLowerCase();
+
 				if(attrs)
 				{
 					attrs = $.trim(attrs);
-					
+
 					// if only one attribute then remove the = from the start and strip any quotes
 					if((attrs.charAt(0) === "=" && (attrs.split("=").length - 1) <= 1) || bbcode === 'url')
-						attrsMap.defaultAttr = base.stripQuotes(attrs.substr(1));
+						attrsMap.defaultattr = base.stripQuotes(attrs.substr(1));
 					else
 					{
 						if(attrs.charAt(0) === "=")
-							attrs = "defaultAttr" + attrs;
+							attrs = "defaultattr" + attrs;
 
 						if (typeof base.bbcodes[bbcode].attrs == 'function')
 						{
@@ -586,7 +567,7 @@
 					.replace(/</g, "&lt;")
 					.replace(/>/g, "&gt;")
 					.replace(/\r/g, "")
-					.replace(/(\[\/?(?:left|center|right|justify)\])\n/g, "$1")
+					.replace(/(\[\/?(?:left|center|right|justify|align|rtl|ltr)\])\n/g, "$1")
 					.replace(/\n/g, "<br />");
 
 			while(text !== oldText)
@@ -597,20 +578,22 @@
 
 			// As hr is the only bbcode not to have a start and end tag it's
 			// just being replace here instead of adding support for it above.
-			text = text.replace(/\[hr\]/gi, "<hr>");
-			
+			text = text.replace(/\[hr\]/gi, "<hr>")
+					.replace(/\[\*\]/gi, "<li>");
+
 			// replace multi-spaces which are not inside tags with a non-breaking space
 			// to preserve them. Otherwise they will just be converted to 1!
 			text = text.replace(/ {2}(?=([^<\>]*?<|[^<\>]*?$))/g, " &nbsp;");
-			
-			return wrapInDivs(text, isPaste);
+
+			return wrapInDivs(text, isFragment);
 		};
-		
+
 		/**
 		 * Wraps divs around inline HTML. Needed for IE
-		 * 
+		 *
 		 * @param string html
 		 * @return string HTML
+		 * @private
 		 */
 		wrapInDivs = function(html, excludeFirstLast)
 		{
@@ -619,10 +602,10 @@
 				outputDiv	= d.createElement('div'),
 				tmpDiv		= d.createElement('div'),
 				div, node, next, nodeName;
-			
+
 			$(tmpDiv).hide().appendTo(d.body);
 			tmpDiv.innerHTML = html;
-			
+
 			node = tmpDiv.firstChild;
 			while(node)
 			{
@@ -635,33 +618,45 @@
 					{
 						div = d.createElement('div');
 						div.appendChild(inlineFrag);
-						
+
 						// Putting BR in a div in IE9 causes it to do a double line break,
 						// as much as I hate browser UA sniffing, to do feature detection would
 						// be more code than it's worth for this specific bug.
-						if(nodeName === "br" && (!$.sceditor.ie || $.sceditor.ie < 9))
+						if(nodeName === "br" && !$.sceditor.ie)
 							div.appendChild(d.createElement('br'));
-						
+
+						// If it's an empty DIV and in compatibility mode is below IE8 then
+						// we must add a non-breaking space to the div otherwise the div
+						// will be collapsed. Adding a BR works but when you press enter
+						// to make a newline it suddenly gose back to the normal IE div
+						// behaviour and creates two lines, one for the newline and one
+						// for the BR. I'm sure there must be a better fix but I've yet to
+						// find one.
+						// Cannot do zoom: 1; or set a height on the div to fix it as that
+						// causes resize handles to be added to the div when it's clicked on/
+						if(!div.childNodes.length && (d.documentMode && d.documentMode < 8 || $.sceditor.ie < 8))
+							div.appendChild(d.createTextNode('\u00a0'));
+
 						outputDiv.appendChild(div);
 						inlineFrag = d.createDocumentFragment();
 					}
-					
+
 					if(nodeName !== "br")
 						outputDiv.appendChild(node);
 				}
 				else
 					inlineFrag.appendChild(node);
-					
+
 				node = next;
 			}
-			
+
 			if(inlineFrag.childNodes.length > 0)
 			{
 				div = d.createElement('div');
 				div.appendChild(inlineFrag);
 				outputDiv.appendChild(div);
 			}
-			
+
 			// needed for paste, the first shouldn't be wrapped in a div
 			if(excludeFirstLast)
 			{
@@ -670,13 +665,13 @@
 				{
 					while((next = node.firstChild))
 						outputDiv.insertBefore(next, node);
-					
+
 					if($.sceditor.ie >= 9)
 						outputDiv.insertBefore(d.createElement('br'), node);
-					
+
 					outputDiv.removeChild(node);
 				}
-				
+
 				node = outputDiv.lastChild;
 				if(node && node.nodeName.toLowerCase() === "div")
 				{
@@ -685,7 +680,7 @@
 
 					if($.sceditor.ie >= 9)
 						outputDiv.insertBefore(d.createElement('br'), node);
-					
+
 					outputDiv.removeChild(node);
 				}
 			}
@@ -696,7 +691,7 @@
 
 		init();
 	};
-	
+
 	$.sceditorBBCodePlugin.bbcodes = {
 		// START_COMMAND: Bold
 		b: {
@@ -791,7 +786,7 @@
 				return '[font=' + this.stripQuotes(element.css('font-family')) + ']' + content + '[/font]';
 			},
 			html: function(element, attrs, content) {
-				return '<font face="' + attrs.defaultAttr + '">' + content + '</font>';
+				return '<font face="' + attrs.defaultattr + '">' + content + '</font>';
 			}
 		},
 		// END_COMMAND
@@ -810,8 +805,10 @@
 				var	fontSize = element.css('fontSize'),
 					size     = 1;
 
+				if(element.attr('size'))
+					size = element.attr('size');
 				// Most browsers return px value but IE returns 1-7
-				if(fontSize.indexOf("px") > -1) {
+				else if(fontSize.indexOf("px") > -1) {
 					// convert size to an int
 					fontSize = fontSize.replace("px", "") - 0;
 
@@ -834,7 +831,7 @@
 				return '[size=' + size + ']' + content + '[/size]';
 			},
 			html: function(element, attrs, content) {
-				return '<font size="' + attrs.defaultAttr + '">' + content + '</font>';
+				return '<font size="' + attrs.defaultattr + '">' + content + '</font>';
 			}
 		},
 		// END_COMMAND
@@ -857,38 +854,38 @@
 				 */
 				var rgbToHex = function(rgbStr) {
 					var m;
-		
+
 					function toHex(n) {
 						n = parseInt(n,10);
 						if(isNaN(n))
 							return "00";
 						n = Math.max(0,Math.min(n,255)).toString(16);
-		
+
 						return n.length<2 ? '0'+n : n;
 					}
-		
+
 					// rgb(n,n,n);
 					if((m = rgbStr.match(/rgb\((\d+),\s*?(\d+),\s*?(\d+)\)/i)))
 						return '#' + toHex(m[1]) + toHex(m[2]-0) + toHex(m[3]-0);
-		
+
 					// expand shorthand
 					if((m = rgbStr.match(/#([0-f])([0-f])([0-f])\s*?$/i)))
 						return '#' + m[1] + m[1] + m[2] + m[2] + m[3] + m[3];
-					
+
 					return rgbStr;
 				};
-		
+
 				var color = element.css('color');
 
 				if(element[0].nodeName.toLowerCase() === "font" && element.attr('color'))
 					color = element.attr('color');
-				
+
 				color = rgbToHex(color);
 
 				return '[color=' + color + ']' + content + '[/color]';
 			},
 			html: function(element, attrs, content) {
-				return '<font color="' + attrs.defaultAttr + '">' + content + '</font>';
+				return '<font color="' + attrs.defaultattr + '">' + content + '</font>';
 			}
 		},
 		black: {
@@ -1024,6 +1021,11 @@
 				}
 			},
 			format: function(element, content) {
+				var	attribs = '',
+					style = function(name) {
+						return element.style ? element.style[name] : null;
+					};
+
 				// check if this is an emoticon image
 				if(typeof element.attr('data-sceditor-emoticon') !== "undefined")
 					return content;
@@ -1038,7 +1040,7 @@
 				return ['alt', 'width', 'height'];
 			},
 			html: function(element, attrs, content) {
-				var attribs = "";
+				var attribs = "", parts;
 
 				// handle [img width=340 height=240]url[/img]
 				if(typeof attrs.width !== "undefined")
@@ -1099,10 +1101,10 @@
 		// START_COMMAND: E-mail
 		email: {
 			html: function(element, attrs, content) {
-				if(typeof attrs.defaultAttr === "undefined")
-					attrs.defaultAttr = content;
+				if(typeof attrs.defaultattr === "undefined")
+					attrs.defaultattr = content;
 
-				return '<a href="mailto:' + attrs.defaultAttr + '">' + content + '</a>';
+				return '<a href="mailto:' + attrs.defaultattr + '">' + content + '</a>';
 			}
 		},
 		// END_COMMAND
@@ -1303,6 +1305,27 @@
 		},
 		// END_COMMAND
 
+
+		// START_COMMAND: Rtl
+		rtl: {
+			styles: {
+				"direction": ["rtl"]
+			},
+			format: "[rtl]{0}[/rtl]",
+			html: '<div style="direction: rtl">{0}</div>'
+		},
+		// END_COMMAND
+
+		// START_COMMAND: Ltr
+		ltr: {
+			styles: {
+				"direction": ["ltr"]
+			},
+			format: "[ltr]{0}[/ltr]",
+			html: '<div style="direction: ltr">{0}</div>'
+		},
+		// END_COMMAND
+
 		abbr: {
 			tags: {
 				abbr: {
@@ -1381,51 +1404,104 @@
 		// Needed for IE.
 		ignore: {}
 	};
-	
+
+	/**
+	 * Static BBCode helper class
+	 * @class command
+	 * @name jQuery.sceditorBBCodePlugin.bbcode
+	 */
+	$.sceditorBBCodePlugin.bbcode =
+	/** @lends jQuery.sceditorBBCodePlugin.bbcode */
+	{
+		/**
+		 * Gets a BBCode
+		 *
+		 * @param {String} name
+		 * @return {Object|null}
+		 * @since v1.3.5
+		 */
+		get: function(name) {
+			return $.sceditorBBCodePlugin.bbcodes[name] || null;
+		},
+
+		/**
+		 * <p>Adds a BBCode to the parser or updates an exisiting
+		 * BBCode if a BBCode with the specified name already exists.</p>
+		 *
+		 * @param {String} name
+		 * @param {Object} bbcode
+		 * @return {this|false} Returns false if name or bbcode is false
+		 * @since v1.3.5
+		 */
+		set: function(name, bbcode) {
+			if(!name || !bbcode)
+				return false;
+
+			// merge any existing command properties
+			bbcode = $.extend($.sceditorBBCodePlugin.bbcodes[name] || {}, bbcode);
+
+			bbcode.remove = function() { $.sceditorBBCodePlugin.bbcode.remove(name); };
+
+			$.sceditorBBCodePlugin.bbcodes[name] = bbcode;
+			return this;
+		},
+
+		/**
+		 * Removes a BBCode
+		 *
+		 * @param {String} name
+		 * @return {this}
+		 * @since v1.3.5
+		 */
+		remove: function(name) {
+			if($.sceditorBBCodePlugin.bbcodes[name])
+				delete $.sceditorBBCodePlugin.bbcodes[name];
+
+			return this;
+		}
+	};
+
 	/**
 	 * Checks if a command with the specified name exists
-	 * 
+	 *
 	 * @param string name
 	 * @return bool
+	 * @deprecated Since v1.3.5
+	 * @memberOf jQuery.sceditorBBCodePlugin
 	 */
 	$.sceditorBBCodePlugin.commandExists = function(name) {
-		return typeof $.sceditorBBCodePlugin.bbcodes[name] !== "undefined";
+		return !!$.sceditorBBCodePlugin.bbcode.get(name);
 	};
-	
+
 	/**
 	 * Adds/updates a BBCode.
-	 * 
+	 *
 	 * @param String		name		The BBCode name
 	 * @param Object		tags		Any html tags this bbcode applies to, i.e. strong for [b]
 	 * @param Object		styles		Any style properties this applies to, i.e. font-weight for [b]
 	 * @param String|Function	format		Function or string to convert the element into BBCode
 	 * @param String|Function	html		String or function to format the BBCode back into HTML.
-	 * @param BOOL			allowsEmpty	If this BBCodes is allowed to be empty, e.g. [b][/b]
+	 * @param bool			allowsEmpty	If this BBCodes is allowed to be empty, e.g. [b][/b]
 	 * @return Bool
+	 * @deprecated Since v1.3.5
+	 * @memberOf jQuery.sceditorBBCodePlugin
 	 */
-	$.sceditorBBCodePlugin.setCommand = function(name, tags, styles, format, html, allowsEmpty) {
-		if(!name || !format || !html)
-			return false;
-		
-		if(!$.sceditorBBCodePlugin.commandExists(name))
-			$.sceditorBBCodePlugin.bbcodes[name] = {};
-
-		$.sceditorBBCodePlugin.bbcodes[name].format = format;
-		$.sceditorBBCodePlugin.bbcodes[name].html = html;
-		
-		if(tags)
-			$.sceditorBBCodePlugin.bbcodes[name].tags = tags;
-		
-		if(styles)
-			$.sceditorBBCodePlugin.bbcodes[name].styles = styles;
-			
-		if(allowsEmpty)
-			$.sceditorBBCodePlugin.bbcodes[name].allowsEmpty = allowsEmpty;
-		
-		return true;
+	$.sceditorBBCodePlugin.setCommand = function(name, tags, styles, format, html, allowsEmpty, isBlock) {
+		return $.sceditorBBCodePlugin.bbcode.set(name,
+		{
+			tags: tags || {},
+			styles: styles || {},
+			allowsEmpty: allowsEmpty,
+			isBlock: isBlock,
+			format: format,
+			html: html
+		});
 	};
 
 	$.fn.sceditorBBCodePlugin = function(options) {
+		if((!options || !options.runWithoutWysiwygSupport) && !$.sceditor.isWysiwygSupported())
+			return;
+
 		return this.each(function() {
 			(new $.sceditorBBCodePlugin(this, options));
 		});

File diff suppressed because it is too large
+ 629 - 217
Themes/default/scripts/jquery.sceditor.js


Some files were not shown because too many files changed in this diff