Spediteur: A WYSIWYG Editor for SPIP

Hello all!

Since 2018 I’ve integrated several WYSIWYG editors with SPIP, for use in the frontend via the porte-plume / pencil plugin. Today I’m announcing Spediteur, an open source WYSIWYG editor that I plan to release for the SPIP platform.

The previous WYSIWYG implementations I’ve done have been quite useful for my clients and collaborators. As developer I can set up each page in HTML, and hand it over to the client/users who can then tweak the text and make simple changes to the website’s contents themselves, autonomously.

I love SPIP because of its stability, performance and elegant templating language. I like that whenever something is more complicated, I can write real code effectively. And I like that SPIP’s codebase is relatively small, so when I need to do something at a deeper level, I can read through it relatively quickly.

For many projects I have the need to make complex content editable for my clients and collaboraters, without them needing to know HTML. Spediteur allows me to create pages in full HTML in line with a project’s requirements, and then hand it over to the client. The client then sees and can directly edit the final result.

Before, the simple WYSIWYG implementations I’ve used over the years were never perfect, but recently the fact that there is no up to date WYSIWYG editor for SPIP at this point felt like a real limitation both for me and for the SPIP ecosystem. A good project to contribute to open source perhaps? Here we go.

Spediteur

Spediteur is a WYSIWYG editor for SPIP. It allows you to graphically edit your website.

It has the following features:

  • Inline editing: Built atop the porte-plume functionality, SPIPedit allows you to edit content directly in the side. No backend, no code: Just edit what you see, as you see it, on the website.
  • Full WYSIWYG HTML editing support
  • Typographical edits via keyboard shortcut and menu (bold, italics, underline, undo, redo)
  • Source view for editing raw html
  • Modeles support: SPIPedit highlights inserted modeles, so users know what they can edit, and what’s loaded as modele-component

