|
|
@@ -88,6 +88,7 @@
|
|
|
ref="PinyinText"
|
|
|
:rich-text-list="item.rich_text_list"
|
|
|
:pinyin-position="data.property.pinyin_position"
|
|
|
+ :body-styles="getBodyStyles()"
|
|
|
@fillCorrectPinyin="fillCorrectPinyin($event, i, -1, 'model_essay')"
|
|
|
/>
|
|
|
</div>
|
|
|
@@ -179,10 +180,11 @@ export default {
|
|
|
const arr = [];
|
|
|
let totalText = '';
|
|
|
let totalRichText = [];
|
|
|
+ const openStyleTagStack = [];
|
|
|
for (let i = 0; i < text_list.length; i++) {
|
|
|
const textItem = text_list[i];
|
|
|
const text = textItem.text || '';
|
|
|
- const isStyle = textItem.is_style === 'true';
|
|
|
+ const isStyle = textItem.is_style === 'true' || textItem.is_style === true;
|
|
|
if (isStyle) {
|
|
|
const isRichFill = /class=\s*(\\?["'])rich-fill\1/.test(text);
|
|
|
if (isRichFill) {
|
|
|
@@ -216,37 +218,39 @@ export default {
|
|
|
} else {
|
|
|
totalText += text;
|
|
|
totalRichText = totalRichText.concat(textItem);
|
|
|
+ this.syncOpenStyleTagStack(openStyleTagStack, textItem);
|
|
|
}
|
|
|
} else {
|
|
|
const splitBlocks = this.splitTextItemByUnderline(textItem, preservedAnyOneAnswers, preservedAnyOneState);
|
|
|
|
|
|
+ const currentOpenStyleTags = openStyleTagStack.map((tagItem) => ({ ...tagItem }));
|
|
|
+ const firstBlockPrefix =
|
|
|
+ totalText.length > 0
|
|
|
+ ? this.buildFirstBlockStylePrefix(totalRichText, currentOpenStyleTags)
|
|
|
+ : currentOpenStyleTags;
|
|
|
+
|
|
|
// 样式标签单独成块会导致 PinyinText 的样式栈断开,需并入紧随其后的文本块。
|
|
|
- if (totalText.length > 0) {
|
|
|
- if (splitBlocks.length > 0) {
|
|
|
+ if (splitBlocks.length > 0) {
|
|
|
+ if (totalText.length > 0) {
|
|
|
splitBlocks[0].content = `${totalText}${splitBlocks[0].content || ''}`;
|
|
|
- const inheritedOpenStyleTags = totalRichText.filter((tagItem) => {
|
|
|
- const tagText = tagItem?.text || '';
|
|
|
- const isStyleTag = tagItem?.is_style === 'true' || tagItem?.is_style === true;
|
|
|
- if (!isStyleTag) return false;
|
|
|
- if (/^<\//.test(tagText)) return false;
|
|
|
- if (/^<br\s*\/?\s*>$/i.test(tagText)) return false;
|
|
|
- return /^<\w+[^>]*>$/.test(tagText);
|
|
|
- });
|
|
|
-
|
|
|
- splitBlocks.forEach((block, blockIndex) => {
|
|
|
- const prevRichTextList = block.rich_text_list || [];
|
|
|
- block.rich_text_list = [
|
|
|
- ...(blockIndex === 0 ? totalRichText : inheritedOpenStyleTags),
|
|
|
- ...prevRichTextList,
|
|
|
- ];
|
|
|
- });
|
|
|
- } else {
|
|
|
- arr.push({
|
|
|
- content: totalText,
|
|
|
- type: 'text',
|
|
|
- rich_text_list: totalRichText,
|
|
|
- });
|
|
|
}
|
|
|
+
|
|
|
+ splitBlocks.forEach((block, blockIndex) => {
|
|
|
+ const prevRichTextList = block.rich_text_list || [];
|
|
|
+ block.rich_text_list = [
|
|
|
+ ...(blockIndex === 0 ? firstBlockPrefix : currentOpenStyleTags),
|
|
|
+ ...prevRichTextList,
|
|
|
+ ];
|
|
|
+ });
|
|
|
+
|
|
|
+ totalText = '';
|
|
|
+ totalRichText = [];
|
|
|
+ } else if (totalText.length > 0) {
|
|
|
+ arr.push({
|
|
|
+ content: totalText,
|
|
|
+ type: 'text',
|
|
|
+ rich_text_list: firstBlockPrefix,
|
|
|
+ });
|
|
|
totalText = '';
|
|
|
totalRichText = [];
|
|
|
}
|
|
|
@@ -265,6 +269,59 @@ export default {
|
|
|
|
|
|
return arr;
|
|
|
},
|
|
|
+ getStyleTagName(tagText = '') {
|
|
|
+ const trimmedText = String(tagText).trim();
|
|
|
+ const closeMatch = trimmedText.match(/^<\/(\w+)>$/);
|
|
|
+ if (closeMatch) return closeMatch[1].toLowerCase();
|
|
|
+
|
|
|
+ const openMatch = trimmedText.match(/^<(\w+)([^>]*)>$/);
|
|
|
+ if (openMatch) return openMatch[1].toLowerCase();
|
|
|
+
|
|
|
+ return '';
|
|
|
+ },
|
|
|
+ isOpenStyleTag(tagItem = {}) {
|
|
|
+ const tagText = String(tagItem?.text || '').trim();
|
|
|
+ const isStyleTag = tagItem?.is_style === 'true' || tagItem?.is_style === true;
|
|
|
+ if (!isStyleTag) return false;
|
|
|
+ if (/^<\//.test(tagText)) return false;
|
|
|
+ if (/^<br\s*\/?\s*>$/i.test(tagText)) return false;
|
|
|
+ return /^<\w+[^>]*>$/.test(tagText);
|
|
|
+ },
|
|
|
+ syncOpenStyleTagStack(openStyleTagStack, styleTagItem) {
|
|
|
+ const tagText = String(styleTagItem?.text || '').trim();
|
|
|
+ const isStyleTag = styleTagItem?.is_style === 'true' || styleTagItem?.is_style === true;
|
|
|
+ if (!isStyleTag) return;
|
|
|
+ if (/^<br\s*\/?\s*>$/i.test(tagText)) return;
|
|
|
+
|
|
|
+ const closeMatch = tagText.match(/^<\/(\w+)>$/);
|
|
|
+ if (closeMatch) {
|
|
|
+ const closeTagName = closeMatch[1].toLowerCase();
|
|
|
+ for (let i = openStyleTagStack.length - 1; i >= 0; i--) {
|
|
|
+ const tagName = this.getStyleTagName(openStyleTagStack[i]?.text);
|
|
|
+ if (tagName === closeTagName) {
|
|
|
+ openStyleTagStack.splice(i, 1);
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (this.isOpenStyleTag(styleTagItem)) {
|
|
|
+ openStyleTagStack.push(styleTagItem);
|
|
|
+ }
|
|
|
+ },
|
|
|
+ buildFirstBlockStylePrefix(transitionStyleTags = [], currentOpenStyleTags = []) {
|
|
|
+ const transitionOpenTagNames = transitionStyleTags
|
|
|
+ .filter((tagItem) => this.isOpenStyleTag(tagItem))
|
|
|
+ .map((tagItem) => this.getStyleTagName(tagItem?.text));
|
|
|
+
|
|
|
+ const missingOpenTags = currentOpenStyleTags.filter((tagItem) => {
|
|
|
+ const tagName = this.getStyleTagName(tagItem?.text);
|
|
|
+ return tagName && !transitionOpenTagNames.includes(tagName);
|
|
|
+ });
|
|
|
+
|
|
|
+ return [...missingOpenTags, ...transitionStyleTags];
|
|
|
+ },
|
|
|
/**
|
|
|
* 根据文本中的连续下划线分割文本块,并将下划线部分转换为输入块
|
|
|
* @param {Object} textItem 富文本中的一个文本项
|
|
|
@@ -620,6 +677,10 @@ export default {
|
|
|
removeWord(index) {
|
|
|
this.data.word_list.splice(index, 1);
|
|
|
},
|
|
|
+ getBodyStyles() {
|
|
|
+ if (!this.$refs.richText) return {};
|
|
|
+ return this.$refs.richText.getBodyInitialStyles();
|
|
|
+ },
|
|
|
},
|
|
|
};
|
|
|
</script>
|