Explorations of using node-webkit + ExtJS4 to build a desktop application

Since the demise of Sencha Desktop Packager and the non-arrival of any examples or clues about how TideKit might actually work I decided to have a look at node-webkit and see whether or not it would work as a desktop packager for ExtJS4. What I say below might work with ExtJS5 but I havent upgraded yet since it is still quite new.

Node-webkit is an executable (one each for Win, OSX, Linux). It is a chromium webkit browser wrapped by a “shell” that adds JavaScript libraries so that you can access the local file system, memory, native windows and menus, system tray, etc etc of the computer it is running on. Hence, it creates the opportunity to turn HTML5/JS/CSS into a desktop application. The extra JavaScript is provided by NodeJS (well the V8 JS engine actually, but via NodeJS libraries). Hence the name “node-webkit”.

The first observation is that there was a lack of any “Using node-webkit with ExtJS4″ information. Lots of little bits and clues but no overall approach. So, I thought I would share my exploration to make the trail easier for the next person.

The second observation is that you can make a desktop app with just node-webkit. However, unless you want to re-invent the wheel in terms of making Http requests or direct remoting (for example) you will also need to install NodeJS separately so you can use the NPM packager to easily download the various NodeJS libraries that you might want to use. There are nearly 90,000 of them!

And, of course, you will need to be familiar with ExtJS4 and Sencha Cmd. I wont be explaining any of that.

Useful resources

These are the things that helped me get my head around the concept:

https://www.youtube.com/watch?v=lNpjx4BJlH4 – A series of 6 videos for beginners. Very helpful.

https://www.youtube.com/watch?v=XmHh4RrlpIk – An introduction by Roger Wang, the guy that made node-webkit.

http://code.tutsplus.com/tutorials/introduction-to-html5-desktop-apps-with-node-webkit–net-36296

http://www.amazon.com.au/Windows-Desktop-App-Creation-node-webkit-ebook/dp/B00EEYFFVC/ – a short, inexpensive eBook that covers the main aspects clearly. Great for beginners. Even though the book is for Windows users, OSX and Linux users will also find the info useful.

(I will add more resources as I find them).

Installation

Installing node-webkit went without a hitch. Just download the installer for your OS from the GitHub page and follow the dots.

First tests

I then used the above mentioned resources to make my first desktop app. I followed the tuts introductory tutorial. That all worked without a hitch. Very excited by now.

With ExtJS4:
To test the ExtJS compatability I created a new ExtJS app using Sencha Cmd generate, built the default production app, then ran it in node-webkit and ….. it worked! More excitement.

Some learnings here:

