Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles / Languages / Javascript

Creating your own widget in iDevUI

5.00/5 (2 votes)
14 Oct 2013CPOL4 min read 9.3K  
Adding functionality to the iDevUI framework

Introduction

In this article, I'm going to teach you how to develop your own custom widget in the iDevUI framework. These are usually called UXs (User eXtensions) and add extra functionality to iDevUI.

Background 

iDevUI is a JavaScript framework which sits atop of jQuery. iDevUI enables you to create rich web applications by simply writing them as a set of JavaScript Objects. This enables developers (like me) to create amazing web applications just be simply defining some objects and letting iDevUI do the rest.

To find out more about iDevUI, you can go to the iDevUI website here. If you don't know about iDevUI, I suggest you try it first before you think about extending it with your own custom widget.

iDevUI is released under the MIT license. 

The code 

So we're going to create our own example widget and I'll show you what tools iDevUI gives you to add to your widget to make it easier for developers to use your widget.

The Setup 

So firstly, we need to download a new copy of iDevUI and place it in a folder.  Once we have done that, the directory structure should look like this: 

css
images
js
- idevui

We're going to create our custom widget inside of the idevui folder. Create a new folder in idevui/ux called examplewidget.

Inside that new folder, we're going to create 2 new blank files: examplewidget.css and examplewidget.js.

The CSS file will hold all of the styling for our new widget and the JS file will hold the code that iDevUI will use to render your widget when the developer writes it in their app.js.

Now we just need to tell iDevUI to load it. To do this open js/preferences.js and inside the ux array add a new row like so: 

JavaScript
ux:[
    "gauge/gauge.js",
    "uploader/uploader.js",
    "datepicker/datepicker.js",
    "signature/signature.js",
    "pictures/pictures.js",
    "treeview/treeview.js",
    "examplewidget/examplewidget.js"
],

Now iDevUI will know about your custom widget. Lets write it!

Writing the JavaScript

For this article, we're just going to create a widget that will output the current time on render.

To start, open your idevui/ux/examplewidget/examplewidget.js file we created earlier.

Firstly, let's define that we're creating a widget and that it should extend from iDevUI's baseWidget class:

JavaScript
idev.ux.widgetExample = baseWidget.extend(
{

});

iDevUI then requires us to create an init function which initialises the widget:

JavaScript
idev.ux.widgetExample = baseWidget.extend(
{
	init: function(config)
	{
		
	}
});

As you can see above, an argument gets passed to the init function automatically by iDevUI called config. This config is an object which the developer has defined in their app.js (with defaults added for anything that is missing).

We can use this to setup our own properties for our widget:

JavaScript
idev.ux.widgetExample = baseWidget.extend(
{
	init: function(config)
	{
		this._super(config); // Required by iDevUI
		this.wtype = "example"; // The wtype for the widget
		
		this.twelvehour = config.twelvehour || false;
		this.tpl = new idev.wTemplate(
			"<div id='{id}' class='ui-example' style='{elementstyle}{style}'>",
			"{clock}",
			"</div>"
		);
	}
});

For now, we're just going to have 1 properly called twelvehour which will set whether the clock is 12 hour rather than 24. By default the clock will be 24 hour.

The tpl property is an iDevUI wTemplate that defines our template for us to render. It uses tags (surrounded by {}) which get filled in using the array we will be passing to it.

Another thing iDevUI requires is a render method. This method gets called when iDevUI wants to render your widget:

JavaScript
idev.ux.widgetExample = baseWidget.extend(
{
	init: function(config)
	{
		this._super(config); // Required by iDevUI
		this.wtype = "example"; // The wtype for the widget
		
		this.twelvehour = config.twelvehour || false;
		this.tpl = new idev.wTemplate(
			"<div id='{id}' class='ui-example' style='{elementstyle}{style}'>",
			"{clock}",
			"</div>"
		);
	},
	render: function()
	{
		if (this.renderTo == null) return; // If there is nowhere to render our widget, don't render it!

		var data = new Array();

		data['id'] = this.id;
		data['width'] = this.width;
		data['height'] = this.height;
		data['elementstyle'] = this.elementstyle;
		data['style'] = this.style;
		data['clock'] = this.generateClock(); // Our custom method

		var sHTML = this.tpl.render(data);

		$("#" + this.renderTo).append(sHTML);

		this.rendered = true;
	}
});

This render method will now successfully render our widget. However, we need to create the generateClock() method to provide the current time. Let's write that.

JavaScript
idev.ux.widgetExample = baseWidget.extend(
{
	init: function(config)
	{
		this._super(config); // Required by iDevUI
		this.wtype = "example"; // The wtype for the widget
		
		this.twelvehour = config.twelvehour || false;
		this.tpl = new idev.wTemplate(
			"<div id='{id}' class='ui-example' style='{elementstyle}{style}'>",
			"{clock}",
			"</div>"
		);
	},
	render: function()
	{
		if (this.renderTo == null) return; // If there is nowhere to render our widget, don't render it!

		var data = new Array();

		data['id'] = this.id;
		data['width'] = this.width;
		data['height'] = this.height;
		data['elementstyle'] = this.elementstyle;
		data['style'] = this.style;
		data['clock'] = this.generateClock(); // Our custom method

		var sHTML = this.tpl.render(data);

		$("#" + this.renderTo).append(sHTML);

		this.rendered = true;
	},
	generateClock: function()
	{
		var d = new Date();
		var ampm;
		var time;

		var hours = d.getHours();
		var minutes = d.getMinutes();

		if(hours < 12)
		{
			ampm = "AM";
		}
		else
		{
			ampm = "PM";
		}
		
		if(this.twelvehour)
		{
			if(hours == 0)
			{
				hours = 12;
			}
			if(hours > 12)
			{
				hours = hours - 12;
			}
		}
		
		if(minutes.length == 1)
		{
			minutes = "0" + minutes;
		}
		
		if(this.twelvehour)
		{
			time = hours + ":" + minutes + " " + ampm;
		}
		else
		{
			time = hours + ":" + minutes + " " + ampm;
		}

		delete d;
		return time;
	}
});

Now we have a successfully generated time which will be generated on render. However, this is still not a complete widget, widgets in iDevUI have their own custom public methods and events attached. Let's add those:

JavaScript
idev.ux.widgetExample = baseWidget.extend(
{
	init: function(config)
	{
		this._super(config); // Required by iDevUI
		this.wtype = "example"; // The wtype for the widget
		
		this.twelvehour = config.twelvehour || false;
		this.tpl = new idev.wTemplate(
			"<div id='{id}' class='ui-example' style='{elementstyle}{style}'>",
			"{clock}",
			"</div>"
		);
	},
	render: function()
	{
		if (this.renderTo == null) return; // If there is nowhere to render our widget, don't render it!

		var data = new Array();

		data['id'] = this.id;
		data['width'] = this.width;
		data['height'] = this.height;
		data['elementstyle'] = this.elementstyle;
		data['style'] = this.style;
		data['clock'] = this.generateClock(); // Our custom method

		var sHTML = this.tpl.render(data);

                // beforerender event which the developer can hook onto
		if(this.events && this.events.beforerender)      this.events.beforerender(this);
		if(this.events && this.events.beforeRender) this.events.beforeRender(this);

		$("#" + this.renderTo).append(sHTML);

                // afterrender event which the developer can hook onto
		if(this.events && this.events.afterrender) this.events.afterrender(this);
		if(this.events && this.events.afterRender) this.events.afterRender(this);

		this.rendered = true;
	},
	generateClock: function()
	{
		var d = new Date();
		var ampm;
		var time;

		var hours = d.getHours();
		var minutes = d.getMinutes();

		if(hours < 12)
		{
			ampm = "AM";
		}
		else
		{
			ampm = "PM";
		}
		
		if(this.twelvehour)
		{
			if(hours == 0)
			{
				hours = 12;
			}
			if(hours > 12)
			{
				hours = hours - 12;
			}
		}
		
		if(minutes.length == 1)
		{
			minutes = "0" + minutes;
		}
		
		if(this.twelvehour)
		{
			time = hours + ":" + minutes + " " + ampm;
		}
		else
		{
			time = hours + ":" + minutes;
		}

		delete d;
		return time;
	},
	setTwelveHour: function()
	{
		this.twelvehour = true;
		idev.dom('#' + this.id).html(this.generateClock());
	},
	setTwentyFourHour: function()
	{
		this.twelvehour = false;
		idev.dom('#' + this.id).html(this.generateClock());
	}
});

