Thursday, May 14, 2009

Integrating Vision in a Xataface application

So I recently had a chance to check out the photo slideshow preview called Vision and I really liked it and I wanted to try to integrate it into a Xataface application I had built. It was quite tricky so I thought I would make a post about it for those who would like to try it in the future.

Before we start, I am using Xataface as my backend while my frontend uses the Smarty engine (something that is packaged into Xataface) to display my html code. So in the backend, the user would be uploading the photos to the system and then I would use vision to display them on the front end. If neccessary, view this http://xataface.com/documentation/how-to/how-to-handle-file-uploadsto see how to upload images using Xataface.

I am going to assume you have used method 2 to store images. If method 1 was used, I am not sure if it's possible to use this post to help you


If you've looked over the example of vision, you'll realize that you need to setup a few variables in order for it to work.

Step 1: Creating a custom action which prepares all the necessary variables needed to run the photo slide show.



The most important variable we need to set is the $imgDir variable which tells the Vision where the images you want to upload are found. We could hardcode this directory name, but hardcoding is bad. So we'll take a slightly tricky yet does the job piece of code. The images are going to be stored in a directory (depending on how you set it up based on the aforementioned document it could be anyway). To find out the exact directory you can make use of the fact that the path is stored in the table's variables.

Note in line 5 and 6, we load the table that stores the image data (in this case, I have a table called photos), and then I grab the field called photo_url which is the column in the database which saves the path of the image. That field itself is an array with lots of key=>value pairs, but the one we are interested in is called the url. Now this is the tricky part, we need to get the relative path to the directory and not the absolute path which is what the url value is (ie. site_url/tables/photos/photo_url/) But since we know that the site_url is nothing more than just the Xataface constant variable called DATAFACE_SITE_URL we can just use the php function explode to get rid of that which is what line 9 and 10 do.

After this explode function, we know that the value we need is stored in the array index 1 which is what we pass into the lsDir() function. This function is defined in the vision source code which you'll have to copy and paste into your code. I didn't post it to save room.

Now we just call the df_display() function sending in our contextual variables we need and call the photos.html file which will be parsed by the Smarty engine.

Step 2: Preparing our smarty .html page to present the slideshow
This next part gets really tricky and quite annoying. Because the vision example code integrates php code with javascript code which is just plain annoying. And anyone who has used the smarty engine knows that you have to use the {literal}{/literal} tags to parse javascript functions properly.



All I've done is taken the original example code they provided and replaced the php echo statements with the php variable. The smarty engine takes care of displaying the variable. Also, on line 8, I removed the use of the php foreach statement and utilized the Smarty foreach statement which is a little cleaner.

After this part was edited, remember to add the master.css and ie.css files. And then add the conditional comment at the top to make sure we use the ie.css file. And it should work!

Please post any errors you received and I can try to help you.



I used the {ldelim} and {rdelim} tags instead of {literal}. Both cases work

Using conditional hacks with IE

You probably know this, but IE is the browser that generally gives the most pain to web developers because of its non-compliance to so many standards. Luckily for us, Microsoft has started to realize this in IE7 and added something called 'conditional comments. This allows developers to add code into comments that will only be interpreted by IE7+ and ignored by the rest. For example,



Wherever this is placed, IE will interpret this was if the browser less than IE7 it will run whatever is in it's block. So it will display a style sheet just for the IE browser.

See these resources for more details:


  1. CSS Hacks and IE7

Printing out a nicely formatted array

A lot of Xataface's core functionality requires the usage of the array data types. So whenever you are dealing with bugs you are going to most likely be dealing with an array and figuring out its contents. You can see the contents of an array in a nice format, but using this trick:



This will print out your array in a format like this:

Monday, May 11, 2009

Preventing a record from beng expandable in the navigation tree

On the left side of each record, there is a section called 'this-record' which has a list of related records. Have you ever had the case where you needed to prevent one of those related records from being expanded? You can achieve this easily using the expandable permissions. For example,



This getPermissions() method belongs to author's delegate table, where we check to see if we are currently in the conference table (author's belong to conferences). If we are, we just set the expandable permission to 0, and so when we go to a conference record none of the author records will be expandable in the navigation tree!

Sunday, May 10, 2009

Calling the functions of a delegate class

