Accented letters not showing properly when exporting CSV using javascript - javascript

I am doing an export to CSV functionality on my website. The data are in spanish so there will be alot of accented characters in there, and one example of this problem is the header "Año" (year) but on excel it shows as "Año".
Here is my export code using javascript:
HTML
Export
Download Now
JS
$(document).on('click', '#export-btn', function(e) {
var _this = $(this);
_this.attr('disabled',true);
var datenow = new Date();
datenow = datenow.getTime();
var exportdata = ConvertToCSV(exportdata);
$('#download').attr("href", "data:text/csv;charset=utf8," + encodeURIComponent(exportdata) );
$('#download').attr("download", "InTrack-Report-"+datenow+".csv");
$('#download').show(); //show download button
_this.attr('disabled',false);
});
here is the ConvertToCSV function, I added sep=; to make excel recognize the semicolon as delimiters.
function ConvertToCSV(objArray) {
var array = typeof objArray != 'object' ? JSON.parse(objArray) : objArray;
var str = 'sep=;\r\n'; //tell excel that we used semicolon as separator
//header
var line = '';
for (var i = 0; i < array.Fields.length; i++) {
if (line != '') line += ';'
line += array.Fields[i]['Title'];
}
str += line + '\r\n';
//rows
for (var i = 0; i < array.Rows.length; i++) {
var line = '';
for (var index in array.Rows[i]) {
if (line != '') line += ';'
line += array.Rows[i][index];
}
str += line + '\r\n';
}
return str;
}
UPDATE:
I found a way to display the accented letters properly by following the solution here. But I had to remove the sep=; which is important as it separates my data by semicolon. Is there a way to add both the BOM and the sep=; at the top? If so, how? Because it seems like I can only use one.
So instead of str='sep=;\r\n' it is now str='\uFEFF sep=;\r\n'

if you get an error with the ASCII in the creation of file.csv, try adding the BOM first.
var BOM = "\uFEFF";
return BOM + str;
and then crate the file headers with the data: "text/csv;charset=utf-8"
instead of utf8 (without - )

Use escape at place of encodeURI and add "sep=;\n" before string and allow it to escape as well
Sample code
var csvString = "sep=;\n" + csvRows.join("\n");
var a = document.createElement('a');
a.href = 'data:attachment/csv;charset=UTF-8,%EF%BB%BF' + escape(csvString);

Related

Javascript spilt function does not recognise one of the tabs in my string

I have a string with tab-separated data copied from Excel. The javascript split does not recognise the 2nd tab in the string. I have pasted the string into notepad++ to see the tabs and they are all there. Exploding the string in PHP works fine. The test code is:
function testTab(str) {
var strSplit = str.split('\t');
for (i=0; i < strSplit.length; i++){
console.log('strSplit['+i+'] = '+strSplit[i]);
}
}
The console output (where the tab between 1st and 2nd item is not recognised):
strSplit[0] = 0.02194 0.028940568
strSplit[1] = 0.05227
strSplit[2] = 0.040229885
strSplit[3] = 0.04650
strSplit[4] = 0.035630689
strSplit[5] = 0.07055
strSplit[6] = 0.015557256
strSplit[7] = 0.01960
strSplit[8] = 0.03527
strSplit[9] = 0.05276
strSplit[10] = 0.05669
strSplit[11] = 0.05680
strSplit[12] = 0.04464
strSplit[13] = 1
Unsure if the string copies correctly with all tabs, but here it is:
const str = `0.02194 0.028940568 0.05227 0.040229885 0.04650 0.035630689 0.07055 0.015557256 0.01960 0.03527 0.05276 0.05669 0.05680 0.04464 1`;
function testTab(str) {
var strSplit = str.split('\t');
for (i = 0; i < strSplit.length; i++) {
console.log('strSplit[' + i + '] = ' + strSplit[i]);
}
}
testTab(str)
Thanks for your suggestions, it inspired me to review all options.
I changed the delimiters in the regex so that the split now reads:
var strSplit = str.split(/\t/);
For some reason it now works.

Passing tab delimiter through via parameter not splitting string

