Merge pull request #2939 from FinnStutzenstein/Encoding

Added UTF-8 byte order mark for csv export
This commit is contained in:
Emanuel Schütze 2017-02-10 21:23:09 +01:00 committed by GitHub
commit 311b134d81
11 changed files with 42 additions and 39 deletions

View File

@ -46,6 +46,7 @@ Core:
- Added watching permissions in client and change the view immediately on changes. - Added watching permissions in client and change the view immediately on changes.
- Validate HTML strings from CKEditor against XSS attacks. - Validate HTML strings from CKEditor against XSS attacks.
- Added success/error symbol to config to show if saving was successful. - Added success/error symbol to config to show if saving was successful.
- Added UTF-8 byte order mark for every CSV export.
Motions: Motions:
- Added adjustable line numbering mode (outside, inside, none) for each - Added adjustable line numbering mode (outside, inside, none) for each

View File

@ -16,7 +16,7 @@ angular.module('OpenSlidesApp.agenda.csv', [])
}); });
}; };
return { return {
export: function (element, agenda) { export: function (agenda) {
var csvRows = [ var csvRows = [
makeHeaderline() makeHeaderline()
]; ];
@ -32,7 +32,7 @@ angular.module('OpenSlidesApp.agenda.csv', [])
row.push('"' + (item.is_hidden ? '1' : '') + '"'); row.push('"' + (item.is_hidden ? '1' : '') + '"');
csvRows.push(row); csvRows.push(row);
}); });
CsvDownload(csvRows, element, 'agenda-export.csv'); CsvDownload(csvRows, 'agenda-export.csv');
}, },
}; };
} }

View File

@ -270,8 +270,7 @@ angular.module('OpenSlidesApp.agenda.site', [
PdfCreate.download(documentProvider.getDocument(), filename); PdfCreate.download(documentProvider.getDocument(), filename);
}; };
$scope.csvExport = function () { $scope.csvExport = function () {
var element = document.getElementById('downloadLinkCSV'); AgendaCsvExport.export($scope.itemsFiltered);
AgendaCsvExport.export(element, $scope.itemsFiltered);
}; };
/** select mode functions **/ /** select mode functions **/

View File

@ -105,6 +105,16 @@ def get_config_variables():
group='General', group='General',
subgroup='System') subgroup='System')
# CSV
yield ConfigVariable(
name='general_csv_separator',
default_value=',',
label='The separator used for the csv export and examples',
weight=144,
group='General',
subgroup='CSV')
# Projector # Projector
yield ConfigVariable( yield ConfigVariable(

View File

@ -5,19 +5,17 @@
angular.module('OpenSlidesApp.core.csv', []) angular.module('OpenSlidesApp.core.csv', [])
.factory('CsvDownload', [ .factory('CsvDownload', [
function () { 'Config',
return function (contentRows, element, fileName) { 'FileSaver',
if (navigator.msSaveBlob && typeof navigator.msSaveBlob === 'function') { function (Config, FileSaver) {
// Bad browsers var utf8_BOM = decodeURIComponent('%EF%BB%BF');
var blob = new Blob([contentRows.join('\r\n')]); return function (contentRows, filename) {
navigator.msSaveBlob(blob, fileName); var separator = Config.get('general_csv_separator').value;
} else { // Good browsers var rows = _.map(contentRows, function (row) {
// %0A is the url encoded linefeed character. Needed to be return row.join(separator);
// percentage encoded for the data url. });
element.href = 'data:text/csv;charset=utf-8,' + contentRows.join('%0A'); var blob = new Blob([utf8_BOM + rows.join('\n')]);
element.download = fileName; FileSaver.saveAs(blob, filename);
element.target = '_blank';
}
}; };
} }
]); ]);

View File

@ -15,7 +15,7 @@ angular.module('OpenSlidesApp.motions.csv', [])
}); });
}; };
return { return {
export: function (element, motions) { export: function (motions) {
var csvRows = [ var csvRows = [
makeHeaderline() makeHeaderline()
]; ];
@ -32,16 +32,16 @@ angular.module('OpenSlidesApp.motions.csv', [])
row.push('"' + motion.origin + '"'); row.push('"' + motion.origin + '"');
csvRows.push(row); csvRows.push(row);
}); });
CsvDownload(csvRows, element, 'motions-export.csv'); CsvDownload(csvRows, 'motions-export.csv');
}, },
downloadExample: function (element) { downloadExample: function () {
var csvRows = [makeHeaderline(), var csvRows = [makeHeaderline(),
// example entries // example entries
['A1', 'Title 1', 'Text 1', 'Reason 1', 'Submitter A', 'Category A', 'Last Year Conference A'], ['A1', 'Title 1', 'Text 1', 'Reason 1', 'Submitter A', 'Category A', 'Last Year Conference A'],
['B1', 'Title 2', 'Text 2', 'Reason 2', 'Submitter B', 'Category B', '' ], ['B1', 'Title 2', 'Text 2', 'Reason 2', 'Submitter B', 'Category B', ''],
['' , 'Title 3', 'Text 3', '' , '' , '' , '' ], ['' , 'Title 3', 'Text 3', '', '', '', ''],
]; ];
CsvDownload(csvRows, element, 'motions-example.csv'); CsvDownload(csvRows, 'motions-example.csv');
}, },
}; };
} }

