07 Oct

jQuery k3dCarousel plugin

I needed a “3D” carousel to rotate images. The currently available jQuery plugins for this purpose were either too large, too restricted (showing only 4 at a time is not good enough), or too old (not working in jQuery 1.4+).

So I wrote my own.


demo

In our CMS, WebME, this is available in the Image-Transition plugin. (If you’re interested in using WebME, you can either download it through SVN, or talk to us about our reseller deals.)

How the thing works, is that you add a list of images to an element like this:

<div id="k3dCarousel">
	<img src="images/concrawood.jpg" />
	<img src="images/fernheasty.jpg" />
	<img src="images/mcnallys.jpg" />
	<img src="images/northernstandard.jpg" />
	<img src="images/soccertours.jpg" />
	<img src="images/soundinsulation.jpg" />
	<img src="images/textaroom.jpg" />
	<img src="images/windhoist.jpg" />
</div>

Then link to the jQuery library and the jquery.k3dCarousel plugin:

<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.4.2/jquery.min.js"></script>
<script src="jquery.k3dCarousel.min.js"></script>

And then tell jQuery to run the plugin after all the images have loaded:

<script>
	$(window).load(function(){
		$('#k3dCarousel').k3dCarousel();
	});
</script>

If you want, you can vary the speed of the cycle by changing the sT (spin-time) variable, or the wT (wait time), which govern how long it takes for the images to move from point to point, and how long they pause once reaching there:

<script>
        $(window).load(function(){
                $('#k3dCarousel').k3dCarousel({
                        wT: 500,
                        sT: 100
                });
        });
</script>

Interested yet? Download it (tar.bz2, zip)

26 Sep

SaorFM progress – the Hidden Files plugin

In the last post, I mentioned that a jQuery plugin had been created.

At the time, it could only be used as a file or directory selector.

It can now also be used to upload, download, and delete files.

I’ve also enhanced the core engine so that it now has plugin support.

The first plugin is a Hidden Files plugin, which lets you hide files or directories depending on their names. The default pattern is to hide nodes with names that begin with a ‘.’ – this is the default for most systems out there.

I’ll explain how plugins work, in the hope that someone out there may be interested in creating one 😉

For this example, I’ll use the Hidden Files plugin, as it’s already created, and uses everything in the engine so far.

First off, you create a directory in the /plugins/ directory of the plugin. In this case, I created the directory /plugins/hidden-files/.

In that, the only essential file is config.php, which holds a configuration for the plugin:

<?php
$config=array(
  'triggers'=>array(
    'checkfilename'=>'HiddenFiles_checkFilename'
  )
);

When you tell SaorFM to install the plugin (using $SaorFM->installPlugin('hidden-files');), it will read through that array and add the details to its own configuration file, so it doesn’t have to open up multiple files every time it boots up.

As an example, here’s my test config before the plugin is installed:

<?php
$SaorFM_config='{"user_files_directory":"\/home\/kae\/websites\/saorfm\/trunk\/tests\/\/userfiles"}';

And here’s how it appears after the installation of the plugin:

<?php
$SaorFM_config='{"user_files_directory":"\/home\/kae\/websites\/saorfm\/trunk\/tests\/\/userfiles","plugins":["hidden-files"],"hiddenfiles":"#^\/?\\.#","triggers":{"checkfilename":["HiddenFiles_checkFilename"]}}';

There are three additions:

  • "plugins":["hidden-files"] – this is an array of installed plugins.
  • "triggers":{"checkfilename":["HiddenFiles_checkFilename"]} – the $config array above had a trigger mentioned – that’s converted into an object and added to the SaorFM config.
  • "hiddenfiles":"#^\/?\\.#" – this is to tell the hidden files plugin what pattern to apply to file names to decide whether they should be hidden or not.

The first two are obvious – the first is the name of the plugin, and the second is the name of a trigger named in the config array.

For the third, we need to run an installation script when Hidden Files is installed, so SaorFM checks the /plugins/hidden-files/ directory to see if a file exists named install.php:

<?php
if (!isset($this->_config->hiddenfiles)) {
  // the default pattern hides files that begin with .
  $this->_config->hiddenfiles='#^/?\.#';
}

That’s run by SaorFM when the plugin is installed. It adds a default hiddenfiles value to the config. This can be changed at any time afterwards.

Ok – so we have the config installed – now how does it work?

Let’s say we ask SaorFM to list the files in ‘/’: $SaorFM->listFiles('/');

Inside the listFiles method, there is a loop which adds filenames to an array. For each one of the filenames, we check it before adding to the array:

    foreach ($files as $f) {
      if ($f->isDot()) {
        continue;
      }
      if ($this->trigger('checkfilename', $f->getFilename())) {
        continue;
      }
      $arr[$f->getFilename()]=array(
        $f->getFilename(),
        $f->getSize(),
        $f->isDir()?1:0 // record as 1 or 0 to save http traffic
      );
    }

Notice the $this->trigger('checkfilename', $f->getFilename()) – if that returns anything other than false, then the file is not added to the list.

The trigger method cycles through any functions which have been named for that trigger, and calls each one in turn. If any return a result other than false, the method returns that result immediately:

  public function trigger($trigger, $vals) {
    if (!isset($this->_config->triggers->{$trigger})) {
      return false;
    }
    foreach ($this->_config->triggers->{$trigger} as $function) {
      $ret=$function($this, $vals);
      // if the trigger gives any response other than false, then return it
      if ($ret) {
        return $ret;
      }
    }
    return false;
  }

Note that we haven’t yet defined the function HiddenFiles_checkFilename.

Upon installation, we also load up the file /plugins/hidden-files/functions.php if it exists, and this file is loaded every time that SaorFM is instantiated after installation as well:

function HiddenFiles_checkFilename(&$saorfm, &$filename) {
  return preg_match($saorfm->get('hiddenfiles'), $filename);
}

This is a very very simple function – it could get a lot more complex in other plugins. For example, an Authentication plugin would be much more verbose.

I hope this is all very clear. It’s very very simple to add arbitrary triggers to SaorFM, so if you want to write a plugin and the trigger doesn’t exist, just tell me and I’ll put it in place.

After all this, let’s say you want to uninstall the plugin.

Within SaorFM, you just call $SaorFM->uninstallPlugin('hidden-files');.

This automatically removes the ‘hidden-files’ value from the plugins array (and removes that array if it’s empty), then removes any added filters as well.

Finally, it also checks to see if /plugins/hidden-files/uninstall.php exists and runs that if so:

<?php
unset($this->_config->hiddenfiles);

After this, the SaorFM config file is back to the exact state it was in before we installed the plugin. Clean.

If you’re interested in hacking on SaorFM, please download a copy from SVN here.

There are a number of things we need to create before it’s usable by the general public. An installer, for example, and some widgets for popular RTEs like CKeditor or TinyMCE. If you feel you’d like to create those, please contact me.

12 Sep

saorfm: first visible results

The first visible project using SaorFM is a jQuery file-selection widget:


demo

Here is the source of that page:

<html>
	<head>
	</head>
	<body>
		<p>Select a file</p>
		<input id="file-select" />

		<link rel="stylesheet" href="http://ajax.googleapis.com/ajax/libs/jqueryui/1.8/themes/base/jquery-ui.css" type="text/css" />
		<link rel="stylesheet" href="/saorfm/jquery-widgets/jquery.saorfm/jquery.saorfm.css" type="text/css" />

		<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.4/jquery.min.js"></script>
		<script src="http://ajax.googleapis.com/ajax/libs/jqueryui/1.8/jquery-ui.js"></script>
		<script src="/saorfm/jquery-widgets/jquery.saorfm/jquery.saorfm.js"></script>
		<script>
			$(function(){
				$('#file-select').saorfm({
					"rpc":"/saorfm/core/rpc.php"
				});
			});
		</script>
	</body>
</html>

In the above demo, we link in the jQuery and jQuery-UI scripts, and load up the widget’s script.

The only content elements are a <p> telling the user to choose a file, and a normal text <input> box which the user can use as a combobox.

The magic happens with this little bit of JavaScript:

$(function(){
	$('#file-select').saorfm({
		"rpc":"/saorfm/core/rpc.php"
	});
});

That tells jQuery to convert the #file-select input box into a saorfm widget. The only parameter in this demo is rpc, which tells the widget where the SaorFM server is to be found online.

To install this on your own server, all you need to do is download the SaorFM engine from Google Code, and add a config.php file to the core directory. Here’s mine:

<?php
$SaorFM_config='{"user_files_directory":"\/home\/verens\/domains\/demo.verens.com\/saorfm","language":"en","json_errors":false}';

In that, a JSON-encoded hash object contains the configuration. Change the user_files_directory parameter to your own files directory, and you are done with the configuration!

