Monthly Archives: June 2011

Create an Ext.tree.TreePanel from an XML document


Hi,

Recently I created menu manager with Ext JS components.
First I loaded tree from XML documents, But then I realize JSON will be very much easy. Still if you think that XML document is perfect for you then here is my work.

On fly I’m just providing html page and xml file, so if you have any doubts or questions then you can place comment bellow.

<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
	<head>
		<title>
			Manage Menu 
		</title>
		<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
		<link href="http://dev.sencha.com/deploy/ext-3.4.0/resources/css/ext-all.css" rel="stylesheet"/>
		<script src="http://dev.sencha.com/deploy/ext-3.4.0/adapter/ext/ext-base.js"></script>
		<script src="http://dev.sencha.com/deploy/ext-3.4.0/ext-all.js"></script>
		<link href="http://dev.sencha.com/deploy/ext-3.4.0/examples/tree/xml-tree-loader.css"/>
		<script src="http://dev.sencha.com/deploy/ext-3.4.0/examples/ux/XmlTreeLoader.js"></script>
		<script>
			//Excellent function that converts tree data into json
			function getJson(treeNode) {
				treeNode.expandChildNodes();
				var json = {};
				var attributes = treeNode.attributes;
				for(var item in attributes){
					if (item == 'src' || item == 'text' || item == 'allowDrop' || item == 'allowDrag') { //get only required attributes
						json[item] = attributes[item];
					}
				}
				json.children = [];
				if(treeNode.childNodes.length > 0){
					for (var i=0; i < treeNode.childNodes.length; i++) {
						json.children.push(getJson(treeNode.childNodes[i]));
					}
					json.leaf = false;
				} else {
					json.leaf = true;
				}
				return json;
			}
			//
			// Extend the XmlTreeLoader to set some custom TreeNode attributes specific to our application:
			//
			Ext.app.CustomTreeLoader = Ext.extend(Ext.ux.tree.XmlTreeLoader, {
				processAttributes : function(attr){
					// Set the node text that will show in the tree since our raw data does not include a text attribute:
					attr.text = attr.title;
					if(attr.src == 'javascript:void(0);'){ // Does the node has child?
						// Override these values for our folder nodes because we are loading all data at once.  If we were
						// loading each node asynchronously (the default) we would not want to do this:
						attr.loaded = true;
						attr.expanded = true;
					}
					else { // is it a leaf node?
						// Tell the tree this is a leaf node.  This could also be passed as an attribute in the original XML,
						// but this example demonstrates that you can control this even when you cannot dictate the format of
						// the incoming source XML:
						attr.leaf = true;
					}
				},
				requestMethod: 'GET'
			});
			Ext.onReady(function(){
				new Ext.Panel({
					title: 'Menu',
					renderTo: 'menuTree',
					layout: 'border',
					width: 500,
					height: 500,
					items: [{
						xtype: 'treepanel',
						id: 'tree-panel',
						region: 'center',
						margins: '2 2 0 2',
						autoScroll: true,
						rootVisible: false,
						enableDD: true,
						viewConfig: {
				            plugins: [{
				                ptype: 'treeviewdragdrop'
				            }]
				        },
						root: new Ext.tree.AsyncTreeNode(),
							loader: new Ext.app.CustomTreeLoader({
								dataUrl:'menu.xml'  //load your xml file
							}),
							listeners: {
								'render': function(tp){
								tp.getSelectionModel().on('selectionchange', function(tree, node){
									var el = Ext.getCmp('details-panel').body;
									tpl.overwrite(el, node.attributes);
								})
							}
						}
					}]
			    });
			});
			function savechanges(){
				var myTree = Ext.getCmp('tree-panel');
				var json = getJson(myTree.getRootNode());
				console.log(Ext.encode(json.children)); //serialize json data into string so we can send back to server
			}
		</script>
	</head>
	<body>
		<div id="menuTree"></div>
	</body>
</html>

Sample XML file…

