Skip to content

Commit

Permalink
Merge pull request #109 from jdugh/move_images
Browse files Browse the repository at this point in the history
Add support for moving images down together with substitution process.
  • Loading branch information
kant2002 authored Jul 27, 2020
2 parents 8becbd0 + 0e6dd8e commit 3262f72
Show file tree
Hide file tree
Showing 4 changed files with 231 additions and 3 deletions.
6 changes: 5 additions & 1 deletion lib/index.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ export default class Workbook
protected readonly workbookPath: string;
protected readonly calcChainPath?: string;

constructor(data? : Buffer);
constructor(data? : Buffer, option? : object);
public deleteSheet(sheetName : string) : this;
public copySheet(sheetName : string, copyName : string) : this;
public loadTemplate(data : Buffer) : void;
Expand All @@ -39,6 +39,10 @@ export default class Workbook
protected replaceString(oldString : string, newString : string) : any; // returns idx
protected loadSheets(prefix : any, workbook : etree.ElementTree, workbookRels : any) : any[];
protected loadSheet(sheet : any) : { filename : any, name : any, id : any, root : any }; // this could definitely return a "Sheet" interface/class
protected loadSheetRels(sheetFilename : string) : { rels : any};
protected loadDrawing(sheet : any, sheetFilename : string, rels : any) : { drawing : any};
protected writeDrawing(drawing : any);
protected moveAllImages(drawing : any, fromRow : int, nbRow : int);
protected loadTables(sheet : any, sheetFilename : any) : any;
protected writeTables(tables : any) : void;
protected substituteHyperlinks(sheetFilename : any, substitutions : any) : void;
Expand Down
92 changes: 90 additions & 2 deletions lib/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -18,12 +18,13 @@ module.exports = (function() {
* Create a new workbook. Either pass the raw data of a .xlsx file,
* or call `loadTemplate()` later.
*/
var Workbook = function(data) {
var Workbook = function(data, option = {}) {
var self = this;

self.archive = null;
self.sharedStrings = [];
self.sharedStringsLookup = {};
self.option = option;

if(data) {
self.loadTemplate(data);
Expand Down Expand Up @@ -196,7 +197,8 @@ module.exports = (function() {
totalRowsInserted = 0,
totalColumnsInserted = 0,
namedTables = self.loadTables(sheet.root, sheet.filename),
rows = [];
rows = [],
drawing = null;

sheetData.findall("row").forEach(function(row) {
row.attrib.r = currentRow = self.getCurrentRow(row, totalRowsInserted);
Expand Down Expand Up @@ -294,6 +296,16 @@ module.exports = (function() {

// Add newly inserted rows
if(newTableRows.length > 0) {
//Move images for each subsitute array if option is active
if(self.option["moveImages"]){
var rels = self.loadSheetRels(sheet.filename);
if (rels != null && drawing == null){
drawing = self.loadDrawing(sheet.root, sheet.filename, rels.root);
}
if(drawing != null){
self.moveAllImages(drawing, row.attrib.r, newTableRows.length)
}
}
newTableRows.forEach(function(row) {
rows.push(row);
++totalRowsInserted;
Expand Down Expand Up @@ -350,6 +362,7 @@ module.exports = (function() {

self.writeSharedStrings();
self.writeTables(namedTables);
self.writeDrawing(drawing);
};

/**
Expand Down Expand Up @@ -482,6 +495,81 @@ module.exports = (function() {
};
};

//Load rels for a sheetName
Workbook.prototype.loadSheetRels = function (sheetFilename) {
var self = this;
var sheetDirectory = path.dirname(sheetFilename),
sheetName = path.basename(sheetFilename),
relsFilename = path.join(sheetDirectory, '_rels', sheetName + '.rels').replace(/\\/g, '/'),
relsFile = self.archive.file(relsFilename);
if (relsFile === null) {
return null;
}
var rels = {filename: relsFilename, root: etree.parse(relsFile.asText()).getroot()}
return rels;
}
//Load Drawing file
Workbook.prototype.loadDrawing = function (sheet, sheetFilename, rels) {
var self = this;
var sheetDirectory = path.dirname(sheetFilename),
sheetName = path.basename(sheetFilename),
drawing = {filename: '', root: null};
var drawingPart = sheet.find("drawing");
if (drawingPart === null) {
return null;
}
var relationshipId = drawingPart.attrib['r:id'],
target = rels.find("Relationship[@Id='" + relationshipId + "']").attrib.Target,
drawingFilename = path.join(sheetDirectory, target).replace(/\\/g, '/'),
drawingTree = etree.parse(self.archive.file(drawingFilename).asText());
drawing.filename = drawingFilename;
drawing.root = drawingTree.getroot();
drawing.relFilename = path.dirname(drawingFilename) + '/_rels/' + path.basename(drawingFilename) + '.rels';
drawing.relRoot = etree.parse(self.archive.file(drawing.relFilename).asText()).getroot();
return drawing;
};

//Write Drawing file
Workbook.prototype.writeDrawing = function (drawing) {
var self = this;
if (drawing!==null){
self.archive.file(drawing.filename, etree.tostring(drawing.root));
self.archive.file(drawing.relFilename, etree.tostring(drawing.relRoot));
}
};

//Move all images after fromRow of nbRow row
Workbook.prototype.moveAllImages = function(drawing, fromRow, nbRow){
var self = this;
drawing.root.getchildren().forEach(function(drawElement){
if(drawElement.tag == "xdr:twoCellAnchor"){
self._moveTwoCellAnchor(drawElement, fromRow, nbRow)
}
//TODO : make the other tags image
})
};

//Move TwoCellAnchor tag images after fromRow of nbRow row
Workbook.prototype._moveTwoCellAnchor = function(drawingElement, fromRow, nbRow){
var self = this;
var _moveImage = function(drawingElement, fromRow, nbRow){
var from = Number.parseInt(drawingElement.find('xdr:from').find('xdr:row').text, 10) + Number.parseInt(nbRow, 10)
drawingElement.find('xdr:from').find('xdr:row').text = from
var to = Number.parseInt(drawingElement.find('xdr:to').find('xdr:row').text, 10) + Number.parseInt(nbRow, 10)
drawingElement.find('xdr:to').find('xdr:row').text = to
}
if(self.option["moveSameLineImages"]){
if(parseInt(drawingElement.find('xdr:from').find('xdr:row').text) + 1 >= fromRow){
_moveImage(drawingElement, fromRow, nbRow)
}
}else{
if(parseInt(drawingElement.find('xdr:from').find('xdr:row').text) + 1 > fromRow){
_moveImage(drawingElement, fromRow, nbRow)
}
}
};


// Load tables for a given sheet
Workbook.prototype.loadTables = function(sheet, sheetFilename) {
var self = this;
Expand Down
136 changes: 136 additions & 0 deletions test/crud-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -871,6 +871,142 @@ describe("CRUD operations", function() {
done();
});
});

it("do not move Images", function(done) {
fs.readFile(path.join(__dirname, 'templates', 'test-move-images.xlsx'), function(err, data) {
buster.expect(err).toBeNull();
var option = {
moveImages : false
}
var t = new XlsxTemplate(data, option);
t.substitute(1, {
users: [
{
name: "John",
surname : "Smith"
},
{
name: "John",
surname : "Doe"
}
]
});
var newData = t.generate();
var drawingSheet = etree.parse(t.archive.file("xl/drawings/drawing1.xml").asText()).getroot();
buster.expect(drawingSheet).toBeDefined();
drawingSheet.findall('xdr:twoCellAnchor').forEach(element => {
if(element.find("xdr:pic/xdr:nvPicPr/xdr:cNvPr[@id='3']")){
buster.expect(element.find("xdr:from/xdr:row").text).toEqual("3");
buster.expect(element.find("xdr:to/xdr:row").text).toEqual("9");
}
if(element.find("xdr:pic/xdr:nvPicPr/xdr:cNvPr[@id='6']")){
buster.expect(element.find("xdr:from/xdr:row").text).toEqual("2");
buster.expect(element.find("xdr:to/xdr:row").text).toEqual("9");
}
if(element.find("xdr:pic/xdr:nvPicPr/xdr:cNvPr[@id='8']")){
buster.expect(element.find("xdr:from/xdr:row").text).toEqual("1");
buster.expect(element.find("xdr:to/xdr:row").text).toEqual("11");
}
if(element.find("xdr:pic/xdr:nvPicPr/xdr:cNvPr[@id='10']")){
buster.expect(element.find("xdr:from/xdr:row").text).toEqual("10");
buster.expect(element.find("xdr:to/xdr:row").text).toEqual("24");
}
});
fs.writeFileSync('test/output/test_donotmoveImages.xlsx', newData, 'binary');
done();
});
});

it("Move Images", function(done) {
fs.readFile(path.join(__dirname, 'templates', 'test-move-images.xlsx'), function(err, data) {
buster.expect(err).toBeNull();
var option = {
moveImages : true
}
var t = new XlsxTemplate(data, option);
t.substitute(1, {
users: [
{
name: "John",
surname : "Smith"
},
{
name: "John",
surname : "Doe"
}
]
});
var newData = t.generate();
var drawingSheet = etree.parse(t.archive.file("xl/drawings/drawing1.xml").asText()).getroot();
buster.expect(drawingSheet).toBeDefined();
drawingSheet.findall('xdr:twoCellAnchor').forEach(element => {
if(element.find("xdr:pic/xdr:nvPicPr/xdr:cNvPr[@id='3']")){
buster.expect(element.find("xdr:from/xdr:row").text).toEqual("4");
buster.expect(element.find("xdr:to/xdr:row").text).toEqual("10");
}
if(element.find("xdr:pic/xdr:nvPicPr/xdr:cNvPr[@id='6']")){
buster.expect(element.find("xdr:from/xdr:row").text).toEqual("2");
buster.expect(element.find("xdr:to/xdr:row").text).toEqual("9");
}
if(element.find("xdr:pic/xdr:nvPicPr/xdr:cNvPr[@id='8']")){
buster.expect(element.find("xdr:from/xdr:row").text).toEqual("1");
buster.expect(element.find("xdr:to/xdr:row").text).toEqual("11");
}
if(element.find("xdr:pic/xdr:nvPicPr/xdr:cNvPr[@id='10']")){
buster.expect(element.find("xdr:from/xdr:row").text).toEqual("11");
buster.expect(element.find("xdr:to/xdr:row").text).toEqual("25");
}
});
fs.writeFileSync('test/output/test_moveImages.xlsx', newData, 'binary');
done();
});
});

it("Move Images with sameLine option", function(done) {
fs.readFile(path.join(__dirname, 'templates', 'test-move-images.xlsx'), function(err, data) {
buster.expect(err).toBeNull();
var option = {
moveImages : true,
moveSameLineImages : true,
}
var t = new XlsxTemplate(data, option);
t.substitute(1, {
users: [
{
name: "John",
surname : "Smith"
},
{
name: "John",
surname : "Doe"
}
]
});
var newData = t.generate();
var drawingSheet = etree.parse(t.archive.file("xl/drawings/drawing1.xml").asText()).getroot();
buster.expect(drawingSheet).toBeDefined();
drawingSheet.findall('xdr:twoCellAnchor').forEach(element => {
if(element.find("xdr:pic/xdr:nvPicPr/xdr:cNvPr[@id='3']")){
buster.expect(element.find("xdr:from/xdr:row").text).toEqual("4");
buster.expect(element.find("xdr:to/xdr:row").text).toEqual("10");
}
if(element.find("xdr:pic/xdr:nvPicPr/xdr:cNvPr[@id='6']")){
buster.expect(element.find("xdr:from/xdr:row").text).toEqual("3");
buster.expect(element.find("xdr:to/xdr:row").text).toEqual("10");
}
if(element.find("xdr:pic/xdr:nvPicPr/xdr:cNvPr[@id='8']")){
buster.expect(element.find("xdr:from/xdr:row").text).toEqual("1");
buster.expect(element.find("xdr:to/xdr:row").text).toEqual("11");
}
if(element.find("xdr:pic/xdr:nvPicPr/xdr:cNvPr[@id='10']")){
buster.expect(element.find("xdr:from/xdr:row").text).toEqual("11");
buster.expect(element.find("xdr:to/xdr:row").text).toEqual("25");
}
});
fs.writeFileSync('test/output/test_moveImages_withSameLineOption.xlsx', newData, 'binary');
done();
});
});
});

describe("Multiple sheets", function() {
Expand Down
Binary file added test/templates/test-move-images.xlsx
Binary file not shown.

0 comments on commit 3262f72

Please sign in to comment.