@ag-grid-enterprise/clipboard
Version:
Advanced Data Grid / Data Table supporting Javascript / Typescript / React / Angular / Vue
7 lines (6 loc) • 16.5 kB
JavaScript
import{ModuleNames as b,_defineModule as R}from"@ag-grid-community/core";import{CsvExportModule as k}from"@ag-grid-community/csv-export";import{EnterpriseCoreModule as M}from"@ag-grid-enterprise/core";function G(g,e){g.clipboardService?.copyToClipboard(e)}function H(g,e){g.clipboardService?.cutToClipboard(e)}function L(g,e){g.clipboardService?.copySelectedRowsToClipboard(e)}function U(g,e){g.clipboardService?.copySelectedRangeToClipboard(e)}function B(g){g.clipboardService?.copyRangeDown()}function _(g){g.clipboardService?.pasteFromClipboard()}import{BeanStub as $,ChangedPath as j,_exists as N,_getActiveDomElement as Y,_getDocument as T,_isClientSideRowModel as z,_last as K,_removeFromArray as Q,_warnOnce as w}from"@ag-grid-community/core";var m="paste",y="dragCopy",P="clipboard",E=g=>`AG Grid: Unable to use the Clipboard API (navigator.clipboard.${g}()). The reason why it could not be used has been logged in the previous line. For this reason the grid has defaulted to using a workaround which doesn't perform as well. Either fix why Clipboard API is blocked, OR stop this message from appearing by setting grid property suppressClipboardApi=true (which will default the grid to using the workaround rather than the API.`,X=class V extends ${constructor(){super(...arguments),this.beanName="clipboardService",this.lastPasteOperationTime=0,this.navigatorApiFailed=!1}wireBeans(e){this.csvCreator=e.csvCreator,this.selectionService=e.selectionService,this.rowModel=e.rowModel,this.ctrlsService=e.ctrlsService,this.valueService=e.valueService,this.focusService=e.focusService,this.rowRenderer=e.rowRenderer,this.visibleColsService=e.visibleColsService,this.funcColsService=e.funcColsService,this.cellNavigationService=e.cellNavigationService,this.cellPositionUtils=e.cellPositionUtils,this.rowPositionUtils=e.rowPositionUtils,this.rangeService=e.rangeService}postConstruct(){z(this.gos)&&(this.clientSideRowModel=this.rowModel),this.ctrlsService.whenReady(this,e=>{this.gridCtrl=e.gridCtrl})}pasteFromClipboard(){!this.gos.get("suppressClipboardApi")&&!this.navigatorApiFailed&&navigator.clipboard&&navigator.clipboard.readText?navigator.clipboard.readText().then(this.processClipboardData.bind(this)).catch(t=>{w(`${t}
${E("readText")}`),this.navigatorApiFailed=!0,this.pasteFromClipboardLegacy()}):this.pasteFromClipboardLegacy()}pasteFromClipboardLegacy(){let e=!1;const t=s=>{const o=new Date().getTime();o-this.lastPasteOperationTime<50&&(e=!0,s.preventDefault()),this.lastPasteOperationTime=o};this.executeOnTempElement(s=>{s.addEventListener("paste",t),s.focus({preventScroll:!0})},s=>{const o=s.value;e?this.refocusLastFocusedCell():this.processClipboardData(o),s.removeEventListener("paste",t)})}refocusLastFocusedCell(){const e=this.focusService.getFocusedCell();e&&this.focusService.setFocusedCell({rowIndex:e.rowIndex,column:e.column,rowPinned:e.rowPinned,forceBrowserFocus:!0})}getClipboardDelimiter(){const e=this.gos.get("clipboardDelimiter");return N(e)?e:" "}processClipboardData(e){if(e==null)return;let t=V.stringToArray(e,this.getClipboardDelimiter());const s=this.gos.getCallback("processDataFromClipboard");if(s&&(t=s({data:t})),t==null)return;this.gos.get("suppressLastEmptyLineOnPaste")&&this.removeLastLineIfBlank(t);const o=(i,l,r,a)=>{this.rangeService?.isMoreThanOneCell()&&!this.hasOnlyOneValueToPaste(t)?this.pasteIntoActiveRange(this.rangeService,t,i,l,a):this.pasteStartingFromFocusedCell(t,i,l,r,a)};this.doPasteOperation(o)}static stringToArray(e,t=","){const s=[],o=l=>l==="\r"||l===`
`;let i=!1;if(e==="")return[[""]];for(let l=0,r=0,a=0;a<e.length;a++){const n=e[a-1],u=e[a],c=e[a+1],p=()=>{s[l]||(s[l]=[]),s[l][r]||(s[l][r]="")};if(p(),u==='"'&&(i?c==='"'?(s[l][r]+='"',a++):i=!1:(n===void 0||n===t||o(n))&&(i=!0)),!i&&u!=='"'){if(u===t){r++,p();continue}else if(o(u)){r=0,l++,p(),u==="\r"&&c===`
`&&a++;continue}}s[l][r]+=u}return s}doPasteOperation(e){const t="clipboard";this.eventService.dispatchEvent({type:"pasteStart",source:t});let s;if(this.clientSideRowModel){const a=this.gos.get("aggregateOnlyChangedColumns");s=new j(a,this.clientSideRowModel.getRootNode())}const o={},i=[],l=this.focusService.getFocusedCell();e(o,i,l,s);const r=[...i];s&&(this.clientSideRowModel.doAggregate(s),s.forEachChangedNodeDepthFirst(a=>{r.push(a)})),this.rowRenderer.refreshCells({rowNodes:r}),this.dispatchFlashCells(o),this.fireRowChanged(i),this.refocusLastFocusedCell(),this.eventService.dispatchEvent({type:"pasteEnd",source:t})}pasteIntoActiveRange(e,t,s,o,i){const l=this.getRangeSize(e)%t.length!=0;let r=0,a=0;const n=(u,c,p,d)=>{if(d-r>=t.length){if(l)return;r+=a,a=0}const C=t[d-r];o.push(c);const S=this.gos.getCallback("processCellFromClipboard");p.forEach((f,v)=>{if(!f.isCellEditable(c)||f.isSuppressPaste(c))return;v>=C.length&&(v=v%C.length);const x=this.processCell(c,f,C[v],y,S,!0);c.setDataValue(f,x,m),i&&i.addParentNode(c.parent,[f]);const{rowIndex:A,rowPinned:D}=u,O=this.cellPositionUtils.createIdFromValues({rowIndex:A,column:f,rowPinned:D});s[O]=!0}),a++};this.iterateActiveRanges(!1,n)}getDisplayedColumnsStartingAt(e){let t=e;const s=[];for(;t!=null;)s.push(t),t=this.visibleColsService.getColAfter(t);return s}pasteStartingFromFocusedCell(e,t,s,o,i){if(!o)return;const l={rowIndex:o.rowIndex,rowPinned:o.rowPinned},r=this.getDisplayedColumnsStartingAt(o.column);this.isPasteSingleValueIntoRange(e)?this.pasteSingleValueIntoRange(e,s,t,i):this.pasteMultipleValues(e,l,s,r,t,P,i)}isPasteSingleValueIntoRange(e){return this.hasOnlyOneValueToPaste(e)&&this.rangeService!=null&&!this.rangeService.isEmpty()}pasteSingleValueIntoRange(e,t,s,o){const i=e[0][0],l=(r,a,n)=>{t.push(a),n.forEach(u=>this.updateCellValue(a,u,i,s,P,o))};this.iterateActiveRanges(!1,l)}hasOnlyOneValueToPaste(e){return e.length===1&&e[0].length===1}copyRangeDown(){if(!this.rangeService||this.rangeService.isEmpty())return;const e=[],t=(s,o,i,l)=>{const r=this.gos.getCallback("processCellForClipboard"),a=this.gos.getCallback("processCellFromClipboard"),n=(u,c,p)=>{e.length?(o.push(c),p.forEach((d,h)=>{if(!d.isCellEditable(c)||d.isSuppressPaste(c))return;const C=this.processCell(c,d,e[h],y,a,!0);c.setDataValue(d,C,m),l&&l.addParentNode(c.parent,[d]);const{rowIndex:S,rowPinned:f}=u,v=this.cellPositionUtils.createIdFromValues({rowIndex:S,column:d,rowPinned:f});s[v]=!0})):p.forEach(d=>{const h=this.processCell(c,d,this.valueService.getValue(d,c),y,r,!1,!0);e.push(h)})};this.iterateActiveRanges(!0,n)};this.doPasteOperation(t)}removeLastLineIfBlank(e){const t=K(e);if(t&&t.length===1&&t[0]===""){if(e.length===1)return;Q(e,t)}}fireRowChanged(e){this.gos.get("editType")==="fullRow"&&e.forEach(t=>{this.eventService.dispatchEvent({type:"rowValueChanged",node:t,data:t.data,rowIndex:t.rowIndex,rowPinned:t.rowPinned})})}pasteMultipleValues(e,t,s,o,i,l,r){let a=t;const n=this.clientSideRowModel!=null&&!this.gos.get("enableGroupEdit")&&!this.gos.get("treeData"),u=()=>{for(;;){if(!a)return null;const c=this.rowPositionUtils.getRowNode(a);if(a=this.cellNavigationService.getRowBelow({rowPinned:a.rowPinned,rowIndex:a.rowIndex}),c==null)return null;if(!(c.detail||c.footer||n&&c.group))return c}};e.forEach(c=>{const p=u();p&&(c.forEach((d,h)=>this.updateCellValue(p,o[h],d,i,l,r)),s.push(p))})}updateCellValue(e,t,s,o,i,l){if(!e||!t||!t.isCellEditable(e)||t.isSuppressPaste(e))return;const r=this.processCell(e,t,s,i,this.gos.getCallback("processCellFromClipboard"),!0);e.setDataValue(t,r,m);const{rowIndex:a,rowPinned:n}=e,u=this.cellPositionUtils.createIdFromValues({rowIndex:a,column:t,rowPinned:n});o[u]=!0,l&&l.addParentNode(e.parent,[t])}copyToClipboard(e={}){this.copyOrCutToClipboard(e)}cutToClipboard(e={},t="api"){this.gos.get("suppressCutToClipboard")||(this.eventService.dispatchEvent({type:"cutStart",source:t}),this.copyOrCutToClipboard(e,!0),this.eventService.dispatchEvent({type:"cutEnd",source:t}))}copyOrCutToClipboard(e,t){let{includeHeaders:s,includeGroupHeaders:o}=e;s==null&&(s=this.gos.get("copyHeadersToClipboard")),o==null&&(o=this.gos.get("copyGroupHeadersToClipboard"));const i={includeHeaders:s,includeGroupHeaders:o},l=this.gos.get("rowSelection"),r=this.gos.get("cellSelection");let a=null;this.shouldCopyCells(r,l)?(this.copySelectedRangeToClipboard(i),a=0):this.shouldCopyRows(l)?(this.copySelectedRowsToClipboard(i),a=1):this.focusService.isAnyCellFocused()&&(this.copyFocusedCellToClipboard(i),a=2),t&&a!==null&&this.clearCellsAfterCopy(a)}shouldCopyCells(e,t){if(!this.rangeService||this.rangeService.isEmpty())return!1;if(e)return!(typeof t=="object"&&t.copySelectedRows&&!this.selectionService.isEmpty());{const s=this.gos.get("suppressCopySingleCellRanges");return!(!this.rangeService.isMoreThanOneCell()&&s)}}shouldCopyRows(e){return this.selectionService.isEmpty()?!1:e&&typeof e!="string"?e.copySelectedRows??!1:!this.gos.get("suppressCopyRowsToClipboard")}clearCellsAfterCopy(e){if(this.eventService.dispatchEvent({type:"keyShortcutChangedCellStart"}),e===0)this.rangeService.clearCellRangeCellValues({cellEventSource:"clipboardService"});else if(e===1)this.clearSelectedRows();else{const t=this.focusService.getFocusedCell();if(t==null)return;const s=this.rowPositionUtils.getRowNode(t);s&&this.clearCellValue(s,t.column)}this.eventService.dispatchEvent({type:"keyShortcutChangedCellEnd"})}clearSelectedRows(){const e=this.selectionService.getSelectedNodes(),t=this.visibleColsService.getAllCols();for(const s of e)for(const o of t)this.clearCellValue(s,o)}clearCellValue(e,t){if(!t.isCellEditable(e))return;const s=this.valueService.getDeleteValue(t,e);e.setDataValue(t,s,"clipboardService")}iterateActiveRanges(e,t,s){if(!this.rangeService||this.rangeService.isEmpty())return;const o=this.rangeService.getCellRanges();e?this.iterateActiveRange(o[0],t,s,!0):o.forEach((i,l)=>this.iterateActiveRange(i,t,s,l===o.length-1))}iterateActiveRange(e,t,s,o){if(!this.rangeService)return;let i=this.rangeService.getRangeStartRow(e);const l=this.rangeService.getRangeEndRow(e);s&&e.columns&&s(e.columns);let r=0,a=!1;for(;!a&&i!=null;){const n=this.rowPositionUtils.getRowNode(i);a=this.rowPositionUtils.sameRow(i,l),t(i,n,e.columns,r++,a&&o),i=this.cellNavigationService.getRowBelow(i)}}copySelectedRangeToClipboard(e={}){if(!this.rangeService||this.rangeService.isEmpty())return;const t=this.rangeService.areAllRangesAbleToMerge(),{data:s,cellsToFlash:o}=t?this.buildDataFromMergedRanges(this.rangeService,e):this.buildDataFromRanges(this.rangeService,e);this.copyDataToClipboard(s),this.dispatchFlashCells(o)}buildDataFromMergedRanges(e,t){const s=new Set,o=e.getCellRanges(),i=new Map,l=[],r={};o.forEach(c=>{c.columns.forEach(h=>s.add(h));const{rowPositions:p,cellsToFlash:d}=this.getRangeRowPositionsAndCellsToFlash(e,c);p.forEach(h=>{const C=`${h.rowIndex}-${h.rowPinned||"null"}`;i.get(C)||(i.set(C,!0),l.push(h))}),Object.assign(r,d)});const a=this.visibleColsService.getAllCols(),n=Array.from(s);return n.sort((c,p)=>{const d=a.indexOf(c),h=a.indexOf(p);return d-h}),{data:this.buildExportParams({columns:n,rowPositions:l,includeHeaders:t.includeHeaders,includeGroupHeaders:t.includeGroupHeaders}),cellsToFlash:r}}buildDataFromRanges(e,t){const s=e.getCellRanges(),o=[],i={};return s.forEach(l=>{const{rowPositions:r,cellsToFlash:a}=this.getRangeRowPositionsAndCellsToFlash(e,l);Object.assign(i,a),o.push(this.buildExportParams({columns:l.columns,rowPositions:r,includeHeaders:t.includeHeaders,includeGroupHeaders:t.includeGroupHeaders}))}),{data:o.join(`
`),cellsToFlash:i}}getRangeRowPositionsAndCellsToFlash(e,t){const s=[],o={},i=e.getRangeStartRow(t),l=e.getRangeEndRow(t);let r=i;for(;r&&(s.push(r),t.columns.forEach(a=>{const{rowIndex:n,rowPinned:u}=r,c=this.cellPositionUtils.createIdFromValues({rowIndex:n,column:a,rowPinned:u});o[c]=!0}),!this.rowPositionUtils.sameRow(r,l));)r=this.cellNavigationService.getRowBelow(r);return{rowPositions:s,cellsToFlash:o}}getCellsToFlashFromRowNodes(e){const t=this.visibleColsService.getAllCols(),s={};for(let o=0;o<e.length;o++){const{rowIndex:i,rowPinned:l}=e[o];if(i!=null)for(let r=0;r<t.length;r++){const a=t[r],n=this.cellPositionUtils.createIdFromValues({rowIndex:i,column:a,rowPinned:l});s[n]=!0}}return s}copyFocusedCellToClipboard(e={}){const t=this.focusService.getFocusedCell();if(t==null)return;const s=this.cellPositionUtils.createId(t),o={rowPinned:t.rowPinned,rowIndex:t.rowIndex},i=t.column,l=this.buildExportParams({columns:[i],rowPositions:[o],includeHeaders:e.includeHeaders,includeGroupHeaders:e.includeGroupHeaders});this.copyDataToClipboard(l),this.dispatchFlashCells({[s]:!0})}copySelectedRowsToClipboard(e={}){const{columnKeys:t,includeHeaders:s,includeGroupHeaders:o}=e,i=this.buildExportParams({columns:t,includeHeaders:s,includeGroupHeaders:o});this.copyDataToClipboard(i);const l=this.selectionService.getSelectedNodes()||[];this.dispatchFlashCells(this.getCellsToFlashFromRowNodes(l))}buildExportParams(e){const{columns:t,rowPositions:s,includeHeaders:o=!1,includeGroupHeaders:i=!1}=e,l={columnKeys:t,rowPositions:s,skipColumnHeaders:!o,skipColumnGroupHeaders:!i,suppressQuotes:!0,columnSeparator:this.getClipboardDelimiter(),onlySelected:!s,processCellCallback:this.gos.getCallback("processCellForClipboard"),processRowGroupCallback:r=>this.processRowGroupCallback(r),processHeaderCallback:this.gos.getCallback("processHeaderForClipboard"),processGroupHeaderCallback:this.gos.getCallback("processGroupHeaderForClipboard")};return this.csvCreator.getDataAsCsv(l,!0)}processRowGroupCallback(e){const{node:t,column:s}=e,o=this.gos.get("treeData"),i=this.gos.get("suppressGroupMaintainValueType");let r=(()=>{if(o||i||!s)return t.key;const n=t.groupData?.[s.getId()];return!n||!t.rowGroupColumn||t.rowGroupColumn.getColDef().useValueFormatterForExport===!1?n:this.valueService.formatValue(t.rowGroupColumn,t,n)??n})();if(e.node.footer){let n="";r&&r.length&&(n=` ${r}`),r=`Total${n}`}const a=this.gos.getCallback("processCellForClipboard");if(a){let n=t.rowGroupColumn;return!n&&t.footer&&t.level===-1&&(n=this.funcColsService.getRowGroupColumns()[0]),a({value:r,node:t,column:n,type:"clipboard",formatValue:u=>this.valueService.formatValue(n,t,u)??u,parseValue:u=>this.valueService.parseValue(n,t,u,this.valueService.getValue(n,t))})}return r}dispatchFlashCells(e){window.setTimeout(()=>{this.eventService.dispatchEvent({type:"flashCells",cells:e})},0)}processCell(e,t,s,o,i,l,r){return i?i({column:t,node:e,value:s,type:o,formatValue:n=>this.valueService.formatValue(t,e??null,n)??n,parseValue:n=>this.valueService.parseValue(t,e??null,n,this.valueService.getValue(t,e))}):l&&t.getColDef().useValueParserForImport!==!1?this.valueService.parseValue(t,e??null,s,this.valueService.getValue(t,e)):r&&t.getColDef().useValueFormatterForExport!==!1?this.valueService.formatValue(t,e??null,s)??s:s}copyDataToClipboard(e){const t=this.gos.getCallback("sendToClipboard");if(t){t({data:e});return}if(!this.gos.get("suppressClipboardApi")&&navigator.clipboard){navigator.clipboard.writeText(e).catch(o=>{w(`${o}
${E("writeText")}`),this.copyDataToClipboardLegacy(e)});return}this.copyDataToClipboardLegacy(e)}copyDataToClipboardLegacy(e){this.executeOnTempElement(t=>{const s=T(this.gos),o=Y(this.gos);t.value=e||" ",t.select(),t.focus({preventScroll:!0}),s.execCommand("copy")||w("Browser did not allow document.execCommand('copy'). Ensure api.copySelectedRowsToClipboard() is invoked via a user event, i.e. button click, otherwise the browser will prevent it for security reasons."),o!=null&&o.focus!=null&&o.focus({preventScroll:!0})})}executeOnTempElement(e,t){const s=T(this.gos),o=s.createElement("textarea");o.style.width="1px",o.style.height="1px",o.style.top=s.documentElement.scrollTop+"px",o.style.left=s.documentElement.scrollLeft+"px",o.style.position="absolute",o.style.opacity="0";const i=this.gridCtrl.getGui();i.appendChild(o);try{e(o)}catch{w("Browser does not support document.execCommand('copy') for clipboard operations")}t?window.setTimeout(()=>{t(o),i.removeChild(o)},100):i.removeChild(o)}getRangeSize(e){const t=e.getCellRanges();let s=0,o=0;return t.length>0&&(s=e.getRangeStartRow(t[0]).rowIndex,o=e.getRangeEndRow(t[0]).rowIndex),s-o+1}},F="32.3.8",I=R({version:F,moduleName:`${b.ClipboardModule}-core`,beans:[X],dependantModules:[M,k]}),q=R({version:F,moduleName:`${b.ClipboardModule}-api`,apiFunctions:{copyToClipboard:G,cutToClipboard:H,copySelectedRowsToClipboard:L,copySelectedRangeToClipboard:U,copySelectedRangeDown:B,pasteFromClipboard:_},dependantModules:[I]}),J=R({version:F,moduleName:b.ClipboardModule,dependantModules:[I,q]});export{J as ClipboardModule};