JavaScript helper: getTextWidth [TypeScript]

Here’s a quick JavaScript helper snippet to calculate width of a string, based on a supplied font styling.

Written in TypeScript.

Credit goes to https://stackoverflow.com/questions/118241/calculate-text-width-with-javascript/21015393#21015393

/**
 * Uses canvas.measureText to compute and return the width of the given text of given font in pixels.
 *
 * @param {String} text The text to be rendered.
 * @param {String} font The css font descriptor that text is to be rendered with (e.g. "bold 14px verdana").
 *
 * @see https://stackoverflow.com/questions/118241/calculate-text-width-with-javascript/21015393#21015393
 */
private getTextWidth(text: string, font: string): number {
	// re-use canvas object for better performance
	let canvas = document.createElement("canvas");
	let context = canvas.getContext("2d");
	context.font = font;
	let metrics = context.measureText(text);

	return metrics.width;
}

JavaScript helper: GetElementInnerWidth [TypeScript]

Here’s a quick JavaScript helper snippet to get the inner width (excluding padding) of an element in the DOM.

Written in TypeScript.

/**
 * Return the calculated inner width of an element.
 * Returns -1 if width is unknown.
 * @param elementID         ID of the element to calculate the width for. Set to "" to use elementClassName
 * @param elementClassName  CSS class name on the element to calcualte the width for. Ignored if elementID is provided.
 */
public static GetElementInnerWidth(elementID: string, elementClassName: string): number {
	let width: number = -1;
	let element: any = null;

	// Get the DOM element to check,
	if (elementID !== "") {
		// Lookup by element ID.
		let elementByID = document.getElementById(elementID);
		if (elementByID !== undefined) {
			element = elementByID;
		}
	} else {
		// Lookup by CSS class name. Use first found node as actual element.
		let elementByClass = document.querySelectorAll("." + elementClassName);
		if (elementByClass !== undefined && elementByClass && elementByClass[0]) {
			element = elementByClass[0];
		}
	}

	if (element !== null) {
		// The outer width of the element
		width = element.clientWidth;

		// Get the calculated padding so we can remove it.
		let paddingLeft = ComponentHelpers.TryParseInt(window.getComputedStyle(element, null).getPropertyValue("padding-left"), 0);
		let paddingRight = ComponentHelpers.TryParseInt(window.getComputedStyle(element, null).getPropertyValue("padding-right"), 0);

		// Innerwidth = outerwidth - padding
		width = width - (paddingLeft + paddingRight);
	}

	return width;
}

JavaScript helper: TryParseInt [TypeScript]

Here’s a quick JavaScript helper snippet to test a string and return a parsed integer value, or a default value if the the parse fails.

Written in TypeScript.

 

/**
 * Try to parase an integer value from a string. Returns the number if successful, otherwise return a default value.
 * @param value The string with an integer to parase.
 * @param defaultValue Default value to return if parsing fails.
 */
public static TryParseInt(value: string, defaultValue: number = 0): number {
	let parsedValue = parseInt(value, 10);

	if (isNaN(parsedValue)) {
		// Failed to parse. Return the default value.
		return defaultValue;
	} else {
		// Return the parsed value.
		return parsedValue;
	}
}

Turn ASCII list of text URLs into HTML list of hyperlinks (with Regex and Notepad++)

I have a plain-text (ASCII) list of URLs, with each URL on a new line, and I need to turn it to a HTML list (<ul>) of actual anchor links (<a>).

For example, I start with:

https://www.site1.com/
https://www.site2.com/
https://www.site3.com/
https://www.siten.com/

And want to end up with:

<ul>
<li><a href="https://www.site1.com/">https://www.site1.com/</a></li>
<li><a href="https://www.site2.com/">https://www.site2.com/</a></li>
<li><a href="https://www.site3.com/">https://www.site3.com/</a></li>
<li><a href="https://www.siten.com/">https://www.siten.com/</a></li>
</ul>

In Notepad++ It’s trivial.

  • Paste your list of links into a new document.
  • Open the “Find” dialogue (Ctrl+F).
  • In the “Search Mode” options select “Regular expression”.
  • For “Find what” enter: ^(.+)$
  • For “Replace with” enter: <li><a href=”\1″>\1</a></li>
  • Select “Replace All”.
  • Then you just have to add the “<ul>” and “</ul>” on the first and last lines (respectively).

That’s it.

And here it is with images:


Image 1: The ASCII list of links.


Image 2: A clearer view of the FInd/Replace interface.


Image 3: The result of “Replace All”.

Don’t forget to add the “<ul>” and “</ul>” on the first and last lines.

(Update – 5 minutes later): I just noticed I can set the transparency of the Find/Replace dialogue, so didn’t need the second image. Oh well…)

TypeScript: Convert a String Variable to a Number Variable

Sometimes the basics can stump you. And I was stumped this morning when I needed to convert a TypeScript variable of type “string” to a variable of type “number”, including a non-numeric check.

IsNaN() and parseInt() in JavasScript didn’t work because in TypeScript the input parameters are numbers, so immediately that’s a compile time exception.