Now we have 2 events, afterRender and beforeRender and we have 2 custom methods which the developer can call, setTwelveHour and setTwentyFourHour.

Finishing touch

Finally, let's register this as a widget in iDevUI and add our CSS styling.

JavaScript
idev.ux.widgetExample = baseWidget.extend(
{
	init: function(config)
	{
		this._super(config); // Required by iDevUI
		this.wtype = "example"; // The wtype for the widget
		
		this.twelvehour = config.twelvehour || false;
		this.tpl = new idev.wTemplate(
			"<div id='{id}' class='ui-example' style='{elementstyle}{style}'>",
			"{clock}",
			"</div>"
		);
	},
	render: function()
	{
		if (this.renderTo == null) return; // If there is nowhere to render our widget, don't render it!

		var data = new Array();

		data['id'] = this.id;
		data['width'] = this.width;
		data['height'] = this.height;
		data['elementstyle'] = this.elementstyle;
		data['style'] = this.style;
		data['clock'] = this.generateClock(); // Our custom method

		var sHTML = this.tpl.render(data);

                // beforerender event which the developer can hook onto
		if(this.events && this.events.beforerender) this.events.beforerender(this);
		if(this.events && this.events.beforeRender) this.events.beforeRender(this);

		$("#" + this.renderTo).append(sHTML);

                // afterrender event which the developer can hook onto
		if(this.events && this.events.afterrender) this.events.afterrender(this);
		if(this.events && this.events.afterRender) this.events.afterRender(this);

		this.rendered = true;
	},
	generateClock: function()
	{
		var d = new Date();
		var ampm;
		var time;

		var hours = d.getHours();
		var minutes = d.getMinutes();

		if(hours < 12)
		{
			ampm = "AM";
		}
		else
		{
			ampm = "PM";
		}
		
		if(this.twelvehour)
		{
			if(hours == 0)
			{
				hours = 12;
			}
			if(hours > 12)
			{
				hours = hours - 12;
			}
		}
		
		if(minutes.length == 1)
		{
			minutes = "0" + minutes;
		}
		
		if(this.twelvehour)
		{
			time = hours + ":" + minutes + " " + ampm;
		}
		else
		{
			time = hours + ":" + minutes;
		}

		delete d;
		return time;
	},
	setTwelveHour: function()
	{
		this.twelvehour = true;
		idev.dom('#' + this.id).html(this.generateClock());
	},
	setTwentyFourHour: function()
	{
		this.twelvehour = false;
		idev.dom('#' + this.id).html(this.generateClock());
	}
});
idev.ux.loadCSS("examplewidget/examplewidget.css");
idev.register("example",idev.ux.widgetExample);
CSS
.ui-example {
	border: 2px dashed red;
}

And we're done! We have a full working widget. Obviously this is just an example and the clock will only show the time of the render and won't update every minute.

Using the widget

Now I'm going to show you what the developer has to do to use your widget.

First they have to download your widget folder from your ux folder (called example widget) and place it in their ux folder. Then they have to update their preferences (in the same way we did above).

Now they can open their js/app.js and add your widget to their page:

JavaScript
{
    wtype: 'example',
    twelvehour: true
}
JavaScript
{
    wtype: 'example',
    events:{
          beforerender: function(wgt){
              wgt.setTwelveHour();
          }
    }
}

Conclusion

This is a really powerful way to creating new custom widgets in iDevUI and allows you to create amazing new widgets for iDevUI developers.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)