Fit and Finish - Enyo: Up and Running (2015)

Enyo: Up and Running (2015)

Chapter 6. Fit and Finish

In the preceding chapters we laid down the foundations you need to create Enyo apps. In this chapter, we’ll explore some of the pieces necessary to make those apps more memorable. We’ll cover how to style your apps, how to tune them to perform well on less powerful platforms, how to prepare them for translation to other languages, and how to troubleshoot bugs that inevitably arise. As always, we’ll explore these concepts through interactive samples.

Styling

Enyo provides some very nice looking controls with the Onyx and Moonstone libraries. However, an app can set itself apart from others by having a unique user interface. Fortunately, it’s very easy to change the look of controls. We’ll explore several ways to accomplish that.

Styles and Classes

All Enyo controls have two properties to aid in styling: style and classes. These two properties correspond to an HTML element’s style and class attributes. The style property can be used to apply a specific style to a single control. To work with the classes property, you must add CSS classes to a style sheet. In general, it is better to use classes in an app for two reasons: first, components are more reusable if styling is not embedded within them; second, using CSS classes allows you to keep the styling in a single, centralized location.

Enyo provides applyStyle() to update an individual style and addStyles() to add styles onto the existing styles of a control. We used the applyStyle() function in the traffic light sample at the start of the book. Passing a null as the second parameter to applyStyle() removes the style. For updating classes, Enyo provides addClass(), removeClass(), and addRemoveClass().

WARNING

It might seem like calling set() with the style and classes properties would be a good way to update a control. However, doing so completely replaces the styles and classes of the control. Use set() carefully with these properties.

Overriding Onyx Styles

Each Onyx control includes one or more classes. It is possible to override some (or all) of the default styling by overriding those styles in your CSS file. One simple way to discover the class names to override is to use your browser’s inspector to see what classes are applied to a particular control. You can then use those classes to override the way that control looks everywhere in your app. The following image shows the Chrome inspector output of the Onyx sample from Chapter 3:

An image of the Chrome inspector

The Onyx button has, among its classes, onyx-button. If we want to override the styling on all the buttons in our app without having to manually add a class to each one, we could write our own CSS rule for onyx-button:

.onyx-button {

background-color: cyan;

}

The Onyx sample with a styled button

TIP

In general, you will need to use a CSS selector that is more specific than the styles in the Enyo CSS. One method is to add a base class to your view component and then use that in combination with your CSS selector. In the Onyx sample, we cannot override the background color of the actual input control without a more specific selector:

.myapp .onyx-input {

background-color: tomato;

}

The Onyx sample with a styled button and input

TIP

In general, it’s better to style the input decorator rather than the input itself.

Less Is More

You could, of course, simply go into the Onyx library directory and directly edit the CSS file. Knowing that app developers would want to do this, the Enyo developers provide Less files for generating the CSS used by Onyx (and Moonstone as well). Less provides a programmatic approach to creating CSS while keeping most of the flavor of CSS. In order to compile Less you will need to have Node.js installed, and it helps to be working on a Bootplate project (see Appendix A).

TIP

Less can be used “live” in a browser. The debug build of Bootplate projects loads a JavaScript library that processes Less files in the browser. Because of the additional processing needed, it isn’t recommended to use that method with deployed code. You can disable Less by commenting out the line in debug.html that loads less.js.

Less files can be found in the css directory of the Onyx library, along with a previously compiled CSS file. Of particular interest is the onyx-variables.less file, which contains some common settings used throughout the library. Here’s a sample from that file:

/* Background Colors */

/* ---------------------------------------*/

@onyx-background: #EAEAEA;

@onyx-light-background: #CACACA;

@onyx-dark-background: #555656;

@onyx-selected-background: #C4E3FE;

@onyx-button-background: #E1E1E1;

By overriding a particular variable, we can affect a wide range of Onyx styles. If you want to create your own overrides, you can modify your app as follows:

§ In source/package.js, change $lib/onyx to $lib/onyx/source.

§ In source/style/package.js, uncomment the reference to Theme.less.

§ Edit source/style/Theme.less and place your overrides into the places indicated.

To change all Onyx buttons to lime green, you could place the following where variable overrides go:

@onyx-button-background: lime;

For more information on Less, see the Less website. For more information on theming Enyo, visit the Enyo UI Theming page.

Moonstone provides Less files as well and the override process is very similar.

Performance Tuning

With all of the styling options available to you it can be very tempting to pull out all the stops and add drop shadows, rounded corners, and all sorts of bells and whistles to your app. You need to be careful, though. While Enyo enables you to make native quality apps with HTML5 and CSS, you need to test the performance on mobile devices and older browsers (such as Internet Explorer 8), if you target them.

In desktop environments you can expect very good performance regardless of the CSS tricks you use. In the mobile world, where there’s less processing power and less memory, things can get bogged down very quickly. Particular performance hogs include the afore-mentioned drop shadows and rounded corners. Other offenders include computed gradients, overlarge images, and long-running JavaScript. It’s very important that you test how your app performs on the least capable system you’re targeting. You may need to disable some features by using enyo.platform to detect the platform you are running on.

One of the most important factors in how an app is perceived is its responsiveness. It is very important that when a user taps on buttons, there is visual feedback that something happened. If you attempt to perform a long running calculation in a tap handler, the user will not see the button respond properly to the tap. Attempt to return as quickly as possible from event handlers and perform the calculations in response to a timer or animation frame request. Enyo includes an Async object for performing asynchronous actions.

TIP

With mobile devices, the simpler the HTML and CSS, the faster the performance. It can be tempting to create every single object that your app might use. However, placing all those components into the DOM, even if they’re hidden, affects performance. Create only the objects you need and get rid of those you don’t need anymore.

Lastly, with installable apps you should be careful about loading remote resources. Mobile users may not always have an Internet connection and, when they do, it may be slow. If your app depends on particular images, package them with your app. If your resources change over time, use caching techniques.

A full discussion of performance tuning is outside the scope of this book. For more information on some of the pitfalls, you can read HTML5 Techniques for Optimizing Mobile Performance and other sites.

Debugging

So far we’ve painted a rosy picture of life with Enyo. Of course, sometimes things don’t go so well. Fortunately, you have a number of tools at your disposal to figure out what went wrong. First and foremost, because Enyo is truly cross-platform, many problems can be detected and fixed by running your apps in a desktop browser. All the modern browsers have JavaScript debuggers available that make it very easy to see errors and even inspect the state of the DOM. In general, problems come in two varieties: code issues and layout issues.

TIP

One of the most common errors in Enyo apps is forgetting to call this.inherited(arguments) when overriding methods on a parent object. This occurs most often with the create() and render() methods but can also happen with others. Leaving out this call can cause components to render incorrectly or not appear at all. Another common error is failing to return a truthy value from event handlers and having the event handled by more than one component. This can be especially bad in the case of nested List components.

Layout Issues

We covered some of the great layout features that Enyo offers in Chapter 4. However, even with these features at your disposal, things can go wrong. One common problem app developers experience occurs when they fail to provide a height to List or Scroller components. Without a height, these elements will end up invisible. Providing a height or placing the component in a fittable layout can solve that issue. Fittables themselves can also cause problems. Forgetting to assign fit: true to one and only one of the components of a fittable component can lead to rendering issues.

Sometimes things just end up in the wrong place or have the wrong style. A quick way to see what has happened is to use the DOM inspector in your browser to see what styles have been applied to the elements in question. Sometimes, CSS precedence can be the source of problems. Use the DOM inspector to check whether a component rendered at all or if it’s merely hidden. Other times, it can help to add !important to a style.

Layout is a complex topic. Some links that might help include: “Four simple techniques to quickly debug and fix your CSS code in almost any browser” and “Diagnose and fix layout problems” (IE-specific, but the same concepts exist in other browsers). Also check out “CSS In Your Pocket - Mobile CSS Tips From The Trenches” by Angelina Fabbro for a great introduction to CSS debugging tools and techniques.

Code Issues

Bugs are unavoidable. Fortunately, there are lots of ways to squash them. One of the best ways to detect code errors is to keep the JavaScript console open while testing Enyo apps. If there’s an error or typo in your code, it can cause strange problems. Seeing errors as they occur really helps in trapping the problem.

Enyo apps can also write to the JavaScript console with the info(), warn(), and error() methods on the enyo object. In addition, every Enyo kind can call this.log() to send output that includes the kind’s name and the name of the method that generated the log message.

Sometimes a passive approach to debugging a problem isn’t enough. In these cases you can set breakpoints in your code and step through methods that are misbehaving. A handy trick that is supported by the major browsers is putting the debugger command into code you want to inspect. When the browser reaches that code, it will stop and allow you to inspect the state of the app. Just remember to remove that command before publishing your app!

Once you’ve identified a place in the code that you want to inspect, it’s easy to see all the components belonging to a component. this.$ will contain a hash of all the owned components. Also, enyo.$ contains a hash of all named components in your app. You can easily walk through these by inspecting deeper and deeper into a kind.

TIP

When inspecting an element in the DOM you can use its id (e.g., “panelsSample_panel1”) to find the reference within the enyo.$ hash. To make things even simpler, Firefox, Chrome, and Safari all set $0 to the last element inspected in the DOM. To find the associated Enyo control simply use enyo.$[$0.id].

JSFIDDLE DEBUGGING

There’s no doubt that jsFiddle is a great environment for quickly testing ideas. It does have some drawbacks, though. Among them is that debugging can be a little more difficult and there aren’t a lot of options for working with complex apps. jsFiddle runs your code in an iframe. Because the code you are executing gets reloaded into the iframe each time you click Run, it can be a little tricky keeping breakpoints in line.

Using the debugger command mentioned previously can be helpful, as can using the Inspector window that shows you active source files. The source for your app will be launched from fiddle.jshell.net and will be in-line with the HTML source for the page. If your app does not appear to be working at all, make sure you have selected the correct framework:

jsFiddle framework settings

If you have the wrong settings, you may see the following error message:

Uncaught TypeError: Cannot read property 'className' of undefined

If you run into an issue with a specific version of Enyo, you can try using the nightly build, which contains the most recent code submissions to Enyo. Conversely, if you run into a problem using the nightly build, try using the last released version. Released versions are tested more thoroughly, while nightly builds have the most recent fixes and features.

When using the JavaScript console, unless you use a breakpoint, you will be in the wrong context to execute commands to inspect the state of Enyo. Both Chrome and Safari support selecting the context through a drop-down list.

Going Global

Now that you’ve produced a beautiful (and bug-free) app, you’ll want to share it with the world. Enyo provides a wrapper for the open source internationalization library iLib. This library provides facilities for substituting translated strings as well as formatting names, dates, and other data based upon a user’s locale. The name of the enyo wrapper is enyo-ilib.

The library will attempt to figure out the locale based on cues from the browser. The current locale can be retrieved by calling ilib.getLocale(). In cases where the locale can’t be determined, you can explicitly create a locale by calling new ilib.LocaleInfo() with the desired locale.

WARNING

The enyo-ilib library is not included if you are using a standard (non-Moonstone) Bootplate-based setup (see Appendix A). To enable the library in a Bootplate setup, execute the command: git submodule add https://github.com/enyojs/enyo-ilib.git lib/enyo-ilib and then add the library to your package.js with the line '$lib/enyo-ilib'.

Globalization Basics

In its most basic form, iLib handles string substitutions. Substitutions are performed using the $L() global function. At run time, the $L() function searches for an appropriate translation file for the user’s locale (or the locale you set manually) and then attempts to locate the string that was passed in as the first argument. If a match is found, the translated string is used. If not, the original string is used.

Translation files should be placed in the resources directory of your app. Each locale translation should be in its own JSON file. Translation files are named strings.json and are stored in directories named after the language and optional subdirectories for the country code and variant. For example, a Canadian English translation file would be found in resources/en/CA/strings.json. Such a file might look like this:

{

"Click": "Click, eh?"

}

Names, Dates, and Measures

App developers can add some extra polish to their apps by correctly formatting information for the user’s region. The iLib library includes the ability to format names, phone numbers, dates, times, and more. For more information on the options supported by these formatters, please refer tothe localization documentation page. The following example shows some of the basic routines for formatting these items:

enyo.kind({

name: 'ILibSample',

components: [

{ name: 'date' },

{ name: 'number' }

],

create: function() {

this.inherited(arguments);

var dateFmt = new ilib.DateFmt({ length: 'short' });

this.$.date.set('content', dateFmt.format(new Date()));

var numFmt = new ilib.NumFmt({maxFractionDigits: 1});

this.$.number.set('content', numFmt.format('86753.09'));

}

});

TIP

Two Onyx components are locale-aware: DatePicker and TimePicker. If enyo-ilib is loaded, they will use the current locale to format their contents. If the library isn’t loaded, then they will default to the US format. All of the number and date components in Moonstone are locale-aware.

There is a lot more power in iLib. You can find out more at the Enyo localization documentation page and the iLib documentation page.

Summary

You’ve now picked up some more tools for creating beautiful and functional Enyo apps and you know what to do when things go wrong. If you get stuck, there are many good resources available to you, including the Enyo forums and the Enyo IRC channel.