My issue essentially is, I have a select box that has 2 options "Tab or CSV", those options meaning what to split a string on, my issue is when every I pass through "\t" as a parameter, it doesn't split on tabs. if I explictly type "\t" it splits the string but not if its being passed via a parameter.
I am trying to create a sql results to jira table chrome extention
The issues reside in the GetDelimiterType function and GenerateLine< first line.
I have no idea what is going on, if i check the value of delimerType it reads "\t" but doesn't split
$("#btn").click(function(){
var textToChange = $("#input").val().split("\n");
var topLineRow = $("#topRow").prop("checked");
var delimiterType = $("#delimiterSelect option:selected").val();
var jiraTable = "";
debugger;
if(topLineRow){
jiraTable += GenerateLine("||", textToChange[0], GetDelimiterType(delimiterType))
}
topLineRow = false;
var generatedString = "";
$.each(textToChange, function(index, value){
if(!topLineRow){
jiraTable += GenerateLine("|", textToChange[index],GetDelimiterType(delimiterType));
}
})
alert(jiraTable);
})
function GetDelimiterType(delimiterType){
debugger;
if(delimiterType == 0){
return ",";
}else if(delimiterType == 1){
return "\\t";
}
}
function GenerateLine(seperator, row, delimiter){
var rowArray = row.split(delimiter);
var rowText = "";
$.each(rowArray, function(index, value){
var isLastElement = index == rowArray.length -1;
value = value.replace(/\s/g,'');
if(index == 0){
rowText += seperator;
}
if(isLastElement){
rowText += value + seperator + "\n";
}else{
rowText += value + seperator;
}
});
return rowText;
}
.split(/.../)
.split() method can pass a regex literal as a delimiter.
/\b[^\S]+?\b|,\s/
\boundary meta-sequence denotes a non-spaced character next to a word character
[^\S]+? class ignores one or more non-whitespace characters
\b as above
|,\s OR a literal comma followed by a space
Demo
var row = `Mike, Alpha, Tango, Tango Zulu Echo Romeo 0 0 November Echo`;
var rowArray = row.split(/\b[^\S]+?\b|,\s/);
console.log(JSON.stringify(rowArray));

Remove HTML tags in script

