Archive for the 'Development' Category

Age From Birthday Calculator

Tuesday, June 24th, 2008

Figured this might be handy to some folks… Just enter in a birthdate (or just any date for that matter, doesn’t necessarily have to be a birthday), and it will give you the number of years that have passed since then! Why use your head when we have computers!?

Month:

Day:

Year:
(YYYY)

UNIMPORTANT NOTE: This script uses the average number of days in a year as part of its calculation. If I hear about that causing any problems I’ll look into another way of doing it, but I think it’s the most reasonable, far more so than using a whole number like 365.

The JavaScript:

function getAgeFromBday() {
  var month = document.getElementById('bdc-month').value;
  var day   = document.getElementById('bdc-day').value;
  var year  = document.getElementById('bdc-year').value;
  var bdate = new Date(year, month, day);

  if (bdate.getDate() != day || bdate.getMonth() != month || bdate.getFullYear() != year) {
    alert('That date appears to be invalid!');
    return false;
  }

  var today = new Date();
  today.setHours(0);
  today.setMinutes(0);
  today.setSeconds(0);

  if (bdate > today) {
    alert('Provided date must fall before today\'s date!');
    return false;
  }

  alert(Math.floor((today - bdate) / 31556952000));
}

The markup:

<p>
  <strong>Month:</strong><br />
  <select name="bdc-month" id="bdc-month">
    <option value="0">January</option>
    <option value="1">February</option>
    <option value="2">March</option>
    <option value="3">April</option>
    <option value="4">May</option>
    <option value="5">June</option>
    <option value="6">July</option>
    <option value="7">August</option>
    <option value="8">September</option>
    <option value="9">October</option>
    <option value="10">November</option>
    <option value="11">December</option>
  </select>
</p>
<p>
  <strong>Day:</strong><br />
  <input name="bdc-day" id="bdc-day" style="width: 15px;" type="text" />
</p>
<p>
  <strong>Year:</strong><br />
  <input name="bdc-year" id="bdc-year" style="width: 30px;" type="text" /> (YYYY)
</p>
<p>
  <button type="submit" onclick="getAgeFromBday()"><strong>DO IT</strong></button>
</p>

PHP Function - Extended Entity Conversion

Friday, March 2nd, 2007

This function serves as an extended version of htmlentities() and htmlspecialchars(). It converts all characters from ASCII 126 to ASCII 255 into their respective HTML entity codes.

function char_entities($data) {
	for ($i = 126; $i < = 255; $i++) {
		if ($i != 160) {
			$badchars[$i]  = chr($i);
			$goodchars[$i] = "&#$i;";
		}
	}

	// Normalize quotes and em dashes (e.g. - MS Word crap)
	$goodchars[145] = '\\'';
	$goodchars[146] = '\\'';
	$goodchars[147] = '"';
	$goodchars[148] = '"';
	$goodchars[151] = '-';
	// We don't want to convert spaces!
	unset($badchars[160]);
	unset($goodchars[160]);

	return str_replace($badchars, $goodchars, $data);
}

As a side note, it seems that WordPress throws a “503 Service Temporarily Unavailable” error when submitting posts that contain the following string (possibly any use of chr()):

chr($i);

I had to escape it in order to get it to work:

chr&#40;$i&#41;

Broken WPG2 Embedded Slideshow and/or CSS

Monday, November 13th, 2006