After a quick search and trusty StackOverflow answer, I came up with the following function:

/**
 * Return the numeric value of a variable if the value is a number, otherwise return zero (0).
 */
function convertToNumber(value: any) : number 
{
  let convertedToNumber: number = 0;

  if (isNaN(Number(value)) === false) {
    convertedToNumber = Number(value);
  }

  return convertedToNumber;
}

 

Running Example

NOTE: You can pop the editor open in a new window by selecting “Edit On StackBlitz” in the bottom-left of the inserted window.
Select the folded-page icon at the top of the left column (below the StackBlizt blue/white icon) to see the list of files.

If you’re using Internet Explorer or there’s just a black window below, here’s the link to the code (and I suggest using a “modern” browser – Chrome and Edge both work): https://stackblitz.com/edit/typescript-x2hpkw.

WordPress – Adding post category requires page refresh to show up

I’m developing a plug-in and today, after a bunch of refactoring, found myself not able to add a category or tag to a Post and have it show in the list (as in this sort of screen):

 

If found the guiding answer at on StackOver at https://stackoverflow.com/a/50656747/115704 and while I also provided the following as an answer on that post I find the moderators on StackOverflow to overzealous pricks and likely to screw with my contributions, so I’m recording it here as well.

The cause

The ultimate cause is white space in PHP files appearing before the opening and closing of PHP code.

Finding the culprit is the hard part and that where I might be able to help.

 

What I said

I experienced this issue today, and white space in PHP files was the problem.

However, I want to share the steps I took to resolve the issue:

  1. I tried opening every PHP file and checking for blank lines at the start and end of the file. I picked up a few problems but the issue persisted.
  2. I was also able to do a regex search in my IDE for problems. I used Textmate/Regex: Strip whitespace from beginning/end of file as a reference point and [without quotation marks] the following regex searches “https://regex101.com/r/5EExaF/1” to find space/blank lines at the end of a file, and “https://regex101.com/r/qs17J9/1” for the start of a file.
  3. There were still problems so I narrowed down the scope by disabling plug-ins (I also knew it was one of my own plug-ins in the site I’m developing, so that made it easier).
  4. Re-activating a plug-in give a warning “The plugin generated X characters of unexpected output during activation”. This helped me in the trial-and-error process of narrowing down the source.
  5. Once I had the plug-in identified, I started commenting out require_once() calls in PHP files until the “The plugin generated X characters of unexpected output” warning disappeared.
  6. Eventually, I realised I’d broken the plug-in during refactoring and was doing a require_once() on a PHP file that was pure HTML (to inject favicon tags into a page header) rather than the appropriate add_action() call on the file as I originally intended.

Hopefully, these debug steps provide some inspiration to other people suffering the same problem. As far as I know, WordPress does not offer any easy way to identify the cause of this problem (i.e. it does not identify which file has bad spaces in it).

NOTE: I had to link to regex101 to shoe the actual values because WordPress or WordFence seems to not like regex in posts.

Tackling Regex – Value cannot start or end with space, but can contain spaces and selected characters, up to max length

Regex Sucks!

But I needed to update a form field regex validation, so I tackled it head-on and won.

As a side note, regular expression creation is also one of the best examples of where Test Driven Development (TDD) works well. You really cannot create or maintain a regex without having all the test cases written first.

 

Validation Requirements

For a value entered in the field, it:

  • Cannot start with a space.
  • Cannot end with a space.
  • May contain a one or more sapces (surrounded by other allowed characters).
  • May also contain the following characters: A-Z, a-Z, 0-0, “-“, “_”, “\”, “/”.
  • If a value is entered in the field the total character count may be from 1 to 20 characters.

 

Regex String

^([A-Za-z0-9\\\/_\-]|([A-Za-z0-9\\\/_\-][A-Za-z0-9\\\/_\- ]{0,18}[A-Za-z0-9\\\/_\-]))$

Regex Summary:

  1. For the first group (green):
    1. If the string contains only 1 character, ensure it is a valid character.
  2. OR, for the second set of 3 groups (purple):
    1. Ensure the first character is a valid character.
    2. Ensure 0-18 of the next characters is a valid character.
    3. Ensure the last character is a valid character.
    4. The combination of point 2.1, 2.2 & 2.3 handle scenarios of 2 up to 20 characters.

 

Test Data

kkdkd df sdf lk aj33<-- Pass
12345678901234567890<-- Pass
kjlf l-Ka034-/\_ kj0<-- Pass
adsfdsafsdaf dsfsdfa<-- Pass
dlASjd83_-/\dfdsfsda<-- Pass
adsfsdas  sdafsdafsa<-- Pass: Contains multiple spaces in a row
dsfsdf<-- Pass
2<-- Pass
11<-- Pass
111<-- Pass
- dsf<-- Pass
-df<-- Pass
/dsaf<-- Pass
\asdf<-- Pass
_asdf<-- Pass
_ sdfjlksdaflk jasdf<-- Pass

