//
// 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