Creating content with Web Components

Many web projects rely on a CMS of some description. The system itself is not important, but rather the content it helps to create. The primary function of a CMS is to enable the creation of content – it should empower content creation. If a new project requires a CMS the question that would tend to spring into a developer’s mind is – can I use an existing CMS already out there, or do I need to build a CMS from scratch for this project? But before that can be answered, perhaps some simple questions need to be asked first.

Asking the simple questions…

Content Management Systems are designed to make it easier to create and publish content. With so many open source systems available there’s a good chance you can find something to do the job you need. Often in the case where additional functionality is required most systems can be extended with some sort of plugin to add that ‘must have’ feature. So why would you ever need to build your own CMS from scratch? This decision should not hang solely upon application’s technical requirements, but rather it depends on who will be using it – we need to ask ourselves who will be the one creating the content? Sounds like a simple question, perhaps even an obvious question but it merits deep thought and careful design decisions. If it is a non-technical audience then displaying a bunch of features that the user doesn’t need is distracting, in the worst case intimidating, ultimately leading to a poor user experience. What if you could design something from scratch so it could be tailored exactly to fit the user’s requirements? Imagine if the UI only contained the functions needed without extraneous menu options or clutter and was designed to maximise ease of use and content creation.

Starting from scratch

Recently I was working on the ‘Badge Builder’ project which required a CMS to author quiz content. But rather than manipulate some existing CMS or plugin that might roughly fit the use case we wondered if we could design and build our own bespoke CMS components during a one week hack. At the very outset of the project we wanted to build a system that would be easy to use and quick to create content regardless of the technical abilities of the user.

Badge Builder

The main problem with building all the CMS components from scratch would be the time required – with only three weeks. However there are a number of things that I feel made the most of the development time we had.

  • Web Components

    By leveraging Web Components we could make our own custom HTML elements for each quiz and content element. Common behaviours could also be shared across elements.

  • Polymer

    During our one week hack the Polymer Starter Kit was a good kick start and saved time by setting up a stack of things like node and bower dependencies. Polymer provides a nice UI kit for web apps which can be separately imported for use. The PSK boilerplate is now available through Polymer-cli.

  • SASS and Foundation grid

    Because nobody likes working with thousands of lines of CSS, SASS can reduce physical line count and can be easily split into separate files which makes it easier to manage in source controlled projects. Also SASS makes it easy to import Foundation Grid for responsive design.

  • Live reload of server and client

    A combination of Nodemon and BrowserSync allowed us to see live updates of all changes made on server and client side. This combo is essential to fine tune the interface and user experience and is my personal ‘must have’ for designing and developing a web app project.

  • Document database

    Saving content as a JSON object allowed greater freedom developing components on client side.

Polymer Web Components

Developing Web Components for each quiz element and content element felt very intuitive. A quiz could be built using a combination of a number of individual quiz and content components.

Quiz components:

  • Single choice

    Select the correct answer from a number of options

  • Multiple choice

    Select one or more answers that apply from a number of options

  • Ordered list

    Move options into their correct order using drag and drop

  • Groups

    Move options into their correct groups using drag and drop

  • Keywords

    Type keywords to answer requirements

  • Comments

    Type a number of words to answer

Content components:

  • HTML

    HTML formatted content

  • Embedded media

    Embedded video player using iframe

  • Link

    External url

  • Section

    Split quiz into sections

Reusable elements

To create reusable Web Components you can use the Polymer Seed Element which sets up a test, demo and documentation page. But rather than have the overhead of managing and publishing multiple custom elements during development, it was faster to have the custom elements bundled with the project – the idea being once we had finished the project we could extract and publish them as separate elements. (One ‘gotya’ to be aware of is that custom element names need to be hyphenated.)

All the Web Components for the Badge Builder needed to operate on two different views – the editor (CMS) screen and the interactive viewer (quiz) screen.

Badge Builder Editor (CMS)

BadgeBuilder-MicroBit

Badge Builder Viewer (quiz)

BadgeBuilder-MicroBit-Quiz

For the editor we wanted the quiz elements to be pretty WYSIWYG so for the most part the same element was used for the editor and viewer. The Polymer dom-if template was a good way to render the parts unique to each view in this case.

Displaying dynamic content using Web Components

To render the dynamic components to the page an empty placeholder was used.

The quiz content was loaded with Polymer’s iron-ajax element and the array of content was parsed in the response handler using a switch statement to check against specific element types.

