<?xml version="1.0" encoding="utf-8"?>
<?xml-stylesheet type="text/xsl" href="https://blog.aabech.no/rss/xslt"?>
<rss xmlns:a10="http://www.w3.org/2005/Atom" version="2.0">
  <channel>
    <title>Lars-Erik's blog</title>
    <link>https://blog.aabech.no/</link>
    <description>Ramblings about Umbraco, .net and JavaScript development. With a sprinkle of other stuff.</description>
    <generator>Articulate, blogging built on Umbraco</generator>
    <item>
      <guid isPermaLink="false">1165</guid>
      <link>https://blog.aabech.no/archive/ourumbracowysiwyggrid-100-beta-released/</link>
      <category>umbraco</category>
      <title>Our.Umbraco.WysiwygGrid 1.0.0 beta released</title>
      <description>&lt;p&gt;A while ago I &lt;a href="/archive/the-state-of-wysiwyg-grid-editing-in-umbraco-a-prototype/"&gt;blogged about the state of WYSIWYG in the Umbraco grid editor&lt;/a&gt;. We're now about to add this script to a second and likely third Umbraco 8 site, so I had to generalize and package up the code.&lt;/p&gt;
&lt;p&gt;There's nothing much to hide or earn from here, so I decided to put it up on github and nuget instead of our internal scm and feeds.&lt;/p&gt;
&lt;p&gt;Hope to see some more community members fiddling with it, if nothing else that it inspires the block editor team to make the backoffice experience more similar to the frontend look and feel.&lt;/p&gt;
&lt;p&gt;A definite change from the previous blogpost is that we favor grid settings over inline styling. By slightly modifying the bootstrap view (we use v4 anyway), we can add multiple classes instead of attributes as is done the original views. As such we can have settings like these:&lt;/p&gt;
&lt;p&gt;&lt;img src="https://blog.aabech.no/media/1035/wysiwyg-grid-settings.png" alt="Example grid settings dialog" /&gt;&lt;/p&gt;
&lt;p&gt;Those will generate extra classes named &lt;code&gt;padding-lots&lt;/code&gt; and &lt;code&gt;theme-inverse&lt;/code&gt;.&lt;br /&gt;
Those classes are added to rows or cells in both the backoffice and the front-end.&lt;br /&gt;
By doing some fancy sass include ninjaing, we can hopefully limit the amount of duplication, while still mimicing the front-end as much as possible in the backoffice.&lt;/p&gt;
&lt;p&gt;There are some samples in the github repo if you're unsure how to get started. The SQLCE database is included with a fairly common test username/password. 😇&lt;/p&gt;
&lt;p&gt;Without further ado, here's the nuget and github links:&lt;/p&gt;
&lt;p&gt;&lt;a href="https://github.com/lars-erik/Our.Umbraco.WysiwygGrid"&gt;https://github.com/lars-erik/Our.Umbraco.WysiwygGrid&lt;/a&gt;&lt;br /&gt;
&lt;a href="https://www.nuget.org/packages/Our.Umbraco.WysiwygGrid/1.0.0-beta01"&gt;https://www.nuget.org/packages/Our.Umbraco.WysiwygGrid/1.0.0-beta01&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Hope you enjoy it, and as usual, hope for a good discussion or feedback from the community!&lt;/p&gt;
</description>
      <pubDate>Thu, 23 Apr 2020 12:09:36 Z</pubDate>
      <a10:updated>2020-04-23T12:09:36Z</a10:updated>
    </item>
    <item>
      <guid isPermaLink="false">1164</guid>
      <link>https://blog.aabech.no/archive/the-state-of-wysiwyg-grid-editing-in-umbraco-a-prototype/</link>
      <category>umbraco</category>
      <title>The state of WYSIWYG grid editing in Umbraco - a prototype</title>
      <description>&lt;h2&gt;The state of the grid&lt;/h2&gt;
