Merge pull request #1 from ranchimall/master

latest changes
This commit is contained in:
sairaj mote 2020-09-11 16:11:39 +05:30 committed by GitHub
commit 4aa79b9eb9
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

View File

@ -731,6 +731,20 @@
border: 0.1rem solid rgba(var(--rgb-bw), 0.2); border: 0.1rem solid rgba(var(--rgb-bw), 0.2);
padding: 0.1rem; padding: 0.1rem;
} }
#sheet-view input {
border-radius: 0.2rem;
border: 0.1rem solid rgba(var(--rgb-bw), 0.2);
padding: 0.1rem;
}
#sheet-view .log-input {
width: 100%;
}
#sheet-view .grade-input {
width: 2rem;
}
</style> </style>
<script id="floGlobals"> <script id="floGlobals">
@ -912,7 +926,7 @@
<textarea name="writers" placeholder="Writers** [line separated]"></textarea></div> <textarea name="writers" placeholder="Writers** [line separated]"></textarea></div>
<div class="input-container i-1"><textarea name="columns" placeholder="Columns* [line separated]" <div class="input-container i-1"><textarea name="columns" placeholder="Columns* [line separated]"
required></textarea></div> required></textarea></div>
<span class="asterisk-notation">*Required<br />**(Blank field) Default subAdmin</span> <span class="asterisk-notation">*Required<br />**(Blank field) = Default subAdmin, ('Public') = Public sheet</span>
<div class="input-container i-2"> <div class="input-container i-2">
<input type="submit" value="Create" /> <input type="submit" value="Create" />
<input type="reset" value="Reset" /> <input type="reset" value="Reset" />
@ -973,8 +987,9 @@
<button id="view-group-by">Groupby</button> <button id="view-group-by">Groupby</button>
<h5 class="margin">*Press ENTER to save your edit.</h5> <h5 class="margin">*Press ENTER to save your edit.</h5>
</div> </div>
<form class="table-container" id="sheet-view" onsubmit="enterLog(); return false;"></form> <div class="table-container" id="sheet-view"></div>
<button type="submit" form="sheet-view" style="display: none;"></button> <form id="new-log" style="display: none;" onsubmit="enterLog(); return false;"></form>
<button type="submit" form="new-log" style="display: none;"></button>
</div> </div>
</div> </div>
@ -1052,22 +1067,20 @@
}) })
document.getElementById('group-by-menu').children[0].addEventListener("change", function (e) { document.getElementById('group-by-menu').children[0].addEventListener("change", function (e) {
try { try {
let title = document.getElementById("sheet-details").children[0].textContent; let title = document.getElementById("sheet-details").children[0].textContent;
let sheet = JSON.parse(document.getElementById("sheet-details").dataset.sheet);
let type = this.value; let type = this.value;
if (type === 'count') { if (type === 'count') {
this.nextSibling.classList.add("hide") this.nextSibling.classList.add("hide")
let data = logSheet.groupLogsBy.count(title) let data = logSheet.groupLogsBy.count(title, sheet)
renderGroupByView("count", data) renderGroupByView("count", data)
} else { } else {
this.nextSibling.classList.remove("hide") this.nextSibling.classList.remove("hide")
let column = this.nextSibling.value; let column = this.nextSibling.value;
let data = logSheet.groupLogsBy[type](title, column); let data = logSheet.groupLogsBy[type](title, sheet, column);
renderGroupByView(`${type}(${column})`, data) renderGroupByView(`${type}(${column})`, data)
} }
} catch (error) { } catch (error) {
showMessage(error, "error") showMessage(error, "error")
} }
@ -1076,16 +1089,16 @@
document.getElementById('group-by-menu').children[1].addEventListener("change", function (e) { document.getElementById('group-by-menu').children[1].addEventListener("change", function (e) {
try { try {
let title = document.getElementById("sheet-details").children[0].textContent; let title = document.getElementById("sheet-details").children[0].textContent;
let sheet = JSON.parse(document.getElementById("sheet-details").dataset.sheet);
let type = this.previousSibling.value; let type = this.previousSibling.value;
let column = this.value; let column = this.value;
let data = logSheet.groupLogsBy[type](title, column); let data = logSheet.groupLogsBy[type](title, sheet, column);
renderGroupByView(`${type}(${column})`, data) renderGroupByView(`${type}(${column})`, data)
} catch (error) { } catch (error) {
showMessage(error, "error") showMessage(error, "error")
} }
}) })
function removeElement(element) { function removeElement(element) {
element.parentNode.removeChild(element); element.parentNode.removeChild(element);
} }
@ -1189,10 +1202,12 @@
let description = form.description.value.trim(); let description = form.description.value.trim();
let columns = form.columns.value.trim().split('\n'); let columns = form.columns.value.trim().split('\n');
let writers = form.writers.value.trim(); let writers = form.writers.value.trim();
if (writers === '') if(writers === '')
writers = floGlobals.subAdmins writers = floGlobals.subAdmins;
else if(writers.toUpperCase() === 'PUBLIC')
writers = null;
else else
writers = writers.split('\n') writers = writers.split('\n').filter(i => floCrypto.validateAddr(i))
logSheet.createNewSheet(title, description, columns, writers) logSheet.createNewSheet(title, description, columns, writers)
renderSheetList([title]) renderSheetList([title])
form.reset() form.reset()
@ -1204,7 +1219,7 @@
} }
function copyToLogInput(floID) { function copyToLogInput(floID) {
let input = document.forms['sheet-view'][0] let input = document.forms['new-log'][0]
if (input.tagName === 'INPUT') if (input.tagName === 'INPUT')
input.value = floID; input.value = floID;
console.log(floID, input) console.log(floID, input)
@ -1212,7 +1227,7 @@
function enterLog() { function enterLog() {
let title = document.getElementById("sheet-details").children[0].textContent; let title = document.getElementById("sheet-details").children[0].textContent;
let form = document.forms['sheet-view'], let form = document.forms['new-log'],
allFormElements = form.querySelectorAll('input') allFormElements = form.querySelectorAll('input')
allFormElements.forEach(element => element.disabled = true) allFormElements.forEach(element => element.disabled = true)
if (form[0].tagName === 'INPUT') { if (form[0].tagName === 'INPUT') {
@ -1225,9 +1240,9 @@
form.reset(); form.reset();
showMessage('Log Entry Successful') showMessage('Log Entry Successful')
let row = document.getElementById("sheet-view").getElementsByTagName("tbody")[0].insertRow(1); let row = document.getElementById("sheet-view").getElementsByTagName("tbody")[0].insertRow(1);
row.insertCell(0).textContent = floID row.insertCell().textContent = floID
for (let k = 0; k < log.length; k++) row.insertCell().innerHTML = `<input type="text" class="grade-input" disabled>`
row.insertCell(k + 1).textContent = log[k] log.forEach(l => row.insertCell().textContent = l)
}).catch(error => { }).catch(error => {
showMessage(error, "error") showMessage(error, "error")
allFormElements.forEach(element => element.disabled = false) allFormElements.forEach(element => element.disabled = false)
@ -1239,7 +1254,7 @@
logSheet.refreshLogs(title).then(result => { logSheet.refreshLogs(title).then(result => {
let data = logSheet.viewLogs(title) let data = logSheet.viewLogs(title)
renderSheetView(data.title, data.description, data.editors, data.attributes, data.sheet, renderSheetView(data.title, data.description, data.editors, data.attributes, data.sheet,
data.editors? data.editors.includes(myFloID) : true) !data.editors || data.editors.includes(myFloID), floGlobals.subAdmins.includes(myFloID))
}).catch(error => showMessage(error, "error")) }).catch(error => showMessage(error, "error"))
} }
@ -1281,38 +1296,63 @@
}) })
} }
function renderSheetView(title, description, editors, attributes, sheet, isWriteable) { function renderSheetView(title, description, editors, attributes, sheet, isWriteable, isSubAdmin) {
const parseVectorClock = (vc) => { const parseVectorClock = (vc) => {
vc = vc.split('_') vc = vc.split('_')
console.log(vc)
let time = new Date(parseInt(vc[0])).toString().slice(4, 24); let time = new Date(parseInt(vc[0])).toString().slice(4, 24);
let floID = vc[1] let floID = vc[1]
return `by ${floID} (${time})` return `by ${floID} (${time})`
} }
const createGradeField = (vc, grade) => {
let gradeField = document.createElement("input")
gradeField.setAttribute("type", "text")
gradeField.className = "grade-input"
gradeField.value = grade
if(!isWriteable || !isSubAdmin || vc.split('_')[1] == myFloID)
gradeField.disabled = true;
else{
gradeField.addEventListener("keypress", (event) => {
if (event.keyCode == 13){
event.preventDefault();
gradeField.disabled = true;
logSheet.forwardLog(title, vc, gradeField.value)
.then(result => showMessage("Graded Log"))
.catch(error => showMessage("Grading failed: "+error, "error"))
.finally(_=> gradeField.disabled = false)
}
})
}
return gradeField
}
//Add Sheet Details //Add Sheet Details
let sheetDetails = document.getElementById("sheet-details") let sheetDetails = document.getElementById("sheet-details")
sheetDetails.classList.remove("hide") sheetDetails.classList.remove("hide")
sheetDetails.children[0].textContent = title; sheetDetails.children[0].textContent = title;
sheetDetails.children[1].textContent = editors || "Public"; sheetDetails.children[1].textContent = editors || "Public";
sheetDetails.children[2].textContent = description; sheetDetails.children[2].textContent = description;
sheetDetails.dataset.sheet = JSON.stringify(sheet);
//Create and add the sheet table //Create and add the sheet table
let table = document.createElement("table") let table = document.createElement("table")
let thead = table.createTHead() let thead = table.createTHead()
let head = thead.insertRow(0) let head = thead.insertRow(0)
head.insertCell(0).textContent = "FLO ID" head.insertCell().textContent = "FLO ID";
head.insertCell().textContent = "Grade";
attributes.forEach(a => head.insertCell().textContent = a) attributes.forEach(a => head.insertCell().textContent = a)
let tbody = document.createElement("tbody") let tbody = document.createElement("tbody")
sheet.forEach(data => { sheet.forEach(data => {
let row = tbody.insertRow(0); let row = tbody.insertRow(0);
row.setAttribute("title", parseVectorClock(data.vc)) row.setAttribute("title", parseVectorClock(data.vc))
row.insertCell(0).textContent = data.floID row.insertCell().textContent = data.floID
row.insertCell().appendChild(createGradeField(data.vc, data.grade));
data.log.forEach(l => row.insertCell().textContent = l) data.log.forEach(l => row.insertCell().textContent = l)
}) })
//Add input fields if writable //Add input fields if writable
if (isWriteable) { if (isWriteable) {
let row = tbody.insertRow(0); let row = tbody.insertRow(0);
row.insertCell(0).innerHTML = `<input type="text">`; row.insertCell().innerHTML = `<input form="new-log" class="log-input" type="text">`;
attributes.forEach(a => row.insertCell().innerHTML = `<input type="text">`); row.insertCell().textContent = ``;
attributes.forEach(a => row.insertCell().innerHTML = `<input form="new-log" class="log-input" type="text">`);
} }
table.appendChild(tbody); table.appendChild(tbody);
clearElement(document.getElementById("sheet-view")).appendChild(table); clearElement(document.getElementById("sheet-view")).appendChild(table);
@ -1345,19 +1385,23 @@
} }
function sortTable(table, n) { function sortTable(table, n) {
console.log(table, n)
let dir = "DESC"; let dir = "DESC";
let flag = false; let flag = false;
let startRow = (table.getElementsByTagName("INPUT").length === 0) ? 1 : 2 let startRow = (table.getElementsByClassName("log-input").length === 0) ? 1 : 2
while (true) { while (true) {
let rows = table.rows; let rows = table.rows;
let swapIndex = false; let swapIndex = false;
console.log(rows)
for (let i = startRow; i < rows.length - 1; i++) { for (let i = startRow; i < rows.length - 1; i++) {
let x = rows[i].getElementsByTagName("TD")[n].textContent; let x, y, x_, y_;
let y = rows[i + 1].getElementsByTagName("TD")[n].textContent; if(n === 1){
let x_ = parseFloat(x) x = rows[i].getElementsByTagName("TD")[n].children[0].value;
let y_ = parseFloat(y) y = rows[i + 1].getElementsByTagName("TD")[n].children[0].value;
} else {
x = rows[i].getElementsByTagName("TD")[n].textContent;
y = rows[i + 1].getElementsByTagName("TD")[n].textContent;
}
x_ = parseFloat(x)
y_ = parseFloat(y)
if (isNaN(x_) || isNaN(y_)) { if (isNaN(x_) || isNaN(y_)) {
x_ = x.toLowerCase() x_ = x.toLowerCase()
y_ = y.toLowerCase() y_ = y.toLowerCase()
@ -8555,10 +8599,10 @@ Bitcoin.Util = {
//Returns public-key from private-key //Returns public-key from private-key
getPubKeyHex: function (privateKeyHex) { getPubKeyHex: function (privateKeyHex) {
if(!privateKeyHex) if (!privateKeyHex)
return null; return null;
var key = new Bitcoin.ECKey(privateKeyHex); var key = new Bitcoin.ECKey(privateKeyHex);
if (key.priv == null) if (key.priv == null)
return null; return null;
key.setCompressed(true); key.setCompressed(true);
var pubkeyHex = key.getPubKeyHex(); var pubkeyHex = key.getPubKeyHex();
@ -8572,7 +8616,7 @@ Bitcoin.Util = {
var floID = key.getBitcoinAddress(); var floID = key.getBitcoinAddress();
return floID; return floID;
} catch (e) { } catch (e) {
console.error(e); return null;
} }
}, },
@ -8860,7 +8904,7 @@ Bitcoin.Util = {
invalids.InvalidSenderPrivKeys.push(key); invalids.InvalidSenderPrivKeys.push(key);
else { else {
if (typeof senderPrivKeys[key] !== 'number' || senderPrivKeys[ if (typeof senderPrivKeys[key] !== 'number' || senderPrivKeys[
key] <= 0) key] <= 0)
invalids.InvalidSenderAmountFor.push(key) invalids.InvalidSenderAmountFor.push(key)
else else
inputVal += senderPrivKeys[key]; inputVal += senderPrivKeys[key];
@ -9097,7 +9141,7 @@ Bitcoin.Util = {
return nodeIdNewInt8Array; return nodeIdNewInt8Array;
}, },
launch: function (superNodeList = Object.keys(floGlobals.supernodes), master_floID = floGlobals launch: function (superNodeList = Object.keys(floGlobals.supernodes), master_floID = floGlobals
.adminID) { .adminID) {
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
try { try {
const SuKBucketId = this.floIdToKbucketId(master_floID); const SuKBucketId = this.floIdToKbucketId(master_floID);
@ -10014,8 +10058,9 @@ Bitcoin.Util = {
//send General Data //send General Data
sendGeneralData: function (message, type, options = {}) { sendGeneralData: function (message, type, options = {}) {
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
if(options.encrypt){ if (options.encrypt) {
let encryptionKey = (options.encrypt === true) ? floGlobals.settings.encryptionKey : options.encrypt let encryptionKey = (options.encrypt === true) ? floGlobals.settings.encryptionKey :
options.encrypt
message = floCrypto.encryptData(JSON.stringify(message), encryptionKey) message = floCrypto.encryptData(JSON.stringify(message), encryptionKey)
} }
this.sendApplicationData(message, type, options) this.sendApplicationData(message, type, options)
@ -10218,7 +10263,8 @@ Bitcoin.Util = {
result => { result => {
floGlobals.settings = result; floGlobals.settings = result;
resolve( resolve(
"Read app configuration from blockchain"); "Read app configuration from blockchain"
);
}) })
}) })
}) })
@ -10295,16 +10341,15 @@ Bitcoin.Util = {
} else { } else {
var privKey; var privKey;
inputFn("PRIVATE_KEY").then(result => { inputFn("PRIVATE_KEY").then(result => {
try { if (!result)
if (!result) return reject("Empty Private Key")
return reject("Empty Private Key") var pubKey = floCrypto.getPubKeyHex(result)
var floID = floCrypto.getFloIDfromPubkeyHex( if (!pubKey)
floCrypto.getPubKeyHex(result))
privKey = result
} catch (error) {
console.error(error)
return reject("Invalid Private Key") return reject("Invalid Private Key")
} var floID = floCrypto.getFloIDfromPubkeyHex(pubKey)
if (!floID || !floCrypto.validateAddr(floID))
return reject("Invalid Private Key")
privKey = result;
}).catch(error => { }).catch(error => {
console.log(error, "Generating Random Keys") console.log(error, "Generating Random Keys")
privKey = floCrypto.generateNewID().privKey privKey = floCrypto.generateNewID().privKey
@ -10614,8 +10659,12 @@ Bitcoin.Util = {
} }
}, },
manageSheetControl(addList, rmList){ manageSheetControl(title, addList, rmList){
let editorList = floGlobals.appObjects.logSheet.sheetList[title].editors if(addList === null && rmList === null){
floGlobals.appObjects.logSheet.sheetList[title].editors = null
return
}
let editorList = floGlobals.appObjects.logSheet.sheetList[title].editors || [];
if(Array.isArray(addList)) if(Array.isArray(addList))
addList.forEach(e => editorList.includes(e) ? null: editorList.push(e)) addList.forEach(e => editorList.includes(e) ? null: editorList.push(e))
if(Array.isArray(rmList)) if(Array.isArray(rmList))
@ -10650,7 +10699,36 @@ Bitcoin.Util = {
return reject("floID not found"); return reject("floID not found");
} else if(!floGlobals.subAdmins.includes(myFloID) && floID != myFloID) } else if(!floGlobals.subAdmins.includes(myFloID) && floID != myFloID)
return reject("Public authorized to log their own floID only"); return reject("Public authorized to log their own floID only");
floCloudAPI.sendGeneralData({floID: floID, log: log}, title) floCloudAPI.sendGeneralData({floID, log}, title)
.then(result => resolve(result))
.catch(error => reject(error))
})
},
forwardLog(title, vc, grade) {
return new Promise((resolve, reject) => {
//reject if user is not subAdmin or editor
if(!floGlobals.subAdmins.includes(myFloID) ||
(floGlobals.appObjects.logSheet.sheetList[title].editors &&
!floGlobals.appObjects.logSheet.sheetList[title].editors.includes(myFloID)))
return reject("Only subAdmins in editor list can forward/grade logs")
let filter = floDapps.util.getFilterString(title)
let forward = null
for(let row of floGlobals.generalData[filter]){
if(row.vectorClock === vc){
forward = row;
break;
} else if (row.message.forward && row.message.forward.vectorClock === vc){
forward = row.message.forward;
break;
}
}
if(!forward)
return reject("Log not found")
if(forward.sender === myFloID)
return reject("Cannot grade own log")
floCloudAPI.sendGeneralData({forward, grade}, title)
.then(result => resolve(result)) .then(result => resolve(result))
.catch(error => reject(error)) .catch(error => reject(error))
}) })
@ -10671,13 +10749,43 @@ Bitcoin.Util = {
viewLogs(title){ viewLogs(title){
if(!(title in floGlobals.appObjects.logSheet.sheetList)) if(!(title in floGlobals.appObjects.logSheet.sheetList))
throw ("Sheet not found") throw ("Sheet not found")
let sheet = [] let sheet = [],
let filter = floDapps.util.getFilterString(title) vcIndex = {},
floGlobals.generalData[filter].forEach(l => sheet.push({ filter = floDapps.util.getFilterString(title),
vc: l.vectorClock, editors = floGlobals.appObjects.logSheet.sheetList[title].editors;
floID: l.message.floID,
log: l.message.log floGlobals.generalData[filter].forEach(l => {
})) if((!editors || editors.includes(l.sender))) {
if(l.message.forward){
if(floGlobals.subAdmins.includes(l.sender) &&
l.sender != l.message.forward.sender) {
let vc = l.message.forward.vectorClock
if(vc in vcIndex)
sheet[vcIndex[vc]].grade = l.message.grade;
else if(floCrypto.validateAddr(l.message.forward.floID)){
sheet.push({
vc: vc,
floID: l.message.forward.floID,
log: l.message.forward.log,
grade: l.message.grade
})
vcIndex[vc] = sheet.length - 1;
}
}
} else if(editors || floGlobals.subAdmins.includes(l.sender) || l.sender === l.message.floID){
if(floCrypto.validateAddr(l.message.floID)){
let vc = l.vectorClock
sheet.push({
vc: vc,
floID: l.message.floID,
log: l.message.log,
grade: null
})
vcIndex[vc] = sheet.length - 1;
}
}
}
})
return { return {
title: title, title: title,
description: floGlobals.appObjects.logSheet.sheetList[title].description, description: floGlobals.appObjects.logSheet.sheetList[title].description,
@ -10689,55 +10797,52 @@ Bitcoin.Util = {
groupLogsBy: { groupLogsBy: {
count(title){ count(title, sheet){
if(!(title in floGlobals.appObjects.logSheet.sheetList)) if(!(title in floGlobals.appObjects.logSheet.sheetList))
throw ("Sheet not found") throw ("Sheet not found")
let group = {}; let group = {};
let filter = floDapps.util.getFilterString(title) sheet.forEach(l => {
floGlobals.generalData[filter].forEach(l => { if(!(l.floID in group))
if(!(l.message.floID in group)) group[l.floID] = 1
group[l.message.floID] = 1
else else
group[l.message.floID] += 1 group[l.floID] += 1
}) })
return group return group
}, },
total(title, attribute){ total(title, sheet, attribute){
if(!(title in floGlobals.appObjects.logSheet.sheetList)) if(!(title in floGlobals.appObjects.logSheet.sheetList))
throw ("Sheet not found") throw ("Sheet not found")
let group = {}; let group = {};
let attrubuteIndex = floGlobals.appObjects.logSheet.sheetList[title].attributes.indexOf(attribute) let attrubuteIndex = floGlobals.appObjects.logSheet.sheetList[title].attributes.indexOf(attribute)
let filter = floDapps.util.getFilterString(title) sheet.forEach(l => {
floGlobals.generalData[filter].forEach(l => { let value = parseFloat(l.log[attrubuteIndex])
let value = parseFloat(l.message.log[attrubuteIndex])
if(!isNaN(value)){ if(!isNaN(value)){
if(!(l.message.floID in group)) if(!(l.floID in group))
group[l.message.floID] = value group[l.floID] = value
else else
group[l.message.floID] += value group[l.floID] += value
} }
}) })
return group return group
}, },
avg(title, attribute){ avg(title, sheet, attribute){
if(!(title in floGlobals.appObjects.logSheet.sheetList)) if(!(title in floGlobals.appObjects.logSheet.sheetList))
throw ("Sheet not found") throw ("Sheet not found")
let group = {}; let group = {};
let attrubuteIndex = floGlobals.appObjects.logSheet.sheetList[title].attributes.indexOf(attribute) let attrubuteIndex = floGlobals.appObjects.logSheet.sheetList[title].attributes.indexOf(attribute)
let filter = floDapps.util.getFilterString(title) sheet.forEach(l => {
floGlobals.generalData[filter].forEach(l => { let value = parseFloat(l.log[attrubuteIndex])
let value = parseFloat(l.message.log[attrubuteIndex])
if(!isNaN(value)){ if(!isNaN(value)){
if(!(l.message.floID in group)) if(!(l.floID in group))
group[l.message.floID] = { group[l.floID] = {
total: value, total: value,
count: 1 count: 1
} }
else{ else{
group[l.message.floID].total += value group[l.floID].total += value
group[l.message.floID].count += 1 group[l.floID].count += 1
} }
} }
}) })
@ -10745,37 +10850,36 @@ Bitcoin.Util = {
group[floID] = group[floID].total / group[floID].count group[floID] = group[floID].total / group[floID].count
return group return group
}, },
min(title, attribute){
min(title, sheet, attribute){
if(!(title in floGlobals.appObjects.logSheet.sheetList)) if(!(title in floGlobals.appObjects.logSheet.sheetList))
throw ("Sheet not found") throw ("Sheet not found")
let group = {}; let group = {};
let attrubuteIndex = floGlobals.appObjects.logSheet.sheetList[title].attributes.indexOf(attribute) let attrubuteIndex = floGlobals.appObjects.logSheet.sheetList[title].attributes.indexOf(attribute)
let filter = floDapps.util.getFilterString(title) sheet.forEach(l => {
floGlobals.generalData[filter].forEach(l => { let value = parseFloat(l.log[attrubuteIndex])
let value = parseFloat(l.message.log[attrubuteIndex])
if(!isNaN(value)){ if(!isNaN(value)){
if(!(l.message.floID in group)) if(!(l.floID in group))
group[l.message.floID] = value group[l.floID] = value
else if(value < group[l.message.floID]) else if(value < group[l.floID])
group[l.message.floID] = value group[l.floID] = value
} }
}) })
return group return group
}, },
max(title, attribute){ max(title, sheet, attribute){
if(!(title in floGlobals.appObjects.logSheet.sheetList)) if(!(title in floGlobals.appObjects.logSheet.sheetList))
throw ("Sheet not found") throw ("Sheet not found")
let group = {}; let group = {};
let attrubuteIndex = floGlobals.appObjects.logSheet.sheetList[title].attributes.indexOf(attribute) let attrubuteIndex = floGlobals.appObjects.logSheet.sheetList[title].attributes.indexOf(attribute)
let filter = floDapps.util.getFilterString(title) sheet.forEach(l => {
floGlobals.generalData[filter].forEach(l => { let value = parseFloat(l.log[attrubuteIndex])
let value = parseFloat(l.message.log[attrubuteIndex])
if(!isNaN(value)){ if(!isNaN(value)){
if(!(l.message.floID in group)) if(!(l.floID in group))
group[l.message.floID] = value group[l.floID] = value
else if(value > group[l.message.floID]) else if(value > group[l.floID])
group[l.message.floID] = value group[l.floID] = value
} }
}) })
return group return group
@ -10785,4 +10889,4 @@ Bitcoin.Util = {
</script> </script>
</body> </body>
</html> </html>