Most elements are unique and are handled separately, apart from the default case which for elements that share exactly the same object properties. In this case the element type is passed to the function to create the element and set the properties by using the document.createElement method. (The other option is to define custom constructor but it’s not necessary.)

Once the element has been created and properties set it still needs added to the DOM. This is handled with appendChild(element) Javascript method. Notice that we can use Polymer’s ‘$’ selector to append children to our div tag with id="components". Because the elements are added dynamically in Javascript and therefore manipulating the DOM it is necessary to wrap the selector using the Polymer DOM API.

The add element method was used when loading saved content, but also when adding new elements to the page. One usability tweak is to have the page scroll down to show a newly added component. The problem with scrolling down here is that height of the new element will not be known until the DOM has updated, so we will need to add a listener to handle the dom-change event. Now we can scroll down to see the element we have added.

Saving dynamic content using Web Components

To save the dynamic content for each element I would need to be able to get the content as JSON. A nice way to handle this for all components is to use a shared behaviour. This would hold the _id property assigned by the database and also assign the element’s type using the built-in method this.localName.

Finally, when changes need to be saved it’s just a case of returning a list of all our custom elements and grabbing the data as JSON using the element’s getData behaviour. This data array can then be posted using Polymer’s iron-ajax element for saving to the database.

Developing a web app that behaves like a native app

Like many developers out there I started out coding for the web. So you might think it would be easier to develop a web app than a native app, right? The short answer is no… but web app development is getting better and the performance gap is closing.

Thoughts on web app vs native app development

Delivering a world-class UX is the main reason to opt for native development. Web app performance has quite some way to go especially on the vast majority of low spec devices. For example even if you get your web app running at a buttery smooth 60fps in iOS Safari, it doesn’t automatically mean you get that sort of performance in an app’s UIWebView.

iOS Tip: Don’t be content testing any web app or web UI framework in Safari and think that it works. A real web app development test is only done by running it inside an embedded WebView.

What you have to be careful off is getting sucked into some web app framework because you can get some decent results pretty quickly, but as soon as you add a little more complexity things can start to break and the speed of development will slow as a result. Whereas while native development might take longer to learn initially, after that you can start building some pretty slick apps just using the standard suite of UI components provided.

Ultimately things are getting better for web app development but probably not enough as to make native app developers want to consider switching. But with all the modern browser javascript speed optimisations and mobile devices becoming ever more powerful it’s worth considering a web app where the ability to share code is most important. After all who wouldn’t rather develop code once that works across mobile and desktop and leverages the extensive web developer knowledge base? So the compelling reason to build a web app is that your code should run on any screen that runs a modern browser.

Postcard app

I’ve been involved with developing the Postcard app which is a web app for demoing a peer to peer web experience using the Thali Cordova plugin. Throughout the design, development and build process of this web app I’ve encountered a number of issues or pain points and thought it would be good to share the golden nuggets I’ve learnt while trying to develop a web app that behaves like a native app!

Postcard app icon

Icons and splashes generator for Cordova web app

With any project I always like to start with design before I jump into development. Design is a time consuming task but some things can be automated like resizing all those app icons and splashscreens across multiple platforms. I wrote a time saving Ruby script to build app icons and splashscreens for iOS and Android with Cordova’s image filenames and sizes. (Usage and instructions are in the gist)

Designing a web app across different screens – live!

Many web apps take advantage of node and there is a great module for designers called BrowserSync.

BrowserSync allows you live preview all your design or code changes across multiple screens. That means you can test your web app in real-time on any browser on Mac or Windows as well as hook up the web app on iPhone, iPad or Android. Also when you interact on one screen for example following a link or scrolling the page this automatically updates everywhere else. This is a must have for any responsive design or adaptive design work!
BrowserSync demo

Polymer 1.0 – a UI kit for web apps

For the UI design side of things I choose Polymer 1.0 due to it’s host of web app elements inspired by a native app’s UI kit. Initially I didn’t like all the custom element names, as this reminded of an Angular wild west of element names but you can quickly learn the Polymer core elements and view the documentation and source behind them. Also there is a benefit to this as it prevents the usual ‘div nest of inception’ meaning that an HTML layout can be understood at a glance.

Getting started developing with Polymer

The trickiest thing is actually getting all the Polymer elements you need to use as these all come separately which of course makes sense later for production. But do yourself a favour and just install all the paper, iron and neon elements for no hassle development.

