vegUI.org home of the javascript based window manager and AJAX framework

VegUIClient - Part 2 - Building the application front-end

written by vegu on 22 Jun, 2007 01:57:25
Okay, in the first part of this tutorial series we went over the file structure of the vegUIclient addon and set it up so that we can now build our application on top of it.

First let's define what we will need in terms of widgets.

We will need a window that will perform as our text editor. The window will hold a text-area node that we will use to edit the contents of a file and a button to save the changes. Oh and of course a button to load the current file contents from the server.

For simplicity we will make it so that the window is opened automatically when the site is loaded.

For theming we will use the styles and graphics from the earlier vegUI tutorials. You can download the graphics here.

Removing the serverinfo module


Before we get to the building part we will remove something first, though. The serverinfo module. We dont need it and it's only purpose is to serve as an example :D

Go to the ui/commented directory and open the file compile.sh (if youre on linux) or the file compile.bat (if youre on windows) and remove the "vegui.serverinfo.class.js" from it. Then run the file to recompile the vegui_client.js library.

You can also remove the vegui.serverinfo.class.js file for the sake of being tidy.

Before we proceed, just because i know some of you skipped this part in the first tutorial, make sure that youre /index.php file is including the commented library not the compressed one.

code: html
<script src="ui/compressed/vegui_client.js" type="text/javascript"></script>


needs to be change to

code: html
<script src="ui/commented/vegui_client.js" type="text/javascript"></script>


in index.php

Then open the ui/templates.js file and remove the section that sets up the template for the serverinfo display:

code: js
/*
* Set up serverinfo module
*/


var o = Client.add_child('ServerInfo', VUI_SERVER_INFO);
o.set('div',0,100,100,100);
o.set_marg(100,100);
o.T.className = 'serverinfo';

Now go to the module directory and remove the serverinfo sub directory, we wont need it anymore.

Okay if you load index.php in your browser now all you should see the black manager node, no more server infos.

Creating the front-end module for our editor



Go to the ui/commented directory again and create a new file called simpleeditor.class.js. This will be the library file that contains the front-end part of our simple editor module.

When i write my modules, for what ever framework, i like to split it up into sections, a global section where i define functions and constants, and a section for the module, neatly delimited by comments.

Lets start with the global section this is were we will define a vegui element type for our module, as well as initialize our module so that the manager can later find it when it's type is submitted to one of the manager's functions.

code: js
/********************************************************************
* G L O B A L S
*******************************************************************/


/* simple editor vegui element type, make sure you chose
* a number higher than 250, as those are reserved for
* original vegui elements. Rule of thumb is stay above
* 1000 to be save ;)
*/


var VUI_SIMPLE_EDITOR = 2455;

/* initialize the simple editor as a vegui module */

vui_module_add(VUI_SIMPLE_EDITOR, SimpleEditor, 'simpleeditor.class.js');

Now we will write the actual module, i will not go as in depth as i did with the calculator application tutorial, so i highly recommend you read that if you haven't yet.

code: js
/********************************************************************
* S I M P L E E D I T O R
*******************************************************************/

/* Class: SimpleEditor */

function SimpleEditor(refName, Parent, Manager) {

/* constructor, this makes sure that the simple editor will
* take over all properties of the VegUIWindow constructor
*/


this.constructor = VegUIWindow;
this.constructor(refName, Parent, Manager);

/* give the simple editor a vegui element type */

this.type = VUI_SIMPLE_EDITOR;

/* create the editor's child elements */

this.BtnSave = this.Ui.add_child('BtnSave', VUI_BUTTON);
this.BtnLoad = this.Ui.add_child('BtnLoad', VUI_BUTTON);
this.FldText = this.Ui.add_child('FldText', VUI_NODE);

/* set wrapper methods for exec_xml and build */

this.build = this.build_editor;
this.exec_xml = this.exec_xml_editor;
}
SimpleEditor.prototype = VegUIWindow;

Okay, we have created the constructor for the SimpleEditor object, using prototype we extended it's properties from the VegUIWindow element.

