Let's understand this. In the result data, we break down the data into its constituent symbols, then get the last symbol from the result data, and delete it from the result data, to have one less of the operation.
However, since there are some operations we added with "(", we have to remove two symbols in such.
Let's work on it now in App.vue in the clearScreen function:
const clearScreen = () => { if (result.value) { let index; const escaped = buttons.map( (s) => s.replace(/[.*+?^${}()|[\]\\]/g, '\\$&') ).join('|') const allMatch = new RegExp(`(${escaped})`, 'g') const all = (result.value as string).match(allMatch) const lastSymbol = all?.slice(-1)[0] if (lastSymbol){ index = result.value.lastIndexOf(lastSymbol) if (lastSymbol == "("){ index = result.value.lastIndexOf(all?.slice(-2, -1)[0]) } result.value = result.value.slice(0, index) if (result.value == "") result.value = undefined } }}
Sup powers
All along, we've being rendered result data on screen using Moustache syntax, but in order to render html, we will need to transform rendering to v-html in AppScreen...
Now, on clicking xy button, we'll do two things for display: 1~ introduce and toggle superscript flag 2~ during calculation, replace the sup tags with **( )
Note: Minor change to basicMatch regex in buttonAction in AppButtons component for point to work. Also, I'm removing / from the pattern since it will match the / in </sup> hence assign it a wrong conditionality, and also since / is not a symbol in the buttons.
const basicMatch = /[+\-()÷%×πe\.\d]/g
Clicking on xy, in buttonAction, we invoke supOps emitter.
In App.vue, let's first initialize the superscript variable.
const superscript = ref(false)
When supOps listener is triggered, call updateScreenSup. This will open the <sup> tag, and then set superscript flag to true so that every value after that will be a power.
When xy is clicked again, close the result data with </sup> then set flag to false.
On setting powers without unsetting, for instance, data like 8<sup>2, or even 5log(100, without actually setting the close tags, eval would break.
We need to write a function that corrects for that, even for nested operations like, sqrt(4<sup>2</sup>-5<sup>3</sup> ~ sqrt(42-53, missing the ending ),
To fix for this, we use the function below,
function correctSup(str: string): string { if (str.slice(-1) == "(") str += "1)" if (str.slice(-5) == "<sup>") str += "1</sup>" const pattern = /\(|<sup>|\)|<\/sup>/g let matches = str.match(pattern) if (matches !== null) { if (matches.length % 2 === 0) return str let counts_sup = matches!.filter((x: string) => ["<sup>", "</sup>"].includes(x)).length if (counts_sup % 2 !== 0) return str += "</sup>" else return str += ")" } else { return str }}
Let's explain the function above. First of all, we fix for errors that might arise due to incomplete closing tags such as 8*5( and 5<sup>. Next, we look for the symbols, (, ), <sup>, </sup> in the result and store in matches.
Matches not being null, we assume if there's evenness, then all tags match.
Otherwise, we look for a pair of tags that are not even, then correct for that to solve for the incomplete tags.