Should I use Polymer’s ‘on-click’ or ‘on-tap’ event?

There is a 300ms click delay issue that affects mobile web apps. The good news is that there is a simple fix by using the viewport meta tag with width=device-width property. But the bad news is that this trick only works in Chrome 32+ on Android.

Thankfully Polymer tries to handle this issue for you if you use the on-tap event however it doesn’t appear to currently trigger a click on Mac Safari (using an iframe web app). So if desktop Safari compatibility is more important then you may have to stick with the standard on-click event until this is fixed. Or just incase you already use a ‘fast click’ javascript polyfill it may run into issues due to click delay complications with the iOS 8 web view.

Meet ‘iron-list’ – the UITableView for web app

Polymer’s iron-list element is essential for scrolling large amounts of data on mobile devices. It does this by using a virtual list and recycling (20) cells to handle smooth scrolling of 1000s of items. One note of caution is that this runs fine in Safari browser but there is currently a scrolling issue in iOS 8 WebView beyond a certain number of items. If only UIWebView would behave the same as Safari then development would run so much smoother!

Make it feel like a native app – not a web site!

It’s important to make sure things act like an app and not feel like a website thrown inside a Cordova webview. There are a couple of giveaway indicators that can be fixed, although not everything will behave perfectly.

Disable the scrolling bounce effect

While adding the magical web app meta tags will give you full screen control in the browser it doesn’t get rid of the web page scrolling spring effect common with iOS and Mac. Now while the spring effect provides a wonderful UX in a web browsing context – native app’s don’t spring! To disable this unwanted behaviour the first thing to do is to enable the DisallowOverscroll preference in Cordova’s config.xml.

If you are not using Cordova then you can disable the iOS webview scroll:

It’s always a good idea to do a CSS reset on the html,body and then add the following to disable the bounce effect in the browser:

Disable select copy/paste

Another annoying web behaviour inherited is that everything is selectable on a web page. Again a useful behaviour in a web browsing context but not so much with a web app. Besides not feeling right there is a UX issue if a user taps the ‘wrong way’ instead of activating a button click as expected they end up in a text selection mode. The easiest workaround is setting user-select to none on the ‘body’. NB: If your web app contains form inputs then you can exclude those inputs using the :not() CSS selector but I find it easier to switch everything off by default.

The one problem you still get with iOS UIWebView is that you always get a magnifying glass when doing a long-press and unfortunately there is no simple way of disabling this without hacking UIWebView private APIs.

Prevent scrolling nav bar when editing input

A quirk with web apps on iOS is trying to fix a nav bar so it won’t scroll off the screen when editing an input or textarea that would obscure the soft-keyboard when it pops up. One trick is to position your input as high up the page as possible in order to avoid the issue. But sometimes this isn’t always possible so the other option is to try a hacky workaround discussed on SO which also seems to work pretty well with Polymer:

In Cordova if you want to enable Javascript focus() calls to open the soft-keyboard you can disable the KeyboardDisplayRequiresUserAction preference. Although bear in mind iOS8 now supports focus() calls but I found the input and keyboard can lose connection sometimes.

Problems with web app when running as a native iOS app…

I encountered quite a number of problems when running a web app inside the iOS 8 UIWebView. I have listed the main issues below to watch out for with possible workarounds:

[WebActionDisablingCALayerDelegate setBeingRemoved:]: unrecognized selector sent to instance 0x174009d20
*** WebKit discarded an uncaught exception in the webView:willRemoveScrollingLayer:withContentsLayer:forNode: delegate: -[WebActionDisablingCALayerDelegate setBeingRemoved:]: unrecognized selector sent to instance 0x174009d20

Solution: Add body style for -webkit-transform. This WebView bug occurred when animating an element sliding up from the bottom of the page. It caused the animation to jump and skip frames and seemed to trigger memory warnings.



[46377:7026777] Received memory warning.

Solution: If you’ve tested for memory leaks then try disabling animations. If this solves the issue then try to optimise your script so that expensive business logic is called only after animations are completed.



Message from debugger: failed to send the k packet

Solution: Keep app awake! In the app delegate enable setIdleTimerDisabled:

iOS Tip: When testing web apps on iOS it can take so long to build and debug on device that the screen locks and the deploy fails. Use the setIdleTimerDisabled to keep the app alive for debugging!