View File

@ -880,8 +880,7 @@ angular.module('OpenSlidesApp.motions.site', [
// Export as a csv file // Export as a csv file
$scope.csvExport = function () { $scope.csvExport = function () {
var element = document.getElementById('downloadLinkCSV'); MotionCsvExport.export($scope.motionsFiltered);
MotionCsvExport.export(element, $scope.motionsFiltered);
}; };
// Export as docx file // Export as docx file
$scope.docxExport = function () { $scope.docxExport = function () {
@ -1746,8 +1745,7 @@ angular.module('OpenSlidesApp.motions.site', [
}; };
// download CSV example file // download CSV example file
$scope.downloadCSVExample = function () { $scope.downloadCSVExample = function () {
var element = document.getElementById('downloadLink'); MotionCsvExport.downloadExample();
MotionCsvExport.downloadExample(element);
}; };
} }
]) ])

View File

@ -15,7 +15,7 @@ angular.module('OpenSlidesApp.topics.csv', [])
}); });
}; };
return { return {
downloadExample: function (element) { downloadExample: function () {
var csvRows = [makeHeaderline(), var csvRows = [makeHeaderline(),
// example entries // example entries
['Demo 1', 'Demo text 1', '1:00', 'test comment', ''], ['Demo 1', 'Demo text 1', '1:00', 'test comment', ''],
@ -23,7 +23,7 @@ angular.module('OpenSlidesApp.topics.csv', [])
['Demo 2', 'Demo text 2', '1:30', '', ''] ['Demo 2', 'Demo text 2', '1:30', '', '']
]; ];
CsvDownload(csvRows, element, 'agenda-example.csv'); CsvDownload(csvRows, 'agenda-example.csv');
}, },
}; };
} }

View File

@ -372,8 +372,7 @@ angular.module('OpenSlidesApp.topics.site', ['OpenSlidesApp.topics', 'OpenSlides
}; };
// download CSV example file // download CSV example file
$scope.downloadCSVExample = function () { $scope.downloadCSVExample = function () {
var element = document.getElementById('downloadLink'); TopicsCsvExample.downloadExample();
TopicsCsvExample.downloadExample(element);
}; };
} }
]); ]);

View File

@ -17,7 +17,7 @@ angular.module('OpenSlidesApp.users.csv', [])
}); });
}; };
return { return {
export: function (element, users) { export: function (users) {
var csvRows = [ var csvRows = [
makeHeaderline() makeHeaderline()
]; ];
@ -38,10 +38,10 @@ angular.module('OpenSlidesApp.users.csv', [])
row.push(user.is_committee ? '1' : '0'); row.push(user.is_committee ? '1' : '0');
csvRows.push(row); csvRows.push(row);
}); });
CsvDownload(csvRows, element, 'users-export.csv'); CsvDownload(csvRows, 'users-export.csv');
}, },
downloadExample: function (element) { downloadExample: function () {
// try to get an example with two groups and one with one group // try to get an example with two groups and one with one group
var groups = Group.getAll(); var groups = Group.getAll();
var csvGroups = ''; var csvGroups = '';
@ -62,7 +62,7 @@ angular.module('OpenSlidesApp.users.csv', [])
['', '', 'Executive Board', '', '', '', '', '', '', '1'], ['', '', 'Executive Board', '', '', '', '', '', '', '1'],
]; ];
CsvDownload(csvRows, element, 'users-example.csv'); CsvDownload(csvRows, 'users-example.csv');
} }
}; };
} }

View File

@ -636,8 +636,7 @@ angular.module('OpenSlidesApp.users.site', [
}; };
// Export as a csv file // Export as a csv file
$scope.csvExport = function () { $scope.csvExport = function () {
var element = document.getElementById('downloadLinkCSV'); UserCsvExport.export($scope.usersFiltered);
UserCsvExport.export(element, $scope.usersFiltered);
}; };
} }
]) ])
@ -1086,8 +1085,7 @@ angular.module('OpenSlidesApp.users.site', [
}; };
// download CSV example file // download CSV example file
$scope.downloadCSVExample = function () { $scope.downloadCSVExample = function () {
var element = document.getElementById('downloadLink'); UserCsvExport.downloadExample();
UserCsvExport.downloadExample(element);
}; };
} }
]) ])