Category Archives: WebDev

Extract function arguments and defaults when using object destructuring

This was such a pain to get working, and the solution isn’t ideal but it works.

I wanted to create an extensible library of functions which could be displayed in a UI. So I created functions like this:

function myFunction({a = '1', b = 2, c = [1,2], d = function(){return 'hi'}} = {}){};

To display the function options in a UI to allow users to call them, I wanted to get all the parameters and their defaults (and not pollute the global scope). I thought it’d be easy. It was not. This is my solution:

function getArguments(f) {
  var t = {};
  (new Function(`with(this) {
    with(new Proxy(this,{
      has(t, p) {return true;},
      get(t, p) {return (p in t ? t : window)[p]}
    })) {
      ${f.toString().match(/^function\s*[^(]*\(\s*{(.*)}\s*=\s*{}/ms)[1]}
    }
  }`)).call(t);
  return Object.entries(t).map(v => ({name: v[0], value: v[1]}))
}

So you can call it like this:

getArguments(myFunction);

And it returns all the arguments and their default values:

Note: it only returns arguments which have defaults.

JavaScript ECMAScript 6 slugify

I wanted to slugify a URL using Javascript.  There are lots of implementations out there, but they aren’t very nice.  I have taken inspiration from the Django implementation to create the following.  It uses String.prototype.normalize(), which is ES6, so it won’t work where you don’t have ES6.  I’m using Node.js, so I’m happy with this, and it’s very neat.  
function slugify(value) {
// Compatibly-decompose and remove combining characters.
value = value.normalize('NFKD').replace(/[\u0300-\u036F]/g, '');
// Remove all non-word characters, leaving spaces and dashes. Trim and convert to lower case.
value = value.replace(/[^\w\s\-]+/g, '').trim().toLowerCase();
// Replace groups of spaces and dashes with a single dash.
return value.replace(/[-\s]+/g, '-');
}
The following runs some test cases through it.  They are designed for a different function, so most fail, but it shows how it works.  

User script to add information to draftfantasyfootball.co.uk transfers page

I have no clue about football, yet I’m in a fantasy league. I’ve written this user script to pull injury information from ‘http://www.physioroom.com/news/english_premier_league/epl_injury_table.php’ and the likely lineups from ‘http://www.fantasyfootballscout.co.uk/team-news/’. Injury information is shown with an ‘Injured’ badge in the status column. Players that are expected to play in the next match are highlighted by adding a black border and black text to the player’s position symbol. Requires Tampermonkey fpldraft

Spotify web client minimized mode bookmarklet

I was playing around with casting spotify from Chrome to Chromecast, and disliked the cluttered interface here’s a bookmarklet that can be dragged to the bookmarks bar.  When clicked, it toggles the interface to show a more minimal look.  

SpotMini

spotSm

Here’s the code:
if (typeof spotTgShown == 'undefined') {
var spotTgShown = true;
};

function spotTg() {
if (spotTgShown){
spotTgShown = false;
spotSm();
} else {
spotTgShown = true;
spotLg();
}
};

function spotSm() {
$('now-playing').setStyle('right', 'auto').setStyle('left', '0');
$('main-nav').setStyle('visibility', 'hidden');
$('main').setStyle('visibility', 'hidden');
$('suggest-area').setStyle('visibility', 'hidden');
$('now-playing-widgets').setStyle('visibility', 'hidden');
$('now-playing').setStyle('width', '100%');
$$('body').setStyle('overflow', 'hidden');
$('wrapper').setStyle('min-width', '0px');
};

function spotLg() {
$('now-playing').setStyle('left', 'auto').setStyle('right', '0');
$('main-nav').setStyle('visibility', 'visible');
$('main').setStyle('visibility', 'visible');
$('suggest-area').setStyle('visibility', 'visible');
$('now-playing-widgets').setStyle('visibility', 'visible');
$('now-playing').setStyle('width', '');
$$('body').setStyle('overflow', '')
$('wrapper').setStyle('min-width', '');
};
spotTg();


Average selling price for completed eBay items on each day of the week

Here’s a bookmarklet to let you know what the average price of items shown in eBay was on each day of the week.

  1. Drag eBayDayAvg to your address bar.
  2. Navigate to a completed and sold page on eBay.
  3. Click on the bookmarklet.

It’s probably best to run it on a page with the max results as high as possible, and try it on a few pages.  Also limit the page to display the most relevant items.

eBayDayAvg

Here’s the code:

msg = '';
days = ['Sunday','Monday','Tuesday','Wednesday','Thursday','Friday','Saturday'];
items = {0:[],1:[],2:[],3:[],4:[],5:[],6:[]};
$('.sresult ').each(function() {
 title = $(this).find('.lvtitle').text();
 if (!(title.includes('fault') || title.includes('spare') || title.includes('issue') || title.includes('damage'))){
 price = parseFloat($(this).find('.lvprice').text().replace('£', ''));
 date = new Date(Date.parse($(this).find('.timeleft').text() + ' ' + new Date().getFullYear()));
 items[date.getDay()].push(price);
 }
});
for(item in items) {
 if (items[item].length > 0) {
 msg += days[item] + ': ' + items[item].reduce(function(a, b){return a+b;}) / items[item].length + '\r\n'
 }
};
alert(msg)

 

Convert LatLng to Point and Point to LatLng in Google Maps API v3

Having googled this, I found code to go one direction, but not the other.  Here’s both.

function latLngToPoint(latLng) {
 var topRight = map.getProjection().fromLatLngToPoint(map.getBounds().getNorthEast());
 var bottomLeft = map.getProjection().fromLatLngToPoint(map.getBounds().getSouthWest());
 var scale = Math.pow(2, map.getZoom());
 var worldPoint = map.getProjection().fromLatLngToPoint(latLng);
 return new google.maps.Point((worldPoint.x - bottomLeft.x) * scale, (worldPoint.y - topRight.y) * scale);
}

function PointTolatLng(point) {
 var topRight = map.getProjection().fromLatLngToPoint(map.getBounds().getNorthEast());
 var bottomLeft = map.getProjection().fromLatLngToPoint(map.getBounds().getSouthWest());
 var scale = Math.pow(2, map.getZoom());
 return map.getProjection().fromPointToLatLng(new google.maps.Point((point.x / scale) + bottomLeft.x, (point.y / scale) + topRight.y));
}

Automate feedback in eBay

Being lazy/efficient, I decided to script the feedback for all the junk I bought from eBay.  The following three lines will give the best feedback for all items listed in the feedback page, then you can just hit submit.  This can be entered, e.g., in Chrome developer tools console (F12, top right tab).

jQuery(":radio[value='positive']").prop('checked',true).click();
jQuery("img[alt*='Very']").click()
jQuery("input[id*='comment']").val("Great. Thanks. ")

The comment could be changed to something more descriptive.  Then I just checked through them and hit the “Leave Feedback” button.

PHP function to remotely run command as root (su)

I rewrote this from somewhere and ended up not needing it, but in case I need it in the future, here it is.

The function ssh to the remote server, issues a su and then runs the command, returning true or false depending on the return code.

function RunRemoteAsRoot($ip, $username, $password, $rootPassword, $commandString)
{
	$connection = ssh2_connect($ip, 22);
	if (!$connection)
		return false;

	if (!ssh2_auth_password($connection, $username, $password))
		return false;

	$stream = ssh2_shell($connection, "vanilla", null, 200);
	if ($stream === false)
		return false;

	stream_set_blocking($stream, true);

	if (fputs($stream, "su -\n") === false)
	{
		fclose($stream);
		return false;
	}

	$line = "";
	$output = "";
	$returnCode = 1;
	while (($char = fgetc($stream)) !== false)
	{
		$line .= $char;
		if ($char != "\n")
		{
			if (preg_match("/Password:/", $line))
			{
				// Password prompt.
				if (fputs($stream, "{$rootPassword}\n{$commandString}\necho [end] $?\n") === false)
				{
					return false;
				}
				$line = "";
			}
			else if (preg_match("/incorrect/", $line))
			{
				//Incorrect root password
				return false;
			}
		}
		else
		{
			$output .= $line;
			if (preg_match("/\[end\]\s*([0-9]+)/", $line, $matches))
			{
				// End of command detected.
				$returnCode = $matches[1];
				break;
			}
			$line = "";
		}
	}
	fclose($stream);

	return ($returnCode == 0);
}