Ever had a situation where you had built a custom function in a particular delegate class, and then had another delegate class need to use that function? It's possible! You have to first load the table you are interested in using the function from, and then load it's delegate. From there you can just treat the delegate as an object and just calls its function. For example:



We just want to borrow the getPermissions() method of the patents delegate class to be used in this delegate class. This is a nice trick to reduce redundant code.

registerPloneFunction

You might need to run a javascript function that needs to be run upon window.load event. A quick and easy way to get this done in Xataface is to write the script however you want it and then use the registerPloneFunction(function). With function being the javascript function you want to run. So for example, you could do something like this:



In the after_view_tab_content block, we add this external javascript. And then in your javascript file:



You can actually add the javascript to any block. The registerPloneFunction always makes sure it is run when the window is finished loading event.

Thursday, May 7, 2009

How to prevent a field from being editable

Sometimes you want to have the user be able to see a field in the details tab, yet when they try to edit the record the field is not editable. It could be case that the field is populated through a trigger or something. Xataface doesn't provide explicit support for this with any attributes in the fields.ini, but the solution isn't that difficult. All you have to do is use the fields__permissions() method:



Note: This code goes into the delegate class of the table that contains this field.


Here the field I want to hide in the edit tab is called the Role field. Now we just return an array with the key=>value attribute of 'edit'=>0. What happens is the this array of permissions gets merged with whatever array of permissions the field normally has. So if the user is viewing the record, they would have view permissions which doesn't have any permission for edit. So by setting the edit permission we would be doing nothing. However, the real beauty comes when we are in the edit tab and we explicitly state 'edit'=>0, and thus the field is no longer editable, but still visible.

Tuesday, May 5, 2009

Show/Hide a chunk of text

A pretty common task that I do a lot is provide the user the ability to show and hide a chunk of text. For example, say I have a page containing a list of songs and I want to allow the user the ability to see and hide the lyrics of the song. The format could potentially be the song title with a "show lyric" link beside it that when clicked will reveal the lyrics below it in a "Ajaxed" slidedown. The 'Show lyrics' text could then change to 'hide lyrics' which when clicked does the opposite effect.

To do this is actually pretty easy. I will be utilizing the scripaculous AJAX libraries.

To get started, you'll need to download the libraries and then include the javascript libraries into your page:



Now this next section gets a little complicated because I am using the Smarty libraries to help me abstract PHP code from my HTML layout. So bear with me:



How it works is we'll have an array of Xataface Records of the songs table. So I will be iterating through this array displaying the title and then displaying the lyrics in the song_item{$item} div id. The reason why I need to use the {$item} variable is because each id has to be unique so that when we click the link to show/hide the lyrics it knows exactly which div element to show. Notice that the onclick handler is to a javascript function called showHideLyrics() with the parameter 'song_item{$item}'. Also important is the id of the anchor link which is 'song_item{$item}_link' This is important so that we can change the anchor link text.

So the showHideLyric() javascript function:



So the first parameter is the div element containing the lyrics. We will check if it is already hidden, and if it is then we want to show it. We will rely on the scriptaculous code to do this for us. And then after that we will use the code:

document.getElementById(element + '_link').firstChild.data = "[Hide Lyrics]";


To change the anchor link text. The use of the firstChild.data properties is proper javascript. We could have used the innerHTML proper, but that is not proper. And the case is nearly the same when the lyrics are shown we just use the scriptaculous code to help us hide it and change the text to "[Show Lyrics]".

Cool hey?

Friday, May 1, 2009

Text getting cut off when using the $record->val() function

One thing that got me really frustrated for the longest time was the fact that I didn't realize that Xataface Records when retrieved from the df_get_records() or df_get_records_array() function would have their values chopped off at 255 characters if it got longer than that.

I am sure this feature was added in so that during list views of the table records we don't blow up main memory by loading the entire field of each record. But this can be a tricky situation when you sometimes require the full value and don't realize it! It can have some really funny effects on your code. In my case, I had a field which stored a serialized array of conference ids that a particular user belonged to. So when we viewed the user, we would have to check whether the conference we are currently viewing falls in that list of conference ids.

You can begin to see where the potential problem lies right? If the conference_ids serialized array string is cut off then its incomplete and so when we go to unserialize it, we get basically an empty array! Frustrating!