&lt;p&gt;Since the grid was launched at the CG talk &amp;quot;The sky is the limit&amp;quot; back in 2015 (i think),
it has been a joy to use for editors, designers and developers alike.
Granted, there's been the other feature that could've gotten more love (configuration and settings), but generally it does the job swell.&lt;br /&gt;
However, it's still just a white canvas with &amp;quot;settings applied&amp;quot;.&lt;br /&gt;
&lt;a href="https://twitter.com/aaantoinee"&gt;Antoine&lt;/a&gt; made &lt;a href="https://our.umbraco.com/packages/backoffice-extensions/lepainter/"&gt;LePainter&lt;/a&gt; back in 2015, but likely didn't get much traction.&lt;br /&gt;
I was just told about it today by &lt;a href="https://twitter.com/callumbwhyte"&gt;Callum&lt;/a&gt;. Shame on me for not watching the package space enough, how embarrasing. 😳&lt;/p&gt;
&lt;p&gt;Anyway...&lt;/p&gt;
&lt;h2&gt;Why should we care&lt;/h2&gt;
&lt;p&gt;Recently, I've been in lots of discussions; near battles IMO; about which CMS to sell to our customers.&lt;br /&gt;
The feedback is that editors wonder why what they see while editing does not match what they see in the front-end.
We do work with another CMS where the backoffice experience has a near 1:1 layout and design with the front-end.
As developers, we tend to think structured data is the better solution. Think nested- and stacked content.
I tend to agree. But in a sales meeting, those arguments are total losing arguments. A competing agency will bury you when they oversell the fancy editing experience. Even though the not-so-apparent technical features of the competing CMS are totally useless.&lt;br /&gt;
And I do agree - the editing experience is what Umbraco likes to sell as well!&lt;/p&gt;
&lt;h2&gt;What can we do?&lt;/h2&gt;
&lt;p&gt;The current HQ efforts are working on the &amp;quot;block based&amp;quot; editor. It's been going on for the better part of a year, but the publicly available information is mostly &lt;a href="https://github.com/umbraco/rfcs/blob/master/cms/0012-rfc-block%20editor.md"&gt;just an RFC with screenshots&lt;/a&gt; looking like stacked / nested content, and that's it. The technical aspects seem super, but there's nothing much (but text) about the general editing experience. Also, and I know this is a hot take, editors DO want to see three columns in the editor when it ends up three columns in the front-end.&lt;/p&gt;
&lt;p&gt;Hopefully, as mentioned in the RFC, it can act as a stepping stone towards the &amp;quot;Grid 2.0&amp;quot; (which we started work on at the retreat &lt;em&gt;two&lt;/em&gt; years ago).&lt;/p&gt;
&lt;p&gt;But as far as I'm concerned, this could just as well end up never happening. The effort is not very visible, Project UniCore 🦄 has (rightly) high priority, and in the mean time we're stuck with Grid 1.0, or maybe, hopefully, a rumored &lt;em&gt;commercial&lt;/em&gt; package called Bento by the eminent &lt;a href="https://twitter.com/pgregorynz"&gt;Peter Gregory&lt;/a&gt; and his colleagues at KØBEN Digital.&lt;/p&gt;
&lt;h2&gt;A prototype&lt;/h2&gt;
&lt;p&gt;So back using Grid 1.0 for projects to be delivered imminently, I've started doing some prototypes for something similar to what LePainter did for early v7 projects.&lt;/p&gt;
&lt;p&gt;I asked the community if it was madness or worth pursuing, and the general feedback is that it's both. Hence this blog post to explore it some more, and hopefully gather some more feedback or at least provide feedback to the block editor team. (Hope they receive it. 😁)&lt;/p&gt;
&lt;p&gt;Here's a quick little preview of what I've been doing so far:&lt;/p&gt;
&lt;iframe width="560" height="315" src="https://www.youtube-nocookie.com/embed/B6LLiO116jc" frameborder="0" allow="accelerometer; autoplay; encrypted-media; gyroscope; picture-in-picture" allowfullscreen&gt;&lt;/iframe&gt;
&lt;h2&gt;The issues&lt;/h2&gt;
&lt;p&gt;Actually getting the styling into the grid is &amp;quot;just&amp;quot; a matter of including a few pagefuls of JavaScript and a limited and scoped CSS file in a package.manifest file for the site. Both classes and styles are applied as expected, and with some due dilligence it doesn't look half bad.&lt;/p&gt;
&lt;p&gt;The biggest issue I have is that the cells and controls are styled white, and while styling one have to mind not messing up the GUI text like &amp;quot;Settings applied&amp;quot;.&lt;/p&gt;
&lt;p&gt;I attempted to lessen the opacity of the cells and controls, and it works to a degree. The minute one adds a background image however, the entire thing starts to crumble. How to keep the WYSIWYG experience while still seeing the GUI? One could fantasize about doing an average color sample of the image and toggling between white and black text, maybe? Could be done in a short hacking sprint...&lt;br /&gt;
Could just keep it fairly white like I've done in the prototype.
Could keep just the active rows white. This is where I start struggling. 😳&lt;/p&gt;
&lt;p&gt;To be frank, the biggest problem lies in the fact that the &amp;quot;Add content&amp;quot; button is &lt;em&gt;in&lt;/em&gt; the grid. Other CMSes have drag drop functionality from a menu over to the side. It could possibly still just be white or slightly transparent. The last problem then is all those &amp;quot;settings applied&amp;quot; and empty cells with the other type of &amp;quot;Add content&amp;quot; button.&lt;/p&gt;
&lt;p&gt;I can't help but think this is all within grasp, albeit just out of my limited back-ender reach. 😆&lt;/p&gt;
&lt;h2&gt;The settings dialog issues&lt;/h2&gt;
&lt;p&gt;The settings dialog is a chapter of itself. It's a mystery to me why we still have a concept of individual &amp;quot;prevalue editors&amp;quot; in Umbraco. Property editors have the same model, and can be sneaked in there by just providing a full path.&lt;/p&gt;
&lt;p&gt;However, as experienced when working on &lt;a href="http://blog.aabech.no/archive/our-umbraco-community-contentlist-10-beta-released/"&gt;our ContentList package&lt;/a&gt;, nesting property editors using built-in directives wreaks total havok on the styling. There's some grey background and drop shadows - that I haven't seen being actively used anywhere. It's generally just a mystery, and a huge candidate for backoffice re-work.&lt;/p&gt;
&lt;p&gt;Also, for instance the slider property editor does look a bit weird when used as a setting editor. I do hope that those things will get an overhaul and are made more uniform sooner or later.&lt;/p&gt;
&lt;p&gt;I'll just leave that hanging, since I know (and appreciate) there are several HQ and community efforts going on to clean things up.&lt;/p&gt;
&lt;h2&gt;The code&lt;/h2&gt;
&lt;p&gt;Since I managed to &lt;a href="https://github.com/umbraco/Umbraco-CMS/pull/2639/commits/76c924fbaa3da89d9865d9ec405e6dbb123852e3"&gt;sneak in a few new events in the grid&lt;/a&gt;, making it work was a matter of hooking into the &amp;quot;grid.initialized&amp;quot; event and start watching the model. There might be some performance issues with large grids since it's a deep watch, but with todays computers that might be irrational over engineering to think as well.&lt;/p&gt;
&lt;p&gt;It adds the configured styles as expected.&lt;br /&gt;
For the configuration, it just adds the value of the configuration setting called &amp;quot;class&amp;quot;. If there's more it concats the setting key with the setting value, delimited by a dash.&lt;/p&gt;
&lt;p&gt;You can scrutinize the JavaScript here, or in &lt;a href="https://gist.github.com/lars-erik/9dbf8f4004121c8eb109423b814af34c"&gt;this gist&lt;/a&gt;.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;angular.module(&amp;quot;umbraco&amp;quot;).run([&amp;quot;eventsService&amp;quot;, function(eventsService) {
    function findModelScope(scope) {
        if (!scope) {
            return null;
        }
        if (scope.model) {
            return scope;
        }
        return findModelScope(scope.$parent);
    }

    function isProtectedClass(className) {
        return className === &amp;quot;umb-row-inner&amp;quot; ||
            className === &amp;quot;umb-cell-inner&amp;quot; ||
            className.substr(0, 2) === &amp;quot;ng-&amp;quot; ||
            className.substr(0, 2) === &amp;quot;ui-&amp;quot;;
    }

    function addClasses(element, gridItem) {
        function classNameFromConfig(e) {
            if (e === &amp;quot;class&amp;quot;) {
                return gridItem.config[e];
            } else {
                return e + &amp;quot;-&amp;quot; + gridItem.config[e];
            }
        }

        var classes = (element.className || &amp;quot;&amp;quot;).split(/\s+/);
        var newClasses = classes.filter(isProtectedClass);
        var nameClass = (gridItem.name || &amp;quot;&amp;quot;).toLowerCase().replace(&amp;quot; &amp;quot;, &amp;quot;-&amp;quot;);
        var configClasses = Object.keys(gridItem.config || {}).map(classNameFromConfig);
        newClasses.push(nameClass);
        newClasses = newClasses.concat(configClasses);
        element.className = newClasses.join(&amp;quot; &amp;quot;);
    }

    function addStyles(element, gridItem) {
        function styleFromKeyPair(e) {
            return e + &amp;quot;:&amp;quot; + gridItem.styles[e];
        }

        var stylesValues = Object.keys(gridItem.styles || {}).map(styleFromKeyPair);
        element.style = stylesValues.join(&amp;quot;;&amp;quot;);
    }

    eventsService.on(&amp;quot;grid.initialized&amp;quot;,
        function(evt, data) {
            var modelScope = findModelScope(data.scope);
            var model = modelScope.model;
            var jqEl = data.element;
            var el = data.element.get(0);
            jqEl.addClass(&amp;quot;stylized-grid&amp;quot;);

            modelScope.$watch(
                &amp;quot;model&amp;quot;,
                function () {
                    var areaElements = el.getElementsByClassName(&amp;quot;umb-column&amp;quot;);
                    if (areaElements.length === 0) {
                        return;
                    }
                    model.value.sections.forEach(function (area, ai) {
                        var rowElements = areaElements[ai].getElementsByClassName(&amp;quot;umb-row-inner&amp;quot;);
                        area.rows.forEach(function (row, ri) {
                            var rowElement = rowElements[ri];
                            addClasses(rowElement, row);
                            addStyles(rowElement, row);

                            var cellElements = rowElement.getElementsByClassName(&amp;quot;umb-cell-inner&amp;quot;);
                            row.areas.forEach(function(cell, ci) {
                                addClasses(cellElements[ci], cell);
                                addStyles(cellElements[ci], cell);
                            });
                        });
                    });
                },
                true
            );
        });

}]);
&lt;/code&gt;&lt;/pre&gt;

