changeset 5247d0b71e4d in sao:default
details: https://hg.tryton.org/sao?cmd=changeset;node=5247d0b71e4d
description:
        Always encode CSV export in UTF-8

        Browsers do not support the charset in Blob, so it is already always 
encoded in
        UTF-8. But to help users on Windows, we add the UTF-8 BOM because 
Windows
        programs use it as magic number to detect encoding.

        issue9527
        review290761002
diffstat:

 CHANGELOG     |    1 +
 src/sao.js    |    2 +
 src/tab.js    |    8 +-
 src/window.js |  169 ++++++++++++++++++++++++++++-----------------------------
 4 files changed, 92 insertions(+), 88 deletions(-)

diffs (270 lines):

diff -r db82cdef5541 -r 5247d0b71e4d CHANGELOG
--- a/CHANGELOG Sat Sep 12 18:28:22 2020 +0200
+++ b/CHANGELOG Sat Sep 12 18:30:11 2020 +0200
@@ -1,3 +1,4 @@
+* Always encode CSV export in UTF-8
 * Use tempusdominus and Popper for date time picker
 * Support PYSON comparison of date and datetime
 * Customize bootstrap default style
diff -r db82cdef5541 -r 5247d0b71e4d src/sao.js
--- a/src/sao.js        Sat Sep 12 18:28:22 2020 +0200
+++ b/src/sao.js        Sat Sep 12 18:30:11 2020 +0200
@@ -336,6 +336,8 @@
     };
     Sao.i18n.locale = {};
 
+    Sao.BOM_UTF8 = '\uFEFF';
+
     Sao.get_preferences = function() {
         var session = Sao.Session.current_session;
         return session.reload_context().then(function() {
diff -r db82cdef5541 -r 5247d0b71e4d src/tab.js
--- a/src/tab.js        Sat Sep 12 18:28:22 2020 +0200
+++ b/src/tab.js        Sat Sep 12 18:30:11 2020 +0200
@@ -1304,19 +1304,21 @@
                             return Sao.Window.Export.format_row(row);
                         });
                         var delimiter = ',';
-                        var encoding = 'utf-8';
                         if (navigator.platform &&
                             navigator.platform.slice(0, 3) == 'Win') {
                             delimiter = ';';
-                            encoding = 'cp1252';
                         }
                         var csv = Papa.unparse(unparse_obj, {
                             quoteChar: '"',
                             delimiter: delimiter,
                         });
+                        if (navigator.platform &&
+                            navigator.platform.slice(0, 3) == 'Win') {
+                            csv = Sao.BOM_UTF8 + csv;
+                        }
                         Sao.common.download_file(
                             csv, export_.name + '.csv',
-                            {'type': 'text/csv;charset=' + encoding});
+                            {'type': 'text/csv;charset=utf-8'});
                     });
             }.bind(this));
         },
