Mercurial Hosting > sceditor
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; |