正如Sports.ru写的所见即所得编辑器

在2018年中,Sports.ru考虑过将新的WYSIWYG文本编辑器用于用户帖子。自2019年6月以来,该编辑器一直处于beta模式。在这段时间内,我们解决了与整个服务的体系结构设计以及基于ProseMirror库的浏览器中编辑器本身的实现相关的许多问题,并决定分享我们的经验。



目录


1.引言
1.1。为什么需要所见即所得
1.2。开发人员面临的任务描述
2.如何选择工具
3.发生了什么
3.1 服务架构
3.2。挑战是什么
4. Beta测试结果


1.简介



1.1。为什么需要所见即所得


Sports.ru是有关体育的媒体,每月有2000万用户。我们与经典媒体的主要区别在于社区和教资会。用户内容-评分,评论,聊天,帖子-不仅可以补充社论的价值,而且可以为用户相互交流提供平台。每个月,我们的用户撰写近一万篇文章。最好的与编辑的内容一起提交到网站的主页,发送到移动应用程序,社交网络。用户内容约占Sports.ru页上所有阅读内容的40%。

我们希望成为体育作家最方便的平台,以帮助创建内容并将其交付给感兴趣的受众。我们使用TinyMCE编辑器已有 10年了-最后,它变得过时了,它不再适合于团队和习惯于现代编辑的用户。


图。1.基于TinyMCE的旧编辑器的界面

博客作者定期收到有关以下投诉的信息:

  • 我写了很长时间,然后不小心合上了标签,一切都消失了。
  • 写长篇文章很不方便;
  • 令人讨厌的是,要插入每张图片,您必须先将其上传到图片托管。

团队也有自己的抱怨:

  • 在TinyMCE中,您不能直接从文件上传图像,只能将链接附加到图像,并且由于用户无法将图像上传到我们的存储,如果链接失效,我们将无能为力。
  • 编辑和格式化文本的可能性不均衡。一方面,没有足够的样式,例如,文本中的内部标题。另一方面,可以以任何组合使用可用的工具。结果,职位看起来不统一(在Sports.ru,开始执行设计系统,用户职位应与其保持一致);
  • 内容是用HTML创建和存储的,因此很难在不同客户端上管理帖子中的样式,仅更改帖子的布局即可。

接下来是一个关于我们如何解决在前端侧创建新编辑器的问题的故事。的确,关于产品,设计和后端部件也将有所涉及,因为如果没有这些,将很难理解为什么要在前端做出特定的决定。


1.2。开发人员面临的任务说明


简而言之,我们最初借鉴的论点是:在Sports.ru上博客是一种痛苦。原则上,可能不做一个新的编辑器,而只是添加自动保存功能,并可以将图片上传到自己的存储中-这样,来自用户和员工的大部分投诉都将消失。但是我仍然不想在旧技术上支持该工具,而是创建一个可以轻松开发和扩展的新的现代编辑器。

除了不方便的界面之外,旧编辑器的主要技术问题之一是,帖子的内容立即保存为HTML字符串,并且帖子外观的更改要么需要后端开发人员的干预,要么在运行时在客户端上实现(例如,广告单元的放置)在帖子的正文中)。除其他事项外,我们的任务是将数据与其表示分离,从而将布局和界面保留在客户端代码中,并使用服务器代码中的数据。

作为榜样,我们采用了Medium,有时还利用Google Doc的想法。除了解决已经发现的问题外,我们还决定添加一些新功能,使使用编辑器更加舒适:

  • WYSIWYG, .. what you see is what you get (. « , », ), , . , ;
  • ( , , , , ; , ) .

同时,编辑者本人不应与Sports.ru的功能联系在一起,因为Sports.ru虽然是我们公司的旗舰项目,但仍然不是唯一的项目。该公司还开发了国际体育媒体Tribuna,这是一个针对博彩爱好者Betting Insider的社交网络,最近还成立了自己的从事广告项目的制作工作室。开发在线编辑器非常昂贵,以至于不想在具有不同排版和样式的另一个站点上重复使用此代码,并拥有自己的一组编辑和格式化工具。

我们有很多文本内容,在开始创建新的帖子编辑器之前,我们考虑了如何存储此内容。 TinyMCE没有给我们选择的余地,而内容只能存储为HTML,如上所述,这不适合团队使用。结果,我们想出了自己的格式来存储符合我们要求的文本数据,并将其称为结构化主体。

结构化主体是反映内容结构的一系列对象。在这种情况下,内容分为独立块的元素,例如,段落,列表,图片。元素存储有关其类型和属性的信息。例如,字幕块描述了文本中的标题,它必须包含文本和级别字段。因此,文本包含该标题的文本,级别包含级别(从1到4)。例如,由一个二级头组成的结构化主体可能看起来像这样:

const structuredBody = [
    {
        type: 'subtitle',
        value: {
            text: '    ',
            level: 2,
        },
    },
];

向结构化主体的过渡使我们能够开始分离业务逻辑,数据及其表示的过程。最终,我们希望服务器和客户端仅交换数据。以及如何以及为什么将这些数据显示给最终用户,每个客户将独立确定。

格式化主体格式的内容存储在JSON中,并且为了验证其内容,我们创建了一个称为结构化主体架构JSON模式。此图描述了所有有效元素及其属性。因此,我们可以确定在需要结构化主体的任何地方都使用一组键和值。

而且,它允许不同的团队使用相同的服务来处理这种格式的内容。例如,用于从用于显示内容的结构化主体生成HTML的服务或用于创建内容的编辑器。这显着降低了开发和支持与内容的创建和显示有关的服务的整个核心的成本。

假定新编辑者应仅接受结构化主体格式的输入和输出内容。这里必须要考虑到一个微妙的问题:由于以前的帖子是立即以HTML格式保存的,因此数据库中的HTML字符串已传输给客户端以供显示(在下文中,除非另有说明,否则客户端仅指浏览器)。现在,我们希望将所有帖子的内容存储在结构化的正文中,但是客户只能处理HTML。因此,除了转移到新编辑器的任务之外,同时实现了一种新的任务,即为客户显示一种新的方式来显示帖子以直接从结构化主体读取。我们认为最好零食大象,所以首先需要完全放弃TinyMCE,然后才采用显示帖子以供阅读的逻辑。此外,并非所有旧帖子都设法将内容转换为新格式,这意味着这些帖子将始终仅以HTML格式存储,因此有必要保留它们的阅读能力。

总计:部分帖子(已成功转移到新格式的所有新旧帖子)将以两种格式存储-HTML和结构化正文-直到实现了用于阅读的新显示逻辑,其余的(大部分是旧的和非常旧的)帖子)将仅保留在HTML中。


2.如何选择工具


考虑到上述功能和限制,我们必须实现在客户端上编辑和创建帖子的功能。与往常一样,您可以采用现成的解决方案,也可以提出自己的解决方案。

首先,我们检查了用于创建所见即所得编辑器的现成库以及它们是否适合我们。我们选择了SlateDraft.jsProseMirror

除了将内容存储在数据结构中之外,对我们来说,关键时刻还在于能够使用Vue或纯JS,因为我们已经开始使用Vue + Vuex将网站迁移到新的技术堆栈中。另外,如有必要,我想借助新模块(第三方或自写)扩展成品库的功能。

标签。1.通过Sports.ru的最重要参数比较审阅的库,


从表中可以看出,ProseMirror完全符合我们的要求,因此我们不再考虑编写自己的库以编辑文本内容的想法,而是开始更详细地研究该库。还有一个相当流行的Quill,它并没有进入我们的比较,只是因为我们在选择工具的阶段诚实地忘记了它。根据我们的关键要求,它也可以通过,但是确实如此。在另一篇文章中,我们已经讨论了ProseMirror是什么以及如何使用它


3.发生了什么事



3.1。服务架构


客户端上的内容编辑器本身远非如此。您需要将编辑器放置在现有项目中,将其显示在网页上的某个位置,还要考虑与后端的交互,解决同时支持两个编辑器(您不能立即放弃旧的编辑器)并以两种格式(HTML和结构化格式)存储内容的问题身体)。

所有这些任务可以分为与前端,后端及其集成相关的任务。尽管我们还提到了后端任务的两个重要方面,但我们主要关注前端和集成问题。

