Web Development in Dart with Enonic CMS

Posted by

Plastic Dart

Traditional programming of Enonic web pages involves XML, XSLT, HTML, CSS, and JavaScript. But JavaScript is a language that, although turing complete, is more oriented towards smaller web development projects than larger applications. Trying to do proper object-oriented programming can be more difficult in JavaScript than in many other popular programming languages today. In order to rectify some shortcomings in JavaScript when it comes to app development, there have been many extensions and alternatives to JavaScript that have been put out on the market. Google's attempt at a web development programming language is Dart, so is it possible to use Dart in an Enonic project? The target was "Edna", Enonic's internal invoicing and hour registration system.

Planning

We identified three different key areas of Edna that we could improve with this project: Project time registration, overview (and edit) time and graphs. We mainly focused on implementing Dart on the “Project time registration” part.

Analyzing this part of the project gave us the information we needed to proceed. One of the problems with the time registration was finding a specific project amongst the enormous list of customers and projects. This was implemented by the “Edna - Timeføringsskjema” portlet which used outdated datasources and a select element.

The new idea

When discussing this part we came up with a few changes that could be implemented with Dart. The biggest change we wanted to make to the existing project time registration form was to remove the drop down menu that listed all the Projects and replace that with a normal text field that would autocomplete as you typed. If that part went well, and we liked the outcome, we would then implement this feature for the Activity field as well. Also some easier handling of the hour/minute field would be implemented if we had enough time left over.

Starting up

For this project to proceed, we need to fully understand what we are up against. We achieve this by thoroughly analyzing the old Edna page and its functionality, discovering all the parts that interact here. We discovered the existing set up had a JavaScript error that prevented the ICE Mode box from appearing. Updating prototype.js fixed that problem.

Then we were able to determine that one portlet and one JavaScript file provided all the functionality for registering project hours. The portlet “Edna - Timeføringsskjema” had two datasources: one to get all the project contents, and one to get the “Ressurs” content for the logged in user. The project contents have Ressurs as a related content so the xsl file makes the dropdown project list that includes only the projects for which the logged in user has been added. Once a project is selected, it triggers an onchange getActivities function which uses Ajax to load the activities for the selected project.

Beginning with Dart

Next we had to really dig deep into Dart to discover what could be done, and how. This wasn't as easy as we first thought, having no experience with Dart.

After getting all the parts in place we started developing a prototype of what we wanted done. This prototype lived outside of Enonic CMS and consisted of just one simple un-styled html page.

Setting up the form was easy. We just used the same fields as the current Edna, and we changed the drop down list of Projects to a simple text field. To get autocomplete data to this field we decided to use json, since that's a format that Dart claims to work extra well with.

We created a dummy json-file containing about 10 different projects, with name and id for each. When selecting a project, the id should be sent via Ajax to fetch the list of matching activities. This part was never implemented.

Just getting the autocomplete up and running took a lot of time. Getting used to the Dart syntax is not as easy as it first seems. The things you would normally accomplish in vanilla Javascript, or in jQuery, are now handled a bit differently. And these minor changes, with a lot of similarities, makes it extra hard to get used to the language. You are just not entirely sure when you make errors, or when you type it the Javascript-way instead of the Dart-way, etc.

Also there are not as many libraries out there adding to Dart, so what would be a super easy one line of code in jQuery can easily turn out to be 10-20 rather complex rows of Dart. Since the language is so new, finding more than one way to solve a problem when Googling is almost impossible. The examples you come by solve one specific problem, but rarely yours, and we found it hard to adapt the examples we found.

So, after investing loads of time to solve this simple autocomplete task we finally got it up and running. Typing in the text field would highlight the projects that matched, from the json-file. Fetching the json was done only on the loading of the page to save precious requests. There's really no need to fetch it each time you type, instead we store the file's data in a variable that we access and filter against instead.

When autocomplete was finally working, including click-enabled fields (click on a Project name to move that text to the text field), we went on to the the next task. Making the hour and minute-input more user friendly. This was done by allowing the user to add and subtract 15 minute steps on the set time (or starting from 1 hour if empty) by tapping the up and down arrow keys. This worked out very well and made it rather smooth to adjust your hours.

After this, we basically did minor tweaks and updates. One of them – changing the format of the dummy json to be more final – resulted in a lot of code rewriting. This took us almost a whole day just to get back running again.

This was the main hurdle for us implementing this functionality in Dart – each little change took immense amount of time to function. Mostly because of tiny typos or hurdles we weren't used to from JavaScript or jQuery. Also we discovered that we automatically think in jQuery to solve problems, thus almost forcing us to start learning completely from scratch to get things done. And when we finally did get it to work it very often felt like a more un-intuitive solution.

Basically we could have finished this functionality in jQuery in under a days work, and dropped it straight into the Enonic page. It would have even been much better and smoother. But when learning Dart and trying to implement it, it took a few days and we still didn't get anything implemented into Enonic, just some half working stand alone prototype.

Addendum: Serving data to Dart in Enonic

The project did not include serving data to Dart in Enonic, but the idea is nevertheless quite relevant to be discussed here, as it is essential to 

After some discussion among the project members, there turned out to be a number of different ways to serve data to Dart:

Method 1: Provide data in the HTML on page load

The quickest method of getting Dart to read data from Enonic, would probably be to write your XSLT stylesheets as normal, but provide extra data direcly in the HTML. A nice way of doing this in HTML 5 is with the data attribute, which then easily can be retrieved by Dart. Many modern JavaScript libraries have begun to rely on this method, and it works nicely as long as your clients all use browsers that can understand HTML 5. But this method can quickly become a bit bloated if you have to provide a lot of data, especially when this data no longer can be related directly to an HTML element that is visible on the page.

Method 2: Write XSLT stylesheets that generate the Web UI markup language

According to Google, the proper way to deliver data to Dart is to use the Web UI Package . With this method, the markup follows a syntax similar to HTML, but some additional elements and attributes provide the necessary data that will be used by the application.

The downside of this method is that you then must use a browser that can read Dart natively, such as Google Dartium. Of course, if Dart turns out to be the Next Big Thing™ after Web 2.0, then other browsers should soon follow, and the Web UI method should be the one to start using regularly. Also, there doesn't seem to be any text editors that support both XSLT and Dart / Web UI, so if you're used to having syntax highlighting and code completion available at your fingertips, you're out of luck.

Method 3: Retrieve XML from datasources through AJAX, then parse into JSON

Since both the two previous methods have their disadvantages, probably the best way to serve data to Dart would be to retrieve JSON data from Enonic. Sadly, there currently are no built-in datasources that deliver data as JSON, only as XML. So the solution to this is either to write a custom datasource plug-in that delivers data as JSON, or to parse the XML into JSON in a manual fashion. The most sensible here is to write a datasource that delivers data as JSON, and if it is feasible to do so in your project, then this method is the one that seems the most promising and has a nice combination of relatively shallow learning curve and still being powerful.

The conclusion that could be drawn from all this, is that unless you have a project that would really benefit from all the good stuff that Dart lets you do, it is currently too demanding to implement an Enonic web app using Dart. First of all, you need to set up a proper development environment. Then there are the deployment routines that must be handled properly, at least if you're going to make the project work in legacy browsers that only understand JavaScript. And lastly, you cannot use traditional Enonic development methods such as built-in datasources and XSLT transformation – certain countermeasures such as writing custom JSON datasources must be made. But if the web application is of greater size, and not just minor projects, then the advantages might turn out to be more fruitful than what the Edna on Dart project has taught us.

Comments