Editable Table in Flask/HTML - javascript

I am trying to create an excel-like table to update and log things on the go.
I have found this javascript:
function init()
{
var tables = document.getElementsByClassName("editabletable");
var i;
for (i = 0; i < tables.length; i++)
{
makeTableEditable(tables[i]);
}
}
function makeTableEditable(table)
{
var rows = table.rows;
var r;
for (r = 0; r < rows.length; r++)
{
var cols = rows[r].cells;
var c;
for (c = 0; c < cols.length; c++)
{
var cell = cols[c];
var listener = makeEditListener(table, r, c);
cell.addEventListener("input", listener, false);
}
}
}
function makeEditListener(table, row, col)
{
return function(event)
{
var cell = getCellElement(table, row, col);
var text = cell.innerHTML.replace(/<br>$/, '');
var items = split(text);
if (items.length === 1)
{
// Text is a single element, so do nothing.
// Without this each keypress resets the focus.
return;
}
var i;
var r = row;
var c = col;
for (i = 0; i < items.length && r < table.rows.length; i++)
{
cell = getCellElement(table, r, c);
cell.innerHTML = items[i]; // doesn't escape HTML
c++;
if (c === table.rows[r].cells.length)
{
r++;
c = 0;
}
}
cell.focus();
};
}
function getCellElement(table, row, col)
{
// assume each cell contains a div with the text
return table.rows[row].cells[col].firstChild;
}
function split(str)
{
// use comma and whitespace as delimiters
return str.split(/,|\s|<br>/);
}
window.onload = init;
And it seems like it will work well in saving and keeping the edits in the table.
The issue is, however, that I am using pycharms and - unfortunately - cannot use a js file within mine.
Is there a way to convert this to Python, or a way to code a table within Python?

Related

Run This Script On Every Tab Except "Main" Tab

I have this script working well, but I'm uncertain how to make it run on every tab not labeled "Main". Thanks in advance!
function hideRows() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var s = ss.getSheetByName("Dude"); // Enter sheet name
var row = s.getRange('A2:A').getValues(); // Enter column letter that has the text "hide" and "unhide"
var cell = s.getRange('A1').getValue();
s.showRows(1, s.getMaxRows());
for(var i=0; i < row.length; i++){ if(row[i] != cell) { s.hideRows(i+2, 1); } // Value to hide
}
}
Jerome
Run on every sheet except Main
I assume that you are running the onEdit trigger.
function hideRows(e) {
const s = e.range.getSheet();
if(s.getName() == "Main") return;
var row = s.getRange(2,1,s.getLastRow() -1 ).getValues().flat();
var cell = s.getRange('A1').getValue();
s.showRows(1, s.getLastRow());
for (var i = 0; i < row.length; i++) {
if (row[i] != cell) { s.hideRows(i + 2, 1); }
}
}
Want to exclude more sheets
function hideRows(e) {
const s = e.range.getSheet();
const ex = ['Main','Sheetx'];//excluded sheet names
const idx = ex.indexOf(s.getName());
if(~idx) return;
var row = s.getRange(2,1,s.getLastRow() -1 ).getValues().flat();
var cell = s.getRange('A1').getValue();
s.showRows(1, s.getLastRow());
for (var i = 0; i < row.length; i++) {
if (row[i] != cell) { s.hideRows(i + 2, 1); }
}
}

How to prevent additional table creation

I've been looking for workarounds to ensure that only one table is created. So far the only one i have come up with is to disable the button after it had been pressed. Here is my code:
function bikeData() {
// Select the Table
var tbl = document.getElementById('bikeInnerTable');
var th = document.getElementById('tableHead_B');
var headerText = ["ID", "Bike Status", "Bike Location", "Depot ID"];
// Set number of rows
var rows = 10;
// Set number of columns
var columns = headerText.length;
// create table header
for (var h = 0; h < columns; h++) {
var td = document.createElement("td");
td.innerText = headerText[h];
th.appendChild(td);
}
// create table data
for (var r = 0; r < rows; r++) {
var cellText = ["UNDEFINED", "UNDEFINED", "UNDEFINED", "UNDEFINED"];
// generate ID
x = getRandomNumber(1000, 1);
cellText[0] = x;
// generate Status
x = getStatus();
cellText[1] = x;
// generate Name
x = getLocation();
cellText[2] = x;
// generate depot ID
x = getRandomNumber(1000, 1);
cellText[3] = x;
var tr = document.getElementById("b_row" + r);
for (var c = 0; c < columns; c++)
{
var td = document.createElement("td");
td.innerText = cellText[c];
tr.appendChild(td);
}
}
}
If the button is pressed multiple times then the table is created multiple times. However how can I adapt the code to ensure that it if the table is already present within the div, then it doesn't continue in creating the table additional times.
You can set a flag and then only execute the code when applicable.
let firstTime = true;
function(){
...
if (firstTime) {
firstTime = false;
...
}
}
This is what Javascript variables are for. You can make a variable, then test that against a condition in the function. Let me show you what I mean:
window.timesRan = 0;
function bikeData() {
//Check if the variable is > 1
if (timesRan > 1) {
return false;
}
//code here
//then just add 1 to the variable every time
timesRan += 1;
}
All the best, and I hope my answer works for you :)

Fullcalendar.io display three events in one row

I am using fullcalendar.io, regular view displays only one event per row. What I want to achieve is displaying three events in one row. This could be done by putting three links in one <td> element. This td element is generated thanks to fullcalendar.io library.
Below there is what I've achieved until now:
for (i = 0; i < levelCnt; i++) { // iterate through all levels
levelSegs = segLevels[i];
col = 0;
tr = $('<tr/>');
segMatrix.push([]);
cellMatrix.push([]);
loneCellMatrix.push([]);
// levelCnt might be 1 even though there are no actual levels. protect against this.
// this single empty row is useful for styling.
if (levelSegs) {
var levelSegsDivided = Math.ceil(levelSegs.length / 3);
iterationStart = 0;
iterationEnd = 3;
for (k = 0; k < levelSegsDivided; k++) {
var elems;
for (j = iterationStart; j < iterationEnd; j++) {
seg = levelSegs[j];
if (seg != null) {
emptyCellsUntil(seg.leftCol);
// create a container that occupies or more columns. append the event element.
td = $('<td class="fc-event-container"/>').append(seg.el);
console.log(seg.el);
//if (seg.leftCol != seg.rightCol) {
// td.attr('colspan', seg.rightCol - seg.leftCol + 1);
//}
//else { // a single-column segment
// loneCellMatrix[i][col] = td;
//}
while (col <= seg.rightCol) {
cellMatrix[i][col] = td;
segMatrix[i][col] = seg;
col++;
}
tr.append(td);
iterationStart = iterationEnd;
iterationEnd = iterationEnd + 3;
}
}
}
//for (j = 0; j < levelSegs.length; j++) { // iterate through segments in level
// seg = levelSegs[j];
// emptyCellsUntil(seg.leftCol);
// // create a container that occupies or more columns. append the event element.
// td = $('<td class="fc-event-container"/>').append(seg.el);
// if (seg.leftCol != seg.rightCol) {
// td.attr('colspan', seg.rightCol - seg.leftCol + 1);
// }
// else { // a single-column segment
// loneCellMatrix[i][col] = td;
// }
// while (col <= seg.rightCol) {
// cellMatrix[i][col] = td;
// segMatrix[i][col] = seg;
// col++;
// }
// tr.append(td);
//}
}
emptyCellsUntil(colCnt); // finish off the row
this.bookendCells(tr);
tbody.append(tr);
}
And regular library code below:
renderSegRow: function(row, rowSegs) {
var colCnt = this.colCnt;
var segLevels = this.buildSegLevels(rowSegs); // group into sub-arrays of levels
var levelCnt = Math.max(1, segLevels.length); // ensure at least one level
var tbody = $('<tbody/>');
var segMatrix = []; // lookup for which segments are rendered into which level+col cells
var cellMatrix = []; // lookup for all <td> elements of the level+col matrix
var loneCellMatrix = []; // lookup for <td> elements that only take up a single column
var i, levelSegs;
var col;
var tr;
var j, seg;
var td;
// populates empty cells from the current column (`col`) to `endCol`
function emptyCellsUntil(endCol) {
while (col < endCol) {
// try to grab a cell from the level above and extend its rowspan. otherwise, create a fresh cell
td = (loneCellMatrix[i - 1] || [])[col];
if (td) {
td.attr(
'rowspan',
parseInt(td.attr('rowspan') || 1, 10) + 1
);
}
else {
td = $('<td/>');
tr.append(td);
}
cellMatrix[i][col] = td;
loneCellMatrix[i][col] = td;
col++;
}
}
for (i = 0; i < levelCnt; i++) { // iterate through all levels
levelSegs = segLevels[i];
col = 0;
tr = $('<tr/>');
segMatrix.push([]);
cellMatrix.push([]);
loneCellMatrix.push([]);
// levelCnt might be 1 even though there are no actual levels. protect against this.
// this single empty row is useful for styling.
if (levelSegs) {
for (j = 0; j < levelSegs.length; j++) { // iterate through segments in level
seg = levelSegs[j];
emptyCellsUntil(seg.leftCol);
// create a container that occupies or more columns. append the event element.
td = $('<td class="fc-event-container"/>').append(seg.el);
if (seg.leftCol != seg.rightCol) {
td.attr('colspan', seg.rightCol - seg.leftCol + 1);
}
else { // a single-column segment
loneCellMatrix[i][col] = td;
}
while (col <= seg.rightCol) {
cellMatrix[i][col] = td;
segMatrix[i][col] = seg;
col++;
}
tr.append(td);
}
}
emptyCellsUntil(colCnt); // finish off the row
this.bookendCells(tr);
tbody.append(tr);
}
return { // a "rowStruct"
row: row, // the row number
tbodyEl: tbody,
cellMatrix: cellMatrix,
segMatrix: segMatrix,
segLevels: segLevels,
segs: rowSegs
};
}

