comparison src/formats/bbcode.js @ 35:cd02cd04bc9d

fix [img]
author Franklin Schmidt <fschmidt@gmail.com>
date Mon, 15 Aug 2022 22:57:06 -0600
parents 20d1f23225fe
children 21090996a131
comparison
equal deleted inserted replaced
34:20d1f23225fe 35:cd02cd04bc9d
158 getEditorCommand('image')._dropDown( 158 getEditorCommand('image')._dropDown(
159 editor, 159 editor,
160 caller, 160 caller,
161 selected, 161 selected,
162 function (url, width, height) { 162 function (url, width, height) {
163 var attrs = ''; 163 if( width || height ) {
164 164 editor.insertText(
165 if (width) { 165 '[img=' + width + 'x' + height + ']' + url + '[/img]'
166 attrs += ' width=' + width; 166 );
167 } else {
168 editor.insertText(
169 '[img]' + url + '[/img]'
170 );
167 } 171 }
168
169 if (height) {
170 attrs += ' height=' + height;
171 }
172
173 editor.insertText(
174 '[img' + attrs + ']' + url + '[/img]'
175 );
176 } 172 }
177 ); 173 );
178 } 174 }
179 }, 175 },
180 email: { 176 email: {
340 } 336 }
341 337
342 return '[font=' + _stripQuotes(font) + ']' + 338 return '[font=' + _stripQuotes(font) + ']' +
343 content + '[/font]'; 339 content + '[/font]';
344 }, 340 },
345 html: '<font face="{defaultattr}">{0}</font>' 341 html: '<font face="{attrib}">{0}</font>'
346 }, 342 },
347 // END_COMMAND 343 // END_COMMAND
348 344
349 // START_COMMAND: Size 345 // START_COMMAND: Size
350 size: { 346 size: {
391 size = fontSize; 387 size = fontSize;
392 } 388 }
393 389
394 return '[size=' + size + ']' + content + '[/size]'; 390 return '[size=' + size + ']' + content + '[/size]';
395 }, 391 },
396 html: '<font size="{defaultattr}">{!0}</font>' 392 html: '<font size="{attrib}">{!0}</font>'
397 }, 393 },
398 // END_COMMAND 394 // END_COMMAND
399 395
400 // START_COMMAND: Color 396 // START_COMMAND: Color
401 color: { 397 color: {
416 } 412 }
417 413
418 return '[color=' + _normaliseColour(color) + ']' + 414 return '[color=' + _normaliseColour(color) + ']' +
419 content + '[/color]'; 415 content + '[/color]';
420 }, 416 },
421 html: function (token, attrs, content) { 417 html: function (token, attrib, content) {
422 return '<font color="' + 418 return '<font color="' +
423 escapeEntities(_normaliseColour(attrs.defaultattr), true) + 419 escapeEntities(_normaliseColour(attrib), true) +
424 '">' + content + '</font>'; 420 '">' + content + '</font>';
425 } 421 }
426 }, 422 },
427 // END_COMMAND 423 // END_COMMAND
428 424
519 } 515 }
520 }, 516 },
521 format: function (element, content) { 517 format: function (element, content) {
522 return attr(element, EMOTICON_DATA_ATTR) + content; 518 return attr(element, EMOTICON_DATA_ATTR) + content;
523 }, 519 },
524 html: function (token, attrs, content, editor) { 520 html: function (token, attrib, content, editor) {
525 return editor.allEmoticons[content] || token.val + content + token.closing.val; 521 return editor.allEmoticons[content] || token.val + content + token.closing.val;
526 } 522 }
527 }, 523 },
528 // END_COMMAND 524 // END_COMMAND
529 525
567 563
568 // only add width and height if one is specified 564 // only add width and height if one is specified
569 if ((element.complete && (width || height)) || 565 if ((element.complete && (width || height)) ||
570 (width && height)) { 566 (width && height)) {
571 567
572 attribs = '=' + dom.width(element) + 'x' + 568 attribs = '=' + width + 'x' +
573 dom.height(element); 569 height;
574 } 570 }
575 571
576 return '[img' + attribs + ']' + attr(element, 'src') + '[/img]'; 572 return '[img' + attribs + ']' + attr(element, 'src') + '[/img]';
577 }, 573 },
578 html: function (token, attrs, content) { 574 html: function (token, attrib, content) {
579 var undef, width, height, match, 575 var undef, width, height, match,
580 attribs = ''; 576 attribs = '';
581 577
582 // handle [img width=340 height=240]url[/img]
583 width = attrs.width;
584 height = attrs.height;
585
586 // handle [img=340x240]url[/img] 578 // handle [img=340x240]url[/img]
587 if (attrs.defaultattr) { 579 if (attrib) {
588 match = attrs.defaultattr.split(/x/i); 580 match = attrib.split(/x/i);
589 581
590 width = match[0]; 582 width = match[0];
591 height = (match.length === 2 ? match[1] : match[0]); 583 height = match[1];
592 } 584 }
593 585
594 if (width !== undef) { 586 if (width) {
595 attribs += ' width="' + escapeEntities(width, true) + '"'; 587 attribs += ' width="' + escapeEntities(width, true) + '"';
596 } 588 }
597 589
598 if (height !== undef) { 590 if (height) {
599 attribs += ' height="' + escapeEntities(height, true) + '"'; 591 attribs += ' height="' + escapeEntities(height, true) + '"';
600 } 592 }
601 593
602 return '<img' + attribs + 594 return '<img' + attribs +
603 ' src="' + escapeUriScheme(content) + '" />'; 595 ' src="' + escapeUriScheme(content) + '" />';
628 return '[url]' + content + '[/url]'; 620 return '[url]' + content + '[/url]';
629 } else { 621 } else {
630 return '[url=' + url + ']' + content + '[/url]'; 622 return '[url=' + url + ']' + content + '[/url]';
631 } 623 }
632 }, 624 },
633 html: function (token, attrs, content) { 625 html: function (token, attrib, content) {
634 attrs.defaultattr = 626 attrib =
635 escapeEntities(attrs.defaultattr, true) || content; 627 escapeEntities(attrib, true) || content;
636 628
637 return '<a href="' + escapeUriScheme(attrs.defaultattr) + '">' + 629 return '<a href="' + escapeUriScheme(attrib) + '">' +
638 content + '</a>'; 630 content + '</a>';
639 } 631 }
640 }, 632 },
641 // END_COMMAND 633 // END_COMMAND
642 634
643 // START_COMMAND: E-mail 635 // START_COMMAND: E-mail
644 email: { 636 email: {
645 quoteType: QuoteType.never, 637 quoteType: QuoteType.never,
646 html: function (token, attrs, content) { 638 html: function (token, attrib, content) {
647 return '<a href="mailto:' + 639 return '<a href="mailto:' +
648 (escapeEntities(attrs.defaultattr, true) || content) + 640 (escapeEntities(attrib, true) || content) +
649 '">' + content + '</a>'; 641 '">' + content + '</a>';
650 } 642 }
651 }, 643 },
652 // END_COMMAND 644 // END_COMMAND
653 645
688 } 680 }
689 } 681 }
690 682
691 return '[quote' + author + ']' + content + '[/quote]'; 683 return '[quote' + author + ']' + content + '[/quote]';
692 }, 684 },
693 html: function (token, attrs, content) { 685 html: function (token, attrib, content) {
694 if (attrs.defaultattr) { 686 if (attrib) {
695 content = '<cite>' + escapeEntities(attrs.defaultattr) + 687 content = '<cite>' + escapeEntities(attrib) +
696 '</cite>' + content; 688 '</cite>' + content;
697 } 689 }
698 690
699 return '<blockquote>' + content + '</blockquote>'; 691 return '<blockquote>' + content + '</blockquote>';
700 } 692 }
959 /* 951 /*
960 * @typedef {Object} TokenizeToken 952 * @typedef {Object} TokenizeToken
961 * @property {string} type 953 * @property {string} type
962 * @property {string} name 954 * @property {string} name
963 * @property {string} val 955 * @property {string} val
964 * @property {Object.<string, string>} attrs 956 * @property {string} attrib
965 * @property {array} children 957 * @property {array} children
966 * @property {TokenizeToken} closing 958 * @property {TokenizeToken} closing
967 */ 959 */
968 960
969 /** 961 /**
971 * 963 *
972 * @param {string} type The type of token this is, 964 * @param {string} type The type of token this is,
973 * should be one of tokenType 965 * should be one of tokenType
974 * @param {string} name The name of this token 966 * @param {string} name The name of this token
975 * @param {string} val The originally matched string 967 * @param {string} val The originally matched string
976 * @param {array} attrs Any attributes. Only set on 968 * @param {string} attrib Any attributes. Only set on
977 * TOKEN_TYPE_OPEN tokens 969 * TOKEN_TYPE_OPEN tokens
978 * @param {array} children Any children of this token 970 * @param {array} children Any children of this token
979 * @param {TokenizeToken} closing This tokens closing tag. 971 * @param {TokenizeToken} closing This tokens closing tag.
980 * Only set on TOKEN_TYPE_OPEN tokens 972 * Only set on TOKEN_TYPE_OPEN tokens
981 * @class {TokenizeToken} 973 * @class {TokenizeToken}
982 * @name {TokenizeToken} 974 * @name {TokenizeToken}
983 * @memberOf BBCodeParser.prototype 975 * @memberOf BBCodeParser.prototype
984 */ 976 */
985 // eslint-disable-next-line max-params 977 // eslint-disable-next-line max-params
986 function TokenizeToken(type, name, val, attrs, children, closing) { 978 function TokenizeToken(type, name, val, attrib, children, closing) {
987 var base = this; 979 var base = this;
988 980
989 base.type = type; 981 base.type = type;
990 base.name = name; 982 base.name = name;
991 base.val = val; 983 base.val = val;
992 base.attrs = attrs || {}; 984 base.attrib = attrib;
993 base.children = children || []; 985 base.children = children || [];
994 base.closing = closing || null; 986 base.closing = closing || null;
995 }; 987 };
996 988
997 TokenizeToken.prototype = { 989 TokenizeToken.prototype = {
1006 998
1007 return new TokenizeToken( 999 return new TokenizeToken(
1008 base.type, 1000 base.type,
1009 base.name, 1001 base.name,
1010 base.val, 1002 base.val,
1011 extend({}, base.attrs), 1003 base.attrib,
1012 [], 1004 [],
1013 base.closing ? base.closing.clone() : null 1005 base.closing ? base.closing.clone() : null
1014 ); 1006 );
1015 }, 1007 },
1016 /** 1008 /**
1131 * @param {string} val 1123 * @param {string} val
1132 * @return {Object} 1124 * @return {Object}
1133 * @private 1125 * @private
1134 */ 1126 */
1135 function tokenizeTag(type, val) { 1127 function tokenizeTag(type, val) {
1136 var matches, attrs, name, 1128 var matches, attrib, name,
1137 openRegex = /\[([^\]\s=]+)(?:([^\]]+))?\]/, 1129 openRegex = /\[([^\]\s=]+)(?:=([^\]]+))?\]/,
1138 closeRegex = /\[\/([^\[\]]+)\]/; 1130 closeRegex = /\[\/([^\[\]]+)\]/;
1139 1131
1140 // Extract the name and attributes from opening tags and 1132 // Extract the name and attributes from opening tags and
1141 // just the name from closing tags. 1133 // just the name from closing tags.
1142 if (type === TOKEN_OPEN && (matches = val.match(openRegex))) { 1134 if (type === TOKEN_OPEN && (matches = val.match(openRegex))) {
1143 name = lower(matches[1]); 1135 name = lower(matches[1]);
1144 1136
1145 if (matches[2] && (matches[2] = matches[2].trim())) { 1137 if (matches[2] && (matches[2] = matches[2].trim())) {
1146 attrs = tokenizeAttrs(matches[2]); 1138 attrib = _stripQuotes(matches[2]);
1147 } 1139 }
1148 } 1140 }
1149 1141
1150 if (type === TOKEN_CLOSE && 1142 if (type === TOKEN_CLOSE &&
1151 (matches = val.match(closeRegex))) { 1143 (matches = val.match(closeRegex))) {
1163 1155
1164 type = TOKEN_CONTENT; 1156 type = TOKEN_CONTENT;
1165 name = '#'; 1157 name = '#';
1166 } 1158 }
1167 1159
1168 return new TokenizeToken(type, name, val, attrs); 1160 return new TokenizeToken(type, name, val, attrib);
1169 }
1170
1171 /**
1172 * Extracts the individual attributes from a string containing
1173 * all the attributes.
1174 *
1175 * @param {string} attrs
1176 * @return {Object} Assoc array of attributes
1177 * @private
1178 */
1179 function tokenizeAttrs(attrs) {
1180 var matches,
1181 /*
1182 ([^\s=]+) Anything that's not a space or equals
1183 = Equals sign =
1184 (?:
1185 (?:
1186 (["']) The opening quote
1187 (
1188 (?:\\\2|[^\2])*? Anything that isn't the
1189 unescaped opening quote
1190 )
1191 \2 The opening quote again which
1192 will close the string
1193 )
1194 | If not a quoted string then match
1195 (
1196 (?:.(?!\s\S+=))*.? Anything that isn't part of
1197 [space][non-space][=] which
1198 would be a new attribute
1199 )
1200 )
1201 */
1202 attrRegex = /([^\s=]+)=(?:(?:(["'])((?:\\\2|[^\2])*?)\2)|((?:.(?!\s\S+=))*.))/g,
1203 ret = {};
1204
1205 // if only one attribute then remove the = from the start and
1206 // strip any quotes
1207 if (attrs.charAt(0) === '=' && attrs.indexOf('=', 1) < 0) {
1208 ret.defaultattr = _stripQuotes(attrs.substr(1));
1209 } else {
1210 if (attrs.charAt(0) === '=') {
1211 attrs = 'defaultattr' + attrs;
1212 }
1213
1214 // No need to strip quotes here, the regex will do that.
1215 while ((matches = attrRegex.exec(attrs))) {
1216 ret[lower(matches[1])] =
1217 _stripQuotes(matches[3]) || matches[4];
1218 }
1219 }
1220
1221 return ret;
1222 } 1161 }
1223 1162
1224 /** 1163 /**
1225 * Parses a string into an array of BBCodes 1164 * Parses a string into an array of BBCodes
1226 * 1165 *
1839 // elements 1778 // elements
1840 content += '<br />'; 1779 content += '<br />';
1841 } 1780 }
1842 1781
1843 if (!isFunction(bbcode.html)) { 1782 if (!isFunction(bbcode.html)) {
1844 token.attrs['0'] = content; 1783 token['0'] = content;
1845 html = formatBBCodeString( 1784 html = formatBBCodeString(
1846 bbcode.html, 1785 bbcode.html,
1847 token.attrs 1786 token
1848 ); 1787 );
1849 } else { 1788 } else {
1850 html = bbcode.html( 1789 html = bbcode.html(
1851 token, 1790 token,
1852 token.attrs, 1791 token.attrib,
1853 content, 1792 content,
1854 editor 1793 editor
1855 ); 1794 );
1856 } 1795 }
1857 } else { 1796 } else {
1981 ret += '\n'; 1920 ret += '\n';
1982 } 1921 }
1983 1922
1984 // Convert the tag and it's attributes to BBCode 1923 // Convert the tag and it's attributes to BBCode
1985 ret += '[' + token.name; 1924 ret += '[' + token.name;
1986 if (token.attrs) { 1925 if (token.attrib) {
1987 if (token.attrs.defaultattr) { 1926 ret += '=' + quote(
1988 ret += '=' + quote( 1927 token.attrib,
1989 token.attrs.defaultattr, 1928 quoteType
1990 quoteType, 1929 );
1991 'defaultattr' 1930 delete token.attrib;
1992 );
1993
1994 delete token.attrs.defaultattr;
1995 }
1996
1997 for (attr in token.attrs) {
1998 if (token.attrs.hasOwnProperty(attr)) {
1999 ret += ' ' + attr + '=' +
2000 quote(token.attrs[attr], quoteType, attr);
2001 }
2002 }
2003 } 1931 }
2004 ret += ']'; 1932 ret += ']';
2005 1933
2006 if (breakStart) { 1934 if (breakStart) {
2007 ret += '\n'; 1935 ret += '\n';
2045 * @param {BBCodeParser.QuoteType} quoteType 1973 * @param {BBCodeParser.QuoteType} quoteType
2046 * @param {string} name 1974 * @param {string} name
2047 * @return {string} 1975 * @return {string}
2048 * @private 1976 * @private
2049 */ 1977 */
2050 function quote(str, quoteType, name) { 1978 function quote(str, quoteType) {
2051 var needsQuotes = /\s|=/.test(str); 1979 var needsQuotes = /\s|=/.test(str);
2052 1980
2053 if (isFunction(quoteType)) { 1981 if (isFunction(quoteType)) {
2054 return quoteType(str, name); 1982 return quoteType(str);
2055 } 1983 }
2056 1984
2057 if (quoteType === QuoteType.never || 1985 if (quoteType === QuoteType.never ||
2058 (quoteType === QuoteType.auto && !needsQuotes)) { 1986 (quoteType === QuoteType.auto && !needsQuotes)) {
2059 return str; 1987 return str;