Archive for the ‘Web Design’ Category

Just got an email from Amazon reminding me that "As part of our continued effort to ensure that the Product Advertising API is an efficient and effective advertising tool, we’ve identified opportunities to streamline the API", which is their way of saying that the API exists to make them money. Anything that doesn't serve that purpose is eliminated, however nice it might be for me. Their right, even if they're not right. I've already taken into account the major changes. The only thing is to change the API version to the most recent; in the aws_signed_request routine, change the $params["Version"] line to read $params["Version"] = "2011-08-01"; and that should be it.

nearlyfreespeech runs with safe mode and safe_mode_gid on, so you can't run shell scripts or other cool things. Usually that's not an issue, but if you do, they let you run CGI scripts, in any of a number of languages. You just have to treat it as a shell script, with a shebang notation of the proper language. There are a few caveats that took me a day to find out:

  1. The correct program is /usr/local/bin/php-cgi (or whereever your server puts PHP), not /usr/local/bin/php. That is the command-line interpreter, which does not output the headers. You can manually do echo "Content-type: text/html\n" etc., followed by a blank line, but who wants to try to debug that?
  2. The script has to be executable. You get a 500 Server Error otherwise. Do a chmod +x scriptname.cgi.
  3. Scripts need the appropriate file and directory permissions to write to the server. Changing the permissions of the server directory is probably too insecure (though for safe mode it's the only way); it's better to set-uid the script, but then keep it under wraps.

So a sample CGI script would be:

#!/usr/local/bin/php-cgi
<?php echo "Hello, world"; ?>

in an executable file with a .cgi extension.

Note that FTP and SFTP can't set the setuid bit, so that if you upload the file (or edit it with an FTP-aware editor like Notepad++), you need to chmod 477 scriptname.cgi again.

I've learned some things about .htaccess, but mostly I've learned that programming it is deep black magic. The most important thing is "Don't use mod-rewrite unless you absolutely need to". All the fancy stuff is better off done by the PHP (or whatever language you're using) code.

Don't do:

RewriteEngine On
RewriteBase /
RewriteRule ^([^/\.]+)/$ /index.php?main=$1&part=$1 [QSA,L]
RewriteRule ^([^/\.]+)/([^/\.]+)$ /index.php?main=$1&part=$2 [QSA,L]

to map your site to your index page; do:

FallbackResource /index.php

And in index.php parse the $_SERVER['REQUEST_URI'] to get your page/subpage arguments. Much easier to debug!

And to use FallbackResource you need to be running Apache 2.2, so get a good web host.

I get lots of comment spam, either obvious ads for dubious products or boilerplate praise in almost understandable Engfish ("This is the most coherent soliloquy on this germane topic in the recent memory") with links to the ads. But I'd never seen comment spam that went out of its way to insult me:

The subsequent time I learn a blog, I hope that it doesnt disappoint me as much as this one. I imply, I know it was my choice to read, however I truly thought youd have one thing attention-grabbing to say. All I hear is a bunch of whining about one thing that you would repair in the event you werent too busy searching for attention.[links to some construction contractor removed]

I guess they know how humble I am and that I'd take criticism more seriously than praise.

But it's still painful to read something negative and have to take the time to parse it and realize it doesn't say anything at all, so I hope it doesn't become a trend. Thank goodness for Akismet!

I'm not a fan of having to create a Google Custom Search Engine to limit searches to one site with an HTML form (which seems to be necessary for mobile sites), so let's play with Bing:


<form method="get" action="http://www.bing.com/search" >
	<input name="q" type="text"/>
	<input type="submit" value="Search with Bing"/>
	<input name="q1" value="site:http://bililite.nfshost.com/blog" type="hidden"/>
</form>

And it works, but fails again on the mobile site, just like Google. This may get better as the search engines figure it out, but I'm going to have to write my own search engine portal. What a pain.

Actually, not such a pain. Something like:

header('Location: http://www.bing.com/search?q='.urlencode($_GET['q']).'+'.urlencode($_GET['q1']))

for Bing and

header('Location: http://www.google.com/search?q='.urlencode($_GET['q']).'+site:'.urlencode($_GET['sitesearch']))

for Google. And that's what I did for the Young Israel site

Earlier, I noted that the old, simple Google search:


<form method="get" action="http://www.google.com/search" >
	<input name="q" type="text"/>
	<input type="submit" value="Search with Google"/>
	<input name="sitesearch" value="http://bililite.nfshost.com/blog" type="hidden"/>
</form>

is deprecated and doesn't work from Google's mobile site. Google does have an API for custom searches that has all sorts of fancy parameters to manipulate, but it requires signing up for a key and constructing the search ahead of time. However, some experimentation shows that not including a key brings back the old, simple search query (with a new URL and some new parameters), so we're back in business:


<form method="get" action="http://www.google.com/cse" >
	<input name="q" type="text"/>
	<input type="submit" value="Search with Google"/>
	<input name="as_sitesearch" value="http://bililite.nfshost.com/blog" type="hidden"/>
</form>

And there's all sorts of interesting things hidden in there, like sorting by date (Google tries to guess that, but doesn't do so well):


<form method="get" action="http://www.google.com/cse" >
	<input name="q" type="text"/>
	<input type="submit" value="Search with Google"/>
	<input name="as_sitesearch" value="http://bililite.nfshost.com/blog" type="hidden"/>
	<input name="sort" value="date:d" type="hidden"/>
</form>

And the entire Web Search API is deprecated, so I'll have to change the googleSearch widget to use the JSON Custom Search API eventually.

Overall, sweet. At least until Google changes things again.

Addendum: it looks as though the mobile site does require the cx parameter to limit the search to a specific site. Oh, well. It's not that hard to create a custom search.

For the search on the Young Israel site, I use Google with a form that creates links like http://www.google.com/search?q=foo&sitesearch=http://youngisrael-stl.org to limit the search to the one site. It works fine in normal browsers, but on my iPhone it detects the browser and changes it to a mobile-optimized site that ignores the sitesearch=http://youngisrael-stl.org and returns results for the whole web. http://www.google.com/search?q=foo+site:youngisrael-stl.org works fine, but I can't make an HTML form add the site: term automatically. A workaround would be to make my own page on the server that mangles the query string and changes Location, but I'm not sure it's worth the effort. I'll see how many complaints I get.

Addendum, later the same day: It looks as though Google isn't supporting the sitesearch query at all; it was deprecated a few months ago. The fact that it still sometimes works is just a lucky coincidence. They use "Custom Searches" now, and this wise person figured out how to use it with forms rather than javascript. So that's what I'm using now. It serves ads at the top of the page, but I'm too cheap to pay for the ad-free version.

The documentation for the query parameters is pretty complete, and it looks as though you could create a "generic" all-web custom search then use the parameters to limit it programmatically. Unfortunately, it looks as though the XML/JSON data is only available to paying customers.

I decided to make the Young Israel site iPhone-friendly, and there are lots of good sites for tips on creating custom CSS for the small screen. The best I found was on CSS wizardry. It doesn't focus on the how so much (using media queries or checking the User-Agent string (evil!)) as the what—making sure the elements are linear vertically, not using floats, shortening headers, etc. The major problem is that his CSS sample has the "wrong" syntax for the media query, so it won't work.

The big gotcha from the official CSS3 documentation: @media (max-device-width: 480px) doesn't work (in either Safari or Firefox), even though the documentation says it's legal. You have to have a media type in there: @media screen and (max-device-width: 480px). Took me forever to find that bug.

I would also use max-device-width rather than max-width; the user on a big screen may shrink the window and it would be confusing for the layout of the site to suddenly change. I would also not use the only screen hack that Apple suggests; there doesn't seem to be any reason to use CSS hacks (shades of the 1990's!) to target only iPhones.

The other gotcha is with my CSS parser: the javascript is run in the order that it is seen, so if you want to remove a widget for the small screen you have to explicitly destroy it:

#q {
  -jquery-googleSearch: /* default */;
}
@media screen and (max-device-width: 480px){
  #q {
    -jquery-googleSearch: destroy;
  }
}

Hope this helps somebody avoid a miserable morning.

Update: I no longer (2012-08-05) use Chili, I've switched to Prism.

I wanted to try different syntax highlighters so I wrote a little WordPress plugin that let me switch between different highlighters (email me if you would like that code). I wanted syntax highlighters that were javascript-based (ruling out GeSHi), and that allowed me to highlight inline code elements as well as code elements within block-level pre elements, using the HTML5 <code class="language-whatever"> notation for determining language. I also wanted something that didn't do any fancy javascript or Flash for selection and copying, and either supported Lisp and Basic or was easy enough to extend.

Everyone seems to use Alex Gorbatchev's syntaxhighlighter but it uses nonstandard name attributes and only works on pre and textarea elements, so I haven't tried that. I tried Benjamin Lupton's jQuery syntaxhighlighter based on Google's prettify. It insisted on making all elements display: block but a little CSS manipulation fixed that.

Then I tried snippet, which only works on pre elements but was easily modifiable to get around that, then also needed some stylesheet changes to keep the results from being display: block. Adding new languages however looks far too complicated; it uses shjs which uses language definitions from GNU Source-highlight, which is a whole different language.

jush does things right (working on code elements and not forcing them to be block) but it's hardwired for a limited number of languages and the CSS is pretty ugly. That could be fixed, though, and it does a cool trick of turning keywords into links to the documentation. Too limited a language selection, though, but it would be a nice base for working on.

In the end, I'm going to stick with chili. It's simple enough for me to modify to suit my needs, it's easy to add new languages and it works. Creating new "themes" is impossible; the styles are hard-coded into the javascript files, but I can live with that. I may sometime write my own highlighter, but for now, I'll stick with what works.

I like Andrea Ercolino's chili syntax highlighter. I like it because it works well with jQuery, it allows me to use the HTML5 <code class="language-whatever"> notation for determining language, and I can highlight inline elements, not just pre elements. And Andrea has been very responsive to my questions.

But it has an annoying habit of being too clever about cutting and pasting: selecting text in marked-up pre elements evidently used to cause problems in Firefox, so chili detects the mousedown when you try to select and creates a pop-up box with plain text instead. Unfortunately, it just gets in the way and the text is no longer formatted correctly. And the problem only exists for code with line numbers, which I never use.

So I modified the code in file jquery.chili.js: I turned the function fixTextSelection (line 1097 in my copy) into a no-op by adding a return; at the beginning. Now select and copy/paste work correctly in Firefox. It may be broken in Internet Explorer, but that doesn't bother me: my whole blog theme breaks in Internet Explorer. That's a feature, not a bug :) .

There still are some problems; it loads styles and scripts dynamically and if there's a lot happening on a page the syntax highlighter tends to lose race conditions and nothing happens. I may look at Benjamin Lupton's jQuery syntaxhighlighter or JUSH or make my own (in my copious free time).