Skip to content

Instantly share code, notes, and snippets.

@andipyk
Created September 10, 2024 15:12
Show Gist options
  • Save andipyk/612863ac0a6b89518127c392b8ba5306 to your computer and use it in GitHub Desktop.
Save andipyk/612863ac0a6b89518127c392b8ba5306 to your computer and use it in GitHub Desktop.
modern-calculator.php
.calculator {
border-radius: 10px;
box-shadow: 0 0 40px 0px rgba(0, 0, 0, 0.15);
margin: 0 auto;
max-width: 15em;
overflow: hidden;
}
.calculator-display {
background-color: #222222;
color: #fff;
font-size: 1.714285714em;
padding: 0.5em 0.75em;
text-align: right;
}
.calculator-display input {
background-color: transparent;
border: none;
color: inherit;
font-size: inherit;
text-align: right;
width: 100%;
}
.calculator-keys {
background-color: #999;
display: grid;
grid-gap: 1px;
grid-template-columns: repeat(4, 1fr);
}
.calculator-keys > * {
background-color: #fff;
padding: 0.5em 1.25em;
position: relative;
text-align: center;
}
.calculator-keys > *:active::before,
.calculator-keys > .is-depressed::before {
background-color: rgba(0, 0, 0, 0.2);
bottom: 0;
box-shadow: 0 0 6px 0 rgba(0, 0, 0, 0.5) inset;
content: "";
left: 0;
opacity: 0.3;
position: absolute;
right: 0;
top: 0;
z-index: 1;
}
.key-operator {
background-color: #eee;
}
.key-equal {
background-image: linear-gradient(to bottom, #fe886a, #ff7033);
grid-column: -2;
grid-row: 2 / span 4;
}
#num1, #num2 {
grid-column: span 2;
}
#operator {
grid-column: span 2;
}
input[type="number"], select {
background-color: #f8f8f8;
border: none;
font-size: 1em;
padding: 0.5em;
width: 100%;
}
button {
background-color: #f8f8f8;
border: none;
font-size: 1em;
cursor: pointer;
}
button:hover {
background-color: #e8e8e8;
}
document.addEventListener('DOMContentLoaded', () => {
const calculator = document.getElementById('modern-calculator');
if (!calculator) return;
const form = {
num1: calculator.querySelector('#num1'),
num2: calculator.querySelector('#num2'),
operator: calculator.querySelector('#operator'),
calculate: calculator.querySelector('#calculate'),
result: calculator.querySelector('#result')
};
form.calculate.addEventListener('click', async (e) => {
e.preventDefault();
if (!validateInputs()) return;
try {
const response = await fetchCalculation();
handleResponse(response);
} catch (error) {
handleError(error);
}
});
function validateInputs() {
if (!form.num1.value || !form.num2.value || !form.operator.value) {
displayResult('Please fill in all fields');
return false;
}
return true;
}
async function fetchCalculation() {
const response = await fetch(modernCalculatorData.ajax_url, {
method: 'POST',
headers: {'Content-Type': 'application/x-www-form-urlencoded'},
body: new URLSearchParams({
action: modernCalculatorData.action,
nonce: modernCalculatorData.nonce,
num1: form.num1.value,
num2: form.num2.value,
operator: form.operator.value
})
});
if (!response.ok) {
throw new Error('Network response was not ok');
}
return response.json();
}
function handleResponse(data) {
if (data.success) {
displayResult(`${data.data.result}`);
} else {
displayResult(`Error: ${data.data}`);
}
}
function handleError(error) {
console.error('Error:', error);
displayResult('An error occurred while calculating');
}
function displayResult(message) {
form.result.value = message;
}
});
<?php
/**
* Plugin Name: Modern Calculator
* Description: A modern calculator plugin for WordPress using ES6+ and Fetch API
* Version: 2.1
* Author: Your Name
*/
declare(strict_types=1);
namespace ModernCalculatorPlugin;
class ModernCalculator {
private const SHORTCODE = 'modern_calculator';
private const AJAX_ACTION = 'modern_calculator_action';
private const NONCE_NAME = 'modern_calculator_nonce';
public function __construct() {
add_shortcode(self::SHORTCODE, [$this, 'renderCalculator']);
add_action('wp_enqueue_scripts', [$this, 'enqueueScripts']);
add_action('wp_enqueue_scripts', [$this, 'enqueueStyles']);
add_action('wp_ajax_' . self::AJAX_ACTION, [$this, 'handleAjax']);
add_action('wp_ajax_nopriv_' . self::AJAX_ACTION, [$this, 'handleAjax']);
}
public function renderCalculator(): string {
ob_start();
?>
<div id="modern-calculator" class="calculator">
<div class="calculator-display">
<input type="text" id="result" readonly>
</div>
<div class="calculator-keys">
<input type="number" id="num1" required placeholder="Enter number">
<select id="operator">
<option value="add">+</option>
<option value="subtract">-</option>
<option value="multiply">×</option>
<option value="divide">÷</option>
</select>
<input type="number" id="num2" required placeholder="Enter number">
<button id="calculate" class="key-equal">=</button>
</div>
</div>
<?php
return ob_get_clean();
}
public function enqueueScripts(): void {
wp_enqueue_script('modern-calculator', plugin_dir_url(__FILE__) . 'calculator.js', [], '2.1', true);
wp_localize_script('modern-calculator', 'modernCalculatorData', [
'ajax_url' => admin_url('admin-ajax.php'),
'nonce' => wp_create_nonce(self::NONCE_NAME),
'action' => self::AJAX_ACTION
]);
}
public function enqueueStyles(): void {
wp_enqueue_style('modern-calculator-style', plugin_dir_url(__FILE__) . 'calculator-style.css', [], '1.0');
}
public function handleAjax(): void {
try {
check_ajax_referer(self::NONCE_NAME, 'nonce');
$num1 = $this->validateNumber('num1');
$num2 = $this->validateNumber('num2');
$operator = $this->validateOperator();
$result = $this->calculate($num1, $num2, $operator);
wp_send_json_success(['result' => $result]);
} catch (\Exception $e) {
wp_send_json_error($e->getMessage());
}
}
private function validateNumber(string $key): float {
$value = filter_input(INPUT_POST, $key, FILTER_VALIDATE_FLOAT);
if ($value === false || $value === null) {
throw new \InvalidArgumentException("Invalid input for {$key}");
}
return $value;
}
private function validateOperator(): string {
$operator = filter_input(INPUT_POST, 'operator', FILTER_SANITIZE_STRING);
if (!in_array($operator, ['add', 'subtract', 'multiply', 'divide'])) {
throw new \InvalidArgumentException('Invalid operator');
}
return $operator;
}
private function calculate(float $num1, float $num2, string $operator): string {
switch ($operator) {
case 'add':
return (string)($num1 + $num2);
case 'subtract':
return (string)($num1 - $num2);
case 'multiply':
return (string)($num1 * $num2);
case 'divide':
if ($num2 === 0.0) {
throw new \DivisionByZeroError('Division by zero');
}
return (string)($num1 / $num2);
default:
throw new \InvalidArgumentException('Invalid operator');
}
}
}
new ModernCalculator();
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment