Wednesday 14 May 2008

Web 2.0 and a Searchable Website

Golf Adept is as much an application as a web site. To provide a consistent look and feel I have included Web 2.0 features from the front page on down - Panels, tabs, zoom, Ajax, JSON, etc. This raised two immediate problems to solve:

  1. Web 2.0 libraries are large to download. ExtJS, for example, is over 900kb uncompressed.
  2. A lot of the pages are invisible to the search engines. They are loaded by JSON and Ajax, then driven by clicks rather than links.
The first problem has traditional solutions. Extranious code can be excluded. I chose not to do that. Standard JavaScript compression (using jsmin) brings the size down to 500kb. Enabling gzip compression on the server reduced transfer to 155kb - a size I have considered acceptable. Broadband is not always that broad - and even 155kb can take some time. I like to give my customers something to read while waiting for the bells and whistles. Fortunately the solution for this is the same as for problem two...

Golf Adept is a Web 2.0 application - basically an empty page that is filled by JavaScript. There is nothing for the search engines to review and nothing for the visitor to read while the JavaScript code is being downloaded. Most of the relatively static pages are downloaded by Ajax to fill the tab frames on demand.

Django allows us to include HTML templates - and just like the Ajax payload downloaded to display it is a pure HTML fragment. I refactored my main Web 2.0 page into staticBase.html with main.html and a new staticPage.html extending it. Even the Web 2.0 main page loads header, home and footer as a static html template to display for the user to read while the JavaScript is loading.

The footer includes a site-map link that points to the staticPage template, giving it the name of the HTML fragments that are the contents of the tabs in the Web 2.0 implementation. The static page has the same layout and look as the main Web 2.0 pages. Where the tabs are is blank with a link to the Web 2.0 site.

In the end I have a Web 2.0 site that can still be walked by search engines - any by other systems that cannot use JavaScript. And all this is without duplication of content - thanks to Django template inheritance.

Hmmm, this has been a text-centric blog. I prefer to learn from example, so here goes:


staticBase.html


<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<title>
{% block title %}{% endblock %}
{%if session.user%} for {{session.user.nickname|escape}}{%endif%}
</title>
{% block css %}{% endblock %}
{%if session.isDev%}
<link rel="stylesheet" type="text/css" href="/static/page/main.css" />
{%endif%}
{%if not session.isDev%}
<link rel="stylesheet" type="text/css" href="/static/all.css" />
{%endif%}
<link rel="stylesheet" type="text/css" "http://www.google.com/uds/solutions/dynamicfeed/gfdynamicfeedcontrol.css" />
<script type="text/javascript" src="/static/lib/dynamicFeeds.js"></script>
</head>
<body>
<div id="static-body">
<table style="width:760px;margin:0 auto;">
<tr><td style="height:380px;"></td></tr>
<tr><td style="height:30px;background-color:#EEEEFF;color:#BBB">
{% block loading-message %}Loading...{% endblock %}
</td></tr>
<tr><td>{% block body %}{% endblock %}</td></tr>
</table>
{%include "page/footer.html"%}

{% block end-load %}{% endblock %}

<!-- Afterwards so image loads after we have something to read -->
{%include "page/header.html"%}
</div>
</body>
</html>



main.html


{% extends "page/staticBase.html" %}

{% block title %}
Golf Adept
{% endblock %}

{% block css %}
<link rel="stylesheet" type="text/css" href="static/lib/ext/resources/css/ext-all.css" />
{#<link rel="stylesheet" type="text/css" href="static/page/main.css" />#}
{% endblock %}

{% block loading-message %}
Loading...
{% endblock %}

{% block body %}
{%include "tab/home.html"%}
{% endblock %}

{% block end-load %}
<!-- Now that we have something to read go ahead with the loading... -->
{%if session.isDev%}
<script type="text/javascript" src="static/lib/ext/adapter/ext/ext-base-debug.js"></script>
<script type="text/javascript" src="static/lib/ext/ext-all-debug.js"></script>
<script type="text/javascript" src="static/lib/Ext.ux.MaximizeTool.js"></script>
<script type="text/javascript" src="static/lib/Ext.ux.Plugin.RemoteComponent.js"></script>
<script type="text/javascript" src="static/lib/Ext.ux.IFrameComponent.js"></script>
<script type="text/javascript" src="static/lib/Ext.ux.layout.CenterLayout.js"></script>
<script type="text/javascript" src="static/lib/Ext.ux.StatefulTabPanel.js"></script>
<script type="text/javascript" src="static/lib/loadJS.js"></script>
<script type="text/javascript" src="static/page/main.js"></script>
{#<script type="text/javascript" src="static/lib/dynamicFeeds.js"></script>#}
{%endif%}
{%if not session.isDev%}
<script type="text/javascript" src="static/all.js.css"></script>
{%endif%}
<script type="text/javascript" src="active/page/main.js"></script>
{% endblock %}



staticPage.html


{% extends "page/staticBase.html" %}

{% block title %}
Golf Adept - {{ title }}
{% endblock %}

{% block loading-message %}
<a href="/">Home</a>
{% endblock %}

{% block body %}
{% include content %}
{% endblock %}



sitemap.html


<h3>Golf Adept Overview</h3>
<ul>
<li><a href="/">Golf Adept Home Page</a></li>
<li><a href="/html/tab/home.html">Know Your Game</a></li>
<li><a href="/html/tab/whatIsGolfAdept.html">What is Golf Adept</a></li>
<li><a href="/html/tab/walkthrough-thumbnails.html">Walkthroughs</a></li>
<li><a href="/html/tab/aboutUs.html">About Us</a></li>
</ul>



main.js


var homeTabs = [
{title: "Home",autoLoad:{url: "tab/home.html", params:"",scripts:true}},
{title: "What is Golf Adept?",autoLoad:{url: "tab/whatIsGolfAdept.html"}},
{title: "Walkthrough",plugins:[Ext.remoteComponent('static/tab/walkthroughs/layout.json')]},
{title: "About Us",autoLoad:{url: "tab/aboutUs.html"}}
];
var homeTabPanel = new Ext.ux.StatefulTabPanel({
id: 'home-tab-panel',
style: "margin: 0px auto 0px auto;",
width:760,
resizeTabs:true, // turn on tab resizing
minTabWidth: 115,
tabWidth:135,
enableTabScroll:true,
defaults: {autoScroll:true,layout:'fit'},
frame:true,
items:homeTabs,
activeTab: 0,
maximizable:true,
// Listener for Google Analitics
listeners: {
activate: function(tab) {trackPageView(tab.title);},
}
});

No comments: