Hi,

Please find the attached patch for RM #2781 : New option to set the
quotation mark for copying to clipboard.

This patch includes:

- Provide options in preferences to control the CSV output which includes
copy to clipboard and download as CSV features in Query Tool
- Modified related jasmine tests
- Modified related feature tests

Thanks,
Khushboo
diff --git a/web/pgadmin/feature_tests/copy_selected_query_results_feature_test.py b/web/pgadmin/feature_tests/copy_selected_query_results_feature_test.py
index d01bf66..41fd6da 100644
--- a/web/pgadmin/feature_tests/copy_selected_query_results_feature_test.py
+++ b/web/pgadmin/feature_tests/copy_selected_query_results_feature_test.py
@@ -66,7 +66,7 @@ class CopySelectedQueryResultsFeatureTest(BaseFeatureTest):
 
         self.page.find_by_xpath("//*[@id='btn-copy-row']").click()
 
-        self.assertEqual("'Some-Name','6','some info'",
+        self.assertEqual('"Some-Name","6","some info"',
                          pyperclip.paste())
 
     def _copies_columns(self):
@@ -75,9 +75,9 @@ class CopySelectedQueryResultsFeatureTest(BaseFeatureTest):
         self.page.find_by_xpath("//*[@id='btn-copy-row']").click()
 
         self.assertEqual(
-            """'Some-Name'
-'Some-Other-Name'
-'Yet-Another-Name'""",
+            """\"Some-Name"
+"Some-Other-Name"
+"Yet-Another-Name\"""",
             pyperclip.paste())
 
     def _copies_row_using_keyboard_shortcut(self):
@@ -86,7 +86,7 @@ class CopySelectedQueryResultsFeatureTest(BaseFeatureTest):
 
         ActionChains(self.page.driver).key_down(Keys.CONTROL).send_keys('c').key_up(Keys.CONTROL).perform()
 
-        self.assertEqual("'Some-Name','6','some info'",
+        self.assertEqual('"Some-Name","6","some info"',
                          pyperclip.paste())
 
     def _copies_column_using_keyboard_shortcut(self):
@@ -96,9 +96,9 @@ class CopySelectedQueryResultsFeatureTest(BaseFeatureTest):
         ActionChains(self.page.driver).key_down(Keys.CONTROL).send_keys('c').key_up(Keys.CONTROL).perform()
 
         self.assertEqual(
-            """'Some-Name'
-'Some-Other-Name'
-'Yet-Another-Name'""",
+            """\"Some-Name"
+"Some-Other-Name"
+"Yet-Another-Name\"""",
             pyperclip.paste())
 
     def _copies_rectangular_selection(self):
@@ -112,8 +112,8 @@ class CopySelectedQueryResultsFeatureTest(BaseFeatureTest):
             .release(bottom_right_cell).perform()
         ActionChains(self.page.driver).key_down(Keys.CONTROL).send_keys('c').key_up(Keys.CONTROL).perform()
 
-        self.assertEqual("""'Some-Other-Name','22'
-'Yet-Another-Name','14'""", pyperclip.paste())
+        self.assertEqual("""\"Some-Other-Name","22"
+"Yet-Another-Name","14\"""", pyperclip.paste())
 
     def _shift_resizes_rectangular_selection(self):
         pyperclip.copy("old clipboard contents")
@@ -128,8 +128,8 @@ class CopySelectedQueryResultsFeatureTest(BaseFeatureTest):
         ActionChains(self.page.driver).key_down(Keys.SHIFT).send_keys(Keys.ARROW_RIGHT).key_up(Keys.SHIFT).perform()
         ActionChains(self.page.driver).key_down(Keys.CONTROL).send_keys('c').key_up(Keys.CONTROL).perform()
 
-        self.assertEqual("""'Some-Other-Name','22','some other info'
-'Yet-Another-Name','14','cool info'""", pyperclip.paste())
+        self.assertEqual("""\"Some-Other-Name","22","some other info"
+"Yet-Another-Name","14","cool info\"""", pyperclip.paste())
 
     def _shift_resizes_column_selection(self):
         pyperclip.copy("old clipboard contents")
@@ -141,9 +141,9 @@ class CopySelectedQueryResultsFeatureTest(BaseFeatureTest):
         ActionChains(self.page.driver).key_down(Keys.CONTROL).send_keys('c').key_up(Keys.CONTROL).perform()
 
         self.assertEqual(
-            """'Some-Name','6'
-'Some-Other-Name','22'
-'Yet-Another-Name','14'""",
+            """\"Some-Name","6"
+"Some-Other-Name","22"
+"Yet-Another-Name","14\"""",
             pyperclip.paste())
 
     def _mouseup_outside_grid_still_makes_a_selection(self):
@@ -160,7 +160,7 @@ class CopySelectedQueryResultsFeatureTest(BaseFeatureTest):
 
         ActionChains(self.page.driver).key_down(Keys.CONTROL).send_keys('c').key_up(Keys.CONTROL).perform()
 
-        self.assertEqual("'cool info'", pyperclip.paste())
+        self.assertEqual('"cool info"', pyperclip.paste())
 
     def after(self):
         self.page.close_query_tool()
diff --git a/web/pgadmin/feature_tests/query_tool_journey_test.py b/web/pgadmin/feature_tests/query_tool_journey_test.py
index 87514b1..6b79948 100644
--- a/web/pgadmin/feature_tests/query_tool_journey_test.py
+++ b/web/pgadmin/feature_tests/query_tool_journey_test.py
@@ -54,7 +54,7 @@ class QueryToolJourneyTest(BaseFeatureTest):
         self.page.find_by_xpath("//*[contains(@class, 'slick-row')]/*[1]").click()
         self.page.find_by_xpath("//*[@id='btn-copy-row']").click()
 
-        self.assertEqual("'Some-Name','6','some info'",
+        self.assertEqual('"Some-Name","6","some info"',
                          pyperclip.paste())
 
     def _test_copies_columns(self):
@@ -65,9 +65,9 @@ class QueryToolJourneyTest(BaseFeatureTest):
         self.page.find_by_xpath("//*[@data-test='output-column-header' and contains(., 'some_column')]").click()
         self.page.find_by_xpath("//*[@id='btn-copy-row']").click()
 
-        self.assertTrue("'Some-Name'" in pyperclip.paste())
-        self.assertTrue("'Some-Other-Name'" in pyperclip.paste())
-        self.assertTrue("'Yet-Another-Name'" in pyperclip.paste())
+        self.assertTrue('"Some-Name"' in pyperclip.paste())
+        self.assertTrue('"Some-Other-Name"' in pyperclip.paste())
+        self.assertTrue('"Yet-Another-Name"' in pyperclip.paste())
 
     def _test_history_tab(self):
         self.__clear_query_tool()
diff --git a/web/pgadmin/static/js/backform.pgadmin.js b/web/pgadmin/static/js/backform.pgadmin.js
index 297e8ec..865746f 100644
--- a/web/pgadmin/static/js/backform.pgadmin.js
+++ b/web/pgadmin/static/js/backform.pgadmin.js
@@ -1723,7 +1723,7 @@
       '   <% var option = options[i]; %>',
       '   <option ',
       '    <% if (option.image) { %> data-image=<%=option.image%> <%}%>',
-      '    value=<%= formatter.fromRaw(option.value) %>',
+      '    value=<%- formatter.fromRaw(option.value) %>',
       '    <% if (option.selected) {%>selected="selected"<%} else {%>',
       '    <% if (!select2.multiple && option.value === rawValue) {%>selected="selected"<%}%>',
       '    <% if (select2.multiple && rawValue && rawValue.indexOf(option.value) != -1){%>selected="selected" data-index="rawValue.indexOf(option.value)"<%}%>',
diff --git a/web/pgadmin/static/js/selection/copy_data.js b/web/pgadmin/static/js/selection/copy_data.js
index 2f30dd7..c098614 100644
--- a/web/pgadmin/static/js/selection/copy_data.js
+++ b/web/pgadmin/static/js/selection/copy_data.js
@@ -14,6 +14,7 @@ function ($, _, clipboard, RangeSelectionHelper, rangeBoundaryNavigator) {
     var selectedRanges = grid.getSelectionModel().getSelectedRanges();
     var dataView = grid.getData();
     var rows = grid.getSelectedRows();
+    var CSVOptions = grid.CSVOptions;
 
     if (RangeSelectionHelper.areAllRangesCompleteRows(grid, selectedRanges)) {
       self.copied_rows = rows.map(function (rowIndex) {
@@ -24,7 +25,7 @@ function ($, _, clipboard, RangeSelectionHelper, rangeBoundaryNavigator) {
       self.copied_rows = [];
       setPasteRowButtonEnablement(self.can_edit, false);
     }
-    var csvText = rangeBoundaryNavigator.rangesToCsv(dataView.getItems(), columnDefinitions, selectedRanges);
+    var csvText = rangeBoundaryNavigator.rangesToCsv(dataView.getItems(), columnDefinitions, selectedRanges, CSVOptions);
     if (csvText) {
       clipboard.copyTextToClipboard(csvText);
     }
diff --git a/web/pgadmin/static/js/selection/range_boundary_navigator.js b/web/pgadmin/static/js/selection/range_boundary_navigator.js
index 274b621..d5014c1 100644
--- a/web/pgadmin/static/js/selection/range_boundary_navigator.js
+++ b/web/pgadmin/static/js/selection/range_boundary_navigator.js
@@ -57,7 +57,7 @@ function (RangeSelectionHelper) {
       }.bind(this));
     },
 
-    rangesToCsv: function (data, columnDefinitions, selectedRanges) {
+    rangesToCsv: function (data, columnDefinitions, selectedRanges, CSVOptions) {
 
       var rowRangeBounds = selectedRanges.map(function (range) {
         return [range.fromRow, range.toRow];
@@ -70,8 +70,9 @@ function (RangeSelectionHelper) {
         colRangeBounds = this.removeFirstColumn(colRangeBounds);
       }
 
-      var csvRows = this.mapOver2DArray(rowRangeBounds, colRangeBounds, this.csvCell.bind(this, data, columnDefinitions), function (rowData) {
-        return rowData.join(',');
+      var csvRows = this.mapOver2DArray(rowRangeBounds, colRangeBounds, this.csvCell.bind(this, data, columnDefinitions, CSVOptions), function (rowData) {
+        var field_separator = CSVOptions.field_separator || ',';
+        return rowData.join(field_separator);
       });
 
       return csvRows.join('\n');
@@ -102,17 +103,30 @@ function (RangeSelectionHelper) {
       return unionedColRanges;
     },
 
-    csvCell: function (data, columnDefinitions, rowId, colId) {
-      var val = data[rowId][columnDefinitions[colId].field];
-
-      if (val && _.isObject(val)) {
-        val = '\'' + JSON.stringify(val) + '\'';
-      } else if (val && typeof val != 'number' && typeof val != 'boolean') {
-        val = '\'' + val.toString() + '\'';
-      } else if (_.isNull(val) || _.isUndefined(val)) {
-        val = '';
+    csvCell: function (data, columnDefinitions, CSVOptions, rowId, colId) {
+      var val = data[rowId][columnDefinitions[colId].field],
+        quoting = CSVOptions.quoting || 'strings',
+        quote_char = CSVOptions.quote_char || '\'';
+
+      if (quoting == 'all') {
+        if (val && _.isObject(val)) {
+          val = quote_char + JSON.stringify(val) + quote_char;
+        } else if (val) {
+          val = quote_char + val.toString() + quote_char;
+        } else if (_.isNull(val) || _.isUndefined(val)) {
+          val = '';
+        }
+      }
+      else if(quoting == 'strings') {
+        if (val && _.isObject(val)) {
+          val = quote_char + JSON.stringify(val) + quote_char;
+        } else if (val && typeof val != 'number' && typeof val != 'boolean') {
+          val = quote_char + val.toString() + quote_char;
+        } else if (_.isNull(val) || _.isUndefined(val)) {
+          val = '';
+        }
       }
       return val;
     },
   };
-});
\ No newline at end of file
+});
diff --git a/web/pgadmin/static/js/slickgrid/event_handlers/handle_query_output_keyboard_event.js b/web/pgadmin/static/js/slickgrid/event_handlers/handle_query_output_keyboard_event.js
index 50ebd47..eb76513 100644
--- a/web/pgadmin/static/js/slickgrid/event_handlers/handle_query_output_keyboard_event.js
+++ b/web/pgadmin/static/js/slickgrid/event_handlers/handle_query_output_keyboard_event.js
@@ -10,6 +10,7 @@ function (copyData, RangeSelectionHelper) {
     var isModifierDown = event.ctrlKey || event.metaKey;
     var self = this || window;
     self.slickgrid = args.grid;
+    self.csvOptions
 
     if (isModifierDown && modifiedKey == KEY_C) {
       copyData.apply(self);
@@ -19,4 +20,4 @@ function (copyData, RangeSelectionHelper) {
       RangeSelectionHelper.selectAll(self.slickgrid);
     }
   }
-});
\ No newline at end of file
+});
diff --git a/web/pgadmin/tools/sqleditor/__init__.py b/web/pgadmin/tools/sqleditor/__init__.py
index 6be9e0b..843a09d 100644
--- a/web/pgadmin/tools/sqleditor/__init__.py
+++ b/web/pgadmin/tools/sqleditor/__init__.py
@@ -235,6 +235,32 @@ class SqlEditorModule(PgAdminModule):
             )
         )
 
+        self.csv_quoting = self.preference.register(
+            'CSV_output', 'csv_quoting',
+            gettext("CSV quoting"), 'options', 'strings',
+            category_label=gettext('CSV Output'),
+            options=[{'label': 'None', 'value': 'none'},
+                     {'label': 'All', 'value': 'all'},
+                     {'label': 'Strings', 'value': 'strings'}]
+        )
+
+        self.csv_quote_char = self.preference.register(
+            'CSV_output', 'csv_quote_char',
+            gettext("CSV quote character"), 'options', '"',
+            category_label=gettext('CSV Output'),
+            options=[{'label': '"', 'value': '"'},
+                     {'label': '\'', 'value': '\''}]
+        )
+
+        self.csv_field_separator = self.preference.register(
+            'CSV_output', 'csv_field_separator',
+            gettext("CSV field separator"), 'options', ',',
+            category_label=gettext('CSV Output'),
+            options=[{'label': ';', 'value': ';'},
+                     {'label': ',', 'value': ','},
+                     {'label': '|', 'value': '|'},
+                     {'label': 'Tab', 'value': '\t'}]
+        )
 
 blueprint = SqlEditorModule(MODULE_NAME, __name__, static_url_path='/static')
 
@@ -1634,7 +1660,9 @@ def start_query_download_tool(trans_id):
                     r.call_on_close(cleanup)
                     return r
 
-                r = Response(gen(), mimetype='text/csv')
+                r = Response(gen(quote=blueprint.csv_quoting.get(),
+                    quote_char=blueprint.csv_quote_char.get(),
+                    field_separator=blueprint.csv_field_separator.get()), mimetype='text/csv')
 
                 if 'filename' in data and data['filename'] != "":
                     filename = data['filename']
diff --git a/web/pgadmin/tools/sqleditor/static/js/sqleditor.js b/web/pgadmin/tools/sqleditor/static/js/sqleditor.js
index d50cca7..c38b172 100644
--- a/web/pgadmin/tools/sqleditor/static/js/sqleditor.js
+++ b/web/pgadmin/tools/sqleditor/static/js/sqleditor.js
@@ -792,6 +792,20 @@ define('tools.querytool', [
             handleQueryOutputKeyboardEvent(event, args);
           });
         } else {
+          var pref_cache = undefined;
+          args.grid.CSVOptions = {};
+
+          if (self.handler.is_new_browser_tab) {
+            pref_cache = window.opener.pgAdmin.Browser.preferences_cache;
+          } else {
+            pref_cache = window.top.pgAdmin.Browser.preferences_cache
+          }
+
+          // Get CSV options from preferences cache
+          args.grid.CSVOptions.quoting = _.findWhere(pref_cache, {'module': 'sqleditor', 'name': 'csv_quoting'}).value;
+          args.grid.CSVOptions.quote_char = _.findWhere(pref_cache, {'module': 'sqleditor', 'name': 'csv_quote_char'}).value;
+          args.grid.CSVOptions.field_separator =  _.findWhere(pref_cache, {'module': 'sqleditor', 'name': 'csv_field_separator'}).value;
+
           handleQueryOutputKeyboardEvent(event, args);
         }
       });
@@ -1236,7 +1250,20 @@ define('tools.querytool', [
 
     // Callback function for copy button click.
     on_copy_row: function () {
-      var self = this;
+      var self = this,
+          pref_cache = undefined;
+      self.grid.CSVOptions = {};
+
+      if (self.handler.is_new_browser_tab) {
+        pref_cache = window.opener.pgAdmin.Browser.preferences_cache;
+      } else {
+        pref_cache = window.top.pgAdmin.Browser.preferences_cache
+      }
+
+      // Get CSV options from preferences cache
+      self.grid.CSVOptions.quoting = _.findWhere(pref_cache, {'module': 'sqleditor', 'name': 'csv_quoting'}).value;
+      self.grid.CSVOptions.quote_char = _.findWhere(pref_cache, {'module': 'sqleditor', 'name': 'csv_quote_char'}).value;
+      self.grid.CSVOptions.field_separator =  _.findWhere(pref_cache, {'module': 'sqleditor', 'name': 'csv_field_separator'}).value;
 
       // Trigger the copy signal to the SqlEditorController class
       self.handler.trigger(
@@ -1244,6 +1271,7 @@ define('tools.querytool', [
         self,
         self.handler
       );
+
     },
 
     // Callback function for paste button click.
@@ -1496,7 +1524,7 @@ define('tools.querytool', [
 
     keyAction: function (event) {
       keyboardShortcuts.processEvent(this.handler, queryToolActions, event);
-    },
+    }
   });
 
   /* Defining controller class for data grid, which actually
@@ -3647,7 +3675,6 @@ define('tools.querytool', [
               explain_timing = res.data.explain_timing;
               auto_commit = res.data.auto_commit;
               auto_rollback = res.data.auto_rollback;
-
               updateUI();
             }
           },
diff --git a/web/pgadmin/utils/driver/psycopg2/__init__.py b/web/pgadmin/utils/driver/psycopg2/__init__.py
index eabe3b0..6913094 100644
--- a/web/pgadmin/utils/driver/psycopg2/__init__.py
+++ b/web/pgadmin/utils/driver/psycopg2/__init__.py
@@ -697,7 +697,6 @@ WHERE
             params: Additional parameters
             formatted_exception_msg: For exception
             records: Number of initial records
-
         Returns:
             Generator response
         """
@@ -787,7 +786,7 @@ WHERE
                 )
             return new_results
 
-        def gen():
+        def gen(quote='strings', quote_char="'", field_separator=','):
 
             results = cur.fetchmany(records)
             if not results:
@@ -816,9 +815,17 @@ WHERE
 
             res_io = StringIO()
 
+            if quote == 'strings':
+                quote = csv.QUOTE_NONNUMERIC
+            elif quote == 'all':
+                quote = csv.QUOTE_ALL
+            else:
+                quote = csv.QUOTE_NONE
+
             csv_writer = csv.DictWriter(
-                res_io, fieldnames=header, delimiter=u',',
-                quoting=csv.QUOTE_NONNUMERIC
+                res_io, fieldnames=header, delimiter=field_separator,
+                quoting=quote,
+                quotechar=quote_char
             )
 
             csv_writer.writeheader()
@@ -837,8 +844,9 @@ WHERE
                 res_io = StringIO()
 
                 csv_writer = csv.DictWriter(
-                    res_io, fieldnames=header, delimiter=u',',
-                    quoting=csv.QUOTE_NONNUMERIC
+                    res_io, fieldnames=header, delimiter=field_separator,
+                    quoting=quote,
+                    quotechar=quote_char
                 )
 
                 if IS_PY2:
diff --git a/web/regression/feature_utils/pgadmin_page.py b/web/regression/feature_utils/pgadmin_page.py
index 030d05e..26e10cd 100644
--- a/web/regression/feature_utils/pgadmin_page.py
+++ b/web/regression/feature_utils/pgadmin_page.py
@@ -73,6 +73,7 @@ class PgadminPage:
         self.find_by_partial_link_text("Query Tool").click()
         self.click_tab('Query -')
 
+
     def enable_menu_item(self, menu_item, wait_time):
         start_time = time.time()
         # wait until menu becomes enabled.
diff --git a/web/regression/javascript/selection/copy_data_spec.js b/web/regression/javascript/selection/copy_data_spec.js
index 2b623b3..7a18b1b 100644
--- a/web/regression/javascript/selection/copy_data_spec.js
+++ b/web/regression/javascript/selection/copy_data_spec.js
@@ -22,11 +22,12 @@ describe('copyData', function () {
 
   beforeEach(function () {
     SlickGrid = Slick.Grid;
-    var data = [{'id': 1, 'brand':'leopord', 'size':'12', '__temp_PK': '123'},
-                {'id': 2, 'brand':'lion', 'size':'13', '__temp_PK': '456'},
-                {'id': 3, 'brand':'puma', 'size':'9', '__temp_PK': '789'}],
+    var data = [{'id': 1, 'brand':'leopord', 'size':12, '__temp_PK': '123'},
+                {'id': 2, 'brand':'lion', 'size':13, '__temp_PK': '456'},
+                {'id': 3, 'brand':'puma', 'size':9, '__temp_PK': '789'}],
       dataView = new Slick.Data.DataView();
 
+    var CSVOptions = {'quoting': 'strings', 'quote_char': '"', 'field_separator': ','};
     var columns = [
       {
         id: 'row-header-column',
@@ -66,6 +67,7 @@ describe('copyData', function () {
     buttonPasteRow = $('<button id="btn-paste-row" disabled></button>');
     $('body').append(buttonPasteRow);
     grid = new SlickGrid('#grid', dataView, columns, {});
+    grid.CSVOptions = CSVOptions;
     dataView.setItems(data, '__temp_PK');
     grid.setSelectionModel(new XCellSelectionModel());
     sqlEditor = {slickgrid: grid};
@@ -93,8 +95,8 @@ describe('copyData', function () {
       expect(sqlEditor.copied_rows.length).toBe(2);
 
       expect(clipboard.copyTextToClipboard).toHaveBeenCalled();
-      expect(clipboard.copyTextToClipboard.calls.mostRecent().args[0]).toContain('1,\'leopord\',\'12\'');
-      expect(clipboard.copyTextToClipboard.calls.mostRecent().args[0]).toContain('3,\'puma\',\'9\'');
+      expect(clipboard.copyTextToClipboard.calls.mostRecent().args[0]).toContain('1,"leopord",12');
+      expect(clipboard.copyTextToClipboard.calls.mostRecent().args[0]).toContain('3,"puma",9');
     });
 
     describe('when the user can edit the grid', function () {
diff --git a/web/regression/javascript/selection/range_boundary_navigator_spec.js b/web/regression/javascript/selection/range_boundary_navigator_spec.js
index 2d56b05..40c754d 100644
--- a/web/regression/javascript/selection/range_boundary_navigator_spec.js
+++ b/web/regression/javascript/selection/range_boundary_navigator_spec.js
@@ -132,7 +132,7 @@ describe('RangeBoundaryNavigator', function () {
   });
 
   describe('#rangesToCsv', function () {
-    var data, columnDefinitions, ranges;
+    var data, columnDefinitions, ranges, CSVOptions;
     beforeEach(function () {
       data = [{'id':1, 'animal':'leopard', 'size':'12'},
               {'id':2, 'animal':'lion', 'size':'13'},
@@ -143,16 +143,21 @@ describe('RangeBoundaryNavigator', function () {
                             {name: 'animal', field: 'animal', pos: 1},
                             {name: 'size', field: 'size', pos: 2}];
       ranges = [new Slick.Range(0, 0, 0, 2), new Slick.Range(3, 0, 3, 2)];
+
+      CSVOptions = [{'quoting': 'all', 'quote_char': '"', 'field_separator': ','},
+                    {'quoting': 'strings', 'quote_char': '"', 'field_separator': ';'},
+                    {'quoting': 'strings', 'quote_char': '\'', 'field_separator': '|'},
+                    {'quoting': 'none', 'quote_char': '"', 'field_separator': '\t'}];
     });
 
-    it('returns csv for the provided ranges', function () {
-      var csvResult = rangeBoundaryNavigator.rangesToCsv(data, columnDefinitions, ranges);
-      expect(csvResult).toEqual('1,\'leopard\',\'12\'\n4,\'tiger\',\'10\'');
+    it('returns csv for the provided ranges for CSV options quoting All with char " with field separator ,', function () {
+      var csvResult = rangeBoundaryNavigator.rangesToCsv(data, columnDefinitions, ranges, CSVOptions[0]);
+      expect(csvResult).toEqual('"1","leopard","12"\n"4","tiger","10"');
     });
 
-    describe('when no cells are selected', function () {
+    describe('when no cells are selected for CSV options quoting Strings with char " with field separator ;', function () {
       it('should return an empty string', function () {
-        var csvResult = rangeBoundaryNavigator.rangesToCsv(data, columnDefinitions, []);
+        var csvResult = rangeBoundaryNavigator.rangesToCsv(data, columnDefinitions, [], CSVOptions[1]);
 
         expect(csvResult).toEqual('');
       });
@@ -167,14 +172,14 @@ describe('RangeBoundaryNavigator', function () {
         ranges = [new Slick.Range(0, 0, 0, 3), new Slick.Range(3, 0, 3, 3)];
       });
 
-      it('returns csv for the columns with data', function () {
-        var csvResult = rangeBoundaryNavigator.rangesToCsv(data, columnDefinitions, ranges);
+      it('returns csv for the columns with data for CSV options quoting Strings with char \' with field separator |', function () {
+        var csvResult = rangeBoundaryNavigator.rangesToCsv(data, columnDefinitions, ranges, CSVOptions[2]);
 
-        expect(csvResult).toEqual('1,\'leopard\',\'12\'\n4,\'tiger\',\'10\'');
+        expect(csvResult).toEqual('1|\'leopard\'|\'12\'\n4|\'tiger\'|\'10\'');
       });
-      describe('when no cells are selected', function () {
+      describe('when no cells are selected for CSV options quoting none with field separator tab', function () {
         it('should return an empty string', function () {
-          var csvResult = rangeBoundaryNavigator.rangesToCsv(data, columnDefinitions, []);
+          var csvResult = rangeBoundaryNavigator.rangesToCsv(data, columnDefinitions, [], CSVOptions[3]);
 
           expect(csvResult).toEqual('');
         });
diff --git a/web/regression/javascript/slickgrid/event_handlers/handle_query_output_keyboard_event_spec.js b/web/regression/javascript/slickgrid/event_handlers/handle_query_output_keyboard_event_spec.js
index 12e3f66..7ab78a4 100644
--- a/web/regression/javascript/slickgrid/event_handlers/handle_query_output_keyboard_event_spec.js
+++ b/web/regression/javascript/slickgrid/event_handlers/handle_query_output_keyboard_event_spec.js
@@ -36,10 +36,12 @@ describe('#handleQueryOutputKeyboardEvent', function () {
       columnDefinitions = [{name: 'checkboxColumn'},
         {pos: 1, name: 'firstColumn', field: 'firstColumn'},
         { pos: 2, name: 'secondColumn', field: 'secondColumn'}],
-      dataView = new Slick.Data.DataView();
+      dataView = new Slick.Data.DataView(),
+      CSVOptions = {'quoting': 'all', 'quote_char': '\'', 'field_separator': ','};
 
     grid = new Slick.Grid($('<div></div>'), dataView, columnDefinitions);
     grid.setSelectionModel(new XCellSelectionModel());
+    grid.CSVOptions = CSVOptions;
     dataView.setItems(data, '__temp_PK');
     slickEvent = {
       grid: grid,

Reply via email to