Universal Windows Apps for Microsoft Surface Pro Hybrids / MS Edge with Ext JS 6

Posted on in Ext JS 6

Now that hybrid touch pc’s / tablets, like the Windows Surface Pro, got popular, I often hear people asking me, if it’s possible to create Ext JS apps for Windows tablets?
Ext JS 6 has support for Windows 10. The classic toolkit supports IE8 and up, and the modern toolkit supports the Edge browser. It even contains a Windows mobile theme!

sp4

Ext JS 6 is also the framework, with supports you by creating universal apps. With one code base you can create Windows desktop apps for mouse and keyboard usage, and tablet interface for touch usage.

Just generate your project like:

sencha generate app MyWindowsApp ../mywindowsapp

This will create a folder structure for you, with a classic and modern toolkit folder, to branche out the separate views. For more information about universal apps, please see my previous blog post: https://www.leeboonstra.com/developer/webinar-secrets-to-building-a-great-looking-universal-app/

The fun stuff comes into the app.json file. I’ve created these build profiles:

“builds”: {
 “desktop”: {
   “toolkit”: “classic”,
   “theme”: “theme-crisp”
  },
 “tablet”: {
   “toolkit”: “modern”, //classic
   “theme”: “theme-windows” //theme-crisp-touch
  }
}

You can set the tablet theme to windows mobile, or in case you prefer to make use of the classic toolkit, then switch the theme to “theme-crisp-touch” for more whitespace around buttons and links, and bigger icons and buttons. So you won’t miss tap.

My index.html file, has an Ext.beforeLoad method, that looks like this:

Ext.beforeLoad = function (tags) {
var s = location.search,  // the query string (ex "?foo=1&bar")
      profile;


      if (s.match(/\bdesktop\b/)) {
         profile = 'desktop';
      } else if (s.match(/\btablet\b/)) {
           profile = 'tablet';
      } else {
         profile = tags.desktop ? 'desktop' : 'tablet';
      }


      Ext.manifest = profile;
};

Ext.platformTags is a singleton http://docs.sencha.com/extjs/6.0.0/classic/Ext.html#property-platformTags within Ext JS which can contain information about what type of device I am running on. When I execute this command on my Windows Surfarce Pro tablet, I get the following information:

Ext.platformTags.tablet
> false
Ext.platformTags.touch
> 10
Ext.platformTags.edge
> 15

If I switch to touch / tablet mode, for example by removing my tablet from the dock:

Ext.platformTags.tablet
> false
Ext.platformTags.touch
> 10
Ext.platformTags.edge
> 15

Hmm. Not what I expected. Unfortunately, there is no out of the box way, on how you can detect the tablet mode, from your browser, or from the Ext.platformTags singleton.

Now obviously you can create a button in the top of your app, which contains an onclick handler that does something like this:

    onTablet: function(){
        var url = window.location.href;
        url = url.split('?')[0];
        window.location.href = url + '?tablet';
    },
    onDesktop: function(){
        var url = window.location.href;
        url = url.split('?')[0];
        window.location.href = url + '?desktop';
    }

It would be nicer, if my device can detect this mode switch programmatically. Unfortunately, by the time of writing there is no HTML5 / JavaScript API solution, which can detect mode changes. I tried to look into projects like Apache Cordova, to figure out if there are native API solutions, but I couldn’t find it either.

I can’t check on touch input either, because on a hybrid machine, like the surface pro, touch input works regardless switching the mode, since the screen is just a touch screen.
So navigator.pointerEnabled will always return true.

So for now, we are left with a trick. It’s a smart trick though. And it won’t work in IE11 or below.
Which is ok, since for our demo, we will make use of the modern toolkit for tablet mode, and modern toolkit is for modern browsers, like Microsoft Edge.

However, it won’t work in any other browser either. So not, in Google Chrome or Firefox. For those browsers, you will have to stick with the button switch approach.
This might be an ok solution for you, since we are talking here about developing universal windows apps.

In tablet mode; there is no browser scrollbar. The browser scrollbar will be 0, while on desktop mode, it will be a value in pixels. (like 12px).
Now, user: robocat created a working JavaScript example in a JSBin, where you can see a working demo: https://output.jsbin.com/puseco. The trick here, is to add an hidden div to your page body with overflow scroll, to start calculating the scrollWidth.
Now I was super amazed and surprised, but apparently Ext JS already has a built-in function like this! Yay. So you only need to call: Ext.getScrollbarSize(true) where you are forcing it to re-check it: http://docs.sencha.com/extjs/6.0.0/classic/Ext.html#method-getScrollbarSize