How to automatical update html table by clicking the button

I am JavaScript/html beginner and currently I am dealing with following issue:
I have several input fields, which are filled by the user.
When he filled up the fields, he presses the button and several tables are created.
So far works everything fine.
BUT
If I update the information in the input field and press the button, the NEW tables are created (the previous tables stay and new are added below)
My idea was to make following:
I put the new tables in a separate div.
Every time I press the button, the div information is deleted and created again.
But as I am a beginner I don’t really know how to do it.
Can anyone help me?
Do you have a better idea?
My code
(...)
/part with the table creation/
var zaehler=0;
for (zaehler = 0; zaehler < n; zaehler++){
tableCreate(n,zaehler,a,b,c,d,e,f,g,h,i,j,k,l);
}}
/the table create function/`
<script>
function tableCreate(maxyear,s4italka, a,b,c,d,e,f,g,h,i,j,k,l) {
var imena = ["Выручка", "Управляющая кампания", "Профилактика", "Налог на Недвижимость", "Страховка", "Амортизация", "Тело кредита", "%-ные выплаты банку", "%-ные выплаты себе", "Доход",
"Налог (15%)", "Финансовый результат" ];
var dannie =[a,b,c,d,e,f,g,h,i,j,k,l];
var body = document.getElementsByTagName('body')[0];
var tbl = document.createElement('table');
tbl.style.width = '40%';
tbl.setAttribute('border', '1');
var tbdy = document.createElement('tbody');
var trh = document.createElement('tr');
var th = document.createElement('th');
var m=s4italka+2015;
th.appendChild(document.createTextNode('Результат на '+m+ ' год'))
th.setAttribute ('colSpan','2');
trh.appendChild(th)
tbdy.appendChild(trh);
for (var i = 0; i < 12; i++) {
var tr = document.createElement('tr');
for (var j = 0; j < 2; j++) {
var td = document.createElement('td');
if ((j % 2) != 0)
{td.appendChild(document.createTextNode(dannie[i]))}
else {
td.appendChild(document.createTextNode(imena[i]))}
tr.appendChild(td)
}
tbdy.appendChild(tr);
}
tbl.appendChild(tbdy);
body.appendChild(tbl)
var p= document.createElement('p');
body.appendChild(p);
}
</script>
You have to remove the previous table first. Currently the code that you have keeps appending new table to the body only but all the previous elements still remain there.
To remove the previous table:
jQuery:
body.find("table").remove();
Javascript:
var tables = document.getElementsByTagName("table");
for (var i = 0; i < tables.length; i++) {
tables[i].remove();
}
You can insert the code above before the line body.appendChild(tbl)
Note: jQuery function remove() will not throw error even if the table does not exist at the time of executing the code.
function tableCreate(maxyear, s4italka, a, b, c, d, e, f, g, h, i, j, k, l) {
var imena = ["Выручка", "Управляющая кампания", "Профилактика", "Налог на Недвижимость", "Страховка", "Амортизация", "Тело кредита", "%-ные выплаты банку", "%-ные выплаты себе", "Доход",
"Налог (15%)", "Финансовый результат"];
var dannie = [a, b, c, d, e, f, g, h, i, j, k, l];
$('.myTabel').remove();
var body = document.getElementsByTagName('body')[0];
var tbl = document.createElement('table');
$(tbl).addClass('myTabel');
tbl.style.width = '40%';
tbl.setAttribute('border', '1');
var tbdy = document.createElement('tbody');
var trh = document.createElement('tr');
var th = document.createElement('th');
var m = s4italka + 2015;
th.appendChild(document.createTextNode('Результат на ' + m + ' год'))
th.setAttribute('colSpan', '2');
trh.appendChild(th)
tbdy.appendChild(trh);
for (var i = 0; i < 12; i++) {
var tr = document.createElement('tr');
for (var j = 0; j < 2; j++) {
var td = document.createElement('td');
if ((j % 2) != 0)
{ td.appendChild(document.createTextNode(dannie[i])) }
else {
td.appendChild(document.createTextNode(imena[i]))
}
tr.appendChild(td)
}
tbdy.appendChild(tr);
}
tbl.appendChild(tbdy);
body.appendChild(tbl)
var p = document.createElement('p');
body.appendChild(p);
}

Getting the index of the current element and change his styles

I have a function whose destination is to work onClick event.
So, we have for example 4 Span elements and 4 Div elements.
The Spans are Tabs-buttons which I would like to "open" those Divs.
The 1st Span onClick would (open) change the style.display of the 1st Div in "block", from "none", and so on for the next Spans.
This piece of code works very well, but it changes only the design of elements.
function activateSup(s) {
var workTable = s.parentNode.parentNode.parentNode.parentNode.parentNode;
var spans = workTable.getElementsByTagName("span");
var supDivs = workTable.getElementsByClassName("supDiv");
for (var i = 0; i < spans.length; i++) {
spans[i].style.backgroundColor = "";
spans[i].style.border = "";
}
s.style.backgroundColor = "#5eac58";
s.style.border = "2px solid #336633";
}
I've tried to add the code below into my function to achieve what I want, but It does not work.
var getIndex = function(s) {
for (var index = 0; s != s.parentNode.childNodes[index]; index++);
return index;
}
for (var d = 0; d < supDivs.length; d++) {
if (getIndex == d) {
supDivs[d].style.display = "block";
}
else {
supDivs[d].style.display = "none";
}
}
I'm not exactly sure what you're trying to do, but one thing I noticed is this:
var getIndex = function(s) { /* .... */ }
for (var d = 0; d < supDivs.length; d++) {
if (getIndex == d) {
supDivs[d].style.display = "block";
}
else { /* ... */ }
}
This code is comparing getIndex to d, which means it's comparing an integer (d) to the function getIndex, instead of the result of the function call getIndex(spans[d]) (which is an integer, like d).
But what I think you're really trying to do, is getting the index of the clicked <span> so you can show the <div> with the matching index (and hide the rest). To achieve this, the code could be changed like so:
function activateSup(s) {
var workTable = s.parentNode.parentNode.parentNode.parentNode.parentNode;
var spans = workTable.getElementsByTagName("span");
var supDivs = workTable.getElementsByClassName("supDiv");
var index;
for (var i = 0; i < spans.length; i++) {
spans[i].style.backgroundColor = "";
spans[i].style.border = "";
if (s == spans[i])
index = i;
}
s.style.backgroundColor = "#5eac58";
s.style.border = "2px solid #336633";
for (var d = 0; d < supDivs.length; d++) {
if (index == d) {
supDivs[d].style.display = "block";
} else {
supDivs[d].style.display = "none";
}
}
}
Instead of the function getIndex, this just saves the correct index inside the first for loop.
There are many more improvements that could be made to this code, like rewriting it so you don't need that ugly s.parentNode.parentNode.parentNode.parentNode.parentNode and working with CSS classes instead of manually setting the style. But I'll leave that to the reader.

Categories