Archive for the ‘Web Development’ Category

Feb22

CSS & Javascript image preloader

While building a photo gallery for a client I ran into an issue where the photos took too long to load and clicking thumbnails before all the photos loaded resulted in ugly transitions.

My solution was to put a semi-transparent “shield” (containing a loading animation) over the gallery. The user will be able to see the images loading, but will be unable to click anything until all images are loaded and the shield is hiddenHere’s the finished product.

Explanation follows the code.

Here’s the html. This goes inside the div that contains your gallery.

<div id="gallery_loader"> <!-- wrapper for shield -->
    <div></div> <!-- this is the actual shield -->
    <img src="animated_loader.gif"><!-- image preloader -->
</div>

…and the CSS:

#gallery_loader {
    position:absolute; /* Position the wrapper at the top left corner */
    top:0;
    left: 0;
    width:100%; /* cover the entire width of your gallery */
    height:100%; /* cover the entire height of your gallery */
    overflow:hidden; /* hide anything that might overflow */
    z-index:999; /* make sure the shield is on top over everything */
}
#gallery_loader div { /* the actual shield */
    position:absolute; /* Position the shield at the top left corner of the wrapper */
    top:0;
    left:0;
    width:100%; /* Take up the entire wrapper */
    height:100%; /* Take up the entire wrapper */
    background: #fff;
    opacity: .8; /* .8 = 80% opacity for all non-ie browsers*/
    -ms-filter:"progid:DXImageTransform.Microsoft.Alpha(Opacity=80)"; /* This and the next style are for IE */
    filter: alpha(opacity=80);
}
#gallery_loader img {
    position:relative;
    display:block; /* Need this so we can center the image */
    margin: 150px auto 0 auto; /* Set this to whatever looks good */
    padding: 30px; /* Adjust to your needs */
    background: #fff;
    border: 1px solid #333;
    -moz-border-radius:5px; /* Round corners in mozilla browsers */
    -webkit-border-radius: 5px; /* Round corners for webkit browsers */
}

Put this inside an included javascript file. This will wait until the page is loaded entirely (images and all) and then fade the loader out. Requires jquery.

$(window).bind("load", function() {
	$('#gallery_loader').fadeOut();
});

#gallery_loader is positioned absolutely and placed on top of everything else (z-index:999). It’s set to take up the entire width/height of its parent. Next comes the shield that will actually do the “blocking” of everything in the gallery. The shield is opacited and set to take up the entire width/height of the wrapper. Finally the animated loading image is loaded and centered.

As you can tell from the HTML, the actual shield is not the container of the loading animation gif. This is because the children of transparent elements can’t be more opaque than their parents. In other words if we put the loading image inside the transparent “shield” (which has an opacity of 80%) it would have a max opacity of 80%. To fix this we put the “shield” underneath the loading image and opacitate it. Here’s a good page on opacity.

Note: If you’re having issues where the loading gif isn’t loading immediately add this right after the opening of your body element

<body>
<img src="animated_loader.gif" style="display:none">
...

This will cause the loading gif to load first.

Here is where i obtained my loading gif

Feb11

Add a category to your magento homepage

  1. In the admin menu navigate to CMS -> Manage pages.
  2. Click Home page to edit it.
  3. Enter this code substituting The category id of the category you want to show for CATEGORY_ID
{{block type="catalog/product_list" category_id="CATEGORY_ID" template="catalog/product/list.phtml"}}

To get the category id go to Catalog -> Manage Categories and click the category you wish to add to your homepage. The category id will be in parenthesis at the top (ID: XX)

Dec31

Button 1px “bug” in firefox

When styling a button using the sliding doors technique i found that firefox shifted the span down 1px, thus foiling the entire idea of sliding doors.

To fix it use this:

button::-moz-focus-inner { border: none;}
Dec24

VirtualHost *:80 — mixing * ports and non-* ports with a NameVirtualHost address is not supported, proceeding with undefined results

Today while setting up an ssl certificate i obtained for my new installation of activecollab i ran into this error:

VirtualHost *:80 -- mixing * ports and non-* ports with a NameVirtualHost address is not supported, proceeding with undefined results

To fix this add this to the beginning of your virtual host

NameVirtualHost *:443

Also change

<VirtualHost *>

to

<VirtualHost *:443>

Then restart apache

Nov22

Wordpress as a CMS

This tutorial is aimed at developers who just want wordpress to function as a lightweight CMS, that is wordpress will only be used for editing page content.

First install wordpress in whatever directory you want the admin to live. I chose /admin.

Any page that needs to use wordpress functionality you must add this:

require('/path/to/wp-blog-header.php');

This gives you access to wordpress functions that we need:

  • get_page – Get the page data from the database
  • wpautop – Automatically add paragraph tags to page content

To get page content:

$page_data = get_page( 4 ); // Where 4 is the page ID in wordpress

There is a bug in certain versions of php, if you get the error:

Fatal error: Only variables can be passed by reference…

Then use this format instead:

$page_id = 4;
$page_data = get_page( $page_id );

$page_data now contains all of the info for that page, and is ready for use in your templates/views. Check the function reference to see the data you have available to you.

To display post_content use the wp function wpautop.

<?= wpautop($page_data->post_content) ?>

It’s simple!

Oct15

Finding a decent text editor for Mac

I recently bought a Mac Mini in hopes of learning to develop for the iphone. I decided to do all my web development work on my new mac for a while, to try and get used to the new OS. On my PC i use notepad++. It has everything I need: built-in ftp, tabbed files, save all open documents, search/replace in all open documents…and it’s free!!! Fine, I can do without built-in ftp, but even after removing that from my required list I still can’t find a decent Mac text editor.

Here’s my rundown:

Coda ($99)

  • No save all open documents
  • No search/replace in all documents

Textmate ($60)

  • no tabs?
  • no tabs? really? No I’m not starting a project!

SubEthaEdit ($43)

  • No search/replace in all documents
  • No save all open documents

BBEdit ($125)

  • Drawer is annoying, tabs are much better
  • No save all open documents
  • No search/replace in all documents

I miss notepad++.

Sep09

MySQL custom sort order

Here is a way to return results from a table in a custom order

select id from products where id in (4,5,6,7,8,9) order by field(id,4,7,6,5,9,8)
Jul15

Ridiculous IE6 bugs – Double margin & Disappearing position:absolute near float

Today while working on a layout I encountered 2 of IE’s more ridiculous bugs: Double margin & Disappearing position:absolute near float.

Double Margin Bug

This occurs when you have a left-margin on a left-floated element, or a right margin on a right-floated element. The margin will randomly double for whatever reason. Simplest way to fix it is to put display:inline on the float

Disapearing position:absolute near float

I’m not sure of the exact circumstances for this bug, but if you have absolutely positioned elements disappearing and they are near floats you’ve probably stumbled onto it. I can’t find a non-markup fix for this unfortunately. The best fix I’ve found is to add an element between the absolutely positioned elements and the floats.

Jun21

Learning Python – Day 2

I’m excited about my new admin interface. Page 2 on the tutorial goes into how to customize the admin. I don’t care about that at the moment so I go to page 3.

Page 3 is about URLs. Django uses a sequence of tuples populated with regular expression -> url maps. Great, this is how I did things in PHP. I add a couple of URLs and move on.

Next it’s time to create my views. I write my first view which simple prints “Hi!”. It works, great. I see that the basics of the template language used in Django are very similar to how I do it in PHP. I port my view from my PHP template to the template in Django.

{% foreach company in category.company.all() %}

Unfortunately this doesn’t work. It’s not looping over my categories/companies/videos. I think it’s because it’s having trouble going backwards with my foreign key relationships.

I find that in order to go backwards you have to do this

{% for company in category.company_set.all() %}

You have to use _set to access foreign key items. This doesn’t work either! I give up on this route and I try the method I use in PHP… creating a giant multi-dimensional array and then looping over that.

This is where I hit a wall. I quickly find out that Python’s version of arrays, called dictionaries, can’t be created like they can in PHP. I don’t like that one bit.

Python doesn’t have a version of

$video['company_id']['category_id']['video_id']['name'] = 'Video Name';

I find some custom classes via google, but Django won’t iterate over them. A couple hours later I figure I need help. I ask a couple of places and everyone suggests that it is possible with Django’s ORM, I just need to remove the ()

I find that you have to do this!

{% for company in category.company_set.all %}

You have to remove the () for functions that have no arguments. Works like a champ. Two minutes later I have all categories/companies/videos displayed correctly. I’m still using Django’s development server though so I have no styles/images, just black test on a white background.

I read somewhere that I should be using mod_wsgi instead of mod_python (I can’t find the source). Using this I get it working with Django pretty quickly.


Good:Django’s ORM

Bad: Python’s dictionary handling not my favorite. I enjoy the way PHP has implemented arrays and how they can be used as lists, dictionaries, stacks, etc. Django’s documentation is thorough, but I get lost in the maze of versions it has.

Notes: I don’t know why I didn’t think of this, but it’s been pointed out to me that you can do this:

a = dict()
a['foo'] = dict()
a['foo']['bar'] = {'this works': 'yes it does'}

That probably would have solved my problem.

Jun20

PHP template engines and why they’re useless

For the past 4 or 5 years I’ve been a proponent of using PHP as it’s own template engine. I cringe every time I see someone using smarty, btemplate, fastTemplate, etc… because I’ve never had to do anything in my html that couldn’t be done with PHP. Never! Why add a layer to your app if you don’t have to?

To illustrate this I’m going to show you a template written in a template engine, and then in PHP.

Here’s an example from the Smarty website

<table border="0" width="300">
    <tr>
        <th colspan="2" bgcolor="#d1d1d1">Guestbook Entries (<a href="{$SCRIPT_NAME}?action=add">add</a>)</th>
    </tr>
    {foreach from=$data item="entry"}
        <tr bgcolor="{cycle values="#dedede,#eeeeee" advance=false}">
            <td>{$entry.Name|escape}</td>        
            <td align="right">{$entry.EntryDate|date_format:"%e %b, %Y %H:%M:%S"}</td>        
        </tr>
        <tr>
            <td colspan="2" bgcolor="{cycle values="#dedede,#eeeeee"}">{$entry.Comment|escape}</td>
        </tr>
    {foreachelse}
        <tr>
            <td colspan="2">No records</td>
        </tr>
    {/foreach}
</table>

Here’s an example using PHP. e() is an escaping function you write yourself.

<table border="0" width="300">
    <tr>
        <th colspan="2" bgcolor="#d1d1d1">Guestbook Entries (<a href="{$SCRIPT_NAME}?action=add">add</a>)</th>
    </tr>
    <?php if ( count( $data ) ): ?>
    <?php foreach( $data as $entry ): ?>
        <tr bgcolor="<?php if( $i++ % 2 ): ?>#dedede<?php else: ?>#eeeeee<?php endif; ?>">
            <td><?= e( $entry['name'] ) ?></td>        
            <td align="right"><?= date( $entry['entryDate'], 'e b Y H M S' ) ?></td>        
        </tr>
        <tr>
            <td colspan="2" bgcolor="<?php if( $i % 2 ): ?>#dedede<?php else: ?>#eeeeee<?php endif; ?>"><?= e( $entry['comment'] ) ?></td>
        </tr>
     <?php endforeach; ?>
     <?php else: ?>
        <tr>
            <td colspan="2">No records</td>
        </tr>
     <?php endif; ?>
</table>

As you can see there is only 2 added lines of code. I had to add an if statement to account for smarty’s foreachelse. No added layer. No extra work for the interpreter. Just as readable (unless you’re a developer, then it will be more readable)

In closing read this post on the sitepoint forums. Pay particular attention to Voostind’s replies (#1, #2, #3)