ibrow

ibrow blog

archive for the ‘Development’ category

Nifty Monthly Calendar Class

Wednesday, September 26th, 2007 by Rob

Recently I had to build a monthly calendar that could be outputted via a templating engine (notably Smarty). I had a brief look around the web, but couldn’t find anything that was light weight and could be used via a templating engine. So I decided to build my own.

I have created a demo for you to have a look at, which you can find here and you can also download a zip file of the source.

What I tried to do as much as possible with this class is to keep all the complex processing out of the template engine. As such I have created a class which collates an array of "Days". Each of these "Days" not only have information on the day, but also instruction to the template, eg "I am at the end of the week" etc, so a new week (eg row of table cells) can be started. No processing going on in the template, just a quick call along the lines of  "if start of week then start new row"

Play with, download and enjoy, and if I have time I’ll write up a tutorial!
 

Struggling on with Sortable lists

Friday, September 14th, 2007 by Rob

Yesterday I wrote about my struggle with sortable lists and how I can’t seem to get them to do what I want - especially in IE.

Well I’ve been hacking at it again this morning and whilst I still can’t quite get it right, at least it now works in IE. You can see version 2 here - feel free to view the source and pull apart as much as you like.

In my search I found a couple of excellent articles and tutorials, some of which I’ll share with you lot.

Bernardo de Pádua has written an excellent extension of jQuery’s Interface plugin which allows for the sorting of nested lists. You can read about it in his blog and see it in action here (his blog article is linking to the wrong place)

There is also quite a good article (if not a little old now) by Simon Willison about his thoughts on JavaScript libraries and I have to agree with his 6th point:

Go with the grain. If you take the time to learn it properly, JavaScript is a powerful and surprisingly elegant language. Good JavaScript code takes advantage of its dynamic, functional nature. Libraries that promise to take the pain out of JavaScript by writing the code for you probably aren’t as smart as they seem. Abstractions leak.

The problem is, when you’re running at full speed to keep up, it’s pretty hard to stop and appreciate the world around you, and in that respect 3rd party libraries (JavaScript or otherwise) will always be useful to get things done now.

jQuery and interface.js - drag and drop which works with overflows

Thursday, September 13th, 2007 by Rob

For a client today I had to create some functionality to take elements out of a list and place them into another list. Sounds pretty straight forward so I decided to build it using Ajax.

For the site I was working on I have been using the Scriptaculous JavaScript library which I’ve been quite happy with, even though their site may be a bit slow at times. Their Sortable functionality looked like it might do the job so I started to plug away in so test designs. However, there was a major problem. My lists were pretty long, and I wanted the ability to scroll. However, when I added an "overflow: scroll" attribute to the CSS, it all went a bit wrong. When I tried to drag an element out of a list to drop into another one, the scoll came into effect and I could not get it out of the list - instead the scroll bars became ever longer. Argh! I looked into it further and soon found that other people were having this problem:
http://wiki.script.aculo.us/scriptaculous/discuss/Sortable.create

I tried a number of fixes advised, but sadly to no avail. I also found Rico, which looked promising, especially this demo:
http://openrico.org/demos?demo=drag_and_drop_custom_draggable
but I didn’t really want to learn yet another library. So i turned to a library I’d been previously playing around with: jquery and it’s interface plugin.

In a relatively short amount of time I was able to get roughly what I wanted working well for Firefox and the overflow problem wasn’t a, er, problem!

Note: sadly IE doesn’t seem to work - but I’m not overly bothered about that at the moment as the client uses Firefox (as yes I know that’s bad practice but deadlines are looming, one day I’ll finish it off!)

 

The Howto

Seeming that I spent pretty much most of the morning tying to find something that did this I’m going to jot down how I did it in the hope that I can stop someone else pulling their hair out.

You can see a demo of the drag and drop here.

First thing is first, include the needed JavaScript files (I find that interface.js is a bit buggy with jquery 1.2 so I prefer to keep to 1.1.2

<script src="jquery-1.1.2.js" type="text/javascript"></script>
<script src="interface.js" type="text/javascript"></script>

Next I set up the styles, just to look nice and to scroll etc

<style type="text/css">
body {
    font-family:Verdana, Arial, Helvetica, sans-serif;
}
#origdiv, #saveddiv {
    float: left;
    margin: 0 10px 10px 10px;
}
select {
    font-size: 10px;
    border: 1px solid #000;
    width: 200px;
    height: 200px;
    overflow: auto;
}
.list1, list2 {
    font-size: 10px;
    padding: 5px 0;
    border-bottom: 1px dashed #ccc;
    cursor: pointer;
}
#origdiv select option, #saveddiv select option {
    display: block;
    padding: 5px 0;
    border-bottom: 1px dashed #999;
    z-index: 999999;
}
</style>

In the body I added the original list that I would be dragging things from. I chose to do it with <option>’s rather that <li>’s as I can easily extract the value from them. As you can see, each option has an ID which roughly matches its value - this is used later when removing the option from the list and putting it into the Saved List. Also, note that each option has been given a class of "list1", this will be used to determine if these elements are allowed to be dropped into the "saved list"

