sforkowany z mirror/soapbox
Merge branch 'greentext2' into 'develop'
Fix greentext postprocessing Closes #668 See merge request soapbox-pub/soapbox-fe!566actually-fix-tabs-bar
commit
9a6f489c6a
|
@ -6,6 +6,7 @@ import { FormattedMessage } from 'react-intl';
|
||||||
import Permalink from './permalink';
|
import Permalink from './permalink';
|
||||||
import classnames from 'classnames';
|
import classnames from 'classnames';
|
||||||
import Icon from 'soapbox/components/icon';
|
import Icon from 'soapbox/components/icon';
|
||||||
|
import { processHtml } from 'soapbox/utils/tiny_post_html_processor';
|
||||||
|
|
||||||
const MAX_HEIGHT = 642; // 20px * 32 (+ 2px padding at the top)
|
const MAX_HEIGHT = 642; // 20px * 32 (+ 2px padding at the top)
|
||||||
|
|
||||||
|
@ -157,25 +158,27 @@ export default class StatusContent extends React.PureComponent {
|
||||||
return this.greentext(properContent);
|
return this.greentext(properContent);
|
||||||
}
|
}
|
||||||
|
|
||||||
greentext = string => {
|
greentext = html => {
|
||||||
if (!this.props.greentext) return string;
|
if (!this.props.greentext) return html;
|
||||||
|
|
||||||
// Copied from Pleroma FE
|
// Copied from Pleroma FE
|
||||||
// https://git.pleroma.social/pleroma/pleroma-fe/-/blob/19475ba356c3fd6c54ca0306d3ae392358c212d1/src/components/status_content/status_content.js#L132
|
// https://git.pleroma.social/pleroma/pleroma-fe/-/blob/19475ba356c3fd6c54ca0306d3ae392358c212d1/src/components/status_content/status_content.js#L132
|
||||||
try {
|
return processHtml(html, (string) => {
|
||||||
if (string.includes('>') &&
|
try {
|
||||||
string
|
if (string.includes('>') &&
|
||||||
.replace(/<[^>]+?>/gi, '') // remove all tags
|
string
|
||||||
.replace(/@\w+/gi, '') // remove mentions (even failed ones)
|
.replace(/<[^>]+?>/gi, '') // remove all tags
|
||||||
.trim()
|
.replace(/@\w+/gi, '') // remove mentions (even failed ones)
|
||||||
.startsWith('>')) {
|
.trim()
|
||||||
return `<span class='greentext'>${string}</span>`;
|
.startsWith('>')) {
|
||||||
} else {
|
return `<span class='greentext'>${string}</span>`;
|
||||||
|
} else {
|
||||||
|
return string;
|
||||||
|
}
|
||||||
|
} catch(e) {
|
||||||
return string;
|
return string;
|
||||||
}
|
}
|
||||||
} catch(e) {
|
});
|
||||||
return string;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
|
|
|
@ -0,0 +1,97 @@
|
||||||
|
// Copied from Pleroma FE
|
||||||
|
// https://git.pleroma.social/pleroma/pleroma-fe/-/blob/develop/src/services/tiny_post_html_processor/tiny_post_html_processor.service.js
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This is a tiny purpose-built HTML parser/processor. This basically detects any type of visual newline and
|
||||||
|
* allows it to be processed, useful for greentexting, mostly
|
||||||
|
*
|
||||||
|
* known issue: doesn't handle CDATA so nested CDATA might not work well
|
||||||
|
*
|
||||||
|
* @param {Object} input - input data
|
||||||
|
* @param {(string) => string} processor - function that will be called on every line
|
||||||
|
* @return {string} processed html
|
||||||
|
*/
|
||||||
|
export const processHtml = (html, processor) => {
|
||||||
|
const handledTags = new Set(['p', 'br', 'div']);
|
||||||
|
const openCloseTags = new Set(['p', 'div']);
|
||||||
|
|
||||||
|
let buffer = ''; // Current output buffer
|
||||||
|
const level = []; // How deep we are in tags and which tags were there
|
||||||
|
let textBuffer = ''; // Current line content
|
||||||
|
let tagBuffer = null; // Current tag buffer, if null = we are not currently reading a tag
|
||||||
|
|
||||||
|
// Extracts tag name from tag, i.e. <span a="b"> => span
|
||||||
|
const getTagName = (tag) => {
|
||||||
|
const result = /(?:<\/(\w+)>|<(\w+)\s?[^/]*?\/?>)/gi.exec(tag);
|
||||||
|
return result && (result[1] || result[2]);
|
||||||
|
};
|
||||||
|
|
||||||
|
const flush = () => { // Processes current line buffer, adds it to output buffer and clears line buffer
|
||||||
|
if (textBuffer.trim().length > 0) {
|
||||||
|
buffer += processor(textBuffer);
|
||||||
|
} else {
|
||||||
|
buffer += textBuffer;
|
||||||
|
}
|
||||||
|
textBuffer = '';
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleBr = (tag) => { // handles single newlines/linebreaks/selfclosing
|
||||||
|
flush();
|
||||||
|
buffer += tag;
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleOpen = (tag) => { // handles opening tags
|
||||||
|
flush();
|
||||||
|
buffer += tag;
|
||||||
|
level.push(tag);
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleClose = (tag) => { // handles closing tags
|
||||||
|
flush();
|
||||||
|
buffer += tag;
|
||||||
|
if (level[level.length - 1] === tag) {
|
||||||
|
level.pop();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
for (let i = 0; i < html.length; i++) {
|
||||||
|
const char = html[i];
|
||||||
|
if (char === '<' && tagBuffer === null) {
|
||||||
|
tagBuffer = char;
|
||||||
|
} else if (char !== '>' && tagBuffer !== null) {
|
||||||
|
tagBuffer += char;
|
||||||
|
} else if (char === '>' && tagBuffer !== null) {
|
||||||
|
tagBuffer += char;
|
||||||
|
const tagFull = tagBuffer;
|
||||||
|
tagBuffer = null;
|
||||||
|
const tagName = getTagName(tagFull);
|
||||||
|
if (handledTags.has(tagName)) {
|
||||||
|
if (tagName === 'br') {
|
||||||
|
handleBr(tagFull);
|
||||||
|
} else if (openCloseTags.has(tagName)) {
|
||||||
|
if (tagFull[1] === '/') {
|
||||||
|
handleClose(tagFull);
|
||||||
|
} else if (tagFull[tagFull.length - 2] === '/') {
|
||||||
|
// self-closing
|
||||||
|
handleBr(tagFull);
|
||||||
|
} else {
|
||||||
|
handleOpen(tagFull);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
textBuffer += tagFull;
|
||||||
|
}
|
||||||
|
} else if (char === '\n') {
|
||||||
|
handleBr(char);
|
||||||
|
} else {
|
||||||
|
textBuffer += char;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (tagBuffer) {
|
||||||
|
textBuffer += tagBuffer;
|
||||||
|
}
|
||||||
|
|
||||||
|
flush();
|
||||||
|
|
||||||
|
return buffer;
|
||||||
|
};
|
Ładowanie…
Reference in New Issue