// // officegen: speaker notes support for pptx documents. // // Please refer to README.md for this module's documentations. // // Copyright (c) 2013 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. // /** * This function creating the pptx speaker notes plugin object. * @param {object} pluginsman Access to the plugins manager for pptx documents. * @constructor * @name MakeSpknotesPlugin */ function MakeSpknotesPlugin(pluginsman) { var funcThis = this if (pluginsman.docType !== 'pptx' && pluginsman.docType !== 'ppsx') { throw new Error( '[pptx-speakernotes] This plugin supporting only PowerPoint 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.pptxData = 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 slide object API: pluginsman.registerCallback('newPage', function(docData) { funcThis.extendPptxSlideApi(docData) }) // This event tell us that the generator is about to start working: pluginsman.registerCallback('beforeGen', function(docObj) { funcThis.beforeGen(docObj) }) // This event tell us to add our xml code to the main presentation file: pluginsman.registerCallback('presentationGen', function(docData) { funcThis.presentationGen(docData) }) return this } // // Events implementations: // /** * This function extending a new created slide object with new API methods. * @param {object} docData - Object with information about the new slide and more. */ MakeSpknotesPlugin.prototype.extendPptxSlideApi = function(docData) { var newSlide = docData.page // The new slide's API. var slideData = docData.pageData // Place here data related to the slide. /** * Set the speaker notes value. * @param {*} messageText - speaker note message. * @param {*} isAppend - is true to append the message as another line. */ newSlide.setSpeakerNote = function(messageText, isAppend) { if (!messageText) { slideData.speakerNoteMsg = [] } else if (typeof messageText === 'string') { if (isAppend) { if ( !slideData.speakerNoteMsg || typeof slideData.speakerNoteMsg !== 'object' ) { slideData.speakerNoteMsg = [] } else if (slideData.speakerNoteMsg.length) { slideData.speakerNoteMsg.push({ text: '\n' + messageText }) return } // Endif. slideData.speakerNoteMsg.push({ text: messageText }) } else { slideData.speakerNoteMsg = [{ text: messageText }] } // Endif. } else if (typeof messageText === 'object') { slideData.speakerNoteMsg = messageText } // Endif. } } /** * This function been called just before starting to generate the output document zip. * @param {object} docObj Document object. */ MakeSpknotesPlugin.prototype.beforeGen = function(docObj) { var funcThis = this var notesCount = 0 this.pluginsman.genPrivate.pages.forEach(function(value, indexId) { if ( value.speakerNoteMsg && typeof value.speakerNoteMsg === 'object' && value.speakerNoteMsg.length ) { // Add each speaker note: funcThis.ogPluginsApi.intAddAnyResourceToParse( funcThis.mainPath + '\\notesSlides\\notesSlide' + (notesCount + 1) + '.xml', 'buffer', { slide: value, slideNum: indexId + 1 }, function(data) { return funcThis.cbMakePptxSpkNote(data) }, false ) funcThis.ogPluginsApi.intAddAnyResourceToParse( funcThis.mainPath + '\\notesSlides\\_rels\\notesSlide' + (notesCount + 1) + '.xml.rels', 'buffer', [ { type: 'http://schemas.openxmlformats.org/officeDocument/2006/relationships/notesMaster', target: '../notesMasters/notesMaster1.xml' }, { type: 'http://schemas.openxmlformats.org/officeDocument/2006/relationships/slide', target: '../slides/slide' + (indexId + 1) + '.xml' } ], funcThis.pluginsman.genPrivate.plugs.type.msoffice.cbMakeRels, false ) // We'll connect the slide to this note: value.rels.push({ type: 'http://schemas.openxmlformats.org/officeDocument/2006/relationships/notesSlide', target: '../notesSlides/notesSlide' + (notesCount + 1) + '.xml' }) // Add this speaker note to the list of files in the document: funcThis.filesList.push({ name: '/' + funcThis.mainPath + '/notesSlides/notesSlide' + (notesCount + 1) + '.xml', type: 'application/vnd.openxmlformats-officedocument.presentationml.notesSlide+xml', clear: 'generate' // Placing 'generate' here means that officegen will destroy this entry in the files list after finishing to generate the document. }) notesCount++ } // Endif. }) this.pptxData.haveNotes = notesCount if (notesCount) { // Speaker notes - master: this.ogPluginsApi.intAddAnyResourceToParse( this.mainPath + '\\notesMasters\\notesMaster1.xml', 'buffer', null, function(data) { return funcThis.cbMakePptxNotesMasters(data) }, false ) this.ogPluginsApi.intAddAnyResourceToParse( this.mainPath + '\\notesMasters\\_rels\\notesMaster1.xml.rels', 'buffer', [ { type: 'http://schemas.openxmlformats.org/officeDocument/2006/relationships/theme', target: '../theme/theme2.xml' } ], this.pluginsman.genPrivate.plugs.type.msoffice.cbMakeRels, false ) // Add a rel entry to the main pptx rels: this.relsApp.push( { target: 'notesMasters/notesMaster1.xml', type: 'http://schemas.openxmlformats.org/officeDocument/2006/relationships/notesMaster', clear: 'generate' // Placing 'generate' here means that officegen will destroy this entry in the files list after finishing to generate the document. }, { type: 'http://schemas.openxmlformats.org/officeDocument/2006/relationships/theme', target: 'theme/theme2.xml', clear: 'generate' } ) funcThis.ogPluginsApi.intAddAnyResourceToParse( funcThis.mainPath + '\\theme\\theme2.xml', 'buffer', null, function(data) { return funcThis.cbMakeTheme2(data) }, false ) // Add the notes master to the list of files in the document: this.filesList.push( { name: '/' + this.mainPath + '/notesMasters/notesMaster1.xml', type: 'application/vnd.openxmlformats-officedocument.presentationml.notesMaster+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 + '/theme/theme2.xml', type: 'application/vnd.openxmlformats-officedocument.theme+xml', clear: 'generate' // Placing 'generate' here means that officegen will destroy this entry in the files list after finishing to generate the document. } ) } // Endif. } /** * This function been called to add extra xml code to the main presentation xml file. * @param {object} docData Document object. */ MakeSpknotesPlugin.prototype.presentationGen = function(docData) { // Check if we have speaker notes: if (this.pptxData.haveNotes) { docData.data += '' } // Endif. } // // Resource generating callbacks: // /** * Generate the 2nd theme, needed to support speaker notes. * * @param {object} data Ignored by this callback function. * @return Text string. */ MakeSpknotesPlugin.prototype.cbMakeTheme2 = function(data) { return ( this.msPluginsApi.cbMakeMsOfficeBasicXml(data) + '' ) } /** * Generate the speaker notes master. * * @param {object} data Data needed to generate this resource. * @return Text string. */ MakeSpknotesPlugin.prototype.cbMakePptxNotesMasters = function(data) { return ( this.msPluginsApi.cbMakeMsOfficeBasicXml(data) + '2/3/2017Click to edit Master text stylesSecond levelThird levelFourth levelFifth level‹#›' ) } /** * Generate a speaker note for a slide. * * @param {object} data Data needed to generate this resource. * @return Text string. */ MakeSpknotesPlugin.prototype.cbMakePptxSpkNote = function(data) { var dataOut = this.msPluginsApi.cbMakeMsOfficeBasicXml(data) + '' // Generate the speaker note lines for this slide: dataOut += this.pluginsman.genobj.cMakePptxOutTextP( '', data.slide.speakerNoteMsg, {}, data.slide.slide ) dataOut += '' + data.slideNum + '' return dataOut } module.exports = MakeSpknotesPlugin