I’ll be adding this to my WebME project next week, after I’ve finished writing the tests (Selenium and PHPUnit).

27 Aug

keeping an admin session active

I had a call from a client who asked why, after logging into a CMS admin area and spending an hour or so writing a document, she was unable to submit it because it claimed she was not logged in.

The answer was that the session had expired.

On busy servers, one method of optimisation is to reduce the session-time. This makes it easier for the server to cope with a large number of visitors, but also has the undesired effect of logging people out if they take their time over anything.

One solution to this is to keep the admin session in a database table, tied to a cookie in the browser. Unfortunately, that means that every time the browser sends the cookie, it must be verified, whereas a session is usually trusted.

The workaround is to use some JavaScript to refresh the session every now and then.

I wrote a simple cyclical script which polled the server every minute to refresh the session.

Here it is, using jQuery to handle the AJAX:

function keep_session_alive(){
  setTimeout(keep_session_alive,60000);
  $.get('/ww.admin/keepalive.php');
}
setTimeout(keep_session_alive,60000);

And the server-side code is this:

<?php
session_start();

Very very simple trick. The polling could be enhanced, if you want, to alert the admin of anything interesting that’s happened on the server.

22 Aug

SaorFM

Last night, I spent four hours chatting with Conor MacAoidh.

We’re both the authors of CMSes, and both need file managers.

I’m the original creator of KFM, but recently, I’ve been getting annoyed at it. The project has grown too large to be easily managed, and it’s slow to start up because of the amount of database configuration involved.

We discussed this, and came up with a plan, which coincides with what I wanted to do for KFM2, but is probably much better.

We are going to reboot the whole thing – write a complete new file manager from scratch. It will only use code from the original KFM2 if the code is demonstrably better than any alternative we come up with.

The project will be properly documented, will have 100% test coverage, and will be completely free.

It will come in a number of separate parts, but only one, the core, will be absolutely needed.

The core of the engine is the bit which handles the actual file management. It will be designed to load in only two or three files for the most part, and as fast as possible.

Communication with the core will be done by either including the core as part of your own CMS, or by interacting with it via RPC.

The RPC will be very important – you send a command such as /rpc.php?action=move&from=/my-files/test1.jpg&to=/images/me.jpg, and results will be returned as JSON.

We decided on the name SaorFM. While this may be slightly confusing for non-Irish-speakers (“Saor”, pronounced half-way between “sair” and “seer”, means “Free”), we feel this is not very important. After all, Ubuntu is a household name, and that’s Bantu.

The main site will be SaorFM.org, the blog will be here, and downloads, issue tracker and SVN can be found here.

We’re still deciding on how to go about things, so there are no downloads yet. The decision to do this was made literally last night.

Having a co-developer on board from the absolute start will encourage me to get my arse in gear on this – if Conor does something cool, I have to beat that. And vice-versa, hopefully!

I’m starting the project off at the moment by working on a description of what it’s all about, and then will start writing some starter tests. This will use “test-driven development”, so every single line of code in this project will be repeatedly tested throughout the development.

We’re planning a load of features, such as desktop-/system- integration for Linux, Mac and Windows, and having totally external UI systems. We even considered going mad and creating a bump-top-like UI for it.

It’s taken me almost a year since planning KFM2 and getting to this.

Part of the reason for the delay is that this is so far removed from the current KFM, that I really didn’t know how to bring KFM1 up to the specification I wanted to reach.

Starting from absolute scratch with a brand new name is the right thing to do, I think.

16 Jun

update: CMS design with jQuery and PHP

EDIT: The CMS that the book is about is available to download here.

I got an “urgent” email recently from my Packt coordinator – she told me that if I kept writing my book at the rate I was writing, then it would end up being about 500 pages.

Thing is, though – it would be tricky to reduce the chapters I’ve already done, as a half explanation is as good as no explanation at all.

So, I looked over the planned chapters again, and saw that the final three could probably be dropped without affecting the core content of the book – they were just more example plugins showing how to integrate various things with the CMS.

The book itself is on how to build a CMS in PHP, that uses jQuery to make administration easier. That has been accomplished already in the existing chapters (1-7).

I suggested to Packt that I would drop the final three chapters and rework the earlier chapters so the book was more easily read (a 40-page chapter is /not/ easy to read).

Got an email back from them yesterday saying that the plan sounded good.

So the current plan is:

  • Finish chapter 8, which is on panels and widgets.
  • Write chapter 9, which will build a plugin demonstrating panels and widgets.
  • Try to break the earlier chapters apart so that there are more chapters, with less pages per chapter.
  • profit