I was changing something in the header of the template for this site and realized that there’s something in there that might be worth sharing. I’m using a Wordpress Gallery2 Plugin called WPG2, and have Gallery2 embedded into Wordpress using a modification of the Matrix theme. I don’t know if this is a common problem, but the slideshow feature was not functioning properly in embedded mode. It looks like in my case I had script and style issues as well, where the CSS/JS for the gallery would not load. No amount of template hacking on the Gallery2 end seemed to do any good. Here’s a solution that I think is effective and rather elegant. It fixed both issues for me:

  1. In wp-gallery2.php (part of WPG2), add the following line right below the commented header:
    define('WPGALLERY2', true);
  2. Open up the header file for your Wordpress theme. Somewhere between your <head> tags, add the following:
    <?php if (defined('WPGALLERY2')) { ?>
    <link rel="stylesheet" href="/path/to/gallery/theme.css" type="text/css" media="screen" />
    <script type="text/javascript" src="/path/to/gallery/modules/search/SearchBlock.js"></script>
    <script type="text/javascript">
        //<![CDATA[
        var agent = navigator.userAgent.toLowerCase();
        var appver = parseInt(navigator.appVersion);
        var bCanBlend = (agent.indexOf('msie') != -1) && (agent.indexOf('opera') == -1) &&
                        (appver >= 4) && (agent.indexOf('msie 4') == -1) &&
                        (agent.indexOf('msie 5.0') == -1);
        var filterNames = new Array(16), filters = new Array(16);
        filterNames[0] = '{g->text text="Blend" forJavascript="1"}';
        filters[0] = 'progid:DXImageTransform.Microsoft.Fade(duration=1)';
        filterNames[1] = '{g->text text="Blinds" forJavascript="1"}';
        filters[1] = 'progid:DXImageTransform.Microsoft.Blinds(duration=1,bands=20)';
        filterNames[2] = '{g->text text="Checkerboard" forJavascript="1"}';
        filters[2] = 'progid:DXImageTransform.Microsoft.Checkerboard(duration=1,squaresX=20,squaresY=20)';
        filterNames[3] = '{g->text text="Diagonal" forJavascript="1"}';
        filters[3] = 'progid:DXImageTransform.Microsoft.Strips(duration=1,motion=rightdown)';
        filterNames[4] = '{g->text text="Doors" forJavascript="1"}';
        filters[4] = 'progid:DXImageTransform.Microsoft.Barn(duration=1,orientation=vertical)';
        filterNames[5] = '{g->text text="Gradient" forJavascript="1"}';
        filters[5] = 'progid:DXImageTransform.Microsoft.GradientWipe(duration=1)';
        filterNames[6] = '{g->text text="Iris" forJavascript="1"}';
        filters[6] = 'progid:DXImageTransform.Microsoft.Iris(duration=1,motion=out)';
        filterNames[7] = '{g->text text="Pinwheel" forJavascript="1"}';
        filters[7] = 'progid:DXImageTransform.Microsoft.Wheel(duration=1,spokes=12)';
        filterNames[8] = '{g->text text="Pixelate" forJavascript="1"}';
        filters[8] = 'progid:DXImageTransform.Microsoft.Pixelate(duration=1,maxSquare=10)';
        filterNames[9] = '{g->text text="Radial" forJavascript="1"}';
        filters[9] = 'progid:DXImageTransform.Microsoft.RadialWipe(duration=1,wipeStyle=clock)';
        filterNames[10] = '{g->text text="Rain" forJavascript="1"}';
        filters[10] = 'progid:DXImageTransform.Microsoft.RandomBars(duration=1,orientation=vertical)';
        filterNames[11] = '{g->text text="Slide" forJavascript="1"}';
        filters[11] = 'progid:DXImageTransform.Microsoft.Slide(duration=1,slideStyle=push)';
        filterNames[12] = '{g->text text="Snow" forJavascript="1"}';
        filters[12] = 'progid:DXImageTransform.Microsoft.RandomDissolve(duration=1,orientation=vertical)';
        filterNames[13] = '{g->text text="Spiral" forJavascript="1"}';
        filters[13] = 'progid:DXImageTransform.Microsoft.Spiral(duration=1,gridSizeX=40,gridSizeY=40)';
        filterNames[14] = '{g->text text="Stretch" forJavascript="1"}';
        filters[14] = 'progid:DXImageTransform.Microsoft.Stretch(duration=1,stretchStyle=push)';
        filterNames[15] = '{g->text text="RANDOM" forJavascript="1"}';
        filters[15] = 'RANDOM';
        // ]]>
    </script>
    <?php } ?>

