first commit
SAP-ERP Portal CI/CD / build (push) Failing after 5m20s

This commit is contained in:
John
2026-09-23 17:31:02 +05:30
commit 69b4e68baf
51657 changed files with 3864077 additions and 0 deletions
+105
View File
@@ -0,0 +1,105 @@
const RichTextXform = require('../strings/rich-text-xform');
const utils = require('../../../utils/utils');
const BaseXform = require('../base-xform');
/**
<comment ref="B1" authorId="0">
<text>
<r>
<rPr>
<b/>
<sz val="9"/>
<rFont val="宋体"/>
<charset val="134"/>
</rPr>
<t>51422:</t>
</r>
<r>
<rPr>
<sz val="9"/>
<rFont val="宋体"/>
<charset val="134"/>
</rPr>
<t xml:space="preserve">&#10;test</t>
</r>
</text>
</comment>
*/
const CommentXform = (module.exports = function(model) {
this.model = model;
});
utils.inherits(CommentXform, BaseXform, {
get tag() {
return 'r';
},
get richTextXform() {
if (!this._richTextXform) {
this._richTextXform = new RichTextXform();
}
return this._richTextXform;
},
render(xmlStream, model) {
model = model || this.model;
xmlStream.openNode('comment', {
ref: model.ref,
authorId: 0,
});
xmlStream.openNode('text');
if (model && model.note && model.note.texts) {
model.note.texts.forEach(text => {
this.richTextXform.render(xmlStream, text);
});
}
xmlStream.closeNode();
xmlStream.closeNode();
},
parseOpen(node) {
if (this.parser) {
this.parser.parseOpen(node);
return true;
}
switch (node.name) {
case 'comment':
this.model = {
type: 'note',
note: {
texts: [],
},
...node.attributes,
};
return true;
case 'r':
this.parser = this.richTextXform;
this.parser.parseOpen(node);
return true;
default:
return false;
}
},
parseText(text) {
if (this.parser) {
this.parser.parseText(text);
}
},
parseClose(name) {
switch (name) {
case 'comment':
return false;
case 'r':
this.model.note.texts.push(this.parser.model);
this.parser = undefined;
return true;
default:
if (this.parser) {
this.parser.parseClose(name);
}
return true;
}
},
});
+82
View File
@@ -0,0 +1,82 @@
const XmlStream = require('../../../utils/xml-stream');
const utils = require('../../../utils/utils');
const BaseXform = require('../base-xform');
const CommentXform = require('./comment-xform');
const CommentsXform = (module.exports = function() {
this.map = {
comment: new CommentXform(),
};
});
utils.inherits(
CommentsXform,
BaseXform,
{
COMMENTS_ATTRIBUTES: {
xmlns: 'http://schemas.openxmlformats.org/spreadsheetml/2006/main',
},
},
{
render(xmlStream, model) {
model = model || this.model;
xmlStream.openXml(XmlStream.StdDocAttributes);
xmlStream.openNode('comments', CommentsXform.COMMENTS_ATTRIBUTES);
// authors
// TODO: support authors properly
xmlStream.openNode('authors');
xmlStream.leafNode('author', null, 'Author');
xmlStream.closeNode();
// comments
xmlStream.openNode('commentList');
model.comments.forEach(comment => {
this.map.comment.render(xmlStream, comment);
});
xmlStream.closeNode();
xmlStream.closeNode();
},
parseOpen(node) {
if (this.parser) {
this.parser.parseOpen(node);
return true;
}
switch (node.name) {
case 'commentList':
this.model = {
comments: [],
};
return true;
case 'comment':
this.parser = this.map.comment;
this.parser.parseOpen(node);
return true;
default:
return false;
}
},
parseText(text) {
if (this.parser) {
this.parser.parseText(text);
}
},
parseClose(name) {
switch (name) {
case 'commentList':
return false;
case 'comment':
this.model.comments.push(this.parser.model);
this.parser = undefined;
return true;
default:
if (this.parser) {
this.parser.parseClose(name);
}
return true;
}
},
}
);
@@ -0,0 +1,39 @@
const BaseXform = require('../../base-xform');
class VmlPositionXform extends BaseXform {
constructor(model) {
super();
this._model = model;
}
get tag() {
return this._model && this._model.tag;
}
render(xmlStream, model, type) {
if (model === type[2]) {
xmlStream.leafNode(this.tag);
} else if (this.tag === 'x:SizeWithCells' && model === type[1]) {
xmlStream.leafNode(this.tag);
}
}
parseOpen(node) {
switch (node.name) {
case this.tag:
this.model = {};
this.model[this.tag] = true;
return true;
default:
return false;
}
}
parseText() {}
parseClose() {
return false;
}
}
module.exports = VmlPositionXform;
@@ -0,0 +1,36 @@
const BaseXform = require('../../base-xform');
class VmlProtectionXform extends BaseXform {
constructor(model) {
super();
this._model = model;
}
get tag() {
return this._model && this._model.tag;
}
render(xmlStream, model) {
xmlStream.leafNode(this.tag, null, model);
}
parseOpen(node) {
switch (node.name) {
case this.tag:
this.text = '';
return true;
default:
return false;
}
}
parseText(text) {
this.text = text;
}
parseClose() {
return false;
}
}
module.exports = VmlProtectionXform;
+60
View File
@@ -0,0 +1,60 @@
const BaseXform = require('../base-xform');
// render the triangle in the cell for the comment
class VmlAnchorXform extends BaseXform {
get tag() {
return 'x:Anchor';
}
getAnchorRect(anchor) {
const l = Math.floor(anchor.left);
const lf = Math.floor((anchor.left - l) * 68);
const t = Math.floor(anchor.top);
const tf = Math.floor((anchor.top - t) * 18);
const r = Math.floor(anchor.right);
const rf = Math.floor((anchor.right - r) * 68);
const b = Math.floor(anchor.bottom);
const bf = Math.floor((anchor.bottom - b) * 18);
return [l, lf, t, tf, r, rf, b, bf];
}
getDefaultRect(ref) {
const l = ref.col;
const lf = 6;
const t = Math.max(ref.row - 2, 0);
const tf = 14;
const r = l + 2;
const rf = 2;
const b = t + 4;
const bf = 16;
return [l, lf, t, tf, r, rf, b, bf];
}
render(xmlStream, model) {
const rect = model.anchor
? this.getAnchorRect(model.anchor)
: this.getDefaultRect(model.refAddress);
xmlStream.leafNode('x:Anchor', null, rect.join(', '));
}
parseOpen(node) {
switch (node.name) {
case this.tag:
this.text = '';
return true;
default:
return false;
}
}
parseText(text) {
this.text = text;
}
parseClose() {
return false;
}
}
module.exports = VmlAnchorXform;
+95
View File
@@ -0,0 +1,95 @@
const BaseXform = require('../base-xform');
const VmlAnchorXform = require('./vml-anchor-xform');
const VmlProtectionXform = require('./style/vml-protection-xform');
const VmlPositionXform = require('./style/vml-position-xform');
const POSITION_TYPE = ['twoCells', 'oneCells', 'absolute'];
class VmlClientDataXform extends BaseXform {
constructor() {
super();
this.map = {
'x:Anchor': new VmlAnchorXform(),
'x:Locked': new VmlProtectionXform({tag: 'x:Locked'}),
'x:LockText': new VmlProtectionXform({tag: 'x:LockText'}),
'x:SizeWithCells': new VmlPositionXform({tag: 'x:SizeWithCells'}),
'x:MoveWithCells': new VmlPositionXform({tag: 'x:MoveWithCells'}),
};
}
get tag() {
return 'x:ClientData';
}
render(xmlStream, model) {
const {protection, editAs} = model.note;
xmlStream.openNode(this.tag, {ObjectType: 'Note'});
this.map['x:MoveWithCells'].render(xmlStream, editAs, POSITION_TYPE);
this.map['x:SizeWithCells'].render(xmlStream, editAs, POSITION_TYPE);
this.map['x:Anchor'].render(xmlStream, model);
this.map['x:Locked'].render(xmlStream, protection.locked);
xmlStream.leafNode('x:AutoFill', null, 'False');
this.map['x:LockText'].render(xmlStream, protection.lockText);
xmlStream.leafNode('x:Row', null, model.refAddress.row - 1);
xmlStream.leafNode('x:Column', null, model.refAddress.col - 1);
xmlStream.closeNode();
}
parseOpen(node) {
switch (node.name) {
case this.tag:
this.reset();
this.model = {
anchor: [],
protection: {},
editAs: '',
};
break;
default:
this.parser = this.map[node.name];
if (this.parser) {
this.parser.parseOpen(node);
}
break;
}
return true;
}
parseText(text) {
if (this.parser) {
this.parser.parseText(text);
}
}
parseClose(name) {
if (this.parser) {
if (!this.parser.parseClose(name)) {
this.parser = undefined;
}
return true;
}
switch (name) {
case this.tag:
this.normalizeModel();
return false;
default:
return true;
}
}
normalizeModel() {
const position = Object.assign(
{},
this.map['x:MoveWithCells'].model,
this.map['x:SizeWithCells'].model
);
const len = Object.keys(position).length;
this.model.editAs = POSITION_TYPE[len];
this.model.anchor = this.map['x:Anchor'].text;
this.model.protection.locked = this.map['x:Locked'].text;
this.model.protection.lockText = this.map['x:LockText'].text;
}
}
module.exports = VmlClientDataXform;
+107
View File
@@ -0,0 +1,107 @@
const XmlStream = require('../../../utils/xml-stream');
const BaseXform = require('../base-xform');
const VmlShapeXform = require('./vml-shape-xform');
// This class is (currently) single purposed to insert the triangle
// drawing icons on commented cells
class VmlNotesXform extends BaseXform {
constructor() {
super();
this.map = {
'v:shape': new VmlShapeXform(),
};
}
get tag() {
return 'xml';
}
render(xmlStream, model) {
xmlStream.openXml(XmlStream.StdDocAttributes);
xmlStream.openNode(this.tag, VmlNotesXform.DRAWING_ATTRIBUTES);
xmlStream.openNode('o:shapelayout', {'v:ext': 'edit'});
xmlStream.leafNode('o:idmap', {'v:ext': 'edit', data: 1});
xmlStream.closeNode();
xmlStream.openNode('v:shapetype', {
id: '_x0000_t202',
coordsize: '21600,21600',
'o:spt': 202,
path: 'm,l,21600r21600,l21600,xe',
});
xmlStream.leafNode('v:stroke', {joinstyle: 'miter'});
xmlStream.leafNode('v:path', {gradientshapeok: 't', 'o:connecttype': 'rect'});
xmlStream.closeNode();
model.comments.forEach((item, index) => {
this.map['v:shape'].render(xmlStream, item, index);
});
xmlStream.closeNode();
}
parseOpen(node) {
if (this.parser) {
this.parser.parseOpen(node);
return true;
}
switch (node.name) {
case this.tag:
this.reset();
this.model = {
comments: [],
};
break;
default:
this.parser = this.map[node.name];
if (this.parser) {
this.parser.parseOpen(node);
}
break;
}
return true;
}
parseText(text) {
if (this.parser) {
this.parser.parseText(text);
}
}
parseClose(name) {
if (this.parser) {
if (!this.parser.parseClose(name)) {
this.model.comments.push(this.parser.model);
this.parser = undefined;
}
return true;
}
switch (name) {
case this.tag:
return false;
default:
// could be some unrecognised tags
return true;
}
}
reconcile(model, options) {
model.anchors.forEach(anchor => {
if (anchor.br) {
this.map['xdr:twoCellAnchor'].reconcile(anchor, options);
} else {
this.map['xdr:oneCellAnchor'].reconcile(anchor, options);
}
});
}
}
VmlNotesXform.DRAWING_ATTRIBUTES = {
'xmlns:v': 'urn:schemas-microsoft-com:vml',
'xmlns:o': 'urn:schemas-microsoft-com:office:office',
'xmlns:x': 'urn:schemas-microsoft-com:office:excel',
};
module.exports = VmlNotesXform;
+95
View File
@@ -0,0 +1,95 @@
const BaseXform = require('../base-xform');
const VmlTextboxXform = require('./vml-textbox-xform');
const VmlClientDataXform = require('./vml-client-data-xform');
class VmlShapeXform extends BaseXform {
constructor() {
super();
this.map = {
'v:textbox': new VmlTextboxXform(),
'x:ClientData': new VmlClientDataXform(),
};
}
get tag() {
return 'v:shape';
}
render(xmlStream, model, index) {
xmlStream.openNode('v:shape', VmlShapeXform.V_SHAPE_ATTRIBUTES(model, index));
xmlStream.leafNode('v:fill', {color2: 'infoBackground [80]'});
xmlStream.leafNode('v:shadow', {color: 'none [81]', obscured: 't'});
xmlStream.leafNode('v:path', {'o:connecttype': 'none'});
this.map['v:textbox'].render(xmlStream, model);
this.map['x:ClientData'].render(xmlStream, model);
xmlStream.closeNode();
}
parseOpen(node) {
if (this.parser) {
this.parser.parseOpen(node);
return true;
}
switch (node.name) {
case this.tag:
this.reset();
this.model = {
margins: {
insetmode: node.attributes['o:insetmode'],
},
anchor: '',
editAs: '',
protection: {},
};
break;
default:
this.parser = this.map[node.name];
if (this.parser) {
this.parser.parseOpen(node);
}
break;
}
return true;
}
parseText(text) {
if (this.parser) {
this.parser.parseText(text);
}
}
parseClose(name) {
if (this.parser) {
if (!this.parser.parseClose(name)) {
this.parser = undefined;
}
return true;
}
switch (name) {
case this.tag:
this.model.margins.inset = this.map['v:textbox'].model && this.map['v:textbox'].model.inset;
this.model.protection =
this.map['x:ClientData'].model && this.map['x:ClientData'].model.protection;
this.model.anchor = this.map['x:ClientData'].model && this.map['x:ClientData'].model.anchor;
this.model.editAs = this.map['x:ClientData'].model && this.map['x:ClientData'].model.editAs;
return false;
default:
return true;
}
}
}
VmlShapeXform.V_SHAPE_ATTRIBUTES = (model, index) => ({
id: `_x0000_s${1025 + index}`,
type: '#_x0000_t202',
style:
'position:absolute; margin-left:105.3pt;margin-top:10.5pt;width:97.8pt;height:59.1pt;z-index:1;visibility:hidden',
fillcolor: 'infoBackground [80]',
strokecolor: 'none [81]',
'o:insetmode': model.note.margins && model.note.margins.insetmode,
});
module.exports = VmlShapeXform;
+64
View File
@@ -0,0 +1,64 @@
const BaseXform = require('../base-xform');
class VmlTextboxXform extends BaseXform {
get tag() {
return 'v:textbox';
}
conversionUnit(value, multiple, unit) {
return `${parseFloat(value) * multiple.toFixed(2)}${unit}`;
}
reverseConversionUnit(inset) {
return (inset || '').split(',').map(margin => {
return Number(parseFloat(this.conversionUnit(parseFloat(margin), 0.1, '')).toFixed(2));
});
}
render(xmlStream, model) {
const attributes = {
style: 'mso-direction-alt:auto',
};
if (model && model.note) {
let {inset} = model.note && model.note.margins;
if (Array.isArray(inset)) {
inset = inset
.map(margin => {
return this.conversionUnit(margin, 10, 'mm');
})
.join(',');
}
if (inset) {
attributes.inset = inset;
}
}
xmlStream.openNode('v:textbox', attributes);
xmlStream.leafNode('div', {style: 'text-align:left'});
xmlStream.closeNode();
}
parseOpen(node) {
switch (node.name) {
case this.tag:
this.model = {
inset: this.reverseConversionUnit(node.attributes.inset),
};
return true;
default:
return true;
}
}
parseText() {}
parseClose(name) {
switch (name) {
case this.tag:
return false;
default:
return true;
}
}
}
module.exports = VmlTextboxXform;