Add Button into HTML Table with JavaScript without generator file - javascript

I apologize in advance, English is not my native language.
I am working on a project that was delegated to me. I am working on a webpage, that is being generated by an XSLT file. I only have access to the source code of the generated page.
What does it do: The page shows a synopsis in form of a table. The left most column (lets call that one A) and the top most row (lets call it B) are the Header (?) segments (like in this table i found on google)
There are also Buttons in the top most row to sort the table.
Now the problem: There is a button to invert the table which activates the following code. This is where the problem is
I have this java code
// FAULTY FUNCTION BEGINNING
function swap_table_horizontally_vertically() {
//This is the code I already have
// Deletes all sort buttons
for (i = 0; i <= 1000; i++) {
try {
var sort_buttons = document.getElementById('sort_buttons');
}
catch(err) {
alert(err.message);
continue;
} finally {
sort_buttons.parentNode.removeChild(sort_buttons);
}
}
//End of the Code I made
//This code was already in the file
var old_table = document.getElementById('synopsis_table'),
old_table_rows = old_table.getElementsByTagName('tr'),
cols = old_table_rows.length, rows = old_table_rows[0].getElementsByTagName('td').length,
cell, next, temp_row, i = 0, new_table = document.createElement('table');
while(i < rows) {
cell = 0;
temp_row = document.createElement('tr');
if (i == 0) {
while(cell < cols) {
next = old_table_rows[cell++].getElementsByTagName('td')[0];
temp_row.appendChild(next);
}
new_table.appendChild(temp_row);
++i;
}
else {
while(cell < cols) {
next = old_table_rows[cell++].getElementsByTagName('td')[0];
temp_row.appendChild(next);
}
new_table.appendChild(temp_row);
++i;
}
}
old_table.parentNode.replaceChild(new_table, old_table);
new_table.setAttribute("id", "synopsis_table");
}
// FAULTY FUNCTION END
Now what I need is a way to add the buttons again into the new table head (top most row) with a class and id attribute.
To summarize: I need to delete the buttons from the previous top most row (because the left column shouldn't have them) and add them again to the new top most row (the previous left column).

Related

How to update instead of aggregating Google Slides when updating records in Google Sheet with Google Apps Script?

Using Google Apps Script, I generate G-Slides based on a template (first slide top left) as shown below...
...from a Google Sheet where each row has a set of attributes corresponding to its respective slide:
Furthermore, a trigger has been set to execute the Google Apps script 'On Open' (i.e. upon refreshing the document) in G-Sheet.
The script currently duplicates the first slide (the template) per rows with complete information, and feeds the variables from G-Sheet as designated in the {{brackets}} onto the template slide (i.e. the template_value matches the template_field).
function fillTemplateV3() {
// Id of the slides template
var PRESENTATION_ID = "PRESENTATION ID HERE";
// Open the presentation
var presentation = SlidesApp.openById(PRESENTATION_ID);
// Read data from the spreadsheet
var values = SpreadsheetApp.getActive().getDataRange().getValues();
// Replace template variables in the presentation with values
let hdr = values.shift()
values.forEach(row =>{
let templateSlide = presentation.getSlides()[0].duplicate()
for ( var i = 0 ; i < 4; i++){
let templateField = hdr[i]
let templateValue = row[i]
let logo = row[4]
console.log(logo)
templateSlide.replaceAllText(templateField, templateValue)
templateSlide.getShapes().forEach(s => {
if (s.getText().asString().trim() == "{{logo}}") s.replaceWithImage(logo);
});
}
}
);
}
The issue I'm having is that the script is additive, i.e. each time the script is executed it keeps on adding slides on top of those already created. I am not convinced that adding a function to delete the Slides before executing the for loop is efficient to address this issue.
How do I execute the script so that the number of slides in G-Slides correspond to the number of rows in G-Sheets? I.e. if I have 3 rows filled with information in G-Sheet, I should only have 4 slides total (counting the template slide). Right now, every-time the script executes, slides are added to the G-Slide document, so that if I add a fourth row, execute the script, and the script ran once before, I end up with 8 slides total. Instead I want to generate 4 slides, not counting the template slide.
Edited to clarify the code's objective.
I was overthinking this by a lot. I simply had to execute a for loop through my slides first, before executing the for loop to fill my G-Slide template from G-Sheets, in order to delete all slides besides the first one, which serves as my template slide:
function fillTemplate() {
// Id of the slides template
// Remember to replace this with the Id of your presentation
var PRESENTATION_ID = "YOUR PRESENTATION ID HERE";
// Open the presentation
var presentation = SlidesApp.openById(PRESENTATION_ID);
// Read data from the spreadsheet
var values = SpreadsheetApp.getActive().getDataRange().getValues();
// Replace template variables in the presentation with values
let hdr = values.shift()
var slides = presentation.getSlides();
//change i to any other index if desired
for (var i = 1; i < slides.length; i++) {
slides[i].remove()
}
values.forEach(row => {
let templateSlide = presentation.getSlides()[0].duplicate()
for (var i = 1; i < 6; i++) {
let templateField = hdr[i]
let templateValue = row[i]
let logo = row[6]
console.log(logo)
templateSlide.replaceAllText(templateField, templateValue)
templateSlide.getShapes().forEach(s => {
if (s.getText().asString().trim() == "{{logo_url}}") s.replaceWithImage(logo);
});
}
});
}
Credit to the answer of this post for helping me find a solution: How to delete slides programmatically after the nth one in google slides?

I can't access nested JavaScript function in index.jsp

I have a function that is supposed to perform pagination on a table. Within that function is another function that needs to be executed when I click on the numbers in the navigation bar. The code works fine in VSCode. When I put the code in index.jsp in eclipse, the function gives the error: Uncaught ReferenceError: sort is not defined at HTMLButtonElement.onclick.
// get the table element
var table = document.getElementById("disposalTable"),
// number of rows per page
n = 5,
// number of rows of the table
rowCount = table.rows.length,
// get the first cell's tag name (in the first row)
firstRow = table.rows[0].firstElementChild.tagName,
// boolean var to check if table has a head row
hasHead = (firstRow === "TH"),
// an array to hold each row
tr = [],
// loop counters, to start count from rows[1] (2nd row) if the first row has a head tag
i,ii,j = (hasHead)?1:0,
// holds the first row if it has a (<TH>) & nothing if (<TD>)
th = (hasHead?table.rows[(0)].outerHTML:"");
// count the number of pages
var pageCount = Math.ceil(rowCount / n);
// if we had one page only, then we have nothing to do ..
if (pageCount > 1) {
// assign each row outHTML (tag name & innerHTML) to the array
for (i = j,ii = 0; i < rowCount; i++, ii++)
tr[ii] = table.rows[i].outerHTML;
// create a div block to hold the buttons
table.insertAdjacentHTML("afterend","<div id='buttons'></div");
// the first sort, default page is the first one
sort(1);
}
// ($p) is the selected page number. it will be generated when a user clicks a button
function sort(p) {
/* create ($rows) a variable to hold the group of rows
** to be displayed on the selected page,
** ($s) the start point .. the first row in each page, Do The Math
*/
var rows = th,s = ((n * p)-n);
for (i = s; i < (s+n) && i < tr.length; i++)
rows += tr[i];
// now the table has a processed group of rows ..
table.innerHTML = rows;
// create the pagination buttons
document.getElementById("buttons").innerHTML = pageButtons(pageCount,p);
// CSS Stuff
document.getElementById("id"+p).setAttribute("class","active");
}
// ($pCount) : number of pages,($cur) : current page, the selected one ..
function pageButtons(pCount,cur) {
/* this variables will disable the "Prev" button on 1st page
and "next" button on the last one */
var prevDis = (cur == 1)?"disabled":"",
nextDis = (cur == pCount)?"disabled":"",
/* this ($buttons) will hold every single button needed
** it will creates each button and sets the onclick attribute
** to the "sort" function with a special ($p) number..
*/
buttons = "<input type='button' value='<< Prev' onclick='sort("+(cur - 1)+")' "+prevDis+">";
for (i=1; i<=pCount;i++)
buttons += "<input type='button' id='id"+i+"'value='"+i+"' onclick='sort("+i+")'>";
buttons += "<input type='button' value='Next >>' onclick='sort("+(cur + 1)+")' "+nextDis+">";
return buttons;
}
I figured it out. Instead of trying to access the nested function. Put the pager code into a function. Then create an instance of the function as a variable. And call that variable every time.
For instance:
let pager = new Pager();
Then the onclick method will call pager.sort(1) or pager.sort(2) everytime.

Creating Table from Google Spreadsheets: How to Manipulate Data?

Currently, I'm working on a project to pull data from a Google Form/Spreadsheet and have it appear on a website using JQuery/DataTables. I had received help on getting the data to appear on the site, but I've hit a new issue.
Previous Question: Is it possible to create a public database (spreadsheet) search with Google Scripts?
On Google, I have a form which outputs eight columns:
Timestamp
Title
Author
Type
URL
Topic(s)
Country(s)
Tages
Of these, I don't need the timestamp to appear, and I would like the title to link to the URL if the URL exists. Since I'm not quite fluent with Javascript or DataTables, I made a second sheet which I tried to simplified it down to the following six:
Title (currently being formatted as an <a> tag using the URL)
Author
Type
Topic(s)
Country(s)
Tages
This almost works, except that the script I'm using to construct the table renders the Title field as it is in the cell with the being visible in the table. See the table under the title "Actual Output" for the current situation; the table under "Target Table Appearance" is what I'm aiming for.
Current Output: http://interculturalresources.weebly.com/webtest.html
Table Creation Script: http://www.weebly.com/uploads/1/7/5/3/17534471/tablescript.js
Thus, is there a way to have the be given as a link despite being put together in a Google Spreadsheet cell? Alternatively, is there a way to edit the current script to a) ignore the timestamp column and b) make the Title output a link to the URL from the URL column (with proper conditionals)?
EDIT: I'm focusing on the links now; I have a solution for the timestamp which involves copying the data to a new spreadsheet (since forms are strict with copy/pasting information). The current issue is getting each entry to have a link assuming the URL is in the first column, and the Title is in the second column. Please read Mogsdad's answer and my first comment for more information.
Solution: First, my thanks to Mogsdad for the "spark" of inspiration and insight which led me in the correct direction towards the solution. To explain the general idea, I wanted to not display one column (URL) from a Google Spreadsheet on the target website, yet use it's content to create a link in another (Title). Then, once the table was made, DataTables is used to format it. All cells in the table must contain something, so if the cell is to be blank, it must be filled with "None".
function cellEntries(json, dest, divId) {
var table = document.createElement('table');
table.setAttribute("id", divId + "table"); //Assign ID to <table> from the <div> name.
var thead = document.createElement('thead');
var tbody = document.createElement('tbody');
var thr;
var tr;
var entries = json.feed.entry;
var cols = json.feed.gs$colCount.$t; //The number of columns in the sheet.
var link; //Teporary holder for the URL of a row.
for (var i=0; i <cols; i++) { //For the first row of cells (column titles),
var entry = json.feed.entry[i];
if (entry.gs$cell.col == '1') { //For First Column / URL Column, (1)
if (thr != null) {
tbody.appendChild(thr);
}
thr = document.createElement('tr'); //Create <thr>/<tr> (???).
}
else { //For all other columns,
var th = document.createElement('th');
th.appendChild(document.createTextNode(entry.content.$t)); //Create title for each column.
thr.appendChild(th);
}
}
for (var i=cols; i < json.feed.entry.length; i++) { //For all remaining cells,
var entry = json.feed.entry[i];
if (entry.gs$cell.col == '1') { //For First Column / URL Column, (1)
if (tr != null) {
tbody.appendChild(tr);
}
tr = document.createElement('tr'); //Create <tr>.
hlink = entry.content.$t; //Put URL content into hlink.
}
else if (entry.gs$cell.col == '2') { //For Title Column,(2)
var td = document.createElement('td');
if (hlink != "None") { //If there is a link,
var alink = document.createElement('a'); //Make <a>
alink.appendChild(document.createTextNode(entry.content.$t)); //Put content in <a>
alink.setAttribute('href',hlink); //Assign URL to <a>.
td.appendChild(alink); //Put <a> in <td>.
}
else { //If there is no link,
td.appendChild(document.createTextNode(entry.content.$t)); //Put content in <td>.
}
tr.appendChild(td);
}
else { //For all other columns,
var td = document.createElement('td');
if (entry.content.$t != "None") { //If content is not "None",
td.appendChild(document.createTextNode(entry.content.$t)); //Output the content.
}
else { //Else,
td.appendChild(document.createTextNode("")); //Output a blank cell.
}
tr.appendChild(td);
}
}
$(thead).append(thr);
$(tbody).append(tr);
$(table).append(thead);
$(table).append(tbody);
$(dest).append(table);
$(dest + "table").dataTable();
};
function importGSS(json){
var divId = "targetdivid" //ID of the target <div>.
cellEntries(json, "#" + divId, divId);
};
Around this bit in tablescript.js:
var th = document.createElement('th');
th.appendChild(document.createTextNode(entry.content.$t));
>>>>
thr.appendChild(th)
You can add a hyperlink by doing this:
th.setAttribute('href',<link>);
...with <link> set to the hyperlink for the particular publication.
To make this work, you could rework your spreadsheet source to have the link in one column, and the Title in another. Then modify tablescript.js to combine the link and text, something like this:
var hlink = null; // Temporary storage for hyperlink
for (var i=0; i <cols; i++) {
var entry = json.feed.entry[i];
if (entry.gs$cell.col == '1') {
if (thr != null) {
tbody.appendChild(thr);
}
thr = document.createElement('tr');
}
// Element 0 assumed to have hyperlink
if (i == 0) {
hlink = entry.content.$t;
}
else {
var th = document.createElement('th');
// If we have an hlink, set the href attribute.
if (hlink !== null) {
th.setAttribute('href',hlink);
hlink = null;
}
th.appendChild(document.createTextNode(entry.content.$t));
thr.appendChild(th);
}
}

