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: