Category Archives: mobile

Custom Message Boxes in Sencha Touch 1.1

08 Mar 2012

Sencha Touch comes with 3 modal message boxes: Alert, Confirm, and Prompt. In all cases the buttons are pretty hard-coded into them. There are many instances where specific button combination or wording is desired yet the defaults for the three canned Message Boxes fall short. I have seen various attempts at getting custom buttons and quite honestly they all seem convoluted to me. All I want is a straight-forward way of creating custom buttons within my Sencha Message Boxes.

IMO the easiest approach is to break away from Alert/Confirm/Prompt and create your own MessageBox via the Ext.MessageBox class.

First, lets declare a new Ext.MessageBox instance like so:

...
var msg = new Ext.MessageBox();
...

I’ve create a variable and assigned an empty Ext.MessageBox to it. What we need to do is to configure it and then show it, both of which can be accomplished with the Ext.MessageBox show() method which itself takes a configuration object which will populate our Message Box with everything that we need before it renders it to the screen. See this next bit of code for an example, which we’ll disect in a moment:

...
msg.show({
    title: 'Hello World',
    msg: 'Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt',
    buttons: [{text:'Sure',itemId:'sure'},{text:'No Way',itemId:'noway'}]
});
...

The above will look like this:

Its easy enough, right? Note the “buttons” config option, this takes an array of configuration objects. Each object has “text” and “itemId” attributes. You can specify whatever you like as the values for these. As well, you can specify just one config object or more if you like. Please note that while there is a “width” config option for Ext.MessageBox setting it has no effect. As a result, the practical limit for custom buttons is 2. If you’re familiar with CSS, you could override the Sencha Touch styles being used on the buttons and squeeze in a third, space permitting.

The next step is to setup a callback function to handle user input. To do so simply assign a function to the fn: config option or do as I did and assign an anonymous function that is setup to receive the “response” from the user. The “response” is the “itemId” that you specified for the button.

...
function custombox(){
    var msg = new Ext.MessageBox();
        msg.show({
        title: 'Hello World',
        msg: 'Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt',
        buttons: [{text:'Sure',itemId:'sure'},{text:'No Way',itemId:'noway'}],
        fn:function(response){
            console.log(response)
        }
    });
}
...

If the above is run and you tap on the “Sure” button you will see the string “sure” print to the console. Same thing for the “No Way” button – its itemId “noway” will also print to the console when its button is tapped. All you need to do is to insert some logic to handle either of the two responses.

Finally, to ensure that your MessageBox conforms to your text always execute a doComponentLayout() on your message boxes after showing them (see line 35 below).

A complete Sencha Touch Custom Message Box example:

...
Ext.setup({
    onReady: function(){
	
        var rootPanel = new Ext.form.FormPanel({
	        fullscreen: true,
	        items: [
		    {
		        xtype:'button',
		        text:'Show Custom Message Box',
		        scope:this,
		        handler: custombox
		    }
	        ],
	        dockedItems:[
		    {
		        xtype:'toolbar',
		        dock:'top',
		        title:'Message Box Example'
		    }          
	        ]
	    }
        );
	
	function custombox(){
	    var msg = new Ext.MessageBox();
	    msg.show({
		title: 'Hello World',
		msg: 'Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt',
		buttons: [{text:'Sure',itemId:'sure'},{text:'No Way',itemId:'noway'}],
		fn:function(response){
		    console.log(response)
		}
	    });
	    msg.doComponentLayout();
	}	
    }
});
...

Eclipse Tips for New Users

28 Feb 2012

I don’t know if this is true, but I imagine that the Eclipse user-base is exploding due to the advent of PhoneGap and Mobile Application frameworks like Sencha Touch and JQuery. I’ll go a step further and assume that a significant portion of HTML 5 Mobile App Developers are coming over from the front-end web development world since these new technologies have dropped the entry curve considerably to mobile app development.

So, a lot of new Eclipse users in a new IDE means… (drumroll)… a lot of questions. So in my short time in using Eclipse I’ve come across a handlful of things that I find myself using/doing all of the time that saves time. I thought I’d share these “tips” as you might find them useful as well.

TODO