Hide table column ondblclick

I have a table and I want to hide a column when I double click a column.
Code for hiding a column is practically all around Stack Overflow. All I need is a hint on how/where to add the ondblclick event so I can retrieve the identity of a <td> within a <table>.
Here are two solutions that should work. One done with jQuery and one with only standard Javascript.
http://jsfiddle.net/GNFN2/2/
// Iterate over each table, row and cell, and bind a click handler
// to each one, keeping track of which column each table cell was in.
var tables = document.getElementsByTagName('table');
for (var i = 0; i < tables.length; i++) {
var rows = tables[i].getElementsByTagName('tr');
for (var j = 0; j < rows.length; j++) {
var cells = rows[j].getElementsByTagName('td');
for (var k = 0; k < cells.length; k++) {
// Bind our handler, capturing the list of rows and colum.
cells[k].ondblclick = column_hide_handler(rows, k);
}
}
}
// Get a click handler function, keeping track of all rows and
// the column that this function should hide.
function column_hide_handler(rows, col) {
return function(e) {
// When the handler is triggered, hide the given column
// in each of the rows that were found previously.
for (var i = 0; i < rows.length; i++) {
var cells = rows[i].getElementsByTagName('td');
if (cells[col]) {
cells[col].style.display = 'none';
}
}
}
}
With jQuery it is much cleaner. This method also uses event bubbling, so you don't need to bind an event handler to each table cell individually.
http://jsfiddle.net/YCKZv/4/
// Bind a general click handler to the table that will trigger
// for all table cells that are clicked on.
$('table').on('dblclick', 'td', function() {
// Find the row that was clicked.
var col = $(this).closest('tr').children('td').index(this);
if (col !== -1) {
// Go through each row of the table and hide the clicked column.
$(this).closest('table').find('tr').each(function() {
$(this).find('td').eq(col).hide();
});
}
});
You can do this way:
<td ondblclick="this.style.display = 'none';">Some Stuff</td>
Here this refers to current td clicked.
Working Example
To go unobtrusive, you can do that easily using jQuery if you want:
$('#tableID td').dblclick(function(){
$(this).hide();
});
Due to lack of answears I came up with a workaround, which is a big ugly, but it works fine.
On the window load event I decided to iterate the table and set each 's onclick event to call my show_hide_column function with the column parameter set from the iteration.
window.onload = function () {
var headers = document.getElementsByTagName('th');
for (index in headers) {
headers[index].onclick = function (e) {
show_hide_column(index, false)
}
}
}
show_hide_column is a function that can be easily googled and the code is here:
function show_hide_column(col_no, do_show) {
var stl;
if (do_show) stl = 'table-cell'
else stl = 'none';
var tbl = document.getElementById('table_id');
var rows = tbl.getElementsByTagName('tr');
var headers = tbl.getElementsByTagName('th');
headers[col_no].style.display=stl;
for (var row=1; row<rows.length; row++) {
var cels = rows[row].getElementsByTagName('td')
cels[col_no].style.display=stl;
}
}
Note: my html only had one table so the code also assumes this. If you have more table you should tinker with it a little. Also it assumes the table has table headers ();
Also I noted this to be an ugly approach as I was expecting to be able to extract the index of a table cell from the table without having to iterate it on load.