As you see we also have added three child elements to the Ui element that was taken over from VegUIWindow. Interactive elements that you add to windows or any objects extended from the window should always be added to the Ui child, not directly to the window element.

BtnLoad, is the button element that we will use to load our text file into the editor, BtnSave is the button element that we will use to save any changes we make to the text file back to server. And FldText will be a simple textarea node that we will use to display and edit the text.

We will also need to define a couple of methods in order to make our module do stuff. We add them using the prototype property of the object, because it's the smart thing to do.

code: js
/*******************************************************************/
/** Method: build_editor
*/


SimpleEditor.prototype.build_editor = function(toNode) {

/* build element, since the editor is extended from the
* VegUIWindow element we will use build_win to build it
*/


if(!this.build_win())
return null;

/* reference to the manager object */

var M = this.Manager;

/* reference to this editor */

var E = this;

/* set up button states for the buttons load and save */

/* clicking the save button will send a request to the simpleedit.save
* script containing the current value of FldText
*/


this.BtnSave.States[VUI_MOUSE_UP].Scripts.add(
function() {
M.request(
'simpleedit.save', 'text='+escape(E.FldText.Base.value), 'POST'
);
}
);

/* clicking the load button will send a request to the simpleedit.load
* script
*/


this.BtnLoad.States[VUI_MOUSE_UP].Scripts.add(
function() {
M.request('simpleedit.load');
}
);

/* dock this element to toNode if it's set */

this.dock(toNode);
return 1;
};

We create the editor's own build method. Mainly to set up the mouse states of the buttons. Note that i am using the state VUI_MOUSE_UP instead of VUI_MOUSE_DOWN, because of the way the vegUI element focus is set up using VUI_MOUSE_DOWN on buttons placed in a window can mess things up.

code: js
/************************************************************/
/** Method: exec_xml_editor
*
* Executes ui operations delivered via xml from the server
*/


SimpleEditor.prototype.exec_xml_editor = function(xml) {

if(!xml || !xml.length)
return 0;

var c = xml, i, e;

for(i = 0; i < c.length; i++) {

e = c[i];

/* if the nodename of the element is op then treat
* the element as an operation call
*/


if(e.nodeName == 'op') {
switch(e.getAttribute('id')) {

/* if operation id is 'load', put the submitted data into
* the FldText element
*/


case 'load':

this.FldText.Base.value = e.getAttribute('text');

break;

}
}
}

};

This is the function that will handle the server responses received from a request to the server. We will use xml as a protocol so when the user clicks on the load button and the simpleedit.load script is requested from the server, the response could look something like this:

code: xml
<vegui>
<module name="SimpleEditor">
<op id="load" text="The contents of the text file" />
</module>
</vegui>

I will go more in-depth on the network protocol later, but just so you understand how the front end handles the server response in case of a selected XML protocol.

The initial response will be handled by the VegUIClient object, it will see the module tag, which serves as a router and all sub elements of the module tag will be sent as an xml object to the specified module's exec_xml function.

Alright, we're done with the front-end library for now. Save the file and open up the compressed/compile.(sh/bat) and add the file to the list. If youre on a windows box and need to edit the bat file make sure to add a plus sign in front of the filename.

Save the compile script and run it to recompile the vegui_client.js library to include our module.

Now its time to set up the template and theme!

Open up ui/ui.css and remove the css class for the serverinfo module which we forgot to get rid of earlier when we removed the module, oops.

Then add these css classes. The comments should explain enough i hope.

code: css
/* the class for our client node */

.client {
background-color: #9da7bf;
}

/* these are the button classes for the min,max and close buttons
* of our window element
*/


.btn_close_1 { background-image: url('img/btn_close_0.gif'); }
.btn_close_2 { background-image: url('img/btn_close_1.gif'); }
.btn_minimize_1 { background-image: url('img/btn_minimize_0.gif'); }
.btn_minimize_2 { background-image: url('img/btn_minimize_1.gif'); }
.btn_maximize_1 { background-image: url('img/btn_maximize_0.gif'); }
.btn_maximize_2 { background-image: url('img/btn_maximize_1.gif'); }