&lt;h2&gt;The CSS&lt;/h2&gt;
&lt;p&gt;To not interfere with any other backoffice styling, the script adds the class &amp;quot;stylized-grid&amp;quot; to the grid container. Here's the (S)CSS I used to make things more transparent:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;.umb-grid.stylized-grid { 

    .umb-cell-content {
        background-color: rgba(255, 255, 255, .8);
    }

    .umb-cell-content:hover {
        background-color: rgba(255, 255, 255, 1);
    }

    .umb-cell-content.-has-editors {
        background-color: rgba(255, 255, 255, .8);
    }

    .umb-cell-content.-has-editors:hover {
        background-color: rgba(255, 255, 255, 1);
    }

    .umb-grid-add-more-content {
        background-color: rgba(255, 255, 255, 1);
    }

    .umb-control-bar, .umb-grid-has-config {
        font-family: Lato, Helvetica Neue, Helvetica, Arial, sans-serif !important;
    }

    iframe {
        background-color: transparent;
    }

    @import &amp;quot;../../../Assets/grid&amp;quot;;
}
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;The import at the bottom is the sass that styles our individual components in the front-end, and that should be reflected in the backoffice. &lt;/p&gt;
&lt;h2&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;We'll be diving into deep water and testing this out on a real customer. I'm a bit weary, but we need to get the experience.&lt;/p&gt;
&lt;p&gt;I do hope I've been able to provide some inspiration, and that WYSIWYG editing in Umbraco might get the renaissance (I believe) it deserves.&lt;/p&gt;
&lt;p&gt;Feel free to drop your comments below or ping me on Twitter or Slack!&lt;br /&gt;
Also happy to continue the discussion on our or github, but not sure the best way forward, if any.&lt;/p&gt;
</description>
      <pubDate>Fri, 03 Apr 2020 13:26:14 Z</pubDate>
      <a10:updated>2020-04-03T13:26:14Z</a10:updated>
    </item>
    <item>
      <guid isPermaLink="false">1091</guid>
      <link>https://blog.aabech.no/archive/templatable-grid-for-umbraco/</link>
      <title>Templatable grid for Umbraco</title>
      <description>&lt;p&gt;Have you ever created several documents in a row and set up more or less the same grid layout for each page? Becomes a hassle after a few pages, doesn't it? Distress no more! &lt;a href="https://www.nuget.org/packages/Our.Umbraco.TemplatableGrid"&gt;Here's a package&lt;/a&gt; that let's you create default layouts for your grids to get a flying start. &lt;/p&gt;
&lt;p&gt;TL;DR: &lt;a href="#video"&gt;There's a video at the bottom&lt;/a&gt;.&lt;/p&gt;
&lt;h3&gt;Word to the wise&lt;/h3&gt;
&lt;p&gt;This is an alpha, and it's probably still got some quirks. We use it in production for all our newer sites, so it should be quite safe. However, if you're going to modify your existing grids:&lt;br /&gt;
&lt;strong&gt;MAKE SURE YOU NOTE DOWN THE CONFIGURATION&lt;/strong&gt;! &lt;br /&gt;
The data type will reset back to the default grid settings when you change the property editor.&lt;br /&gt;
You could probably just change the property editor alias in the database, but I'll leave that for the savvy ones.&lt;br /&gt;
There's one other drawback, namely that it cannot be set up properly when using the document type editor to edit the datatype.&lt;/p&gt;
&lt;h3&gt;Usage&lt;/h3&gt;
&lt;p&gt;In addition to the built-in prevalues for layout and RTE configuration, there is an additional prevalue for the default layout. Add rows and editors like in a regular document, until you've got a nice starting point for all pages.&lt;br /&gt;
&lt;strong&gt;NB!&lt;/strong&gt; When changing the layout configuration, especially renaming things, you may have to use the &amp;quot;Reset layout&amp;quot; button to be able to create a new layout.&lt;/p&gt;
&lt;h3&gt;Core potential&lt;/h3&gt;
&lt;p&gt;I've made a PR for this to be part of the core since I believe it's a pretty useful feature for many sites. Feel free to &lt;a href="http://issues.umbraco.org/issue/U4-8444"&gt;give the issue a vote&lt;/a&gt; if you'd like to see it built-in too. By &amp;quot;popular&amp;quot; demand, I decided to release it as a package for better community support. Thanks, &lt;a href="https://twitter.com/leekelleher"&gt;Lee&lt;/a&gt;! :)&lt;/p&gt;
&lt;p&gt;&lt;a id="video"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h3&gt;Oh shut up, just show me how it works&lt;/h3&gt;
&lt;p&gt;Aww, OK. At least I hope I got some proper SEO out of the babble above. :)&lt;/p&gt;
&lt;iframe width="560" height="315" src="https://www.youtube.com/embed/2Ie7elvBsRw" frameborder="0" allowfullscreen&gt;&lt;/iframe&gt;</description>
      <pubDate>Wed, 28 Sep 2016 20:33:56 Z</pubDate>
      <a10:updated>2016-09-28T20:33:56Z</a10:updated>
    </item>
    <item>
      <guid isPermaLink="false">1084</guid>
      <link>https://blog.aabech.no/archive/building-a-text-flow-editor-for-the-grid/</link>
      <title>Building a text flow editor for the grid</title>
      <description>&lt;p&gt;I'm continuing &lt;a href="/archive/separating-data-from-content-in-umbraco"&gt;my journey in search of a good separation&lt;/a&gt;  between content and layout in Umbraco. I'm fairly confident it should be quite quick to get a prototype together. Even when blogging while doing it. Let's see if we can't create a grid editor which can be configured to show another rich text editor property in the document. It should also have a way to limit said content. Say &lt;em&gt;n&lt;/em&gt; root elements from the HTML.&lt;/p&gt;
&lt;p&gt;In our sites, we've modified the grid slightly. There's &lt;a href="http://issues.umbraco.org/issue/U4-8444"&gt;a PR hoping to be pulled&lt;/a&gt; to the core. (&lt;a href="/archive/templatable-grid-for-umbraco/"&gt;Now also a package&lt;/a&gt;) It makes it possible to create a &amp;quot;template&amp;quot; for new grids of a type. Whenever the user creates a &amp;quot;Page&amp;quot;, it has a grid with a header, a summary and a body. It's also got a column for widgets and hullabaloo's. The template is just the grid on the data type settings page. It's just another setting. If I put that on tab number 2, then in many cases, editors wouldn't even have to relate to the layout. They'll tackle that when they &lt;em&gt;do&lt;/em&gt; need to add a form or other functionality.&lt;/p&gt;
&lt;p&gt;So with this new editor, I'm hoping to swap out the header and the rich text editors with pointers to some structured fields instead. As an added challenge, my eminent colleague and world class UX expert Stig Hammer insists this will only be used by 5% of all editors. It'll be too abstract and complex for the general crowd to use. We'll see. We might just be surprised.&lt;/p&gt;
&lt;h3&gt;Follow along?&lt;/h3&gt;
&lt;p&gt;The &lt;a href="https://github.com/lars-erik/our.umbraco.flowingtext"&gt;code for this article is on GitHub&lt;/a&gt;. There's a chance I'll miss an update or two in the samples here, but there's working code in the repo. I'll also omit large setup fragments and other things that obscure the valuable bits.&lt;/p&gt;
&lt;h3&gt;First iteration: UI prototype&lt;/h3&gt;
&lt;p&gt;I'd like to start off by having a placeholder in the grid. It should make use of grid editor settings (a cog for grid editors) and two settings where we'll use some one-off &amp;quot;virtual&amp;quot; property editors. We'll stick with the &amp;quot;nerdy&amp;quot; UX for now and see about some sugar later.&lt;/p&gt;
&lt;p&gt;Except for the views, it should pretty much just be package.manifest configuration. Here's what I'm starting out with:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;{
    &amp;quot;gridEditors&amp;quot;: [
        {
            &amp;quot;name&amp;quot;: &amp;quot;Flowing text&amp;quot;,
            &amp;quot;alias&amp;quot;: &amp;quot;flowingText&amp;quot;,
            &amp;quot;view&amp;quot;: &amp;quot;/App_Plugins/FlowingText/editor.html&amp;quot;,
            &amp;quot;icon&amp;quot;: &amp;quot;icon-article&amp;quot;,
            &amp;quot;config&amp;quot;: {
                &amp;quot;settings&amp;quot;: {
                    &amp;quot;source-property&amp;quot;: {
                        &amp;quot;label&amp;quot;: &amp;quot;Source property&amp;quot;,
                        &amp;quot;key&amp;quot;: &amp;quot;source-property&amp;quot;,
                        &amp;quot;description&amp;quot;: &amp;quot;The source for the text&amp;quot;,
                        &amp;quot;view&amp;quot;: &amp;quot;/umbraco/views/propertyeditors/dropdown/dropdown.html&amp;quot;,
                        &amp;quot;config&amp;quot;: {
                            &amp;quot;items&amp;quot;: {
                                &amp;quot;dummy&amp;quot;: &amp;quot;Dummy&amp;quot;,
                                &amp;quot;dummy2&amp;quot;: &amp;quot;Dummy 2&amp;quot;
                            }
                        }
                    },
                    &amp;quot;fragments&amp;quot;: {
                        &amp;quot;label&amp;quot;: &amp;quot;Fragments to show&amp;quot;,
                        &amp;quot;key&amp;quot;: &amp;quot;fragments&amp;quot;,
                        &amp;quot;description&amp;quot;: &amp;quot;How many paragraphs or fragments to show&amp;quot;,
                        &amp;quot;view&amp;quot;: &amp;quot;/umbraco/views/propertyeditors/integer/integer.html&amp;quot;,
                        &amp;quot;config&amp;quot;: {

                        }
                    }
                }
            }
        }
    ]
}
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;We'll just stub up a simple view for now to see if the settings dialog works as expected.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&amp;lt;div&amp;gt;Some day I'll flow like a river!&amp;lt;/div&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;I've changed the Fanoe Text Page to have an RTE called &amp;quot;Body Text&amp;quot; on a tab before the one with the &amp;quot;Content&amp;quot; grid on it. I've changed the tab names so the body is in &amp;quot;Content&amp;quot; and the grid is in &amp;quot;Layout&amp;quot;.&lt;/p&gt;
&lt;p&gt;Jumping into the layout and the grid, I've enabled &amp;quot;Flowing text&amp;quot; for a couple of the row defs. Adding one and clicking the cog gives me this:&lt;/p&gt;
&lt;p&gt;&lt;img src="https://blog.aabech.no/media/1007/first-iteration.png" alt="Grid editor with dummy template and settings based on virtual property editors" /&gt;&lt;/p&gt;
&lt;p&gt;I'd say that's a feasible prototype to start with, so let's see if we can feed the properties of the document into that dropdown and show some text.&lt;/p&gt;
&lt;h3&gt;Second Iteration: Live data&lt;/h3&gt;
&lt;p&gt;Since the &amp;quot;property editors&amp;quot; we used for the settings are just pointing to the views and not the property editor defintions themselves, we're free to configure them as we want. Fortune wants it so that the entire graph from the package.manifest makes its way to the controllers we add to our grid editors. Umbraco also has this &lt;a href="https://umbraco.github.io/Belle/#/api/umbraco.services.editorState"&gt;nice little service called editorState&lt;/a&gt;. It holds the current entity of the main editor area. In our case - the document.&lt;/p&gt;
&lt;p&gt;I'll do this test-driven for kicks. Here's the stub of a unit test that verifies our code will populate the dropdown with the properties in the document. I've omitted some setup stuff, but you can see the entire test in the GitHub repo.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;/// &amp;lt;reference path=&amp;quot;/Umbraco/lib/angular/1.1.5/angular.js&amp;quot; /&amp;gt;
/// &amp;lt;reference path=&amp;quot;/Umbraco/lib/angular/1.1.5/angular-mocks.js&amp;quot; /&amp;gt;
/// &amp;lt;reference path=&amp;quot;../flowingtext.js&amp;quot; /&amp;gt;
(function () {

    describe(&amp;quot;Flowing text grid editor&amp;quot;, function () {

        var rootScope,
            scope,
            controllerFactory,
            defaultEditorState = { ... },
            model = { ... };

        beforeEach(module(&amp;quot;umbraco&amp;quot;));
        beforeEach(
            inject(function ($controller, $rootScope) {
                controllerFactory = $controller;
                rootScope = $rootScope;
                scope = rootScope.$new();
                scope.control = angular.extend({}, model);
            })
        );

        it(&amp;quot;populates the source property options with the properties of the document&amp;quot;, function () {

            var sourcePropertySetting = scope.control.editor.config.settings[&amp;quot;source-property&amp;quot;];

            controllerFactory(&amp;quot;our.umbraco.flowingtext.controller&amp;quot;, {
                &amp;quot;$scope&amp;quot;: scope,
                &amp;quot;editorState&amp;quot;: angular.extend({}, defaultEditorState)
            }),

            expect(sourcePropertySetting.config.items).toEqual({
                &amp;quot;bodyText&amp;quot;: &amp;quot;Body text&amp;quot;,
                &amp;quot;content&amp;quot;: &amp;quot;Content&amp;quot;
            });

        });

    });

}());
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;I want to verify that &amp;quot;content&amp;quot; isn't in that list, but I'll leave that for a later iteration for now. If you can't guess why i'd like that, take 2 minutes to think about that right now. ;)&lt;/p&gt;
&lt;p&gt;In any case, let's add the controller and hook it up to our view and see where that takes us:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;(function () {
    var umbraco;

    function FlowingTextController(scope, editorState) {
        var model = scope.control,
            ti, pi, 
            tab,
            prop,
            items = {},
            sourcePropertySetting = model.editor.config.settings[&amp;quot;source-property&amp;quot;];

        sourcePropertySetting.config = angular.extend(
            sourcePropertySetting.config,
            { items: items }
        );

        for (ti = 0; ti &amp;lt; editorState.current.tabs.length; ti++) {
            tab = editorState.current.tabs[ti];
            for (pi = 0; pi &amp;lt; tab.properties.length; pi++) {
                prop = tab.properties[pi];
                items[prop.alias] = prop.label;
            }
        }
    }

    function initializeUmbraco() {} // Fancy testing requirements inside

    initializeUmbraco();
    umbraco.controller(&amp;quot;our.umbraco.flowingtext.controller&amp;quot;, [
        &amp;quot;$scope&amp;quot;,
        &amp;quot;editorState&amp;quot;,
        FlowingTextController
    ]);
}());
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;And the view:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&amp;lt;div ng-controller=&amp;quot;our.umbraco.flowingtext.controller&amp;quot;&amp;gt;
    Some day I'll flow like a river, really!