That’s it! If you’re not having issues with the CSS for your embedded gallery, just leave out the <link> tag. What this is doing is defining a constant (WPGALLERY2) as soon as the WPG2 script begins. If you need to take any gallery-specific actions later on in your WP template, you just need to check whether the constant is defined (i.e. - whether the embedded gallery is active) using the if statement:

<?php if (defined('WPGALLERY2')) { ?>

Put any gallery code/CSS in there, and then close the if statement:

<?php } ?>

IE and scrollHeight

Monday, July 24th, 2006

I ran into trouble while trying to use JavaScript to set the pixel height of an element to the height of the entire page, including everything outside the viewport. Here’s an example scenario:

A block element on the page:

<div id="some-element"></div>

I want this element to stretch on the fly to the width and height of the entire page. The width is easy, just set the width to 100%:

someElement = document.getElementById('some-element');
someElement.style.position = 'absolute';
someElement.style.top      = '0px';
someElement.style.left     = '0px';
someElement.style.margin   = '0px';
someElement.style.padding  = '0px';
someElement.style.width    = ‘100%’;

The height, on the other hand, turned into a mess. At first I was just setting the height in the same way. Unfortunately, that only covers the currently viewable area. So, if I scroll the page, the effect is broken. I left it that way for a while, figuring it wasn’t a big deal right now.

The issue came up again today, and through a tip from Matt, I started fiddling with scrollHeight and offsetHeight for both the body tag and the html tag. It wasn’t working in Internet Explorer. It was giving the wrong values for both properties. I think it was using the value visible within the viewport. I wrote some debugging alerts:

alert('bodyscroll=' + document.getElementsByTagName('body')[0].scrollHeight);
alert('htmlscroll=' + document.getElementsByTagName('html')[0].scrollHeight);
alert('bodyoffset=' + document.getElementsByTagName('body')[0].offsetHeight);
alert('htmloffset=' + document.getElementsByTagName('html')[0].offsetHeight);

Oddly, IE was returning inconsistent values when the page is scrolled. When the property was accessed while the page was scrolled to the top, the scrollHeight for the body returned 654 pixels, which is wrong. If the page was scrolled down before the property was accessed, the scrollHeight for the body element returned 1134px, which is correct. So we’re getting somewhere. All of the other properties return incorrect values, but at least one of them seems to be halfway working.

The solution came by accident. Later on in the script, I was accessing the body element’s scrollHeight again. It was consistently returning the correct value. So I tried the debugging alerts again, this time with each one doubled:

alert('bodyscroll=' + document.getElementsByTagName('body')[0].scrollHeight);
alert('bodyscroll2=' + document.getElementsByTagName('body')[0].scrollHeight);

alert('htmlscroll=' + document.getElementsByTagName('html')[0].scrollHeight);
alert('htmlscroll2=' + document.getElementsByTagName('html')[0].scrollHeight);

alert('bodyoffset=' + document.getElementsByTagName('body')[0].offsetHeight);
alert('bodyoffset2=' + document.getElementsByTagName('body')[0].offsetHeight);

alert('htmloffset=' + document.getElementsByTagName('html')[0].offsetHeight);
alert('htmloffset2=' + document.getElementsByTagName('html')[0].offsetHeight);

While all of the other properties were still incorrect, the second body scrollHeight alert was consistently returning the correct value. So, here is the solution that worked:

document.getElementsByTagName('body')[0].scrollHeight;
someElement.style.height = document.getElementsByTagName('body')[0].scrollHeight + 'px';

The first call to the scrollHeight property is on it’s own line, and not even used.

Maybe there’s a better way to fix this, and maybe I’m not the first person to come up with this “hack.” But that would be cool if I have found an IE bug and workaround on my own! (Even if it was by accident)

Google Bombs Away!

Wednesday, June 28th, 2006

UPDATE: Google pulled the plug on this type of thing, so I guess I might as well get rid of the links I’ve got.

Creating a “Google bomb” is an attempt by webmasters to influence the rankings of certain webpages using common link text. You may or may not have known the official term for this concept, but you may have seen or at least heard of the one outlined below. It’s my favorite, and here are the steps for seeing it in action:

  1. Go to http://www.google.com/.
  2. In the search box, type miserable failure.
  3. Click the “I’m Feeling Lucky” button.

Pretty neat, eh? The reason this happens is because when ranking websites for indexing, Google looks at link text as well as page content. You won’t find the words “miserable” or “failure” on that page. What Google figures is that when people link things, they will use descriptive text for the link. As an example, I could say I’ve found a site with cool favicon (the little icon that appears to left of the current URL in your Firefox address bar). You won’t see the words “cool” or “favicon” anywhere on there, in fact I think the site is down right now. But it has a cool favicon, and it’s one way to describe the site. So I put it in the link text, and Google uses it (among other things) to index the site in its database.

Since Bush Jr. is a miserable failure (as a president), it makes sense to use that as the text for a link describing the page for his biography on whitehouse.gov.

If you would like to add this “Google Bomb” to your site, copy and paste the following HTML onto your site:

<a href="http://www.whitehouse.gov/president/gwbbio.html" title="George W. Bush is a Miserable Failure">Miserable Failure</a>

If you look under the “politics” section of the sidebar, you’ll see more common ones mixed with some other interesting links. Please don’t overdo it, because you don’t want it to come across as SPAM. It’s not SPAM, it’s legitimate, because it describes the subject matter to which the text is linking.

On a related subject, AOL Search is the worst search engine ever. Their results are powered by Google, but they selectively censor the results. They have completely filtered out the most relevant result for the #1 spot, and moved a different Google Bomb that they apparently deemed “okay,” to number one. That angers me.

Goodbye BBClone, Hello Google Analytics

Wednesday, May 24th, 2006

Yay! I finally received my Google Analytics invite today! So now I’ll be trying that for a while… From what I’ve heard, I think it will do just fine for me. Some people complain about the 24-hour wait before the stats are updated, but that doesn’t bother me. If I am that desperate to see what’s going on so quickly, I’ll check the Apache logs.

At first I added the Analytics code manually. Then I realized that it would be nice to track outbound links. Then I thought about how much of a pain it would be to go through and add the code to all of the links in this whole blog. Then I thought about writing a WordPress plugin to do it automatically. Then I remembered hearing about other Analytics plugins for WordPress. Then I decided to quit beginning my thoughts with “then I.” So I did some research on all the Analytics plugins I could find. And the winner of the “Best Google Analytics Plugin for WordPress” award iiiis:

Google Analyticator

I like the attention to detail, and the code is very well-written. I did make a few modifications, but they are mostly cosmetic. I’m going to submit those to the author and see if they will be included in a later version. If that doesn’t happen, I’ll just post the changes on here.

Using BBClone with WordPress

Tuesday, February 7th, 2006

BBClone is great website statistics application. I ran into a little trouble integrating it with WordPress, so maybe this guide will help you fix the same problems I was having.

Symptoms:

  • It’s not working at all!
  • The page names are pretty much useless
  • In the global stats page, all the links point the blog root

First of all, here is how you 1) get it working, and 2) fix the page names to something more useful. There were other suggestions on the WordPress support forums, but I find this way to be the best. This is mainly because it it makes it more similar to my Apache logs (it uses the full path/file as the page name).

You’ll have to make changes to a lot of your theme’s files, so you might want to back up your theme’s directory before getting started. This guide is catered towards the Kubrick theme (and modifications of it that stick to its basic framework).

Open up the following files from your theme’s directory: 404.php, archive.php, archives.php, attachment.php, index.php, links.php, page.php, search.php, and single.php. I guess that 404.php would be optional, but I personally am curious about people landing on non-existent pages.

Near the top of each of these files, you should notice the following code:

<?php get_header(); ?>

Replace that line, and only that line, with the following code:

<?php
define('_BBC_PAGE_NAME', $_SERVER['REQUEST_URI']);
define('_BBCLONE_DIR', '/path/to/bbclone/');
define('COUNTER', _BBCLONE_DIR . 'mark_page.php');
if (is_readable(COUNTER)) include_once(COUNTER);

get_header();
?>