So on my Windows Surface Pro, in desktop mode, it will return:

Ext.getScrollbarSize(true).height
> 12
Ext.getScrollbarSize(true).width
> 12

And in tablet mode:

Ext.getScrollbarSize(true).height
>0
Ext.getScrollbarSize(true).width
>0

Great! We are getting close. Now let’s check and see if we can detect it automatically!
Most of the times, when switching modes, it will also fire a window resize http://docs.sencha.com/extjs/6.0.0/classic/Ext.container.Viewport.html#event-resize or a childmove http://docs.sencha.com/extjs/6.0.0/classic/Ext.container.Viewport.html#event-childmove event.
We can attach a resize listener on an Ext.Viewport, like our main.js file, and run the mode switch. Note the extra check that I created to make sure you are switching profiles. (Otherwise your app would keep on refreshing.)
Main.js

   listeners: {
        resize: 'onMainResize',
        childmove: 'onMainResize'
    },

MainController.js

   onMainResize: function(){
        var url = window.location.href;
        url = url.split('?')[0];

        //console.log(Ext.getScrollbarSize(true).height == 0);
        //console.log(Ext.manifest.profile);

        if (
            Ext.platformTags.edge > 0 &&
            Ext.manifest.profile == 'desktop' && 
            Ext.getScrollbarSize(true).width == 0 && 
            Ext.getScrollbarSize(true).height == 0
        ) {
           window.location.href = url + '?tablet';
        } else if (
            Ext.platformTags.edge > 0 &&
            Ext.manifest.profile == 'tablet' && 
            Ext.getScrollbarSize(true).width != 0 && 
            Ext.getScrollbarSize(true).height != 0
        ) {
            window.location.href = url + '?desktop';
        }
    },

Let’s finish this article with a bonus topic. Sencha has responsiveConfig to change configuration on runtime, based on criteria. http://docs.sencha.com/extjs/6.0.0/classic/Ext.plugin.Responsive.htm. Responsive Design in Ext JS, means it’s JavaScript configuration, which means that you can write any type of criteria. It also means, that you can change anything you like on runtime. This doesn’t necessary means that you have to change the look and feel. You can change anything, so for example also load different models, redraw or refresh a page. (..because you can override a setter/update method).
Here’s a simple example. Any property can be configured as long as it has an setter under the hood. (if not, you can create your own setters of course.)

plugins: ['responsive']
responsiveConfig: {
   tall: {
      tabPosition: 'left'
    },
    wide: {
      tabPosition: 'bottom'
     }
},

Now look into this customized example, where I override the updateMethod

config: {
  customTabPanel: false
},
plugins: ['responsive']
responsiveConfig: {
    tall: {
      customTabPanel: true
    },
    wide: {
      customTabPanel: false
    }
},
updateCustomTabPanel: function(isCustomTabPanel){
   if(isCustomTabPanel){
    //manually build my tabpanel, and do a whole bunch of
      //other stuff, like creating models or something
      //or destroying a screen and rebuild it
   } else {
      //code for when customTabPanel is false
   }
}

The criteria to choose from are:

tall — Viewport width < height regardless of device type
wide — Viewport width > height regardless of device type.
landscape — Like wide, but always true on desktop devices
portrait — Like tall, but always false on desktop devices
width — An expression that tests for the specific width of the viewport
height— An expression that tests for the specific height of the viewport
platform — An object containing various booleans describing the platform

So how can you create a custom criteria? With responsiveFormulas! http://docs.sencha.com/extjs/6.0.0/classic/Ext.mixin.Responsive.html#cfg-responsiveFormulas

        responsiveFormulas: {
            touch: function(context) {
                return Ext.feature.has.Touch;
            },
            notTouch: function(context) {
                return !Ext.feature.has.Touch;
            }
        },

I have used this example, for example in a chart. On a touch device I use pinch to zoom, and on a mouse and keyboard device, I use the crosshair interaction.
Although this is a great example, it would make less sense for a windows universal app, since hybrid tablet PCs have both interfaces: touch and mouse/keyboard support.
Maybe you are creating an interface that needs to support mouse/keyboard or touch support.
Do you have a tablet/pc hybrid and want to play around with this? Here’s my project on Github to fork:

https://github.com/savelee/sencha-windows-universal-apps

studio

(PS: I own a Microsoft Surface Pro 4, and the best thing of it, is it’s keyboard. 😉 - As a small hybrid touch windows PC it’s great. As a tablet, it really sucks. No matter to what mode you switch it, it feels and breaths like a PC with touch support. Certain things in Windows are designed for mouse and keyboard usage. And also, the way how it boots, load times etc, it just shows you, it’s a PC. ..but a really good one.)

How to Build a Great Looking Universal App with Ext JS – Part 2

Posted on in Ext JS 6

In part 1 of this series, I described what a universal app is and how it’s created in Ext JS 6. Now, I’ll show you how I built my application.

Folder structure

To create a high performance Ext JS 6 universal app, I used Sencha Cmd. I generated a workspace first, because in my folder I host multiple versions of my app (free and commercial), which all share the same code packages and framework.

To generate a workspace, I browsed to the downloaded Ext JS 6 SDK. From there, I typed the following command:

sencha generate workspace ../spotifinderworkspace6

This generated the following structure:

Generate workspace

Then, I generated the application. I called it _engine. Why? Because I can create customized versions of my app with different behavior or branding. For example, a music app that plays songs in Pandora. To do that, I would only need to extend the engine Ext.Application, and override certain elements.

Here’s how I generated the application:

cd spotifinderworkspace6/ext
sencha generate app Engine ../_engine

Generate application

Toolkits

The classic folder is the folder structure for the classic toolkit. It contains the rich components that are great for desktops (or tablets). Also, it has support for legacy browsers.

Here’s what my app in the classic toolkit looks like:

App in Classic toolkit

It kind of looks like Spotify. I used traditional desktop components with a custom stylesheet. Because the application is shown on a large screen, there is a lot of space for showing extras, such as the album artwork, additional information, and also the settings screen (which is docked to the side).

I created unique views. Some of these views require their own logic. That’s why my folder structure in the classic toolkit looks like this:

Folder structure in Classic toolkit

The modern folder contains lightweight touch components. These are great for touch devices, including phones (or in some cases, tablets too). These components are optimized for a touch experience instead of mouse and keyboard. Because these components are lightweight, they also perform really well on a mobile device which has less processing power.

App in Modern toolkit

Because the screen is small, just the absolute necessary components are shown. To open the settings view, tap the gear button. It will nicely slide in the settings screen with an animation.

Folder structure is small

Because it doesn’t contain too many components, my folder structure is small. Again, only views and some behavior code, which are required by this view, are unique. Everything else will be shared across toolkits.

The shared code can be found in the app folder:

Shared code in app folder<

Tip: You can extend from view controllers (VC) too.

For example, you could have a shared Viewport VC that contains most of the behavior. The Viewport VC of the classic and modern toolkit folders only contains code that’s required for their own components.

Here’s an example. Below is a snippet of the Viewport VC, which is located in the app/main/ folder. As you can see, it extends from Ext.app.ViewController. The class itself is called Engine.view.main.MainController.

Snippet of Viewport VC

Now, here is the code of the Viewport VC in the classic folder. It’s located in the classic/src/main/ folder, and this time it extends from Engine.view.main.MainController, which is the shared VC. Don’t forget to put an alias in this class. That’s how you would link this classic view controller to the classic main view.

Code of Viewport VC in Classic folder

Microloader

The microloader can detect on which environment it’s running, and serve the right experience. This means when I load my application on a desktop, I see my desktop version of the app with the Spotify theme, and when I open my application on an iPhone, I get the phone interface with the iOS theme.

All the magic here is in the Ext.platformTags. You can even run this command from your browser console, in an existing Ext JS 6 app. It will provide the object with all kinds of information, such as the browser version you’re running, OS, device type, etc tamiflu dosage for adults.

You can configure your app, so it serves the right experience. The secret here is the app.json file. You need to create build profiles, and you can bind every app.json setting you like to a build profile, such as the toolkit (component set) and the theme:

    "builds": {
        "classic": { //name of the build profile
            "toolkit": "classic", //component set
            "theme": "theme-spotifext", //name of the theme
        },
        "modern": {
            "toolkit": "modern",
            "theme": "theme-cupertino",
        }
}

Switching the experiences is handled in the index.html file. When you generate your application with Sencha Cmd, this will be all stubbed out for you.

Index.html file

MVVM Pattern

With Ext JS 6, you can use the MVVM pattern.

MVVM pattern

View – all components on your screen
ViewController – logics for a view
ViewModel – for binding data to a view