&amp;lt;/div&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;And don't forget the package.manifest like I did. :)&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;...
&amp;quot;javascript&amp;quot;: [
    &amp;quot;~/App_Plugins/FlowingText/flowingtext.js&amp;quot;
],
&amp;quot;gridEditors&amp;quot;: [
...
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Now how does it look when we pop the settings for the editor? On second thought, let's skip the click-the-cog step for new editors. Should be a quick fix....&lt;/p&gt;
&lt;p&gt;We'll add an empty function to the test variable list:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;editGridItemSettings = function() {};
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;And we'll add it to the root scope in the &lt;code&gt;beforeEach(inject())&lt;/code&gt; call:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;rootScope.editGridItemSettings = editGridItemSettings;
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Add a tad to the controller&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;if (!model.config) {
    model.config = {};
    scope.editGridItemSettings(model, 'control');
}
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Et voilà, when we now add a &amp;quot;Flowing text&amp;quot; to the grid, it has all the properties we could want in it's list. And the settings dialog show by default.&lt;/p&gt;
&lt;p&gt;&lt;img src="https://blog.aabech.no/media/1008/second-iteration.png" alt="Grid editor with dummy template and settings based on virtual property editors" /&gt;&lt;/p&gt;
&lt;p&gt;We should probably try to remove a few irrelevant properties. Not to mention the &amp;quot;Content&amp;quot; one. (What? You didn't realise why yet? Go think about it some more! Think Inception...)&lt;/p&gt;
&lt;p&gt;I'm happy for now though. Let's see if we can't make it so that when we select &amp;quot;Body text&amp;quot; the entire contents of the rich text editor is shown in our preview.&lt;/p&gt;
&lt;h3&gt;Third iteration: Present the text&lt;/h3&gt;
&lt;p&gt;First off, until now I've tried hard to keep this as compatible with property editors as I could. I'll get sloppy now, but I promise I'll return with a post about that, or just fix this up. The code should be pretty similar, if not the same for Archetype or Nested Content versions. So anyway, here's me getting sloppy. I'm sorry.&lt;/p&gt;
&lt;p&gt;We'll need to watch the editor's config. When we submit the settings dialog, the root &lt;code&gt;scope.control.config&lt;/code&gt; will be given key/value pairs from the settings dialog. For a property-editor in NC or Archetype, you'd have to watch &lt;code&gt;scope.model.config&lt;/code&gt;. So you see where the sloppyness takes place.&lt;/p&gt;
&lt;p&gt;I've also cached up the properties in the loop where we populate the dropdown:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;for (pi = 0; pi &amp;lt; tab.properties.length; pi++) {
    prop = tab.properties[pi];
    properties.push(prop); // Remember to declare it...
    items[prop.alias] = prop.label;
}
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Let's not get ahead of ourselves, though. We add a value to the &lt;code&gt;defaultEditorState&lt;/code&gt;'s bodyText property, then we go ahead and assert it's set as &lt;code&gt;model.value&lt;/code&gt; when we digest:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;    it(&amp;quot;sets the value when a source property is selected&amp;quot;, function() {
        var expectedText = &amp;quot;&amp;lt;p&amp;gt;The expected value&amp;lt;/p&amp;gt;&amp;quot;,
            initialText = &amp;quot;&amp;lt;p&amp;gt;Unexpected value&amp;lt;/p&amp;gt;&amp;quot;
            property = defaultEditorState.current.tabs[0].properties[0];

        property.value = initialText;

        scope.control.config = {
            &amp;quot;source-property&amp;quot;: &amp;quot;bodyText&amp;quot;
        };
        scope.$digest();

        // we have to do double digest here to simulate update to the text
        property.value = expectedText;
        scope.$digest();

        expect(scope.control.value).toBe(expectedText);

    });
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;So as we expect, whenever &lt;code&gt;control.config[&amp;quot;source-property&amp;quot;]&lt;/code&gt; changes, the editor value changes to the value of that property.&lt;/p&gt;
&lt;p&gt;Here's the satisfying code:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;        scope.$watch(&amp;quot;control.config['source-property']&amp;quot;, function() {
            if (model.config[&amp;quot;source-property&amp;quot;]) {
                sourceProperty = $.grep(properties, function(p) {
                    return p.alias === model.config[&amp;quot;source-property&amp;quot;];
                })[0];

                if (watch) {
                    watch(); // unregister if source changes
                }

                watch = scope.$watch(function() {
                    return sourceProperty.value;
                }, function() {
                    model.value = sourceProperty.value;
                });
            }
        });
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;And the view can now show the value:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&amp;lt;div ng-controller=&amp;quot;our.umbraco.flowingtext.controller&amp;quot;
     ng-bind-html-unsafe=&amp;quot;control.value&amp;quot;&amp;gt;