This is a very handy feature. I find myself starting Sencha Touch projects by first building out the “skeleton” – all the panels, nested panels (the parents of which I personally call “card decks”, as most child panels have the “card” layout), setting up listeners, creating empty functions knowing that I will need to flesh them out at a later date, etc. And so while doing this I need a handy way of indicating that there is something to do in that particular location in my code. Eclipse has a nice visual que for this called “TODO’s” that when used appear in a thin vertical strip next to the vertical scrollbar. This strip is called the “Overview Ruler”. To add a TODO to your project simply create a comment and put the “TODO” text after it (i.e., “/* TODO */” and Eclipse will display a blue marker in the Overview Ruler. Feel free to expound on what needs to be done within your comment as well.

Eclipse also does something that I think is annoying and that interferes with the “TODO” feature – it displays a yellow marker in the same vertical area as it does the blue “TODO” markers for things like variables that it thinks arent used or for lines that might be missing a semi-colon (which often are not). All this clutter will hide your “TODO” markers. To turn off the yellow markers do the following:

Right click the Overview Ruler and choose “Preferences”:

Next click “Annotations”, then scroll down to the “Warnings” Annotation Type. Click “Warnings” and then deselect “Overview ruler”. Click Apply/Ok and your done.

Wildcard Searches with CTRL+F

Find/Replace is not so much of a tip as we’re all familiar with it. But, if you are like me and have a long history using Dreamweaver you may have learned how to take advantage of regular expressions in your search/replace activities. No worries, this little tip is simple – you can do wild card searches in your projects by using an asterisk (*) – as long as you check the “Regular Expressions” check box. This is especially useful if you employ naming conventions for variable and function names.

For example, if you know that you are looking for an ID but don’t recall the entire string, but know that due to your naming conventions that it starts with “txn” and its a “sheet” (a Sencha Touch-specific feature) you would search for all occurances of it by entering “txn*sheet” and then hit the Find button until you find what you’re looking for.

Jump to Last Edit with CTRL+Q

I use this more than anything else – simply jump back to your last edit point from anywhere in your code by pressing CTRL+Q.

Go to line using CTRL+L

Not much to say here – when I debug using Chrome with the developer tools turned on I can see where errors and my console.log statements appear within my code. Just look at Chrome’s console, note the line number, then zip straight to the line in Eclipse.

Filter LogCat

LogCat is where all your console.log statements appear within Eclipse – as well as a million other things happening on your phone or tablet. So much stuff shows up that the one thing that you’re interested in often just scrolls out of view. You can filter the LogCat window by typing in an expression where Eclipse indicates as much:

The easiest thing to do is to simply follow Eclipse’s direction and type the Prefix of what you are looking for and enough characters to get what you want. In our case, what we want is the Web Console. But thats two words with a space in between which won’t work (as you will discover). We can do something as simple as just “tag:web” which narrows down the list greatly:

Thats better – but not perfect. We see everything with the word “web” in its Tag, but all we want is the “Web Console”. To get there we need to write a Java regular expression – the entire string would be: “tag:^web\sconsole$”, as shown below:

And, if you are lazy, you can save your regular expression for later use by toggeling the Saved Filters View button illustrated to open the Saved Filters pane:

At this point, click the “Plus” icon and fill in the desired fields. Whenever you want to filter the log you can just click the Saved Filter View button to reveal your saved filters and select the filter that you want to apply.

Memory Allocation

Eclipse runs better with more memory, and what doesn’t? Thing is you might have 8 or 16GB or more in your dev machine but that doesn’t mean Eclipse is using it. The memory it uses is defined in the eclipse.ini file. If you get out-of-memory errors and the like you need to allocate more RAM to Eclipse.

On a standard Windows install, you will need to edit the ini file which is located in the root of your Eclipse install directory. This is a topic that others have expounded on better than I ever could so I’ll leave you with a link to a particularly good post on the topic:

Read more here: http://blog.xam.dk/?p=58.

XTemplates and Sheets in Sencha Touch

24 Feb 2012

I was recently working on a project where there was specific help text that proved to be quite long in many cases. The original plan was to use Ext.Msg but that quickly became impractical due to the sheer amount of text. Next thing to use was Ext.Sheet which has the flexibility and options that I needed.

The Sheet ended up configured to have a toolbar and footer, docked to the top and bottom respectively. I further configured it to float in the center of the screen with about a 40 pixel margin around the sides. The lone item in the Sheet was a panel configured to use an XTemplate so that I could update it as needed with whatever help text came across the help web service.

The problem I encountered was that I could only populate the content panel within the Sheet once. It turns out that the activate listener for the content panel only ever fires one time – the very first time that the Sheet is displayed which is the first time the panel is activated.

After some thought this behavior makes sense. The panel is rendered the first time and the activate event fires. Thereafter, it doesn’t need to fire because it is always the lone active item of the sheet – it has already been activated/rendered. If I were to add another item to the sheet and switch between the two I would then get the activate event firing for both panels every time they are switched. As it is, the panel is activated the very first time out of necessity, activate naturally fires, and that is pretty much the end of it.

Back to the task at hand, I don’t have anything bound to stores, no proxies… I didn’t want to mess with that, I just wanted to push an object into the panel and I could only do it once with the panel’s activate event. Every other call to show the Sheet would not update the content with new text – only the very first item was ever displayed and all further use of the Sheet would only show the content that it was initially updated with.

See the following code which fits this scenario:

...
var helpSheet_tpl = new Ext.XTemplate(
    '',
        '
{data}
', '
', { compiled:true } ); var helpContent = new Ext.Panel({ id:'helpContent', layout:'card', scroll:'vertical', tpl:helpSheet_tpl, listeners:{ activate:function(e,o){ // this event will only ever fire once!!! helpContent.update(DATA); } } }); var helpSheet = new Ext.Sheet({ id:'helpSheet', cardSwitchAnimation:{type:'pop',duration:1000}, height: window.innerHeight - 40, width: window.innerWidth - 40, centered:true, floating:'true', layout: { type: 'card', align: 'stretch' }, items:[ helpContent ], dockedItems:[ { xtype:'toolbar', layout:'card', dock:'top', id:'help_header', title:'Help', }, { xtype:'button',text:'OK', layout:'card', dock:'bottom', listeners:{ tap:function(o,e){ helpSheet.hide(); } } } ] }); ...

The learning here is that the activate event for the above content panel will only fire once because it is the lone item – there is no item-switching happening and so therefore no opportunities for activate to fire again. Also, Ext.Sheet doesn’t have any events so you can’t put an activate event listener on it. At least, when I attempted this nothing happened at all. The Sencha docs imply that it is inherited but if you check the option to hide inherited you will see that there is nothing left event-wise for Ext.Sheet.

If you want to push an object into a panel in the above scenario by using the panel update() method you will have to do so outside of the panel, and not rely on the panel’s activate event. In my case I placed it within the JSONP callback. First I use the show() method to show the sheet and then I follow that up with the update() method on the panel.

Making a Phone Call from Within PhoneGap in Android and iOS

22 Feb 2012

Today I came across a feature request that I had not done before – dialing a number from within an app. Some quick research shows that its possible using a specific URI scheme.

What are URI schemes? Honestly Wikipedia does a better job than I ever could in describing them but I think of them as something that allows a specific piece of functionality to happen over the internet, and thus they are usually referred to as protocols. You probably have already seen them – the most common ones are http: and https: (for web browsing), and ftp:, among others. Some are unique to an application and really don’t qualify as schemes and are definitely not a “protocol”, such as mailto: (to open up the mail client on a person’s computer), javascript: or about: – in fact, try typing about: in the address bar of your browser and hit “enter” on your keyboard, notice what happens…

In our case where we want to dial a number from within our app we need a way of telling the mobile phone that we want to make a call. There is a scheme for this purpose called tel:. A sample number using this scheme would look like this: “tel:+1-800-555-1234”. If you wanted a number to work around the world you would use an international number which includes the country code.

Implementing this is simple, we could do this within our mobile html5 app like so:

...
call this number
...

Ideally though we would delegate the event and fire a function to call our mythical phone number. To send the url (the “tel” url) to the browser we would write the following:

...
document.location.href = 'tel:+1-800-555-1234';
...

As of PhoneGap 3.6 all schemes are subject to whitelists. This means you have to add the tel scheme to a second whitelist that will allow your app to launch external applications. To do this you need to edit your config.XML to include the following (a mailto example is included):



Go here for more information: Cordova 3.6.0 Whitelist Guide.

Of interest to this topic is getting Android to treat phone numbers (as well as URLs and mailto schemes) as clickable links in text fields. I’ve not tested it but try adding the following to your config.xml.


Additional information on this can be found here: http://developer.android.com/reference/android/widget/TextView.html#attr_android:autoLink.

[EDIT: Note that what follows no longer applies but remains here for historical purposes.]

When we run the above code in Android 2.3.6 the phone dialer appears and does so with our number pre-populated ready to be dialed. Unfortunately on iOS 5 this doesn’t happen. A quick review of iOS documentation implies that it should work – so I suppose its just broken.
No need to panic, there is a PhoneGap plugin available which will take care of things. The plugin can be downloaded from here:

Click here to download the iOS Phone Dialer PhoneGap plugin

Its simple to install – just drag and drop the “m” and “h” files on to the classes folder of your xcode project. When you do this a dialog will appear with some options – be sure to click the radio button for copying “…files if needed..”.

Next, update the PhoneGap.plist file to reflect that you are adding a new plugin. The link for downloading the plugin explains the plist values as being “phonedialer > PhoneDialer”… but I think its easier to explain with an image:

The final step is to place the “PhoneDialer.js” javascript file somewhere within the root of your project and then to add it to your index.html file via a script tag.

Now that the Phone Dialer plugin is installed you’ll naturally want to know how to use it:

...
window.plugins.phoneDialer.dial('1-800-555-1234');
...

All in all pretty easy and straight forward, however now you have two methods of dialing a number within a single project. What you want is to use the tel: url scheme in Android and the Phone Dialer plugin in iOS.

Within Sencha Touch we have something called the Ext.is object whose attributes reflect everything that you could possibly want to know about the environment that your mobile app is living within.

For our purposes all we want to know is if we are in iOS or if we are in Android. These two lines provide us the answer:

...
Ext.is.Android // boolean, "true" for android, false otherwise
Ext.is.iOS // boolean, "true" for iOS, false otherwise
...

Thats all we need to impliment phone dialing across the two platforms within our mobile app. Lets build a function that makes use of one of the above (we don’t need both) and we should also give the user a choice in the matter, so the code below includes a message to the user to see if they really do want to suspend the app in favor of the device’s phone dialer:

...
function callSomeone(){
    var msg = Ext.Msg.confirm('Please Confirm','Are you sure you want to make a phone call?',
        function(r){
            if (r == 'yes'){
                if (Ext.is.Android){
                    document.location.href = 'tel:+1-800-555-1234';
		} else { // we assume the device is running iOS
		    window.plugins.phoneDialer.dial('1-800-555-1234');
		}
	    }   
	});
    msg.doComponentLayout();
}
...

All done… I suppose the very last thing to do here is to provide a complete working Sencha Touch example, and some screen captures…

...
Ext.setup({
    onReady: function(){
	
        var rootPanel = new Ext.form.FormPanel({
	    fullscreen: true,
	        items: [
		    {
			xtype:'button',
			text:'Call 1-800-555-1234',
			scope:this,
			handler: callSomeone
		    }
		],
		dockedItems:[
		    {
			xtype:'toolbar',
			dock:'top',
			title:'Phone Dialer Example'
		    }          
		]
	    }
	);
	
	function callSomeone(){
	    var msg = Ext.Msg.confirm('Please Confirm','Are you sure you want to make a phone call?',
		function(r){
		    if (r == 'yes'){
		        if (Ext.is.Android){
		            document.location.href = 'tel:+1-800-555-1234';
			} else { // we assume the device is running iOS
			    window.plugins.phoneDialer.dial('1-800-555-1234');
			}
		    }   
		}
	    );
	    msg.doComponentLayout();
	}

    }
});
...

The final product on a Samsung Galaxy S2:

XHR Post in Sencha Touch 1 & PhoneGap

13 Feb 2012

Sencha Touch has built in support for JSONP via “GET”, but if you have a lot of data to send you may quickly run into the GET character limit which varies across browsers. For a lot of data, “POST” is the preferred method and may be even preferred over GET for security reasons. The rub is that form POSTs will reload a page meaning that your app will reload and you’ll lose whatever state you had. That means we’ll have to do the POST via AJAX.

The astute among you might first ask about the cross domain policy and how it would prevent such a thing from happening (which JSONP by definition allows but is not useful here because its essentially a GET). As PhoneGap loads your Sencha Touch project via the file:// protocol cross domain XHR (XMLHttpRequest) is thus possible. Files loaded in this manner a free of the same domain policy.

With that aside it appears that Sencha Touch 1 just doesn’t have AJAX form posts as part of its framework but we can use Ext.Ajax.request() which allows us to set the desired form method and gives us success and error callbacks and even a timeout – which Ext.util.JSONP.request() lacks (bonus!).

The only additional setup is to add android.permission.INTERNET to the android manifest and to add the domain that you’re posting to to the whitelist in iOS. There has been some discussion about whitelisting in PhoneGap, it might be worthwhile to see how its evolved.

Here is a code snippet showing how the Ext.Ajax.request() method can be utilized within Sencha Touch:

...
Ext.Ajax.request({
	url: 'http://www.somewhere.com',
	method:'POST',
	params: 'configuration object goes here',
	scope:this,
	timeout:15000,
	disableCaching:true,
	failure: function(responseObj, opts){
		// handle your error response object here
	},
	success: function(responseObj, opts){
		// handle your success response object here
	}
});
...

The configuration object is simply something along these lines: {name:value,name:value,name:value,……}