It aims to have the following features in the future:

  • Upload images via SPIP documents
  • Improve saved HTML syntax (match as closely as possible to SPIP’s native syntax)
  • Bi directional source-graphical view updates (Updates in source view reflect in WYSIWYG view)
  • Hotload Modeles when they are added (Adding a modele loads it dynamically into the WYSIWYG view)
  • move and copy, paste modeles.
  • configure modeles (click on modele area, opens dialog to tweak modele source code, or for img modeles, SPIP document picker/upload
  • various improvements based on feedback and edge cases

A quick Demo of Spediteur:

Video: https://ursrig.com/IMG/mp4/spipedit_demo.mp4

Note: I noticed a project called SPIPedit already exists - I’ve therefore chosen Spediteur as the name of the plugin.


Technical points

When SPIP renders a website, it performs various syntax checks on the content of, say, an article. Users may have placed titles, links, pictures and modeles (SPIP custom elements) into the article. SPIP understands all this and then renders the page's HTML and the browser displays the page.

Spediteur is adding additional markup around modeles. With this additional markup, the WYSIWYG editor can show which areas are actually editable, and which are custom elements (modeles) that cannot be edited (they can be deleted, moved, or reconfigured, at least that’s the idea, see todo section above).

Using Contenteditable, Spediteur is able to show the website 100% as-is, so users can edit the site « live ». Squire editor is used under the hood to make the contenteditable experience solid.

On save, the HTML is parsed back into SPIP markup, meaning that the wrapping elements are removed and we have a clean, SPIP compatible output that is saved to the article, and can also be edited as usual in SPIP’s backend.

Next steps

At the moment, I just have a basic implementation that is usable for me, but needs polishing to become an actual SPIP plugin.

I’ll be using that to get feedback from users, to improve the system. Then I plan to package the solution as a SPIP plugin.

To make this possible, some changes may be needed to the SPIP core. I’ll be seeking out input from the community on how to make this possible.

I am interested to make an effort to build compatibility between Spediteur and SPIP’s core syntax and tackle the other todos. An example is that the current implementation adds

-tags around paragraphs, so in order to improve SPIP-compatibility, the parser would need to remove these consistently before saving. Newlines are also an issue. The goal would be that the conversion from source to Spediteur and back to source will create changes to the source just where edits are made, and not affect any newlines, etc to keep diffs minimal.

My questions

I have made some modifications to SPIP code and would like to know what's the best way to integrate this (Either by overloading the method in my plugin or by contributing to spip core).

1. controleurs/article_texte.html
Here I’m overloading a porte plume file, adding the WYSIWYG editor, which loads Squire JS, and custom JS to sanitize the WYSIWYG-HTML back into the porte-plume Textarea for saving (that also serves as fallback source editor). It also loads the edit bar. This is easy to put into a plugin.

2. spediteur_fonctions.php
Custom functions to convert source text to html text with Spediteur metadata.

3. ecrire/src/Texte/Collecteur/Modeles.php

Is there a way I need to either overload the function traiter_modeles() from a plugin, or make a modification in spip core Modeles.php.

The idea is to wrap each modele with some metadata, so the HTML editor can know both the modele’s metadata, e.g. <modele|id=1> and its output, e.g.

Modele 1 rendered
at the same time.

/**
<?php
	 * Traiter les modeles d'un texte
	 * @param string $texte
	 * @param array $options
	 *   bool|array $doublons
	 *   string $echap
	 *   ?Spip\Texte\CollecteurLiens $collecteurLiens
	 *   ?array $env
	 *   ?string $connect
	 * @return string
	 */
	public function traiter(string $texte, array $options) {
		if ($texte) {
			...
			$modeles = $this->collecter($texte, ['collecter_liens' => true]);
			if (!empty($modeles)) {
				include_spip('public/assembler');
				$wrap_embed_html = charger_fonction('wrap_embed_html', 'inc', true);

				$offset_pos = 0;
				foreach ($modeles as $m) {
					...
					else {
						...
						//Spediteur: add contenteditable wrapper.
 						//Wraps a modele with metadata needed for Spediteur editor
						if( is_spediteur() ){
						    $modele = "<div class='contenteditable_modele'  data-modele=" . json_encode(htmlspecialchars($m['raw'])) . ">" . $modele . "</div>";
						}

4. html/plugins/auto/crayons/v3.3.0/action/crayons_html.php
Lastly I would need to overload or adjust / remove any limitations to the largeur and hauteur max of the porte plume plugin:

public $largeurMaxi = 4000;|
public $hauteurMaxi = 4000;|

Thanks for reading! At this point 1 have only 3 questions:

  • Do you have any feedback, concerns, about my approach? Would you like the plugin?
  • About 3: ecrire/src/Texte/Collecteur/Modeles.php → Do you have any advise on this? Oveload, or modify in code?
  • About 4: html/plugins/auto/crayons/v3.3.0/action/crayons_html.php* → Should I overload this, or propose a PR to the plugin to increase? Should it become a Gobal variable e.g. define(_PORTE_PLUME_LARGEUR_MAXI, « 4000 »); ?

Thank you!
Urs

1 « J'aime »

Hello @2a08d92699ec237569fa very interesting project!

I didn’t had time for the moment to analyse this approach (I surely will) but just to let you know that long long old discussion Refaire un éditeur à base de CodeMirror + ajouts (#3720) · Issues · spip / porte-plume · GitLab which WAS at the very start about a WYSIWYMean editor, but then also about a WYSIWYG editor with many technical solutions compared and evaluated. And after a choice for ProseMirror/TipTap AND Markdown only, after months of development it resulted last year in this POC plugin : spip-contrib-extensions / Éditeur Markdown pour SPIP · GitLab

You can see 2 (old) screencasts in this thread : Refaire un éditeur à base de CodeMirror + ajouts (#3720) · Issues · spip / porte-plume · GitLab

To summarize:

  • markdown only (it’s a better sustainable core to pool and reuse existing components)
  • use of maintained libraries (TipTap / ProseMirror)
  • for the moment integration inside the SPIP admin, but it’s totally possible to integrate also in the public website
  • manage about all markdown feature
  • but also manage internal spip links (« article123 », « myobject456 »)
  • fully manage SPIP modeles in WYSIWYG : viewing, inserting and modification of existing, by using the YAML description of the modeles inspired by the plugin « Insérer modèles » (totally integrated inside the editor)

Obviously there is still plenty of work to finish, polish (and integrate in the public site too) :slight_smile:

1 « J'aime »