/** @copyright 2018 Planning Village Corporation Co., Ltd. */ (function () { 'use strict'; // [IE11] Polyfill of Object.values if (!Object.values) { const ownKeys = ( (typeof Reflect === 'object' && typeof Reflect.ownKeys === 'function') ? Reflect.ownKeys : // @ts-ignore (typeof Object.getOwnPropertySymbols === 'function') ? (function (O) { // @ts-ignore return Object.getOwnPropertyNames(O).concat(Object.getOwnPropertySymbols(O)); }) : Object.getOwnPropertyNames); // @ts-ignore const reduce = Function.bind.call(Function.call, Array.prototype.reduce); // @ts-ignore const isEnumerable = Function.bind.call(Function.call, Object.prototype.propertyIsEnumerable); // @ts-ignore const concat = Function.bind.call(Function.call, Array.prototype.concat); //@ts-ignore Object.values = function values(O) { //@ts-ignore return reduce(ownKeys(O), function (v, k) { return concat(v, typeof k === 'string' && isEnumerable(O, k) ? [O[k]] : []) }, []) }; } // [IE11] Polyfill of Number.isNaN if (!Number.isNaN) { Number.isNaN = function (value) { return value !== null && (value != value || +value != value); }; } // [IE11] Polyfill of String.prototype.startsWith if (!String.prototype.startsWith) { Object.defineProperty(String.prototype, 'startsWith', { //@ts-ignore value: function (search, rawPos) { var pos = rawPos > 0 ? rawPos | 0 : 0; return this.substring(pos, pos + search.length) === search; } }); } // [IE11] Polyfill of String.prototype.includes if (!String.prototype.includes) { String.prototype.includes = function (search, start) { 'use strict'; //@ts-ignore if (search instanceof RegExp) { throw TypeError('first argument must not be a RegExp'); } if (start === undefined) { start = 0; } return this.indexOf(search, start) !== -1; }; } // [IE11] Polyfill of Array.prototype.findIndex if (!Array.prototype.findIndex) { // @ts-ignore Array.prototype.findIndex = function (predicate) { if (this === null) { throw new TypeError('Array.prototype.findIndex called on null or undefined'); } if (typeof predicate !== 'function') { throw new TypeError('predicate must be a function'); } var list = Object(this); var length = list.length >>> 0; var thisArg = arguments[1]; var value; for (var i = 0; i < length; i++) { value = list[i]; if (predicate.call(thisArg, value, i, list)) { return i; } } return -1; }; } //@ts-ignore window.pvc = window.pvc || {}; //@ts-ignore window.pvc.lib = window.pvc.lib || {}; //@ts-ignore window.pvc.lib.exceljsUtil = (function () { const exceljs = { /** * ワークブックの blob を読み取ります。 * @param {Blob} blob Blob * @return {Promise} ワークブック */ loadWorkbookBlob: function (blob) { return new Promise(function (resolve, reject) { var reader = new FileReader(); reader.onload = function (e) { // @ts-ignore resolve(e.target.result); }; reader.onerror = function (e) { reject(e); } reader.onabort = function (e) { reject(e); } reader.readAsArrayBuffer(blob); }).then(function (arrayBuffer) { // 非公式のメンバー load を使用 // @ts-ignore return new ExcelJS.Workbook().xlsx.load(arrayBuffer); }); }, /** * ワークブックを Blob に変換します。 * @param {ExcelJS.Workbook} workbook ワークブック * @return {Promise} Blob */ saveWorkbookToBlob: function (workbook) { // writeBuffer の戻り値 ExcelJS.Buffer はブラウザ環境では Uint8Array となる return workbook.xlsx.writeBuffer().then(function (ua) { return new Blob([ua], { type: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet' }); }); }, /** * 行をコピーします。 * @param {ExcelJS.Worksheet} worksheet ワークシート * @param {number} topRowNumber コピー元の開始行番号(1から開始) * @param {number} [bottomRowNumber] コピー元の終了行番号(1から開始)。省略時は開始行番号と同じ値となります。 * @returns {pvc.lib.exceljsUtil.CopiedRowsInfo} 行のコピー情報 */ copyRows: function (worksheet, topRowNumber, bottomRowNumber) { const _bottomRowNumber = (bottomRowNumber == null ? topRowNumber : bottomRowNumber); if (topRowNumber < 0 || _bottomRowNumber < topRowNumber) { throw new Error('コピー元の領域とが不正です。'); } // コピー元の領域の情報を収集 const rows = []; for (let r = topRowNumber; r <= _bottomRowNumber; r++) { const row = worksheet.getRow(r); const cells = []; for (let c = 1; c <= worksheet.columnCount; c++) { const cell = row.getCell(c); cells.push({ value: cell.value, style: cell.style, }); } rows.push({ cells: cells, height: row.height, // 非公式のメンバー style を使用 // @ts-ignore style: row.style, }); } // コピー元の領域の内部に収まるマージを収集 const merges = deepCopyObject(getWorksheetMerges(worksheet).filter(function (merge) { return (topRowNumber <= merge.top && merge.bottom <= _bottomRowNumber); }).map(function (merge) { return { top: merge.top - topRowNumber, right: merge.right, bottom: merge.bottom - topRowNumber, left: merge.left, }; })); return deepCopyObject({ rows: rows, merges: merges }); }, /** * 指定された開始行を起点に、コピーした行を貼り付けます。 * コピー元の領域と領域外の両方にまたがるセルのマージは貼り付けされません。 * コピー先の領域を一部でも含むマージは全て解除されます。 * @param {ExcelJS.Worksheet} worksheet ワークシート * @param {number} topRowNumber コピー先の開始行番号(1から開始) * @param {pvc.lib.exceljsUtil.CopiedRowsInfo} copiedRowsInfo 行のコピー情報 */ pasteRows: function (worksheet, topRowNumber, copiedRowsInfo) { const bottomRowNumber = topRowNumber + copiedRowsInfo.rows.length - 1; if (topRowNumber < 0) { throw new Error('コピー先の領域とが不正です。'); } // コピー先の行のマージを解除(コピー先の領域を一部でも含むマージは全て解除) getWorksheetMerges(worksheet).filter(function (merge) { return (topRowNumber <= merge.bottom && merge.top <= bottomRowNumber); }).forEach(function (merge) { worksheet.unMergeCells(merge.range); }); // マージをペースト copiedRowsInfo.merges.forEach(function (mergeInfo) { worksheet.mergeCells( topRowNumber + mergeInfo.top, mergeInfo.left, topRowNumber + mergeInfo.bottom, mergeInfo.right); }); // セルをペースト copiedRowsInfo.rows.forEach(function (rowInfo, i) { const row = worksheet.getRow(topRowNumber + i); row.height = rowInfo.height; // 非公式のメンバー style を使用 // @ts-ignore row.style = rowInfo.style; for (let c = 1; c <= worksheet.columnCount; c++) { const cell = row.getCell(c); const cellInfo = rowInfo.cells[c - 1]; if (cellInfo) { cell.value = cellInfo.value; cell.style = cellInfo.style; } else { exceljs.clearCell(cell); } } }); }, /** * 指定された開始行を起点に、コピーした行を挿入します。 * コピー元の領域と領域外の両方にまたがるセルのマージは貼り付けされません。 * @param {ExcelJS.Worksheet} worksheet ワークシート * @param {number} topRowNumber コピー先の開始行番号(1から開始) * @param {pvc.lib.exceljsUtil.CopiedRowsInfo} copiedRowsInfo 行のコピー情報 */ insertRows: function (worksheet, topRowNumber, copiedRowsInfo) { const bottomRows = ( topRowNumber <= worksheet.rowCount ? exceljs.copyRows(worksheet, topRowNumber, worksheet.rowCount) : null); exceljs.pasteRows(worksheet, topRowNumber, copiedRowsInfo); if (bottomRows) { exceljs.pasteRows(worksheet, topRowNumber + copiedRowsInfo.rows.length, bottomRows); } }, /** * 列をコピーします。 * @param {ExcelJS.Worksheet} worksheet ワークシート * @param {number | string} leftColumn コピー元の開始列の列番号(1から開始)または列ラベル。終了列の引数を省略して、代わりに "A:B" の形式でコピー元の列の範囲を指定することも可能。 * @param {number | string} [rightColumn] コピー元の終了列の列番号(1から開始)または列ラベル。省略時は開始列と同じとみなされます(開始列を "A:B" の形式で指定された場合を除く)。 * @returns {pvc.lib.exceljsUtil.CopiedColumnsInfo} 列のコピー情報 */ copyColumns: function (worksheet, leftColumn, rightColumn) { if (rightColumn == null) { rightColumn = leftColumn; if (typeof leftColumn === 'string') { const sp = leftColumn.split(':'); if (sp.length === 2) { leftColumn = sp[0]; rightColumn = sp[1]; } } } const leftColumnNumber = ((typeof leftColumn === 'number') ? leftColumn : exceljs.columnLetterToColumnNumber(leftColumn)); const rightColumnNumber = ((typeof rightColumn === 'number') ? rightColumn : exceljs.columnLetterToColumnNumber(rightColumn)); if (leftColumnNumber < 0 || rightColumnNumber < leftColumnNumber) { throw new Error('コピー元の領域とが不正です。'); } // コピー元の領域の情報を収集 const columns = []; for (let c = leftColumnNumber; c <= rightColumnNumber; c++) { const column = worksheet.getColumn(c); const cells = []; for (let r = 1; r <= worksheet.rowCount; r++) { const cell = worksheet.getRow(r).getCell(c); cells.push({ value: cell.value, style: cell.style, }); } columns.push({ cells: cells, width: column.width, style: column.style, }); } // コピー元の領域の内部に収まるマージを収集 const merges = deepCopyObject(getWorksheetMerges(worksheet).filter(function (merge) { return (leftColumnNumber <= merge.left && merge.right <= rightColumnNumber); }).map(function (merge) { return { top: merge.top, right: merge.right - leftColumnNumber, bottom: merge.bottom, left: merge.left - leftColumnNumber, }; })); return { columns: columns, merges: merges }; }, /** * 指定された開始列を起点に、コピーした列を貼り付けます。 * コピー元の領域と領域外の両方にまたがるセルのマージは貼り付けされません。 * コピー先の領域を一部でも含むマージは全て解除されます。 * @param {ExcelJS.Worksheet} worksheet ワークシート * @param {number | string} leftColumn コピー先の開始列の列番号(1から開始)または列ラベル * @param {pvc.lib.exceljsUtil.CopiedColumnsInfo} copiedColumnsInfo 列のコピー情報 */ pasteColumns: function (worksheet, leftColumn, copiedColumnsInfo) { const leftColumnNumber = ((typeof leftColumn === 'number') ? leftColumn : exceljs.columnLetterToColumnNumber(leftColumn)); const rightColumnNumber = leftColumnNumber + copiedColumnsInfo.columns.length - 1; if (leftColumnNumber < 0) { throw new Error('コピー先の領域とが不正です。'); } // コピー先の列のマージを解除(コピー先の領域を一部でも含むマージは全て解除) getWorksheetMerges(worksheet).filter(function (merge) { return (leftColumnNumber <= merge.right && merge.left <= rightColumnNumber); }).forEach(function (merge) { worksheet.unMergeCells(merge.range); }); // マージをペースト copiedColumnsInfo.merges.forEach(function (mergeInfo) { worksheet.mergeCells( mergeInfo.top, leftColumnNumber + mergeInfo.left, mergeInfo.bottom, leftColumnNumber + mergeInfo.right); }); // セルをペースト copiedColumnsInfo.columns.forEach(function (columnInfo, i) { const column = worksheet.getColumn(leftColumnNumber + i); column.width = columnInfo.width; column.style = columnInfo.style; for (let r = 1; r <= worksheet.rowCount; r++) { const cell = worksheet.getRow(r).getCell(leftColumnNumber + i); const cellInfo = columnInfo.cells[r - 1]; if (cellInfo) { cell.value = cellInfo.value; cell.style = cellInfo.style; } else { exceljs.clearCell(cell); } } }); }, /** * 指定された開始列を起点に、コピーした列を挿入します。 * コピー元の領域と領域外の両方にまたがるセルのマージは貼り付けされません。 * @param {ExcelJS.Worksheet} worksheet ワークシート * @param {number | string} leftColumn コピー先の開始列の列番号(1から開始)または列ラベル * @param {pvc.lib.exceljsUtil.CopiedColumnsInfo} copiedRowsInfo 列のコピー情報 */ insertColumns: function (worksheet, leftColumn, copiedRowsInfo) { const leftColumnNumber = ((typeof leftColumn === 'number') ? leftColumn : exceljs.columnLetterToColumnNumber(leftColumn)); const rightColumns = ( leftColumnNumber <= worksheet.columnCount ? exceljs.copyColumns(worksheet, leftColumnNumber, worksheet.columnCount) : null); exceljs.pasteColumns(worksheet, leftColumnNumber, copiedRowsInfo); if (rightColumns) { exceljs.pasteColumns(worksheet, leftColumnNumber + copiedRowsInfo.columns.length, rightColumns); } }, /** * セルをクリアします。 * @param {ExcelJS.Cell} cell セル */ clearCell: function (cell) { cell.value = null; /// @ts-ignore cell.style = cell._mergeStyle(cell._row.style, cell._column.style, {}); }, /** * 列ラベルから列番号(1から開始)を取得します。 * @param {string} columnLetter 列ラベル * @return {number} 列番号(1から開始) */ columnLetterToColumnNumber: function (columnLetter) { const letter = columnLetter.toUpperCase(); const l = letter.length; const charCodeA = 65; let result = 0; for (let i = 0, j = l - 1; i < l; i++, j--) { result += (letter.charCodeAt(j) - charCodeA + 1) * (i === 0 ? 1 : Math.pow(26, i)); } return result; }, /** * 日付のセルの値を作成します。 * @param {Date} date * @returns {any} */ createDateCellValue: function (date) { // UTC にしないと正しく Excel に反映されない return new Date(Date.UTC(date.getFullYear(), date.getMonth(), date.getDate(), date.getHours(), date.getMinutes(), date.getSeconds())); }, deepCopyObject: deepCopyObject, }; /** * ワークシートのマージを取得します。 * @param {ExcelJS.Worksheet} worksheet ワークシート */ function getWorksheetMerges(worksheet) { // 非公式のメンバー _merges を使用 // @ts-ignore const mergesDic = worksheet._merges; return Object.keys(mergesDic).map(function (address) { return mergesDic[address]; }); } /** * オブジェクのコピーします。ディープコピーとなります。 * @template T * @param {T} obj * @returns {T} */ function deepCopyObject(obj) { return copyObject(obj); //@ts-ignore function copyObject(obj) { return ( obj == null ? null : Array.isArray(obj) ? copyArray(obj) : isDate(obj) ? copyDate(obj) : isDic(obj) ? copyDic(obj) : obj); } //@ts-ignore function copyArray(array) { //@ts-ignore return array.map(function (item) { return copyObject(item); }); } //@ts-ignore function isDate(obj) { return (obj != null && Object.prototype.toString.call(obj) === '[object Date]'); } //@ts-ignore function copyDate(date) { return (isNaN(date) ? null : new Date(date.getTime())); } //@ts-ignore function isDic(obj) { return (obj != null && typeof obj === 'object'); } //@ts-ignore function copyDic(dic) { let result = {}; for (let key in dic) { //@ts-ignore result[key] = copyObject(dic[key]); } return result; } } return exceljs; }()); })();