officegen-dbb
Version:
Modification of Ziv Barber's officegen, to provide a reasonable way to have line breaks in table cells.
318 lines (272 loc) • 17.1 kB
JavaScript
//
// officegen: Header and footer support for docx documents.
//
// Please refer to README.md for this module's documentations.
//
// NOTE:
// - Before changing this code please refer to the hacking the code section on README.md.
//
// Copyright (c) 2017 Ziv Barber;
//
// Permission is hereby granted, free of charge, to any person obtaining
// a copy of this software and associated documentation files (the
// 'Software'), to deal in the Software without restriction, including
// without limitation the rights to use, copy, modify, merge, publish,
// distribute, sublicense, and/or sell copies of the Software, and to
// permit persons to whom the Software is furnished to do so, subject to
// the following conditions:
//
// The above copyright notice and this permission notice shall be
// included in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
//
var docxP = require('./docx-p.js');
/**
* Create the API object for either the header or the footer.
* @param {object} headFootPlug Access to our plugin.
* @param {string} mainElement The name of the main element of this resource type.
* @param {string} pStyleDef The default style for the paragraph.
* @constructor
* @name MakeHeadFootObj
*/
function MakeHeadFootObj ( headFootPlug, mainElement, pStyleDef ) {
this.headFootPlug = headFootPlug;
this.docType = mainElement;
this.docStartExtra = '';
this.docEndExtra = '';
this.pStyleDef = pStyleDef;
this.data = [];
return this;
}
/**
* Create a new paragraph.
*
* @param {string} options Default options for all the objects inside this paragraph.
*/
MakeHeadFootObj.prototype.createP = function ( options ) {
// Create a new instance of the paragraph object:
return new docxP ( this.headFootPlug.pluginsman.genobj, this.headFootPlug.pluginsman.genPrivate, 'docx', this.data, {}, options );
};
/**
* This function creating the docx header-footer plugin object.
* @summary Create a new docx plugin.
* @param {object} pluginsman Access to the plugins manager for docx documents.
* @constructor
* @name MakeHeadfootPlugin
*/
function MakeHeadfootPlugin ( pluginsman ) {
var funcThis = this;
// You can change it if you want to support more types, since that the Word and Excel document generators also supporting very similar plugins:
if ( pluginsman.docType !== 'docx' ) {
throw "[docx-headfoot] This plugin supporting only Word based documents.";
} // Endif.
this.ogPluginsApi = pluginsman.ogPluginsApi; // Generic officegen API for plugins.
this.msPluginsApi = pluginsman.genPrivate.plugs.type.msoffice; // msoffice plugins API.
this.pluginsman = pluginsman; // Document type specific plugins API.
this.docxData = pluginsman.getDataStorage (); // Here you can store any temporary data needed for generating the document and depending on the data filled by the user.
this.mainPath = pluginsman.genPrivate.features.type.msoffice.main_path; // The "folder" name inside the document zip that all the specific resources of this document type are stored.
this.mainPathFile = pluginsman.genPrivate.features.type.msoffice.main_path_file; // The name of the main real xml resource of this document.
this.relsMain = pluginsman.genPrivate.type.msoffice.rels_main; // Main rels file.
this.relsApp = pluginsman.genPrivate.type.msoffice.rels_app; // Main rels file inside the specific document type "folder".
this.filesList = pluginsman.genPrivate.type.msoffice.files_list; // Resources list xml.
this.srcFilesList = pluginsman.genPrivate.type.msoffice.src_files_list; // For storing extra files inside the document zip.
//
// Catch events inside the document so we can extent it:
//
// We want to extend the main API of the docx document object:
pluginsman.registerCallback ( 'makeDocApi', function ( docObj ) { funcThis.extenddocxApi ( docObj ); } );
// This event tell us that the generator is about to start working:
pluginsman.registerCallback ( 'beforeGen', function ( docObj ) { funcThis.beforeGen ( docObj ); } );
return this;
}
//
// Events implementations:
//
/**
* This function extending the main document object with new API methods.
* @param {object} docObj Document object.
*/
MakeHeadfootPlugin.prototype.extenddocxApi = function ( docObj ) {
var funcThis = this;
docObj.getHeader = function ( objSubType ) {
if ( objSubType ) {
if ( objSubType !== 'even' && objSubType !== 'first' ) {
throw 'objSubType can be either "even", "first" or false value';
} // Endif.
} // Endif.
objSubType = 'docHeader' + (objSubType || '');
if ( funcThis.docxData[objSubType] ) {
return funcThis.docxData[objSubType];
} // Endif.
funcThis.docxData[objSubType] = new MakeHeadFootObj ( funcThis, 'hdr', 'Header' );
return funcThis.docxData[objSubType];
};
docObj.getFooter = function ( objSubType ) {
if ( objSubType ) {
if ( objSubType !== 'even' && objSubType !== 'first' ) {
throw 'objSubType can be either "even", "first" or false value';
} // Endif.
} // Endif.
objSubType = 'docFooter' + (objSubType || '');
if ( funcThis.docxData[objSubType] ) {
return funcThis.docxData[objSubType];
} // Endif.
funcThis.docxData[objSubType] = new MakeHeadFootObj ( funcThis, 'ftr', 'Footer' );
return funcThis.docxData[objSubType];
};
}
/**
* This function been called just before starting to generate the output document zip.
* @param {object} docObj Document object.
*/
MakeHeadfootPlugin.prototype.beforeGen = function ( docObj ) {
var funcThis = this;
var isNeedHeadFoot = false;
if ( funcThis.docxData.docHeader || funcThis.docxData.docHeadereven || funcThis.docxData.docHeaderfirst || funcThis.docxData.docFooter || funcThis.docxData.docFootereven || funcThis.docxData.docFooterfirst ) {
isNeedHeadFoot = true;
} // Endif.
if ( isNeedHeadFoot ) {
// Create the endnotes resource:
this.ogPluginsApi.intAddAnyResourceToParse ( this.mainPath + '\\endnotes.xml', 'buffer', null, function ( data ) { return funcThis.cbEndNotes ( data ) }, false );
// Create the footnotes resource:
this.ogPluginsApi.intAddAnyResourceToParse ( this.mainPath + '\\footnotes.xml', 'buffer', null, function ( data ) { return funcThis.cbFootNotes ( data ) }, false );
// Create header1.xml:
this.ogPluginsApi.intAddAnyResourceToParse ( this.mainPath + '\\header1.xml', 'buffer', funcThis.pluginsman.genobj.getHeader ( 'even' ), funcThis.pluginsman.genobj.cbMakeDocxDocument, false );
// Create header2.xml:
this.ogPluginsApi.intAddAnyResourceToParse ( this.mainPath + '\\header2.xml', 'buffer', funcThis.pluginsman.genobj.getHeader (), funcThis.pluginsman.genobj.cbMakeDocxDocument, false );
// Create header3.xml:
this.ogPluginsApi.intAddAnyResourceToParse ( this.mainPath + '\\header3.xml', 'buffer', funcThis.pluginsman.genobj.getHeader ( 'first' ), funcThis.pluginsman.genobj.cbMakeDocxDocument, false );
// Create footer1.xml:
this.ogPluginsApi.intAddAnyResourceToParse ( this.mainPath + '\\footer1.xml', 'buffer', funcThis.pluginsman.genobj.getFooter ( 'even' ), funcThis.pluginsman.genobj.cbMakeDocxDocument, false );
// Create footer2.xml:
this.ogPluginsApi.intAddAnyResourceToParse ( this.mainPath + '\\footer2.xml', 'buffer', funcThis.pluginsman.genobj.getFooter (), funcThis.pluginsman.genobj.cbMakeDocxDocument, false );
// Create footer3.xml:
this.ogPluginsApi.intAddAnyResourceToParse ( this.mainPath + '\\footer3.xml', 'buffer', funcThis.pluginsman.genobj.getFooter ( 'first' ), funcThis.pluginsman.genobj.cbMakeDocxDocument, false );
// Add a rel entry to the main docx rels:
this.relsApp.push ({
target: 'header1.xml',
type: 'http://schemas.openxmlformats.org/officeDocument/2006/relationships/header',
clear: 'generate' // Placing 'generate' here means that officegen will destroy this entry in the files list after finishing to generate the document.
});
this.docxData.header1RelId = this.relsApp.length;
this.relsApp.push ({
target: 'header2.xml',
type: 'http://schemas.openxmlformats.org/officeDocument/2006/relationships/header',
clear: 'generate' // Placing 'generate' here means that officegen will destroy this entry in the files list after finishing to generate the document.
});
this.docxData.header2RelId = this.relsApp.length;
this.relsApp.push ({
target: 'header3.xml',
type: 'http://schemas.openxmlformats.org/officeDocument/2006/relationships/header',
clear: 'generate' // Placing 'generate' here means that officegen will destroy this entry in the files list after finishing to generate the document.
});
this.docxData.header3RelId = this.relsApp.length;
this.relsApp.push ({
target: 'footer1.xml',
type: 'http://schemas.openxmlformats.org/officeDocument/2006/relationships/footer',
clear: 'generate' // Placing 'generate' here means that officegen will destroy this entry in the files list after finishing to generate the document.
});
this.docxData.footer1RelId = this.relsApp.length;
this.relsApp.push ({
target: 'footer2.xml',
type: 'http://schemas.openxmlformats.org/officeDocument/2006/relationships/footer',
clear: 'generate' // Placing 'generate' here means that officegen will destroy this entry in the files list after finishing to generate the document.
});
this.docxData.footer2RelId = this.relsApp.length;
this.relsApp.push ({
target: 'footer3.xml',
type: 'http://schemas.openxmlformats.org/officeDocument/2006/relationships/footer',
clear: 'generate' // Placing 'generate' here means that officegen will destroy this entry in the files list after finishing to generate the document.
});
this.docxData.footer3RelId = this.relsApp.length;
this.relsApp.push ({
target: 'endnotes.xml',
type: 'http://schemas.openxmlformats.org/officeDocument/2006/relationships/endnotes',
clear: 'generate' // Placing 'generate' here means that officegen will destroy this entry in the files list after finishing to generate the document.
});
this.relsApp.push ({
target: 'footnotes.xml',
type: 'http://schemas.openxmlformats.org/officeDocument/2006/relationships/footernotes',
clear: 'generate' // Placing 'generate' here means that officegen will destroy this entry in the files list after finishing to generate the document.
});
// Filling secPrExtra with data will connect the header and footer to the Word document:
funcThis.docxData.secPrExtra = '<w:headerReference w:type="default" r:id="rId' + this.docxData.header2RelId + '"/>';
funcThis.docxData.secPrExtra += '<w:footerReference w:type="default" r:id="rId' + this.docxData.footer2RelId + '"/>';
funcThis.docxData.secPrExtra += '<w:headerReference w:type="first" r:id="rId' + this.docxData.header3RelId + '"/>';
funcThis.docxData.secPrExtra += '<w:footerReference w:type="first" r:id="rId' + this.docxData.footer3RelId + '"/>';
funcThis.docxData.secPrExtra += '<w:headerReference w:type="even" r:id="rId' + this.docxData.header1RelId + '"/>';
funcThis.docxData.secPrExtra += '<w:footerReference w:type="even" r:id="rId' + this.docxData.footer1RelId + '"/>';
// Add the notes master to the list of files in the document:
this.filesList.push (
{
name: '/' + this.mainPath + '/footnotes.xml',
type: 'application/vnd.openxmlformats-officedocument.wordprocessingml.footnotes+xml',
clear: 'generate' // Placing 'generate' here means that officegen will destroy this entry in the files list after finishing to generate the document.
},
{
name: '/' + this.mainPath + '/endnotes.xml',
type: 'application/vnd.openxmlformats-officedocument.wordprocessingml.endnotes+xml',
clear: 'generate' // Placing 'generate' here means that officegen will destroy this entry in the files list after finishing to generate the document.
},
{
name: '/' + this.mainPath + '/footer1.xml',
type: 'application/vnd.openxmlformats-officedocument.wordprocessingml.footer+xml',
clear: 'generate' // Placing 'generate' here means that officegen will destroy this entry in the files list after finishing to generate the document.
},
{
name: '/' + this.mainPath + '/footer2.xml',
type: 'application/vnd.openxmlformats-officedocument.wordprocessingml.footer+xml',
clear: 'generate' // Placing 'generate' here means that officegen will destroy this entry in the files list after finishing to generate the document.
},
{
name: '/' + this.mainPath + '/footer3.xml',
type: 'application/vnd.openxmlformats-officedocument.wordprocessingml.footer+xml',
clear: 'generate' // Placing 'generate' here means that officegen will destroy this entry in the files list after finishing to generate the document.
},
{
name: '/' + this.mainPath + '/header1.xml',
type: 'application/vnd.openxmlformats-officedocument.wordprocessingml.header+xml',
clear: 'generate' // Placing 'generate' here means that officegen will destroy this entry in the files list after finishing to generate the document.
},
{
name: '/' + this.mainPath + '/header2.xml',
type: 'application/vnd.openxmlformats-officedocument.wordprocessingml.header+xml',
clear: 'generate' // Placing 'generate' here means that officegen will destroy this entry in the files list after finishing to generate the document.
},
{
name: '/' + this.mainPath + '/header3.xml',
type: 'application/vnd.openxmlformats-officedocument.wordprocessingml.header+xml',
clear: 'generate' // Placing 'generate' here means that officegen will destroy this entry in the files list after finishing to generate the document.
}
);
} // Endif.
}
//
// Resource generating callbacks:
//
/**
* Create the endnotes resource.
*
* @param {object} data Data needed to generate this resource.
* @return Text string.
*/
MakeHeadfootPlugin.prototype.cbEndNotes = function ( data ) {
return this.msPluginsApi.cbMakeMsOfficeBasicXml ( data ) + '<w:endnotes xmlns:ve="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:o="urn:schemas-microsoft-com:office:office" xmlns:r="http://schemas.openxmlformats.org/officeDocument/2006/relationships" xmlns:m="http://schemas.openxmlformats.org/officeDocument/2006/math" xmlns:v="urn:schemas-microsoft-com:vml" xmlns:wp="http://schemas.openxmlformats.org/drawingml/2006/wordprocessingDrawing" xmlns:w10="urn:schemas-microsoft-com:office:word" xmlns:w="http://schemas.openxmlformats.org/wordprocessingml/2006/main" xmlns:wne="http://schemas.microsoft.com/office/word/2006/wordml"><w:endnote w:type="separator" w:id="-1"><w:p w:rsidR="002E67D7" w:rsidRDefault="002E67D7" w:rsidP="009F2180"><w:pPr><w:spacing w:after="0" w:line="240" w:lineRule="auto"/></w:pPr><w:r><w:separator/></w:r></w:p></w:endnote><w:endnote w:type="continuationSeparator" w:id="0"><w:p w:rsidR="002E67D7" w:rsidRDefault="002E67D7" w:rsidP="009F2180"><w:pPr><w:spacing w:after="0" w:line="240" w:lineRule="auto"/></w:pPr><w:r><w:continuationSeparator/></w:r></w:p></w:endnote></w:endnotes>';
}
/**
* Create the footnotes resource.
*
* @param {object} data Data needed to generate this resource.
* @return Text string.
*/
MakeHeadfootPlugin.prototype.cbFootNotes = function ( data ) {
return this.msPluginsApi.cbMakeMsOfficeBasicXml ( data ) + '<w:footnotes xmlns:ve="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:o="urn:schemas-microsoft-com:office:office" xmlns:r="http://schemas.openxmlformats.org/officeDocument/2006/relationships" xmlns:m="http://schemas.openxmlformats.org/officeDocument/2006/math" xmlns:v="urn:schemas-microsoft-com:vml" xmlns:wp="http://schemas.openxmlformats.org/drawingml/2006/wordprocessingDrawing" xmlns:w10="urn:schemas-microsoft-com:office:word" xmlns:w="http://schemas.openxmlformats.org/wordprocessingml/2006/main" xmlns:wne="http://schemas.microsoft.com/office/word/2006/wordml"><w:footnote w:type="separator" w:id="-1"><w:p w:rsidR="002E67D7" w:rsidRDefault="002E67D7" w:rsidP="009F2180"><w:pPr><w:spacing w:after="0" w:line="240" w:lineRule="auto"/></w:pPr><w:r><w:separator/></w:r></w:p></w:footnote><w:footnote w:type="continuationSeparator" w:id="0"><w:p w:rsidR="002E67D7" w:rsidRDefault="002E67D7" w:rsidP="009F2180"><w:pPr><w:spacing w:after="0" w:line="240" w:lineRule="auto"/></w:pPr><w:r><w:continuationSeparator/></w:r></w:p></w:footnote></w:footnotes>';
}
module.exports = MakeHeadfootPlugin;