Showing posts with label JavaScript. Show all posts
Showing posts with label JavaScript. Show all posts

Thursday, December 11, 2008

Bookmarklet to add recycle comment in GreenMetropolis

I'm selling a fair number of my old paperbacks on GreenMetropolis.com. When listing a book I invariably want to note that I will send in recycled packaging in the comments field. I was using iMacro to speed this up but I've finally got around to creating a simple bookmarklet to do the same thing. Here it is:

javascript:(
function(){
var cmts=document.getElementsByTagName('TEXTAREA');
for(var ic=0;ic<cmts.length;ic++){
if(cmts[ic].name=='comment'){
cmts[ic].value+='I will send with reused or recycled packaging.'
}
}
}
)()

And here it is as a link you can drag and drop into your own bookmarks or try it out by clicking on it here: Add note to TextArea



Reset text area

This would be fairly easy to customize for your own text or to adapt to a different form that you use regularly and get tired of typing in the same old text or if you are familiar with RegEx tweaking the text you already have in the text box. For example changing the text in the text box to Title Case or Shout.

Tuesday, December 9, 2008

Creating an intelligent shortcut (bookmarklet) in Firefox

On of the frequent address shortcuts I use in Firefox is to redirect "w sometext" in the address bar to lookup a term (sometext) in Wikipedia. As I frequently go to my "Watchlist" in Wikipedia I though it would be neat to default to that page if I had not specified a term. A little research and I'd worked out how to get this to work as a bookmarklet. In the address bar any text added to the shortcut is referenced as "%s".

Using this basic structure it would be pretty easy to add a more complex set of conditions to make the same shortcut do many more things, such as looking up a book and working out if the text you put in was an ISBN or a title.

Here's my example formatted so you can read it:


javascript:(
function(){
  if("%s".length==0){
     // Default
    window.location="http://en.wikipedia.org/wiki/Special:Watchlist"
  }else{
     // Wikipedia lookup
    window.location="http://en.wikipedia.org/wiki/%s"
  }
}
)()


And here it is formatted as a link you can drop into your bookmarks, don't forget to edit it so that it has "w" as a keyword/shortcut:
Wikipedia lookup

Sunday, November 16, 2008

Use Greasemonkey to link UK postcodes to Google Maps

See my last blog post for general details about using Greasemonkey. This titbit of source code uses a large standard regex to match any UK postcode in a web page text (you could be matching paragraph elements) and converts it into a hyperlink to a google map of that area. It assumes that this titbit is inside a script that searches relevant elements of the page and tests them as variable "thisElement".

// Convert postcodes to google map links (z=15 puts names on tube stations)
thisElement.innerHTML=thisElement.innerHTML.replace(/([A-PR-UWYZ0-9][A-HK-Y0-9][AEHMNPRTVXY0-9]?[ABEHMNPRVWXY0-9]? {1,2}[0-9][ABD-HJLN-UW-Z]{2}|GIR 0AA)/,"<a href='http://maps.google.com/maps?f=q&hl=en&geocode=&q=$1&ie=UTF8&z=15&iwloc=addr' target=_blank>$1</a>");

Friday, November 14, 2008

Write your own Greasemonkey script to highlight and hide items on a website

Here are some handy code segments that have taken me a little while to work out. Greasemonkey is a useful Firefox plugin with a massive shared library of scripts to do interesting things like adding collapsible folders to your online gmail web page. You can also write your own javascript code for Greasemonkey to apply to web sites you name.

The following code I use for a mystery shopping website I visit regularly but their table of possible assignments available in London can be several pages long. This script helps filter and colour in the table with my preferences (for example out of 80 London assignments I currently have 7 highlighted as suitable).

// ==UserScript==
// @name Website filter
// @namespace Filters
// @include http://mywebsite.com

/* Here I'm searching out items in a table that have been
highlighted in bold already. I'm then searching the bold
text and if it contains "William", I then hide the row
completely. I then go on to pick out items with "London"
in the text in dark green */


var allElements, thisElement;
allElements = document.evaluate(
'//tr/td/b',
document,
null,
XPathResult.UNORDERED_NODE_SNAPSHOT_TYPE,
null);
for (var i = 0; i < allElements.snapshotLength; i++) {
thisElement = allElements.snapshotItem(i);
// Hide these rows
if(thisElement.innerHTML.search(/William/i)>=0) {
thisElement.parentNode.parentNode.style.display="none";
}
// Highlight these elements
if(thisElement.innerHTML.search(/London/i)>=0) {
thisElement.style.color="darkgreen";
}
}

/* In this section I'm searching for any table cell and
checking the text for certain postcodes and addresses.
If there is a match, the cell is highlighted in bold
blue text. */


allElements = document.evaluate(
'//td',
document,
null,
XPathResult.UNORDERED_NODE_SNAPSHOT_TYPE,
null);
for (var i = 0; i < allElements.snapshotLength; i++) {
thisElement = allElements.snapshotItem(i);
// Highlight these addresses
if(thisElement.innerHTML.search(/SE(22|15|1\s)|London Bridge/i)>0) {
with(thisElement.style){
color="blue";
fontWeight="bold";
}
}
}

// ==/UserScript==

Explanations

Regular expressions (Regex) can be a bit cryptic but as you'll need to tailor these in the above code I though I'd explain what these bits do:
search(/William/i) ==> Search anywhere in the string for "William" and return the starting position within the string, the 'i' means that it will not be case sensitive.
search(/SE(22|15|1\s)|London Bridge/i) ==> Search anywhere in the string for "SE22", "SE15", "SE1 " or "London Bridge", ignore case and return the position.

You will also note that the first search that hides matching rows uses parentNode twice on the assumption that the bold text will be in a cell which will be in a row, so the second parent node is the "TR" tag containing the row. By changing the style.display attribute this dynamically hides the row from view (to reset and show the row again you would set style.display to null). Phew.

Useful links

Greasemonkey: https://addons.mozilla.org
XPath syntax: http://www.w3schools.com/XPath

Tuesday, May 27, 2008

Track Flickr group membership history using iMacro


User Guide
This script keeps a running log (every time you execute it), by updating a discussion message and/or saving a snapshot of group memberships. For the running log you have to create a message in each Flickr group you are an administrator for (or specifically declare), called "Member count". This log keeps a historical record of "date, membership total, total number of items". Before adding a new log entry it checks if the last entry (and the one before that) was less than a fortnight ago and updates it semi-intelligently.
Why?
I created this script as there is no easy alternative for keeping a history of membership for restricted groups in Flickr.
NotesI'm an administrator for 9 Flickr groups and maintain membership logs in 4 other groups. Watching the macro chug along updating the logs is quite satisfying. It takes 10 seconds per group (loading 3 to 4 web pages each time and added waiting time, to avoid possible page freezes, composes most of that time) but this can increase up to three-fold depending on Flickr traffic. For a macro that I only need to run once every one or two weeks that doesn't seem too shabby.

[Source code now maintained at Sourceforge.net]

iMacro setupiMacro installs itself with some example JavaScript files (.js) which are visible in the folders that iMacro shows you in Firefox.

If you find the location of these folders on your hard disk (on the Mac these are under /<your_username>/iMacros/Macros/) and then save the script in this location with a ".js" extension you should be able to see the file when you refresh the iMacro folder list in Firefox.

You should then be able to play the script from within iMacro (you have to already be logged in to your Flickr account and have created "Member count" discussion topics for groups you want to log). In the first instance I suggest you try the test test version which will run fully and show you the intended changes in the detailed change log but will not actually commit them.

See wiki.imacros.net for further help.

Monday, May 26, 2008

Flickr iMacro script to invite all your Flickr friends to a group

There was no automatic way to invite all your friends to join a group so I knocked up this quick script to take you from any group main page to the invite page, extract your list of friends (and no other contacts) and then send off the invite. The invite only goes to friends not yet in the group and not previously invited so you will not be bugging them with unwanted spam.

Note that more than 500 friends may result in time-out errors waiting for Flickr to respond. In this situation you may be better off inviting a few hundred at a time by recording an iMacro selecting the first checkbox on the invite page, then generalize it by removing the ATTR=NAME: and copy that line 200 times but change POS=1 to POS=R1 so that the next checkbox relative to the cursor position is ticked each time. When you've trimmed to a more manageable number then this script can apply again.

[JavaScript source code START]
/*
Description:
JavaScript for iMacro to create a block invite for all your
friends (but not family or other contacts) to join a Flickr group.
For more information see http://useroffline.blogspot.com

Assumptions:
- You have iMacro installed.
- You have your group's main page currently displayed.

Why:
There is no block invite facility built into Flickr.
*/

// Get friends list
var friendArr=new Array();
iimPlay("CODE:\
TAG POS=1 TYPE=A ATTR=TXT:Invite\n\
TAG POS=1 TYPE=A ATTR=TXT:Choose<SP>from<SP>your<SP>contacts?\n\
TAG POS=5 TYPE=TR EXTRACT=HTM\
");
// Tidy up extracted data
friendArr=iimGetLastExtract(1).split("name=\"");
friendArr.splice(0,1);
for(i in friendArr){
friendArr[i]=friendArr[i].split("\"")[0];
friendArr[i]="TAG POS=1 TYPE=INPUT:CHECKBOX ATTR=NAME:"+friendArr[i]+" CONTENT=YES";
}
iimPlay("CODE:"+
"' Total no. of friends = "+friendArr.length+"\n"+
friendArr.join("\n"));
// Send the message
iimPlay("CODE:\
TAG POS=1 TYPE=INPUT:SUBMIT ATTR=NAME:Submit&&VALUE:PREVIEW*\n\
TAG POS=1 TYPE=INPUT:SUBMIT ATTR=NAME:done_send&&VALUE:SEND*\
");

[JavaScript source code END]

Thursday, May 22, 2008

Re-list books on Amazon using iMacro

User GuideThis script imports my Google spreadsheet of books and then pastes them to sell on Amazon books. It takes about 20 seconds to list each book but you only process those in your spreadsheet marked to be re-listed.
Example Google Spreadsheet.
Why?Unless you pay £28.75 per month to Amazon Books to become a professional seller, you don't get the facility to import from a spreadsheet. This iMacro code does exactly that, for free, though it is of course intended for smallish quantities (in practice I'm normally adding less than 6 books at a time and have less than 20 books up for sale).
Having recently realized that the handful of books I was trying to sell had not only all expired but had also permanently gone from my closed listings so I had to put them in from scratch, I had the incentive to spend a few hours playing with JavaScript and iMacro to find a decent work around.
Known Bugs
When I have more than 20 books the last ones on the list are ignored as already listed, probably due to export limitations with iMacro. My work around is to list new books at the top of the spreadsheet and it will work fine. You could also cut and paste previously listed books into a second page of the spreadsheet and keep the front page for new books to be listed.

Sunday, April 27, 2008

How to find the cheapest train tickets by website scraping

One of my niggles with train timetable websites is that it can be very tricky to find the cheapest train ticket if you want to ask questions like "What is the cheapest ticket if I could travel on Sunday, Monday or Tuesday next month?" or even worse "What would be the cheapest 1st class ticket if can travel any weekend in June?". If you phone up a train hotline they would probably give up (and you are normally paying 10p/min while they try) or they would guess and might miss the best deal.

My solution was to use iMacro. This is a macro recording plugin for Firefox that can automate interactions with a website. I can now set up an initial script and set the browser to look for the cheapest possible ticket.

For example, below are the results for London to Nottingham travelling in the mornings (9am to 1pm) from 3rd to 5th May searching for the cheapest direct train ticket in any 2 hour slot. It took 20 seconds to configure the script (after taking a day to develop it) and my computer took 5 minutes to run the search as it has to enter data on the timetable website 12 times (3 days x 2 time slots x two classes of travel) and wait each time for the website to refresh with new data. I chose the Virgin Trains website as it seemed to have quite a nice interface which made it easy to pick the first radio button to find the cheapest ticket and seemed to return the most comprehensive results (I kept finding discrepancies on other sites, which surprised me as I assumed they shared the same underlying data).
Results for London to Nottingham 
[click to show longer example]

Searched on Sun, 27 Apr 2008 12:44:50 GMT

Saturday 3 May 2008
Slot | Time | Std | Time | 1st
09:00 | 08:55 | £ 15.00 | 08:55 | £ 18.00
11:00 | 12:55 | £ 15.00 | 11:55 | £ 18.00

Sunday 4 May 2008
Slot | Time | Std | Time | 1st
09:00 | 09:00 | £ 15.00 | 09:00 | £ 18.00
11:00 | 11:00 | £ 15.00 | 11:00 | £ 18.00

Monday 5 May 2008
Slot | Time | Std | Time | 1st
09:00 | 08:55 | £ 11.00 | 08:55 | £ 18.00
11:00 | 10:55 | £ 11.00 | 10:55 | £ 18.00
I have tested with very long queries taking more than an hour to run and the only problem may be time-outs from the website. In these cases iMacro appears to lock but by pressing the Pause/Resume button will continue without losing data. Note it is best not to use the browser when running an iMacro script but I have successfully used a different browser (Safari) at the same time without any problems.

The macro is run from a javascript file in iMacro which calls iMacro commands (previously I passed variables to an iim file but it seems easier to put it all in one file) and I tweak the "Set up query" section of the javascript to query a particular train route, this could easily be set from user prompts. For the time being it is always cheapest to get two singles rather than a return so I've only bothered writing the macro for a single. Note that the slot hours (set in array myhour) are based on the maximum number of hours that Virgin trains will display in the particular train route. For London/Nottingham this is 2 hours and for London/Redruth this is 3 hours. Nice bonus functionality I've included are returning the date in long text form from the Virgin site and keeping the iMacro code display updated telling you the estimated time left.

The latest version opens a results window to show the data in an html table. You can use iimDisplay() but it is limited to a tiny window and was (at the time of writing) not resizeable by scripting.

Here's the source code. Note that the source code is not word wrapped and long lines may appear truncated, but if you cut & paste to your editor you should see all the text.

JavaScript source code Virgin-Trains.js (click to show)