data model – structure of your entity
data record – the actual data
data store – client-side cache

All views in Ext JS can be nested, and so can the view models and view controllers.

Nested views, view models, and view controllers

The benefits of this pattern is that code is easy to read and maintain.
It’s a consistent file structure for your code and classes, and it facilitates code reuse.

Why Ext JS vs. Open Source

With Ext JS 6, you get an all-in-one solution. You don’t need to maintain various dependencies and have expertise in many different technologies that all need to work together.

For the application that I created, I used the following Ext JS 6 solutions.

Ext JS 6

Example Open Source Solution

Sencha Class System ECMAScript 6 Classes
Border Layout JS + CSS
MVVM Architecture Angular JS
Desktop App Bootstrap / Responsive CSS
Mobile App jQuery Mobile / Ionic
Promises ECMAScript 6
Grids jQuery Plugin
Touch Gestures / Events JS
Routing AngularJS Plugin
Offline Caching HTML5 / JS
Theming Sass / CSS
Sencha Cmd Grunt + Yeoman + Bower

I could have used an open source solution, but then I would have had to stack technologies on top of one another. For example, ECMAScript 6 is not supported by Internet Explorer yet. With Bootstrap or responsive web design, my users would have to download lots of code, which they don’t even see, and it’s not optimized for each device (as described in my previous blog post). There are jQuery plugins for grid components, but these are not half as powerful, and don’t perform well with large data sets. And who should I call when my AngularJS plugin suddenly stops working with the latest browser update?

My application is just a simple app, and I already would have at least 10 dependencies. What about a real enterprise app, which has a codebase that’s 50 times bigger? I would need to have knowledge of all these various tools, cross my fingers that these technologies work well together, and are future proof for the next 5 or 10 years (while browsers are upgrading).

Conclusion

That’s exactly the reason why I chose Ext JS 6. An all-in-one solution, where everything is configured the same way, every piece works together, and looks the same. And because Sencha is a commercial company, there is always a support number to call, and they will make sure that my app works in the future.

How to Build a Great Looking Universal App with Ext JS – Part 1

Posted on in Ext JS 6

Background

Back in 2011, I wanted to create an app. I love music, and I am a huge fan of Spotify. I love that I can listen to a huge database of songs. The only thing that always bothered me was that I had to manually search for songs. That’s fine when I’m using my laptop, but it’s not so great when I’m walking or biking, and I use Spotify on my phone. Typing on a virtual keyboard is just not fun.

So, I created a Sencha Touch app that could connect to my LastFm account (an online database that can “scrobble” and save music that you’ve listened to). My app lists all the music I like, and with one button tap, I can play the song in Spotify.

Sencha Touch app

Sencha Touch was great for building this app. It has a powerful, smooth scrolling list and stylesheets that make my app look great on my iPhone. It was quick to build and ready to use.

I liked this app so much that I decided to share it. I deployed my app in the Apple App Store, by wrapping it with Cordova. Then, I noticed I was also using it on my desktop. It was just easier to choose songs, so I deployed my app on my webserver and hosted it in the Google Chrome Web Store.

A week later, I checked my reviews on the Chrome Web Store. I was heartbroken to see that I only had bad reviews: “What a weird looking app” and “Why can’t I use the mouse wheel to scroll?” It totally made sense though – my app was originally designed for iPhones. It looked like an iPhone app because of the stylesheet, but it behaved like a touch app because it was built with Sencha Touch using Touch events & gestures. To scroll the music list, users had to tap the list and drag it up or down. That works great on touch devices, but it’s odd on a desktop. I realized that I needed a desktop version of my app too.

Ext JS app

That was when I started to play around with Ext JS, which is a great framework for creating desktop applications. It has fast performing desktop components like the grid, and a similar MVC architecture and class system as in Sencha Touch 2. I created the desktop version, and later I migrated my Ext JS 4 app to Ext JS 5. I chose Ext JS 5 because I wanted to clean up my code and use the new MVVM pattern, and also use touch events, responsive design, and stylesheets for a tablet version of my app. But when I realized I had to maintain two different code bases, with two frameworks, I turned to Ext JS 6.

Now, with Ext JS 6, you can create universal apps. With one codebase, your apps run on any supported device type.

Tech Specs of My App

