Contents


Introduction to rapid web application development with Mavo, Part 2

Handle multiple properties, plugins, and GitHub storage with Mavo

Learn how to use Mavo, an open source web application framework

Comments

Content series:

This content is part # of 2 in the series: Introduction to rapid web application development with Mavo, Part 2

Stay tuned for additional content in this series.

This content is part of the series:Introduction to rapid web application development with Mavo, Part 2

Stay tuned for additional content in this series.

In Part 1 of this series, I introduced Mavo, an open source framework for developing data-driven web applications. Mavo was created for people who are comfortable with HTML but are not programmers. The framework lets you declare data properties using special HTML attributes, and interprets these properties with user-editing features according to the semantics of the underlying HTML elements. It also allows applications to manipulate data using a simplified expression language.

In this article, I'll show you how to:

  • Use plugins to extend Mavo's features.
  • Create properties which are lists of items.
  • Use GitHub for storing updates from a Mavo app.

Use plugins to extend Mavo's features

In this article, I demonstrate Mavo's features using an example of a website for a LEGO enthusiast's club. The club needs a website where members can show off their creations and collections and also edit the club's description.

The following video describes the steps I took to create this application.

Declaring plugins

The following snippet is from the top section of the main element that hosts the Mavo app. Though similar to examples in the earlier article, this snippet includes a new attribute: mv-plugins="tinymce".

<main mv-app="legoclub" mv-storage="local" mv-plugins="tinymce">
  <header>
    <h1>The Intrepid LEGO Club</h1>
    <img property="image"
      src="//gonzaga.ogbuji.net/~osi/elements/rooikatsplash.png"
      alt="LEGO link image" height="236"/>
  </header>

  <p property="summary" class="tinymce">
    Some people think of <strong>LEGO</strong> as kid stuff, but many enthusiastic
    adults disagree. Here is a showcase of some of the creative, original LEGO
    projects by our members.
  </p>

Mavo plugins extend the functionality of the Mavo web application framework. You can use these plugins to simplify your application development or you can build plugins yourself if you're more technically midned. One of Mavo's included plugins makes the popular rich text editor TinyMCE available for users to edit the content of Mavo properties.

In the above snippet, on the first highlighted line, there is an mv-plugins="tinymce" attribute on the element containing the mv-app declaration, main in this case. Because the plugin is known to the Mavo library, you just use its name in the attribute. You can list multiple plugins by their names, separated by spaces. For example, mv-plugins="tinymce markdown php" is a way to list multiple plugins.

Using plugins

Each plugin can be used in a different way. In the case of the TinyMCE plugin, you can declare Mavo properties with a class of TinyMCE which, when in editing mode, presents the rich text editor to the user. In this case, you can edit the summary description of the Lego Club, including adding your own HTML markup.

At the bottom of Figure 1 you can see TinyMCE in action. You can see controls for markup such as bold or italic, or adding images, hyperlinks, lists, etc. These all turn into HTML within the Mavo property's element. Here I entered editing mode and clicked the summary property's paragraph.

Figure 1. TinyMCE in action
User editing summary paragraph of LEGO club page
User editing summary paragraph of LEGO club page

Multiple properties

So far, we've only looked at properties that have one value per name. Real-world information is more complex. Mavo supports multiple properties, which can be used in situations where you have items in a list, a set of rows in a table, or some other collection of things.

The LEGO Club's page holds a collection of data, each a creation made by one of its members. The following snippet shows code for an HTML table that holds such a collection.

<tbody>
  <tr mv-multiple>
    <td><span property="name">Skeleton Trophy Truck</span></td>
    <td><img property="image"
      src="https://m.rebrickable.com/media/cache/f7/f4/f7f4d3add5ada3b2e65e177aefb4dd4c.jpg"
      alt="Snapshot"></td>
    <td><span property="creator">ChocolatEinstien</span></td>
    <td><p property="description" class="tinymce">
      Fast vehicle designed around a long travel front suspension and a robust
      live axle in the rear.</p></td>
    <td><span property="partcount">882</span></td>
    <td><span property="tags">technics,automobile,remotecontrol</span></td>
  </tr>