Don’t forget to change “/path/tp/bbclone/” to the correct value! If you need help with doing that, leave a comment. If you see something like this at the top of any of the files…

<?php
/*
Template Name: [NAME]
*/
?>

…then leave that part of the code the way it is. Only change the part mentioned above.

For advanced users, if you have other files that contain the get_header() function, make the modification to them as well. If you add more template pages in the future, don’t forget to include the BBClone code.

By default, BBClone truncates page names at about 57 characters (and adds an ellipses). I thought that was too small a number since I’m using the full paths as the page name. Here is how you change it to around 150 characters:

Navigate to the BBClone directory, and open the file named log_processor.php. You should make a backup of this file before you continue. Around line 116 of log_processor.php, you should see the following code:

  $over_60 = ((defined("_BBC_MBSTRING") ? mb_strlen($long_page) : strlen($long_page)) > 60) ? 1 : 0;
  $connect['page'] = $over_60 ? "...".(defined("_BBC_MBSTRING") ? mb_substr($long_page, -57) :
                     substr($long_page, -57)) : $long_page;

Replace that code, and only that code, with the following:

  $over_150 = ((defined("_BBC_MBSTRING") ? mb_strlen($long_page) : strlen($long_page)) > 150) ? 1 : 0;
  $connect['page'] = $over_150 ? "...".(defined("_BBC_MBSTRING") ? mb_substr($long_page, -147) :
                     substr($long_page, -147)) : $long_page;

That takes care of everything except for the problem with the global stats. I have a workaround for that, but I am not going to post it yet, because it is not fully tested. What I’ve done may have been a very bad idea, so it would definitely not be a good idea to share it on here until I can guarantee that it’s safe. If you are curious about the workaround, leave a comment and I’ll send it to you in an email. You don’t need to include your e-mail address in the comment, just make sure you include it in the E-mail box.

Please post any suggestions you may have to improve or replace this integration method.

Note: If you are using WPG2, there are a few extra steps involved in getting the stats displaying in your gallery. I’m not going to post them unless someone leaves a request in a comment. That will remind me to do it. UPDATE: This was posted before I started using Google Analytics, and before I upgraded WordPress to the latest version. I can still do what I can to help, but I may not remember details.

Political Websites from a Development Perspective

Friday, January 27th, 2006

When I surf the web, I’m always looking through the eyes of a web developer. This has something to do with the fact that I develop websites. Not everyone knows exactly what he or she is doing when it comes to this stuff; when it comes to things such as government sites, however, the development team certainly should! Somewhat recently, I’ve discovered an interesting and humorous trend. At least I think it’s interesting and humorous.

First, let’s start the demonstration by taking a look at the official websites of two of the most prominent, opposing political parties in the U.S. If you browse with Firefox, consider opening them in new tabs so that you can easily come back here and read on.

  1. Democratic Party (or view a cached copy from 1.27.2006)
  2. GOP (or view a cached copy from 1.27.2006)

First, you might notice how clean the Democrat’s site is versus the GOP’s. We still have not scratched the surface of the real differences.

Accessibility

Any design should keep accessibility in mind. Especially a government site. There is actually a law in place about this:

From the Wikipedia article on the Section 508 Amendment to the Rehabilitation Act of 1973:

Section 508 requires that electronic and information technology developed, procured, used, or maintained by all agencies and departments of the Federal Government be accessible both to Federal employees with disabilities and to members of the public with disabilites, and that these two groups have equal use of such technologies as federal employees and members of the public that do not have disabilities.

Most experienced web developers today use (X)HTML for content (what you read), and CSS for presentation (graphics and design). The idea is to separate the two, and experienced designers consider it a web standard. The practice has numerous, important benefits.

To put it simply, democrats.org adheres to these standards, and gop.com does not.

If your browser has the functionality of disabling stylesheets on a page, try it with the websites of both parties. If it doesn’t, I have set up mirrors so that you can see the effect. Again, you’ll want to open these in tabs, otherwise you can use your back button.

  1. Democrats.org unstyled
  2. GOP.com unstyled

