In a previous post, I walked through the simple process of creating a custom UI for a toolbar in Sencha Touch. Since theming in Sencha Touch and ExtJS 4 are extremely similar, I thought I’d walk through the same process, but with an ExtJS 4 flair.

In fact, the last post that I wrote was meant to be this one. However, as I worked through the process of creating a custom UI, I found that the setup of Compass compilation for ExtJS 4 might have some *gotchas* that could trip people up (like me), so I decided to start from the beginning, get a solid foundation, and now move on to the actual fun stuff.

Ok? Good? On we go!

What We’re Going to Make

In this walkthrough, we’re going to try to accomplish a few things.

Objective #1: I want to show how it’s perfectly possible (maybe preferable?) to mix custom UIs with the stylesheets/images/etc. of the “default” ExtJS 4 theme. In this particular example, we’re going to create a custom Ext.ProgressBar UI.

Objective #2: We’re also going to create a custom stylesheet that produces only the minimum of what we need for the “application” we’re going to build. So instead of having a monster ext-all.css file that includes ALL the styles for the entire library, we’re going to pare down our final stylesheet to only the bare bones of what we need.

Objective #3: We’re going to use the SDK’s “slice” tool to create “backup” images for old, crappy browsers that don’t support CSS3 goodness like background gradients and borde-radius.

BTW, I want to be completely up front about this. Nothing I’m doing here is “new” to me. The basic structure of what we’ll be doing is shamelessly stolen from the Theming Guide on Sencha’s website. I wanted to walk through the process, though, a bit more in depth with screenshots, code snippets, and real examples, just so any trip-ups can be explained and dealt with along the way.

Let’s Get Started

In what follows, I’ll be using the structure that we setup in the last post on this subject. Obviously, you can flex it to suit your needs; however, if you want to follow along step-by-step, be sure to take care of that first. If you’d like some source code, grab it on GitHub.

Before we start creating our custom UI, let’s build our “app.” First, let’s create an HTML file in the root of my project (playground). Now, let’s create a JavaScript file that will house our app’s code.

Here’s the JS code:

playground/js/progress.js

Ext.onReady(function(){
   var pb = Ext.create('Ext.ProgressBar', {
      margin: 50,ui:'default'
   });
   // Wait for 5 seconds, then update the status el (progress bar will auto-reset)
   pb.wait({
      interval: 500, //bar will move fast!
      duration: 50000,
      increment: 15,
      text: "Hi, I've got a custom UI...",
      scope: this,
      fn: function(){
         p.updateText('Done!');
      }
   });
   var pa = Ext.create("Ext.panel.Panel", {
      title: "I'm a regular 'default' UI Panel",
      width: 500,
      items: pb, // put the progressbar in our panel
      floating: true,
      renderTo: Ext.getBody(),
      closable: true
   })
})

Here’s the HTML file:

playground/progress.html

<html>
   <head>
      <title>Custom Progress Bar UI</title>
      <link rel="stylesheet" type="text/css" href="extjs/resources/css/ext-all.css">
      <script type="text/javascript" src="extjs/ext-all.js"></script>
      <script type="text/javascript" src="js/progress.js"></script>
   </head>
   <body></body>
</html>

Once you’ve got these set up, go ahead a open your file in the browser. You should see a fancy blue panel, which contains a fancy blue animated progress bar.

Now that we have something that’s working, let’s get down to styling the darn thing!

Ok, the first thing we’re going to do is to make a copy of our “my-ext-all.scss” file with the playground/extjs/resources/custom folder. Since we’re making a custom Ext.ProgressBar UI, I’m going to call this new file “progress.scss” (if you can’t tell, I’m a sucker for originality). Since our config.rb file was working as expected in our last walkthrough, it’s fine how it is; no need for us to mess with it anymore.

Now, open up progress.scss. At the very top, you’ll see a variable called $include-default. If it’s not already, set it to false. This tells the compiler to NOT include the entire all components in our final .css file. Also, setting this to false will allow us more granularly specify exactly what components we want to include (see Objective #2 above).

Moving on down the file, we’ll come to a section that has a list of all the components. It should look something like this:

@include extjs-boundlist;
@include extjs-button;
@include extjs-btn-group;
@include extjs-datepicker;
@include extjs-colorpicker;
@include extjs-menu;
@include extjs-grid;
@include extjs-form;
   @include extjs-form-field;
   @include extjs-form-fieldset;
   @include extjs-form-checkboxfield;
   @include extjs-form-checkboxgroup;
   @include extjs-form-triggerfield;
   @include extjs-form-htmleditor;
@include extjs-panel;
@include extjs-qtip;
@include extjs-slider;
@include extjs-progress;
@include extjs-toolbar;
@include extjs-window;
@include extjs-messagebox;
@include extjs-tabbar;
@include extjs-tab;
@include extjs-tree;
@include extjs-drawcomponent;
@include extjs-viewport;

If we leave this as is, the compiler is going to pull in all of the style rules for these components into our stylesheet. However, since we’re only using 2 of them (panel and progress bar), let’s get rid of the others.

The final list should look like this:

@include extjs-panel;
@include extjs-progress;

Awesome. Ok, the final line in our progress.scss file is the variable $relative-image-paths-for-uis, and is set to true. I’ll leave the note for you to read, but let’s leave its value as true.

Excellent. So these slight modifications, our progress.scss file looks like this:

// Unless you want to include all components, you must set $include-default to false
// IF you set this to true, you can also remove lines 10 to 38 of this file
$include-default: false;

@import 'compass';
@import 'ext4/default/all';

// You may remove any of the following modules that you
// do not use in order to create a smaller css file.
@include extjs-progress;
@include extjs-panel;

// This line changes the location of your images when creating UIs to be relative instead of within the ExtJS directory.
// You MUST set this to true/string value if you are creating new UIs + supporting legacy browsers.
// This only applies to new UIs. It does not apply to default component images (i.e. when changing $base-color)
// The value can either be true, in which case the image path will be "../images/"
// or a string, of where the path is
$relative-image-path-for-uis: true; // defaults to "../images/" when true

Before moving on, let’s go ahead an compile. I want to show that while we haven’t actually done any style customization yet, we can reduce the size of our CSS file by only including the components we need.

To compile, navigate to the custom folder and execute the compass compile command. Once this completes successfully, you should see a new CSS file in the playground/extjs/resources/css folder called progress.css.

Now go back to your progress.html file and change the stylesheet link to point to this new CSS file. Reload the page. If everything compiled correctly, you shouldn’t notice any difference. However, if you look at the progress.css file itself, you’ll notice that it’s quite a bit lighter than the full ext-all.css. Yay, we did it 🙂 Objective #2 is complete!

Get on with the Custom UI Already!

Yeah, I know, we’ve gone through a lot of background stuff. However, I think it’s important. After all, you don’t want to spend a bunch of time creating custom UIs if your .scss file’s basic structure won’t compile correctly. So I strongly advocate verifying that each step is working correctly before moving on. But since we’ve already done that, let’s get to some styling!

As with creating a custom toolbar UI in Sencha Touch, a great place to start with creating our custom ProgressBar UI is to figure out what the “mixin” for the ProgressBar UI looks like, what arguments it takes, etc. This will allow us to fully maximize the customization that we make in our custom UI.

To inspect the ProgressBar UI mixin, we can simply navigate to the following:

  • playground/extjs/resources/themes/stylesheets/ext4/default/widgets/_progress-bar.scss

On line 66, we’ll see the beginning of the extjs-progress-ui mixin. As you can see, this mixing accepts a number of arguments:

  • label (the name of our custom UI)
  • base-color (the foundation color for the UI)
  • border-color
  • background-color
  • bar-background-color
  • bar-background-gradient
  • color-front (the color of text when the progress bar is not behind the text)
  • color-back (the color of text when the progress bar is behind the text)

SImple enough. So let’s go back to our progress.scss file. After the @includes of the progress bar and panel, we can simply include our custom UI via the mixin. Here’s what my example looks like:

// set a custom progress base color to use in custom UI
$custom_pb_base_color: #Bfff00;
// here's the custom UI! :)
@include extjs-progress-ui(
   'lime',
   $ui-base-color: $custom_pb_base_color,
   $ui-background-color: $progress-background-color,
   $ui-border-color: adjust-color($custom_pb_base_color, $hue: 0deg, $saturation: -3.08%,       $lightness: -23.725%),
   $ui-bar-background-color: adjust-color($custom_pb_base_color, $hue: 0deg, $saturation: -11.37%, $lightness: 7.451%),
   $ui-color-front: #333333,
   $ui-color-back: #333333
);

In the above, I’m creating a new progress bar UI called “lime.”  I set a custom variable for the base-color I want to use, and then simply specify the colors that I’d like for the background, border, text, etc.

Once everything looks good, it’s time to compile. Now that my newly compiled CSS file has the “lime” ui for my progress bar, all that’s left is to apply the UI to the progress bar itself:

In playground/js/progress.js:

var p = Ext.create('Ext.ProgressBar', {
      margin: 50,
      ui: 'lime'
   });

Once I save this, I should be able to reload my HTML page, and see a beautiful lime green progress bar inside of the default blue themed panel.

Using this approach, we could create as many UIs as we’d like, simply adding similar snippets to our progress.scss file and recompiling when ready to use them.

Ah, But We Couldn’t Get This Far WIthout a Gotcha…

Yes, indeed. Even though we’ve successfully compiled our custom CSS file with a custom progress bar UI, there’s one slight problem…depending on how you look at it, at least. What’s the issue?

Pop open your progress.css file that you just compiled. If you go all the way to the end of it, you’ll see this style rule:

.x-nlg .x-progress-lime .x-progress-bar{background:url(‘../themes/images/default/progress/progress-lime-bg.gif’) repeat-x}

Notice the background-image with “lime” in its name. Now, if you go to that path, guess what you’ll find? You’ll find a progress-default-bg-gif file, but no progress-lime-bg.gif file. What gives?

Well, because ExtJS is a thoroughly committed cross-browser framework, the theming tools automatically create style rules to accomodate old, crappy browsers like < IE9. So for example, since older versions of IE don’t support background gradients and rounded corners in pure CSS. ExtJS 4’s stylesheets achieve the same effect through background images.

Therefore, when you create a custom UI, the compilation automatically provides a rule to a theoretical image that you will create, and even handily names it according to your theme.

At this point, you might feel hoodwinked. After all, who wants to be bothered with creating images for background gradients and rounded corners? Not me, for sure. And if you really don’t care, just skip it. However, if you need to finish out this process, the SDK fortunately has one more tool that will make this ridiculously easy…and you’ll never have to open Photoshop, not even once.

Sencha Slicing Tool

Sorry, the Sencha Slicing Tool won’t give you finely shaved roast beef (I tried…). However, it will help you create the “helper” images to support your theme in outdated browsers. Here’s how we do it.

The first step is that you have to create a “manifest” of your UIs and the components to which they correspond. This basically allows the Slicing Tool to determine precisely which images it needs to create based on the type of component, the parameters of your UI, etc.

The manifest is a simple JSON file. I added mine into the playground/extjs/resources/custom folder, right along side my custom .scss file.

Here’s what the contents should look like:

Ext.onReady(function() {
   Ext.manifest = {
      widgets: [
         {
            xtype: 'widget.progressbar',
            ui   : 'lime'
         }
      ]
   };
});

Nothing to it. We simply define the component’s xtype, as well as the label of our custom UI that we’re going to use for it.

If you don’t know the “xtype” for the component you’re using, the easy way to find out is to look up the component in the documentation. Next to the class’ name, you’ll see the xtype.

Now for the fun part. Open up Terminal, and navigate to the root of your project.

Now, we need to execute the proper command with the appropriate arguments in order to allow the SDK to do its magic. First, here’s the full string I used. Assuming you have the same setup, it should work without issue:

sencha slice theme -d extjs -c extjs/resources/css/progress.css -o extjs/resources/themes/images/default -m extjs/resources/custom/manifest.json -v

Here’s the break down of this:

  • slice theme : this the command for firing up the Slicing tool
  • -d extjs : -d is for the directory of ExtJS. In our case, this is “extjs”, relative to our root directory
  • -c …progress.css : -c is for the path to the CSS file which will be used in the Slicing process
  • -o …default : the path to the main “theme” images folder. Since our CSS is already pointing to the “default” theme’s images folder, that’s where we want the new image(s) created by the Slicing tool to go
  • -m …manifest.json: -m is for the path to the manifest.json file we created, which will tell the Slicing tool what kinds of images it needs to be creating, based on the custom UIs that we’ve specified
  • -v : this simply instructs the program to give us a listing of the images that its creating

Alright, good to go. Let’s run the command. You should see something like the following:

As you’ll notice, the tool has generated a new image, and saved it to the location we specified. If we go back and look now, we’ll see that we now have two images in our folder.

…And with that, we’re done. Objective #3 complete!

Wrapping Up

If you’ve been following along this and the previous posts on theming ExtJS 4 and Sencha Touch, I hope you’re catching on to just how powerful the theming possibilities are. Sure, it can take a few minutes to get setup…but once you are set up, making remarkable changes to your application’s theme is dead simple. As we’ve only just scratched the surface of what can be done, I hope you’ll continue to explore.