编辑器的前端服务可以分为几个级别:

  1. 用于创建和编辑帖子的网页;
  2. Vue-app, . , , Vue, -, , , , .., , , ;
  3. WYSIWYG- ProseMirror, Vue. , , ;
  4. SB2HTML – HTML structured body, . , structured body – , . , , , . Sports.ru HTML structured body, - HTML . HTML Node.Js, JS- .

保存帖子的过程如图2所示。2.具有结构化正文格式的帖子内容及其元数据将传输到后端。后端将内容发送到SB2HTML服务,在响应中接收就绪的HTML,将所有这些都放入数据库中,并告诉客户端帖子已成功保存,或报告错误。


图。2.在所见即所得编辑器中创建或编辑时用于保存帖子的方案


3.2。您遇到了什么困难?


有许多困难,它们经常在最意想不到的时刻不断出现。

就像我们已经说过的那样,内容编辑器位于表单内部,它使您可以输入创建帖子所必需的其他数据,例如标题,注释等。对于注释,应该可以从文件中或通过Internet链接下载图像。但是对于内容,我们还希望根据相同的规则从文件中加载图像,并通过引用加载图像。这里我们面临一个难题:一方面,帖子的内容在编辑时与外部表单隔离开来,并由ProseMirror工具提供服务,但另一方面,我想观察DRY原理并且不要重复相同的代码。我们按以下方式解决了这一问题:我们将在Vue表单级别的对象中将图像加载为一组方法,并将该对象作为参数之一传递给WYSIWYG编辑器的构造函数。

在ProseMirror模型中定义了描述内容的实体(节点和片段)。但是,仅索引用于事务来确定应用此事务的字符范围(从文档的开头和父节点的开头开始都对索引进行计数)。字符索引是ProseMirror的核心概念之一,但是在编辑和设置文本格式时,考虑ProseMirror模型中的实体要方便得多。因此,为了舒适地处理内容,我们编写了助手来简化与交易文档的交互。在工作开始之后,出现Tiptap,它是一组类似的帮助程序。

下一个问题是,在创建方案的阶段,我们意识到我们已经拥有一种批准的用于存储内容的内部格式-可以满足我们需求的结构化主体,并且ProseMirror将内容以其自己的格式存储在故事中。切换到ProseMirror格式既困难又不切实际。我们发现自己处于一种情况,即一种格式的数据通过API到达客户端,而另一种格式则需要显示。当有必要保存修改或创建的内容时,会发生类似情况。为此,我们实现了一个转换器,可以来回转换格式。他们为他编写了一个简单的测试,该测试以结构化正文格式获取一篇帖子的内容,将其转换为ProseMirror格式,然后返回并已将原始版本与收到的帖子进行了比较。事实证明,这一过程既快速又轻松。

将来,随着文档方案的更改,并且通常变得更加复杂,很明显,最细微的更改都可能导致编辑器中的错误,并且这样的测试似乎覆盖面很差。结果,我不得不用两种小型转换器方法对几乎所有节点和品牌组合进行测试。现在,如果没有这些测试,就无法确定电路的下一个变化是否会破坏某些东西。

下一个问题再次与对旧技术和新技术的向后兼容性的需求有关。我们的WYSIWYG编辑器仅在浏览器(台式机和移动版)中实现。因此,为了在客户端上编辑内容,使用格式结构体以JSON形式给出,但是,浏览器中的阅读文章仅从HTML执行。同时,大多数移动应用程序已切换为直接从结构化主体显示用户帖子。

对于移动应用程序,必须提供客户端无法处理结构化主体中某些元素的情况。例如,如果将新元素添加到结构化主体,则仅在应用程序的较新版本中实现其显示。由于并非所有用户都同时更新其应用程序,因此有必要为旧版本提供计划“ B”:与其从结构化主体中创建HTML,不如为所需元素插入现成的HTML片段。结构化主体方案中未提供每个元素的HTML片段的存在,因为该结构的初衷是拒绝将数据存储在HTML中。但是最后,我们得出的结论是,我们需要两种结构化的主体方案-一种用于显示,另一种用于编辑。方案之间的区别是用于编辑的结构化主体仅包含文章的内容,并且为了显示,我们添加了一些其他元素。特别是,将帖​​子保存在SB2HTML服务中时,将为每个元素创建一个HTML片段,并且仅将其添加到结构化正文中以显示该帖子。另外,结构化主体还在内容中显示广告空间以供显示。

