这是我第一次在 Stack Overflow 上写作,我请求您帮助解决问题。
我要向您提交的问题与我的新初创公司的 MVP 开发有关,该公司致力于为创意产业开发 SaaS。有问题的 MVP 是一个用于编写剧本的文本编辑器,我遇到了问题。
如果您不知道剧本有很多功能,包括场景标题是这样制作的:“1. EXT. PUB - NIGHT”
请记住,我能够执行以下操作:
import { Extension } from '@tiptap/core';
import { Plugin } from 'prosemirror-state';
import { Fragment } from 'prosemirror-model';
let paragraphCount = 0; // Variable to track paragraph count
const SceneTitle = Extension.create({
name: 'SceneTitle',
addProseMirrorPlugins() {
return [
new Plugin({
appendTransaction: (_, oldState, newState) => {
let tr = newState.tr;
let oldParagraphCount = 0;
let newParagraphCount = 0;
const regex = /^(INT\.|EXT\.|int\.|ext\.|INT|EXT|int|ext|EST|EST\.|est|est\.)/;
oldState.doc.descendants((node) => {
if (node.type.name === 'paragraph') {
oldParagraphCount++;
}
});
newState.doc.descendants((node, pos) => {
if (node.type.name === 'paragraph') {
newParagraphCount++;
if (regex.test(node.textContent)) {
let from = pos + 1;
let to = from + node.textContent.length;
let fragment = Fragment.from(newState.schema.text(node.textContent.toUpperCase()));
tr.replaceWith(from, to, fragment);
}
}
});
if (newParagraphCount > oldParagraphCount) {
paragraphCount++;
console.log(`Paragraph inserted. Total paragraphs: ${paragraphCount}`); // Print paragraph count
} else if (newParagraphCount < oldParagraphCount) {
paragraphCount = 0;
console.log(`Paragraphs deleted. Paragraph count reset to zero.`); // Print paragraph count reset
}
return tr;
},
}),
];
},
});
export default SceneTitle;
接下来,当我输入场景标题的编号时,通过创建索引,我可以将段落分为三个部分,即:编号、包含关键字的文本和其余文本。只有当我去写关键字时,作为“Int”,它会让我只大写关键字,而不是它后面的文本,但是还没有写,如果我先写将要写的文本在关键字之后,然后写下关键字,如“Int”,它使我将所有内容都大写。
import { Extension } from '@tiptap/core';
import { Plugin } from 'prosemirror-state';
import { Fragment } from 'prosemirror-model';
let paragraphCount = 0; // Variable to keep track of paragraph count
let sceneCount = 1; // Variable to track scene count
let appliedPositions = new Set(); // Together to track applied positions
const SceneTitle = Extension.create({
name: 'SceneTitle',
addProseMirrorPlugins() {
return [
new Plugin({
appendTransaction: (_, oldState, newState) => {
let tr = newState.tr;
let oldParagraphCount = 0;
let newParagraphCount = 0;
const regex = /^(INT\.|EXT\.|int\.|ext\.|INT|EXT|int|ext|EST|EST\.|est|est\.)/;
oldState.doc.descendants((node) => {
if (node.type.name === 'paragraph') {
oldParagraphCount++;
}
});
newState.doc.descendants((node, pos) => {
if (node.type.name === 'paragraph' && regex.test(node.textContent)) {
if (!appliedPositions.has(pos)) {
let from = pos + 1;
let to = from + node.textContent.length;
let fragment = Fragment.from(newState.schema.text(sceneCount + "." + " " + node.textContent.toUpperCase() + "." + " "));
tr.replaceWith(from, to, fragment);
appliedPositions.add(pos);
sceneCount++;
}
}
if (node.type.name === 'paragraph') {
newParagraphCount++;
}
});
if (newParagraphCount > oldParagraphCount) {
paragraphCount++;
console.log(`Paragraph inserted. Total paragraphs: ${paragraphCount}`); // Print paragraph count
} else if (newParagraphCount < oldParagraphCount) {
paragraphCount = 0;
sceneCount = 1; // Resets scene count only when paragraphs are deleted
appliedPositions.clear();
console.log(`Paragraphs deleted. Paragraph and scene count reset to zero.`); // Print paragraph and scene count reset
}
return tr;
},
}),
];
},
});
export default SceneTitle;
现在我不知道如何使场景标题具有渐进编号,它不循环,并且该段落中的所有文本都是大写的。
我遇到的另一个问题是,模拟用户可能能够做的事情,记住他们是编剧、电影制作人和视频制作人,就是在现有的场景标题之上插入一个新的场景标题,只有我能够做到这一点更新但不正确,也就是说,新标题的序列号位于创建的最后一段之后,所以:
“1.INT....”
“1. 分机....”
“2.INT....”
“3. 分机....”
“4.INT....”
“1. 分机....”
“2.INT....”
“3. 分机....”
我使用的技术栈如下:
下面是几个示例:
- INT。酒吧 - 夜晚
- INT。酒吧 - 夜晚
我们发现肖恩正和一个女人莉兹坐在一起。他们是
两人都二十多岁了。 LZ看起来有点担心,
肖恩看上去有些困惑。他们正在喝酒。- INT。公寓大楼 - 早上
- INT。公寓 - 早上
- INT。客厅 - 早上
我以前从未做过一些NextJS,但我只会给你一些 提示一个最小的普通 JS 示例,然后您可以实现 你自己在你的应用程序中。
正如我在评论中提到的,你的正则表达式应该 被重写以处理您的所有输入。我已经做到了 处理:
带点或不带点的可选数字。这个可能是 正如您提到的,这是错误的,所以我们将放弃它。
一种地点(
INT
、EXT
或 EST
),带有可选
点,并且不区分大小写,以便匹配“INT”,“Int”
或“int”等
地名(例如:“卧室”)。
连字符分隔符,周围有强制空格。
什么时候(例如:“早上”)。
基于我通过评论发布的正则表达式,附加 在开始时处理最终不需要的数字:
/^(\d+\.?\s*)?(?<place_type>int|ext|est)\.?\s*(?<place>.*?)\s+-\s+(?<when>.*?)\s*$/i
如您所见,我使用命名组是因为我发现它们比 索引组,特别是如果您稍后更改正则表达式。团体 名称不会改变,但索引组会改变。
在此处测试详细信息:https://regex101.com/r/qDPvYK/1
正如我在评论中也提到的,不这样做可能要简单得多 自己计算标题,只需使用 CSS 计数器即可。
您说您无法将段落转换为标题。 是的你是对的。但只要用谷歌搜索一下,你很快就会 发现你只需要创建一个新的
<h2>
标签并将其放入
而不是 <p>
标签。这可以通过很多方式来完成。这
我发现最简单的是获取父节点,然后使用
.replaceChild()
方法。
我在 HTML 演示中添加了一个按钮,以便您可以看到 运行转换算法之前和之后的内容。
const regexTitle = /^(\d+\.?\s*)?(?<place_type>int|ext|est)\.?\s*(?<place>.*?)\s+-\s+(?<when>.*?)\s*$/gmi;
document.addEventListener('DOMContentLoaded', function() {
function convertToTitles() {
// Loop over all paragraphs to try and convert some to headings.
document.querySelectorAll('p').forEach((p, i) => {
const match = regexTitle.exec(p.innerText);
if (match) {
const placeType = match.groups.place_type.toUpperCase(),
place = match.groups.place,
when = match.groups.when;
const h2 = document.createElement('h2');
h2.innerText = placeType + '. ' + place + ' - ' + when;
p.parentNode.replaceChild(h2, p);
}
});
}
const convertButton = document.getElementById('convert-to-titles');
convertButton.addEventListener('click', convertToTitles);
});
body {
background: silver;
padding: 2em;
}
.scenario {
min-width: 15em;
max-width: 30em;
background: white;
/* More padding on the left to pull out the scene title number. */
padding: 2em 2em 2em 4em;
margin-bottom: 2em;
box-shadow: 0 0 .5em rgba(0, 0, 0, 0.2);
font-family: "Courrier New", Courrier, monospace;
counter-reset: scene-title-nbr;
}
h1 {
margin-top: 0;
}
h2 {
margin: 1em 0 .5em 0;
font-size: 1em;
text-transform: uppercase;
position: relative; /* For absolute ::before pseudo-element. */
}
h2::before {
content: counter(scene-title-nbr);
counter-increment: scene-title-nbr;
position: absolute;
left: -2em;
}
<article class="scenario">
<header>
<h1>Scenario</h1>
</header>
<p>INT. Pub - night</p>
<p>
We reveal that SHAUN is sitting with a woman, LIZ. They are both in their
late twenties. LIZ looks slightly concerned, SHAUN looks slightly confused.
They are having a drink.
</p>
<p>INT. Apartment complex - morning</p>
<p>
Lorem ipsum dolor sit amet consectetur adipisicing elit. Quasi
maxime quisquam itaque numquam quas tempore quo, ex reprehenderit
ea dicta sequi voluptatem ipsum id cupiditate autem perspiciatis
obcaecati consectetur quod.
</p>
<p>1. INT. Apartment - morning</p>
<p>
Text should come here...
</p>
<p>INT. Living room - morning</p>
<p>
Text should come here...
</p>
<p>3. Ext Swimming-pool - midday</p>
<p>SHAUN dives into the pool while LIZ is sunbathing...</p>
</article>
<button id="convert-to-titles">Convert to titles</button>