Sunday, July 03, 2011

Being a good programmer

First of all this is not a post about best practices, being smart and all that jazz. It's about me exploring new areas to use my programming knowledge.


Update


I put the code on github


The problem


I'm a fan of the WFMU radiostation. They have a wide variety of music and they archive all their shows.
The downside is that after a month they delete the mp3 archive of the shows and because I don't listen all the time I'm missing episodes of my favorite shows.
That is why I started to download the mp3's but it takes too many steps and I needed to switch programms.



  1. Download the m3u file.

  2. Open the m3u file

  3. Copy the content

  4. Open a browsertab

  5. Paste the m3u content in the locationbar


So i went in developer-mode and started to work out a faster way to download the mp3's.


The brainstorm session


As i'm getting the mp3 archives as an rss feed and i'm using google reader to view it, the step to making it a browser add-on was taken quickly.


The easiest way to download the mp3 for me is to right click the link, click on a context item and the download starts.


The development process


I've done only a little chrome extension development, but the browser makes it a painless process with it's extension developers-mode.

This mode lets you choose a directory on your pc where the extension files are located and once you 'installed' the extension you can reload it when you changed the source code.


Because i never used contextmenu code i donwloaded the sample code from the google code site, which i also use to learn more about the api's.


The contextmenu item


The code is simple enough to understand.



  • Define when the menu item has to be added, the contexts.

  • Iterate over all the defined contexts to add the menu item and click handler, the genericOnClick.


The m3u content


From the sample I learned the first parameter of the click handler, info, holds the m3u url, linkUrl. Not a lot of brainpower needed here.


From my previous experience i know to get the file content i have to do an ajax request.

To make a cross-origin request possible you need to add the sites to the permissions variable of the manifest.json. This file contains all the metadata of the extension.


The download


Now we come to the head scratching part. As much as I searched I couldn't find a way to use the ajax responseText to automate the download.


I was trying to inject the mp3 url in the originating tab and then programmatically clicking on it. To do this i had to use the tabs.executeScript method but as i found out the code is executed in a sandbox so it can not use values from the click handler.


So i had to settle with opening a new tab which has as url the mp3 url.


The future


Now the number of actions has reduced to 3 and i can stay in the browser.



  1. Right click the link.

  2. Click the contextmenu item.

  3. Save file from tab.


I'm not going to show the code now because I want to make it more robust and universal.

There are no messages when something went wrong. I assume the content of the file only contains one mp3 link but i know it can contain multiple files.


Later i could support more metadata files and use a converting service like zamzar to make it an allround downloading extension.

Sunday, February 08, 2009

Chromeless browser 2

My second day in a chromeless browser taught me i visually depend on more UI elements that i was aware of.

For instance the throbber. Because there is no statusbar or a locationbar that shows the page loading progress the throbber becomes a crucial element. Lucky for me vimperator gives a messaget when a background tab is opened. This gave me the idea to have a two tone throbber. The darker colour throbber would appear when the current tab loads and the lighter colour throbber would appear when a background tab is loading.

The throbber should be clickable. In the current tab it should stop the page loading. With background tabs it should do the same if only one background tab is loading and open a list of loading background tabs if there are more. There has to be an option to exclude often refreshing pages like passpack.com with one click on.

Another UI element is the download progress of files. I'm using the download statusbar add-on for a long while now and i find i come to depend on it. The add-on has an option to keep downloading in the download manager after the browser is closed but you can't see when a download is finished during the browser session.

The thing i miss the most is the tab overview the tabsbar gives me. So i installed the ctrl-tab add-on which gives an overview of the tabs using the shortcut ctrl-shift-A.

As a power user i want to have access to the url. I could make a ubiquity command for this but i don't know how to put the fetched url in the commandline.

Saturday, February 07, 2009

Chromeless browser



After seeing the video of Aza and Alex about designing a chromeless browser I was wondering how to get my browser chromeless to feel what it's like.

The first thing i did was hiding the statusbar. Next on the list is the tabsbar, as i already was using the tree style tab add-on i only needed to set the autohide options.
Then i needed to remove all toolbars, for that i installed the vimperator add-on.

