1 var Clipboard =
function(table){
4 this.copySelector =
false;
5 this.copySelectorParams = {};
6 this.copyFormatter =
false;
7 this.copyFormatterParams = {};
8 this.pasteParser =
function(){};
9 this.pasteAction =
function(){};
10 this.htmlElement =
false;
16 Clipboard.prototype.initialize =
function(){
19 this.mode = this.table.options.clipboard;
21 if(this.mode ===
true || this.mode ===
"copy"){
22 this.table.element.addEventListener(
"copy",
function(e){
30 data =
self.generateContent();
32 if (window.clipboardData && window.clipboardData.setData) {
33 window.clipboardData.setData(
'Text', data);
34 }
else if (e.clipboardData && e.clipboardData.setData) {
35 e.clipboardData.setData(
'text/plain', data);
37 e.clipboardData.setData(
'text/html',
self.htmlElement.outerHTML);
39 }
else if (e.originalEvent && e.originalEvent.clipboardData.setData) {
40 e.originalEvent.clipboardData.setData(
'text/plain', data);
42 e.originalEvent.clipboardData.setData(
'text/html',
self.htmlElement.outerHTML);
46 self.table.options.clipboardCopied.call(this.table, data);
53 if(this.mode ===
true || this.mode ===
"paste"){
54 this.table.element.addEventListener(
"paste",
function(e){
59 this.setPasteParser(this.table.options.clipboardPasteParser);
60 this.setPasteAction(this.table.options.clipboardPasteAction);
63 Clipboard.prototype.processConfig =
function(){
65 columnHeaders:
"groups",
70 if(typeof this.table.options.clipboardCopyHeader !==
"undefined"){
71 config.columnHeaders = this.table.options.clipboardCopyHeader;
72 console.warn(
"DEPRECATION WARNING - clipboardCopyHeader option has been deprecated, please use the columnHeaders property on the clipboardCopyConfig option");
75 if(this.table.options.clipboardCopyConfig){
76 for(var key in this.table.options.clipboardCopyConfig){
77 config[key] = this.table.options.clipboardCopyConfig[key];
81 if (config.rowGroups &&
this.table.options.groupBy &&
this.table.modExists(
"groupRows")){
82 this.config.rowGroups =
true;
85 if(config.columnHeaders){
86 if((config.columnHeaders ===
"groups" || config ===
true) && this.table.columnManager.columns.length != this.table.columnManager.columnsByIndex.length){
87 this.config.columnHeaders =
"groups";
89 this.config.columnHeaders =
"columns";
92 this.config.columnHeaders =
false;
95 if (config.columnCalcs &&
this.table.modExists(
"columnCalcs")){
96 this.config.columnCalcs =
true;
101 Clipboard.prototype.reset =
function(){
102 this.blocked =
false;
103 this.originalSelectionText =
"";
107 Clipboard.prototype.setPasteAction =
function(action){
109 switch(typeof action){
111 this.pasteAction = this.pasteActions[action];
113 if(!this.pasteAction){
114 console.warn(
"Clipboard Error - No such paste action found:", action);
119 this.pasteAction = action;
124 Clipboard.prototype.setPasteParser =
function(parser){
125 switch(typeof parser){
127 this.pasteParser = this.pasteParsers[parser];
129 if(!this.pasteParser){
130 console.warn(
"Clipboard Error - No such paste parser found:", parser);
135 this.pasteParser = parser;
141 Clipboard.prototype.paste =
function(e){
142 var data, rowData, rows;
144 if(this.checkPaseOrigin(e)){
146 data = this.getPasteData(e);
148 rowData = this.pasteParser.call(
this, data);
153 if(this.table.modExists(
"mutator")){
154 rowData = this.mutateData(rowData);
157 rows = this.pasteAction.call(
this, rowData);
158 this.table.options.clipboardPasted.call(this.table, data, rowData, rows);
160 this.table.options.clipboardPasteError.call(this.table, data);
165 Clipboard.prototype.mutateData =
function(data){
169 if(Array.isArray(data)){
170 data.forEach(
function(row){
171 output.push(
self.table.modules.mutator.transformRow(row,
"clipboard"));
181 Clipboard.prototype.checkPaseOrigin =
function(e){
184 if(e.target.tagName !=
"DIV" ||
this.table.modules.edit.currentCell){
191 Clipboard.prototype.getPasteData =
function(e){
194 if (window.clipboardData && window.clipboardData.getData) {
195 data = window.clipboardData.getData(
'Text');
196 }
else if (e.clipboardData && e.clipboardData.getData) {
197 data = e.clipboardData.getData(
'text/plain');
198 }
else if (e.originalEvent && e.originalEvent.clipboardData.getData) {
199 data = e.originalEvent.clipboardData.getData(
'text/plain');
206 Clipboard.prototype.copy =
function(selector, selectorParams, formatter, formatterParams,
internal){
207 var range, sel, textRange;
208 this.blocked =
false;
210 if(this.mode ===
true || this.mode ===
"copy"){
212 if (typeof window.getSelection !=
"undefined" && typeof document.createRange !=
"undefined") {
213 range = document.createRange();
214 range.selectNodeContents(this.table.element);
215 sel = window.getSelection();
217 if(sel.toString() &&
internal){
218 selector =
"userSelection";
220 selectorParams = sel.toString();
223 sel.removeAllRanges();
225 }
else if (typeof document.selection !=
"undefined" && typeof document.body.createTextRange !=
"undefined") {
226 textRange = document.body.createTextRange();
227 textRange.moveToElementText(this.table.element);
231 this.setSelector(selector);
232 this.copySelectorParams = typeof selectorParams !=
"undefined" && selectorParams != null ? selectorParams : this.config.columnHeaders;
233 this.setFormatter(formatter);
234 this.copyFormatterParams = typeof formatterParams !=
"undefined" && formatterParams != null ? formatterParams : {};
236 document.execCommand(
'copy');
239 sel.removeAllRanges();
244 Clipboard.prototype.setSelector =
function(selector){
245 selector = selector || this.table.options.clipboardCopySelector;
247 switch(typeof selector){
249 if(this.copySelectors[selector]){
250 this.copySelector = this.copySelectors[selector];
252 console.warn(
"Clipboard Error - No such selector found:", selector);
257 this.copySelector = selector;
262 Clipboard.prototype.setFormatter =
function(formatter){
264 formatter = formatter || this.table.options.clipboardCopyFormatter;
266 switch(typeof formatter){
268 if(this.copyFormatters[formatter]){
269 this.copyFormatter = this.copyFormatters[formatter];
271 console.warn(
"Clipboard Error - No such formatter found:", formatter);
276 this.copyFormatter = formatter;
282 Clipboard.prototype.generateContent =
function(){
285 this.htmlElement =
false;
286 data = this.copySelector.call(
this, this.config, this.copySelectorParams);
288 return this.copyFormatter.call(
this, data, this.config, this.copyFormatterParams);
291 Clipboard.prototype.generateSimpleHeaders =
function(columns){
294 columns.forEach(
function(column){
295 headers.push(column.definition.title);
301 Clipboard.prototype.generateColumnGroupHeaders =
function(columns){
304 this.table.columnManager.columns.forEach((column) => {
305 var colData = this.processColumnGroup(column);
308 output.push(colData);
315 Clipboard.prototype.processColumnGroup =
function(column){
316 var subGroups = column.columns;
320 title:column.definition.title,
324 if(subGroups.length){
325 groupData.subGroups = [];
328 subGroups.forEach((subGroup) => {
329 var subGroupData = this.processColumnGroup(subGroup);
332 groupData.width += subGroupData.width;
333 groupData.subGroups.push(subGroupData);
337 if(!groupData.width){
341 if(column.field && (column.definition.clipboard || (column.visible && column.definition.clipboard !==
false))){
351 Clipboard.prototype.groupHeadersToRows =
function(columns){
355 function parseColumnGroup(column, level){
357 if(typeof headers[level] ===
"undefined"){
361 headers[level].push(column.title);
363 if(column.subGroups){
364 column.subGroups.forEach(
function(subGroup){
365 parseColumnGroup(subGroup, level+1);
372 function padColumnheaders(){
375 headers.forEach(
function(title){
376 var len = title.length;
382 headers.forEach(
function(title){
383 var len = title.length;
385 for(var i = len; i < max; i++){
392 columns.forEach(
function(column){
393 parseColumnGroup(column,0);
399 Clipboard.prototype.rowsToData =
function(rows, columns, config, params){
402 rows.forEach(
function(row){
404 rowData = row instanceof RowComponent ? row.getData(
"clipboard") : row;
406 columns.forEach(
function(column){
407 var value = column.getFieldValue(rowData);
409 switch(typeof value){
411 value = JSON.stringify(value);
423 rowArray.push(value);
432 Clipboard.prototype.buildComplexRows =
function(config){
434 groups = this.table.modules.groupRows.getGroups();
436 groups.forEach((group) => {
437 output.push(this.processGroupData(group));
445 Clipboard.prototype.processGroupData =
function(group){
446 var subGroups = group.getSubGroups();
453 if(subGroups.length){
454 groupData.subGroups = [];
456 subGroups.forEach((subGroup) => {
457 groupData.subGroups.push(this.processGroupData(subGroup));
460 groupData.rows = group.getRows(
true);
466 Clipboard.prototype.getCalcRow =
function (calcs, columns, selector, pos){
467 var calcData = calcs[selector];
471 calcData = calcData[pos];
474 if(Object.keys(calcData).length){
475 return this.rowsToData([calcData], columns);
483 Clipboard.prototype.buildOutput =
function(rows, config, params){
489 this.table.columnManager.columnsByIndex.forEach(
function(column){
490 if(column.definition.clipboard || (column.visible && column.definition.clipboard !==
false)){
491 columnsByIndex.push(column);
495 if(config.columnHeaders ==
"groups"){
496 columns = this.generateColumnGroupHeaders(this.table.columnManager.columns);
497 output = output.concat(this.groupHeadersToRows(columns));
499 columns = columnsByIndex;
501 output.push(this.generateSimpleHeaders(columns));
504 if(this.config.columnCalcs){
505 calcs = this.table.getCalcResults();
509 if(this.table.options.clipboardCopyStyled){
510 this.generateHTML(rows, columns, calcs, config, params);
514 if(config.rowGroups){
515 rows.forEach((row) => {
516 output = output.concat(this.parseRowGroupData(row, columnsByIndex, config, params, calcs || {}));
519 if(config.columnCalcs){
520 output = output.concat(this.getCalcRow(calcs, columnsByIndex,
"top"));
523 output = output.concat(this.rowsToData(rows, columnsByIndex, config, params));
525 if(config.columnCalcs){
526 output = output.concat(this.getCalcRow(calcs, columnsByIndex,
"bottom"));
534 Clipboard.prototype.parseRowGroupData =
function (group, columns, config, params, calcObj){
537 groupData.push([group.key]);
540 group.subGroups.forEach((subGroup) => {
541 groupData = groupData.concat(this.parseRowGroupData(subGroup, config, params, calcObj[group.key] ? calcObj[group.key].groups || {} : {}));
544 if(config.columnCalcs){
545 groupData = groupData.concat(this.getCalcRow(calcObj, columns, group.key,
"top"));
548 groupData = groupData.concat(this.rowsToData(group.rows, columns, config, params));
550 if(config.columnCalcs){
551 groupData = groupData.concat(this.getCalcRow(calcObj, columns, group.key,
"bottom"));
559 Clipboard.prototype.generateHTML =
function (rows, columns, calcs, config, params){
562 headers = [], body, oddRow, evenRow, calcRow, firstRow, firstCell, firstGroup, lastCell, styleCells;
565 this.htmlElement = document.createElement(
"table");
566 self.mapElementStyles(this.table.element,
this.htmlElement, [
"border-top",
"border-left",
"border-right",
"border-bottom"]);
568 function generateSimpleHeaders(){
569 var headerEl = document.createElement(
"tr");
571 columns.forEach(
function(column){
572 var columnEl = document.createElement(
"th");
573 columnEl.innerHTML = column.definition.title;
575 self.mapElementStyles(column.getElement(), columnEl, [
"border-top",
"border-left",
"border-right",
"border-bottom",
"background-color",
"color",
"font-weight",
"font-family",
"font-size"]);
577 headerEl.appendChild(columnEl);
580 self.mapElementStyles(
self.table.columnManager.getHeadersElement(), headerEl, [
"border-top",
"border-left",
"border-right",
"border-bottom",
"background-color",
"color",
"font-weight",
"font-family",
"font-size"]);
582 self.htmlElement.appendChild(document.createElement(
"thead").appendChild(headerEl));
586 function generateHeaders(headers){
588 var headerHolderEl = document.createElement(
"thead");
590 headers.forEach(
function(columns){
591 var headerEl = document.createElement(
"tr");
593 columns.forEach(
function(column){
594 var columnEl = document.createElement(
"th");
596 if(column.width > 1){
597 columnEl.colSpan = column.width;
600 if(column.height > 1){
601 columnEl.rowSpan = column.height;
604 columnEl.innerHTML = column.title;
606 self.mapElementStyles(column.element, columnEl, [
"border-top",
"border-left",
"border-right",
"border-bottom",
"background-color",
"color",
"font-weight",
"font-family",
"font-size"]);
608 headerEl.appendChild(columnEl);
611 self.mapElementStyles(
self.table.columnManager.getHeadersElement(), headerEl, [
"border-top",
"border-left",
"border-right",
"border-bottom",
"background-color",
"color",
"font-weight",
"font-family",
"font-size"]);
613 headerHolderEl.appendChild(headerEl);
616 self.htmlElement.appendChild(headerHolderEl);
620 function parseColumnGroup(column, level){
622 var actualColumns = [];
624 if(typeof headers[level] ===
"undefined"){
628 headers[level].push({
632 children:!!column.subGroups,
633 element:column.column.getElement(),
636 if(column.subGroups){
637 column.subGroups.forEach(
function(subGroup){
638 actualColumns = actualColumns.concat(parseColumnGroup(subGroup, level+1));
641 return actualColumns;
643 return [column.column];
647 function padVerticalColumnheaders(){
648 headers.forEach(
function(row, index){
649 row.forEach(
function(header){
650 if(!header.children){
651 header.height = headers.length - index;
657 function addCalcRow(calcs, selector, pos){
658 var calcData = calcs[selector];
662 calcData = calcData[pos];
665 if(Object.keys(calcData).length){
667 processRows([calcData]);
673 if(config.columnHeaders){
674 if(config.columnHeaders ==
"groups"){
676 var actualColumns = [];
678 columns.forEach(
function(column){
679 actualColumns = actualColumns.concat(parseColumnGroup(column,0));
682 columns = actualColumns;
684 padVerticalColumnheaders();
685 generateHeaders(headers);
687 generateSimpleHeaders();
694 body = document.createElement(
"tbody");
697 if(window.getComputedStyle){
698 oddRow = this.table.element.querySelector(
".tabulator-row-odd:not(.tabulator-group):not(.tabulator-calcs)");
699 evenRow = this.table.element.querySelector(
".tabulator-row-even:not(.tabulator-group):not(.tabulator-calcs)");
700 calcRow = this.table.element.querySelector(
".tabulator-row.tabulator-calcs");
701 firstRow = this.table.element.querySelector(
".tabulator-row:not(.tabulator-group):not(.tabulator-calcs)");
702 firstGroup = this.table.element.getElementsByClassName(
"tabulator-group")[0];
705 styleCells = firstRow.getElementsByClassName(
"tabulator-cell");
706 firstCell = styleCells[0];
707 lastCell = styleCells[styleCells.length - 1];
711 function processRows(rowArray){
713 rowArray.forEach(
function(row, i){
714 var rowEl = document.createElement(
"tr"),
719 if(row instanceof RowComponent){
720 rowData = row.getData(
"clipboard");
726 columns.forEach(
function(column, j){
727 var cellEl = document.createElement(
"td"),
728 value = column.getFieldValue(rowData);
730 switch(typeof value){
732 value = JSON.stringify(value);
744 cellEl.innerHTML = value;
746 if(column.definition.align){
747 cellEl.style.textAlign = column.definition.align;
750 if(j < columns.length - 1){
752 self.mapElementStyles(firstCell, cellEl, [
"border-top",
"border-left",
"border-right",
"border-bottom",
"color",
"font-weight",
"font-family",
"font-size"]);
756 self.mapElementStyles(firstCell, cellEl, [
"border-top",
"border-left",
"border-right",
"border-bottom",
"color",
"font-weight",
"font-family",
"font-size"]);
760 rowEl.appendChild(cellEl);
766 if(!(i % 2) && oddRow){
770 if((i % 2) && evenRow){
776 self.mapElementStyles(styleRow, rowEl, [
"border-top",
"border-left",
"border-right",
"border-bottom",
"color",
"font-weight",
"font-family",
"font-size",
"background-color"]);
779 body.appendChild(rowEl);
783 function processGroup(group, calcObj){
784 var groupEl = document.createElement(
"tr"),
785 groupCellEl = document.createElement(
"td");
787 groupCellEl.colSpan = columns.length;
789 groupCellEl.innerHTML = group.key;
791 groupEl.appendChild(groupCellEl);
792 body.appendChild(groupEl);
794 self.mapElementStyles(firstGroup, groupEl, [
"border-top",
"border-left",
"border-right",
"border-bottom",
"color",
"font-weight",
"font-family",
"font-size",
"background-color"]);
797 group.subGroups.forEach((subGroup) => {
798 processGroup(subGroup, calcObj[group.key] ? calcObj[group.key].groups || {} : {});
801 if(config.columnCalcs){
802 addCalcRow(calcObj, group.key,
"top");
805 processRows(group.rows);
807 if(config.columnCalcs){
808 addCalcRow(calcObj, group.key,
"bottom");
814 if(config.rowGroups){
815 rows.forEach((group) => {
816 processGroup(group, calcs || {});
819 if(config.columnCalcs){
820 addCalcRow(calcs,
"top");
825 if(config.columnCalcs){
826 addCalcRow(calcs,
"bottom");
830 this.htmlElement.appendChild(body);
833 Clipboard.prototype.mapElementStyles =
function(from, to, props){
836 "background-color" :
"backgroundColor",
837 "color" :
"fontColor",
838 "font-weight" :
"fontWeight",
839 "font-family" :
"fontFamily",
840 "font-size" :
"fontSize",
841 "border-top" :
"borderTop",
842 "border-left" :
"borderLeft",
843 "border-right" :
"borderRight",
844 "border-bottom" :
"borderBottom",
847 if(window.getComputedStyle){
848 var fromStyle = window.getComputedStyle(from);
850 props.forEach(
function(prop){
851 to.style[lookup[prop]] = fromStyle.getPropertyValue(prop);
859 Clipboard.prototype.copySelectors = {
860 userSelection:
function(config, params){
863 selected:
function(config, params){
866 if(this.table.modExists(
"selectRow",
true)){
867 rows = this.table.modules.selectRow.getSelectedRows();
870 if(config.rowGroups){
871 console.warn(
"Clipboard Warning - select coptSelector does not support row groups");
874 return this.buildOutput(rows, config, params)
876 table:
function(config, params){
877 if(config.rowGroups){
878 console.warn(
"Clipboard Warning - table coptSelector does not support row groups");
881 return this.buildOutput(this.table.rowManager.getComponents(), config, params);
883 active:
function(config, params){
886 if(config.rowGroups){
887 rows = this.buildComplexRows(config);
889 rows = this.table.rowManager.getComponents(
"active");
892 return this.buildOutput(rows, config, params);
894 visible:
function(config, params){
897 if(config.rowGroups){
898 rows = this.buildComplexRows(config);
900 rows = this.table.rowManager.getComponents(
"visible");
903 return this.buildOutput(rows, config, params);
907 Clipboard.prototype.copyFormatters = {
908 raw:
function(data, params){
911 table:
function(data, params){
914 data.forEach(
function(row){
916 row.forEach(
function(value){
917 if(typeof value ==
"undefined"){
921 value = typeof value ==
"undefined" || value === null ?
"" : value.toString();
923 if(value.match(/\r|\n/)){
924 value = value.split(
'"').join(
'""');
925 value =
'"' + value +
'"';
930 output.push(newRow.join(
"\t"));
933 return output.join(
"\n");
937 Clipboard.prototype.pasteParsers = {
938 table:
function(clipboard){
941 headerFindSuccess =
true,
942 columns = this.table.columnManager.columns,
947 clipboard = clipboard.split(
"\n");
949 clipboard.forEach(
function(row){
950 data.push(row.split(
"\t"));
953 if(data.length && !(data.length === 1 && data[0].length < 2)){
957 data[0].forEach(
function(value){
958 var column = columns.find(
function(column){
959 return value && column.definition.title && value.trim() && column.definition.title.trim() === value.trim();
963 columnMap.push(column);
965 headerFindSuccess =
false;
970 if(!headerFindSuccess){
971 headerFindSuccess =
true;
974 data[0].forEach(
function(value){
975 var column = columns.find(
function(column){
976 return value && column.field && value.trim() && column.field.trim() === value.trim();
980 columnMap.push(column);
982 headerFindSuccess =
false;
986 if(!headerFindSuccess){
987 columnMap = this.table.columnManager.columnsByIndex;
992 if(headerFindSuccess){
996 data.forEach(
function(item){
999 item.forEach(
function(value, i){
1001 row[columnMap[i].field] = value;
1015 Clipboard.prototype.pasteActions = {
1016 replace:
function(rows){
1017 return this.table.setData(rows);
1019 update:
function(rows){
1020 return this.table.updateOrAddData(rows);
1022 insert:
function(rows){
1023 return this.table.addData(rows);
1029 Tabulator.prototype.registerModule(
"clipboard", Clipboard);