2023-03-15 22:34:48 +00:00
|
|
|
|
import QtQuick 2.15
|
|
|
|
|
|
|
|
|
|
/// \note ensures data model always has consecutive Separator and Number after Base without duplicates except current element
|
|
|
|
|
/// \note for future work: split deleteInContent in deleteInContent and deleteElements and move data model to a DataModel object;
|
|
|
|
|
/// also fix code duplication in parseDerivationPath generating static level definitions and iterate through it
|
2023-04-05 11:10:44 +00:00
|
|
|
|
/// \note using Item to support embedded sub-components
|
2023-03-15 22:34:48 +00:00
|
|
|
|
Item {
|
|
|
|
|
id: root
|
|
|
|
|
|
|
|
|
|
required property color enabledColor
|
|
|
|
|
required property color frozenColor
|
|
|
|
|
required property color errorColor
|
2023-04-03 18:30:01 +00:00
|
|
|
|
required property color warningColor
|
2023-03-15 22:34:48 +00:00
|
|
|
|
|
|
|
|
|
/// Don't allow inserting more than \c levelsLimit Number elements
|
|
|
|
|
property int levelsLimit: 0
|
2023-05-02 08:54:10 +00:00
|
|
|
|
property bool complainTooBigAccIndex: true
|
2023-03-15 22:34:48 +00:00
|
|
|
|
|
|
|
|
|
readonly property string inputError: qsTr("Please enter numbers only")
|
|
|
|
|
readonly property string tooBigError: qsTr("Account number must be <100")
|
2023-04-03 18:30:01 +00:00
|
|
|
|
readonly property string nonEthCoinWarning: qsTr("Non-Ethereum cointype")
|
2023-03-15 22:34:48 +00:00
|
|
|
|
|
|
|
|
|
QtObject {
|
|
|
|
|
id: d
|
|
|
|
|
|
|
|
|
|
// d flag and named capture groups not supported in Qt 5.15. Use multiple regexes instead
|
2023-05-15 13:58:39 +00:00
|
|
|
|
// Captured groups: ?<coin_type_h> ?<coin_type_s> ?<account> ?<change>
|
|
|
|
|
readonly property var derivationPathRegex: /^m\/44[’|']\/?(?:(.*?)[’|'])?(.*?)(?:\/(.*?)[’|']?)?(?:\/(.*?))?((?:\/.*?)?)$/
|
2023-04-03 18:30:01 +00:00
|
|
|
|
// The expected characters before each group. Workaround to missing capture group offsets in Qt 5.15
|
|
|
|
|
readonly property var offsets: [6, 0, 2, 2]
|
|
|
|
|
|
2023-03-15 22:34:48 +00:00
|
|
|
|
readonly property int addressIndexStart: 3
|
2023-04-03 18:30:01 +00:00
|
|
|
|
readonly property int ethereumCoinType: 60
|
2023-03-15 22:34:48 +00:00
|
|
|
|
|
|
|
|
|
// Reference derivation path used to normalize separators (hardened or not). The last separator will be used
|
|
|
|
|
property var referenceElements: []
|
|
|
|
|
function initializeReferenceElementsIfRequired() {
|
|
|
|
|
if (referenceElements.length === 0) {
|
|
|
|
|
referenceElements = root.parseDerivationPath("m/44'/0'/1'/2/3")
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function createElement(content, startIndex, endIndex, contentType, isFrozen = false) {
|
|
|
|
|
return elementComponent.createObject(root, {
|
|
|
|
|
content: content,
|
|
|
|
|
startIndex: startIndex,
|
|
|
|
|
endIndex: endIndex,
|
|
|
|
|
contentType: contentType,
|
|
|
|
|
isFrozen: isFrozen});
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// Returns null if the derivationPath is invalid or an array of Element objects if derivationPath is valid
|
|
|
|
|
function parseDerivationPath(derivationPath) {
|
|
|
|
|
const matches = d.derivationPathRegex.exec(derivationPath)
|
|
|
|
|
if (matches === null) {
|
|
|
|
|
return null
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
var elements = []
|
|
|
|
|
var groupIndex = 0
|
|
|
|
|
var currentIndex = 0
|
|
|
|
|
|
2023-04-03 18:30:01 +00:00
|
|
|
|
// Extract the captured groups
|
|
|
|
|
const coin_type_hardened = matches[1]
|
|
|
|
|
const coin_type_simple = matches[2]
|
|
|
|
|
const coin_type = coin_type_hardened || coin_type_simple
|
|
|
|
|
const account = matches[3]
|
|
|
|
|
const change = matches[4]
|
|
|
|
|
const addressIndexes = matches[5] ? matches[5].substring(1) : ""; // remove the leading slash
|
|
|
|
|
|
|
|
|
|
var nextIndex = coin_type != null ? d.offsets[groupIndex] : derivationPath.length
|
2023-03-15 22:34:48 +00:00
|
|
|
|
elements.push(d.createElement(derivationPath.slice(currentIndex, nextIndex), currentIndex, nextIndex, Element.ContentType.Base))
|
|
|
|
|
|
2023-04-03 18:30:01 +00:00
|
|
|
|
if (coin_type != null && nextIndex < derivationPath.length) {
|
2023-03-15 22:34:48 +00:00
|
|
|
|
currentIndex = nextIndex
|
|
|
|
|
nextIndex = currentIndex + coin_type.length
|
|
|
|
|
elements.push(d.createElement(coin_type, currentIndex, nextIndex, Element.ContentType.Number))
|
2023-04-03 18:30:01 +00:00
|
|
|
|
groupIndex += 2
|
|
|
|
|
|
|
|
|
|
if(coin_type_simple && derivationPath.length > nextIndex) {
|
|
|
|
|
return null
|
|
|
|
|
}
|
2023-03-15 22:34:48 +00:00
|
|
|
|
|
2023-04-03 18:30:01 +00:00
|
|
|
|
// Standard separator if there is an account otherwise keep the rest
|
2023-03-15 22:34:48 +00:00
|
|
|
|
currentIndex = nextIndex
|
2023-04-03 18:30:01 +00:00
|
|
|
|
nextIndex = (account != null ? currentIndex + d.offsets[groupIndex] : derivationPath.length)
|
|
|
|
|
if(currentIndex < nextIndex) {
|
|
|
|
|
elements.push(d.createElement(derivationPath.slice(currentIndex, nextIndex), currentIndex, nextIndex, Element.ContentType.Separator))
|
|
|
|
|
}
|
2023-03-15 22:34:48 +00:00
|
|
|
|
|
|
|
|
|
if(account != null) {
|
|
|
|
|
currentIndex = nextIndex
|
|
|
|
|
nextIndex = currentIndex + account.length
|
|
|
|
|
elements.push(d.createElement(account, currentIndex, nextIndex, Element.ContentType.Number))
|
|
|
|
|
groupIndex++
|
|
|
|
|
|
|
|
|
|
currentIndex = nextIndex
|
2023-04-03 18:30:01 +00:00
|
|
|
|
nextIndex = (change != null ? currentIndex + d.offsets[groupIndex] : derivationPath.length)
|
|
|
|
|
if(currentIndex < nextIndex) {
|
|
|
|
|
elements.push(d.createElement(derivationPath.slice(currentIndex, nextIndex), currentIndex, nextIndex, Element.ContentType.Separator))
|
|
|
|
|
}
|
2023-03-15 22:34:48 +00:00
|
|
|
|
|
|
|
|
|
if(change != null) {
|
|
|
|
|
currentIndex = nextIndex
|
|
|
|
|
nextIndex = currentIndex + change.length
|
|
|
|
|
elements.push(d.createElement(change, currentIndex, nextIndex, Element.ContentType.Number))
|
|
|
|
|
|
|
|
|
|
// Check if there are any address indexes
|
2023-04-03 18:30:01 +00:00
|
|
|
|
if (matches[5] != null && matches[5].length > 0) {
|
2023-03-15 22:34:48 +00:00
|
|
|
|
const addressIndexesParts = addressIndexes.split('/')
|
|
|
|
|
for (const addressIndex of addressIndexesParts) {
|
|
|
|
|
currentIndex = nextIndex
|
|
|
|
|
nextIndex = currentIndex + 1
|
|
|
|
|
elements.push(d.createElement(derivationPath.slice(currentIndex, nextIndex), currentIndex, nextIndex, Element.ContentType.Separator))
|
|
|
|
|
|
|
|
|
|
currentIndex = nextIndex
|
|
|
|
|
nextIndex = currentIndex + addressIndex.length
|
|
|
|
|
elements.push(d.createElement(addressIndex, currentIndex, nextIndex, Element.ContentType.Number))
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
} else if(addressIndexes.length > 0) {
|
|
|
|
|
return null
|
|
|
|
|
}
|
|
|
|
|
} else if(change || addressIndexes.length > 0) {
|
|
|
|
|
return null
|
|
|
|
|
}
|
|
|
|
|
} else if(account || change || addressIndexes.length > 0) {
|
|
|
|
|
return null
|
|
|
|
|
}
|
|
|
|
|
return elements
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function generateHtmlFromElements(elements) {
|
2023-04-03 18:30:01 +00:00
|
|
|
|
// d class is disabled; e class is editable; f class is error; w class is warning
|
|
|
|
|
var res = `<style>.d{color:${root.frozenColor};}.e{color:${root.enabledColor};}.f{color:${root.errorColor};}.w{color:${root.warningColor};}</style>`
|
2023-03-15 22:34:48 +00:00
|
|
|
|
const format = (content, cssClass) => `<span class="${cssClass}">${content}</span>`
|
|
|
|
|
|
|
|
|
|
var numberLevel = 0
|
|
|
|
|
for(var i = 0; i < elements.length; i++) {
|
|
|
|
|
if (elements[i].isFrozen) {
|
|
|
|
|
res += format(elements[i].content, "d")
|
2023-04-03 18:30:01 +00:00
|
|
|
|
} else if(validateElement(elements[i], elements[i].isNumber() ? numberLevel : -1).error.length > 0) {
|
2023-03-15 22:34:48 +00:00
|
|
|
|
res += format(elements[i].content, "f")
|
2023-04-03 18:30:01 +00:00
|
|
|
|
} else if(validateElement(elements[i], elements[i].isNumber() ? numberLevel : -1).warning.length > 0) {
|
|
|
|
|
res += format(elements[i].content, "w")
|
2023-03-15 22:34:48 +00:00
|
|
|
|
} else {
|
|
|
|
|
res += format(elements[i].content, "e")
|
|
|
|
|
}
|
|
|
|
|
if(elements[i].isNumber()) {
|
|
|
|
|
numberLevel++
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return res
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Component {
|
|
|
|
|
id: completedDerivationPathComponent
|
|
|
|
|
QtObject {
|
|
|
|
|
required property var elements
|
|
|
|
|
required property string errorMessage
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// Matches the derivation path with a base path and freezes the base path elements
|
|
|
|
|
/// It also completes last separator and content if needed
|
|
|
|
|
/// \return CompletedDerivationPath
|
|
|
|
|
function completeDerivationPath(basePath, derivationPath) {
|
|
|
|
|
const errorResponse = () => {
|
|
|
|
|
const res = completedDerivationPathComponent.createObject(root, {
|
|
|
|
|
elements: [],
|
|
|
|
|
errorMessage: root.inputError
|
|
|
|
|
})
|
|
|
|
|
return res
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const baseElements = root.parseDerivationPath(basePath)
|
|
|
|
|
if (!baseElements) {
|
|
|
|
|
console.info(`Invalid base of derivation path: ${basePath}`)
|
|
|
|
|
return errorResponse()
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
var elements = root.parseDerivationPath(derivationPath)
|
|
|
|
|
if (!elements) {
|
|
|
|
|
console.info(`Invalid derivation path: ${derivationPath}`)
|
|
|
|
|
return errorResponse()
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if(baseElements.length > elements.length) {
|
|
|
|
|
console.info(`Base path elements length (${baseElements.length}) bigger than path length (${elements.length})`)
|
|
|
|
|
return errorResponse()
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
for(const i in elements) {
|
|
|
|
|
if(i < baseElements.length) {
|
|
|
|
|
if(!baseElements[i].isSimilar(elements[i])) {
|
|
|
|
|
console.warn(`Base content "${baseElements[i].content}" doesn't match derivation path content "${elements[i].content}" for index ${i}`)
|
|
|
|
|
return errorResponse()
|
|
|
|
|
}
|
|
|
|
|
elements[i].isFrozen = true
|
|
|
|
|
} else {
|
|
|
|
|
elements[i].isFrozen = !elements[i].isNumber()
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if(elements[elements.length - 1].isBase()
|
|
|
|
|
&& (elements[elements.length - 1].content.slice(-1) === "'" || elements[elements.length - 1].content.slice(-1) === "’")) {
|
|
|
|
|
elements[elements.length - 1].content += "/"
|
|
|
|
|
}
|
|
|
|
|
if(elements[elements.length - 1].isSeparator() || elements[elements.length - 1].isBase()) {
|
|
|
|
|
elements.push(d.createElement("", elements[elements.length - 1].endIndex, elements[elements.length - 1].endIndex, Element.ContentType.Number))
|
|
|
|
|
}
|
|
|
|
|
normalizeAndRemoveDuplicateSeparators(elements, elements.length - 1)
|
|
|
|
|
|
|
|
|
|
let res = completedDerivationPathComponent.createObject(root, {
|
|
|
|
|
elements: elements,
|
|
|
|
|
errorMessage: ""
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
return res
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// \return true if an element was added
|
|
|
|
|
function tryAddAndFixSeparators(elements, insertIndex, insertLeft = false) {
|
|
|
|
|
if(root.levelsLimit > 0 && countNonEmptyLevels(elements) >= root.levelsLimit) {
|
|
|
|
|
return -1
|
|
|
|
|
}
|
|
|
|
|
return addAndFixSeparators(elements, insertIndex, insertLeft)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// \return the newly created element's index or -1 if no element was created
|
|
|
|
|
function addAndFixSeparators(elements, insertIndex, insertLeft = false) {
|
|
|
|
|
var finalInsertIndex = insertIndex
|
|
|
|
|
var newContentIndex = 0
|
|
|
|
|
if(insertLeft) {
|
|
|
|
|
while(finalInsertIndex >= 0 && elements[finalInsertIndex].isFrozen) {
|
|
|
|
|
finalInsertIndex--
|
|
|
|
|
}
|
|
|
|
|
if(finalInsertIndex >= 0) {
|
|
|
|
|
newContentIndex = finalInsertIndex
|
|
|
|
|
elements.splice(newContentIndex, 0, d.createElement("", elements[finalInsertIndex - 1].endIndex, elements[finalInsertIndex - 1].endIndex, Element.ContentType.Number))
|
|
|
|
|
elements.splice(finalInsertIndex + 1, 0, d.createElement("/", elements[finalInsertIndex].endIndex, elements[finalInsertIndex].endIndex + 1, Element.ContentType.Separator, true))
|
|
|
|
|
} else {
|
|
|
|
|
insertLeft = false
|
|
|
|
|
finalInsertIndex = insertIndex
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if(!insertLeft) {
|
|
|
|
|
while(finalInsertIndex < elements.length && !elements[finalInsertIndex].isFrozen) {
|
|
|
|
|
finalInsertIndex++
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
elements.splice(finalInsertIndex, 0, d.createElement("/", elements[finalInsertIndex - 1].endIndex, elements[finalInsertIndex - 1].endIndex + 1, Element.ContentType.Separator, true))
|
|
|
|
|
newContentIndex = finalInsertIndex + 1
|
|
|
|
|
elements.splice(newContentIndex, 0, d.createElement("", elements[finalInsertIndex].endIndex, elements[finalInsertIndex].endIndex, Element.ContentType.Number))
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
normalizeAndRemoveDuplicateSeparators(elements, newContentIndex)
|
|
|
|
|
return findFirstEmptyContent(elements)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function insertContent(elements, elementIndex, text, cursorPos) {
|
|
|
|
|
while(elementIndex < (elements.length - 1) && (!elements[elementIndex].isNumber() || elements[elementIndex].isFrozen)) {
|
|
|
|
|
elementIndex++
|
|
|
|
|
}
|
|
|
|
|
if(cursorPos < elements[elementIndex].startIndex)
|
|
|
|
|
cursorPos = elements[elementIndex].endIndex
|
|
|
|
|
const element = elements[elementIndex]
|
|
|
|
|
const insertIdx = cursorPos - element.startIndex
|
|
|
|
|
element.content = element.content.slice(0, insertIdx) + text + element.content.slice(insertIdx)
|
|
|
|
|
element.endIndex += text.length
|
|
|
|
|
controller.updateFollowingIndices(elements, elementIndex)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// \return cursor offset
|
|
|
|
|
function deleteInContent(elements, elementIndex, cursorPos, deleteRightOfCursor = true) {
|
|
|
|
|
const element = elements[elementIndex]
|
|
|
|
|
var deleteIdx = -1 // Also marks content change
|
|
|
|
|
var cursorOffset = 0
|
|
|
|
|
var startOfIndicesUpdate = elementIndex
|
|
|
|
|
if(deleteRightOfCursor) {
|
|
|
|
|
if (cursorPos === element.endIndex) {
|
|
|
|
|
// If at the end of the content delete next separator and merge content
|
|
|
|
|
if((elementIndex + 2) < elements.length && elements[elementIndex + 1].isSeparator() && !elements[elementIndex + 2].isFrozen) {
|
|
|
|
|
const newContent = element.content + elements[elementIndex + 2].content
|
|
|
|
|
elements.splice(elementIndex + 1, 2)
|
|
|
|
|
element.content = newContent
|
|
|
|
|
startOfIndicesUpdate = elementIndex
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
deleteIdx = cursorPos - element.startIndex
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
if (cursorPos === element.startIndex) {
|
|
|
|
|
// If at content's beginning delete left separator and merge content
|
|
|
|
|
var deletedChars = 0
|
|
|
|
|
if((elementIndex - 2) > 0 && elements[elementIndex - 1].isSeparator() && !elements[elementIndex - 2].isFrozen) {
|
|
|
|
|
const newContent = elements[elementIndex - 2].content + element.content
|
|
|
|
|
cursorOffset = -(elements[elementIndex - 1].content.length)
|
|
|
|
|
elements.splice(elementIndex - 2, 2)
|
|
|
|
|
element.content = newContent
|
|
|
|
|
startOfIndicesUpdate = elementIndex - 2
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
deleteIdx = cursorPos - element.startIndex - 1
|
|
|
|
|
cursorOffset = -1
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if(deleteIdx > -1) {
|
|
|
|
|
element.content = element.content.slice(0, deleteIdx) + element.content.slice(deleteIdx + 1)
|
|
|
|
|
element.endIndex -= 1
|
|
|
|
|
}
|
|
|
|
|
controller.updateFollowingIndices(elements, startOfIndicesUpdate)
|
|
|
|
|
return cursorOffset
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function countNonEmptyLevels(elements) {
|
|
|
|
|
var count = 0
|
|
|
|
|
for(var i = 0; i < (elements.length-1); i++) {
|
|
|
|
|
if((elements[i].isSeparator() || elements[i].isBase()) && elements[i + 1].isNumber() && !elements[i + 1].isEmptyNumber()) {
|
|
|
|
|
count++
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return count
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function normalizeAndRemoveDuplicateSeparators(elements, exceptIndex) {
|
|
|
|
|
var currentContent = ""
|
|
|
|
|
|
|
|
|
|
var markToDelete = []
|
|
|
|
|
for(var i = 0; i < (elements.length - 1); i++) {
|
|
|
|
|
if(elements[i].isEmptyNumber() && elements[i+1].isSeparator() && i !== exceptIndex) {
|
|
|
|
|
markToDelete.push(i)
|
|
|
|
|
markToDelete.push(i + 1)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
// Cleanup the last separator if it is the case
|
|
|
|
|
if(elements.length > 2 && elements[elements.length - 2].isSeparator() && elements[elements.length - 1].isEmptyNumber() && (elements.length - 1) !== exceptIndex) {
|
|
|
|
|
markToDelete.push(elements.length - 2)
|
|
|
|
|
markToDelete.push(elements.length - 1)
|
|
|
|
|
}
|
|
|
|
|
for (var i = markToDelete.length - 1; i >= 0; i--) {
|
|
|
|
|
elements.splice(markToDelete[i], 1)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
d.initializeReferenceElementsIfRequired()
|
|
|
|
|
// Normalize separators
|
|
|
|
|
for(var i = 0; i < elements.length; i++) {
|
|
|
|
|
if(i < d.referenceElements.length && d.referenceElements[i].isSeparator()) {
|
|
|
|
|
currentContent = d.referenceElements[i].content
|
|
|
|
|
} // else: use the last separator
|
|
|
|
|
|
|
|
|
|
if(elements[i].isSeparator() && currentContent.length > 0 && elements[i].content !== currentContent) {
|
|
|
|
|
elements[i].content = currentContent
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
updateFollowingIndices(elements, 0)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function updateFollowingIndices(elements, firstElementIndex) {
|
|
|
|
|
for(var i = firstElementIndex; i < elements.length; i++) {
|
|
|
|
|
if(i == 0) {
|
|
|
|
|
elements[i].startIndex = 0
|
|
|
|
|
} else {
|
|
|
|
|
elements[i].startIndex = elements[i - 1].endIndex
|
|
|
|
|
}
|
|
|
|
|
elements[i].endIndex = elements[i].startIndex + elements[i].content.length
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function findFirstEmptyContent(elements) {
|
|
|
|
|
for(var i = 0; i < elements.length; i++) {
|
|
|
|
|
if(elements[i].content.length === 0) {
|
|
|
|
|
return i
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return -1
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function deleteFromStartToEnd(elements, startPos, endPos) {
|
|
|
|
|
var startIndex = -1
|
|
|
|
|
var endIndex = -1
|
|
|
|
|
for(var i = 0; i < elements.length; i++) {
|
|
|
|
|
if(startIndex == -1 && startPos >= elements[i].startIndex) {
|
|
|
|
|
startIndex = i
|
|
|
|
|
} else if(endIndex == -1 && endPos <= elements[i].startIndex) {
|
|
|
|
|
endIndex = i
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
elements.splice(startIndex, endIndex - startIndex)
|
|
|
|
|
updateFollowingIndices(elements, 0)
|
|
|
|
|
}
|
|
|
|
|
|
2023-04-03 18:30:01 +00:00
|
|
|
|
/// \return the object {error: "", warning: ""}
|
2023-03-15 22:34:48 +00:00
|
|
|
|
function validateAllElements(elements) {
|
|
|
|
|
var numberLevel = 0
|
2023-04-03 18:30:01 +00:00
|
|
|
|
var warningMessage = ""
|
2023-03-15 22:34:48 +00:00
|
|
|
|
for(var i = 0; i < elements.length; i++) {
|
2023-04-03 18:30:01 +00:00
|
|
|
|
const res = validateElement(elements[i], elements[i].isNumber() ? numberLevel : -1)
|
|
|
|
|
if(res.error.length > 0) {
|
|
|
|
|
return res
|
|
|
|
|
} else if(res.warning.length > 0 && warningMessage === "") {
|
|
|
|
|
warningMessage = res.warning
|
2023-03-15 22:34:48 +00:00
|
|
|
|
}
|
|
|
|
|
if(elements[i].isNumber()) {
|
|
|
|
|
numberLevel++
|
|
|
|
|
}
|
|
|
|
|
}
|
2023-04-03 18:30:01 +00:00
|
|
|
|
return {error: "", warning: warningMessage}
|
2023-03-15 22:34:48 +00:00
|
|
|
|
}
|
|
|
|
|
|
2023-04-03 18:30:01 +00:00
|
|
|
|
/// Expect -1 if not an number element
|
|
|
|
|
/// \return the object {error: "", warning: ""}
|
2023-03-15 22:34:48 +00:00
|
|
|
|
function validateElement(element, numberLevel) {
|
2023-04-03 18:30:01 +00:00
|
|
|
|
if(numberLevel > -1 && !element.validateNumber() && !element.isEmptyNumber()) {
|
|
|
|
|
return {error: root.inputError, warning: ""}
|
|
|
|
|
} else if(numberLevel == 0 && !element.isEmptyNumber() && element.number() != d.ethereumCoinType) {
|
|
|
|
|
return {error: "", warning: root.nonEthCoinWarning}
|
2023-05-02 08:54:10 +00:00
|
|
|
|
} else if(root.complainTooBigAccIndex && numberLevel >= d.addressIndexStart && element.number() >= 100) {
|
2023-04-03 18:30:01 +00:00
|
|
|
|
return {error: root.tooBigError, warning: ""}
|
2023-03-15 22:34:48 +00:00
|
|
|
|
}
|
2023-04-03 18:30:01 +00:00
|
|
|
|
return {error: "", warning: ""}
|
2023-03-15 22:34:48 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Component {
|
|
|
|
|
id: elementComponent
|
|
|
|
|
Element {
|
|
|
|
|
content: ""
|
|
|
|
|
startIndex: 0
|
|
|
|
|
endIndex: 0
|
|
|
|
|
contentType: 0
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|