ChatGPT-4oでiPad用の電卓アプリ作ってみたよ中編
前編で四則演算が出来るだけのシンプルな電卓アプリが完成しました。
中編では履歴機能を追加して完成を目指します。
計算履歴機能を追加する
履歴機能
1. index.html
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>電卓アプリ</title>
<link rel="stylesheet" href="styles.css">
<link rel="manifest" href="manifest.json">
</head>
<body>
<div id="container">
<div id="history">
<ul id="history-list"></ul>
</div>
<div id="calculator">
<div id="display">
<div id="previous-input"></div>
<div id="current-input">0</div>
</div>
<div id="copy-message">コピーしました</div>
<div id="buttons">
<button>AC</button>
<button>C</button>
<button>%</button>
<button>+</button>
<button>1</button>
<button>2</button>
<button>3</button>
<button>-</button>
<button>4</button>
<button>5</button>
<button>6</button>
<button>*</button>
<button>7</button>
<button>8</button>
<button>9</button>
<button>/</button>
<button>0</button>
<button>00</button>
<button>.</button>
<button>=</button>
</div>
</div>
</div>
<script src="script.js"></script>
<script>
if ('serviceWorker' in navigator) {
window.addEventListener('load', () => {
navigator.serviceWorker.register('/service-worker.js')
.then(registration => {
console.log('ServiceWorker registration successful with scope: ', registration.scope);
}, err => {
console.log('ServiceWorker registration failed: ', err);
});
});
}
</script>
</body>
</html>
2. styles.css
body {
margin: 0;
font-family: Arial, sans-serif;
}
#container {
display: flex;
flex-direction: column;
height: 100vh;
}
#history {
flex: 1;
overflow-y: auto;
background-color: #f9f9f9;
padding: 10px;
border-bottom: 1px solid #ccc;
}
#history-list {
list-style-type: none;
padding: 0;
margin: 0;
}
.history-item {
display: flex;
justify-content: space-between;
align-items: center;
padding: 5px 0;
border-bottom: 1px solid #ddd;
}
.history-text {
flex: 1;
}
.history-buttons {
display: flex;
gap: 5px;
}
.history-buttons button {
background: none;
border: none;
cursor: pointer;
}
#calculator {
flex: 2;
display: flex;
flex-direction: column;
background-color: #fff;
}
#display {
flex: 1;
display: flex;
flex-direction: column;
justify-content: center;
padding: 10px 20px;
background-color: #222;
color: #fff;
border-top-left-radius: 10px;
border-top-right-radius: 10px;
overflow-x: auto; /* 長い数式をスクロール可能にする */
cursor: pointer; /* クリック可能にする */
}
#previous-input {
font-size: 1.2em; /* 小さいフォントサイズ */
color: #888; /* 薄い色 */
text-align: right;
height: 1.5em; /* 高さを固定 */
margin-bottom: 0.5em; /* 下の行との間にスペースを追加 */
}
#current-input {
font-size: 2em; /* 大きいフォントサイズ */
text-align: right;
height: 1.5em; /* 高さを固定 */
}
#copy-message {
color: #4CAF50;
text-align: center;
margin: 5px 0; /* 上下の余白を追加 */
height: 1.5em; /* 高さを固定 */
line-height: 1.5em; /* 行の高さを中央に揃える */
opacity: 0; /* デフォルトでは透明 */
transition: opacity 0.3s ease; /* 透明度のトランジションを追加 */
}
#buttons {
flex: 3;
display: grid;
grid-template-columns: repeat(4, 1fr);
gap: 10px;
padding: 10px;
overflow-y: auto; /* 縦方向のはみ出しを防ぐ */
}
button {
font-size: 1.5em;
padding: 15px;
background-color: #e0e0e0;
border: none;
border-radius: 5px;
cursor: pointer;
transition: background-color 0.3s;
display: flex;
justify-content: center;
align-items: center;
}
button:hover {
background-color: #d0d0d0;
}
button:active {
background-color: #c0c0c0;
}
@media (min-width: 600px) {
button {
padding: 20px;
}
}
@media (orientation: landscape) {
#container {
flex-direction: row;
}
#history {
flex: 1;
border-bottom: none;
border-right: 1px solid #ccc;
}
#calculator {
flex: 2;
}
}
3. script.js
const previousInputDisplay = document.getElementById('previous-input');
const currentInputDisplay = document.getElementById('current-input');
const copyMessage = document.getElementById('copy-message');
const historyList = document.getElementById('history-list');
const buttons = Array.from(document.querySelectorAll('button'));
let currentInput = '0'; // 初期値を'0'に設定
let previousInput = '';
let operator = '';
let resultDisplayed = false;
// ボタンのクリックイベントを処理する関数
function handleButtonClick(value) {
try {
if (value === 'AC') {
currentInput = '0';
previousInput = '';
operator = '';
currentInputDisplay.innerText = '0';
previousInputDisplay.innerText = '';
} else if (value === 'C') {
currentInput = '0';
currentInputDisplay.innerText = '0';
} else if (value === '%') {
currentInput = (parseFloat(currentInput) / 100).toString();
currentInputDisplay.innerText = currentInput;
} else if (value === '00') {
// currentInputが '0' または空文字の場合は何もしない
if (currentInput !== '0' && currentInput !== '') {
currentInput += '00';
currentInputDisplay.innerText = currentInput;
}
} else if (value === '.') {
// 小数点が既に含まれている場合は何もしない
if (!currentInput.includes('.')) {
if (currentInput === '0') {
currentInput = '0.';
} else {
currentInput += '.';
}
currentInputDisplay.innerText = currentInput;
}
} else if (['+', '-', '*', '/'].includes(value)) {
if (operator && previousInput && currentInput) {
previousInput = eval(`${previousInput} ${operator} ${currentInput}`).toString();
currentInput = '';
} else if (!previousInput) {
previousInput = currentInput;
currentInput = '';
}
operator = value;
resultDisplayed = false;
currentInputDisplay.innerText = previousInput + ' ' + operator;
previousInputDisplay.innerText = '';
} else if (value === '=') {
if (operator && previousInput && currentInput) {
currentInput = eval(`${previousInput} ${operator} ${currentInput}`).toString();
addHistory(`${previousInput} ${operator} ${currentInputDisplay.innerText} = ${currentInput}`);
previousInputDisplay.innerText = '';
currentInputDisplay.innerText = currentInput;
previousInput = '';
operator = '';
resultDisplayed = true;
}
} else {
if (resultDisplayed) {
currentInput = value;
resultDisplayed = false;
} else {
if (currentInput === '0') {
currentInput = value;
} else {
currentInput += value;
}
}
currentInputDisplay.innerText = currentInput;
// オペレーターがある場合は上の行に移動
if (operator) {
previousInputDisplay.innerText = previousInput + ' ' + operator;
}
}
} catch (error) {
currentInputDisplay.innerText = 'Error';
previousInputDisplay.innerText = '';
currentInput = '0';
previousInput = '';
operator = '';
}
}
// 計算履歴を追加する関数
function addHistory(entry) {
const li = document.createElement('li');
li.classList.add('history-item');
const span = document.createElement('span');
span.classList.add('history-text');
span.textContent = entry;
const buttonsDiv = document.createElement('div');
buttonsDiv.classList.add('history-buttons');
const copyButton = document.createElement('button');
copyButton.innerHTML = '📋'; // コピーアイコン
copyButton.addEventListener('click', () => {
navigator.clipboard.writeText(entry).then(() => {
copyMessage.style.opacity = '1'; // メッセージを表示
setTimeout(() => {
copyMessage.style.opacity = '0'; // メッセージを隠す
}, 2000);
}).catch(err => {
console.error('Error copying to clipboard: ', err);
});
});
const deleteButton = document.createElement('button');
deleteButton.innerHTML = '🗑️'; // ゴミ箱アイコン
deleteButton.addEventListener('click', () => {
historyList.removeChild(li);
});
buttonsDiv.appendChild(copyButton);
buttonsDiv.appendChild(deleteButton);
li.appendChild(span);
li.appendChild(buttonsDiv);
historyList.appendChild(li);
}
// ボタンのクリックイベントリスナーを追加
buttons.forEach(button => {
button.addEventListener('click', () => handleButtonClick(button.innerText));
});
// キーボードのキー入力を処理するイベントリスナーを追加
document.addEventListener('keydown', (event) => {
const key = event.key;
if (key >= '0' && key <= '9') {
handleButtonClick(key);
} else if (key === '.') {
handleButtonClick('.');
} else if (key === '+') {
handleButtonClick('+');
} else if (key === '-') {
handleButtonClick('-');
} else if (key === '*') {
handleButtonClick('*');
} else if (key === '/') {
handleButtonClick('/');
} else if (key === 'Enter') {
handleButtonClick('=');
} else if (key === 'Escape') {
handleButtonClick('AC');
} else if (key === 'Backspace') {
handleButtonClick('C');
} else if (key === '%') {
handleButtonClick('%');
}
});
// クリップボードに結果をコピー
currentInputDisplay.addEventListener('click', () => {
let textToCopy = currentInput;
// 演算子を除外してコピー
if (['+', '-', '*', '/'].includes(operator)) {
textToCopy = currentInputDisplay.innerText.replace(/[+\-*/]/g, '').trim();
}
// クリップボードにコピー
navigator.clipboard.writeText(textToCopy).then(() => {
copyMessage.style.opacity = '1'; // メッセージを表示
setTimeout(() => {
copyMessage.style.opacity = '0'; // メッセージを隠す
}, 2000);
}).catch(err => {
console.error('Error copying to clipboard: ', err);
});
});
変更点の説明
履歴表示領域の追加:
#history を追加し、計算履歴を表示する #history-list を内包しています。
計算結果を表示するためにリスト項目(li)を生成し、それにコピーアイコンとゴミ箱アイコンのボタンを追加します。
レスポンシブデザイン:
縦表示では、履歴が上部に、電卓が下部に配置されます。
横表示では、履歴が左側に、電卓が右側に配置されます。
履歴の追加:
計算結果が出たときに addHistory 関数を呼び出し、履歴リストに計算履歴を追加します。
コピーと削除の機能:
各履歴項目にコピーアイコンとゴミ箱アイコンのボタンを追加し、クリックでコピーまたは削除ができるようにします。
チェーン計算に対応させる
修正後の script.js
const previousInputDisplay = document.getElementById('previous-input');
const currentInputDisplay = document.getElementById('current-input');
const copyMessage = document.getElementById('copy-message');
const historyList = document.getElementById('history-list');
const buttons = Array.from(document.querySelectorAll('button'));
let currentInput = '0'; // 初期値を'0'に設定
let previousInput = '';
let operator = '';
let resultDisplayed = false;
// ボタンのクリックイベントを処理する関数
function handleButtonClick(value) {
try {
if (value === 'AC') {
currentInput = '0';
previousInput = '';
operator = '';
currentInputDisplay.innerText = '0';
previousInputDisplay.innerText = '';
} else if (value === 'C') {
currentInput = '0';
currentInputDisplay.innerText = '0';
} else if (value === '%') {
currentInput = (parseFloat(currentInput) / 100).toString();
currentInputDisplay.innerText = currentInput;
} else if (value === '00') {
// currentInputが '0' または空文字の場合は何もしない
if (currentInput !== '0' && currentInput !== '') {
currentInput += '00';
currentInputDisplay.innerText = currentInput;
}
} else if (value === '.') {
// 小数点が既に含まれている場合は何もしない
if (!currentInput.includes('.')) {
if (currentInput === '0') {
currentInput = '0.';
} else {
currentInput += '.';
}
currentInputDisplay.innerText = currentInput;
}
} else if (['+', '-', '*', '/'].includes(value)) {
if (operator && previousInput && currentInput) {
const result = eval(`${previousInput} ${operator} ${currentInput}`).toString();
addHistory(`${previousInput} ${operator} ${currentInput} = ${result}`);
previousInput = result;
currentInput = '';
} else if (!previousInput) {
previousInput = currentInput;
currentInput = '';
}
operator = value;
resultDisplayed = false;
currentInputDisplay.innerText = previousInput + ' ' + operator;
previousInputDisplay.innerText = '';
} else if (value === '=') {
if (operator && previousInput && currentInput) {
currentInput = eval(`${previousInput} ${operator} ${currentInput}`).toString();
addHistory(`${previousInput} ${operator} ${currentInputDisplay.innerText} = ${currentInput}`);
previousInputDisplay.innerText = '';
currentInputDisplay.innerText = currentInput;
previousInput = '';
operator = '';
resultDisplayed = true;
}
} else {
if (resultDisplayed) {
currentInput = value;
resultDisplayed = false;
} else {
if (currentInput === '0') {
currentInput = value;
} else {
currentInput += value;
}
}
currentInputDisplay.innerText = currentInput;
// オペレーターがある場合は上の行に移動
if (operator) {
previousInputDisplay.innerText = previousInput + ' ' + operator;
}
}
} catch (error) {
currentInputDisplay.innerText = 'Error';
previousInputDisplay.innerText = '';
currentInput = '0';
previousInput = '';
operator = '';
}
}
// 計算履歴を追加する関数
function addHistory(entry) {
const li = document.createElement('li');
li.classList.add('history-item');
const span = document.createElement('span');
span.classList.add('history-text');
span.textContent = entry;
const buttonsDiv = document.createElement('div');
buttonsDiv.classList.add('history-buttons');
const copyButton = document.createElement('button');
copyButton.innerHTML = '📋'; // コピーアイコン
copyButton.addEventListener('click', () => {
navigator.clipboard.writeText(entry).then(() => {
copyMessage.style.opacity = '1'; // メッセージを表示
setTimeout(() => {
copyMessage.style.opacity = '0'; // メッセージを隠す
}, 2000);
}).catch(err => {
console.error('Error copying to clipboard: ', err);
});
});
const deleteButton = document.createElement('button');
deleteButton.innerHTML = '🗑️'; // ゴミ箱アイコン
deleteButton.addEventListener('click', () => {
historyList.removeChild(li);
});
buttonsDiv.appendChild(copyButton);
buttonsDiv.appendChild(deleteButton);
li.appendChild(span);
li.appendChild(buttonsDiv);
historyList.appendChild(li);
}
// ボタンのクリックイベントリスナーを追加
buttons.forEach(button => {
button.addEventListener('click', () => handleButtonClick(button.innerText));
});
// キーボードのキー入力を処理するイベントリスナーを追加
document.addEventListener('keydown', (event) => {
const key = event.key;
if (key >= '0' && key <= '9') {
handleButtonClick(key);
} else if (key === '.') {
handleButtonClick('.');
} else if (key === '+') {
handleButtonClick('+');
} else if (key === '-') {
handleButtonClick('-');
} else if (key === '*') {
handleButtonClick('*');
} else if (key === '/') {
handleButtonClick('/');
} else if (key === 'Enter') {
handleButtonClick('=');
} else if (key === 'Escape') {
handleButtonClick('AC');
} else if (key === 'Backspace') {
handleButtonClick('C');
} else if (key === '%') {
handleButtonClick('%');
}
});
// クリップボードに結果をコピー
currentInputDisplay.addEventListener('click', () => {
let textToCopy = currentInput;
// 演算子を除外してコピー
if (['+', '-', '*', '/'].includes(operator)) {
textToCopy = currentInputDisplay.innerText.replace(/[+\-*/]/g, '').trim();
}
// クリップボードにコピー
navigator.clipboard.writeText(textToCopy).then(() => {
copyMessage.style.opacity = '1'; // メッセージを表示
setTimeout(() => {
copyMessage.style.opacity = '0'; // メッセージを隠す
}, 2000);
}).catch(err => {
console.error('Error copying to clipboard: ', err);
});
});
変更点の説明
履歴の追加:
「+」、「-」、「*」、「/」が入力されたときに、現在の計算結果を履歴に追加するようにしました。
「=」が入力されたときも同様に、現在の計算結果を履歴に追加します。
履歴から再入力できるように変更
修正後の script.js
const previousInputDisplay = document.getElementById('previous-input');
const currentInputDisplay = document.getElementById('current-input');
const copyMessage = document.getElementById('copy-message');
const historyList = document.getElementById('history-list');
const buttons = Array.from(document.querySelectorAll('button'));
let currentInput = '0'; // 初期値を'0'に設定
let previousInput = '';
let operator = '';
let resultDisplayed = false;
// ボタンのクリックイベントを処理する関数
function handleButtonClick(value) {
try {
if (value === 'AC') {
currentInput = '0';
previousInput = '';
operator = '';
currentInputDisplay.innerText = '0';
previousInputDisplay.innerText = '';
} else if (value === 'C') {
currentInput = '0';
currentInputDisplay.innerText = '0';
} else if (value === '%') {
currentInput = (parseFloat(currentInput) / 100).toString();
currentInputDisplay.innerText = currentInput;
} else if (value === '00') {
// currentInputが '0' または空文字の場合は何もしない
if (currentInput !== '0' && currentInput !== '') {
currentInput += '00';
currentInputDisplay.innerText = currentInput;
}
} else if (value === '.') {
// 小数点が既に含まれている場合は何もしない
if (!currentInput.includes('.')) {
if (currentInput === '0') {
currentInput = '0.';
} else {
currentInput += '.';
}
currentInputDisplay.innerText = currentInput;
}
} else if (['+', '-', '*', '/'].includes(value)) {
if (operator && previousInput && currentInput) {
const result = eval(`${previousInput} ${operator} ${currentInput}`).toString();
addHistory(`${previousInput} ${operator} ${currentInput} = ${result}`);
previousInput = result;
currentInput = '';
} else if (!previousInput) {
previousInput = currentInput;
currentInput = '';
}
operator = value;
resultDisplayed = false;
currentInputDisplay.innerText = previousInput + ' ' + operator;
previousInputDisplay.innerText = '';
} else if (value === '=') {
if (operator && previousInput && currentInput) {
currentInput = eval(`${previousInput} ${operator} ${currentInput}`).toString();
addHistory(`${previousInput} ${operator} ${currentInputDisplay.innerText} = ${currentInput}`);
previousInputDisplay.innerText = '';
currentInputDisplay.innerText = currentInput;
previousInput = '';
operator = '';
resultDisplayed = true;
}
} else {
if (resultDisplayed) {
currentInput = value;
resultDisplayed = false;
} else {
if (currentInput === '0') {
currentInput = value;
} else {
currentInput += value;
}
}
currentInputDisplay.innerText = currentInput;
// オペレーターがある場合は上の行に移動
if (operator) {
previousInputDisplay.innerText = previousInput + ' ' + operator;
}
}
} catch (error) {
currentInputDisplay.innerText = 'Error';
previousInputDisplay.innerText = '';
currentInput = '0';
previousInput = '';
operator = '';
}
}
// 計算履歴を追加する関数
function addHistory(entry) {
const li = document.createElement('li');
li.classList.add('history-item');
const span = document.createElement('span');
span.classList.add('history-text');
span.textContent = entry;
const buttonsDiv = document.createElement('div');
buttonsDiv.classList.add('history-buttons');
const copyButton = document.createElement('button');
copyButton.innerHTML = '📋'; // コピーアイコン
copyButton.addEventListener('click', () => {
const result = entry.split('=')[1].trim();
if (resultDisplayed || (!operator && currentInput === '0')) {
currentInput = result;
} else if (operator) {
currentInput += result;
} else {
currentInput = result;
}
currentInputDisplay.innerText = currentInput;
});
const deleteButton = document.createElement('button');
deleteButton.innerHTML = '🗑️'; // ゴミ箱アイコン
deleteButton.addEventListener('click', () => {
historyList.removeChild(li);
});
buttonsDiv.appendChild(copyButton);
buttonsDiv.appendChild(deleteButton);
li.appendChild(span);
li.appendChild(buttonsDiv);
historyList.appendChild(li);
}
// ボタンのクリックイベントリスナーを追加
buttons.forEach(button => {
button.addEventListener('click', () => handleButtonClick(button.innerText));
});
// キーボードのキー入力を処理するイベントリスナーを追加
document.addEventListener('keydown', (event) => {
const key = event.key;
if (key >= '0' && key <= '9') {
handleButtonClick(key);
} else if (key === '.') {
handleButtonClick('.');
} else if (key === '+') {
handleButtonClick('+');
} else if (key === '-') {
handleButtonClick('-');
} else if (key === '*') {
handleButtonClick('*');
} else if (key === '/') {
handleButtonClick('/');
} else if (key === 'Enter') {
handleButtonClick('=');
} else if (key === 'Escape') {
handleButtonClick('AC');
} else if (key === 'Backspace') {
handleButtonClick('C');
} else if (key === '%') {
handleButtonClick('%');
}
});
// クリップボードに結果をコピー
currentInputDisplay.addEventListener('click', () => {
let textToCopy = currentInput;
// 演算子を除外してコピー
if (['+', '-', '*', '/'].includes(operator)) {
textToCopy = currentInputDisplay.innerText.replace(/[+\-*/]/g, '').trim();
}
// クリップボードにコピー
navigator.clipboard.writeText(textToCopy).then(() => {
copyMessage.style.opacity = '1'; // メッセージを表示
setTimeout(() => {
copyMessage.style.opacity = '0'; // メッセージを隠す
}, 2000);
}).catch(err => {
console.error('Error copying to clipboard: ', err);
});
});
変更点の説明
コピーアイコンの動作変更:
コピーアイコンをクリックした際に、その履歴行の結果を電卓に入力します。
resultDisplayed が true または現在の入力が「0」である場合は、コピーした結果を新しい入力として設定します。
現在の入力に演算子が含まれている場合は、演算子の後にコピーした結果を追加します。
修正後の script.js
const previousInputDisplay = document.getElementById('previous-input');
const currentInputDisplay = document.getElementById('current-input');
const copyMessage = document.getElementById('copy-message');
const historyList = document.getElementById('history-list');
const buttons = Array.from(document.querySelectorAll('button'));
let currentInput = '0'; // 初期値を'0'に設定
let previousInput = '';
let operator = '';
let resultDisplayed = false;
// ボタンのクリックイベントを処理する関数
function handleButtonClick(value) {
try {
if (value === 'AC') {
currentInput = '0';
previousInput = '';
operator = '';
currentInputDisplay.innerText = '0';
previousInputDisplay.innerText = '';
} else if (value === 'C') {
currentInput = '0';
currentInputDisplay.innerText = '0';
} else if (value === '%') {
currentInput = (parseFloat(currentInput) / 100).toString();
currentInputDisplay.innerText = currentInput;
} else if (value === '00') {
// currentInputが '0' または空文字の場合は何もしない
if (currentInput !== '0' && currentInput !== '') {
currentInput += '00';
currentInputDisplay.innerText = currentInput;
}
} else if (value === '.') {
// 小数点が既に含まれている場合は何もしない
if (!currentInput.includes('.')) {
if (currentInput === '0') {
currentInput = '0.';
} else {
currentInput += '.';
}
currentInputDisplay.innerText = currentInput;
}
} else if (['+', '-', '*', '/'].includes(value)) {
if (operator && previousInput && currentInput) {
const result = eval(`${previousInput} ${operator} ${currentInput}`).toString();
addHistory(`${previousInput} ${operator} ${currentInput} = ${result}`);
previousInput = result;
currentInput = '';
} else if (!previousInput) {
previousInput = currentInput;
currentInput = '';
}
operator = value;
resultDisplayed = false;
currentInputDisplay.innerText = previousInput + ' ' + operator;
previousInputDisplay.innerText = '';
} else if (value === '=') {
if (operator && previousInput && currentInput) {
currentInput = eval(`${previousInput} ${operator} ${currentInput}`).toString();
addHistory(`${previousInput} ${operator} ${currentInputDisplay.innerText} = ${currentInput}`);
previousInputDisplay.innerText = '';
currentInputDisplay.innerText = currentInput;
previousInput = '';
operator = '';
resultDisplayed = true;
}
} else {
if (resultDisplayed) {
currentInput = value;
resultDisplayed = false;
} else {
if (currentInput === '0') {
currentInput = value;
} else {
currentInput += value;
}
}
currentInputDisplay.innerText = currentInput;
// オペレーターがある場合は上の行に移動
if (operator) {
previousInputDisplay.innerText = previousInput + ' ' + operator;
}
}
} catch (error) {
currentInputDisplay.innerText = 'Error';
previousInputDisplay.innerText = '';
currentInput = '0';
previousInput = '';
operator = '';
}
}
// 計算履歴を追加する関数
function addHistory(entry) {
const li = document.createElement('li');
li.classList.add('history-item');
const span = document.createElement('span');
span.classList.add('history-text');
span.textContent = entry;
const buttonsDiv = document.createElement('div');
buttonsDiv.classList.add('history-buttons');
const copyButton = document.createElement('button');
copyButton.innerHTML = '📋'; // コピーアイコン
copyButton.addEventListener('click', () => {
const result = entry.split('=')[1].trim();
if (resultDisplayed || (!operator && currentInput === '0')) {
currentInput = result;
} else if (operator) {
previousInputDisplay.innerText = currentInputDisplay.innerText;
currentInput = result;
} else {
currentInput = result;
}
currentInputDisplay.innerText = currentInput;
});
const deleteButton = document.createElement('button');
deleteButton.innerHTML = '🗑️'; // ゴミ箱アイコン
deleteButton.addEventListener('click', () => {
historyList.removeChild(li);
});
buttonsDiv.appendChild(copyButton);
buttonsDiv.appendChild(deleteButton);
li.appendChild(span);
li.appendChild(buttonsDiv);
historyList.appendChild(li);
}
// ボタンのクリックイベントリスナーを追加
buttons.forEach(button => {
button.addEventListener('click', () => handleButtonClick(button.innerText));
});
// キーボードのキー入力を処理するイベントリスナーを追加
document.addEventListener('keydown', (event) => {
const key = event.key;
if (key >= '0' && key <= '9') {
handleButtonClick(key);
} else if (key === '.') {
handleButtonClick('.');
} else if (key === '+') {
handleButtonClick('+');
} else if (key === '-') {
handleButtonClick('-');
} else if (key === '*') {
handleButtonClick('*');
} else if (key === '/') {
handleButtonClick('/');
} else if (key === 'Enter') {
handleButtonClick('=');
} else if (key === 'Escape') {
handleButtonClick('AC');
} else if (key === 'Backspace') {
handleButtonClick('C');
} else if (key === '%') {
handleButtonClick('%');
}
});
// クリップボードに結果をコピー
currentInputDisplay.addEventListener('click', () => {
let textToCopy = currentInput;
// 演算子を除外してコピー
if (['+', '-', '*', '/'].includes(operator)) {
textToCopy = currentInputDisplay.innerText.replace(/[+\-*/]/g, '').trim();
}
// クリップボードにコピー
navigator.clipboard.writeText(textToCopy).then(() => {
copyMessage.style.opacity = '1'; // メッセージを表示
setTimeout(() => {
copyMessage.style.opacity = '0'; // メッセージを隠す
}, 2000);
}).catch(err => {
console.error('Error copying to clipboard: ', err);
});
});
変更点の説明
コピーボタンの動作変更:
現在の入力に演算子が含まれている場合、その演算子を含む数字を電卓の上の行に表示し、履歴の結果を新しい入力として設定します。
不具合修正
修正後の script.js
……(中略)……
変更点の説明
handleButtonClick 関数の修正:
演算子が入力された場合、演算結果を計算し、previousInputDisplay と currentInputDisplay を正しく更新します。
= が入力された場合も、同様に演算結果を計算し、ディスプレイを更新します。
履歴の結果を電卓に入力する処理の修正:
履歴のコピーボタンを押した場合の処理を修正し、現在の入力に演算子が含まれている場合には、上の行にその演算子を含む数字を表示し、結果を新しい入力として設定します。
ここまでの成果画面
見た目の調整、その他
レイアウトの調整
機能は実装できたので、ここから最後のレイアウト調整を……と思っていたのですが、ここからが大変でした。
指示を出して、ChatGPTが修正という繰り返しで、一見上手くいっているように見えますが、後半に行くにしたがって、1つ直すと他がずれたり、指示してないところが変更されてたり……。堂々巡りでいつまでたっても完成しない……。
修正後の styles.css
……(中略)……
変更点の説明
横向き表示のバランス調整:
#history の flex プロパティを 3 に設定し、横向き表示時に履歴の幅を広くしました。
#calculator の flex プロパティを 2 に設定し、横向き表示時に電卓の幅を狭くしました。
そして後編へ……
ここまでぐるぐるとやり取りをして力尽きました。
後編では、新規にChatGPTを開き、ここまでに完成したファイルを読み込んで仕切り直しした様子をお伝えします。
この記事が参加している募集
この記事が気に入ったらサポートをしてみませんか?