My First Milestone

It was a hard one

Posted by German Kalinec on 12/12/2024 08:17 PM

I released the first update in about a month. It could have taken longer if I didn't decide to cut features out of blogger for this dev cycle because I was tired of staring at it's code.  Still, some really important updates were done and I even reached my first milestone for DiCMS.  There was only one new feature added to blogger, which was also a feature removed from DiCMS.

The Text Editor

When I first started building DiCMS, my main editor of choice was GrapeJS, which is what the system is mainly built around. However I realized that in the case of Blog Posts, GrapesJS was simply too unwieldy. What I needed was a text editor that I could use to concentrate on simply writing and not designing.  Thus, in addition to including the GrapesJS through a BLADE variable, I also added the possibility of doing the same for the text editor. My plan was to place them in a livewire/blade container widget eventually in order to keep all the code together.

As I developed more, I realized that I was working a lot more on the GrapesJS editor than the text editor. I had chosen CKEditor for my text editor because I was actually a big fan of it back in the versions 3 and 4, especially in the open source version. Well, this revision is far more commercial than the original one, but I liked it well enough. I did try Quill and Trix as alternatives, but I simply could not a lot of the features that CKEditor had out of the box for free. What did bug me was the lack of a full screen plugin for it, but it was easily resolved by writing one.

In the end though, there was only a single place where I was using the text editor: in the blog post editor. This meant that there was no real reason why DiCMS should include a text editor; all the editing needed was already being done by GrapesJS. The text editor was really useless outside of that one single blog post editing page. What made the most sense was to move the text editor to a livewire widget in the blogger package. So that is what was done, the text editor is now a feature on Blogger only.  I did make it into a Livewire widget, because it is just so easy to work with that they make sense.  

The text editor was really the last update that I did before release. Before that, all the work was on DiCMS, with two major updates.

Widgets

The interface for widgets was created, with one widget released as the core of DiCMS, the page visitor counter.  The design of it is interesting, but I think I like it. Essentially, widgets are all defined through an interface

interface DiCmsWidget
{

    /**
     * @return string a unique id for this widget, which will be some string (usually the name)
     * with no spaces. Best practice is for the name in lowercase with '-' instead of spaces.
     */
    public static function widgetId(): string;

    /**
     * @return string The name of the widget. No spaces.
     */
    public static function widgetName(): string;

    /**
     * @return string The icon that will be displayed for this widget in
     * the HTML editor
     */
    public static function widgetIcon(): string;

    /**
     * @return string The description of this widget
     */
    public static function widgetDescription(): string;

    /**
     * @return string The HTML representation of the component in "dummy"
     * form, meaning that this should not be functional (as no page is passed)
     * but rather a representation of what the widget should appear to users.
     */
    public static function widgetControlHtml(): string;

    /**
     * @return string The HTML representation of the component that will
     * be directly pasted in the page. There will be an HTML variable, $page
     * available to the widget through Blade.
     */
    public static function widgetHtml(): string;

    /**
     * @return string This function will return the HTML representation of the configuration widget. This
     * widget is a livewire (or blade) component that will be used to configure this
     * widget. It will be set in a specific route as a full-page component.
     */
    public static function widgetConfig(): string;
}

The first three functions are mainly for displaying information about the widget and an id to track it. The magic is in the last three functions. The first one public static function widgetControlHtml(): string; returns an HTML representation of what the widget looks like statically. Mainly this is used to represent the widget statically in the grapesjs editor. The page view counter uses the following simple HTML

<div class="dicms-counter-container">
	<i class="dicms-counter-icon fa fa-eye"></i>
	<span class="dicms-counter-counter">XXXXX</span>
	<p class="dicms-counter-label">Page Views</p>
</div>

Note that there is no inherent CSS customization. Instead, it is left to the user through the GrapesJS interface.  The next function is public static function widgetHtml(): string; which will return the HTML code that will actually be pasted in the page with a single php variable that is guaranteed to be there, $page.  Now, this is where it gets a bit tricky; in most cases if what you're returning a simple html string or even a blade component, it doesn't work if you're using some advanced blade directives or a livewire component.

My guess as to why is that the pasted html does not get processed by BLADE since the act of pasting it is the processing. Now, I have no clue why this is the not the case for BLADE components, but it is certainly the case for livewire components, as the only way to “paste” them through a variable is to run them through blade.  For my proof is that returning this string

public static function widgetHtml(): string
    {
        return "<x-page-views-counter :page=\"\$page\" />";
    }

This works just fine when put on front page. Doing the same for a livewire component will not work.   Instead, it must be wrapped in a render function. I do this for the last function: public static function widgetConfig(): string;  In this function, it will be almost guaranteed to be a livewire widget. Currently, the page visitor widget displays a log of IP addresses that have visited your site and how many times they've viewed it.  When it comes to displaying the widget, it is done like this:

public static function widgetConfig(): string
    {
        return Blade::render("<livewire:page-views-counter-config />");
    }

The widget system is the last part of three parts that make up the last update.

The Plugin System

The plugin system is a collection of three interfaces that define how the plugin interfaces with the core system.

  • DiCmsPlugin: The main entry point for the widget. This is where the Widget administration is mainly done.
  • DiCmsGrapesJsPlugin: This defines a plugin that can be added to GrapesJS
  • DiCmsWidget: This defines a widget that can be added to a page, header, or footer through GrapeJS

I will be going over the plugin system in my next blog post.