The solution is quite simple actually. I will list three potential solutions to the problem:


  1. The first solution is to simply add the attribute struct=1 to the appropriate field in the fields.ini file. According to the wiki:

    A boolean (0 or 1) value indicating whether this field is considered a structure. A value of 1 indicates that this field is a structure and should not be truncated under any circumstances. Normally fields are truncated at 255 chars in list view. This is useful if the field contains XML or other structured data so that attempts to truncate it would destroy integrity.


  2. This above solution works, however it then becomes on every request we retrieve the entire text when sometimes it's not actually necessary. If you were using Xataface as a back-end to a webpage, you can control when to actually retrieve the whole 255 characters by sending in a particular parameter to the df_get_records function. According to the API, the df_get_records_array function looks like this:

    function &df_get_records_array($table, $query=null, $start=null, $limit=null, $preview=true){

    There is actually a parameter call $preview which when set to false will return you the whole thing. Nice and easy. That's the way it should be!


  3. This last method gets down to the nitty grity code and can be used for very explicit purposes (eg. one record should display 255 characters while another could also all). All we have to do is just check if the field value is at least 255 which signifies that it could be longer. And then we would just either use the df_get_record() function (This function DOES return the full length of the fields. It is the df_get_records() functions that don't) to get the record and the full value. Or we can just write a quick sql query to get that one column:



Thursday, April 23, 2009

Aptana IDE for Xataface

I've spent most of my development time simply using Notepad++ simply because it's so fast and just gets the job done. But I decided to try something different and actually get some sort of IDE for my development one that could recommend me the Xataface functions/classes to use.

I heard about this IDE called Aptana which was designed specifically for web development decided to give it a try. And after trying it out and setting it up with Xataface, I must say it is really wicked.

To set it up to work with Xataface is really simple:


  1. First download Aptana from http://www.aptana.com/. You can get it as standalone or as a plugin to Eclipse. Doesn't matter. I downloaded the .zip file as I try to avoid installers as much as possible.

  2. After it has downloaded, just go to the folder and start up Aptana by clicking on the .exe file. A slashscreen will appear and Aptana will start setting up some folders and configuration files on your computer. And after a few seconds, you'll be brought to the Aptana application frontpage.

  3. The tab you are on should be the "My Aptana" tab. Next, click "Plugins" and then you will see "Aptana PHP" and then click on get it. It will start downloading and install the PHP plugin for Aptana.

  4. After this is done, you'll need to tell Aptana to use the libraries/class of Xataface in it's php autocomplete. This is very simple. Go to:

    Windows->Preferences->Aptana->Editors->PHP->PHP Libraries.

    Now add the folder where Xataface is and then called the library name whatever you want (I called it Xataface Framework).

  5. Now when you start a PHP project, and a php file. You can start typing any Xataface class and it will recognize the class and recommend it as well as the syntax!



This is really good as Xataface as never been officially documented to use any IDE. I'll continue to keep posting about my experiences and any tips/tricks I learn along the way.

Editing the userchrome.css file

I recently discovered something really helpful in Firefox called the userchrome.css file. By editing this file you can add some pretty slick styling features to your Firefox browser to help you browse the web. For example, I was able to disable the forward and backward buttons when they weren't necessary. This tutorial is of very good help.

Here is the userchrome.css file I customed myself:

Thursday, April 9, 2009

How to access the conf.ini fields

Xataface will load all the attributes in the conf.ini and use them to setup the application. But what happens if you decide to store some attributes in the conf.ini yourself that Xataface itself doesn't need, but you would like to use it during the execution of your code?

Say for example, you have this:



Here we have a database connection that you would like to use to connect to another database [other than the one that xataface is using to setup the application]. The code to access it:



The Xataface_Application object has attribute which you can access which then contains the entire conf.ini data in an array-array.

Very useful!

Display a 0 value

In Xataface, if the column in the database is of integer type and the row has a 0 value in that column then it would be displayed in the view tab. Normally this isn't a problem and actually nice because then it won't clutter up the screen. But sometimes you actually need to display this 0 value. To solve this, you can just use the field__htmlValue function to override the default function execution:



Here we have this field called 'single_conference_delay' which signifies how long it will take before the conference starts. And it's important to specify if it starts immediately like 0 days. This code will display it.

Using the echo <<<

Have you ever had the case where you need to echo a lot of things in PHP, but using the echo function just took too long because of all the quotes and stuff. Well there is a way to to echo things in PHP that makes it a lot easier. It is called the "here document" syntax:



The END (any word actually works) on the first line acts a document terminator to tell when the text has stopped. So the the the last line can't have anything else on it except for END

For example:



See this link for more details.

Tuesday, March 17, 2009

View the contents of a related record inside the view record tab

Say you have an abstract which belongs to a conference. The abstract to conference is a many-to-many relationship stored in a table. When you view the abstract record, you may have set the conferenceID to be a valuelist so that it displays the conference name.

Instead of just displaying the conference name, you can include an expando box beside the name. And if the user clicks on it, then the details of the conference appears and you can hide it again very quickly by clicking on the collapse button. For example:



This is a snippet of the view record of an abstract. You can see the conference name it belongs to and the expando box to the left. When you click it:



All the contents of the conference appear right. Very cool! So how does this work. It's actually pretty easy.

Start off by adding the field__htmlValue code to the delegate class (in our class it would be the Abstracts delegate class)



In line 2, we define our javascript file which will do most of the work for us. We will add this file in a bit. In line 3, we attempt to get the conference record from this record we have. You'll need to add another function to do this because the abstract record only has a conferenceID. So you can do this:



This will grab the conference record to use. Now in our scripts.js file, we add this:



And that should do it!

The return value of df_get_record()

The df_get_record() function is a very useful function because it returns you the specific Xataface record given a set of parameters. For example:



This would get the course record with the primary key (course_id) of 1. When you don't give the function enough searching parameters and it could return a number of records with the parameters, then it returns only the first one.

Tuesday, March 10, 2009

Using the url attribute for an image

If you have an image field, and you have the url attribute for that field. Then you can access that field pretty easily to do some interesting things. Like for example, if in the event that there is no image we can set a default image using the same url attribute.

Say in your fields.ini of your delegate class you have:



The attribute url tells Xataface where in the application the images for this field are found. If you put your default image in this folder, then there are a number ways to make a default image appear. The idea is you don't want to have to hardcode the directory path into the code/template, but rather use that attribute in the fields.ini file (except for method 3).


  1. Method 1: Using the PHP function dirname()
    You can have an if statement which checks if there is an image, and if not then use the directory path of the folder containing your default image:


    if (!$record->display('image'))
    $default = dirname($record->display('image')).'/default.jpg';



  2. Method 2: Directly access the url attribute from the fields.ini file


    $fld = $record->_table->getField('image');
    $default = $fld['url'].'/default.jpg';


  3. Method 3: Move the image the default xataface image folder.
    Not really a method, but you can just place the default image in another folder and rely on Xataface's environment variables to help you. Say you want to display a default image in the event there is no image. You do this in the smarty template:


    {if $row->val('image') }
    <img src="{$row->display('image')}?max_height=100&max_width=100" />
    {else}
    <img src="{$ENV.DATAFACE_SITE_URL}/images/default_tire.jpg?max_height=100&max_width=100" />
    {/if}



Monday, March 2, 2009

How to display/hide fields in a xataface form

Sometimes you are faced with a situation where you want certain components of a form to appear/hide when a certain choice has been selected. You can do this very easily through xataface.

The first thing you need to decide is which element will be the determining factor. If necessary, you can use a field that is of transient type and will only exist in the form, but is never actually stored in the database. We will present an example of this now. In our example, our record can belong to either a course or a conference. Depending on which type it is, it should be associated with either a CourseID or a ConferenceID. If the record is of one type, then the other type's ID should not appear.

So to do this,



We first start by adding a field called CourseOrConference field in the fields.ini file. The user will be able to choose the record to be either a course or conference. Note the use of transient field here, no field exists in the database called CourseOfConference. It is simply be used for this particular situation.

Now once the that choice is selected the hideFields() javascript method is called which is in a separate javascript file.

The javascript file.

hideFields();

//description: used to display which fields to display upon the user choosing conference or course
function hideFields() {
var type = document.getElementById('CourseOrConference').value;
if (type.length == 0){ //if the user hasn't selected the abstract to be part of course or conference or actually reset the type
//clear both type ids, and hide them both
document.getElementById('AbstractConferenceID_form_row').style.display = 'none';
document.getElementById('AbstractConferenceID').value = "";
document.getElementById('AbstractCourseID_form_row').style.display = 'none'; //hide the course_id
document.getElementById('AbstractCourseID').value = "";
} else if (type == 'course'){ //if the user has chosen the abstract to be part of a course
//clear the conference id field, hide it, and display the course
document.getElementById('AbstractConferenceID_form_row').style.display = 'none';
document.getElementById('AbstractConferenceID').value = "";
document.getElementById('AbstractCourseID_form_row').style.display = ''; //makes it appear as it originally was

} else if (type == 'conference'){ //if the user has chosen the abstract to be part of a conference
//clear the course id field, hide it, and display the conference
document.getElementById('AbstractCourseID_form_row').style.display = 'none';
document.getElementById('AbstractCourseID').value = "";
document.getElementById('AbstractConferenceID_form_row').style.display = '';
}
}



We first call the hideFields() in the javascript when it is first loaded. You will see why in a second.


  1. First, the ConferenceOrConference form field is selected. If it is empty that means the user hasn't selected anything yet, and thus we should hide the AbstractID and ConferenceID fields. Because xataface uses tables to layout the forms, the proper way to hide them is to actually hide the entire row which contains the label too. We also need to set the values to "" so that if the user chooses to change type then the fields are reset to start again.

  2. If the type is a course, then we need to hide all the conference information

  3. If the type is a conference, then we need to hide all the conference information



And that's it basically. Note you have to make sure of the proper element ids to be hiding because that is dependent on the name of the field in the database.

How to svn checkout the xataface modules

Xataface by itself doesn't come with any modules to reduce the size of the download. But if you want to get some modules for your xataface, it is very simple!

You can checkout the repository for modules at:

http://weblite.ca/svn/dataface/modules/


There is a list of modules. Once you've decided to checkout a module, you can then do this through the command prompt using the 'svn checkout' command, or through the gui interface.

How to properly checkout xataface from svn command prompt

So to checkout from xataface from the command prompt, you can simply enter the command


svn checkout https://weblite.ca/svn/dataface/core/trunk


This will check everything that was in the trunk folder out and into a trunk folder.. However, if you want to say check it out into another folder you need to provide a parameter. So for example:

svn checkout https://weblite.ca/svn/dataface/core/trunk xataface


This will check everything out into the xataface folder (everything in the trunk folder).

Monday, February 16, 2009

How to dynamically change the onclick handler

More related to just web development in general, but sometimes you might need to change the onclick event handler of an element. This can be a little tricky, but I find the best way to do this is:


element.onclick = function() {this_is_my_function($param)}


The tricky part is that the value of the onclick is a reference to the function and not the function itself. So if you simply put:

element.onclick = this_is_my_function($param)


It would actually fail. You need to wrap this under another function, hence the original code where the function() calls the this_is_my_function().

Setting the access to the templates_c

The templates_c folder is location of where the smarty tag templates are compiled to. And these templates are used to display the Xataface application. So it's important that end-users are able to read from this folder so that they are use the application. To properly set this up, the templates_c folder should have the 755 permissions:

chmod 755 templates_c


This basically means that everyone has read and execute access. And also that the owner has write access to the file/folder.

You then need to explicitly set the permissions for the user 'apache' because end users will be under that username when viewing the application. To do this:

setfacl -m user:apache:rwx,mask:rwx templates_c


After that end-users should have no problem viewing the application!

Friday, February 6, 2009

How to change the label of the save button?

Recently ran into an interesting request on how to change the label of the save button on the edit form to something else. While I don't believe there is a direct way to do this in Xataface, you can utilize a little workaround with the feature of "internationalization" of Xataface to get this to work.

How you can do this is:

  1. Create a 'lang' folder in the delegate folder of your class you wish to change the edit form form

  2. Inside that folder, create an en.ini file.

  3. Then add this line:
    save_button_label="Submit"

    What this does is it overrides the label and causes it to say Submit.



The real function of this feature is to actually allow the display of that label to differ depending on the language chosen. In our case, we just override the original label for english (ie. en) and volia!

A nice little work around hey?