I've found this piece of code on the internet. It takes a sentence and makes every single word into link with this word. But it has weak side: if a sentence has HTML in it, this script doesn't remove it.
For example: it replaces '<b>asserted</b>' with 'http://www.merriam-webster.com/dictionary/<b>asserted</b>'
Could you please tell me what to change in this code for it to change '<b>asserted</b>' to 'http://www.merriam-webster.com/dictionary/asserted'.
var content = document.getElementById("sentence").innerHTML;
var punctuationless = content.replace(/[.,\/#!$%\؟^?&\*;:{}=\-_`~()”“"]/g, "");
var mixedCase = punctuationless.replace(/\s{2,}/g);
var finalString = mixedCase.toLowerCase();
var words = (finalString).split(" ");
var punctuatedWords = (content).split(" ");
var processed = "";
for (i = 0; i < words.length; i++) {
processed += "<a href = \"http://www.merriam-webster.com/dictionary/" + words[i] + "\">";
processed += punctuatedWords[i];
processed += "</a> ";
}
document.getElementById("sentence").innerHTML = processed;
This regex /<{1}[^<>]{1,}>{1}/g should replace any text in a string that is between two of these <> and the brackets themselves with a white space. This
var str = "<hi>How are you<hi><table><tr>I<tr><table>love cake<g>"
str = str.replace(/<{1}[^<>]{1,}>{1}/g," ")
document.writeln(str);
will give back " How are you I love cake".
If you paste this
var stripHTML = str.mixedCase(/<{1}[^<>]{1,}>{1}/g,"")
just below this
var mixedCase = punctuationless.replace(/\s{2,}/g);
and replace mixedCase with stripHTML in the line after, it will probably work
function stripAllHtml(str) {
if (!str || !str.length) return ''
str = str.replace(/<script.*?>.*?<\/script>/igm, '')
let tmp = document.createElement("DIV");
tmp.innerHTML = str;
return tmp.textContent || tmp.innerText || "";
}
stripAllHtml('<a>test</a>')
This function will strip all the HTML and return only text.
Hopefully, this will work for you
if you need to remove HTML tags And HTML Entities You can use
const text = '<p>test content </p><p><strong>test bold</strong> </p>'
text.replace(/<[^>]*(>|$)| |‌|»|«|>/g, '');
the result will be "test content test bold"

AppendTo previous iteration (each)

I have the following code, which should split this string #266##271##295# into this
266
271
295
and append it to the same container where it came from: .groups
$('.groups').each(function(){
var str = $(this).html();
if (str.substring(0, 1) == '#') {
str = str.substring(1); // Remove first #
}
if(str.substring(str.length-1, str.length) == '#'){
str = str.substring(0, str.length-1); // Remove last #
}
str = str.split(/[##]+/);
$(this).empty(); // empty the groups container
$.each(str, function(index, val){
alert(val);
var html = '' + val + ''
$(html).appendTo(this);
});
});
My problem (i think) is the line $(html).appendTo(this);
i somehow need to add it to the previous each().
How can I do this. Or am I moving in the wrong direction with this code?
I think you made this way too complicated, just do this:
var str = $(this).html();
var parts = str.split("#");
var html = "";
for (var i = 0; i < parts.length; i++) {
html += '' + parts[i] + '';
}
$(this).append(html);
Something like this?
$('.groups').each(function(){
var str = $(this).html();
if (str.substring(0, 1) == '#') {
str = str.substring(1); // Remove first #
}
if(str.substring(str.length-1, str.length) == '#'){
str = str.substring(0, str.length-1); // Remove last #
}
str = str.split(/[##]+/);
$(this).empty(); // empty the groups container
var target = $(this);
$.each(str, function(index, val){
alert(val);
var html = '' + val + ''
$(html).appendTo(target);
});
});
I added the var target = $(this) outside your second loop as a reference that you can use inside your second loop.
You do need to be mindful of the leading and trailing #'s, but you can easily trim them while you split with a clever regex. When you use $.each to iterate over an array, the this reference no longer refers to your original context but to the current item. Constructing the item's markup and concatenating to a string which you insert outside of the loop will not only get around this, but also provide better performance since you will only be doing one DOM insertion.
$('.groups').each(function(){
var str = $(this).html();
str = str.replace(/^#+|#+$/g, ''); // trim leading and trailing #
var links = str.split("#");
var markup = '';
$.each(links, function(){
markup += '' + this + "\n";
});
$(markup).appendTo(this);
});

Is there a way to remove %20 from dynamically created breadcrumbs?

So, I was messing around with this Dynamic Breadcrumbs write-up, and came across an issue where if the directory name has a space in it, then %20 gets added to the actual visible breadcrumb. Would this be removed using the decodeURI() function or is there a better way?
Here's the js:
var crumbsep = " • ";
var precrumb = "<span class=\"crumb\">";
var postcrumb = "</span>";
var sectionsep = "/";
var rootpath = "/"; // Use "/" for root of domain.
var rootname = "Home";
var ucfirst = 1; // if set to 1, makes "directory" default to "Directory"
var objurl = new Object;
// Grab the page's url and break it up into directory pieces
var pageurl = (new String(document.location));
var protocol = pageurl.substring(0, pageurl.indexOf("//") + 2);
pageurl = pageurl.replace(protocol, ""); // remove protocol from pageurl
var rooturl = pageurl.substring(0, pageurl.indexOf(rootpath) + rootpath.length); // find rooturl
if (rooturl.charAt(rooturl.length - 1) == "/") //remove trailing slash
{
rooturl = rooturl.substring(0, rooturl.length - 1);
}
pageurl = pageurl.replace(rooturl, ""); // remove rooturl from pageurl
if (pageurl.charAt(0) == '/') // remove beginning slash
{
pageurl = pageurl.substring(1, pageurl.length);
}
var page_ar = pageurl.split(sectionsep);
var currenturl = protocol + rooturl;
var allbread = precrumb + "" + rootname + "" + postcrumb; // start with root
for (i=0; i < page_ar.length-1; i++)
{
var displayname = "";
currenturl += "/" + page_ar[i];
if (objurl[page_ar[i]])
{
displayname = objurl[page_ar[i]];
}
else
{
if (ucfirst == 1)
{
displayname = page_ar[i].charAt(0).toUpperCase() + page_ar[i].substring(1);
}
else
{
displayname = page_ar[i];
}
}
if ( i < page_ar.length -2 )
{
allbread += precrumb + crumbsep + "" + displayname + "" + postcrumb;
}
else
{
allbread += crumbsep + displayname;
}
}
document.write(allbread);
If decodeURI() was to be used, where exactly would it go? Also, more unrelated, would there be an option you could add to the code above that would make the actual page inside of the directory be included in the breadcrumbs as the last item instead of the last directory? Not real important but thought I would ask as well. Thanks for any input!
Yes, decodeURI will do the trick. You can add the line displayname = decodeURI(displayname); right before the if that reads if ( i < page_ar.length -2 ):
...
displayname = decodeURI(displayname);
if ( i < page_ar.length -2 )
...
Note that since displayname and currenturl end up being directly embedded in a raw HTML string, any special HTML characters should be escaped first, otherwise you're open to some XSS attacks (imagine some malicious individual posting a link to your site like yoursite.com/valid/page/%3Cscript%3Ealert%28%22Oh%20no%2C%20not%20XSS%21%22%29%3C%2Fscript%3E). One of the simplest ways to do so is covered by this answer, though it requires jQuery.
If you want the current page included in the breadcrumbs, I believe it is sufficient to change the loop to go from 0 to page_ar.length instead of page_ar.length - 1:
...
for (i=0; i < page_ar.length; i++)
...
You should use decodeURIComponent(), not decodeURI() for this. It's a little hard to see what you're trying to do, but here's some simpler code that will give you an array of the 'directories' in the current URI, decoded:
var dirs = location.pathname.split('/');
for (var i=0,len=dirs.length;i<len;++i){
dirs[i] = decodeURIComponent(dirs[i]);
}

Categories

Resources