<div id="origdiv">
<h3>Original List</h3>
<select size="5">
<option class="list1" id="o1" value="1">Original List 1</option>
<option class="list1" id="o2" value="2">Original List 2</option>
<option class="list1" id="o3" value="3">Original List 3</option>
<option class="list1" id="o4" value="4">Original List 4</option>
<option class="list1" id="o5" value="5">Original List 5</option>
<option class="list1" id="o6" value="6">Original List 6</option>
<option class="list1" id="o7" value="7">Original List 7</option>
<option class="list1" id="o8" value="8">Original List 8</option>
<option class="list1" id="o9" value="9">Original List 9</option>
<option class="list1" id="o10" value="10">Original List 10</option>
<option class="list1" id="o11" value="11">Original List 11</option>
<option class="list1" id="o12" value="12">Original List 12</option>
<option class="list1" id="o13" value="13">Original List 13</option>
<option class="list1" id="o14" value="14">Original List 14</option>
<option class="list1" id="o15" value="15">Original List 15</option>
<option class="list1" id="o16" value="16">Original List 16</option>
<option class="list1" id="o17" value="17">Original List 17</option>
<option class="list1" id="o18" value="18">Original List 18</option>
<option class="list1" id="o19" value="19">Original List 19</option>
<option class="list1" id="o20" value="20">Original List 20</option>
</select>
</div>

And next was another select box where the dropped entries will end up

<div id="saveddiv">
<h3>Saved List</h3>
<select class="savedlist" id="savedlist" name="savedlist" size="5">
<!– list entries will end up here –>
</select>
</div>

Also, as select boxes only return what you have selected and not all items in the box, I have included this space to add hidden fields with the values of the dropped entries

<div id="hidden">
<p><small><em>When items are dragged onto the list, there values will display here.<br />
Normally these would be hidden fields</em></small></p></div>
</div>

Now for the JavaScript.

I created an array which will be looped through to get the values of the options. The reason I am looping through an array of values and not simply doing a for(i=0; i<20; i++) loop is because in the real version my options do not follow a numeric pattern so it is easier to create an array of values and loop through those than to manually create a draggable for each option. Thinking about it, I could loop through the actual options to get their values, but it’s late at night and I now can’t be bothered.

/*
 * Create an array with which to init the draggable element
 * Note, I could have looped though numbers 1-20 but I have done it
 * this way so if you are using items that don’t follow a numeric
 * pattern, it will still work
 */
o_array = new Array(
    ‘1′,’2′,’3′,’4′,’5′,’6′,’7′, ‘8′, ‘9′,’10′,’11′,’12′,’13′,’14′,’15′,’16′,’17′, ‘18′, ‘19′,’20′
);

Loop though the array to create a draggable element for each option

/*
 * Using the array, loop through creating the draggable elements
 */
for(i=0; i<o_array.length; i++) {
    var id = "#o"+o_array[i];
    $(id).Draggable(
        {
            zIndex:     1000,
            ghosting:    true,
            revert: true,
            opacity:     0.7
        }
    );
}

Init the dropable area. Note the "accept: ‘list1′. This makes it possible to drop the options each of which, if you recall, have been given the class "list1". When something is dropped onto this it will fire up the "add_to_saved()" function passing the element - or option - that has been dropped on it

/**
 * Create the droppable area
 **/
$(’#savedlist’).Droppable(
    {
        accept : ‘list1′,
        ondrop:    function (drag)
            {
                add_to_saved(drag);
            },
        fit: true
    }
);

Now all the initiation has been done, we can get on and write the actual function that removes the dragged option from the original list and adds it to the saved list, plus populating our form so we can submit it.

add_to_save() is called when an option is successfully dropped onto the Saved List select box and the element that is dropped onto it is passed - in our case an option element. From the value of the option element we can get its ID, which we then use to remove it from the scene. Once removed we now add it back, but this time into the Saved List, giving it a different class just to be sure we don’t confuse ourselves. So the list looks like it is all working, but stupidly when I began this I forgot that only the selected options of the select box are passed. To fix this I simply created a new hidden field with the value of the dropped option - for the demo it’s not hidden so you can see what’s going on.

/**
 * add_to_saved()
 * Adds items from the original list to the saved list
 **/
function add_to_saved(e) {
    // remove the old option from the original list
    $(’#o’+e.value).remove();
    o = ‘<option class="list2" id="o’+e.value+’" value="’+e.value+’">’+e.text+’</option>’;
    // append new option to saved list
    $(’#savedlist’).append(o);
    // as select lists only submit what is selected and we want to submit
    // the whole list, for each entry added, create a hidden field for it
    // this format will be saved in a PHP array within the $_REQUEST array
    // NOTE: for demo I these are plain text fields
    $(’#hidden’).append(’<input type="text" name="entry[]" value="’+e.value+’" size="2"/>’);
}

And that’s it. Hopefully this might help you out, or you can improve it. Still lots to do on it, not least being to get it working on IE, but that’s for another day.

Fake Method Overloading

Wednesday, July 4th, 2007 by Rob

Been struggling for the past hour or so with method overloading within objects, so I thought I’d write a little not on my blog to hopefully help others and to remind myself.

The premise for this is that I was writing a new database wrapper class to speed up the rather rubbish database module I have been using previously. My plan was to encapsulate all my methods in the wrapper (such as get_table_name() etc) in my class then all others fire off to the ADODB class by PHPlens. My plan was to do this with method overloading, such as:

public function __call($m, $a) {
    return $this->db->$m($a);   
    throw new Exception(’Tried to call unknown method ‘.get_class($this->db).’::’.$m);
}

However, PHP5 doesn’t seem to support that, which is irritating. After some search on the web I find out that PHP5 doesn’t support real overloading.

So after much effort and searching the web and docs I decide to use the call_user_func_array(&obj) technique.

Finished method below:

public function __call($m, $a) {
    // check the method being called exists
    if (method_exists($this->db, $m)) {
        return call_user_func_array(array(&$this->db, $m), $a);
    }
    else {
        throw new Exception(’Tried to call unknown method ‘.get_class($this->db).’::’.$m);
    }
}

Seems to work, so please feel free to use

ibrow.com


tel: 020 7183 2328

BarCamp Berlin 3