1. To test your app you basically pass the folder containing your app (ie the folder with the main html file in it) to nw.exe. You *can* drag and drop it but I found the fasted way was to create a batch file (I am using Win7) in the same folder as the app and then run that. The batch file contents (for my machine) looks like:
..\..\node-webkit-v0.10.2-win-ia32\nw ./
which basically says (go back up to the folder containing the nw.exe and run it with the current folder as the parameter. You could also add the node-webkit folder to your PATH (on windows) to avoid needing the path in the batch file.
Edit: And/or of course maybe rename the folder to (say) NW so the folder or path doesnt need updating when you update your version of node-webkt!

Executing nw opens the window and displays your app (as you would have seen in the video series above.

2. Note that my initial testing built the ExtJS app first then passed that to NW. Also at this stage there is no NodeJS library being used, It is just my ExtJS app. It gets a bit more complicated when you want to pass the unbuilt version (so you can debug your app via the NW chrome debugger). More on that below – I am still exploring all that.

NodeJS

Now, installing NodeJS so I can require the appropriate extra libraries. This wasn’t as simple initially. The default installation folder is C:\Program files\nodejs. That seems fair enough. However, even though I am logged in as Adminstrator on my computer file permission problems meant that I couldn’t run npm (the package installer). See this post for details of errors. My solution was to uninstall NodeJS and reinstall in C:\nodejs. That worked perfectly and I could run npm without errors.

Using NodeJS packages (modules)

To use the downloaded NodeJS packages you need to install them in the node_modules folder at the root of your app. It must be called node_modules. So, one way to install a module is to run npm install {package name} from a command line in the root of your app’s folder. The node_modules folder will be created if necessary and the module will be saved in that folder. For me I just ran  C:\nodejs\npm install httpreq from a terminal / command line (to load the httpreq module, for example).

More tests: Adding Node to ExtJS4

This is preliminary. Starting with the default ExtJS app generated by Sencha Cmd I added the following:
1. The require() statements which I placed above Ext.define(‘App.view.Main’, {:

var gui = require('nw.gui');
var httpreq = require('httpreq');

2. a toolbar to the centre Tab panel with some test buttons

{
        region: 'center',
        xtype: 'tabpanel',
        dockedItems: [{
            xtype: 'toolbar',
            dock: 'top',
            items: [{
                xtype: 'button',
                text: 'Open file',
                handler: function(btn, e) {
                    // Test opening a Word Doc
                    console.log('Pressed open file');
                    gui.Shell.openItem('Test1.doc');
                }
            }, {
                xtype: 'button',
                text: 'Http request',
                handler: function(btn, e) {
                    // Test making a http request
                    // Using https://www.npmjs.org/package/httpreq
                    var url = "http://www.google.com";
                    console.log(url);
                    httpreq.get(url, function(err, res) {
                        if (err) return console.log(err);
                        console.log(res);
                    });
                }
            }]
        }],
        items: [

            {
                title: 'Center Tab 1',
                html: 'Hello first app'
            }
        ]
    }

 

I then built the production app and loaded it into NW as described above and yes! it works!

Next steps

My next task is to work out the best way to integrate ExtJS4 and node-webkit so that it is possible to run the uncompressed version of my app in NW so I can debug it using the chrome developer tools in NW. I will report back when I have done that!

CFPOP – deleting an email when there is a comma in the UID

It seems that a problem has existed with the CFPOP delete action for a number of versions and it has not been fixed. The problem occurs when trying to delete a single email (or a list of emails) from the mail server where the mail server has included a comma in the UID. eg “1382396111.12731.mydomain.net,S=965″

The CF docs for the CFPOP Delete action says: “UID or a comma-separated list of UIDs to get or delete. Invalid UIDs are ignored.”

So, the abovementioned UID gets split into 2 uids (notice that it has a comma in it) and of course the email is not located so cant be deleted. CFPOP does not include a DELIMITERS parameter to use with the UID paramater which would solve the problem, I think. eg

 
<cfset myUIDlist = "1382051456.15221.mydomain.net,S=965|1382051456.18000.mydomain.net,S=966" />  
<cfpop server = "********" username = "********" password = "******** 
	action = "Delete" uid="#myUIDlist#" delimiter="|" >

Fortunately, there is a solution – use POP CFC instead of CFPOP! Thanks to Paul Vernon.

So, here is a sample page to demonstrate a way to use POP CFC.

<cfscript>
/**
 * Example of reading, processing then deleting individual emails from the pop mail server
 * using the POP CFC custom component.
 * http://popcfc.riaforge.org/
 */

	// To make it easier to rescope this example (local, variables ... whatever)
variables.s = {};

			// Initialise the custom POP CFC component. Used instead of CFPOP
			// Set your values here
s.popAccount = createObject("component", "pop").init(myPopServerHostname, myUsername, myPassword)

			// Specify a non-comma separator for the UID lists. 
			// You must do this in order for the list functionality
			// of POP CFC to work (including deletions)
s.mySeparator = "|";
s.popAccount.setProperty("separator",s.mySeparator);

			// Get an array of the UIDs of the messages in the mail account.
			// ie retrieve them from the mail server
			// This is a necessary step to solve the comma-in-uid problem
s.UIDArray = s.popAccount.getUIDList();

if (arrayLen(s.UIDArray)) {
			// Convert the array to a list
			// Keep the list to use for deletions
	s.UIDList = ArrayToList(s.UIDArray, s.mySeparator);

			// Get an array of the raw messages - one entry per UID supplied
			// This gets the raw email data from the pop server for whichever
			// emails are in the UIDList
	s.msgSrcArray = s.popAccount.GetRawMessageByUID(s.UIDList);

			// Turn the array into a query of email structures
	s.messagesQry = s.popAccount.parseRawMessage(s.msgSrcArray);

			// Loop over the array of email messages
	for( s.i=1; s.i <= s.messagesQry.recordcount; s.i=s.i+1) {

			// Process the message as you wish
			// ....
		
		writeOutput("<br/>" & s.messagesQry.subject[s.i]);


			// Now, delete this email from the server 
			// Note: you can also delete all the emails in your query 
			// in one go after the loop. See below.

			// The UID is NOT present in the messagesQry. Therefore,
			// you need to look up the UID by list position.
			// Obviously, you can also selectively delete single messages 
			// based on your criteria.

		s.uid = listGetAt(s.UIDList, s.i, s.mySeparator);
		s.popAccount.deleteMessagesByUID(s.uid);

	}

			// Uncomment to delete all messages in the list in one go, 
			// instead of one by one as above
	//s.popAccount.deleteMessagesByUID(s.UIDList);
}

</cfscript>

POP CFC has lots of other useful functions too.

Cheers,
Murray

Sublime Text – exclude / include search folders using regex

I recently switched from Eclipse to Sublime Text 3 and am very happy I did. It is fast to load, lots of extensions, active community.

One thing that I couldnt figure out was how to exclude folders from the search within files (project). I mostly code in JS (Sencha Ext/Touch) and ColdFusion and keep my JSDuck API Docs etc in the same project folder as my source files. That means that when I search within files in my project I end up with matches from the docs folder, which is not what I want. Also, and probably more importantly, when using Sencha Cmd to build production apps there is a /build folder which I do not want to search in since that is the “compiled” output.

There is a forum post about using -/my/path/to/folderToExclude (ie prefix the path with a – ). http://sublimetext.userecho.com/topic/97052-find-in-files-exclude-directories/

For Windows (which I use) you need backslashes instead of forward slashes and the syntax becomes odd (IMJ). At the end of that post was an example of using regex in the Where input box. This was a revelation.

So, to exclude the various folders within my project that I never want to search in, my where box looks like:

-*/docs/*,-*/build/*,-*/ext/*,-*/sass/*

which means search in all folders and subfolders in the project except these ones. Brilliant!

By the same method you can be specific about which folder to include. eg:

*/app/* will find a match in all “app” folders (and sub folders of course) eg myappname/app and myappname/build/app. However I want the first one but not the second one (build). So:

*/myappname/app/*

does the trick, only searching in folder (and sub folders of) myappname/app.

And, of course you can combine exclude and include:

*/myappname/app/*,-*/controller/*

ie only search in myappname/app/ but NOT in myappname/app/controller (or any sub folder with ‘controller’ in the path)

Finally, dont forget that the Where box is cached and previous contents are available by clicking the down arrow at the end of the input box. So, you can easily switch between saved search strings.

All very nifty!

ColdDuck – beautiful documentation for ColdFusion CFCs

Background

I have been a consumer of the Sencha ExtJS documentation for a while now and wanted to be able to use JSDuck for my ColdFusion CFCs. But how? While I am a JSDuck novice I figured that trying to make JSDuck produce documentation directly from ColdFusion CFCs was likely to result in tears (mine!). So, after some thought, I came up with another strategy that users of other programming languages might want to consider.

My CF to JSDuck strategy

Mark Mandel’s ColdDoc can be extended to produce different kinds of output by utilising a “strategy” cfc. It comes with one that produces the JavaDoc style HTML format. Strategies utilise the CF ComponentMetaData. So, I made my own strategy that takes ColdFusion CFCs and makes a pseudo-app in JavaScript code that is annotated using JSDuck formatting. Of course it auto-documents functions etc and picks up the ‘hint’ attributes where it finds them and uses all that to produce the raw material for rich documentation. It also works with CF ORM CFCs (although this part could be made even richer than it is at present).

Video overview

Here is a really quick video to give an overview of what ColdDuck does: http://www.screencast.com/t/5p4JqbvNR

Documentation

The ColdDuck package includes the documentation. You can also view it here http://murrah.com.au/coldduck/docs

Sample output

Here is the sample SuperBlog app documented with ColdDoc in JavaDoc format

Here is the sample SuperBlog app documented with ColdDuck in JSDuck format

A full implementation of JSDuck style documentation is here http://docs.sencha.com/extjs/4.1.3/

Almost all of that JSDuck functionality is available for you to use for your ColdFusion projects. I say “almost” because there are a few JSDuck features that are JavaScript specific (eg view JS class source).

Installation

Get it at GitHub https://github.com/murrah/ColdDuck

I hope you find this useful and fun. Please leave your comments below.

Thanks,
Murray

Solved: The CFML compiler encountered an unexpected java.lang.StringIndexOutOfBoundsException exception.

Just a quick one. I received the following error while working a a Coldfusion entity cfc.

The CFML compiler encountered an unexpected java.lang.StringIndexOutOfBoundsException exception.

The line it pointed to as the error condition had no errors in it.

It turned out the the problem was that just before the error line I had an empty comment (an artifact of testing) like /**/ ie no space between the comments “braces”. After changing it to /* */ the error is not thrown. Just in case someone else encounters this message.

Outlook 2007 – take care when switching from Exchange Server!

Our company recently switched it’s email server from Exchange Server. Not thinking, I deleted the Exchange item: Tools / Account Settings / Email / Remove. Not a good move!

Normal Outlook data files are PST files (e.g. outlook.pst). Exchange Server files are .OST files. Microsoft intentionally do not provide a way to convert an OST file to a PST file! Oh shit! There are commercial solutions and other solutions that may or may not work to convert the file.

After the panic subsided, I realised that I still had the company’s Exchange Server setup on my old laptop’s Outlook. So, I copied the OST file across to that laptop (so I had the emails that were present at the time I stopped using Exchange), fired up Outlook which told me the server was AWOL (which didnt matter), all my email and folders were there! Phew.

I then Archived ALL the folders (File / Archive, etc which copies the data to a PST file – e.g. archive.pst). I then copied the archive.pst file back to my new laptop, started Outlook and voila, all the old email was available.

So, the moral is, if you are switching from Exchange and not migrating your old email to a new mail system, ARCHIVE all your old email BEFORE you disconnect the Exchange data file from Outlook!

 

Solved: Outlook 2007 – email stuck in Outbox after switching from Exchange Server to Gmail IMAP – error 0x80040201

This took a long time to work out. As usual, someone had walked the path before me but it took a while to find that solution amongst all the false leads (in my case).

Our company had recently switched it’s email from Exchange Server to Gmail. (Yes, they are aware of the security issues. Anyway …). Not liking the GMail interface etc I wanted to continue using Outlook for my mail client and using GMail’s IMAP to do that. After setting that up (lots of posts on the net on how to do that), I noticed the following problem.

Important note: See this post BEFORE you delete your old Outlook Exchange file. If you do it the wrong way you will lose all your email!

The problem: When I created a new email to some of my contacts, or replied to an email from one of those same contacts, the email stayed in the Outbox of my default PST file. Sometimes it threw the error 0x80040201. Nothing I did would cause Outlook to send the email. Other email addresses worked fine! Very weird. Eventually I discovered the post below that explained that the problem was due to the Outlook.nk2 file that contains the data for the auto-complete functionality of Outlook. That file remembers whether the address is an Exchange Server address or an SMTP address. And guess what? All the addresses I had problems with had Exchange settings.

So, see the LAST item on this post: http://www.pcreview.co.uk/forums/getting-error-0x80040201-t1872774.html which explains a couple of fixes.

Alternatively, download this: http://www.nirsoft.net/utils/outlook_nk2_edit.html and delete all the email items with an account type of EX (as opposed to SMTP) and follow the instructions. You will then need to type the full email address the next time you send to that person and it will then remember the correct settings. Some addresses had both EX and SMTP entries so deleting the EX entries allowed the SMTP entries to correctly auto-correct.

I hope this saves someone the hours it took for me to find the solution.

NB: there is still a problem with Outlook that appears to be a bug. To get the email to actually send, you must click Send/Receive / Send ALL. I haven’t found a way for it to send automatically but at least I can send email with a couple of extra button clicks!

Now, I wonder how well Thunderbird’s IMAP works?

Cheers,

Murray