Created
September 10, 2024 15:12
-
-
Save andipyk/612863ac0a6b89518127c392b8ba5306 to your computer and use it in GitHub Desktop.
modern-calculator.php
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
.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; | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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; | |
} | |
}); |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?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