</tbody>

Notice the new attribute in line 2, mv-multiple. This declaration instructs Mavo to treat the element as one that can be multiplied by the user. You can use this element's initial form as a template to create additional items. The properties within this template element are available for users to edit on each additional item. The parent element, tbody in this case, becomes the container for all items in the collection.

Notice, also, the use of the tinymce class on line 8. That means the description property can be edited as rich text for each item, and is stored as HTML content.

The LEGO Club

The following is the HTML header from legoclub1.html.

<head>
  <meta charset="utf-8">
  <title>The Intrepid LEGO Club</title>

  <link rel="stylesheet" href="https://get.mavo.io/mavo.css"/>
  <script src="https://get.mavo.io/mavo.js"></script>

  <link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Roboto:300,300italic,700,700italic">
  <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/normalize/5.0.0/normalize.css">
  <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/milligram/1.3.0/milligram.min.css">
  <link rel="stylesheet" href="legoclub.css">
</head>

As you can see from the robust HTML, Mavo can be used in concert with other page design frameworks. Notice that there are now CSS declarations from the minimalist milligram framework. You can also see the entire table structure that hosts the collection of LEGO creations, complete with headers.

Collections editing in action

Deploy legoclub1.html to a web host of your choice, as well as legoclub.css from this article's code base, and you should see something like figure 2 when you load it in the browser.

Figure 2. LEGO Club page, browser view of legoclub1.html
LEGO club page, browser view of legoclub1.html
LEGO club page, browser view of legoclub1.html

To start, the bootstrap template item is the only content of the table. Once you click the edit button, the first thing you'll notice is the "Add Collection" button underneath the table as Figure 3 illustrates.

Figure 3. User in editing mode adding a collection
User in editing mode before adding a collection item
User in editing mode before adding a collection item

Once you click this, an empty table row is added, with placeholders based on the field names in order to guide your editing, as Figure 4 shows.

Figure 4. User ready to add collection item
User in editing mode, ready to add a collection item
User in editing mode, ready to add a collection item

Once you fill in the details, click save, and then the "Editing" button to toggle it. The collection has two items in it, as Figure 5 illustrates.

Figure 5. LEGO Club page with added collection item
LEGO club page with an added collection item
LEGO club page with an added collection item

Fun with conditionals

One of Mavo's neat tricks is to make URL query parameters available to expressions through special properties. Among many possible uses for this feature, you can create a super simple search capability.

Let's say you deployed the LEGO Club to the URL http://example.org/legoclub/legoclub.html. You might want to make it possible to show only collection items according to their tags. For example, you could show only items tagged as "military" using the following URL: http://example.org/legoclub/legoclub.html?tag=military.

The component ?tag=military is a query parameter, and Mavo makes this available to expressions as $url.tag.

$url is a special property that always holds the URL to the page containing the Mavo app. It can also be used with a period, then the name of any query parameter, such as tag.

If you change the table in the HTML source file as follows, excerpted from legoclub2.html in the article's code, you can have the app only show collection items that include the provided tag.

<tbody>
  <tr mv-multiple class="[if($url.tag and search(tags, $url.tag) = -1, hidden)]">
    <td><span property="name">Skeleton Trophy Truck</span></td>
    <td><img property="image"
      src="https://m.rebrickable.com/media/cache/f7/f4/f7f4d3add5ada3b2e65e177aefb4dd4c.jpg"
      alt="Snapshot"></td>
    <td><span property="creator">ChocolatEinstien</span></td>
    <td><p property="description" class="tinymce">
      Fast vehicle designed around a long travel front suspension and a robust
      live axle in the rear.</p></td>
    <td><span property="partcount">882</span></td>
    <td><span property="tags">technics,automobile,remotecontrol</span></td>
  </tr>
</tbody>

If this, then that

The added class attribute in line 2 uses the Mavo expression [if($url.tag and search(tags, $url.tag) = -1, hidden)]. The condition first checks whether a tag query parameter is provided. If it is, it uses the search function to search the item's full tags property for the tag query parameter value. Remember that the tr element acts as a sort of template for each item in the collection. This condition is applied to each item.

The tags property value used for the collection is the one in the last contained property, also highlighted above. Mavo is pretty clever about finding the nearest property value to the expression where it's used, even when there are multiple items, each of which has that property.

The search function takes two arguments. It returns the position within the first argument string where the second appears. It returns -1 if the second string is not found within the first. If you edited the page to add a second item, as shown in Figure 2, with a tags property value of technics,automobile,military,remotecontrol, the tag military from the query parameter is found. The search function result would not be -1, so the condition would not be met, and the resulting class attribute would be empty.

In the case of the initial item, with tags property value of technics,automobile,remotecontrol, the string military would not be found, the search function result would be -1, so the condition would be met, and the resulting class attribute would be hidden.

To complete the picture, legoclub.css contains the following snippet.

.hidden{
  display: none;
}

This ensures that if the condition results in a class name of hidden, the relevant item's table row will not be displayed.

GitHub storage

So far in this article and the previous one, I've shown you examples that use a browser's local storage. Most real-world applications require multiuser storage that is shared and lasts longer than a single session. Mavo allows you to access this long-term storage via data repositories like GitHub and Dropbox. Let's look at how to use Mavo with GitHub storage.

First, you need to create a free GitHub account. GitHub is primarily a tool for programmers and can seem a bit complex, but don't fear. You only need to know a few basics to use this Mavo feature.

Note that anyone who wants to make updates to data in your Mavo app will also need a GitHub account. It's best not to share GitHub login information because it makes it hard to track chanegs and manage workflow.

Updating the LEGO Club app

To have the LEGO Club app use my GitHub storage, I changed the Mavo declaration element. The following snippet is taken from legoclub-gh.html, in this article's code base.

<main mv-app="legoclub" mv-storage="https://github.com/uogbuji/ibmdw/mavo/legoclub"
      mv-plugins="tinymce">

The mv-storage attribute is now a full URL, starting with the service, https://github.com, and then specifying my account, uogbuji. Replace my account name with your own account name, or perhaps an organization's account, which is a feature GitHub offers.

The next part of the URL is the repository, ibmdw. This is a collection of code or data that is managed in concert. You can have folders within repositories. In this case, I had a mavo folder containing a legoclub folder. Given this URL pattern, Mavo saves the data as JSON within the specified folder in the form APPNAME.json. So, here the app data is stored at https://github.com/uogbuji/ibmdw/mavo/legoclub/legoclub.json.

GitHub storage in action

When you, or any of your users, first comes to an app with a GitHub storage Mavo declaration, as described above, you will see a single "Login" button. Click "Login" to initiate the process of connecting the Mavo app to your GitHub account. The first step in the process is to grant GitHub integration permission to the Mavo framework as a whole. You only need to do this for the first Mavo app.

Figure 6 is an example of the resulting pop-up.

Figure 6. Mavo framework and GitHub integration pop-up
Mavo framework GitHub integration pop-up
Mavo framework GitHub integration pop-up

Once this is done, each Mavo app needs a separate, additional authentication step per user. Figure 7 is an example of this pop-up.

Figure 7. Mavo app and GitHub integration pop-up
Mavo app GitHub integration pop-up
Mavo app GitHub integration pop-up

Once you log in, the three Mavo buttons reappear, followed by a "Logout" button. The Mavo bar also indicates the GitHub user account that is linked to the Mavo app. Figure 8 shows the Mavo bar in this state.

Figure 8. Mavo bar after GitHub login
Mavo bar after GitHub login
Mavo bar after GitHub login

Users of your app can now make edits, such as adding a new collection item. When they click "Save," they get a popup saying that the changes will be saved to their own profile where no one else can see them. If they want to, users can click "Send edit suggestion" to nominate their edits to be incorporated into the app. Figure 9 shows this step.

Figure 9. Dialog to save Mavo edits as suggestions for the app owners
Dialog to save Mavo edits as suggestions for the app owners
Dialog to save Mavo edits as suggestions for the app owners