Before we move on, here are some technical specs for how my app works.

  • To play songs in Spotify, I use URL Schemes.
  • To retrieve data from LastFm, I use an external JavaScript API, that must be in a custom written proxy, which is part of a package.
  • The LastFm username is saved in the HTML5 browser local storage.
  • Phones will get modern touch components, for now just iOS views.
  • Tablets and desktops will get rich classic desktop components, with a Spotify look & feel.
  • MVVM pattern is used.

Universal Apps vs Responsive Web Design

There are differences in how Universal Apps work in Sencha frameworks, and how Responsive Web Design is used for mobile websites to respond to certain environments.

Responsive Design for websites is usually done within a stylesheet using relative units, values in percentages, and breakpoints (mediaqueries) that can re-order and show/hide certain HTML elements.

Take a look at the code snippet below:

@media all and (min-width: 800px) and (max-width: 1024px) {
 ul li.products {
    width: 50%;
    display: inline-block;
 }
}
@media all and (min-width: 1025px) {
 ul li.products {
    width: 25%;
display: inline-block;
 }
}
@media all and (max-width: 799px){
 ul li.products {
    display: none;
 }
}

The previous code example has a few breakpoints. Small screens with a viewport width smaller than 799px, screens between 800px and 1024px, and large viewports with screens wider than 1025px. On big screens, there are list elements positions next to each other with a size of 25% width. For medium screens it’s 50%, and for small screens (such as phones), the list will be hidden.

This technique is great for websites, but not for real world applications. Why?

  • When you are on a mobile phone, chances are that you are on a slow mobile network or using an (expensive) data plan. That’s very expensive, and you’re not even seeing these elements and data.
  • Also, you may want to change the text on a smaller screen size. I’ve worked a lot with copywriters, and they believe that text on a phone should be written differently than what’s on a desktop. Nobody likes to read whole books of text on a small screen.
  • By using only responsive web design, you’re probably missing a lot of opportunities to refine content or use device features, because you’re serving one code base. For example, your fancy floating calendar component looks great on a desktop, but it doesn’t work well on a phone. A text hyperlink works fine when you control your app with a mouse, but you will probably have trouble tapping it on a small touch device. Users are used to native app behavior, such as the built-in datepicker on an iPhone, or a big button as a link. Most often, responsive mobile websites don’t deliver the same experience as a native app.

That’s why the Sencha approach is different and better. Universal apps in Ext JS 6 are far beyond just responsive design. We know you want to control the UI with more than just re-ordering, show/hiding elements. There are various approaches that you can take, and most of these, are not just limited to views. You can also control data and behavior.

Toolkit / Universal app approach: The user experience is chosen before the framework is downloaded.

How it works: You can create different views with touch (modern toolkit) or desktop (classic toolkit) component sets tamiflu generic. The microloader will detect your device, OS, or browser, and serve the right component set for you, by loading a build profile. You can attach a particular theme to that build profile. You can create as many build profiles as you like, and it’s not only limited to views, you can also serve different data stores or behavior code.

In the screenshot below, you can see how my application looks on a desktop, and how it looks on an iPhone:

App UI on desktop and phone

Device specific stylesheets: The stylesheet is chosen before the framework is downloaded.

How it works: Ext JS 6 ships with themes (Sass stylesheets) that are great for classic toolkit, touch interfaces (with the look and feel of iOS, Android, and Windows Phone), or stylesheets that look great on both toolkits. The microloader can detect the environment, and serve the correct theme.

Device specific stylesheets

Device Profiles: The profile for each user is chosen when the application launches.

How it works: It’s possible to create a device profile, which contains different code or different component positioning. For example, when you open an email app on your phone, you see a list with an overview of all emails, and when you tap on an item, it opens the email on top. However, when you open the email application on a tablet, the list is docked to the left, and the body of the email is positioned on the right side of the screen. You can achieve these layouts with device profiles. It’s not just re-positioning certain components (list docked or not). It’s also different behavior under the hood (when you tap an email, it opens an extra window on top vs. loading next to the list).

Device profiles

Responsive Design with JavaScript: Code responds to custom criteria at runtime.

How it works: JavaScript responds to certain conditions (like screen size) at runtime. It’s possible to create any custom condition and have the view, data, or behavior respond.

Responsive Design with JavaScript

Traditional Web Design with CSS: The view responds to an environment at runtime.

How it works: You can also use traditional responsive web design. You can use it for styling simple elements in views.

Conclusion

In this article, I’ve described what an Ext JS 6 universal app is, what I like about the universal app approach, and why I converted my app. In Part 2, I’ll show you exactly how I converted my music app to a universal app.