I think I’ll be finished the current chapters within three weeks, then take a week or two to rework the earlier chapters, then another month for rewrites, and finally the book will be published 2/3 weeks later.

So, the book may be out within two months.

After this, I’m taking a break from modern technology to write about baroque technology – I’ll be writing a book on how to build a cheap clavichord.

27 May

happy birthday KFM

KFM is 4 years old today:

http://verens.com/2006/05/27/file-manager-for-fckeditor-day-one/

demos of older versions no longer available, but it’s interesting to know that it’s lasted four years!

of particular interest in my own case, is that there has been no major functionality change in the last two years or so. KFM today is basically the same as KFM two years ago; just faster, more secure, and better coded.

07 May

closing a filament-group menu on mouseout

The filament group menu plugin is one of the better ones out there.

But it has a few flaws. One of the major ones is that they’re not developing it anymore, leaving that to the jQuery UI team. But, development on that is really painfully slow… I don’t expect to see a working menu for months. Even the demos linking from the jQuery UI Menu page are hardly inspiring – they’ve got practically no functionality at all. Hardly useful.

For that reason, I’m okay with taking the current fgmenu code and extending it.

Here’s a simple fix, which has been asked for on their blog. I can’t comment on it because comments are closed.

To close menus onmouseout, all you need to do is to add a mouseout to all menu items, and if it’s triggered, then a second or so later, close all menus.

Obviously there’s a little more to it than just that. Read the code if you want the full details.

Just add this bit to your fg.menu.js file:

$('.fg-menu,.fg-menu-top-level')
  .live('mouseover',function(){
    this.mouse_is_over=true;
    clearTimeout(window.fgmenu_mouseout_timer);
  })
  .live('mouseout',function(){
    this.mouse_is_over=false;
    window.fgmenu_mouseout_timer=setTimeout(function(){
      var o=0;
      $('.fg-menu,.fg-menu-top-level').each(function(){
        if (this.mouse_is_over) o++;
      });
      if(!o){
        $.each(allUIMenus, function(i){
          if (allUIMenus[i].menuOpen) { allUIMenus[i].kill(); };
        });
      }
    },2000);
  });
03 May

what I'm up to

As usual, I’m behind on stuff.

I just submitted chapter 3 of my upcoming book “CMS Design with PHP and jQuery”, and chapter 4 was due to be complete and sent two days ago.

My clavichord project stalled when the cumulative number of mistakes made it incredibly unlikely I’ll complete it in a usable fashion.

In work, I’m behind on a pretty large online-store project, but in that case I’m okay with it – I wasn’t slacking; things are just very busy at the moment.

My piano playing has also stalled – I’ve been trying to learn The Heart Asks Its Pleasure First for the last month. I’m stuck on the final page, where the left hand is all over the place and the right has an intricate tune to play. Its all in my head, but I just can’t play it smoothly. Thinking of putting that on the back-burner and going onto Bach’s 2-part inventions instead.

upcoming

Packt have asked me to review Expert PHP5 Tools. Looking forward to it. It’s got some stuff in it which I’ve read about but never tried. Including: UML design of applications, incorporating tests into subversion submissions, and automated documentation of source (among other things).

My piano teacher found an examiner who will be testing in Monaghan next month, so I’ll finally be able to get grade 2 out of the way. I’ve been practicing grade 2 and 3 tunes for months. Playing 6 tunes every day before I do anything else has been reducing th amount of time I have for the rest of my practice, so I’ll be glad to get this one passed as well.

I’m trying to push myself to get the current book finished as soon as possible. This is difficult as writing a CMS is a much more complex job than writing a cookbook of techniques. The chapter I just finished had 40 pages in it. By the 40th page of the previous book I was already into chapter 3. Chapter 2 wasn’t much smaller either!

When this book is finished, I’ll be starting a new one, on building a clavichord as cheaply as possible. Because I failed with the current one, but learned quite a lot from it, I feel I’ll get it right this time, and would like to document it as I go. There’s a lot of math involved in building a clavichord, and I think I may even get a good programming application out of it!

After that, I’m thinking of starting up contact juggling again, and completing the book, this time with videos.

When I get the time, I’d also like to get back into building robots. I think the gardening robot is a bit beyond me at the moment (involves some very complex AI), but I thought I’d try build a digger bot. You tell it what you want dug, where to put the debris, etc., and it gets to work.