Java Applets in 2023

I’ve explained recently how to display Macromedia Flash movies in 2023, using Ruffle; today we’re going to learn how to run Java Applets in your modern browser of 2023, without having to install Java. Yes, it’s possible.

Enter CheerpJ. It’s an extension for Google Chrome or Microsoft Edge that somehow transpiles *.class files into WebAssembly… which allows a good old applet I wrote in 1997 (!) to render correctly on a “modern” browser of 2023.

To run the calculator, install the extension and then click on it to activate and load the applet. It will appear in the white space between this paragraph and the next. Pretty promise.

This is how the calculator above should look like, in case you’re using Firefox or don’t have the extension installed:

I wrote it on Windows 3.1 (yes, it was still my OS in 1997) using the first 16-bit implementation of the JDK and JRE ever produced: the IBM Applet Development Kit, released August 1996. Don’t believe me? Here’s an InfoWorld article proving it. A few months later Microsoft released its own 16-bit JVM for Windows 3.1, still a very popular operating system in 1996 and 1997. But I used IBM’s.

I don’t remember what editor I used to write the code, though; most probably Notepad.

Feel free to download the archive with the complete project, with files dated September 17th, 1997 (hint: it was a Wednesday.) Find below the (admittedly terrible) Java code I wrote in 1997 to make this contraption. My apologies. You’ve been warned.

import java.applet.*;
import java.awt.*;

/** Calculator Applet
	@author Adrian Kosmaczewski, (c) 1997
	@version 1.0
*/

public class CalcApplet extends Applet
{
	String CalcType = "";
	CalcMachine calculator = null;
	Label errorLabel = new Label("Missing <PARAM NAME=\"CalcType\" VALUE=\"Standard\" \nor VALUE=\"Scientific\"> tag in CalcApplet.html.");
	private double firstValue, secondValue;
	private char operationChosen = '=';
	private boolean dotNotAlreadyUsed = true;

	public void init()
	{
		CalcType = getParameter("CalcType");
		if(CalcType == null)     // if the HTML page is wrong...
		{
			add(errorLabel);
		}
		else if(CalcType.equals("Standard") || CalcType.equals("Scientific"))
		//  if the HTML page is correct...
		{
			calculator = new CalcMachine(CalcType);
			add(calculator);
		}
	}

	public boolean action(Event evt, Object obj)  //Modelo 1.0.2 de Java
	{
		if(obj.equals("1") || obj.equals("2") || obj.equals("3") ||
		obj.equals("4") || obj.equals("5") || obj.equals("6") ||
		obj.equals("7") || obj.equals("8") || obj.equals("9") ||
		obj.equals("0"))
		{
			if(calculator.display.getText().equals("0"))
			{
				calculator.display.setText("");
			}
			calculator.display.setText(calculator.display.getText() + obj.toString());
		}
		if(obj.equals("."))
		{
			if(dotNotAlreadyUsed)
			{
				calculator.display.setText(calculator.display.getText() + obj.toString());
				dotNotAlreadyUsed = false;
			}
		}
		if(obj.equals("+"))
		{
			firstValue = getDoubleValue(calculator.display.getText());
			operationChosen = '+';
		}
		if(obj.equals("-"))
		{
			firstValue = getDoubleValue(calculator.display.getText());
			operationChosen = '-';
		}
		if(obj.equals("*"))
		{
			firstValue = getDoubleValue(calculator.display.getText());
			operationChosen = '*';
		}
		if(obj.equals("/"))
		{
			firstValue = getDoubleValue(calculator.display.getText());
			operationChosen = '/';
		}
		if(obj.equals("="))
		{
			secondValue = getDoubleValue(calculator.display.getText());
			switch(operationChosen)
			{
				case('+'):
					showResult(firstValue + secondValue);
					break;
				case('-'):
					showResult(firstValue - secondValue);
					break;
				case('*'):
					showResult(firstValue * secondValue);
					break;
				case('/'):
					if(secondValue == 0)
					{
						calculator.display.setText("Cannot divide by zero");
					}
					else
					{
						showResult(firstValue / secondValue);
					}
					break;
			}
			operationChosen = '=';
		}
		if(obj.equals("AC"))
		{
			calculator.display.setText("0");
			operationChosen = '=';
		}
		if(obj.equals("C"))
		{
			if(operationChosen == '=')
			{
				calculator.display.setText("0");
				operationChosen = '=';
			}
			else
			{
				calculator.display.setText("0");
			}
		}
		if(obj.equals("sqrt"))
		{
			firstValue = getDoubleValue(calculator.display.getText());
			showResult(Math.sqrt(firstValue));
		}
		return true;
	}

