changeset 35:cd02cd04bc9d

fix [img]
author Franklin Schmidt <fschmidt@gmail.com>
date Mon, 15 Aug 2022 22:57:06 -0600
parents 20d1f23225fe
children 21090996a131
files src/changes.txt src/formats/bbcode.js
diffstat 2 files changed, 52 insertions(+), 122 deletions(-) [+]
line wrap: on
line diff
--- a/src/changes.txt	Mon Aug 15 21:35:44 2022 -0600
+++ b/src/changes.txt	Mon Aug 15 22:57:06 2022 -0600
@@ -1,6 +1,8 @@
 changes, most recent at top
 
 
+Removed complex parameterized tags: [tag value1=”xxx” value2=”yyy”]something[/tag]  This is over-engineering and shouldn't be in BBCode.
+
 Removed sceditor.command with its get(), set(), and remove().  It is better to work with sceditor.commands directly.  I also added an options.onCreate callback which lets one work with the final editor.commands .
 
 Remove DOMPurify.  This was a huge amount of incomprehensible code that adds little value.  XSS should basically be handled on the server side, and if one is using bbcode then it isn't an issue anyway.
--- a/src/formats/bbcode.js	Mon Aug 15 21:35:44 2022 -0600
+++ b/src/formats/bbcode.js	Mon Aug 15 22:57:06 2022 -0600
@@ -160,19 +160,15 @@
 					caller,
 					selected,
 					function (url, width, height) {
-						var attrs  = '';
-
-						if (width) {
-							attrs += ' width=' + width;
+						if( width || height ) {
+							editor.insertText(
+								'[img=' + width + 'x' + height + ']' + url + '[/img]'
+							);
+						} else {
+							editor.insertText(
+								'[img]' + url + '[/img]'
+							);
 						}
-
-						if (height) {
-							attrs += ' height=' + height;
-						}
-
-						editor.insertText(
-							'[img' + attrs + ']' + url + '[/img]'
-						);
 					}
 				);
 			}
@@ -342,7 +338,7 @@
 				return '[font=' + _stripQuotes(font) + ']' +
 					content + '[/font]';
 			},
-			html: '<font face="{defaultattr}">{0}</font>'
+			html: '<font face="{attrib}">{0}</font>'
 		},
 		// END_COMMAND
 
@@ -393,7 +389,7 @@
 
 				return '[size=' + size + ']' + content + '[/size]';
 			},
-			html: '<font size="{defaultattr}">{!0}</font>'
+			html: '<font size="{attrib}">{!0}</font>'
 		},
 		// END_COMMAND
 
@@ -418,9 +414,9 @@
 				return '[color=' + _normaliseColour(color) + ']' +
 					content + '[/color]';
 			},
-			html: function (token, attrs, content) {
+			html: function (token, attrib, content) {
 				return '<font color="' +
-					escapeEntities(_normaliseColour(attrs.defaultattr), true) +
+					escapeEntities(_normaliseColour(attrib), true) +
 					'">' + content + '</font>';
 			}
 		},
@@ -521,7 +517,7 @@
 			format: function (element, content) {
 				return attr(element, EMOTICON_DATA_ATTR) + content;
 			},
-			html: function (token, attrs, content, editor) {
+			html: function (token, attrib, content, editor) {
 				return editor.allEmoticons[content] || token.val + content + token.closing.val;
 			}
 		},
@@ -569,33 +565,29 @@
 				if ((element.complete && (width || height)) ||
 					(width && height)) {
 
-					attribs = '=' + dom.width(element) + 'x' +
-						dom.height(element);
+					attribs = '=' + width + 'x' +
+						height;
 				}
 
 				return '[img' + attribs + ']' + attr(element, 'src') + '[/img]';
 			},