I'm planning to use the Ubiquity add-on as my main chrome replacement. It's more user-friendly than the vimperator commands and it can be extended very easy.

For instance i want the awesombar functionality and i found the go 3.0 command, now i have the awsomebar and a screenshot preview as a bonus.

The first thing i noticed changing to the chromeless browser is how much i return to the tabsbar to select the tabs. Using the tab command to search for the tab with a certain name is useful when you have an overview of the tabs.

This will be an experiment as long as i can stand it so this could turn into a series.

Wednesday, December 17, 2008

Laptop future



source

There are two things i think are wrong with the picture above, both the keyboard and the screen are too small.
Lately it seems all cellphones get a full keyboard but they suffer the same defect as the mini pc.

If you have a computer the input and output should be made for a human not for a mouse.



source

This could be the future but i think the five parts that form a whole is too inflexible and you will not always have the possibility to project the keyboard or the screen.

I think the laptop of the future comes in three parts; the computer, the input device and the screen. This modularity makes the computer multifunctional.

Stan goes to work and he has a presentation to give. When he is dressed he puts the computer in one of his pockets and puts his projector and 24" rolled-up screen and alphanumeric keyboard with touchpad in his briefcase.
When he goes out of the door he puts on an ear piece and puts a hardcover touchscreen in another pocket.

Using his earpiece he recieves and makes calls while he does visual tasks on his touchscreen. When he arrives at work he places his 24" screen and keyboard on his desk.
Uh oh ten o'clock time to set up in the meeting room. He takes his projector and keyboard.

This is a computer orientated scenario but other input devices could be photo and video camera's, pens, cooking utilities, and so on. An other output device is a speaker.

I don't think we are that far of this picture of the future but it seems manufacturers rather want to make everything convenient then configurable.

Monday, September 29, 2008

locale number formating

With money_format you can do great things to display the number.

// Let's justify to the left, with 14 positions of width, 8 digits of
// left precision, 2 of right precision, withouth grouping character
// and using the international format for the de_DE locale.
setlocale(LC_MONETARY, 'de_DE');
echo money_format('%=*^-14#8.2i', 1234.56) . "\n";
// DEM 1234,56****

So it's very tempting to do

echo money_format('%!n',1234.56);

But the with the money function is that you either display decimals or you don't. I was looking for a function that has the possibility to only display decimals if the the number is floating.

After a few tries i came up with this

function locale_number($number,$decimals=2,$always_decimals=false)
{
if(is_int($number) && ! $always_decimals){ $decimals = 0; }
return number_format($number, $decimals, nl_langinfo(RADIXCHAR), nl_langinfo(THOUSEP));
}

I set the $always_decimals flag to FALSE because the money_format function will be faster if you always want to display decimals.

Saturday, September 27, 2008

CI/php trick for easier to remember function names

Most of the people who use php, including me, are not so keen on the inconsistent naming of the functions but with a php trick and the help op CI you can create easier to remember function names without performance loss.

Maybe some people will find this awkward at first but in php it's possible to assign a function to a variable by adding the function name as a value to the variable.

$STR_REMOVE_BEFORE = 'strstr';


In CI 1.6.1 they added the constants.php file which gets loaded early on so you could misuse this file to add your function variables but at the same time you could use all upper-case letters to distinguish the function variables from all the other variables. See the example above which gives you the opportunity to do;

echo $STR_REMOVE_BEFORE('name@example.com','@');


There is one problem with using a variable as a function and that is that you can't use it with parameters that are passed on by reference.

$ARR_LAST_VALUE = 'end';

Using this variable as a function will result in an error.

Saturday, September 20, 2008

Simple ubiquity commands

If you go to the command editor you can add these commands if you want.

// -------------------------------------
// firefox interfaces
// -------------------------------------
CmdUtils.CreateCommand({
name: "add-ons",
icon: "http://www.spreadfirefox.com/files/spreadfirefox_RCS_favicon.png",
execute: function(){
Utils.openUrlInBrowser( "chrome://mozapps/content/extensions/extensions.xul" );
}
});