	private double getDoubleValue(String s) // Converts from String to double
	{
		if(isOnlyNumbers(s))
		{
			Double tempDouble = new Double(s);
			calculator.display.setText("0");
			return tempDouble.doubleValue();
		}
		else
		{
			calculator.display.setText("0");
			operationChosen = '=';
			return 0;
		}
	}

	private boolean isOnlyNumbers(String text)
	{
		for(int i=0; i<text.length(); i++)
		{
			if(text.charAt(i)=='0' || text.charAt(i)=='1' || text.charAt(i)=='2' ||
				text.charAt(i)=='3' || text.charAt(i)=='4' || text.charAt(i)=='5' ||
				text.charAt(i)=='6' || text.charAt(i)=='7' || text.charAt(i)=='8' ||
				text.charAt(i)=='9' || text.charAt(i)=='.')
			{
				return true;
			}
		}
		return false;
	}

	private void showResult(double d)
	// Converts from double to String and shows the result on the display
	{
		Double tempDouble = new Double(d);
		calculator.display.setText(tempDouble.toString());
	}
}

/**********************************************************************************/

class CalcMachine extends Panel
{
	CalcDisplay display = null;
	CalcKeyboard keyb = null;
	int columns = 20;

	public CalcMachine(String type)
	{
		if(type.equals("Standard"))
		{
			columns = 20;
		}
		else if(type.equals("Scientific"))
		{
			columns = 50;
		}
		initialize(type);
	}

	public void initialize(String type)
	{
		display = new CalcDisplay();
		keyb =  new CalcKeyboard(type);
		setLayout(new BorderLayout());
		add("North", display);
		add("Center", keyb);
	}
}

/**********************************************************************************/

class CalcKeyboard extends Panel
{
	CalcButton one = new CalcButton("1");
	CalcButton two = new CalcButton("2");
	CalcButton three = new CalcButton("3");
	CalcButton four = new CalcButton("4");
	CalcButton five = new CalcButton("5");
	CalcButton six = new CalcButton("6");
	CalcButton seven = new CalcButton("7");
	CalcButton eight = new CalcButton("8");
	CalcButton nine = new CalcButton("9");
	CalcButton zero = new CalcButton("0");
	CalcButton point = new CalcButton(".");
	CalcButton plus = new CalcButton("+");
	CalcButton minus = new CalcButton("-");
	CalcButton times = new CalcButton("*");
	CalcButton division = new CalcButton("/");
	CalcButton equal = new CalcButton("=");
	CalcButton clear = new CalcButton("C");
	CalcButton clearAll = new CalcButton("AC");
	CalcButton sqrt = new CalcButton("sqrt");
	CalcButton percent = new CalcButton("%");

	public CalcKeyboard(String type)
	{
		if(type.equals("Standard"))
		{
			setLayout(new GridLayout(5,4));

			add(seven);
			add(eight);
			add(nine);
			add(division);

			add(four);
			add(five);
			add(six);
			add(times);

			add(one);
			add(two);
			add(three);
			add(minus);

			add(zero);
			add(point);
			add(equal);
			add(plus);

			add(clear);
			add(clearAll);
			add(sqrt);
			add(percent);
		}
		else
		{
			add(new Label("The Scientific Calculator\nis under construction"));
		}
	}
}

/**********************************************************************************/

class CalcDisplay extends Label
{
	public CalcDisplay()
	{
		super("0", RIGHT);
	}
}

/**********************************************************************************/

class CalcButton extends Button
{
	public CalcButton(String text)
	{
		super(text);
	}
}