ExtJs 3.4 – Using XTemplate – Basics

ExtJs has a whole range of useful components, but sometimes a more appealing interface object is required or one that is lighter to render. ExtJs provides you with a function that makes it easier to basically make anything you want within the limits of HTML and CSS.

Traffic light example
For this article I will use a component we use to illustrate risk within our application in the form of a traffic light. I will extend this example step by step to give you an idea how to design a control from the ground up and give you a feeling on how easy it can be.

If you are searching for more in dept information about how to create any kind of control try “Using XTemplate – Advanced” article.

Note: I will declare all variables in global space to make the example easier to read and try out. Using it like this is strongly discouraged as it will NOT provide any data layer abstraction. So when you got 1000+ variables inside your applicition, you are bound to override one that is used by another part of the application. When I got the time I will provide you with an article that explains this more in dept and provides you with solutions.

Setup XTemplate: Hello world
This example will output an Ext.Window that shows hello world as content.

trafficLight = new Ext.Window({
   height: 100,
   width: 100,
   template: new XTEmplate('Hello world'),
   data: {}
})

trafficLight.show();

I agree, you can achieve the same with the HTML tag or by adding an element with that text. So lets make it more dynamic.
Now add message: ‘hello this world’ to the data object and replace hello world in the template with {message}

trafficLight = new Ext.Window({
   height: 100,
   width: 100,
   template: new XTemplate('{message}'),
   data: {
       message: "Hello this world"
   }
})

trafficLight.show();

Now the message shown is read from the data object provided. This works because this behavior is inherited from Ext.Component. When tpl and data are provided, it will attempt to fill the given element with these 2 variables on render.

Now their are 2 ways to move forward. You can either call overwrite on the tpl, supply the target and data directly or call update on this component by providing the data needed. I will show you both. But first we need to split off the data object, because in a window the property ‘data’ it is not available after render. This while we want it to know what the previous state of the window was.

trafficLightData = {
   message: "Hello this world"
}

trafficLight = new Ext.Window({
   height: 100,
   width: 100,
   template: new XTemplate('{message}'),
   data: trafficLightData
})

trafficLight.show();

Call update on component
There, now the easiest way is the following which uses the internal update function to handle the request.

trafficLightData.message = "Goodbye and thank you for all the fish";
trafficLight.update(trafficLightData);

Call overwrite on the template
Although the following example is more ‘difficult’ and does not provide extra functionality in this example. I would like to show it to you because you can use it to apply one template to multiple components. Because it uses element as a target you can apply a template to Objects that are not inherited from Component.

trafficLightData.message = "Goodbye and thank you for all the fish";
trafficLight.tpl.overwrite(trafficLightData.body, trafficLightData);

In short what I do is call overwrite on the Template, the same method used by update(), but provide the target myself. Which is Window.Body, the element that shows the content part of a Window.
Note that this only works when the Window is rendered as the body element is created then.

Example adaptive render
Now this does not at all look like a traffic light. So let’s change that.

trafficLightData = {
   color: "red"
}

trafficLight = new Ext.Window({
   height: 100,
   width: 100,
   tpl: new Ext.XTemplate(
       '',
           '
', '
', '
', '
' ) }) trafficLight.show();

Wow, what is all this?
Well first is the template: When you keep adding string as parameters, these will be appended to the template. So this makes it a lot more readable. Then I have added 3 bullets using HTML entity • • and put them in to div as the conveniently puts them on new lines.

Next, let’s make the component show the actual value, which is red as shown in trafficLightData.

trafficLightData = {
   color: "red"
}

trafficLight = new Ext.Window({
   height: 100,
   width: 100,
   tpl: new Ext.XTemplate(
       '',
           '
font-size: 20px;"•
', '
font-size: 20px;">•
', '
font-size: 20px;">•
', '
' ) }) trafficLight.show();

Now this is one of the more interesting things of a template. When is used, you can add logical expressions, loops and functions in the template. In this example I use IF. Now inside the if attribute I have put “color==\’red\’”.
When a value is not inside ” it is seen as a variable that it will try to get from the data object. When put between ” it becomes a string you can use to compare. So this is essentially a simple if construction, that adds ‘ font-size: 20px;’ to the style attribute of the div when true.

Example click events
Now it makes the red light show up on default, but we want it to change dynamically, on click for example. So let’s do that first.

trafficLightData = {
   color: "red"
}

trafficLight = new Ext.Window({
   height: 100,
   width: 100,
   tpl: new Ext.XTemplate(
       '',
           '
font-size: 20px;">•
', '
font-size: 20px;">•
', '
font-size: 20px;">•
', '
' ), colorSwitch: { red: "green", orange: "red", green: "orange" } }) trafficLight.on("afterrender", function() {     trafficLight.body.on('click', function(){         trafficLightData.color = trafficLight.colorSwitch[trafficLightData.color];         trafficLight.update(trafficLightData);    }, this); }, this); trafficLight.show();

Although not very elegant this will make the traffic light switch from red -> green -> orange -> red. This is achieved by making an event click on Window.body which is created after render of the Window. Then the colorSwitch object is used to retrieve the next value. Then update() is called with the updated value.

Now to make a more useful component out of this you probably want to click the color you would like to select and be able to retrieve it.

This requires the following, you need to know which element has been clicked. You can make a listener for every rendered element, but this is heavier and in my opinion not a very nice solution. Instead we introduce our own attributes on the rendered elements. And let this same event return the element that was clicked.

trafficLightData = {
   color: "red"
}

trafficLight = new Ext.Window({
   height: 100,
   width: 100,
   tpl: new Ext.XTemplate(
       '',
           '
font-size: 20px;">•
', '
font-size: 20px;">•
', '
font-size: 20px;">•
', '
' ) }) trafficLight.on("afterrender", function() {     trafficLight.body.on('click', function(fEvent, fHtmlElement, fOption object){         //get attribute from element. See W3schools get getAttribute() from HTML DOM element for details.         var colorValue = fHtmlElement.getAttribute("valuecolor");         //safegaurd. The user can click on something else then the lights.         if(colorValue){            //directly change the color variable by feeding the color value from the element to the colorSwitch object            //which returns the next color            trafficLightData.color = trafficLight.colorSwitch[trafficLightData.color];            //update from template            trafficLight.update(trafficLightData);         }    }, this); }, this); trafficLight.show();

Et voila. As the data object holds the actual value that can be used to identify the current state of the Component and the Component shows the correct state.

Optional improvements
To make this component more useful it needs a couple of things.

Use a Component or Panel as you base instead of Window, it’s more easily usable inside layouts. You might even want to consider using Ext.form.Field as a base is even lighter.

Give it fixed height and width, else you need to redesign the layout to scale.

You can also make it dynamic by being able to add any colors by a config option.

Expose something like an setValue and GetValue so you don’t have to fiddle with the data object and Update(). You might also want to expose an onValueChange() or similar event.

You can use background-color or border color to make the selection more visible and use a pointer on the values to make it appear clickable.
Note: CSS code with Internet Explorer ‘hack’
cursor:pointer;cursor:hand

Final thoughts
Making a component like this is (arguably) easy. This is one of the things that make ExtJs stand out as it gives you tools, but also the possibility to easily extend on those tools to suit them for your needs. To actually create a new component you might want to look at our tutorials we have about extending and creating new components.

The possibilities of XTemplate are not exhausted by a long shot, see my article about advanced XTemplating to get a grip on those. But in the mean time, I hope you have been able to follow up on my rambling and have a grasp on the basic concept of the XTemplate.

Have a nice day.

December in the it department

While December for most people is a cheerful and happy month it is also has another side most commonly experienced by the IT department.

  • Spam rises notably
  • Hack attempts rise significantly (strangely the week after the Paris attacks they skyrocketed from French ip’s)
  • Server loads become more spastic, especially in retail

This year santa claus appears to be handing out free .biz extensions as a lot of spam (neatly formed and a great pain for the spam filters I might add) is arriving from freshly registered domains.

A quick example over the last 24 hours, for every ham e-mail there are 1.6 spam! (usually it’s below a 1:1 ratio)
spam 09-12-2015
Ham 09-12-2015

ExtJs 3.4 – Using XTemplate – Advanced

This article goes more in dept on XTemplate usage, for an outline, look at “Using XTemplate – Basics”.

Feeding an object to XTemplate
Quick refresh. Anything within the root of given data object can be called in the template using {propertyName}.

var tpl = new Ext.XTemplate(
    '

Name: {name}

', '

Full name: {nameObject.first} {nameObject.last}

' ); var dataObj = { name: 'demo text', nameObject: { first: 'thirst', last: 'past' }; tpl.overwrite(panel.body, data);

Simply using name.firstname could be using to reach deeper elements when objects are nested.

If statement
In the simple example we already showed you how to use the if statement.

var tpl = new Ext.XTemplate(
    '

Name: {name} good

' ); var dataObj = {    name: 'demo text' }; tpl.overwrite(panel.body, data);

The if statement also supports lower then < and higher then > as well as the <= and >= variations.
Although these expressions work on string, we do not recommend using them like that because it provide tricky behavior one might only understand when you know how character encoding works.

Feeding an array of objects to XTemplate
Then more interesting things. You can loop through arrays and template objects inside them.
For example:

var tpl = new Ext.XTemplate(
    '

Name: {name} good

', '', 'Name: {name}
', 'Age: {age}
', '
' ); var dataObj = {    name: 'demo text',    kids: [         { name: "sammie", age: 10 },         { name: "tom", age: 13 },    ] }; tpl.overwrite(panel.body, data);

Both kids will be shown with their ages. When looping an array of strings use . to point to the base of the iterated element.

Using self defined functions inside the template
Closing the parameter list of a template with an object abless you to set things to the template object, but can also be used to add self defined functions.

var tpl = new Ext.XTemplate(
    '

Name: {name} good

', '', 'Name: {name}
', 'Age: {age}
', 'Baby: ', 'Yes', 'No', '
',     {         //xtemplate properties         compiled: true,         disableFormats: true,         //custom function         isBoy: function(name){             return name == 'Timmy';         },         isBaby: function(age){             return age < 1;         }     } ); var dataObj = {    name: 'demo text',    kids: [         { name: "sammie", age: 10 },         { name: "tom", age: 13 },         { name: "lillie", age: 0 },    ] }; tpl.overwrite(panel.body, data);

As you can see above a function is used along with the for function, to loop through the children and see if they are babies.

Basic math functions
When dealing with integers + – / and * can be used to directly alter the value before showing them inside the template.
So something like:

var tpl = new Ext.XTemplate(
    '

Birth year: {current_year - age}

',

Is permitted and could be useful for example to show a certain value from 3 different offsets.

Conclusion
Xtemplate is a excellent way to do layout as it makes markup readable using powerful tools to make dynamic markup functional. Also because it’s almost pure code when compiled it delivers high performance also reducing memory when reused on many elements.

And that’s all I have to say about that.

PNGCrush all

Some programs are great to use but are annoying when it comes to bulk operations they are just too cumbersome, PNGCrush is one of them.
Don’t get me wrong, I really like this program (and actually use it quite often), but it needs a bit of spice to be more useful in our busy daily lives. I don’t want to figure out the syntax every usage and windows “scripting” is just to unreliable.

DotNet to the rescue!, if there is one thing this framework is useful for it’s fast and reliable programming, so a simple CLI helper is quickly formed.

  • Can easily be adapted for other programs/use cases
  • Launches one PNCrush instance per core
  • Displays files that will be processed
  • Displays neatly formatted results
  • Finds the best available PNGCrush executable (version and architecture)
  • Works with DotNet 4.5.2 and newer, older versions require some tinkering (although I don’t see valid reasons to remain on any older version)
  • Could be converted to .AsParallel() LinQ, but where is the fun in that?
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;

namespace CrushAll
{
    public class Program
    {
        public static void Main(string[] args)
        {
            _args = args;
            try
            {
                CrushAll();
            }
            catch (Exception exception)
            {
                Console.WriteLine(exception.ToString());
            }

            Console.WriteLine("Done, press any key to exit");
            Console.ReadLine();
        }

        private static string[] _args;
        private static readonly List ActiveTasks = new List();
        private static string _pngCrush = "";
        private static string _currentPath = "";
        private static void CrushAll()
        {
            _currentPath = AppDomain.CurrentDomain.BaseDirectory;
            List files = ReturnFiles(_currentPath, true, new List { ".png" }).ToList();
            files.AddRange(_args.Where(argument => argument.EndsWith(".png", StringComparison.OrdinalIgnoreCase) && File.Exists(argument)));
            IEnumerable executables = ReturnFiles(_currentPath, true, new List { ".exe" });

            // ReSharper disable PossibleMultipleEnumeration
            if (!files.Any())
            {
                Console.WriteLine("No images found!");
                return;
            }
            if (!executables.Any())
            {
                Console.WriteLine("No PNG Crush executable(s) found!");
                return;
            }

            List possibleExecutables = new List();
            foreach (string file in executables.Select(Path.GetFileName).Where(file => file.StartsWith("pngcrush_", StringComparison.OrdinalIgnoreCase)))
            {
                try
                {
                    possibleExecutables.Add(new PossibleExecutable { X64 = file.Contains("_w64"), Version = Version.Parse(file.Substring(file.IndexOf("_", StringComparison.Ordinal) + 1, file.LastIndexOf("_", StringComparison.Ordinal) - (file.IndexOf("_", StringComparison.Ordinal) + 1)).Replace("_", ".")), Executable = file});
                }
                catch (Exception) {}
            }
            // ReSharper restore PossibleMultipleEnumeration

            Version highestX64 = new Version(0, 0);
            Version highestX86 = new Version(0, 0);
            foreach (PossibleExecutable executable in possibleExecutables)
            {
                if (executable.Version > highestX86 && !executable.X64)
                {
                    highestX86 = executable.Version;
                }
                if (executable.Version > highestX64 && executable.X64)
                {
                    highestX64 = executable.Version;
                }
            }
            
            if (highestX86 > highestX64 && Environment.Is64BitOperatingSystem)
            {
                foreach (PossibleExecutable executable in possibleExecutables.Where(executable => executable.Version == highestX86))
                {
                    _pngCrush = executable.Executable;
                    break;
                }
            }
            else if (highestX64.Major != 0 && Environment.Is64BitOperatingSystem)
            {
                foreach (PossibleExecutable executable in possibleExecutables.Where(executable => executable.Version == highestX64 && executable.X64))
                {
                    _pngCrush = executable.Executable;
                    break;
                }
            }
            else if (highestX86.Major != 0)
            {
                foreach (PossibleExecutable executable in possibleExecutables.Where(executable => executable.Version == highestX86 && !executable.X64))
                {
                    _pngCrush = executable.Executable;
                    break;
                }
            }

            if (string.IsNullOrEmpty(_pngCrush))
            {
                Console.WriteLine("No suitable executable found!");
                return;
            }

            Console.WriteLine("Preparing to crush:");
            Console.WriteLine("Thread(s): " + Environment.ProcessorCount.ToString(CultureInfo.InvariantCulture));
            Console.WriteLine("Executable: " + _pngCrush.Replace(_currentPath, ""));

            Queue queue = new Queue();
            foreach (string file in files)
            {
                queue.Enqueue(file);
                Console.WriteLine("File: " + file.Replace(_currentPath, ""));
            }
            
            while (queue.Any())
            {
                Thread.Sleep(500);

                lock (ActiveTasks)
                {
                    while (queue.Any())
                    {
                        if (Environment.ProcessorCount <= ActiveTasks.Count) break;
                        string file = queue.Dequeue();
                        Task task = Task.Factory.StartNew(() => { ProcessFile(file); }, TaskCreationOptions.LongRunning);
                        task.ContinueWith(t => HandleException(t.Exception), TaskContinuationOptions.OnlyOnFaulted);
                        task.ContinueWith(DoneProcessing, TaskContinuationOptions.None);
                        ActiveTasks.Add(task);
                    }
                }
            }

            while (true)
            {
                lock (ActiveTasks)
                {
                    Thread.Sleep(500);
                    if (!ActiveTasks.Any())
                    {
                        break;
                    }
                }
            }
        }
        private static void HandleException(AggregateException exception)
        {
            foreach (Exception ex in exception.Flatten().InnerExceptions)
            {
                Console.WriteLine(ex.ToString());
            }
        }
        private static void DoneProcessing(Task task)
        {
            lock (ActiveTasks)
            {
                ActiveTasks.Remove(task);
            }
        }

        public static void ProcessFile(string file)
        {
            string tempFile = file + ".tmp";
            Int64 orriginalLength, newLength;
            using (FileStream fileInfo = File.Open(file, FileMode.Open, FileAccess.Read, FileShare.Write))
            {
                orriginalLength = fileInfo.Length;
            }
            
            // ReSharper disable once AssignNullToNotNullAttribute
            ProcessStartInfo processStartInfo = new ProcessStartInfo { FileName = _pngCrush, Arguments = "-brute -q -reduce \"" + file + "\" \"" + file + ".tmp\"", WorkingDirectory = Path.GetDirectoryName(_pngCrush), CreateNoWindow = true, UseShellExecute = false };
            Process process = Process.Start(processStartInfo);
            if (process != null)
            {
                process.WaitForExit();
                process.Close();
                process.Dispose();
            }
            else
            {
                Console.WriteLine("Could not start PNGCrush!");
                return;
            }

            if (!File.Exists(tempFile))
            {
                Console.WriteLine("Could not recompress: " + file.Replace(_currentPath, ""));
                return;
            }

            using (FileStream fileInfo = File.Open(tempFile, FileMode.Open, FileAccess.Read, FileShare.Write))
            {
                newLength = fileInfo.Length;
            }
            
            if (newLength > orriginalLength)
            {
                Console.WriteLine(file.Replace(_currentPath, "") + ": resize was bigger, ignoring");
            }
            else if (newLength == orriginalLength)
            {
                Console.WriteLine(file.Replace(_currentPath, "") + ": resize was equal, ignoring");
            }
            else
            {
                Console.WriteLine(file.Replace(_currentPath, "") + ": reduced by " + FormatBytes(orriginalLength - newLength));

                int retries = 0;

                // File operations can be a bit quirky in DotNet, sometimes the file handle isn't released on time so we wait a bit and retry
retry:
                File.Delete(file);
                if (File.Exists(file))
                {
                    if (retries > 3)
                    {
                        Console.WriteLine(file.Replace(_currentPath, "") + ": could not be deleted");
                        return;
                    }
                    Thread.Sleep(250);
                    retries++;
                    goto retry;
                }

                retries = 0;

retry2:
                File.Move(tempFile, file);
                if (!File.Exists(file))
                {
                    if (retries > 3)
                    {
                        Console.WriteLine(file.Replace(_currentPath, "") + ": could not recreated");
                        return;
                    }
                    Thread.Sleep(250);
                    retries++;
                    goto retry2;
                }
            }

            // Don't remove the tempFile if the original no longer exists
            if (File.Exists(tempFile) && File.Exists(file))
            {
                File.Delete(tempFile);
            }
        }
        
        public static IEnumerable ReturnFiles(string localPath, bool recurseDirectories, List includedExtensions = null)
        {
            if (!Directory.Exists(localPath)) return new List();

            try
            {
                List directories = new List();
                if (recurseDirectories)
                {
                    directories.AddRange(RecurseDirectories(localPath).ToArray());
                }
                else
                {
                    directories.Add(localPath);
                }

                List list = new List();
                foreach (string directory in directories)
                {
                    DirectoryInfo directoryInfo = new DirectoryInfo(directory);
                    list.AddRange(from file in directoryInfo.GetFiles() where !(includedExtensions != null && !includedExtensions.Contains(file.Extension, StringComparer.OrdinalIgnoreCase)) select directory + file);
                }
                return list;
            }
            catch (Exception exception)
            {
                Console.WriteLine(exception.ToString());
                return new List();
            }
        }
        public static IEnumerable RecurseDirectories(string localPath)
        {
            List directoriesReturn = new List();
            try
            {
                string[] directories = Directory.GetDirectories(localPath, "*", SearchOption.AllDirectories);
                directoriesReturn.AddRange(directories.Reverse());
                directoriesReturn.Add(localPath);
            }
            catch (Exception exception)
            {
                Console.WriteLine(exception.ToString());
            }

            return directoriesReturn;
        }

        private static readonly string[] Sizes = { "B", "KB", "MB", "GB", "TB", "PB", "EB", "ZB", "YB" };
        public static string FormatBytes(Int64 bytes)
        {
            int order = 0;
            double size = bytes;
            while (size >= 1024 && order + 1 < Sizes.Length)
            {
                order++;
                size = size / 1024;
            }
            return $"{size:0.##}{Sizes[order]}";
        }
    }

    public class PossibleExecutable
    {
        public string Executable;
        public bool X64;
        public Version Version;
    }
}

PNGCrush-All

http/2 with Apache on Debian

One of the nice things to come out this year (at least on paper) is the the http/2 specification.
Most web servers still don’t support it as only the latest Apache (2.4.17) has inbuilt support for it, so only people who compile their own or use experimental distributions are lucky enough to get it.

Below is an easy patch to enable it on a stable Debian configuration, this server has been running part unstable for a long time but it does require some attention to detail.

Prerequisites

  • Up to date stable Debian installation
  • Some nerves / acceptable downtime
  • Configured ssl certificate, there is virtually no support for non https http/2

/etc/apt/sources.list add:

#unstable
deb http://ftp.us.debian.org/debian unstable main contrib non-free

/etc/apt/preferences add:

Package: apache2-bin
Pin: release a=unstable
Pin-Priority: 800

Package: apache2-data
Pin: release a=unstable
Pin-Priority: 800

Package: apache2
Pin: release a=unstable
Pin-Priority: 800

Package: apache2-utils
Pin: release a=unstable
Pin-Priority: 800

Package: *
Pin: release l=Debian-Security
Pin-Priority: 999

Package: *
Pin: release a=stable
Pin-Priority: 700

Package: *
Pin: release a=unstable
Pin-Priority: 1

Run:

sudo apt-get update && apt-get install apache2

/etc/apache2/apache2.conf add:

ProtocolsHonorOrder On
Protocols h2c h2 http/1.1

This method can also be used to install a more up to date version of other packages, but beware that packages in unstable are compiled against unstable libraries so this might not be a great idea to start upgrading everything you see.

Calling Synchronous Methods Asynchronously

Using the BeginInvoke function is way to much fun and something that entry level C# programmers get their hands on fairly quickly. That doesn’t mean it doesn’t have its pitfalls as most don’t bother to read the documentation.

The Microsoft article clearly states:

  • No matter which technique you use, always call EndInvoke to complete your asynchronous call
  • EndInvoke blocks the calling thread until it completes

In situations where a blocking call is not a problem it is a quick and easy fix, but in most situations it just becomes tedious to clean up after yourself.

        public static void AutoEndInvoke(this IAsyncResult result, ISynchronizeInvoke control)
        {
            Task task = Task.Factory.StartNew(() => { AutoEndInvokeTask(result, control); }, TaskCreationOptions.PreferFairness);
            task.ContinueWith(t => HandleException(t.Exception), TaskContinuationOptions.OnlyOnFaulted);
        }
        private static void AutoEndInvokeTask(IAsyncResult result, ISynchronizeInvoke control)
        {
            control.EndInvoke(result);
        }

Using the code is easy to:

            _window.BeginInvoke(new Action(OpenFileWindow)).AutoEndInvoke(_window);

It isn’t the cleanest of solutions, it spoils a whole thread so it might not be the best solution for very heavy situations (bulk loading invokes works way better in those cases). But it does alleviate most of the occasional BeginInvoke calls.

Android fragmentation, security and real world expectations

In the recent time some security ‘concerns’ within Android have caused widespread concerns about the OS.

What really grinds my gears about this is that everybody seems to expect the highest marks on all fronts because they get shown all kinds of marketing images with great expectations (even the ones made by other brands, because hey, they can do it, so should the brand you own…).

As an avid programmer with a long running interest in security this is something that I still cannot get used to. We live in a world where it’s easier to just throw away stuff we are getting bored with, we consider to old or just didn’t pay any maintenance to. Not only is this incredibly wasteful and degenerative to the skill we should be acquiring it also prompts the development of software (and also cars, appliances etc.) to be geared to this default.

When Google launched android it was the great success that many of us had been waiting for an open source system that runs on a phone, something most people believed impossible because of the closed system that was created in the years before. In the following years the ecosystem grew giving us enormous diversity and possibilities.

  • There are thousands if not tens of thousands of developers making code submissions, apps, patches, hacks etc to the OS itself
  • As of writing there are 1,600,000 “different” apps in the official Play store, even more on the internet
  • There are an innumerable amount of different devices (from the extreme high end to nearly feature phone capabilities)
  • Everybody wants everything to work with everything
    • They also expect it to be cheap
    • It must be fast, no matter how cheap the device
    • Every app should is expected to run on every device

While it is a great thing that we have a global network that enables us to get the latest updates almost real time for very low prices we should expect our security to be treated the same way!

On the other hand I do think that Google (and “re-sellers”) could do a lot more on updating old devices and keeping the cluster down.
In reality the bigger profit margin always wins, never security, reliability or service.

ExtJs 3.4 – Tips and tricks

Introduction

This post is mostly a whole bunch of information I have gathered to using ExtJs 3.4 grouped by different subjects.

I hope any one stuck with Extjs 3.4 to have use for it.

Errors and possible solutions

Writing code and debugging ExtJs can sometimes be a pain because errors trown by browsers are not always clear. Like with most software, not all errors shown point directly to the actual problem. Unforntunately because javascript is very flexible, it can go wrong on many levels.

The following list gives you a guide in which errors indicate to which problems.

this.addEvents is not a function:’statesave’
Check if you use new for all of your created Ext components.

‘events’ is null or not an object
Check comma’s in items arrays

‘minWidth’ is null or not an object
Check comma’s in buttons arrays.

Expected identifier, string or number
Check comma’s inside Ext element config objects or/and arrays.

Comp is undefined
Check for non existing or empty references in an items list.

‘id’ is null or not an object
Check comma’s in ColumnModel arrays.

Unterminated string constant
If it occurs in Internet Explorer it is likely caused by disabling a form prior uploading a file. This somehow causes internet explorer to not send any form information when it is submitted.

TypeError: this.ds is undefined
Stores is not defined for a grid(panel)

Unable to get value of the property ‘0’: object is null or undefined
Check comma’s in field array of stores.

TypeError: this.config[col] is undefinedvar width = this.config[col].width;
Column model with autoexpand not pointing to a valid column. Must point to an id that exists within the column model.

TypeError: c is undefined
Calling add() on a panel/component with an empty or otherwhise faulty reference

Debugging events

Blog about logging all events. https://coderwall.com/p/jnqupq

Ext.util.Observable.capture(myObj, function(evname) {console.log(evname, arguments);})

Store query on exact value

   
var selectedOptions = this.optionStore.query('id', new RegExp('^' + Ext.escapeRe(String(selRecord.get("answer"))) + '$'));
 
   //Returns: MixedCollection\\
   //Returns an Ext.util.MixedCollection of the matched records

Store ‘fix’ modifiedRecords()

ExtJS store by default does NOT remove records from modified records on remove or load.
To make this happen use pruneModifiedRecords: true to do this

    this.data.productsComboStore=new Ext.data.SimpleStore({
        fields:["id","name"],
        pruneModifiedRecords: true
    });

Create new record for store

   var data = { id: 4, name: 'something' }; //initial data
   var recCreate = myStore.recordType;      //cosntructor for a new record (can allso be called directly)
   var rec = new recCreate(data);           //create record
   rec.set("id", 0);                        //alter after creation
   myStore.add(rec);                        //add to store

Find row index from record

   var recIndex = myStore.indexOf(rec);
   myGrid.getView().focusRow(recIndex);

Find data index from columnIndex and record from rowIndex

var dataIndex = fGrid.getColumnModel().getColumnAt(fColumnIndex).dataIndex;
var record = fGrid.getStore().getAt(fRowIndex); 
var recValue = record .get(dataIndex);

Using filter with combobox

Apply following config options on combo to make it work

clearFilterOnReset: false, //to make filter on store work
lastQuery: '', //another filter fix

Grid rendereres

percentageRenderer:function(fValue, fMeta, fRecord, fRowIndex, fColumnIndex, fStore) {
        fMeta.css += "cssClass";
        return fValue + "%";
},
 
checkboxRenderer:function(fValue, fMeta, fRecord, fRowIndex, fColumnIndex, fStore){
    return '
'; }

Set scope of renderer to current object

renderer: {
    fn: this.someUsefulRenderer,
    scope: this
}

Grid cellclick with image or other elements in renderer

When rendering images or other deep elements within a cell the cellclick events do not longer work correctly. To fix this increase the GridViews depth search paramters. This works on any type of grid view.

view: new Ext.grid.GridView({
   cellSelectorDepth: 4, //increase to find deeper elements
   rowSelectorDepth: 10 //increase to find deeper elements
})

Grid using drag an drop in grids

define following grid config options

enableDragDrop: true, 
ddGroup: 'mygrid-dd',  
ddText: 'Place this row.'

Create drop target class after render

this.data.grid.period.on("afterrender", function(){
   var store = this.stores.periodEdit; //change to actual store
   var grid = this.periodGrid;  //change to actual grid
 
var ddrow = new Ext.dd.DropTarget(grid.getEl(), {  
     ddGroup: 'mygrid-dd',  
     copy: false,
     scope: this
   })
}, this);

Override notifyOver on this dropTarget instance to see if may be dropped Notice: using ‘dd.getDragData(e)’ causes the selections in the selectionModel to be changed

notifyOver : function(dd, e, data){
  var sourceIndex = data.rowIndex; //get sourceIndex
  var targetIndex = dd.getDragData(e).rowIndex; //get targetIndex
}

Override notifyDrop on this dropTarget instance to do an action when dropped

notifyDrop : function(dd, e, data){
    var sourceIndex = data.rowIndex; //get sourceIndex
    var targetIndex = dd.getDragData(e).rowIndex; //get targetIndex
}

Prompt for question

When you want input from the user on a question. Questions like: “sure you want to delete this?”, “Sure you want to go on and lose your unsaved data” etc.
Use the here under described function
Note: Although the buttons can be localized the answer inside the function doesn’t change. Look up the function to see more button configurations if needed.

Ext.Msg.show({
	title: "Opslaan",
	msg: "Would you like to delete this item?", //use translate to localize the message
	width: 400,
	buttons: Ext.Msg.YESNO,
//      buttons : { ok: 'Actie uitvoeren', cancel: 'Terug' },
	closable: false,
	hideBorders: true,
	style: "border: 0;",
	fn: function(answer, text){
		if (answer == "yes"){
			this.deleteItem();
		}
		else {
			//do nothing
		}
	},
	icon: Ext.MessageBox.QUESTION,
	scope: this
});

Checkbox column in grid

Toggle selection

    this.grid.on("cellclick", function(grid, rowIndex, columnIndex) {
        //get record
        var rec = grid.store.getAt(rowIndex);
 
        //get data index
        var dataIndex= grid.getColumnModel().getDataIndex(columnIndex);
 
        //toggle value false/true
        rec.set(dataIndex, !rec.get(dataIndex));
 
    }, this);

Renderer

	function(fValue, fMeta, fRec, fRow, fCol, fStore){
             fMeta.css += " x-grid-col-selected";
 
             return '
'; }

Grouping grid The column you want to group with must be included within the columnModel. Even if it’s hidden, it MUST be included.

Use CSS background class to an image

'';

Replacing or reseting upload field

Because of security reasons an upload field cannot be set or reset.
The only way to do so, is to replace the whole field.

See the example below:

//replace upload field
var config = uploadField.initialConfig;
 
uploadField.destroy();
 
uploadField = new Ext.form.TextField(config);
 
//re-add to the fomd the upload field contained too
//this can also be a grouping label etc
form.add(FF.paragraphImageUploadField);
form.doLayout();

Show / hide loadmask

When you are loading or saving something inside your interface, you don’t want the user to change things that might get updated the next second or will not be saved because the actual data is already send to the server. Additionally you would like show the user a vissual indication something is going on.

The following functions add a loadmask to a component to achieve this. The inner workings have been proven to fix problems that occur when this function is called before the actual component is rendered. And even shows the loadMask in the event that rendering completes before loading does.

    //show load mask
    //shows it on this gui, waits for gui to render if not already done 
    //and if hideMasks is called before showLoadMask. The loadMask will not be shown.
    showLoadMask:function(){
        //see if main screen is already rendered
        if(this.rendered){
 
            //if no loadmask created
            if(!this.loadMask){
                //create loadmask
                this.loadMask = new Ext.LoadMask(this.getEl(), {
                    msg: app.instance.translate("loading data") + "..."
                });
            }
 
            //if supress load mask flag is set
            if(this.surpressLoadMask){
                //do now show mask
                delete this.surpressLoadMask;
            }else{
 
                //if everything ok, show load mask
                this.loadMask.show();
            }
        }else{
            //if main screen not rendered, rerun when rendered with small delay
            this.on('render', this.showLoadMask, this, {single: true, delay: 100});
        }
    },
    //hide the load mask (and additional masks if added)
    hideMasks:function(){
        //if loadmask is created
        if(this.loadMask){
            //hide loadmask
            this.loadMask.hide();
        }else{
            //if loadmask is not created, but this function is called. 
            //set supressloadmask flag to prevent load mask from being shown here after
            this.surpressLoadMask = true;
        }
    },

Managing buttons within a control interface

It sounds trivial, but have you ever found yourself clicking on a button at the bottom of an administrative panel to delete an item while nothing was selected inside a grid or list, presenting you with a ‘nice’ exception.

Why does this happen? The answer is probably: that the most forward way to make button states work, is to manually disable buttons for different actions.

Note: All code are orginall written in Javascript for ExtJs 3.4, but if you can read it are easily transferable to other programming languages.

DeleteItem:function(){
   var selectedRec = this.grid.getSelectionModel().getSelected();
   this.stores.items.remove(selectedRec);
   this.deleteButton.disable();
   this.editbutton.disabled();
}

Consider the following case.

  • You have a grid with items that can be deleted and edited.
  • You can always add something.
  • When you delete something, nothing is selected afterward. So edit and delete should be disabled.

Now there are multiple cases this will break when you manage button states with every action.

  • You add another button, move for example.
    You have to add the disable to the end of edit and delete function.
  • Items get states where they can’t be either deleted or edited.
    The logic of this will be scattered.
  • An item can be deselected by a refresh called from numerous functions.
    Again scattering logic and leaving room for errors.

You get the idea.

Interfaces like this have lot’s of states ending in an even larger list of actions that a possible. So what IS a good way to do this? In my personal opinion it’s best to fit all state information into ONE function.

Why?

  • Because you want the logic to be in one place.
  • You can call this function as often you want, so if you are unsure about states. Call it.
  • When it is done, it is guaranteed to be valid because it doesn’t care which function just got executed.
  • When you add a new state or button you only have to add a little logic to this function and don’t have to bother to check all the other places the state could change in a way unintended.
DeleteItem:function(){
   var selectedRec = this.grid.getSelectionModel().getSelected();
   this.stores.items.remove(selectedRec);
   this.ManageButtons();
},
ManageButtons:function(){
   var hasSelection = this.grid.getSelectionModel().hasSelection();
   if(hasSelection){
      this.deleteButton.disable();
      this.editbutton.disabled();
   }else{
      this.deleteButton.enabled();
      this.editbutton.enabled();
   }
}

Last consideration

Yes, it creates some overhead. It will run checks that ‘could’ be unnecessary because part of the buttons only change ‘sometimes’.

That are a lot of ifs. Furthermore checking for states is not that expensive. That is unless you need to loop a whole lot of items to find out if something is true. Which would be a good thing to cache or split off so you only check it when necessary.

You could consider making logical groups that you pass as parameters for things to check during the manageButtons call. But I have not experimented with that yet.

Feel free to leave comments about your own findings on the subject.

Old school crypto

Recently I have begun coding a simple library that can encrypt/decrypt files based on the old enigma machines (and type-x etc).

But what fun is it to just digitize a known breakable piece of hardware?Technology has come far enough for us to hold way more computing power in the palm of our hands than a soldier was able to carry around on his back a few decades ago.

The first big improvement step is to switch the alphabet for bytes, which gives us a few distinct advantages:

  • Ability to process any file we want to
  • Still easily represented in a human readable form [0-255]
  • Bigger “rotors”, which means more possibilities
  • Easier comparisons programmatically

Also the following steps have been implemented to improve the strength based on the type-x and other ideas:

  • A byte can become itself!
  • A second switching board after the rotors
  • Configurable rotors (including stronger random generator)
  • Configurable number of rotors
  • Filler bytes which can only be removed when successfully decrypted
  • Random filler data before and after payload
  • Configurable hashing algorithm combined with length indicator
  • Ability to rotate more than one rotor after each character

As well as a few basic functions:

  • Import and export keys (XML and binary)
  • Proper file handling
  • Basic DLL calls

This should be more than enough to stop the attacks on the old enigma and should prevent most modern day crypt analysis.

The implementation is written in C# but should be easy to convert to other languages as well, keep in mind that given the large number of bytes a simple document has become and the amount of array operations required this will not be a great solution for large files (AMD X4 965 scores about 5MB/min). Which will obviously decrease as more steps are implemented, though I think there still are some optimizations that be done to simplify some operations.

The following points are on the bucket list:

  • Plugboards
  • Fully functional UI
  • Implement a configurable stepping maze (hard work, but should increase the entropy big time)
  • Better file deletion (first overwrite with random data, then delete the inode)
  • Release the source if there is some interest
  • Ability to encrypt/decrypt a continues stream