123456789012345678901<-- Fail. More than 20 characters
 asdf<-- Fail: Starts with a space
adsfsdas  sdafsdafs#<-- Fail: Ends with a #
 adsfsdafsdfsdfsadds<-- Fail: Starts with a space
dfsdafljkasdfklsdsd <-- Fail: Ends with a space
#<-- Fail: Invalid character only
 <-- Fail: Space only
2 <-- Fail: Ends with space
 2<-- Fail: Starts with a space

<-- Ignore: Blank line

 

See it in action

https://regex101.com/r/2uMivO/6

 

Tricky Bits

It took some trial and error to get this and using https://regex101.com was a huge help and time saver.

My final problem was allowing a single character, and that was whee the OR (“|”) came in, adding it to the start of the group.

webpack issue: “The CLI moved to a separate package: webpack-cli”

I’m working on a project that uses ‘webpack’. After pulling in a code update that required developers to clear out node_modules and update yarn, I started receiving the following prompt when running webpack:

The CLI moved to a separate package: webpack-cli
Would you like to install webpack-cli? (That will run yarn add -D webpack-cli) (yes/NO)

(I found running this – even manually running the yarn command – didn’t actually install the CLI and in fact, produced further errors).

Even trying to return the webpack version raised the prompt:

 

The problem, I have been told, is the version of webpack being loaded with “npm install -g webpack” was higher than the version we actually wanted and included ‘webpack-cli’ being split into a separate package. Specifically, we want to work with version 3.8.1.

You can see in the screenshots above just running “npm install -g webpack” installs version 3.8.3 (incidentally I cannot find a reference to version 3.8.3 on the NPM webpack page or webpack’s GitHub releases page).

 

The solution:

1) Delete the ‘npm’ and ‘npm-cache’ folder from your user profile Roaming AppData folder (i.e.  from the Windows “Run” prompt run %AppData%).

2) Install the specific webpack version. i.e. npm install -g webpack@8.3.1

Now you can run ‘webpack’ as expected.

Working with JavaScript dates deserialized from JSON

This is a quick post inspired by a problem I helped a colleague with yesterday.

The problem is a “date.getFullYear is not a function” error was thrown when calling getFullYear() on a TypeScript Date object.

This was happening when the Date object was populated from a deserialized JSON string and the deserialization was silently failing in the background in the app.

It happens due to the format of the date string, and on top of that, the string is in the format “dd/mm/yyyy” (the short date format used by most of the world)..
JavaScript being what it is, it doesn’t like this for dates like “18/05/2018” (18th May) because it actually wants to do a conversion on “05/18/2018” (US short date format).
More importantly, you can’t implicitly deserialize a string representation of a date to a JavaScript Date object. How does the dezerializer (in this case JSON.parase()) know the string is really a date?

How do we fix this?

There are 2 parts to the answer:

  1. We need to explicitly set the target/deserialized date variable/field to a Date()
    i.e. myObject.myDate = new Date(“date-string-in-accepted format”);
    For example: myObject.myDate = new Date(“05/18/2018”).
  2. Ensure the string we are passing into the Date() object is in an allowed format (best format is ISO: yyyy-mm-dd).
    For example:
    myObject.myDate = new Date(“2018-05-18”) – using ISO date format.
    myObject.myDate = new Date(“05/18/2018”) – using US date format.

Below you can see it a quick running code sample I whipped up to demonstrate this.

Play around with commenting.uncommenting the “json = “…”;” lines and the “let dataObject: DataObject = JSON.parse(json);” line.

Running Example

NOTE: You can pop the editor open in a new window by selecting “Edit On StackBlitz” in the bottom-left of the inserted window.
Select the folded-page icon at the top of the left column (below the StackBlizt blue/white icon) to see the list of files.

If you’re using Internet Explorer or there’s just a black window below, here’s the link to the code (and I suggest using a “modern” browser – Chrome and Edge both work): https://stackblitz.com/edit/typescript-riapny.

SQL SERVER WHERE clause returns match when field contains trailing space

It’s nice to know you can still discover new things after 20 years in the industry.

Last week while investigating a defect of some data import work I’d done in SQL SERVER, one of my initial steps was to query the database for the imported records. For example:

SELECT * FROM [MyTable] WHERE [SomeField] = ‘SomeValue’;

That’s a standard, simple query. Nothing tricky about it.

However, what I had already discovered from inspecting the value returned to the application that uses it, is my value actually had a trailing space (i.e. ‘SomeValue ‘).

What surprised me was when I ran the query above it still returned the record.

That is: [SomeField] actually equals ‘SomeValue ‘ (with a trailing space) in the database record, yet my comparison to ‘SomeValue’ (no trailing space) still returned the record.

It turns out this is a quirk of SQL SERVER’s implementation of SQL.
It also turns out in all my years working with databases I must have been cleansing my data enough to never encounter this (in this instance I was generating SQL statements in Excel and was explicitly told not to touch import values [some of which included an incorrect trailing space]).

Check out this StackExchange question for more information.