CmdUtils.CreateCommand({
name: "downloads",
icon: "http://www.spreadfirefox.com/files/spreadfirefox_RCS_favicon.png",
execute: function(){
Utils.openUrlInBrowser( "chrome://mozapps/content/downloads/downloads.xul" );
}
});

CmdUtils.CreateCommand({
name: "places",
icon: "http://www.spreadfirefox.com/files/spreadfirefox_RCS_favicon.png",
execute: function(){
Utils.openUrlInBrowser( "chrome://browser/content/places/places.xul" );
}
});
// -------------------------------------
// website based functions
// -------------------------------------
CmdUtils.CreateCommand({
name: "copy-url",
icon: "http://www.spreadfirefox.com/files/spreadfirefox_RCS_favicon.png",
execute: function(){
Utils.openUrlInBrowser( context.focusedWindow.location.href );
}
});

As you can see the openUrlInBrowser function is the engine behind all of these functions. The firefox interface commands are based on the behavior of the vimperator, where the add-ons and downloads are presented in a tab.

Sunday, September 07, 2008

New FF add-ons

Ubiquity is the first add-on that makes me want to dive in the firefox internals. I tried creating add-ons myself but i was turned off by all the files you need to maintain. Ubiquity makes it easier to start playing with firefox. For example this Ubiq, ubiquity is just too long to write it all the time, command

// speeddial, sqlitemanager, fireftp, firefly
CmdUtils.CreateCommand({
name: "add-on-gui",
icon: "https://addons.mozilla.org/img/favicon.ico",
takes: {name: noun_arb_text},
execute: function(name){
var addon = name.text;
Utils.openUrlInBrowser( "chrome://"+addon+"/content/"+addon+".xul" );
}
});

Ubiquity is a javascript powered addon, they even included jQuery. It has several functions to let the creation of commands not stand in your way, CreateCommand is the most basic. As you see it takes a YAML like syntax as an argument, in javascript it's know as JSON.

What this command does is opening the GUI for add-ons like speeddial, sqlitemanager, fireftp, firefly in a new tab by pressing ctrl+SPACE, typing add-on-gui speeddial and pressing return.
If you used one of those add-ons extensively you could have bookmarked the url but in my opinion that makes your bookmarks more browser bound. Maybe i'm just an old school bookmarker thinking that bookmarks are only for websites.

Now i'm talking about bookmarks, another recent add-on is tagmarks. Tagmarks adds a number of icons next to the bookmark star in the locationbar for easy tagging. There are a few read later add-ons that want to make your bookmarks easier to maintain but firefox 3 bookmarks are database powered so maintaining them already is easy if you use the tag feature.
It comes out-of-the-box with a few tags most people won't find useful; radiation, add, stop. But creating your own tags is not that hard if you are willing to do a little bit of graphic work.

The icons are stored in the profile\extentions\tagmarks@felipc.com\chrome\skin\icons directory. If you look at the icons they have a grey and color part. This is called in css programming a sprite. Only one part of the image is visible. So if you want to make your own tagmark you have to make a sprite. I use xnview and inkscape to do it but there will be one application solutions.

  1. open the icon file you want to use in xnview

  2. grayscale the icon and save it

  3. import the color and gray icon in inkscape and position them next to eachother

  4. Select the two images and export as bitmap


Now all you need to do is, put the icon in the icons directory and open ...\tagmarks@felipc.com\chrome\content\taglist.js in notepad or another editor. There you find again a JSON formatted list that you can modify.

If you don't want to go through all this trouble you just press ctrl+SPACE, type tag any-tags-you-like and press return. So we are back to Ubiquity with one of the build-in commands. The add-on still needs a bit more work but it already proves to be an essential add-on, certainly for the people who are used to command line like applications as launchy, quicksilver, and others. Ubiquity will make it possible to reduce the number of add-ons if you like to type. But people who like GUI extensions are not left in the cold because of it.

Wednesday, June 18, 2008

First FF3 bug

