xlsx-populate
Version:
Excel XLSX parser/generator written in JavaScript with Node.js and browser support, jQuery/d3-style method chaining, and a focus on keeping existing workbook features and styles in tact.
162 lines (146 loc) • 4.85 kB
JavaScript
"use strict";
const _ = require("lodash");
const RichTextFragment = require("./RichTextFragment");
/**
* A RichText class that contains many {@link RichTextFragment}.
*/
class RichText {
/**
* Creates a new instance of RichText. If you get the instance by calling `Cell.value()`,
* adding a text contains line separator will trigger {@link Cell.style}('wrapText', true), which
* will make MS Excel show the new line. i.e. In MS Excel, Tap "alt+Enter" in a cell, the cell
* will set wrap text to true automatically.
*
* @param {undefined|null|Object} [node] - The node stored in the shared string
*/
constructor(node) {
this._node = [];
this._cell = null;
this._remainingNodes = [];
if (node) {
for (let i = 0; i < node.length; i++) {
const fragment = node[i];
if (fragment.name === 'r') {
this._node.push(new RichTextFragment(fragment, null, this));
} else {
// special node, e.g. rPh, phoneticPr in Japanese language.
this._remainingNodes.push(fragment);
}
}
}
}
/**
* Gets which cell this {@link RichText} instance belongs to.
* @return {Cell|undefined} The cell this instance belongs to.
*/
get cell() {
return this._cell;
}
/**
* Gets the how many rich text fragment this {@link RichText} instance contains
* @return {number} The number of fragments this {@link RichText} instance has.
*/
get length() {
return this._node.length;
}
/**
* Gets concatenated text without styles.
* @return {string} concatenated text
*/
text() {
let text = '';
for (let i = 0; i < this._node.length; i++) {
text += this.get(i).value();
}
return text;
}
/**
* Gets the instance with cell reference defined.
* @param {Cell} cell - Cell reference.
* @return {RichText} The instance with cell reference defined.
*/
getInstanceWithCellRef(cell) {
this._cell = cell;
return this;
}
/**
* Returns a deep copy of this instance.
* If cell reference is provided, it checks line separators and calls
* `cell.style('wrapText', true)` when needed.
* @param {Cell|undefined} [cell] - The cell reference.
* @return {RichText} A deep copied instance
*/
copy(cell) {
const newRichText = new RichText(_.cloneDeep(this.toXml()));
if (cell && _.includes(this.text(), '\n')) {
cell.style('wrapText', true);
}
return newRichText;
}
/**
* Gets the ith fragment of this {@link RichText} instance.
* @param {number} index - The index
* @return {RichTextFragment} A rich text fragment
*/
get(index) {
return this._node[index];
}
/**
* Removes a rich text fragment. This instance will be mutated.
* @param {number} index - the index of the fragment to remove
* @return {RichText} the rich text instance
*/
remove(index) {
this._node.splice(index, 1);
this.removeUnsupportedNodes();
return this;
}
/**
* Adds a rich text fragment to the last or after the given index. This instance will be mutated.
* @param {string} text - the text
* @param {{}} [styles] - the styles js object, i.e. {fontSize: 12}
* @param {number|undefined|null} [index] - the index of the fragment to add
* @return {RichText} the rich text instance
*/
add(text, styles, index) {
if (index === undefined || index === null) {
this._node.push(new RichTextFragment(text, styles, this));
} else {
this._node.splice(index, 0, new RichTextFragment(text, styles, this));
}
this.removeUnsupportedNodes();
return this;
}
/**
* Clears this rich text
* @return {RichText} the rich text instance
*/
clear() {
this._node = [];
this._remainingNodes = [];
this._cell = undefined;
return this;
}
/**
* Remove all unsupported nodes (phoneticPr, rPh for Japanese language).
* @return {undefined}
*/
removeUnsupportedNodes() {
this._remainingNodes = [];
}
/**
* Convert the rich text to an XML object.
* @returns {Array.<{}>} The XML form.
* @ignore
*/
toXml() {
const node = [];
for (let i = 0; i < this._node.length; i++) {
node.push(this._node[i].toXml());
}
return node.concat(this._remainingNodes);
}
}
// IE doesn't support function names so explicitly set it.
if (!RichText.name) RichText.name = "RichText";
module.exports = RichText;