当我们在浏览器中打开要编辑的内容时,基本上不会遇到未知元素,因为所有帖子都是以相同的方式创建和显示的。但是他们决定也预见将来会有这样的情况。为此,我们向ProseMirror模式添加了一个默认的stub元素。我们将此元素命名为unsupportedBlock。存根将显示在不支持的项目的位置。我们将其样式化为带有文本的灰色矩形,指出该元素不受支持并且无法编辑。保存帖子后,此类元素在结构化主体中保持不变。用户可以更改其相对于其他元素的位置,但是无法更改或编辑未知元素的内部内容。但是,用户可以删除这样的元素,然后,当然,它不会保存在最终文档中。

所描述的所有问题都与实现所见即所得编辑器本身的困难有关。但是,尽管它以beta模式存在,但我们不能放弃TinyMCE上的旧编辑器,而被迫支持这两种编辑器,从而提供它们之间的向后兼容性。例如,您可以在WYSIWYG编辑器中创建一个帖子,保存,然后在TinyMCE中对其进行编辑,保存,然后在WYSIWYG中再次打开,依此类推。结果,在所见即所得中打开时,我们看到的内容与之前在TinyMCE中保存的内容相同。为了实现向后兼容,必须将HTML内容提交给TinyMCE,我们已经学会了如何从结构化主体创建HTML内容并在保存帖子的同时将其保存到数据库。当通过TinyMCE保存帖子时,服务器上创建的内容将通过HTML2SB服务运行,结果,我们可以保存新鲜的HTML和结构化的正文。

HTML2SB与SB2HTML的功能相反,即将SB2HTML的内容从HTML转换为结构化主体。按时间顺序,此服务首先出现,因为在创建所见即所得编辑器之前,以结构化主体格式获取帖子内容的唯一方法是直接从HTML解析。HTML2SB是帖子编辑器的后端基础结构的一部分,但是在放弃TinyMCE之后,就不再需要它了。


4. Beta结果


现在,所见即所得编辑器已向所有用户提供Beta版,并将很快成为Sports.ru帖子的主要编辑者。我们已经收到了用于创建和编辑帖子的工具,该工具可以满足我们的大多数要求:

  • 编辑器的界面变得清晰,简洁,现代,撰写长帖子变得更加容易;
  • 现在,您可以从文件中下载图像并通过链接立即将其下载到我们的存储库中;
  • 添加了从主要社交网络和视频托管网站嵌入嵌入的选项;
  • 清理文本格式样式;
  • 移动应用程序已经切换到显示结构化正文中的帖子,并且可以设置自己的内容样式。

当然,编辑器尚未完全调试,我们会定期检测到新的错误。以下更新即将发布:

  • 自动保存;
  • 所见即所得版本,用于具有扩展权限的用户(管理员,专职编辑器);
  • 通过移动浏览器创建和编辑帖子;
  • 有关多个用户并行编辑文档的消息;
  • 提示和入职;
  • 运动队,比赛和阵容的统计小部件。

在撰写本文时,已经通过Beta版编辑器发布了13,000多个帖子,约占Sports.ru在2019年6月至2020年2月(含)期间用户文本总数的20%。通过新编辑器创建和发布的帖子所占的份额正在稳步增长。


图。 3.在新编辑器中创建和发布的用户帖子的比例

似乎通过新编辑器创建和发布的用户帖子所占比例的有机增长表明用户对更新感到满意,这一点也得到了Beta测试发布公告中的反馈的肯定(其中一些如图4所示)。因此,在接下来的几个月中,我们计划将帖子的创建工作完全转移给新编辑,以便仅专注于其支持和发展。 
顺便说一句,您将向我们的所见即所得编辑器中添加什么功能?


图。4.用户在发布所见即所得编辑器更新的帖子中发表评论 

All Articles