Users typically modify the app through their own GitHub accounts. To manage the workflow that comes from user suggestions, Mavo uses GitHub's "pull requests" feature. The pull request contains the details of the data changes the user wishes to make. The app owner, or anyone else who has write access to the GitHub repository, can review the changes in the pull request and opt to incorporate them into the shared, public app data. As this process is initiated, the user sees a notice such as shown in figure 10.

Figure 10. Confirmation to save Mavo edits as suggestions for app owners
Confirmation to save Mavo edits as suggestions for the app owners
Confirmation to save Mavo edits as suggestions for the app owners

The rest of the change process occurs on GitHub. The app owners or anyone with write access will receive notifications of the suggested changes. They can click through, review the proposed changes, and, if needed, chat with the user through the comments. The owners can either approve the changes or close the request without approval, which denies the request. Figure 11 is a GitHub page showing the interaction between a user suggesting a change (a contributor) and the repository's owner.

Figure 11. GitHub pull request for a Mavo change
Github pull request for a Mavo change
Github pull request for a Mavo change

Notice the link to preview the changes. If the result looks fine, you can click "Merge pull request" to accept the changes.

GitHub pull requests can be complex if you go beyond the preview provided by Mavo. These complexities get easier to handle with practice.

A peek behind the data curtain

By default, Mavo stores app data as JSON. Like so many aspects of Mavo, this is customizable. Mavo also supports CSV and a plain text format, with some restrictions. Other data formats are available through plugins. You don't have to understand JSON to use Mavo, but it's useful to have an idea of the format if you end up using Mavo seriously.

The following code snippet shows the Mavo representation of the data as initially set up in the legoclub.html:

{
    "collection": [
        {
            "name": "Skeleton Trophy Truck",
            "image": "https://m.rebrickable.com/media/cache/f7/f4/f7f4d3add5ada3b2e65e177aefb4dd4c.jpg",
            "creator": "ChocolatEinstien",
            "description": "Fast vehicle designed around a long travel front suspension and a robust live axle in the rear.",
            "partcount": "882",
            "tags": "technics,automobile,remotecontrol"
        }
    ]
}

If you add a second row to the LEGO table, the data looks as follows:

{
    "collection": [
        {
            "name": "Skeleton Trophy Truck",
            "image": "https://m.rebrickable.com/media/cache/f7/f4/f7f4d3add5ada3b2e65e177aefb4dd4c.jpg",
            "creator": "ChocolatEinstien",
            "description": "Fast vehicle designed around a long travel front suspension and a robust live axle in the rear.",
            "partcount": "882",
            "tags": "technics,automobile,remotecontrol"
        },
        {
            "name": "Rooikat XL",
            "image": "http://gonzaga.ogbuji.net/~osi/elements/rooikatxl.png",
            "creator": "ChocolatEinstein",
            "description": "Rooikat XL has all four rear wheels powered, either with differential for max speed, or without for max South African Veldt fun.",
            "partcount": "1157",
            "tags": "technics,automobile,military,remotecontrol"
        }
    ]
}

When a user sends an edit suggestion via Mavo GitHub storage, the request is to change the first data set to the second, but Mavo's preview tries to shield you from having to deal with that directly.

Conclusion

GitHub's approval process for edits makes it a bit daunting for some users. I describe Mavo's suitability as being for apps with "chunky" storage patterns, where, every so often, a user makes a batch of changes that can be incorporated at once. While it's possible to code more fine-grained storage using plugins, for now this is a key limitation of Mavo as an application framework.

I'm excited to watch Mavo evolve since its basic ideas are quite broadly applicable. In these articles, I've shown you how to use Mavo's simple declarations to turn any HTML element into a data manipulation widget, including how to represent collections with multiple items. Hopefully you've gotten a sense of how to construct additional manipulations using MavoScript, and how you can use the GitHub storage back end for multiuser applications. Now that you've seen how easy it is to use Mavo, I hope you'll think about Mavo the next time you need to quickly exercise an idea for a web app.

Related topics


Downloadable resources


Comments

Sign in or register to add and subscribe to comments.

static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=1
Zone=Web development
ArticleID=1051719
ArticleTitle=Introduction to rapid web application development with Mavo, Part 2: Handle multiple properties, plugins, and GitHub storage with Mavo
publish-date=11012017