&amp;lt;/div&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;&lt;img src="https://blog.aabech.no/media/1009/third-iteration.png" alt="Editor showing body text and debug json" /&gt;&lt;/p&gt;
&lt;p&gt;Those of you still awake will notice a little gray json snippet there. I got desperate for a little while, so I added the universal debugging tool for any angular developer:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&amp;lt;div ng-controller=&amp;quot;our.umbraco.flowingtext.controller&amp;quot; 
     ng-bind-html-unsafe=&amp;quot;control.value&amp;quot;&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;pre&amp;gt;{{control | json}}&amp;lt;/pre&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;We're more or less done with a nice little mirroring grid editor now. It can actually already replace my header grid editor with something mirroring a single document property for the header. We just need a razor view. I know you guys know how to fix that, so let's see if we can't make it do what we set out to now.&lt;/p&gt;
&lt;h3&gt;Forth iteration: Bringing it all together&lt;/h3&gt;
&lt;p&gt;We're almost there now, and it's getting late. Let's just jump straight at the next test:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;    it(&amp;quot;gets a limited amount of fragments&amp;quot;, function () {
        var expectedText =
                &amp;quot;&amp;lt;h1&amp;gt;Expected header&amp;lt;/h1&amp;gt;&amp;quot; +
                &amp;quot;&amp;lt;p&amp;gt;The expected value&amp;lt;/p&amp;gt;&amp;quot;,
            allText =
                expectedText +
                &amp;quot;&amp;lt;p&amp;gt;Unexpected value&amp;lt;/p&amp;gt;&amp;quot;,
            property = defaultEditorState.current.tabs[0].properties[0];

        property.value = allText;

        scope.control.config = {
            &amp;quot;source-property&amp;quot;: &amp;quot;bodyText&amp;quot;,
            &amp;quot;fragments&amp;quot;: 2
        };
        scope.$digest();

        expect(scope.control.value).toBe(expectedText);
    });
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;I've added some more fragments to the other property. We configure it to show only two fragments. So we expect a heading and a paragraph. Here's a quite changed controller. I'll excuse myself and claim I'll come back and refactor it. Hope you can make sense of it.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;    function FlowingTextController(scope, editorState) {
        var model = scope.control,
            ti, pi, 
            tab,
            prop,
            items = {},
            properties = [],
            watch,
            sourceProperty,
            sourcePropertySetting = model.editor.config.settings[&amp;quot;source-property&amp;quot;];

        // We now update the value from two watches, so the function is extracted
        function updateFlow() {
            var elements,
                begin = 0,
                end = begin + model.config.fragments;
            if (!sourceProperty) {
                return;
            }
            elements = $.grep($(sourceProperty.value), function(e) {
                return !(e instanceof Text);
            });
            model.value =
                $(&amp;quot;&amp;lt;div&amp;gt;&amp;quot;).append(
                    $(Array.prototype.slice.call(elements, begin, end))
                )
                .html();
        }

        sourcePropertySetting.config = angular.extend(
            sourcePropertySetting.config,
            { items: items }
        );

        for (ti = 0; ti &amp;lt; editorState.current.tabs.length; ti++) {
            tab = editorState.current.tabs[ti];
            for (pi = 0; pi &amp;lt; tab.properties.length; pi++) {
                prop = tab.properties[pi];
                properties.push(prop);
                items[prop.alias] = prop.label;
            }
        }

        // Initialize an empty config
        if (!model.config) {
            model.config = {};
            scope.editGridItemSettings(model, 'control');
        }

        // Watch the fragments too
        scope.$watch(&amp;quot;control.config['fragments']&amp;quot;, updateFlow);

        scope.$watch(&amp;quot;control.config['source-property']&amp;quot;, function() {
            if (model.config[&amp;quot;source-property&amp;quot;]) {
                sourceProperty = $.grep(properties, function(p) {
                    return p.alias === model.config[&amp;quot;source-property&amp;quot;];
                })[0];

                if (watch) {
                    watch();
                }

                watch = scope.$watch(function() {
                    return sourceProperty.value;
                }, updateFlow);
            }
        });
    }
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;There are some polish needed here to adher to all practices. But again, I'll excuse myself. It's almost 12 am. :) Running this code now let's us add the first few fragments of the body text over and over again in the grid. I've put some text from slipsum.com in the body text and had a go with it (header's mine for motivation though):&lt;/p&gt;
&lt;p&gt;&lt;img src="https://blog.aabech.no/media/1010/fourth-iteration.png" alt="Editor with first fragments in action" /&gt;&lt;/p&gt;
&lt;p&gt;I can almost feel it now. Let's do one more iteration and see if we can't get that second editor to show the rest of the body text instead of the same first parts.&lt;/p&gt;
&lt;h3&gt;Fifth iteration: Making it flow&lt;/h3&gt;
&lt;p&gt;We'll jump right into the next test again:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;    it(&amp;quot;gets the fragments remaining from the previous ones&amp;quot;, function() {
        var expectedText =
                &amp;quot;&amp;lt;p&amp;gt;Expected paragraph&amp;lt;/p&amp;gt;&amp;quot; +
                &amp;quot;&amp;lt;p&amp;gt;Another expected paragraph&amp;lt;/p&amp;gt;&amp;quot;,
            allText =
                &amp;quot;&amp;lt;h1&amp;gt;Unexpected header&amp;lt;/h1&amp;gt;&amp;quot; +
                expectedText +
                &amp;quot;&amp;lt;p&amp;gt;Unexpected value&amp;lt;/p&amp;gt;&amp;quot;,
            property = defaultEditorState.current.tabs[0].properties[0];

        property.value = allText;

        scope.control.config = {
            &amp;quot;source-property&amp;quot;: &amp;quot;bodyText&amp;quot;,
            &amp;quot;fragments&amp;quot;: 2
        };

        gridModel.value.sections[0].rows[0].areas[0].controls = [
            {
                editor: {
                    alias: &amp;quot;flowingText&amp;quot;
                },
                config: {
                    &amp;quot;source-property&amp;quot;: &amp;quot;bodyText&amp;quot;,
                    fragments: 1
                }
            },
            scope.control
        ];

        scope.$digest();

        expect(scope.control.value).toBe(expectedText);
    });

});
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;I've added the grid model to the root scope. It'll be there on &lt;code&gt;scope.model&lt;/code&gt; in the controller. So this test inserts another editor before the one under test. It shows one fragment, so our instance under test should show the two next ones.&lt;/p&gt;
&lt;p&gt;The code to satisfy this is by far the most incompatible with Archetype and Nested Context. I hope some of you guys find this interesting enough to hunt for a nice solution for those. Give me a shout if you need a hand.&lt;/p&gt;
&lt;p&gt;Again, there's a lot of code omitted by now, but you can find it all on GitHub.&lt;/p&gt;
&lt;p&gt;For the controller, I've added this big traversing method that finds the previous editors' fragment counts. It could most definitely be prettified, but I'm in a hurry to get this post to market and myself to bed. Here's the entire nested mess of it:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;        function alreadyRenderedFragments() {
            var sections = scope.model.value.sections,
                section, si, row, ri, area, ai, control, ci,
                fragments = 0;
            for (si = 0; si &amp;lt; sections.length; si++) {
                section = sections[si];
                for (ri = 0; ri &amp;lt; section.rows.length; ri++) {
                    row = section.rows[ri];
                    for (ai = 0; ai &amp;lt; row.areas.length; ai++) {
                        area = row.areas[ai];
                        for (ci = 0; ci &amp;lt; area.controls.length; ci++) {
                            control = area.controls[ci];
                            if (control === model) {
                                return fragments;
                            }
                            if (control.editor.alias === model.editor.alias &amp;amp;&amp;amp;
                                control.config[&amp;quot;source-property&amp;quot;] === model.config[&amp;quot;source-property&amp;quot;]) {
                                fragments += control.config.fragments;
                            }
                        }
                    }
                }
            }
            return fragments;
        }
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;The only change to the rest of the controller is that &lt;code&gt;updateFlow&lt;/code&gt; now initializes &lt;code&gt;begin&lt;/code&gt; to the result of &lt;code&gt;alreadyRenderedFragments&lt;/code&gt;.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;                ...
                begin = alreadyRenderedFragments(),
                ...
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Now updating our text pages gives us something more interesting:&lt;/p&gt;
&lt;p&gt;&lt;img src="https://blog.aabech.no/media/1011/fifth-iteration.png" alt="Content text spread over two columns with a macro between last two paragraphs" /&gt;&lt;/p&gt;
&lt;p&gt;Mesa like! There's the macro we don't want in the middle of our RTEs. Glimmering between the second and third paragraph of the body text.&lt;/p&gt;
&lt;h3&gt;Rounding up&lt;/h3&gt;
&lt;p&gt;There's a few more issues to tackle here. We should allow blank fragment configurations to represent &amp;quot;to the end of the text&amp;quot; or something along those lines. We should inform the user that there is no more fragments to render. I guess there's no real end to this. But I'm certainly satisfied with the proof of concept, and excited to see if it spawns some nice collaboration in the community.&lt;/p&gt;
&lt;p&gt;What I'd really like next for this tool, is to make it so the first editor you add show everything by default. Closing the settings dialog and hovering the editor shows a scissor and a line between the fragments where you're currently hovering. Clicking splits the editor in two and let's you move the second one to another area. That would hopefully be a pleasant user experience.&lt;/p&gt;
&lt;p&gt;I hope you enjoyed tagging along with me for this experiment. I certainly enjoyed bringing you. And thanks a lot for staying with me if you got this far. I'll see about continuing this, but for now, &lt;a href="https://github.com/lars-erik/our.umbraco.flowingtext"&gt;head over to GitHub&lt;/a&gt;, fork the project and have some fun with it. &lt;/p&gt;
&lt;p&gt;Here's a video showing the final spin of the code so far.&lt;/p&gt;
&lt;iframe width="560" height="315" src="https://www.youtube.com/embed/nNODsGCTqzw" frameborder="0" allowfullscreen&gt;&lt;/iframe&gt;</description>
      <pubDate>Tue, 20 Sep 2016 18:08:20 Z</pubDate>
      <a10:updated>2016-09-20T18:08:20Z</a10:updated>
    </item>
    <item>
      <guid isPermaLink="false">1081</guid>
      <link>https://blog.aabech.no/archive/separating-data-and-content-from-layout-in-umbraco/</link>
      <title>Separating data and content from layout in Umbraco</title>
      <description>&lt;p&gt;There's been some discussion on &lt;a href="https://twitter.com/James_M_South/status/775188336231141376"&gt;twitter&lt;/a&gt; and the &lt;a href="http://issues.umbraco.org/issue/U4-8964"&gt;issue tracker&lt;/a&gt; recently, about whether macros should be discontinued in Umbraco. They all end up discussing ways to use the grid or nested content, even archetype, to replace macro usage in rich text editors. The latter being a somewhat painful artifact from times forgotten. I also had an enjoyable discussion with Søren at &lt;a href="http://www.ucommerce.net"&gt;uCommerce&lt;/a&gt; about whether storing data in the grid is a good idea at all. His point being quite valid, that the grid defines layout and should do only that, while content should be put in some other part of the document graph. While I find that a bit radical, I still appreciate the point. Here's a few of my thoughts on separating data from content with our current tools.&lt;/p&gt;