/* the css class for the header of our window */

.win_header {
background-color: #5c5b5b;
}

/* the css class for the caption (header font) of our window */

.win_caption {
color: #fff;
font: bold 10px Verdana, Arial, Helvetica;
}

/* the base css class for the window */

.win {
background-color: #d9d9d9;
border: 1px #838383 solid;
}

/* the css class for the window skin */

.win_skin {
border: 1px #fff solid;
}

/* the css class for the window shadow, the frame that is seen
* when the window is being moved or resized by mouse
*/


.win_shad {
border: 2px #838383 solid;
}

/* the css classes for our load and save buttons */

.btn_load_1 { background-image: url('img/btn_load_1.gif'); }
.btn_load_2 { background-image: url('img/btn_load_2.gif'); }
.btn_save_1 { background-image: url('img/btn_save_1.gif'); }
.btn_save_2 { background-image: url('img/btn_save_2.gif'); }

/* the css classes for our text area */

textarea.fldtext {
border: 1px #838383 solid;
background-color: #fff;
padding: 5px;
font: bold 10px Verdana, Arial, Helvetica;
color: #838383;
}

Save ui.css.

Also create a new directory called img as sub-directory of the ui directory (ui/img) and copy all the image files you downloaded earlier into it.

Now open up ui/templates.js.

In the I N I T section add this to the bottom so that the shared FX object gets initialized.

code: js
/* make sure the fx engine is initialized, because we will use the
* shadow effect on our window
*/


Client.init_fx(50);

While we are in the area, also replace this line:

code: js
Client.T.Css.backgroundColor = 'black';

to

code: js
Client.T.className = 'client';

Next we will add a generic window template that we will later use to clone the Simple Editor module from. You could theoretically assign all these properties directly to the Simple Editor module, but what if you would want to add another window based module to the application later.

code: js
/*
* Generic Window Template. Theoretically you could assign these properties
* to the simpleeditor module directly, but instead we will clone it
* from this template later on. This is to demonstrate once again how
* to use the template engine.
*/


genericWin = Client.get_new(VUI_WIN);
genericWin.set('My Window', 300, 150, 50, 50);

genericWin.Header.T.className = 'win_header';
genericWin.Caption.T.className = 'win_caption';
genericWin.T.className = 'win';

/* spiffy shadow effect that will be applied to the window once it
* is built
*/


genericWin.event_add(
'onbuild', function(a) {
a[0].Manager.FX.effect_add(
a[0], new VegUIFXShadow()
);
}
);

/* set up the buttons of the window */

genericWin.BtnClose.set(null,3,18,18,'btn_close_1','btn_close_2');
genericWin.BtnClose.set_marg(null,null,5);

genericWin.BtnMaximize.set(null,3,18,18,'btn_maximize_1','btn_maximize_2');
genericWin.BtnMaximize.set_marg(null,null,25);

genericWin.BtnMinimize.set(null,3,18,18,'btn_minimize_1','btn_minimize_2');
genericWin.BtnMinimize.set_marg(null,null,45);

/* set maximum proportions of the window */

genericWin.T.maxY = 0;
genericWin.T.maxH = 600;
genericWin.T.maxW = 800;

/* set minimum proportions of the window */

genericWin.T.minW = 150;
genericWin.T.minH = 100;

/* skin window */

genericWin.Skin.T.className = 'win_skin';
genericWin.Skin.set_marg(2,2);
genericWin.Header.set(2,2);
genericWin.Header.set_marg(2);

Okay, we're done here for now, but we will be back in a bit. Save the file.

It is actually time now to add a second module, an extension to the VegUIClient object that we will use.

Create the file ui/commented/customclient.class.js.

We are going to add the Simpl Editor as a child element to our main application. However you should never edit the VegUIClient object to do so, because it will make you inflexible for VegUIClient patches.

