jdorn / dorncms-2

A complete rewrite of DornCMS
2 stars 0 forks source link

Twig WYSIWYG editor #1

Open jdorn opened 11 years ago

jdorn commented 11 years ago

DornCMS needs a WYSIWYG editor capable of editing Twig templates. Ideally, any code within Twig tags would show up as plain text in WYSIWYG mode.

The following complexities make this difficult:

Escaping within Twig tags

Twig tags can contain html special characters (like "<" and "&"). These should not be escaped when typed into the WYSIWYG mode

This can probably be fixed with a regular expression replacing all html codes with their unescaped equivalent prior to submitting.

New lines and Twig tags

When an if block is put on it's own line, it should not be wrapped in "

". For example, this would be entered in WYSIWYG mode:

{% if test %}
This is a test
{% endif %}

When going to source mode, most editors would produce this, which is incorrect.

<p>
{% if test %}
</p>
<p>This is a test</p>
<p>
{% endif %}
</p>

In some cases though, it is perfectly valid to wrap Twig tags in html. For example:

<p>
{% include "mytemplate.html.twig" %}
</p>

You can't just do self closing vs. non-self closing since "set" and "extends" should never be wrapped in "

".

This is also valid source. How would this show up in WYSIWYG mode?

<p>
This is 
{% if test %}
</p><p>
{% endif %}
a test
</p>

Possible solutions

<div>{% if test %}this is correct{% endif %}</div>

<div>
{% if test %}
this is not correct
{% endif %}
</div>
<!-- initial source -->
This
{% if test %}
is a
{% endif %}
test.

<!-- shown in WYSIWYG mode -->
<p>
This
</p>
<p>
<span class='twig_tag'>{% if test %}</span>
</p>
<p>
is a
</p>
<p>
<span class='twig_tag'>{% endif %}</span>
</p>
<p>
test.
</p>

<!-- back in source view -->
<p>
This
</p>
{% if test %}
<p>
is a
</p>
{% endif %}
<p>
test.
</p>

As you can see, this also isn't very attractive since it adds a bunch of p tags.

jdorn commented 11 years ago

Because of the complexities involved, this will be the solution:

  1. Split templates into logical segments (e.g. parent template include, variable declarations, macro declarations, blocks). This is already mostly implemented
  2. For each segment provide an editor. Textbox or Text Input for single line things like parent templates. WYSIWYG editor for blocks. Ace editor for everything else.
  3. Allow a block to be wrapped in a special comment tag that forces it to use Ace instead of WYSIWYG. Possibly automatically do this for blocks that contain "{% if" or "{% for" or a few other tags.
  4. Allow editing the entire template with Ace. This will let you add new blocks and things like that.
  5. By default, collapse all non-block editors. This keeps the editing page simple but allows you to edit anything if you want.

This method will work best with templates that follow the best practice of 3 level templates:

  1. One template for the html shell. It has blocks for javascript, stylesheets, meta data, content, etc.
  2. One template for the site layout (or multiple site layouts). Has a header, footer, content, and maybe side bar blocks.
  3. One template for each page. Extends blocks as needed.
jdorn commented 11 years ago

There were some major problems with implementing the above solution. To keep things simple the following rule is used:

This method works best when using 4 levels of templates:

  1. One template for the html shell. It has blocks for javascript, stylesheets, meta data, content, etc.
  2. One template for the site layout (or multiple site layouts). Has a header, footer, content, and maybe side bar blocks.
  3. One template for each page. Fill in content blocks with HTML and one or more include statements.
  4. Page elements (included from within page templates). Standalone HTML.

Only the Page elements will use a WYSIWYG editor since they won't contain blocks. This is the part that will change most often anyway. If you want to change the structure of the page or layout, you need to use the source editor.

Here is an example template structure:

page.html.twig

<!doctype html>
<html>
    <head>
        <title>{% block title %}MySite.com{% endblock %}</title>
        {% block javascript %}{% endblock %}
        {% block stylesheets %}{% endblock %}
        {% block meta %}{% endblock %}
    </head>
    <body>
        {% block body %}
        {% endblock %}
    </body>
</html>

main-layout.html.twig

{% extends "page.html.twig" %}
{% block body %}
    <header>
        MySite.com 
        <nav>
           <ul>
              <li><a href='/'>Home</a></li>
           </ul>
        </nav>
    </header>
    <div id='content'>
    {% block content %}{% endblock %}
    </div>
    <footer>
       {% include "footer.html.twig" %}
    </footer>
{% endblock %}

home.html.twig

{% extends "main-layout.html.twig" %}
{% block content %}
<h1>{% include "home-title.html.twig" %}</h1>

<div class='welcome-message'>
    {% include "home-welcome.html.twig" %}
</div>
{% endblock %}

home-welcome.html.twig

<p>Welcome to my site!</p>

Every template except the last one (an example of a page element) will use the Ace editor. Page elements (anything loaded with an "{% include %}" tag will use a WYSIWYG editor.

To keep templates organized, the default directory structure for templates will be as follows:

+ templates
|    * page.html.twig
|    + layouts
|    |    * main.html.twig
|    + pages
|    |    * home.html.twig
|    + elements
|    |    + home
|    |    |    * welcome_message.html.twig