-			html: function (token, attrs, content) {
+			html: function (token, attrib, content) {
 				var	undef, width, height, match,
 					attribs = '';
 
-				// handle [img width=340 height=240]url[/img]
-				width  = attrs.width;
-				height = attrs.height;
-
 				// handle [img=340x240]url[/img]
-				if (attrs.defaultattr) {
-					match = attrs.defaultattr.split(/x/i);
+				if (attrib) {
+					match = attrib.split(/x/i);
 
 					width  = match[0];
-					height = (match.length === 2 ? match[1] : match[0]);
+					height = match[1];
 				}
 
-				if (width !== undef) {
+				if (width) {
 					attribs += ' width="' + escapeEntities(width, true) + '"';
 				}
 
-				if (height !== undef) {
+				if (height) {
 					attribs += ' height="' + escapeEntities(height, true) + '"';
 				}
 
@@ -630,11 +622,11 @@
 					return '[url=' + url + ']' + content + '[/url]';
 				}
 			},
-			html: function (token, attrs, content) {
-				attrs.defaultattr =
-					escapeEntities(attrs.defaultattr, true) || content;
+			html: function (token, attrib, content) {
+				attrib =
+					escapeEntities(attrib, true) || content;
 
-				return '<a href="' + escapeUriScheme(attrs.defaultattr) + '">' +
+				return '<a href="' + escapeUriScheme(attrib) + '">' +
 					content + '</a>';
 			}
 		},
@@ -643,9 +635,9 @@
 		// START_COMMAND: E-mail
 		email: {
 			quoteType: QuoteType.never,
-			html: function (token, attrs, content) {
+			html: function (token, attrib, content) {
 				return '<a href="mailto:' +
-					(escapeEntities(attrs.defaultattr, true) || content) +
+					(escapeEntities(attrib, true) || content) +
 					'">' + content + '</a>';
 			}
 		},
@@ -690,9 +682,9 @@
 
 				return '[quote' + author + ']' + content + '[/quote]';
 			},
-			html: function (token, attrs, content) {
-				if (attrs.defaultattr) {
-					content = '<cite>' + escapeEntities(attrs.defaultattr) +
+			html: function (token, attrib, content) {
+				if (attrib) {
+					content = '<cite>' + escapeEntities(attrib) +
 						'</cite>' + content;
 				}
 
@@ -961,7 +953,7 @@
 	 * @property {string} type
 	 * @property {string} name
 	 * @property {string} val
-	 * @property {Object.<string, string>} attrs
+	 * @property {string} attrib
 	 * @property {array} children
 	 * @property {TokenizeToken} closing
 	 */
@@ -973,7 +965,7 @@
 	 *                       should be one of tokenType
 	 * @param  {string} name The name of this token
 	 * @param  {string} val The originally matched string
-	 * @param  {array} attrs Any attributes. Only set on
+	 * @param  {string} attrib Any attributes. Only set on
 	 *                       TOKEN_TYPE_OPEN tokens
 	 * @param  {array} children Any children of this token
 	 * @param  {TokenizeToken} closing This tokens closing tag.
@@ -983,13 +975,13 @@
 	 * @memberOf BBCodeParser.prototype
 	 */
 	// eslint-disable-next-line max-params
-	function TokenizeToken(type, name, val, attrs, children, closing) {
+	function TokenizeToken(type, name, val, attrib, children, closing) {
 		var base      = this;
 
 		base.type     = type;
 		base.name     = name;
 		base.val      = val;
-		base.attrs    = attrs || {};
+		base.attrib   = attrib;
 		base.children = children || [];
 		base.closing  = closing || null;
 	};
@@ -1008,7 +1000,7 @@
 				base.type,
 				base.name,
 				base.val,
-				extend({}, base.attrs),
+				base.attrib,
 				[],
 				base.closing ? base.closing.clone() : null
 			);
@@ -1133,8 +1125,8 @@
 		 * @private
 		 */
 		function tokenizeTag(type, val) {
-			var matches, attrs, name,
-				openRegex  = /\[([^\]\s=]+)(?:([^\]]+))?\]/,
+			var matches, attrib, name,
+				openRegex  = /\[([^\]\s=]+)(?:=([^\]]+))?\]/,
 				closeRegex = /\[\/([^\[\]]+)\]/;
 
 			// Extract the name and attributes from opening tags and
@@ -1143,7 +1135,7 @@
 				name = lower(matches[1]);
 
 				if (matches[2] && (matches[2] = matches[2].trim())) {
-					attrs = tokenizeAttrs(matches[2]);
+					attrib = _stripQuotes(matches[2]);
 				}
 			}
 
@@ -1165,60 +1157,7 @@
 				name = '#';
 			}
 
-			return new TokenizeToken(type, name, val, attrs);
-		}
-
-		/**
-		 * Extracts the individual attributes from a string containing
-		 * all the attributes.
-		 *
-		 * @param {string} attrs
-		 * @return {Object} Assoc array of attributes
-		 * @private
-		 */
-		function tokenizeAttrs(attrs) {
-			var	matches,
-				/*
-				([^\s=]+)				Anything that's not a space or equals
-				=						Equals sign =
-				(?:
-					(?:
-						(["'])					The opening quote
-						(
-							(?:\\\2|[^\2])*?	Anything that isn't the
-												unescaped opening quote
-						)
-						\2						The opening quote again which
-												will close the string
-					)
-						|				If not a quoted string then match
-					(
-						(?:.(?!\s\S+=))*.?		Anything that isn't part of
-												[space][non-space][=] which
-												would be a new attribute
-					)
-				)
-				*/
-				attrRegex = /([^\s=]+)=(?:(?:(["'])((?:\\\2|[^\2])*?)\2)|((?:.(?!\s\S+=))*.))/g,
-				ret       = {};
-
-			// if only one attribute then remove the = from the start and
-			// strip any quotes
-			if (attrs.charAt(0) === '=' && attrs.indexOf('=', 1) < 0) {
-				ret.defaultattr = _stripQuotes(attrs.substr(1));
-			} else {
-				if (attrs.charAt(0) === '=') {
-					attrs = 'defaultattr' + attrs;
-				}
-
-				// No need to strip quotes here, the regex will do that.
-				while ((matches = attrRegex.exec(attrs))) {
-					ret[lower(matches[1])] =
-						_stripQuotes(matches[3]) || matches[4];
-				}
-			}
-
-			return ret;
+			return new TokenizeToken(type, name, val, attrib);
 		}
 
 		/**
@@ -1841,15 +1780,15 @@
 						}
 
 						if (!isFunction(bbcode.html)) {
-							token.attrs['0'] = content;
+							token['0'] = content;
 							html = formatBBCodeString(
 								bbcode.html,
-								token.attrs
+								token
 							);
 						} else {
 							html = bbcode.html(
 								token,
-								token.attrs,
+								token.attrib,
 								content,
 								editor
 							);
@@ -1983,23 +1922,12 @@
 
 					// Convert the tag and it's attributes to BBCode
 					ret += '[' + token.name;
-					if (token.attrs) {
-						if (token.attrs.defaultattr) {
-							ret += '=' + quote(
-								token.attrs.defaultattr,
-								quoteType,
-								'defaultattr'
-							);
-
-							delete token.attrs.defaultattr;
-						}
-
-						for (attr in token.attrs) {
-							if (token.attrs.hasOwnProperty(attr)) {
-								ret += ' ' + attr + '=' +
-									quote(token.attrs[attr], quoteType, attr);
-							}
-						}
+					if (token.attrib) {
+						ret += '=' + quote(
+							token.attrib,
+							quoteType
+						);
+						delete token.attrib;
 					}
 					ret += ']';
 
@@ -2047,11 +1975,11 @@
 		 * @return {string}
 		 * @private
 		 */
-		function quote(str, quoteType, name) {
+		function quote(str, quoteType) {
 			var	needsQuotes = /\s|=/.test(str);
 
 			if (isFunction(quoteType)) {
-				return quoteType(str, name);
+				return quoteType(str);
 			}
 
 			if (quoteType === QuoteType.never ||