&lt;h3&gt;Context&lt;/h3&gt;
&lt;p&gt;First of all, it's all about context. Many early grid adopters have embraced the grid as salvation for &amp;quot;feature&amp;quot; pages. I really dunno if that's the right term, but you know the billboards going on and on. New colors and background images for each new area on a long scrolling page.&lt;br /&gt;
These pages are seldom more than gateways to the real meat, if there is any. Otherwise, they all lead the way to a big contact form or CTA at the bottom. The pages should be easily find on Google, but you're not that hard pressed for them in the internal site search.&lt;/p&gt;
&lt;p&gt;But then there's your good old feature- and news articles, blog posts and what-nots. These are carefully structured into headings, summaries, body-texts, feature image, tags and all these things we find interesting in search and presentation contexts. You cannot as easily extract these interesting properties of an article type from the grid. After all, you'd have to traverse a big row/column tree checking editor aliases to find each item.&lt;/p&gt;
&lt;p&gt;So it's all about context. There's pages where layout and content is deeply intertwined, and there's pages where layout has nothing to do with the content. And of course there's all the in-betweens.&lt;/p&gt;
&lt;h3&gt;The in-betweens&lt;/h3&gt;
&lt;p&gt;The discussions we had showcased a few pretty common scenarios. Editors want to insert a form, a quote or even an image gallery in the midst of their articles or pages. For ages, the solution has been macros inserted into the rich text editor representing the body of the page. Then came Archetype and Nested Content, which allowed us to create a list of rich text editors with stuff in between them. A body could consist of some text, a gallery, some more text, a form, and some finishing text. Maybe even a discussion plug-in at the bottom. (I guess some would)&lt;/p&gt;
&lt;p&gt;I don't quite fancy this model. It can be done even worse with the grid. You'd separate the contents of an article even more than just in a list. There'd be rows and columns in between.&lt;/p&gt;
&lt;p&gt;To be frank, our latest starter site per fall 2016 is just like that. We use the grid for a lot, although we still have and use my precious article document type. While thinking about this post, I've found several things I want to try out. But here's the rationale for keeping the main coherent text of a page out of your layout and widgets.&lt;/p&gt;
&lt;h3&gt;Main body&lt;/h3&gt;
&lt;p&gt;Imagine writing a book or and article. While working on the content, would you care to fiddle around with the figures, fact-boxes and images while putting your thoughts to paper? Imagine being the editor re-reading the text several times. How relevant is all the final extras to the core of the text you're editing? What about the proof-reader? Should everything be evaluated each time?&lt;/p&gt;
&lt;p&gt;My point is - when writing this article, I leave out all links and illustrations until I'm satisfied with the content. I'll add this stuff later. It shouldn't really be part of the body of the article. There has to be a way to separate the decoration from the content.&lt;/p&gt;
&lt;p&gt;More issues occur too when we mingle functionality and presentation with the content. What if a search result highlights the last two words of a rich text editor next to a form. It might show the containing phrases around the two words, including the label of the first field in the form. That'd be a bit embarrassing.&lt;/p&gt;
&lt;h3&gt;What others did&lt;/h3&gt;
&lt;p&gt;I guess already in the 80s or even 70s, desktop publishing programs could take a text and spread it out in columns, with images at fixed positions, boxes in fixed positions and everything that makes magazines nice to look at. They've got these nice little algorithms that pads text and makes it fit and spread nicely into whatever layout it's given. The text, however, is more or less plain ASCII stored in a linked text file. (Like this markdown)&lt;/p&gt;
&lt;p&gt;Could we do the same with our content?&lt;/p&gt;
&lt;h3&gt;How about...&lt;/h3&gt;
&lt;p&gt;With either Nested Content or the grid, we could device an artifact that defines from which, and how many paragraphs to show. This means that we could keep our precious body RTE with naught but &lt;code&gt;Hn&lt;/code&gt;, &lt;code&gt;ul&lt;/code&gt;, &lt;code&gt;b&lt;/code&gt;, &lt;code&gt;i&lt;/code&gt; and &lt;code&gt;a&lt;/code&gt; as allowed formatting. If I'd like to be able to insert a form at paragraph 3, I'd go to my NC or grid property. There, I'd add the body-text widget and configure paragraph 1-2. I'd add my macro or custom thingy next. Then I'd add another body-text widtget and configure paragraph 3-4. And so on. As you can see from the illustration, there are only pointers stored in our layout definition.&lt;/p&gt;
&lt;p&gt;&lt;img src="https://blog.aabech.no/media/1006/separate-data-and-presentation.png" alt="Diagram showing pointers from layout to objects" /&gt;&lt;/p&gt;
&lt;p&gt;Hopefully, the other devices in the layout also actually reside as their own respective object graphs somewhere. So the only things we put in the list or grid is pointers to- and/or limiters to our content. Layout is kept separate from content.&lt;/p&gt;
&lt;h3&gt;The exceptions&lt;/h3&gt;
&lt;p&gt;As mentioned initially, it's all about context. Some of the stuff we put into our layout definitions are only to be used there. Ever! It's short. It might be two sentences ment to lure the user to click on them. It might be a bullet-list only relevant in this page.&lt;/p&gt;
&lt;p&gt;These things I'll forgive putting into the grid or nested content. They're not relevant enough to be stored in a structured way. But we should really be adamant in our consideration of what should go into a layout definition and what should be structured content.&lt;/p&gt;
&lt;p&gt;Products, re-usable content, forms, images, galleries (maybe not) and everything you might want to address individually from code or search should be persisted individually. To use them in grids or lists, you should refer to them. Create pointers. Create relations. Create layout definitions. You'll thank your past self for it some time in the future.&lt;/p&gt;
&lt;h3&gt;Disclaimer&lt;/h3&gt;
&lt;p&gt;This whole article is not to say you shouldn't go and abuse the new support for custom examine indexing of JSON coming in 7.6. ;)&lt;br /&gt;
(Yours truly might have had something to do with that)&lt;/p&gt;
&lt;h3&gt;A prototype&lt;/h3&gt;
&lt;p&gt;The day after I wrote this, I wrote a prototype. &lt;a href="/archive/building-a-text-flow-editor-for-the-grid/"&gt;You can follow along here&lt;/a&gt;.&lt;/p&gt;
</description>
      <pubDate>Mon, 19 Sep 2016 20:07:12 Z</pubDate>
      <a10:updated>2016-09-19T20:07:12Z</a10:updated>
    </item>
  </channel>
</rss>