In all the heat of the world record download attempt i still experience the same bug that kept me away from using the FF beta versions.

Closing the browser using alt-F4 or the close button in the upper right corner gets me me an empty page on restarting the browser when the homepage value is set to open previous tabs.

The only the tabs are restored is by closing the the browser with the file menu exit option.

Wednesday, May 07, 2008

IE8 < IE5

It's been a long time ago that i visited the windows update site and now that i installed IE8 beta i wanted to visit the site for the SP3 service pack but i've got the message i had to install IE with a higher version number than 5.

Is IE8 IE4 in disguise?

Sunday, March 23, 2008

php do

Recently i discovered you can't use do as a class method.

class Activate
{
function do()
{
return "it's good for you.";
}
}

if you want to use Activate::do() you will get an error.

Wednesday, March 12, 2008

simple word to number and number to word functions

I saw this python blog post and i wondered how the functions translate to php.

// to make the function language independent i put the array outside the functions
$array = array('zero','one','two','three','four','five','six','seven','eight','nine');
// number to words function
function d_to_w($digits,$array)
{
$temp = preg_split('//', $digits, -1, PREG_SPLIT_NO_EMPTY);
$return = array();
foreach($temp as $check)
{
if(is_numeric($check))
{
$return[] = $array[$check];
}
}
return implode(' ',$return);
}
// words to number function
function w_to_d($word,$array)
{
$temp = preg_split('/(\.|,|;|:| )/',$word, -1, PREG_SPLIT_NO_EMPTY);
$return = array();
foreach($temp as $check)
{
$temp2 = array_search(strtolower($check), $array);
if(is_numeric($temp2))
{
$return[] = $temp2;
}
}
return implode('',$return);
}

I've added a check to make the function more real world usable. An example use of the functions is;

echo d_to_w('100',$array).'
'.w_to_d('one zero zero',$array).'
';
echo d_to_w('1.00',$array).'
'.w_to_d('one,zero zero',$array).'
';

Saturday, February 16, 2008

Strange loop behaviour in php

I was doing some minor adjustments and i was puzzled why i could only get the last item from the loop. I found out the behavoir was created by a semi colon behind the round brackets.

$array = array(1,2,3);
foreach($array as $item);
{
echo $item;
}

Produces 3 and not 123 as expected.

Monday, November 12, 2007

CodeIgniter and jQuery

On the CodeIgniter forum there are quite a few jQuery questions so I'm bringing up some pointers.

jQuery file splitting


One big jquery file is great if you want to save http connections but it's not always the best approach. For instance if you have page specific code that doesn't need to be loaded until the visitor gets on that page.

Once you separated the page specific code into different files you can do two things :
- add the link to the javascript file to your page specific view
- have a variable in your view file and add the link to the javascript file when it's needed.
With the first method you can run into trouble if someone uploads his view without the javascript link. The second method can be a source of bugs if you have a templated site because the variable always needs a value if you add it to the basic lay-out.

Ajax


The relative url is most of the time (/index.php)/controller/method but if you refer to the same controller you can use ../method.

If you are using a get request don't add the parameters using jQuerys build in functionality but add them to the url (controller/method/key/value/key/value) and retrieve the key-value pairs using the CodeIgniter uri->uri_to_assoc method.

My latest jQuery snippets on the CodeIgniter forum


Content to new window
Highlight words using a sentence/keywords on the page
hack for inline links

Wednesday, October 31, 2007

jquery plugin : switchcss

Introduction



I was answering a question posed on the CodeIgniter forum about a stylesheet switcher and i came up with this code. It is rough but it worked.

Later that day i read in the mailinglist of jquery there was A Plugin Development Pattern tutorial

After reading this i wanted to make the rough code into a plugin and switchcss was born.

Features



Other stylesheet switchers i found where based on alternative stylesheets that had to be loaded and thus making the pages heavier to load. This was the concern of the poster on the CodeIgniter forum so i made this stylesheet switcher to work with one theme css that gets changed.

It remembers the chosen theme using a cookie.

Files



Dependencies:


switchcss plugin