<?xml version="1.0" encoding="UTF-8"?>
<menu src="root" title="root" id="0">
	<!-- Home -->
	<menu src="/page.htm2" title="Home"></menu>
	<menu title="Clients" src="javascript:void(0);">
		<menu src="/page1.html" title="Bank Management"></menu>
		<menu src="/page2.html" title="Client Management"></menu>
		<menu src="javascript:void(0);" title="Updates">
			<menu src="/page2.html" title="View Updates"></menu>
			<menu src="/page3.html" title="Report Bug"></menu>
		</menu>
	</menu>
	<!--  Ends -->
</menu>

I used third party control, that extends the XMLLoader for processing XML attributes…

In the Next post, I’ll show you how we can use JSON for easy storage and loading into tree. I’ll also post add/edit/delete/drag & drop/restriction etc.

Android: Play sound or Mp3 file from Assets


Hi,

I spend lots of time to play sound in Android Application.
Basically I wanted to play a sound file from android Assets, rather than from SDCard!

it was a small code like this:

MediaPlayer m = new MediaPlayer();
   try{
	   AssetFileDescriptor descriptor = AmbeMaAartiActivity.this.getAssets().openFd("myfile.mp3");
	   m.setDataSource(descriptor.getFileDescriptor(), descriptor.getStartOffset(), descriptor.getLength() );
	   descriptor.close();
	   m.prepare();
	   m.start();
   } catch(Exception e){
	   // handle error here.. 
   }

Cheers!!

Tips on jquery mobile


Hi,

For last month I am using jquery mobile. I’ve gone through lots of issues and learned a lot.

Web is good but when it comes with browser, HTML and java-scripts it becomes more buggy!

Generally I use chrome for development, and jquery mobile works perfect as it based on web-kit.

I tested and published my code, for desktop testing I use Firefox and chrome (not testing on IE as its jquery mobile). But when I open it in Android device, I see only half of the page rendering. And this is because of I made mistake in mark up language.

I forgot to close div tag and closed with li tag. In Firefox and chrome its ignored, but in safari it rendered differently.

See this code and output in chrome and safari, you will get the idea what i’m taking about.

Conclusion: While testing you web app IE is your acid test, while targeting web-kit or jquery mobile, safari is your acid test.

Create File Explorer in BlackBerry PhoneGap project


Hi,

I am using PhoneGap + jQuery Mobile for my current project.
It was required to upload images from gallery.

Unfortunately, In BlackBerry we can’t open built in Gallery to pick an image. So though why not to provide my file explorer? What worked pretty well.

As I am using PhoneGap, you can also use the same code for Android and may be for WebOS. In iOS it may not work.

Your index.html file:

<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1"> 
<title>File Explorer</title>
<script src="javascript/phonegap.min.js" type="text/javascript"></script>
<link rel="stylesheet" href="stylesheet/jquery.mobile.min.css" />
<script src="javascript/jquery.min.js"></script>
<script src="javascript/jquery.mobile.min.js"></script>
<script src="javascript/source.js"></script>
</head>
<body>
	<div data-role="page" id="FileExplorerPage">
		<div data-role="header" data-position="fixed">
			<h1>
				File Explorer
			</h1>
		</div>
		<div data-role="content">
			<div id="Explorer" style="float:left"></div>
		</div>
	</div>
</body>
</html>

And you JavaScript magic code:

/**
 * File explorer logic
 */
var currentPath = "file:///store";
$('#FileExplorerPage').live('pagebeforeshow', function(event) {
	populate(currentPath);
});
function populate(path){
	try {
		var dirEntry = new DirectoryEntry({fullPath: path});
		var directoryReader = dirEntry.createReader();
		directoryReader.readEntries(successDirectoryReader,failDirectoryReader);
	} catch (e) {
		alert(dump(e));
	}
}
function successDirectoryReader(entries) {
    var i;
    $("#Explorer").html('');
    for (i=0; i<entries.length; i++) {
        if (entries[i].isDirectory) {
        	$("#Explorer").append("<div style='width:104px;float:left;text-align:center;'><div><img src='local:///resources/folder.png' style='border:2px;' onclick='changePath(this)'/></div><div style='width:100px;word-wrap:break-word;'>" + entries[i].name + "</div></div>");
        } else {
        	var fileType = blackberry.io.file.getFileProperties(entries[i].fullPath).mimeType;
        	if (Left(fileType,5) == 'image') {
        		// if file is of type image, then show in small size
        		$("#Explorer").append("<div style='width:104px;float:left;text-align:center;'><div><img src='" + entries[i].fullPath + "' height='80px' width='80px' style='border:2px;' /></div><div  style='width:100px;word-wrap:break-word;'>" + entries[i].name + "</div></div>");
        	} else {
        		$("#Explorer").append("<div style='width:104px;float:left;text-align:center;'><div><img src='local:///resources/file.png' style='border:2px;' /></div><div>" + entries[i].name + "</div></div>");
        	}
        }
    }
    // add an option to go to parent directory
    if (currentPath != "file:///store") {
    	$("#Explorer").append("<div style='width:104px;float:left;text-align:center;'><div><img src='local:///resources/folder.png' style='border:2px;' onclick='backPath()'/></div><div style='width:100px;word-wrap:break-word;'>..</div></div>");
    }
}
function failDirectoryReader(error) {
    alert("Failed to list directory contents: " + error.code);
}
function backPath() {
	currentPath = Left(currentPath, currentPath.lastIndexOf('/'));
	populate(currentPath); 
}
function changePath(ele){
	currentPath = currentPath + "/" + $(ele).parent().next().html();
	populate(currentPath);
}

//Error dump function
function dump(arr,level) {
    var dumped_text = "";
    if(!level) level = 0;

    var level_padding = "";
    for(var j=0;j<level+1;j++) level_padding += "    ";

    if(typeof(arr) == 'object') {  
        for(var item in arr) {
            var value = arr[item];

            if(typeof(value) == 'object') { 
                dumped_text += level_padding + "'" + item + "' ...\n";
                dumped_text += dump(value,level+1);
            } else {
                dumped_text += level_padding + "'" + item + "' => \"" + value + "\"\n";
            }
        }
    } else { 
        dumped_text = "===>"+arr+"<===("+typeof(arr)+")";
    }
    return dumped_text;
}

//String left function
function Left(str, n){
	if (n <= 0)
	    return "";
	else if (n > String(str).length)
	    return str;
	else
	    return String(str).substring(0,n);
}

Download full project from here

Enable/disable link button in jquery Mobile


Hi,

I am developing mobile application, where I use jquery Mobile.

Buttons can be created by input tag, button tag and even link tag. See examples:


<button>Button1</button>

<input type="button" value="Button2" />

<a href="#" data-role="button">Button3</a>

In docs, I see enable/disable method for button. See.

But using this method, it can only set style, functionally it doesn’t! May be they missed it!

Anyway, I got some trick to make link enable/disable.

HTML5 now has data attribute that user can use it, browser will ignore it while rendering it.

So Disabling a link, I just remove href and onclick value to some data attribute and vice versa.

function test(){
    if ($("#mytest").parent().attr("aria-disabled") == "true") {
      $("#mytest").attr("href", $("#mytest").attr("data-href"));
      $("#mytest").attr("onclick", $("#mytest").attr("data-onclick"));
      $("#mytest").button('enable');
    } else {
      $("#mytest").attr("data-href", $("#mytest").attr("href"));
      $("#mytest").attr("data-onclick", $("#mytest").attr("onclick"));
      $("#mytest").attr("href","#");
      $("#mytest").attr("onclick","return");
      $("#mytest").button('disable');
    }
  }

See live example here.

Source code here.

New touch BlackBerry® Bold™ 9900/9930 smartphones


BlackBerry will launch two new smartphone. They will come with new OS version 7.0. Check here.

Developers can now get beta version of OS 7.0. They can test the phone in simulator also. Download beta version here.

Attractive features:

  • 1.2 GHz processor
  • 8 GB of onboard memory
  • 720p HD video recording
  • Accelerated graphics and the Open GL ES 2.0 standard
  • And many more… see

What I don’t like about this model is, its keypad. It should have left side keypad slider, so screen will be larger and typing will also be easier.