People that are blind need to use screen readers to surf the web. Adhering to accessibilty standards is all about making it as easy as possible for provisions such as a screen reader to effectively cater to those with disabilities. It’s an important thing to keep in mind when designing a site, and that’s why the law is in place. Can you see where the Democratic site is far superior in this respect? Moving on…

There are resources on the web that can test a website to see if it holds up to accessibility standards. I tested both sites for Section 508 as well as WAI (Web Accessibility Initiative from the W3C; A more comprehensive effort than that of the U.S. government) compliance. It’s not easy to adhere completely to these standards, but we try as best we can.

First, let’s look at Section 508. Where the tested aspects applied, Democrats.org failed in five places, and passed in two. GOP.com failed in six places, and passed in one.

For WAI, Democrats.org failed in seven places, and passed in seven. GOP.com fails in nine places, and passes in six. It should also be noted that for many of the aspects tested, the number of errors for GOP.com is very lengthy.

Design

Let’s not stop at accessibility. As important as it is, there’s more to a website than that. There are right ways and wrong ways to put together a site, regardless of whether or not it appears to display properly.

There are validators out there to test for design quality as well. The most commonly used validators for (X)HTML and CSS are provided by the W3C.

At the time of this writing, Democrats.org produces 17 errors, and GOP.com produces a whopping 143 errors! That’s a lot of errors, and this is not including any warnings.

As far as CSS, one of those 17 XHTML errors on Democrats.org causes the CSS parser to abort. Even though the error doesn’t cause the page to display improperly, they should still fix that. Compliments to them, though, for designing in XHTML (”the next generation of HTML”). It is considerably more of a challenge to write valid XHTML than it is to write valid HTML, in which GOP.com is coded.

When forced to validate, the CSS on Democrats.org produces nine errors. GOP.com’s produces twenty. The W3C CSS parser also produces “warnings,” but those generally serve as reminders to be sure that the designer has not overlooked something; for the most part, and in this case, they should be ignored.

In conclusion, the Democratic Party should be applauded for the attention to detail paid in the making of their site. The design team certainly knows what they are doing. The Republican Party, on the other hand, needs to get with the program, and in more ways than one.

You may also want to try comparing College Democrats with College Republicans. Or, try some unofficial sites: Progressive Democrats of America and Vote Republican. As a side note, John Kerry’s 2004 campaign site was significantly better than Bush Jr.’s.

This trend is no joke; Democratic websites are better than those of Republicans.

Is Gallery2 Breaking Your Layout?

Tuesday, January 24th, 2006

Thanks to the team at WPG2 (Wordpress Gallery2), it is now relatively easy for us to fully integrate Gallery2 into WordPress. I like to use the default Matrix theme (and this tutorial is designed for it), but there is a feature of this theme that can create problems with a fixed-width layout. This can potentially affect any integrated setup, not just WordPress. By default, if you go to single-image view, it gives the user the option of displaying the image at different sizes. You can change the default 640×480 initial size, but that’s not the main issue of this tutorial. Just in case you aren’t sure how to do that, though, these steps are for you:

  1. Login.
  2. Go to Edit Album -> Album.
  3. In that area, you should see a section called “Resized Images.” Change the first target width row to the maximum width that will fit in your layout. Make sure that the row is “Active.” Also be sure that all of the other sizes are blank.
  4. In the “Recreate thumbnails and resizes” section, select “Recreate resized images.”
  5. Save the changes.

My understanding is that you’ll have to repeat this process for all sub-albums. As far as I know Gallery2 has no provision for applying the changes to all albums below the parent album. So, click on each album to open it, and then repeat the process from step 2. UPDATE: It looks like that feature has been added since this post was first written.

Even after this change, another problem persists. This brings us to the main point of this tutorial. When viewing a single image, a user has the option of viewing the image full-size. The problem is that the full-sized image is displayed inline with the layout. So, if the width of the image is larger than the width of your layout, the image will extend beyond the intended bounds of your layout.

I checked the Gallery forums to see if there were any solutions to this problem. There weren’t, so I started a new thread. Here is the first reply:

mindless writes: siriux theme shows the resize and a link to download the full size. PGtheme (documentation/user contributions) has an option for showing full size in a separate window. you can learn from these examples and modify matrix to behave however you like :)

This is one way the solution can be implemented:

Navigate to the directory of your Gallery2 theme. Go to the templates directory of your theme (in my case /gallery/ themes/ matrix/ templates/), and create a new subdirectory in there called local. This ensures that we don’t overwrite the original template files. Gallery will use files in this directory before it looks in the main templates directory. Anyway, copy the photo.tpl file from the main templates directory into your new local directory.

In the new copy of photo.tpl (in the local directory), delete line 38:
{g->block type="core.PhotoSizes" class="giInfo"}

Replace it with the following code (taken from the Siriux theme):

                <a href="{g->url arg1="view=core:DownloadItem" arg2="itemId=`$theme.item.id`"}">
                  {if $theme.sourceImage.mimeType != $theme.item.mimeType}
                    {g->text text="Download %s in original format" arg1=$theme.sourceImage.itemTypeName.1}
                  {else}
                    {g->text text="Download %s" arg1=$theme.sourceImage.itemTypeName.1}
                  {/if}
                  {if !empty($theme.sourceImage.width)}
                    {g->text text="(%dx%d)" arg1=$theme.sourceImage.width arg2=$theme.sourceImage.height}
                  {/if}
                </a>

Or, if you want the image to open in a new window (compliant with XHTML 1.0 Strict), you can use this code:

                <a href="{g->url arg1="view=core:DownloadItem" arg2="itemId=`$theme.item.id`"}" onclick="window.open(this.href); return false;">
                  {if $theme.sourceImage.mimeType != $theme.item.mimeType}
                    {g->text text="Download %s in original format" arg1=$theme.sourceImage.itemTypeName.1}
                  {else}
                    {g->text text="Download %s" arg1=$theme.sourceImage.itemTypeName.1}
                  {/if}
                  {if !empty($theme.sourceImage.width)}
                    {g->text text="(%dx%d)" arg1=$theme.sourceImage.width arg2=$theme.sourceImage.height}
                  {/if}
                </a>

If you copy and paste that code as it is, the proper indenting should be preserved. That’s why the spaces are there.

I hope this helps someone. As always, if it does, it would be great to hear from you. If it doesn’t, it would also be great to hear from you so we can work out why it’s not working.

Things I Don’t Like About Borland C++ Builder 6

Thursday, January 19th, 2006
  1. Default tab width of 8 spaces
  2. No “bulk indent” functionality (that I could find)
  3. Random window pops up every time it checks for updates (or something… This can be disabled)
  4. Errors come up in realtime after typing valid code too fast. I type void somefunction(), and if I don’t wait a second before closing the parenthesis, I get this error: [C++ Error] filename.cpp(1): Unable to invoke Code Parameters due to errors in source code… What the heck!
  5. No brace matching
  6. No code collapsing, but I can live without that
  7. Tabs don’t close on middle-click
  8. Does not remember last selected tab
  9. You have to take extra effort to work with header (.h) files, which are an integral part of C++. What the heck?!? It’s not in the default file types list, so you have to click on “Any file (*.*)” to see them.
  10. As far as I know, it’s not possible to select a whole line at a time. If you click in the margin, it sets a breakpoint instead of selecting the whole line.
  11. Anywhere you click in the editor, the insertion point is placed there. This can get annoying.
  12. When I open a project file, some seemingly pointless .bpr file is the only file loaded. The user does not create this file, and I did not have it open when I saved the project. All it contains is a sentence that includes “This file is used by the project manager only…” and the word “main.” No other files from the project are loaded when you open one.

I’ll list more as I think of them.

My recommendation: For a C++ IDE, a great free choice is Bloodshed Software’s DEV-C++. For a more generic and lightweight solution, I highly recommend the PSPad text editor. It has the capability to integrate with a compiler; however, as far as I know you won’t get fancy debugging features such as breakpoints without a full-featured IDE. PSPad is definitately worth checking out anyway.