Usage



Link to the files and at least one theme css file and add following code to your ready method

$(function(){
// previously chosen theme
$.cookieswitchcss();
// elements that hold the alternate themes
$('.switchcss').switchcss();
});

Now clicking on the elements changes the stylesheet and adds the theme to the cookie.

By default the css filename is prefixed with theme_ and the text of the element is extracted to add to the prefix of the name. And the link element should have the title themecss.

All the defaults :

cookiename

default : csstheme

linktitle

the value of the title attribute from the link element that holds the theme css file.

default : themecss

cssprefix

general prefix used by the theme css files

default : theme_

themename

Which value to use to complete the css file name.

text : content of the element

other : value of the attribute you define here

default : text



These options are used by the two functions so i made them public (thank you tutorial) so you only have to define them once.


$.fn.switchcss.defaults.linktitle = 'theme';
// gets the value of the title attribute of the anchors
$.fn.switchcss.defaults.themename = 'title';
$.cookieswitchcss();
$('a').switchcss();


I hope it comes in handy for someone.

Thursday, October 18, 2007

Instant form validation

When you think about javascript validation and when to trigger it the first thing you think about is the onblur event. The trouble with the onblur even is not everyone is tabbing through form so it's possible not all fields are validated. The same goes for a key event.

So most of the programmers use the click event to submit the form. The problem in asp.net is that if you use the asp:net button tag the javascript of the asp.net control is handled after your own javascript code so the form is processed even if you added return false for the event.

I don't know how to influence the control behavior yet so what i did is attach the validation to the button mouseover event. This way you see the errors before you even click the button.

I don't know why i haven't thought of that before because it's so easy and noticeable.

You can find a demo at mouseover button validation

Friday, August 31, 2007

date class update

I hadn't used the class before i posted it, stupid me, therefore i wasn't aware of the problem inserting the custom dateformat in a sql statement.

Mysql formats the dates as following yyyy-mm-dd hh:mm:ss so i had to convert the custom format into the database format. As you can see the added function dbformat is pretty simple leaving room for self formatted date strings.

In the interface functions i call the dbformat function and that gets the class up and running.




class Datemodel extends Model
{
function Datemodel()
{
parent::Model();
}

/**
*
* interface functions
*
*/

function get($format = 'YmdHis', $date = null)
{
$date = (!isset($date))?$this->timestamp('db'):$this->dbformat($date);
return $this->format($date,$this->preformat($format));
}

function getstr($str,$format = 'YmdHis', $date = null)
{
$date = (!isset($date))?$this->timestamp('db'):$this->dbformat($date);
$sign = substr($str,0,1);
$period = trim(substr($str,1));
return $this->get($format,$this->interval($date,$sign,$period));
}

/**
*
* helper functions
*
*/

function timestamp($type = '')
{
switch($type)
{
case 'db': $query = $this->db->query('select NOW() as ts'); break;
default: $query = $this->db->query('select NOW()+0 as ts'); break;
}
$row = $query->row();
return $row->ts;
}

function format($date,$format)
{
$query = $this->db->query('select date_format("'.$date.'","'.$format.'") as val');
$row = $query->row();
return $row->val;
}

function interval($date,$sign,$period)
{
switch($sign)
{
case '+': $query = $this->db->query('select date_add("'.$date.'", interval '.$period.') as val'); break;
case '-': $query = $this->db->query('select date_sub("'.$date.'", interval '.$period.') as val'); break;
}
$row = $query->row();
return $row->val;
}

function dbformat($date)
{
if(strlen($date) == 14)
{
$year = substr($date,0,4);
$month = substr($date,4,2);
$day = substr($date,6,2);
$hour = substr($date,8,2);
$min = substr($date,10,2);
$sec = substr($date,12,2);
$date = $year.'-'.$month.'-'.$day.' '.$hour.':'.$min.':'.$sec;
}
return $date;
}

function preformat($str)
{
$array = array('%','a','b','c','d','e','h','i','j','k','l','m','p','r','s','u','v','w','x','y','D','H','I','M','S','U','V','W','X','Y');
foreach($array as $char)
{
$str = str_replace($char,'%'.$char,$str);
}
return $str;
}
}
?>


Saturday, August 25, 2007

mysql date functions for own timestamp format

Introduction

I recently got familiar with the limitations of the unix_timestamp. I had to make it possible to generate dates from before 1970. This was a real pain because i had used the normal date functions of php.

So i had to come up with something quick and my first thought was using the date functions of mysql. Mysql doesn't have the 1970 limitation so i was free to use any date possible.

Because i don't wanted to change all the datatypes of the fields containing dates i had to find a numeric timestamp. This was not so hard, YYYYMMDDHHMMSS gives me a date range from 10000101010101 to 99991231235959.

The code
I got used to have two functions to generate timestamps, date and strtotime. Because i wanted my functions in a class i had to use short names because no self respecting programmer want to type a lot, but they do it any way.
get and getstr seemed descriptive enough because i named the class date.

I made the class as a model class for code igniter because that's the framework i use nowadays for almost all my projects. But changing it to native php code is not going be to hard.
i only show the basic, alpha class here because i first want to test the more complex functions.



class Datemodel extends Model
{
function Datemodel()
{
parent::Model();
}

/**
*
* interface functions
*
*/

function get($format = 'YmdHis', $date = null)
{
if(!isset($date)){ $date = $this->timestamp('db'); }
return $this->format($date,$this->preformat($format));
}

function getstr($str,$format = 'YmdHis', $date = null)
{
if(!isset($date)){ $date = $this->timestamp('db'); }
$sign = substr($str,0,1);
$period = trim(substr($str,1));
return $this->get($format,$this->interval($date,$sign,$period));
}

/**
*
* helper functions
*
*/

function timestamp($type = '')
{
switch($type)
{
case 'db': $query = $this->db->query('select NOW() as ts'); break;
default: $query = $this->db->query('select NOW()+0 as ts'); break;
}
$row = $query->row();
return $row->ts;
}

function format($date,$format)
{
$query = $this->db->query('select date_format("'.$date.'","'.$format.'") as val');
$row = $query->row();
return $row->val;
}

function interval($date,$sign,$period)
{
switch($sign)
{
case '+': $query = $this->db->query('select date_add("'.$date.'", interval '.$period.') as val'); break;
case '-': $query = $this->db->query('select date_sub("'.$date.'", interval '.$period.') as val'); break;
}
$row = $query->row();
return $row->val;
}

function preformat($str)
{
$array = array('%','a','b','c','d','e','h','i','j','k','l','m','p','r','s','u','v','w','x','y','D','H','I','M','S','U','V','W','X','Y');
foreach($array as $char)
{
$str = str_replace($char,'%'.$char,$str);
}
return $str;
}
}
?>



As you can see the sql statements are very simple and for the format i made it possible to use the letter only format instead of the mysql format.

Future
This is only a basic, alpha class which should not be used on production sites.

i'm planning to make the class cross-database so it can be used everywhere and for now i'm testing a more complex method, diff, which takes care of date calculations. And the possibility for getstr and diff to be aware of weekends and vacations.

Saturday, July 28, 2007

Programmers and black holes

it's been awhile since i posted because i'm busy working on some things. I have to many ideas and to little time to work things out.

The one thing that is visible is the simple view library for the code igniter framework. I have abandoned it for a while because i needed to train a puppy but i will pick it up soon.

Apart from that i had the idea of creating an integrator library to generate jQuery code using only php. It's an effort which is maybe to much to handle alone but i want to have at least a proof of concept code.

In the past month(s) i also realised there is a big gap between developers and users. Where developers speak about rendering engines and applications, users speak about websites. Users don't care about programming languages, progressive enchantment, ajax, ... . They care about does the site does what i want it to do and does it do it fast and does it look nice enough to work on. I never understood why people wanted to work with the black and white/green programs and still do. I don't care much about how a certain button looks like but it has to te be descriptive or at least consistent within the GUI.

i'm going to have myself a summer of code on my own so keep checking the blog.