So we are first going to create our own custom version of the client.

Open the file you just created and lets get to work. Don't worry this will be real quick and painless :).

code: js
/********************************************************************
* G L O B A L S
*******************************************************************/


/* note that unlike our simple editor module we do not need to define
* a vegui element type for this element. Because it's a manager element
* meaning it will be created manually using the 'new' keyword
*/


/********************************************************************
* C U S T O M C L I E N T
*******************************************************************/


function CustomClient(refName, Parent, Manager) {

/* constructor, this is so the stuff from the VegUIClient constructor
* is applied to this object as well
*/


this.constructor = VegUIClient;
this.constructor(refName, Parent, Manager);

/* child elements */

/* adding our simple editor as a child of our custom client */

this.SimpleEditor = this.add_child('SimpleEditor', VUI_SIMPLE_EDITOR);

}
CustomClient.prototype = VegUIClient;

You dont need to define a module type for modules that extend the VegUIManager, because those will always be instanced by using the new keyword manually and never over another manager. Unless maybe you would do a multi layered manager experiment, i will have to try that some time :D A VegUIManager inside a VegUIManager, i am not even sure what would happen :) Anyways back to the good stuff.

Okay, you know the drill, save the file. And open up the commented/compile.(bat|sh) and add this module to the list and run the script.

Then open ui/templates.js again - see i told you we would be back soon - and change this line:

code: js
var Client = new VegUIClient('Client');

to this:

code: js
var Client = new CustomClient('Client');

Alright, since we're already here lets set up our Simple Editor object as well. If there were going to be multiple SimpleEditor windows we would create a Simple Editor template that we would clone them from. But since there will only be one Simple Editor window we will just clone it from the GenericWindow and set up it's other properties and elements right away.

We do this under / after the genericWin set up we did earlier.

code: js
/*
* Simple Editor setup
*/


/* i am pointing the variable o at the Client.SimpleEditor object
* just so i dont have to type it over and over again :)
* - what can i say, laaazy
*/


var o = Client.SimpleEditor;

/* clone properties from our generic window template */

o.clone(genericWin);

/* set the window title and proportions */

o.set('Simple Editor', 500, 350);

/* set up FldText element */

o.FldText.set('textarea', 100, 100, 10, 25);
o.FldText.T.className = 'fldtext';

/* setting it's margin. I need to be aware aware of the padding
* of the element that was set via css when i set the margins
* as it will modify the elements size in a way that vegui
* does no recognize. In the css we set the flttext class
* to have a padding of 5 px, which adds up to 10px extra
* width, so in order to have a right margin of 10px we need
* to set it to 20px
*/


o.FldText.set_marg(20,60);

/* set up save button, note that i am using the exact image size
* of our button image
*/


o.BtnSave.set(10,0,74,27,'btn_save_1','btn_save_2');

/* set up the margin to make sure it is positioned at the bottom
* of the window at all times, even if the window is
* resized
*/


o.BtnSave.set_marg(null,null,null,10);

/* setting up the load button the same way */

o.BtnLoad.set(94,0,74,27,'btn_load_1','btn_load_2');
o.BtnLoad.set_marg(null,null,null,10);

Also, we want to make sure that the Simple Editor window is opened when the client has been built so scroll down to the bottom of the template.js file and find a function called "vuiclient_init()". This function is set as the onload event of the page meaning it gets called when the page has finished loading.

In it, after the Client.build call add the following code.

code: js
/* make sure the simple editor is opened when the client has been
* built
*/


Client.SimpleEditor.show();

Alright! Go check it out, navigate to the /index.php with your browser and if everything went smoothly you should be presented with a more or less tidy looking editor window with an field to edit text and two buttons to load and save.

That's the end of part 2 of this tutorial series, in the next part we will build the backend module that will handle retrieving the content of the text file from the server as well as saving any changes to it.

Related Posts


Your Comment

name:*
email-address:

Are you human?



Comments

No comments yet.