diff -r db82cdef5541 -r 5247d0b71e4d src/window.js
--- a/src/window.js     Sat Sep 12 18:28:22 2020 +0200
+++ b/src/window.js     Sat Sep 12 18:30:11 2020 +0200
@@ -3,6 +3,53 @@
 (function() {
     'use strict';
 
+    var ENCODINGS = ["866", "ansi_x3.4-1968", "arabic", "ascii",
+        "asmo-708", "big5", "big5-hkscs", "chinese", "cn-big5", "cp1250",
+        "cp1251", "cp1252", "cp1253", "cp1254", "cp1255", "cp1256",
+        "cp1257", "cp1258", "cp819", "cp866", "csbig5", "cseuckr",
+        "cseucpkdfmtjapanese", "csgb2312", "csibm866", "csiso2022jp",
+        "csiso2022kr", "csiso58gb231280", "csiso88596e", "csiso88596i",
+        "csiso88598e", "csiso88598i", "csisolatin1", "csisolatin2",
+        "csisolatin3", "csisolatin4", "csisolatin5", "csisolatin6",
+        "csisolatin9", "csisolatinarabic", "csisolatincyrillic",
+        "csisolatingreek", "csisolatinhebrew", "cskoi8r", "csksc56011987",
+        "csmacintosh", "csshiftjis", "cyrillic", "dos-874", "ecma-114",
+        "ecma-118", "elot_928", "euc-jp", "euc-kr", "gb18030", "gb2312",
+        "gb_2312", "gb_2312-80", "gbk", "greek", "greek8", "hebrew",
+        "hz-gb-2312", "ibm819", "ibm866", "iso-2022-cn", "iso-2022-cn-ext",
+        "iso-2022-jp", "iso-2022-kr", "iso-8859-1", "iso-8859-10",
+        "iso-8859-11", "iso-8859-13", "iso-8859-14", "iso-8859-15",
+        "iso-8859-16", "iso-8859-2", "iso-8859-3", "iso-8859-4",
+        "iso-8859-5", "iso-8859-6", "iso-8859-6-e", "iso-8859-6-i",
+        "iso-8859-7", "iso-8859-8", "iso-8859-8-e", "iso-8859-8-i",
+        "iso-8859-9", "iso-ir-100", "iso-ir-101", "iso-ir-109",
+        "iso-ir-110", "iso-ir-126", "iso-ir-127", "iso-ir-138",
+        "iso-ir-144", "iso-ir-148", "iso-ir-149", "iso-ir-157", "iso-ir-58",
+        "iso8859-1", "iso8859-10", "iso8859-11", "iso8859-13", "iso8859-14",
+        "iso8859-15", "iso8859-2", "iso8859-3", "iso8859-4", "iso8859-5",
+        "iso8859-6", "iso8859-7", "iso8859-8", "iso8859-9", "iso88591",
+        "iso885910", "iso885911", "iso885913", "iso885914", "iso885915",
+        "iso88592", "iso88593", "iso88594", "iso88595", "iso88596",
+        "iso88597", "iso88598", "iso88599", "iso_8859-1", "iso_8859-15",
+        "iso_8859-1:1987", "iso_8859-2", "iso_8859-2:1987", "iso_8859-3",
+        "iso_8859-3:1988", "iso_8859-4", "iso_8859-4:1988", "iso_8859-5",
+        "iso_8859-5:1988", "iso_8859-6", "iso_8859-6:1987", "iso_8859-7",
+        "iso_8859-7:1987", "iso_8859-8", "iso_8859-8:1988", "iso_8859-9",
+        "iso_8859-9:1989", "koi", "koi8", "koi8-r", "koi8-ru", "koi8-u",
+        "koi8_r", "korean", "ks_c_5601-1987", "ks_c_5601-1989", "ksc5601",
+        "ksc_5601", "l1", "l2", "l3", "l4", "l5", "l6", "l9", "latin1",
+        "latin2", "latin3", "latin4", "latin5", "latin6", "logical", "mac",
+        "macintosh", "ms932", "ms_kanji", "shift-jis", "shift_jis", "sjis",
+        "sun_eu_greek", "tis-620", "unicode-1-1-utf-8", "us-ascii",
+        "utf-16", "utf-16be", "utf-16le", "utf-8", "utf8", "visual",
+        "windows-1250", "windows-1251", "windows-1252", "windows-1253",
+        "windows-1254", "windows-1255", "windows-1256", "windows-1257",
+        "windows-1258", "windows-31j", "windows-874", "windows-949",
+        "x-cp1250", "x-cp1251", "x-cp1252", "x-cp1253", "x-cp1254",
+        "x-cp1255", "x-cp1256", "x-cp1257", "x-cp1258", "x-euc-jp", "x-gbk",
+        "x-mac-cyrillic", "x-mac-roman", "x-mac-ukrainian", "x-sjis",
+        "x-user-defined", "x-x-big5"];
+
     Sao.Window = {};
 
     Sao.Window.InfoBar = Sao.class_(Object, {
@@ -860,52 +907,6 @@
 
     Sao.Window.CSV = Sao.class_(Object, {
         init: function(title) {
-            this.encodings = ["866", "ansi_x3.4-1968", "arabic", "ascii",
-            "asmo-708", "big5", "big5-hkscs", "chinese", "cn-big5", "cp1250",
-            "cp1251", "cp1252", "cp1253", "cp1254", "cp1255", "cp1256",
-            "cp1257", "cp1258", "cp819", "cp866", "csbig5", "cseuckr",
-            "cseucpkdfmtjapanese", "csgb2312", "csibm866", "csiso2022jp",
-            "csiso2022kr", "csiso58gb231280", "csiso88596e", "csiso88596i",
-            "csiso88598e", "csiso88598i", "csisolatin1", "csisolatin2",
-            "csisolatin3", "csisolatin4", "csisolatin5", "csisolatin6",
-            "csisolatin9", "csisolatinarabic", "csisolatincyrillic",
-            "csisolatingreek", "csisolatinhebrew", "cskoi8r", "csksc56011987",
-            "csmacintosh", "csshiftjis", "cyrillic", "dos-874", "ecma-114",
-            "ecma-118", "elot_928", "euc-jp", "euc-kr", "gb18030", "gb2312",
-            "gb_2312", "gb_2312-80", "gbk", "greek", "greek8", "hebrew",
-            "hz-gb-2312", "ibm819", "ibm866", "iso-2022-cn", "iso-2022-cn-ext",
-            "iso-2022-jp", "iso-2022-kr", "iso-8859-1", "iso-8859-10",
-            "iso-8859-11", "iso-8859-13", "iso-8859-14", "iso-8859-15",
-            "iso-8859-16", "iso-8859-2", "iso-8859-3", "iso-8859-4",
-            "iso-8859-5", "iso-8859-6", "iso-8859-6-e", "iso-8859-6-i",
-            "iso-8859-7", "iso-8859-8", "iso-8859-8-e", "iso-8859-8-i",
-            "iso-8859-9", "iso-ir-100", "iso-ir-101", "iso-ir-109",
-            "iso-ir-110", "iso-ir-126", "iso-ir-127", "iso-ir-138",
-            "iso-ir-144", "iso-ir-148", "iso-ir-149", "iso-ir-157", 
"iso-ir-58",
-            "iso8859-1", "iso8859-10", "iso8859-11", "iso8859-13", 
"iso8859-14",
-            "iso8859-15", "iso8859-2", "iso8859-3", "iso8859-4", "iso8859-5",
-            "iso8859-6", "iso8859-7", "iso8859-8", "iso8859-9", "iso88591",
-            "iso885910", "iso885911", "iso885913", "iso885914", "iso885915",
-            "iso88592", "iso88593", "iso88594", "iso88595", "iso88596",
-            "iso88597", "iso88598", "iso88599", "iso_8859-1", "iso_8859-15",
-            "iso_8859-1:1987", "iso_8859-2", "iso_8859-2:1987", "iso_8859-3",
-            "iso_8859-3:1988", "iso_8859-4", "iso_8859-4:1988", "iso_8859-5",
-            "iso_8859-5:1988", "iso_8859-6", "iso_8859-6:1987", "iso_8859-7",
-            "iso_8859-7:1987", "iso_8859-8", "iso_8859-8:1988", "iso_8859-9",
-            "iso_8859-9:1989", "koi", "koi8", "koi8-r", "koi8-ru", "koi8-u",
-            "koi8_r", "korean", "ks_c_5601-1987", "ks_c_5601-1989", "ksc5601",
-            "ksc_5601", "l1", "l2", "l3", "l4", "l5", "l6", "l9", "latin1",
-            "latin2", "latin3", "latin4", "latin5", "latin6", "logical", "mac",
-            "macintosh", "ms932", "ms_kanji", "shift-jis", "shift_jis", "sjis",
-            "sun_eu_greek", "tis-620", "unicode-1-1-utf-8", "us-ascii",
-            "utf-16", "utf-16be", "utf-16le", "utf-8", "utf8", "visual",
-            "windows-1250", "windows-1251", "windows-1252", "windows-1253",
-            "windows-1254", "windows-1255", "windows-1256", "windows-1257",
-            "windows-1258", "windows-31j", "windows-874", "windows-949",
-            "x-cp1250", "x-cp1251", "x-cp1252", "x-cp1253", "x-cp1254",
-            "x-cp1255", "x-cp1256", "x-cp1257", "x-cp1258", "x-euc-jp", 
"x-gbk",
-            "x-mac-cyrillic", "x-mac-roman", "x-mac-ukrainian", "x-sjis",
-            "x-user-defined", "x-x-big5"];
             this.dialog = new Sao.Dialog(title, 'csv', 'lg');
             this.el = this.dialog.modal;
 
@@ -1078,38 +1079,6 @@
                 .appendTo(this.expander_csv);
             this.expander_csv.append(' ');
 
-            var encoding_label = jQuery('<label/>', {
-                'text': Sao.i18n.gettext('Encoding:'),
-                'class': 'control-label',
-                'for': 'input-encoding'
-            });
-
-            this.el_csv_encoding = jQuery('<select/>', {
-                'class': 'form-control',
-                'id': 'input-encoding'
-            });
-
-            for(var i=0; i<this.encodings.length; i++) {
-                jQuery('<option/>', {
-                    'val': this.encodings[i]
-                }).append(this.encodings[i]).appendTo(this.el_csv_encoding);
-            }
-
-            var enc = 'utf-8';
-            if (navigator.platform &&
-                    navigator.platform.slice(0, 3) == 'Win') {
-                enc = 'cp1252';
-            }
-            this.el_csv_encoding.children('option[value="' + enc + '"]')
-            .attr('selected', 'selected');
-
-            jQuery('<div/>', {
-                'class': 'form-group'
-            }).append(encoding_label)
-                .append(this.el_csv_encoding)
-                .appendTo(this.expander_csv);
-            this.expander_csv.append(' ');
-
             this.el.modal('show');
             this.el.on('hidden.bs.modal', function() {
                 jQuery(this).remove();
@@ -1169,6 +1138,38 @@
             }).append(this.file_input))
             .appendTo(this.chooser_form);
 
+            var encoding_label = jQuery('<label/>', {
+                'text': Sao.i18n.gettext('Encoding:'),
+                'class': 'control-label',
+                'for': 'input-encoding'
+            });
+
+            this.el_csv_encoding = jQuery('<select/>', {
+                'class': 'form-control',
+                'id': 'input-encoding'
+            });
+
+            for(var i=0; i < ENCODINGS.length; i++) {
+                jQuery('<option/>', {
+                    'val': ENCODINGS[i]
+                }).append(ENCODINGS[i]).appendTo(this.el_csv_encoding);
+            }
+
+            var enc = 'utf-8';
+            if (navigator.platform &&
+                    navigator.platform.slice(0, 3) == 'Win') {
+                enc = 'cp1252';
+            }
+            this.el_csv_encoding.children('option[value="' + enc + '"]')
+            .attr('selected', 'selected');
+
+            jQuery('<div/>', {
+                'class': 'form-group'
+            }).append(encoding_label)
+                .append(this.el_csv_encoding)
+                .appendTo(this.expander_csv);
+            this.expander_csv.append(' ');
+
             var skip_label = jQuery('<label/>', {
                 'text': Sao.i18n.gettext('Lines to Skip:'),
                 'class': 'control-label',
@@ -1870,7 +1871,6 @@
             }
         },
         export_csv: function(fields, data) {
-            var encoding = this.el_csv_encoding.val();
             var locale_format = this.el_csv_locale.prop('checked');
             var unparse_obj = {};
             unparse_obj.data = data.map(function(row) {
@@ -1883,8 +1883,12 @@
                 quoteChar: this.el_csv_quotechar.val(),
                 delimiter: this.el_csv_delimiter.val()
             });
+            if (navigator.platform &&
+                navigator.platform.slice(0, 3) == 'Win') {
+                csv = Sao.BOM_UTF8 + csv;
+            }
             Sao.common.download_file(
-                csv, this.name + '.csv', {type: 'text/csv;charset=' + 
encoding});
+                csv, this.name + '.csv', {type: 'text/csv;charset=utf-8'});
             return Sao.common.message.run(
                 Sao.i18n.ngettext('%1 record saved', '%1 records saved',
                     data.length));
@@ -1926,11 +1930,6 @@
                 query_string.push(['f', field.getAttribute('path')]);
             });
 
-            var encoding = this.el_csv_encoding.val();
-            if (encoding) {
-                query_string.push(['enc', encoding]);
-            }
-
             query_string.push(['dl', this.el_csv_delimiter.val()]);
             query_string.push(['qc', this.el_csv_quotechar.val()]);
 

Reply via email to