1
goffy
Implement modal calculator
  • 2022/7/11 15:33

  • goffy

  • Just can't stay away

  • Posts: 535

  • Since: 2010/12/27


Hi to all

in my modul wgsimpleacc I had the request to implement a simple calculator (if e.g. someone wants to sum up various small bills).
my goal was to implement a modal version.
I played around a little bit and I found (IMO) a good solution for this feature, which I want to share with you, maybe you can also use it.

first of all I need the modal form:
<div class="modal fade" id="calcModal" tabindex="-1" role="dialog" aria-labelledby="calcModalLabel" aria-hidden="true">
    <
div class="modal-dialog" role="document">
        <
div class="modal-content">
            <
div class="modal-header">
                <
h4 class="modal-title" id="calcModalLabel"><{$smarty.const._MA_WGSIMPLEACC_CALC}></h4>
                <
button type="button" class="close" data-dismiss="modal" aria-label="<{$smarty.const._CLOSE}>">
                    <
span class="btn btn-danger" aria-hidden="true">&times;</span>
                </
button>
            </
div>
            <
div id="modal-body" class="modal-body">
                <
div class="calculator">
                    <
input id="calc-screen" type="text" class="calculator-screen" value="" disabled />
                    <
div class="calculator-keys">
                        <
button type="button" class="btn btn-warning operator" value="+">+</button>
                        <
button type="button" class="btn btn-warning operator" value="-">-</button>
                        <
button type="button" class="btn btn-warning operator" value="*">&times;</button>
                        <
button type="button" class="btn btn-warning operator" value="/">&divide;</button>
                        <
button type="button" class="btn btn-primary digit" value="7">7</button>
                        <
button type="button" class="btn btn-primary digit" value="8">8</button>
                        <
button type="button" class="btn btn-primary digit" value="9">9</button>
                        <
button type="button" class="btn btn-primary digit" value="4">4</button>
                        <
button type="button" class="btn btn-primary digit" value="5">5</button>
                        <
button type="button" class="btn btn-primary digit" value="6">6</button>
                        <
button type="button" class="btn btn-primary digit" value="1">1</button>
                        <
button type="button" class="btn btn-primary digit" value="2">2</button>
                        <
button type="button" class="btn btn-primary digit" value="3">3</button>
                        <
button type="button" class="btn btn-primary digit" value="0">0</button>
                        <
button type="button" class="btn btn-primary decimal" value="."><{$sepComma}></button>
                        <
button type="button" class="btn btn-danger all-clear" value="all-clear">AC</button>
                        <
button type="button" class="btn btn-warning equal-sign operator" value="=">=</button>
                    </
div>
                </
div>
            </
div>
            <
div class="modal-footer">
                <
button id="btnApplyResult" type="button" class="btn btn-secondary btn-success" data-dismiss="modal"><{$smarty.const._MA_WGSIMPLEACC_CALC_APPLY}></button>
            </
div>
        </
div>
    </
div>
</
div>


additional to bootstrap I have added some style:
.calculator {
        
border1px solid #ccc;
        
border-radius5px;
        
width100%;
    }
    .
calculator-screen {
        
width100%;
        
font-size5rem;
        
height80px;
        
bordernone;
        
background-color#252525;
        
color#fff;
        
text-alignright;
        
padding-right20px;
        
padding-left10px;
    }
    
button {
        
height60px;
        
font-size24px !important;
    }
    .
equal-sign {
        
height100%;
        
grid-area5;
    }
    .
equal-sign:hover {
        
background-color#4e9ed4;
    
}
    .
calculator-keys {
        
displaygrid;
        
grid-template-columnsrepeat(41fr);
        
grid-gap20px;
        
padding20px;
    }


for calculation itself I have implemented following code, which can handle click and keydown events:
const calculator = {
        
displayValue'0',
        
firstOperandnull,
        
waitingForSecondOperandfalse,
        
operatornull,
    };

    
//Manage Operators
    
const performCalculation = {
        
'+': (firstOperandsecondOperand) => firstOperand secondOperand,
        
'-': (firstOperandsecondOperand) => firstOperand secondOperand,
        
'*': (firstOperandsecondOperand) => firstOperand secondOperand,
        
'/': (firstOperandsecondOperand) => firstOperand secondOperand,
        
'=': (firstOperandsecondOperand) => secondOperand
    
};

    function 
inputDigit(digit) {
        const {
            
displayValue,
            
waitingForSecondOperand
        
} = calculator;

        if (
waitingForSecondOperand === true) {
            
calculator.displayValue digit;
            
calculator.waitingForSecondOperand false;
        } else {
            
calculator.displayValue displayValue === '0' digit displayValue digit;
        }

        
console.log(calculator);
    }

    function 