Deleting all the clone node of a table row in javascript

function newRow(t) {
var parent = t.parentNode.parentNode.parentNode;
var row = t.parentNode.parentNode.cloneNode(true);
row.firstChild.nextSibling.firstChild.setAttribute('value', 'sumit');
parent.appendChild(row);
}
function removeRow(t) {
var y = t.parentNode.parentNode;
y.parentNode.removeChild(y);
}
the above code is working fine but i want to delete all the clones at once which are created by above code on a onchange event of a select box
Just add a class name to the cloned elements which would allow you to search for them and delete them later:
var row = t.parentNode.parentNode.cloneNode(true);
row.className += ' clonedrow';
...
// Remove all the cloned rows
var clonedRows = document.querySelectorAll('.clonedrow');
for (var i = 0; i < clonedRows.length; i++) {
clonedRows[i].parentNode.removeChild(clonedRows[i]);
}
Once the cloned rows have been added to the DOM, they look (to JavaScript) just like the original rows.
Since you're just appending cloned rows to the table body, what I would do is as follows:
Outside the functions, as soon as the document loads, use .childNodes.length to get the number of rows in your table and store it globally in, say, lastpos.
When you need to delete the clones, start at .childNodes[lastpos] and remove nodes until the table has lastpos rows again.

Categories

Resources