I am using the following function to export a table to a csv file for our users to export a copy of their purchases to a format they can use in quickbooks, excel, etc.
The function works great, except that the first column of our table contains urls and these columns appear blank in the export.
I am wondering how i could modify this so when a link is encountered as a field the text of that link would be added to the csv.
Example: an example would add an example to the csv for that field.
function exportTableToCSV($table, filename) {
var $rows = $table.find('tr:has(td),tr:has(th)'),
tmpColDelim = String.fromCharCode(11), // vertical tab character
tmpRowDelim = String.fromCharCode(0), // null character
colDelim = '","',
rowDelim = '"\r\n"',
csv = '"' + $rows.map(function (i, row) {
var $row = $(row), $cols = $row.find('td,th');
return $cols.map(function (j, col) {
var $col = $(col), text = $col.text();
return text.replace(/"/g, '""'); // escape double quotes
}).get().join(tmpColDelim);
}).get().join(tmpRowDelim).split(tmpRowDelim).join(rowDelim).split(tmpColDelim).join(colDelim) + '"',
csvData = 'data:application/csv;charset=utf-8,' + encodeURIComponent(csv);
console.log(csv);
if (window.navigator.msSaveBlob) { // IE 10+
window.navigator.msSaveOrOpenBlob(new Blob([csv],
{type: "text/plain;charset=utf-8;"}),
"csvname.csv")
} else {
$(this).attr({ 'download': filename, 'href': csvData, 'target': '_blank' });
}
}
As far as I can see, your snippet should already support this. It iterates over all rows of the table and for each row over all of its column fields, where jQuery's text() function is applied in order to extract the text. This should return the text between a tags as well.
Example:
console.log($('<td>Test page</td>').text());
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
will return the string Test page.
This fiddle contains the function you provided and a dummy table with some anchor elements. In my opinion it already meets your requirements.
var a = document.createElement('a');
a.href = "http://example.php";
a.append("an example");
document.body.appendChild(a);
console.log(a.textContent);
Related
I have been researching all afternoon and playing around with various solutions I have found on the internet and Stack OverFlow to try to keep the gridlines turned on when I export data from my HTML webpage but to no avail. I am really trying to avoid using a plug in and something this simple shouldn't require on in my opinion. I'm actually shocked that this is proving as challenging as it is. Anyway...I found this code....
function exportTableToExcel(tableID, filename = ''){
var downloadLink;
var dataType = 'application/vnd.ms-excel';
var tableSelect = document.getElementById(tableID);
var tableHTML = tableSelect.outerHTML.replace(/ /g, '%20');
// Specify file name
filename = filename?filename+'.xls':'excel_data.xls';
// Create download link element
downloadLink = document.createElement("a");
document.body.appendChild(downloadLink);
if(navigator.msSaveOrOpenBlob){
var blob = new Blob(['\ufeff', tableHTML], {
type: dataType
});
navigator.msSaveOrOpenBlob( blob, filename);
}else{
// Create a link to the file
downloadLink.href = 'data:' + dataType + ', ' + tableHTML;
// Setting the file name
downloadLink.download = filename;
//triggering the function
downloadLink.click();
}
}
And coupled with this HTML.....
<table id="tblData" class="table10">
<tr>
<th class="title36">Description</th>
</tr>
</table>
<button onclick="exportTableToExcel('tblData')"</button>
It all works beautifully! Except when I open the file the gridlines are gone and the user would have to go the view tab and turn the gridlines back on every time. Is there a setting I can change somewhere that will allow this?
The second example in this SO works...but I have a problem whereby I need to use a button and not an input button....for styling purposes...and then in doing so because the solution is written as a var and not a function....I had trouble working it out. So I know what I'm trying to do is possible...I just can't quite figure out how to work out doing this as Javascript without a plugin. I'm fairly new at Javascript so thanks in advance for any pointers...perhaps how I can rewrite the second solution as a function?
This is the code that I found that works....
<script type="text/javascript">
var tableToExcel = (function() {
var uri = 'data:application/vnd.ms-excel;base64,'
, template = '<html xmlns:o="urn:schemas-microsoft-com:office:office" xmlns:x="urn:schemas-microsoft-com:office:excel" xmlns="http://www.w3.org/TR/REC-html40"><head><!--[if gte mso 9]><xml><x:ExcelWorkbook><x:ExcelWorksheets><x:ExcelWorksheet><x:Name>{worksheet}</x:Name><x:WorksheetOptions><x:DisplayGridlines/></x:WorksheetOptions></x:ExcelWorksheet></x:ExcelWorksheets></x:ExcelWorkbook></xml><![endif]--><meta http-equiv="content-type" content="text/plain; charset=UTF-8"/></head><body><table>{table}</table></body></html>'
, base64 = function(s) { return window.btoa(unescape(encodeURIComponent(s))) }
, format = function(s, c) { return s.replace(/{(\w+)}/g, function(m, p) { return c[p]; }) }
return function(table, name) {
if (!table.nodeType) table = document.getElementById(table)
var ctx = {worksheet: name || 'Worksheet', table: table.innerHTML}
window.location.href = uri + base64(format(template, ctx))
}
})()
</script>
But I need to rewrite it so that I can call it in like the first function that is referenced at the beginning of my code above. Thanks again for any pointers or thoughts.
After more research I realized the second piece of code was the answer. I simply needed to update my HTML button reference as follows...
<button type="button" onclick="tableToExcel('tblData',)" class="class"><div class="class1"><h3 class="class2">Export To Excel</h3></div></button>
I have created a JSX for reading the data from TAB delimited input file (input file has two columns; ID and description). I want to read the input file and place the description on text layer and save the filename with ID.
It works when the description field letters and numbers. But it does not work when it has (é) in the description.
var Description = "on the ***pavé***";
textlayer.textItem.encoding = "UTF-8";
textlayer.textItem.contents = Description;
textlayer.textItem.tracking =50;
textlayer.textItem.wrapBend=70;
var saveFile = new File(outputfolder + "\\" + ID + "_16.psd");
saveFile.encoding="UTF-8";
app.activeDocument.saveAs( saveFile, saveOptions, true );
Works for me:
// Switch off any dialog boxes
displayDialogs = DialogModes.NO; // OFF
var outputfolder = "C:\\temp";
var description = "pavé_16";
var mySaveFile = outputfolder + "\\" + description + ".psd";
var psdFile = new File(mySaveFile);
activeDocument.saveAs(psdFile, SaveDocumentType.PHOTOSHOP, true, Extension.LOWERCASE);
displayDialogs = DialogModes.ALL; // NORMAL
Are you sure you're saving out as pavé_16.psd and not ***pavé***_16.psd? As asterisks (stars) in your filename will not work :)
Hoping someone can help me it's driving me nuts.
I am using SPServices and Javascript to rewrite some links after a small content migration.
I have some HTML in a variable and I'm trying to find a string which is a specific URL and replace it with a different URL. This works:
newHTML = newHTML.replace("http://urlhere/subsite/page.aspx",newLink);
Also this works:
newHTML = newHTML.replace(new RegExp("http://urlhere/subsite/page.aspx", 'gi'), newLink);
But if I have a variable containing the same string in there it doesn't work:
newHTML = newHTML.replace(new RegExp(oldLink, 'gi'), newLink);
My oldLink variable comes from an SPServices call to another list column containing HTML, which I take the 'a' tags and put them into an array:
function rewriteLinks() {
var urlStart = "http://urlstart";
var linkContainerArray = [];
var theContent = $('.htmlContentDiv').html();
// get a tags
var aTags = ('a',theContent);
//loop through A tags and get oldLink and Text
$(aTags).each(function(){
var ID;
var itemTitle = $(this).text();
var oldLink = $(this).attr('href');
var newLink;
if(itemTitle.length > 2){
//SpService call to get ID of that item using inner text as query to SharePoint list
$().SPServices({
operation: "GetListItems",
async: false,
CAMLViewFields: "<ViewFields><FieldRef Name='Title' /><FieldRef Name='ID' /></ViewFields>",
CAMLQuery: '<Query><Where><Eq><FieldRef Name="Title" /><Value Type="Text"><![CDATA['+itemTitle+']]></Value></Eq></Where></Query>',
listName: 'AGItems',
completefunc: function (xData, Status) {
$(xData.responseXML).SPFilterNode("z:row").each(function() {
ID = $(this).attr("ows_ID");
//Now have oldLink and newID in variables - build newLink from known URL & newID
newLink = urlStart+ID;
});//response xml
}//completefunc
});//spservices
//check for empty links
if((oldLink && newLink != '') && (oldLink && newLink != undefined)){
var linkPair = [oldLink,newLink];
linkContainerArray.push(linkPair);
}
}
});
replaceLinks(linkContainerArray);
}
Then I call a function to find and replace the links (this is where my variable won't work). I've tried escaping in all combinations of the following ways:
function escapeRegExp(stringToGoIntoTheRegex) {
return stringToGoIntoTheRegex.replace(/[\/\\^$*+?.|[\]{}]/g, '\\$&');
}
function htmlEncode(value){
//create a in-memory div, set it's inner text(which jQuery automatically encodes)
//then grab the encoded contents back out. The div never exists on the page.
return $('<div/>').text(value).html();
}
function htmlEscape(str) {
return String(str)
.replace(/"/g, '"')
.replace(/'/g, "'")
.replace(/</g, '<')
.replace(/>/g, '>');
}
function escapeRegExp(stringToGoIntoTheRegex) {
return stringToGoIntoTheRegex.replace(/[\/\\^$*+?.|[\]{}]/g, '\\$&');
}
Also removed full stops and question marks from the HTML & variable to make everything simple and it's still not working.
Also tried encodeURIComponent on the HTML & oldlink variable.. still no luck
If anyone has any help for me with this at all it would be much appreciated or can maybe see what I'm missing?!
Thanks
It does not work because some the characters in the string have a special meaning in a regular expression, like \ and .. So they need to be escaped.
You can use this function:
function escapeRegExp(str) {
return str.replace(/[\-\[\]\/\{\}\(\)\*\+\?\.\\\^\$\|]/g, "\\$&");
}
var newHTML = ' my link ';
var oldLink = 'http://someplaintext/pages/GuidelinesaspxiPageId=14495';
var newLink = 'http://urlstart?id=14495';
newHTML = newHTML.replace(new RegExp(escapeRegExp(oldLink), 'gi'), newLink);
console.log(newHTML);
See also this question.
Target: write&download a csv file starting with a json string, for example data.csv containing
col1,col2,col3
"324","19-08-2014","13000"
"325","19-08-2014","5010"
What I have done until now:
1) iframe and button to call my conversion function
<iframe id="frame" style="display:none"></iframe>
<form><input type="submit" value="Export CSV" onclick="javascript:Download();"></form>
2) my Download() function which would want to download my csv file
<script type="text/javascript">
function Download(){
var csv=ConvertToCSV(<?php echo $json_string ?>);
var url='data:application/csv,'+csv;
var _iframe_dl = $('<iframe />')
.attr('src', url)
.hide()
.appendTo('body');
};
</script>
3) my json to csv conversion function which tries to create a csv string
<script type="text/javascript">
function ConvertToCSV(json) {
var array = typeof json != 'object' ? JSON.parse(json) : json;
var str = '';
for (var i = 0; i < array.length; i++) {
var line = '';
for (var index in array[i]) {
if (line != '') line += ','
line += '"'+array[i][index]+'"';
}
str += line + "\r\n";
}
return str;
}
</script>
Encountered problems :
i) it seems that it doesn't recognize \r\n, infact output is just one line
"324","19-08-2014","13000""325","19-08-2014","5010"
ii) I cannot set the filename and the extension, infact the downloaded file is "download" without extension containing the single line mentioned above
First of all, you will need to ensure your data is in this format, like the example below.
var array = [["col1","col2","col3"],["324","19-08-2014","13000"],["324","19-08-2014","13000"]]
then you need to create csv variable as shown below
var csv = "data:text/csv;charset=utf-8,";
after this you need to loop through your data array and append each line to the csv variable you just set.
array.forEach(function(arrayItem, index){
arrayAsString = arrayItem.join(",");
csv += index < array.length ? arrayAsString+ "\n" : arrayAsString;
});
now to give this file a name and create a download link you must create a hidden anchor node and set its download attribute.
var encUri = encodeURI(csv);
var link = document.createElement("a");
link.setAttribute("href", encUri);
link.setAttribute("download", "file_name.csv");
//add anchor element to body
document.body.appendChild(link);
link.click();
EDIT:
Tested on Chrome and is working, also on Safari. Does not work on Firefox for some reason which i will take a look at now
I found out that if you add the link into the body of the page only then will Firefox initiate the download, you can use a code like so. I have updated my code above
document.body.appendChild(link);
I tried to export my html table to excel using the code given in this Gist. But after exporting, when i opened the file, It displays the html code of the demo page in excel. Can anyone please give the correct sample of javascript used to export the html table to excel (Should be opened in office Calc too).
EDIT: Attached the image screenshot.
Here is a function I made.
Add "remove" class on elements you do not want to show in the excel.
function exportExcel(id,name){ //<table> id and filename
var today = new Date();
var date = ('0'+today.getDate()).slice(-2)+"-"+('0'+(today.getMonth()+1)).slice(-2)+"-"+today.getFullYear();
var file_name = name+"_"+date+".xls"; //filename with current date, change if needed
var meta = '<meta http-equiv="content-type" content="text/html; charset=UTF-8" />';
var html = $("#"+id).clone();
html.find('.remove').remove(); //add the 'remove' class on elements you do not want to show in the excel
html.find('a').each(function() { //remove links, leave text only
var txt = $(this).text();
$(this).after(txt).remove();
});
html.find('input, textarea').each(function() { //replace inputs for their respectives texts
var txt = $(this).val().replace(/\r\n|\r|\n/g,"<br>");
$(this).after(txt).remove();
});
html.find('select').each(function() { //replace selects for their selected option text
var txt = $(this).find('option:selected').text();
$(this).after(txt).remove();
});
html.find('br').attr('style', "mso-data-placement:same-cell"); //make line breaks show in single cell
html = "<table>"+html.html()+"</table>";
var uri = 'data:application/vnd.ms-excel,'+encodeURIComponent(meta+html);
var a = $("<a>", {href: uri, download: file_name});
$(a)[0].click();
}
Call it on an event, example:
$("#export_button").click(function(e){
exportExcel("table_id", "filename");
});