inputDecimal(dot) {
        
// If the `displayValue` does not contain a decimal point
        
if (!calculator.displayValue.includes(dot)) {
            
// Append the decimal point
            
calculator.displayValue += dot;
        }
    }

    function 
handleOperator(nextOperator) {
        const {
            
firstOperand,
            
displayValue,
            
operator
        
} = calculator
        
const inputValue parseFloat(displayValue);

        if (
operator && calculator.waitingForSecondOperand) {
            
calculator.operator nextOperator;
            
console.log(calculator);
            return;
        }

        if (
firstOperand == null) {
            
calculator.firstOperand inputValue;
        } else if (
operator) {
            const 
currentValue firstOperand || 0;
            const 
result performCalculation[operator](currentValueinputValue);

            
calculator.displayValue String(result.toFixed(2));
            
calculator.firstOperand result;
        }

        
calculator.waitingForSecondOperand true;
        
calculator.operator nextOperator;
        
console.log(calculator);
    }

    function 
updateDisplay() {
        const 
display document.querySelector('.calculator-screen');
        
display.value calculator.displayValue;
    }
    function 
resetCalculator() {
        
calculator.displayValue '0';
        
calculator.firstOperand null;
        
calculator.secondOperand null;
        
calculator.currentValue 0;
        
calculator.waitingForSecondOperand false;
    }

    
updateDisplay();

    
//code for button clicks
    
const keys document.querySelector('.calculator-keys');
    
keys.addEventListener('click', (event) => {
        const {
            
target
        
} = event;
        if (!
target.matches('button')) {
            return;
        }
        if (
target.classList.contains('operator')) {
            
handleOperator(target.value);
            
updateDisplay();
            return;
        }
        if (
target.classList.contains('decimal')) {
            
inputDecimal(target.value);
            
updateDisplay();
            return;
        }
        if (
target.classList.contains('all-clear')) {
            
resetCalculator();
            
updateDisplay();
            return;
        }
        
inputDigit(target.value);
        
updateDisplay();
    });

    
//code for keydown events
    
document.getElementById("calcModal").addEventListener('keydown', function(event) {
        var 
key event.key.toString();

        if (
key == '<{$sepComma}>') {
            
inputDecimal('.');
            
updateDisplay();
            return;
        }
        if (
key == '+' || key == '-' || key == '/' || key == '*') {
            
handleOperator(event.key);
            
updateDisplay();
            return;
        }
        if (
key == 'Enter') {
            
handleOperator('=');
            
updateDisplay();
            return;
        }
        if (
key == 'Delete') {
            
resetCalculator();
            
updateDisplay();
            return;
        }
        if (
key == '0' || key == '1' || key == '2' || key == '3' || key == '4' || key == '5' || key == '6' || key == '7' || key == '8' || key == '9') {
            
//alculator.waitingForSecondOperand = false;
            
inputDigit(event.key);
            
updateDisplay();
            return;
        }
        if (
key == '<{$sepThousand}>') {
            
//ignore thousands
            
return;
        }
        
//alert($key);
    
}, true);

    
//code for applying result to field of calling form
    
$(function () {
        $(
"#btnApplyResult").click(function () {
            const 
display document.querySelector('.calculator-screen');
            
$result display.value;
            
$result $result.replace(".""<{$sepComma}>");
            
document.getElementById("tra_amount").value $result;
        });
    });


finally in my form I added a button to call the modal form:
$traAmountTray = new XoopsFormElementTray(_MA_WGSIMPLEACC_TRANSACTION_AMOUNT'&nbsp;');
        
$traAmountTray->addElement(new XoopsFormText('''tra_amount'20150$traAmount));
        
$button = new XoopsFormButton('''calcAmount'_MA_WGSIMPLEACC_CALCULATOR);
        
$button->setExtra('onclick="$('#calcModal').modal();"');
        
$traAmountTray->addElement($button);
        
$form->addElement($traAmountTray);



have fun

2
Mamba
Re: Implement modal calculator
  • 2022/7/12 3:46

  • Mamba

  • Moderator

  • Posts: 11366

  • Since: 2004/4/23


Very cool!!!

Thank you for sharing!!!!
Support XOOPS => DONATE
Use 2.5.10 | Docs | Modules | Bugs

3
Cesagonchu
Re: Implement modal calculator

Thanks for sharing

Login

Who's Online

157 user(s) are online (54 user(s) are browsing Support Forums)


Members: 0


Guests: 157


more...

Donat-O-Meter

Stats
Goal: $100.00
Due Date: Mar 31
Gross Amount: $0.00
Net Balance: $0.00
Left to go: $100.00
Make donations with PayPal!

Latest GitHub Commits