def __renderIcons(self, style): """ Return xhtml string for dispay all icons """ iconpath = Path(G.application.config.stylesDir / style) iconfiles = iconpath.files("icon_*") html = '<div id="styleIcons"><div style="height:300px;overflow:auto">' for iconfile in iconfiles: iconname = iconfile.namebase icon = iconname.split("_", 1)[1] iconExists = False iconExtension = "gif" myIcon = Path(G.application.config.stylesDir / style / iconname + ".gif") if myIcon.exists(): iconExists = True iconValue = icon + '.' + iconExtension iconSrc = '/style/%s/icon_%s' % (style, iconValue) else: myIcon = Path(G.application.config.stylesDir / style / iconname + ".png") if myIcon.exists(): iconExists = True iconExtension = "png" iconValue = icon + '.' + iconExtension iconSrc = '/style/%s/icon_%s' % (style, iconValue) else: myIcon = Path(G.application.config.stylesDir / style / iconname + ".svg") if myIcon.exists(): iconExists = True iconExtension = "svg" iconValue = icon + '.' + iconExtension iconSrc = '/style/%s/icon_%s' % (style, iconValue) if iconExists: filename = "/style/%s/%s.%s" % (style, iconname, iconExtension) html += u'<div style="float:left; text-align:center; width:105px;\n' html += u'margin-right:10px; margin-bottom:15px" > ' html += u'<img src="%s" \n' % filename html += u"style=\"border:1px solid #E8E8E8;padding:5px;cursor:pointer;max-width:60px;height:auto\" onclick=\"window[0].selectStyleIcon('%s',this, '%s', '%s')\" title=\"%s.%s\">\n" % ( icon, iconSrc, self.id, icon, iconExtension) html += u'<br /><span style="display:inline-block;width:100px;overflow:hidden;text-overflow:ellipsis">%s.%s</span></div>\n' % ( icon, iconExtension) html += '</div></div>' return html
def __renderIcons(self): """ Return xhtml string for dispay all icons """ iconpath = Path(self.webDir).joinpath("style", self.style) iconfiles = iconpath.files("icon_*") html = "" for iconfile in iconfiles: iconname = iconfile.namebase icon = iconname.split("_", 1)[1] filename = "/style/%s/%s.gif" % (self.style, iconname) html += u'<div style="float:left; text-align:center; width:80px;\n' html += u'margin-right:10px; margin-bottom:10px" > ' html += u'<img src="%s" \n' % filename html += u' alt="%s" ' % _("Submit") html += u"onclick=\"submitLink('selectIcon','%s',1)\">\n" % icon html += u'<br/>%s.gif</div>\n' % icon return html
def __renderIcons(self, style): """ Return xhtml string for dispay all icons """ iconpath = Path(G.application.config.stylesDir/style) iconfiles = iconpath.files("icon_*") html = '<div id="styleIcons"><div style="height:300px;overflow:auto">' for iconfile in iconfiles: iconname = iconfile.namebase icon = iconname.split("_", 1)[1] iconExists = False iconExtension = "gif" myIcon = Path(G.application.config.stylesDir/style/iconname + ".gif") if myIcon.exists(): iconExists = True iconValue = icon+'.'+iconExtension iconSrc = '/style/%s/icon_%s' % (style, iconValue) else: myIcon = Path(G.application.config.stylesDir/style/iconname + ".png") if myIcon.exists(): iconExists = True iconExtension = "png" iconValue = icon+'.'+iconExtension iconSrc = '/style/%s/icon_%s' % (style, iconValue) if iconExists: filename = "/style/%s/%s.%s" % (style, iconname, iconExtension) html += u'<div style="float:left; text-align:center; width:105px;\n' html += u'margin-right:10px; margin-bottom:15px" > ' html += u'<img src="%s" \n' % filename html += u"style=\"border:1px solid #E8E8E8;padding:5px;cursor:pointer;max-width:60px;height:auto\" onclick=\"window[0].selectStyleIcon('%s',this, '%s', '%s')\" title=\"%s.%s\">\n" % (icon, iconSrc, self.id, icon ,iconExtension) html += u'<br /><span style="display:inline-block;width:100px;overflow:hidden;text-overflow:ellipsis">%s.%s</span></div>\n' % (icon, iconExtension) html += '</div></div>' return html
class ScormExport(object): """ Exports an eXe package as a SCORM package """ def __init__(self, config, styleDir, filename, scormType): """ Initialize 'styleDir' is the directory from which we will copy our style sheets (and some gifs) """ self.config = config self.imagesDir = config.webDir / "images" self.scriptsDir = config.webDir / "scripts" self.templatesDir = config.webDir / "templates" self.schemasDir = config.webDir / "schemas" self.styleDir = Path(styleDir) self.filename = Path(filename) self.pages = [] self.hasForum = False self.scormType = scormType def export(self, package): """ Export SCORM package """ # First do the export to a temporary directory outputDir = TempDirPath() # Export the package content self.pages = [ ScormPage("index", 1, package.root, scormType=self.scormType) ] self.generatePages(package.root, 2) uniquifyNames(self.pages) for page in self.pages: page.save(outputDir) if not self.hasForum: for idevice in page.node.idevices: if hasattr(idevice, "isForum"): if idevice.forum.lms.lms == "moodle": self.hasForum = True break # Create the manifest file manifest = Manifest(self.config, outputDir, package, self.pages, self.scormType) manifest.save("imsmanifest.xml") if self.hasForum: manifest.save("discussionforum.xml") # Copy the style sheet files to the output dir # But not nav.css styleFiles = [self.styleDir / '..' / 'base.css'] styleFiles += [self.styleDir / '..' / 'popup_bg.gif'] styleFiles += [ f for f in self.styleDir.files("*.css") if f.basename() <> "nav.css" ] styleFiles += self.styleDir.files("*.jpg") styleFiles += self.styleDir.files("*.gif") styleFiles += self.styleDir.files("*.png") styleFiles += self.styleDir.files("*.js") styleFiles += self.styleDir.files("*.html") # FIXME for now, only copy files referenced in Common Cartridge # this really should apply to all exports, but without a manifest # of the files needed by an included stylesheet it is too restrictive if self.scormType == "commoncartridge": for sf in styleFiles[:]: if sf.basename() not in manifest.dependencies: styleFiles.remove(sf) self.styleDir.copylist(styleFiles, outputDir) # copy the package's resource files package.resourceDir.copyfiles(outputDir) # Copy the scripts if self.scormType == "commoncartridge": self.scriptsDir.copylist(('libot_drag.js', 'common.js'), outputDir) else: self.scriptsDir.copylist(('APIWrapper.js', 'SCOFunctions.js', 'libot_drag.js', 'common.js'), outputDir) schemasDir = "" if self.scormType == "scorm1.2": schemasDir = self.schemasDir / "scorm1.2" schemasDir.copylist( ('imscp_rootv1p1p2.xsd', 'imsmd_rootv1p2p1.xsd', 'adlcp_rootv1p2.xsd', 'ims_xml.xsd'), outputDir) elif self.scormType == "scorm2004": schemasDir = self.schemasDir / "scorm2004" schemasDir.copylist( ('imscp_rootv1p1p2.xsd', 'imsmd_rootv1p2p1.xsd', 'adlcp_rootv1p2.xsd', 'ims_xml.xsd'), outputDir) # copy players for media idevices. hasFlowplayer = False hasMagnifier = False hasXspfplayer = False isBreak = False for page in self.pages: if isBreak: break for idevice in page.node.idevices: if (hasFlowplayer and hasMagnifier and hasXspfplayer): isBreak = True break if not hasFlowplayer: if 'flowPlayer.swf' in idevice.systemResources: hasFlowplayer = True if not hasMagnifier: if 'magnifier.swf' in idevice.systemResources: hasMagnifier = True if not hasXspfplayer: if 'xspf_player.swf' in idevice.systemResources: hasXspfplayer = True if hasFlowplayer: videofile = (self.templatesDir / 'flowPlayer.swf') videofile.copyfile(outputDir / 'flowPlayer.swf') if hasMagnifier: videofile = (self.templatesDir / 'magnifier.swf') videofile.copyfile(outputDir / 'magnifier.swf') if hasXspfplayer: videofile = (self.templatesDir / 'xspf_player.swf') videofile.copyfile(outputDir / 'xspf_player.swf') if self.scormType == "scorm1.2" or self.scormType == "scorm2004": if package.license == "GNU Free Documentation License": # include a copy of the GNU Free Documentation Licence (self.templatesDir / 'fdl.html').copyfile(outputDir / 'fdl.html') # Zip it up! self.filename.safeSave( self.doZip, _('EXPORT FAILED!\nLast succesful export is %s.'), outputDir) # Clean up the temporary dir outputDir.rmtree() def doZip(self, fileObj, outputDir): """ Actually does the zipping of the file. Called by 'Path.safeSave' """ # Zip up the scorm package zipped = ZipFile(fileObj, "w") for scormFile in outputDir.files(): zipped.write(scormFile, scormFile.basename().encode('utf8'), ZIP_DEFLATED) zipped.close() def generatePages(self, node, depth): """ Recursive function for exporting a node. 'node' is the node that we are making a page for 'depth' is the number of ancestors that the page has +1 (ie. root is 1) """ for child in node.children: pageName = child.titleShort.lower().replace(" ", "_") pageName = re.sub(r"\W", "", pageName) if not pageName: pageName = "__" page = ScormPage(pageName, depth, child, scormType=self.scormType) self.pages.append(page) self.generatePages(child, depth + 1)
class SinglePageExport(object): """ SinglePageExport will export a package as a website of HTML pages """ def __init__(self, stylesDir, outputDir, imagesDir, scriptsDir, cssDir, templatesDir): """ 'stylesDir' is the directory where we can copy the stylesheets from 'outputDir' is the directory that will be [over]written with the website """ self.html = "" self.style = None self.name = None self.stylesDir = Path(stylesDir) self.outputDir = Path(outputDir) self.imagesDir = Path(imagesDir) self.scriptsDir = Path(scriptsDir) self.cssDir = Path(cssDir) self.templatesDir = Path(templatesDir) self.page = None # Create the output dir if it doesn't already exist if not self.outputDir.exists(): self.outputDir.mkdir() def export(self, package, for_print=0): """ Export web site Cleans up the previous packages pages and performs the export """ self.style = package.style self.page = SinglePage("index", 1, package.root) ext = 'html' if G.application.config.cutFileName == "1": ext = 'htm' self.page.save(self.outputDir / "index" + '.' + ext, for_print) if hasattr(package, 'exportSource') and package.exportSource and not for_print: (G.application.config.webDir / 'templates' / 'content.xsd').copyfile(self.outputDir / 'content.xsd') (self.outputDir / 'content.data').write_bytes( encodeObject(package)) (self.outputDir / 'contentv3.xml').write_bytes( encodeObjectToXML(package)) self.copyFiles(package) def copyFiles(self, package): """ Copy all the files used by the website. """ # Copy the style files to the output dir # But not nav.css if os.path.isdir(self.stylesDir): styleFiles = [self.stylesDir / '..' / 'popup_bg.gif'] styleFiles += self.stylesDir.files("*.*") if "nav.css" in styleFiles: styleFiles.remove("nav.css") self.stylesDir.copylist(styleFiles, self.outputDir) # copy the package's resource files package.resourceDir.copyfiles(self.outputDir) listCSSFiles = getFilesCSSToMinify('singlepage', self.stylesDir) exportMinFileCSS(listCSSFiles, self.outputDir) # copy script files. my_style = G.application.config.styleStore.getStyle(package.style) # jQuery if my_style.hasValidConfig: if my_style.get_jquery() == True: jsFile = (self.scriptsDir / 'exe_jquery.js') jsFile.copyfile(self.outputDir / 'exe_jquery.js') else: jsFile = (self.scriptsDir / 'exe_jquery.js') jsFile.copyfile(self.outputDir / 'exe_jquery.js') dT = common.getExportDocType() if dT == "HTML5": jsFile = (self.scriptsDir / 'exe_html5.js') jsFile.copyfile(self.outputDir / 'exe_html5.js') # Minify common.js file listFiles = getFilesJSToMinify('singlepage', self.scriptsDir) exportMinFileJS(listFiles, self.outputDir) # Incluide eXe's icon if the Style doesn't have one themePath = Path(G.application.config.stylesDir / package.style) themeFavicon = themePath.joinpath("favicon.ico") if not themeFavicon.exists(): faviconFile = (self.imagesDir / 'favicon.ico') faviconFile.copyfile(self.outputDir / 'favicon.ico') #JR Metemos los reproductores necesarios self.compruebaReproductores(self.page.node) if package.license == "license GFDL": # include a copy of the GNU Free Documentation Licence ext = 'html' if G.application.config.cutFileName == "1": ext = 'htm' (self.templatesDir / 'fdl' + '.' + ext).copyfile(self.outputDir / 'fdl' + '.' + ext) def compruebaReproductores(self, node): """ Comprobamos si hay que meter algun reproductor """ # copy players for media idevices. hasFlowplayer = False hasMagnifier = False hasXspfplayer = False hasGallery = False hasFX = False hasSH = False hasGames = False hasWikipedia = False hasInstructions = False hasMediaelement = False hasTooltips = False hasABCMusic = False for idevice in node.idevices: if (hasFlowplayer and hasMagnifier and hasXspfplayer and hasGallery and hasFX and hasSH and hasGames and hasWikipedia and hasInstructions and hasMediaelement and hasTooltips and hasABCMusic): break if not hasFlowplayer: if 'flowPlayer.swf' in idevice.systemResources: hasFlowplayer = True if not hasMagnifier: if 'mojomagnify.js' in idevice.systemResources: hasMagnifier = True if not hasXspfplayer: if 'xspf_player.swf' in idevice.systemResources: hasXspfplayer = True if not hasGallery: hasGallery = common.ideviceHasGallery(idevice) if not hasFX: hasFX = common.ideviceHasFX(idevice) if not hasSH: hasSH = common.ideviceHasSH(idevice) if not hasGames: hasGames = common.ideviceHasGames(idevice) if not hasWikipedia: if 'WikipediaIdevice' == idevice.klass: hasWikipedia = True if not hasInstructions: if 'TrueFalseIdevice' == idevice.klass or 'MultichoiceIdevice' == idevice.klass or 'VerdaderofalsofpdIdevice' == idevice.klass or 'EleccionmultiplefpdIdevice' == idevice.klass: hasInstructions = True if not hasMediaelement: hasMediaelement = common.ideviceHasMediaelement(idevice) if not hasTooltips: hasTooltips = common.ideviceHasTooltips(idevice) if not hasABCMusic: hasABCMusic = common.ideviceHasABCMusic(idevice) if hasFlowplayer: videofile = (self.templatesDir / 'flowPlayer.swf') videofile.copyfile(self.outputDir / 'flowPlayer.swf') controlsfile = (self.templatesDir / 'flowplayer.controls.swf') controlsfile.copyfile(self.outputDir / 'flowplayer.controls.swf') if hasMagnifier: videofile = (self.templatesDir / 'mojomagnify.js') videofile.copyfile(self.outputDir / 'mojomagnify.js') if hasXspfplayer: videofile = (self.templatesDir / 'xspf_player.swf') videofile.copyfile(self.outputDir / 'xspf_player.swf') if hasGallery: exeLightbox = (self.scriptsDir / 'exe_lightbox') exeLightbox.copyfiles(self.outputDir) if hasFX: exeEffects = (self.scriptsDir / 'exe_effects') exeEffects.copyfiles(self.outputDir) if hasSH: exeSH = (self.scriptsDir / 'exe_highlighter') exeSH.copyfiles(self.outputDir) if hasGames: exeGames = (self.scriptsDir / 'exe_games') exeGames.copyfiles(self.outputDir) if hasWikipedia: wikipediaCSS = (self.cssDir / 'exe_wikipedia.css') wikipediaCSS.copyfile(self.outputDir / 'exe_wikipedia.css') if hasInstructions: common.copyFileIfNotInStyle('panel-amusements.png', self, self.outputDir) common.copyFileIfNotInStyle('stock-stop.png', self, self.outputDir) if hasMediaelement: mediaelement = (self.scriptsDir / 'mediaelement') mediaelement.copyfiles(self.outputDir) dT = common.getExportDocType() if dT != "HTML5": jsFile = (self.scriptsDir / 'exe_html5.js') jsFile.copyfile(self.outputDir / 'exe_html5.js') if hasTooltips: exe_tooltips = (self.scriptsDir / 'exe_tooltips') exe_tooltips.copyfiles(self.outputDir) if hasABCMusic: pluginScripts = (self.scriptsDir / 'tinymce_4/js/tinymce/plugins/abcmusic/export') pluginScripts.copyfiles(self.outputDir) for child in node.children: self.compruebaReproductores(child) def hasUncutResources(self): """ Check if any of the resources in the exported package has an uncut filename """ for idevice in self.page.node.idevices: for resource in idevice.userResources: if type(resource) == Resource and len( resource.storageName) > 12: return True return False
class IMSExport(object): """ Exports an eXe package as a SCORM package """ def __init__(self, config, styleDir, filename): """ Initialize 'styleDir' is the directory from which we will copy our style sheets (and some gifs) """ self.config = config self.imagesDir = config.webDir/"images" self.scriptsDir = config.webDir/"scripts" self.cssDir = config.webDir/"css" self.templatesDir = config.webDir/"templates" self.schemasDir = config.webDir/"schemas/ims" self.styleDir = Path(styleDir) self.filename = Path(filename) self.pages = [] def export(self, package): """ Export SCORM package """ # First do the export to a temporary directory outputDir = TempDirPath() self.metadataType = package.exportMetadataType # Copy the style files to the output dir # But not nav.css styleFiles = [self.styleDir/'..'/'popup_bg.gif'] styleFiles += self.styleDir.files("*.*") if "nav.css" in styleFiles: styleFiles.remove("nav.css") self.styleDir.copylist(styleFiles, outputDir) # copy the package's resource files for resourceFile in package.resourceDir.walkfiles(): file = package.resourceDir.relpathto(resourceFile) if ("/" in file): Dir = Path(outputDir/file[:file.rindex("/")]) if not Dir.exists(): Dir.makedirs() resourceFile.copy(outputDir/Dir) else: resourceFile.copy(outputDir) listCSSFiles=getFilesCSSToMinify('ims', self.styleDir) exportMinFileCSS(listCSSFiles, outputDir) # Export the package content self.pages = [ IMSPage("index", 1, package.root, metadataType=self.metadataType) ] self.generatePages(package.root, 2) uniquifyNames(self.pages) for page in self.pages: page.save(outputDir, self.pages) # Create the manifest file manifest = Manifest(self.config, outputDir, package, self.pages, self.metadataType) manifest.save("imsmanifest.xml") # Create lang file langGameFile = open(outputDir + '/common_i18n.js', "w") langGameFile.write(common.getJavaScriptStrings(False)) langGameFile.close() # jQuery my_style = G.application.config.styleStore.getStyle(page.node.package.style) if my_style.hasValidConfig(): if my_style.get_jquery() == True: jsFile = (self.scriptsDir/'exe_jquery.js') jsFile.copyfile(outputDir/'exe_jquery.js') else: jsFile = (self.scriptsDir/'exe_jquery.js') jsFile.copyfile(outputDir/'exe_jquery.js') dT = common.getExportDocType() if dT == "HTML5": jsFile = (self.scriptsDir/'exe_html5.js') jsFile.copyfile(outputDir/'exe_html5.js') listFiles=getFilesJSToMinify('ims', self.scriptsDir) exportMinFileJS(listFiles, outputDir) self.schemasDir.copylist(('imscp_v1p1.xsd', 'imsmd_v1p2p2.xsd', 'lom.xsd', 'lomCustom.xsd', 'ims_xml.xsd'), outputDir) # copy players for media idevices. hasFlowplayer = False hasMagnifier = False hasXspfplayer = False hasGallery = False hasFX = False hasSH = False hasGames = False hasElpLink = False hasWikipedia = False isBreak = False hasInstructions = False hasMediaelement = False hasTooltips = False hasABCMusic = False listIdevicesFiles = [] for page in self.pages: if isBreak: break for idevice in page.node.idevices: if (hasFlowplayer and hasMagnifier and hasXspfplayer and hasGallery and hasFX and hasSH and hasGames and hasElpLink and hasWikipedia and hasInstructions and hasMediaelement and hasTooltips and hasABCMusic): isBreak = True break if not hasFlowplayer: if 'flowPlayer.swf' in idevice.systemResources: hasFlowplayer = True if not hasMagnifier: if 'mojomagnify.js' in idevice.systemResources: hasMagnifier = True if not hasXspfplayer: if 'xspf_player.swf' in idevice.systemResources: hasXspfplayer = True if not hasGallery: hasGallery = common.ideviceHasGallery(idevice) if not hasFX: hasFX = common.ideviceHasFX(idevice) if not hasSH: hasSH = common.ideviceHasSH(idevice) if not hasGames: hasGames = common.ideviceHasGames(idevice) if not hasElpLink: hasElpLink = common.ideviceHasElpLink(idevice,package) if not hasWikipedia: if 'WikipediaIdevice' == idevice.klass: hasWikipedia = True if not hasInstructions: if 'TrueFalseIdevice' == idevice.klass or 'MultichoiceIdevice' == idevice.klass or 'VerdaderofalsofpdIdevice' == idevice.klass or 'EleccionmultiplefpdIdevice' == idevice.klass: hasInstructions = True if not hasMediaelement: hasMediaelement = common.ideviceHasMediaelement(idevice) if not hasTooltips: hasTooltips = common.ideviceHasTooltips(idevice) if not hasABCMusic: hasABCMusic = common.ideviceHasABCMusic(idevice) if hasattr(idevice, "_iDeviceDir"): listIdevicesFiles.append((idevice.get_jsidevice_dir()/'export')) common.exportJavaScriptIdevicesFiles(page.node.idevices, outputDir); if hasFlowplayer: videofile = (self.templatesDir/'flowPlayer.swf') videofile.copyfile(outputDir/'flowPlayer.swf') controlsfile = (self.templatesDir/'flowplayer.controls.swf') controlsfile.copyfile(outputDir/'flowplayer.controls.swf') if hasMagnifier: videofile = (self.templatesDir/'mojomagnify.js') videofile.copyfile(outputDir/'mojomagnify.js') if hasXspfplayer: videofile = (self.templatesDir/'xspf_player.swf') videofile.copyfile(outputDir/'xspf_player.swf') if hasGallery: exeLightbox = (self.scriptsDir/'exe_lightbox') exeLightbox.copyfiles(outputDir) if hasFX: exeEffects = (self.scriptsDir/'exe_effects') exeEffects.copyfiles(outputDir) if hasSH: exeSH = (self.scriptsDir/'exe_highlighter') exeSH.copyfiles(outputDir) if hasGames: exeGames = (self.scriptsDir/'exe_games') exeGames.copyfiles(outputDir) # Add game js string to common_i18n langGameFile = open(outputDir + '/common_i18n.js', "a") langGameFile.write(common.getGamesJavaScriptStrings(False)) langGameFile.close() if hasElpLink or package.get_exportElp(): # Export the elp file currentPackagePath = Path(package.filename) currentPackagePath.copyfile(outputDir/package.name+'.elp') if hasWikipedia: wikipediaCSS = (self.cssDir/'exe_wikipedia.css') wikipediaCSS.copyfile(outputDir/'exe_wikipedia.css') if hasInstructions: common.copyFileIfNotInStyle('panel-amusements.png', self, outputDir) common.copyFileIfNotInStyle('stock-stop.png', self, outputDir) if hasMediaelement: mediaelement = (self.scriptsDir/'mediaelement') mediaelement.copyfiles(outputDir) if dT != "HTML5": jsFile = (self.scriptsDir/'exe_html5.js') jsFile.copyfile(outputDir/'exe_html5.js') if hasTooltips: exe_tooltips = (self.scriptsDir/'exe_tooltips') exe_tooltips.copyfiles(outputDir) if hasABCMusic: pluginScripts = (self.scriptsDir/'tinymce_4/js/tinymce/plugins/abcmusic/export') pluginScripts.copyfiles(outputDir) if hasattr(package, 'exportSource') and package.exportSource: (G.application.config.webDir/'templates'/'content.xsd').copyfile(outputDir/'content.xsd') (outputDir/'content.data').write_bytes(encodeObject(package)) (outputDir/'contentv3.xml').write_bytes(encodeObjectToXML(package)) if package.license == "license GFDL": # include a copy of the GNU Free Documentation Licence (self.templatesDir/'fdl.html').copyfile(outputDir/'fdl.html') # Zip it up! self.filename.safeSave(self.doZip, _('EXPORT FAILED!\nLast succesful export is %s.'), outputDir) # Clean up the temporary dir outputDir.rmtree() def doZip(self, fileObj, outputDir): """ Actually does the zipping of the file. Called by 'Path.safeSave' """ zipped = ZipFile(fileObj, "w") for scormFile in outputDir.walkfiles(): zipped.write(scormFile, outputDir.relpathto(scormFile), ZIP_DEFLATED) zipped.close() def generatePages(self, node, depth): """ Recursive function for exporting a node. 'outputDir' is the temporary directory that we are exporting to before creating zip file """ for child in node.children: pageName = child.titleShort.lower().replace(" ", "_") pageName = re.sub(r"\W", "", pageName) if G.application.config.cutFileName == "1": pageName = pageName[0:8] if not pageName: pageName = "__" page = IMSPage(pageName, depth, child, metadataType=self.metadataType) self.pages.append(page) self.generatePages(child, depth + 1) def hasUncutResources(self): """ Check if any of the resources in the exported package has an uncut filename """ for page in self.pages: for idevice in page.node.idevices: for resource in idevice.userResources: if type(resource) == Resource and len(resource.storageName) > 12: return True return False
class SinglePageExport(object): """ SinglePageExport will export a package as a website of HTML pages """ def __init__(self, stylesDir, outputDir, imagesDir, scriptsDir, templatesDir): """ 'stylesDir' is the directory where we can copy the stylesheets from 'outputDir' is the directory that will be [over]written with the website """ self.html = "" self.style = None self.name = None self.stylesDir = Path(stylesDir) self.outputDir = Path(outputDir) self.imagesDir = Path(imagesDir) self.scriptsDir = Path(scriptsDir) self.templatesDir = Path(templatesDir) self.page = None # Create the output dir if it doesn't already exist if not self.outputDir.exists(): self.outputDir.mkdir() def export(self, package, for_print=0): """ Export web site Cleans up the previous packages pages and performs the export """ self.style = package.style self.page = SinglePage("index", 1, package.root) self.page.save(self.outputDir/"index.html", for_print) self.copyFiles(package) def copyFiles(self, package): """ Copy all the files used by the website. """ # Copy the style sheet files to the output dir # But not nav.css styleFiles = [self.stylesDir/'..'/'base.css'] styleFiles += [self.stylesDir/'..'/'popup_bg.gif'] styleFiles += self.stylesDir.files("*.css") if "nav.css" in styleFiles: styleFiles.remove("nav.css") styleFiles += self.stylesDir.files("*.jpg") styleFiles += self.stylesDir.files("*.gif") styleFiles += self.stylesDir.files("*.png") styleFiles += self.stylesDir.files("*.js") styleFiles += self.stylesDir.files("*.html") self.stylesDir.copylist(styleFiles, self.outputDir) # copy the package's resource files package.resourceDir.copyfiles(self.outputDir) # copy script files. self.scriptsDir.copylist(('libot_drag.js', 'common.js'), self.outputDir) # copy players for media idevices. hasFlowplayer = False hasMagnifier = False hasXspfplayer = False for idevice in self.page.node.idevices: if (hasFlowplayer and hasMagnifier and hasXspfplayer): break if not hasFlowplayer: if 'flowPlayer.swf' in idevice.systemResources: hasFlowplayer = True if not hasMagnifier: if 'magnifier.swf' in idevice.systemResources: hasMagnifier = True if not hasXspfplayer: if 'xspf_player.swf' in idevice.systemResources: hasXspfplayer = True if hasFlowplayer: videofile = (self.templatesDir/'flowPlayer.swf') videofile.copyfile(self.outputDir/'flowPlayer.swf') if hasMagnifier: videofile = (self.templatesDir/'magnifier.swf') videofile.copyfile(self.outputDir/'magnifier.swf') if hasXspfplayer: videofile = (self.templatesDir/'xspf_player.swf') videofile.copyfile(self.outputDir/'xspf_player.swf') if package.license == "GNU Free Documentation License": # include a copy of the GNU Free Documentation Licence (self.templatesDir/'fdl.html').copyfile(self.outputDir/'fdl.html')
class HandoutExport(object): """ This class transform a exe-package to a DOMPresenatation """ def __init__(self, config, styleDir, filename): """ 'stylesDir' is the directory where we can copy the stylesheets from 'outputDir' is the directory that will be [over]written with the website """ self.config = config self.imagesDir = config.webDir/"images" self.scriptsDir = config.webDir/"scripts" self.templatesDir = config.webDir/"templates" self.stylesDir = Path(styleDir) self.filename = Path(filename) self.pages = [] def export(self, package): """ exports package to a dom presentation """ outputDir = self.filename if not outputDir.exists(): outputDir.mkdir() self.pages = [ HandoutPage("Index", 1, package.root) ] self.generatePages(package.root, 1) log.debug(map(lambda x : getattr(x, "name"), self.pages)) html = u'''<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd"> <html dir="ltr" lang="en"> <head> <meta http-equiv="Content-Type" content="text/html; charset=utf-8"> <title>%s</title> <style type="text/css" media="screen"> @import url(base.css); @import url(content.css); </style> <script type="text/javascript"> function print_page() { window.print(); window.close(); } </script> </head> <body onload=print_page()> <div id="boundary"> <h1 align="center">%s</h1> ''' % (package.name, package.name) for page in self.pages: slidehtml = page.render() if slidehtml != "": html += u'<div class="page">' html += u'<p id="nodeTitle">%s</p>' % escape(page.node.titleLong) html += slidehtml html += u'</div>' log.debug(type(html)) html = html.encode("utf8") log.debug(type(html)) log.debug(html) output = open(outputDir / "index.html", "w") output.write(html) output.close() self.copyFiles(package, outputDir) def copyFiles(self, package, outputDir): """ Copy all the files used by the website. """ print outputDir # Copy the style sheet files to the output dir styleFiles = [self.stylesDir/'..'/'base.css'] styleFiles += [self.stylesDir/'..'/'ds_styles.css'] styleFiles += [self.stylesDir/'..'/'popup_bg.gif'] styleFiles += self.stylesDir.files("*.css") styleFiles += self.stylesDir.files("*.jpg") styleFiles += self.stylesDir.files("*.gif") styleFiles += self.stylesDir.files("*.png") styleFiles += self.stylesDir.files("*.js") styleFiles += self.stylesDir.files("*.html") self.stylesDir.copylist(styleFiles, outputDir) # copy the package's resource files package.resourceDir.copyfiles(outputDir) def generatePages(self, node, depth): """ recursively generates pages """ for child in node.children: title = child.titleShort if not title: title = "__" self.pages.append(HandoutPage(title, depth, child)) self.generatePages(child, depth + 1)
class WebsiteExport(object): """ WebsiteExport will export a package as a website of HTML pages """ def __init__(self, config, styleDir, filename, prefix="", report=False): """ 'stylesDir' is the directory where we can copy the stylesheets from 'outputDir' is the directory that will be [over]written with the website """ self.config = config self.imagesDir = config.webDir / "images" self.scriptsDir = config.webDir / "scripts" self.cssDir = config.webDir / "css" self.templatesDir = config.webDir / "templates" self.stylesDir = Path(styleDir) self.filename = Path(filename) self.pages = [] self.prefix = prefix self.report = report self.styleSecureMode = config.styleSecureMode def gDriveNotificationStatus(self, client, mesg): client.sendScript( "eXe.controller.eXeViewport.prototype.gDriveNotificationStatus('%s');" % (mesg), filter_func=allSessionClients) def gDriveNotificationNotice(self, client, mesg, type): client.sendScript( "eXe.controller.eXeViewport.prototype.gDriveNotificationNotice('%s', '%s');" % (mesg, type), filter_func=allSessionClients) # def exportGoogleDrive(self, package, client, auth_token, user_agent): # """ # Creates an authorized HTTP conexion, exports the current package as # 'webSite' to a temporary directory and uploads the exported files to # Google Drive # """ # num_total = 0; # file_num = 0; # # def finishExport(public_folder, outputDir): # self.gDriveNotificationStatus(client, _(u'Deleting temporary directory')) # rmtree(outputDir) # # link_url = 'http://googledrive.com/host/%s'%(public_folder['id']) # link_text = public_folder['title'] # self.gDriveNotificationStatus(client, _(u'Package exported to <a href="%s" target="_blank" title="Click to visit exported site">%s</a>') %(link_url,link_text)) # return public_folder # # def insertFile(public_folder, drive, upload_file, file_num): # """ # Creates the deferred that will upload files to the public folder # once it is created # """ # upload_content_d = threads.deferToThread(uploadContent, public_folder, drive, upload_file, file_num) # upload_content_d.addCallbacks(uploadContent_onSuccess, uploadContent_onFail) # # return upload_content_d # # def uploadContent(public_folder, drive, upload_file, file_num): # """ # Uploads one file to the given GDrive folder # """ # try : # filepath = os.path.join(self.filename, upload_file) # filetype = mimetypes.guess_type(filepath, False) # # if filetype[0] is None : # # Hard-coded types for special cases not detected by mimetypes.guess_type() # if upload_file == 'content.data' : # filetype = ('application/octet-stream', None) # # # if filetype[0] is not None : # link_url = 'http://googledrive.com/host/%s'%(public_folder['id']) # link_text = public_folder['title'] # #self.gDriveNotificationStatus(client, _(u'Package exported to <a href="%s" target="_blank" title="Click to visit exported site">%s</<a>') %(link_url,link_text)) # self.gDriveNotificationStatus(client, _(u'Uploading <em>%s</em> to public folder <a href="%s" target="_blank" title="Click to visit exported site">%s</a> (%d/%d)') # %(upload_file, link_url, link_text, file_num, num_total)) # mimetype = filetype[0] # meta = { # 'title': upload_file, # 'mimeType': mimetype, # 'parents' : [{'id' : public_folder['id']}] # } # media_body = MediaFileUpload(filepath, mimetype, resumable=True) # drive.files().insert(body=meta, media_body=media_body).execute() # else : # self.gDriveNotificationNotice(client, _(u'File <em>%s</em> skipped, unknown filetype (%d/%d)') %(upload_file, file_num, num_total), 'warning') # except Exception, e : # log.error(str(e)) # self.gDriveNotificationNotice(client, _(u'Failed upload of file %s (%d/%d)') % (upload_file, file_num, num_total), 'error') # # return public_folder # # def uploadContent_onFail(err): # log.error(str(err)) # self.gDriveNotificationNotice(client, _(u'Failed exporting to GoogleDrive'), 'error') # return err # # def uploadContent_onSuccess(public_folder): # # self.gDriveNotificationStatus(client, _(u'Exported to GoogleDrive: %s') % public_folder['title']) # return public_folder # # def publicFolder(drive, folder_name): # """ # Creates a Public Web folder, that can be read as a web site with any # web browser, and populates it with the content of the given directory # """ # # # Create public folder # self.gDriveNotificationStatus(client, _(u'Creating public folder to host published web site')) # body = { # 'title': folder_name, # 'mimeType': 'application/vnd.google-apps.folder' # } # public_folder = drive.files().insert(body=body).execute() # # permission = { # 'value': '', # 'type': 'anyone', # 'role': 'reader' # } # drive.permissions().insert(fileId=public_folder['id'], body=permission).execute() # # return public_folder # # def publicFolder_onFail(err): # log.error(str(err)) # self.gDriveNotificationNotice(client, _(u'Failed exporting to GoogleDrive'), 'error') # return err # # def publicFolder_onSuccess(public_folder): # self.gDriveNotificationStatus(client, _(u'Created public folder to host published web site: %s') % (public_folder['title'])) # return public_folder # # try: # # Creates a new temporary dir to export the package to, it will be deleted # # once the export process is finished # self.filename = Path(mkdtemp()) # self.gDriveNotificationStatus(client, _(u'Exporting package as web site in: %s') % (jquote(self.filename))) # outputDir = self.export(package) # # self.gDriveNotificationStatus(client, _(u'Starting authorized connection to Google Drive API')) # credentials = AccessTokenCredentials(auth_token, user_agent) # ca_certs = None # if hasattr(sys, 'frozen'): # ca_certs = 'cacerts.txt' # http = httplib2.Http(ca_certs=ca_certs) # http = credentials.authorize(http) # drive_service = build('drive', 'v2', http=http) # # publicFolder_d = threads.deferToThread(publicFolder, drive_service, package.name) # publicFolder_d.addCallbacks(publicFolder_onSuccess, publicFolder_onFail) # # # Loop through files in exportDir, each upload will be called from # # a chained callback function. These callbacks will return a # # deferred so the file N upload will start when file N-1 has # # successfully called its own callback # # (Deferred chain, see: http://krondo.com/?p=2159#attachment_2196) # for upload_file in os.listdir(outputDir): # file_num = file_num + 1 # publicFolder_d.addCallback(insertFile, drive_service, upload_file, file_num) # # num_total = file_num # publicFolder_d.addCallback(finishExport, outputDir) # # # TODO clean exportDir after uploading has finished # # except Exception, e: # log.error(str(e)) # self.gDriveNotificationNotice(client, _('EXPORT FAILED!'), 'error') # raise # #client.alert(_(u'Exported to %s') % filename) def exportZip(self, package): """ Export web site Cleans up the previous packages pages and performs the export """ outputDir = TempDirPath() # Import the Website Page class , if the secure mode is off. If the style has it's own page class # use that, else use the default one. if self.styleSecureMode == "0": if (self.stylesDir / "websitepage.py").exists(): global WebsitePage module = imp.load_source("websitepage", self.stylesDir / "websitepage.py") WebsitePage = module.WebsitePage self.pages = [WebsitePage("index", 0, package.root)] self.generatePages(package.root, 1) uniquifyNames(self.pages) prevPage = None thisPage = self.pages[0] for nextPage in self.pages[1:]: thisPage.save(outputDir, prevPage, nextPage, self.pages) prevPage = thisPage thisPage = nextPage thisPage.save(outputDir, prevPage, None, self.pages) self.copyFiles(package, outputDir) # Zip up the website package self.filename.safeSave( self.doZip, _('EXPORT FAILED!\nLast succesful export is %s.'), outputDir) # Clean up the temporary dir outputDir.rmtree() def doZip(self, fileObj, outputDir): """ Actually saves the zip data. Called by 'Path.safeSave' """ zipped = ZipFile(fileObj, "w") for scormFile in outputDir.files(): zipped.write(scormFile, scormFile.basename().encode('utf8'), ZIP_DEFLATED) zipped.close() def appendPageReport(self, page, package): if not page.node.idevices: self.report += u'"%s","%s",%d,"%s",,,,,,\n' % ( package.filename, page.node.title, page.depth, page.name + '.html') for idevice in page.node.idevices: if not idevice.userResources: self.report += u'"%s","%s",%d,"%s","%s","%s",,,,\n' % ( package.filename, page.node.title, page.depth, page.name + '.html', idevice.klass, idevice.title) for resource in idevice.userResources: if type(resource) == Resource: self.report += u'"%s","%s",%d,"%s","%s","%s","%s","%s","%s","%s"\n' % ( package.filename, page.node.title, page.depth, page.name + '.html', idevice.klass, idevice.title, resource.storageName, resource.userName, resource.path, resource.checksum) else: self.report += u'"%s",%d,"%s","%s","%s","%s",,,\n' % ( package.filename, page.node.title, page.depth, page.name + '.html', idevice.klass, idevice.title, resource) def export(self, package): """ Export web site Cleans up the previous packages pages and performs the export """ if not self.report: outputDir = self.filename if not outputDir.exists(): outputDir.mkdir() # Import the Website Page class. If the style has it's own page class # use that, else use the default one. if (self.stylesDir / "websitepage.py").exists(): global WebsitePage module = imp.load_source("websitepage", self.stylesDir / "websitepage.py") WebsitePage = module.WebsitePage self.pages = [WebsitePage(self.prefix + "index", 0, package.root)] self.generatePages(package.root, 1) uniquifyNames(self.pages) prevPage = None thisPage = self.pages[0] if self.report: self.report = u'"%s","%s","%s","%s","%s","%s","%s","%s","%s","%s"\n' % ( 'File', 'Page Name', 'Level', 'Page File Name', 'Idevice Type', 'Idevice Title', 'Resource File Name', 'Resource User Name', 'Resource Path', 'Resource Checksum') self.appendPageReport(thisPage, package) for nextPage in self.pages[1:]: if self.report: self.appendPageReport(nextPage, package) else: thisPage.save(outputDir, prevPage, nextPage, self.pages) prevPage = thisPage thisPage = nextPage if not self.report: thisPage.save(outputDir, prevPage, None, self.pages) if self.prefix == "": self.copyFiles(package, outputDir) return outputDir else: self.filename.write_text(self.report, 'utf-8') def copyFiles(self, package, outputDir): """ Copy all the files used by the website. """ if os.path.isdir(self.stylesDir): # Copy the style sheet files to the output dir styleFiles = [self.stylesDir / '..' / 'base.css'] styleFiles += [self.stylesDir / '..' / 'popup_bg.gif'] styleFiles += self.stylesDir.files("*.css") styleFiles += self.stylesDir.files("*.jpg") styleFiles += self.stylesDir.files("*.gif") styleFiles += self.stylesDir.files("*.png") styleFiles += self.stylesDir.files("*.js") styleFiles += self.stylesDir.files("*.html") styleFiles += self.stylesDir.files("*.ico") styleFiles += self.stylesDir.files("*.ttf") styleFiles += self.stylesDir.files("*.eot") styleFiles += self.stylesDir.files("*.otf") styleFiles += self.stylesDir.files("*.woff") self.stylesDir.copylist(styleFiles, outputDir) # copy the package's resource files package.resourceDir.copyfiles(outputDir) # copy script files. my_style = G.application.config.styleStore.getStyle(package.style) # jQuery if my_style.hasValidConfig: if my_style.get_jquery() == True: jsFile = (self.scriptsDir / 'exe_jquery.js') jsFile.copyfile(outputDir / 'exe_jquery.js') else: jsFile = (self.scriptsDir / 'exe_jquery.js') jsFile.copyfile(outputDir / 'exe_jquery.js') jsFile = (self.scriptsDir / 'common.js') jsFile.copyfile(outputDir / 'common.js') #dT = common.getExportDocType() dT = common.getExportDocType() if dT == "HTML5": jsFile = (self.scriptsDir / 'exe_html5.js') jsFile.copyfile(outputDir / 'exe_html5.js') # Incluide eXe's icon if the Style doesn't have one themePath = Path(G.application.config.stylesDir / package.style) themeFavicon = themePath.joinpath("favicon.ico") if not themeFavicon.exists(): faviconFile = (self.imagesDir / 'favicon.ico') faviconFile.copyfile(outputDir / 'favicon.ico') # copy players for media idevices. hasFlowplayer = False hasMagnifier = False hasXspfplayer = False hasGallery = False hasFX = False hasGames = False hasWikipedia = False isBreak = False hasInstructions = False hasMediaelement = False hasTooltips = False for page in self.pages: if isBreak: break for idevice in page.node.idevices: if (hasFlowplayer and hasMagnifier and hasXspfplayer and hasGallery and hasFX and hasGames and hasWikipedia and hasInstructions and hasMediaelement and hasTooltips): isBreak = True break if not hasFlowplayer: if 'flowPlayer.swf' in idevice.systemResources: hasFlowplayer = True if not hasMagnifier: if 'mojomagnify.js' in idevice.systemResources: hasMagnifier = True if not hasXspfplayer: if 'xspf_player.swf' in idevice.systemResources: hasXspfplayer = True if not hasGallery: hasGallery = common.ideviceHasGallery(idevice) if not hasFX: hasFX = common.ideviceHasFX(idevice) if not hasGames: hasGames = common.ideviceHasGames(idevice) if not hasWikipedia: if 'WikipediaIdevice' == idevice.klass: hasWikipedia = True if not hasInstructions: if 'TrueFalseIdevice' == idevice.klass or 'MultichoiceIdevice' == idevice.klass or 'VerdaderofalsofpdIdevice' == idevice.klass or 'EleccionmultiplefpdIdevice' == idevice.klass: hasInstructions = True if not hasMediaelement: hasMediaelement = common.ideviceHasMediaelement(idevice) if not hasTooltips: hasTooltips = common.ideviceHasTooltips(idevice) if hasFlowplayer: videofile = (self.templatesDir / 'flowPlayer.swf') videofile.copyfile(outputDir / 'flowPlayer.swf') controlsfile = (self.templatesDir / 'flowplayer.controls.swf') controlsfile.copyfile(outputDir / 'flowplayer.controls.swf') if hasMagnifier: videofile = (self.templatesDir / 'mojomagnify.js') videofile.copyfile(outputDir / 'mojomagnify.js') if hasXspfplayer: videofile = (self.templatesDir / 'xspf_player.swf') videofile.copyfile(outputDir / 'xspf_player.swf') if hasGallery: exeLightbox = (self.scriptsDir / 'exe_lightbox') exeLightbox.copyfiles(outputDir) if hasFX: exeEffects = (self.scriptsDir / 'exe_effects') exeEffects.copyfiles(outputDir) if hasGames: exeGames = (self.scriptsDir / 'exe_games') exeGames.copyfiles(outputDir) if hasWikipedia: wikipediaCSS = (self.cssDir / 'exe_wikipedia.css') wikipediaCSS.copyfile(outputDir / 'exe_wikipedia.css') if hasInstructions: common.copyFileIfNotInStyle('panel-amusements.png', self, outputDir) common.copyFileIfNotInStyle('stock-stop.png', self, outputDir) if hasMediaelement: mediaelement = (self.scriptsDir / 'mediaelement') mediaelement.copyfiles(outputDir) dT = common.getExportDocType() if dT != "HTML5": jsFile = (self.scriptsDir / 'exe_html5.js') jsFile.copyfile(outputDir / 'exe_html5.js') if hasTooltips: exe_tooltips = (self.scriptsDir / 'exe_tooltips') exe_tooltips.copyfiles(outputDir) if hasattr(package, 'exportSource') and package.exportSource: (G.application.config.webDir / 'templates' / 'content.xsd').copyfile(outputDir / 'content.xsd') (outputDir / 'content.data').write_bytes(encodeObject(package)) (outputDir / 'contentv3.xml').write_bytes( encodeObjectToXML(package)) if package.license == "license GFDL": # include a copy of the GNU Free Documentation Licence (self.templatesDir / 'fdl.html').copyfile(outputDir / 'fdl.html') def generatePages(self, node, depth): """ Recursively generate pages and store in pages member variable for retrieving later """ for child in node.children: # assure lower pagename, without whitespaces or alphanumeric characters: pageName = child.titleShort.lower().replace(" ", "_") pageName = re.sub(r"\W", "", pageName) if not pageName: pageName = "__" self.pages.append(WebsitePage(self.prefix + pageName, depth, child)) self.generatePages(child, depth + 1)
class Epub3Export(object): """ Exports an eXe package as a epub 3 package The 'Hello World' of a epub 3 publication might contain files: mimetype META-INF/container.xml Content/HelloWorld.opf Content/HelloWorld.xhtml """ def __init__(self, config, styleDir, filename): """ Initialize 'styleDir' is the directory from which we will copy our style sheets (and some gifs) """ self.config = config self.imagesDir = config.webDir / "images" self.scriptsDir = config.webDir / "scripts" self.cssDir = config.webDir / "css" self.templatesDir = config.webDir / "templates" self.schemasDir = config.webDir / "schemas/ims" self.styleDir = Path(styleDir) self.filename = Path(filename) self.pages = [] def export(self, package): """ Export epub 3 package """ # First do the export to a temporary directory outputDir = TempDirPath() ''' fileDir = outputDir/"META-INF" fileDir.mkdir() fileDir = outputDir/"Content" fileDir.mkdir() ''' metainfPages = Path(outputDir.abspath() + '/META-INF') # metainfPages = outputDir/'META-INF' metainfPages.mkdir() contentPages = Path(outputDir.abspath() + '/EPUB') # contentPages = outputDir/'Content' contentPages.mkdir() # print contentPages.abspath() # print outputDir.abspath() # Export the package content self.pages = [self.make_cover_page(package)] self.generatePages(package.root, 2) uniquifyNames(self.pages, suffix = ".xhtml") cover = None for page in self.pages: page.save(contentPages) if hasattr(page, 'cover'): cover = page.cover # Create mimetype file mimetypeFile = open(outputDir.abspath() + '/mimetype', "w") mimetypeFile.write('application/epub+zip') mimetypeFile.close() # Copy the style sheet files to the output dir # But not nav.css styleFiles = [self.styleDir / '..' / 'base.css'] styleFiles += [self.styleDir / '..' / 'popup_bg.gif'] styleFiles += [f for f in self.styleDir.files("*.css") if f.basename() != "nav.css"] styleFiles += self.styleDir.files("*.jpg") styleFiles += self.styleDir.files("*.gif") styleFiles += self.styleDir.files("*.png") styleFiles += self.styleDir.files("*.js") styleFiles += self.styleDir.files("*.html") styleFiles += self.styleDir.files("*.ttf") styleFiles += self.styleDir.files("*.eot") styleFiles += self.styleDir.files("*.otf") styleFiles += self.styleDir.files("*.woff") # FIXME for now, only copy files referenced in Common Cartridge # this really should apply to all exports, but without a manifest # of the files needed by an included stylesheet it is too restrictive package.resourceDir.copyfiles(contentPages) self.styleDir.copylist(styleFiles, contentPages) self.scriptsDir.copylist(('common.js',), contentPages) # copy players for media idevices. hasFlowplayer = False hasMagnifier = False hasXspfplayer = False hasGallery = False hasWikipedia = False isBreak = False hasInstructions = False for page in self.pages: if isBreak: break for idevice in page.node.idevices: if (hasFlowplayer and hasMagnifier and hasXspfplayer and hasGallery and hasWikipedia): isBreak = True break if not hasFlowplayer: if 'flowPlayer.swf' in idevice.systemResources: hasFlowplayer = True if not hasMagnifier: if 'mojomagnify.js' in idevice.systemResources: hasMagnifier = True if not hasXspfplayer: if 'xspf_player.swf' in idevice.systemResources: hasXspfplayer = True if not hasGallery: hasGallery = common.ideviceHasGallery(idevice) if not hasWikipedia: if 'WikipediaIdevice' == idevice.klass: hasWikipedia = True if not hasInstructions: if 'TrueFalseIdevice' == idevice.klass or 'MultichoiceIdevice' == idevice.klass or 'VerdaderofalsofpdIdevice' == idevice.klass or 'EleccionmultiplefpdIdevice' == idevice.klass: hasInstructions = True if hasFlowplayer: videofile = (self.templatesDir / 'flowPlayer.swf') videofile.copyfile(contentPages / 'flowPlayer.swf') controlsfile = (self.templatesDir / 'flowplayer.controls.swf') controlsfile.copyfile(contentPages / 'flowplayer.controls.swf') if hasMagnifier: videofile = (self.templatesDir / 'mojomagnify.js') videofile.copyfile(contentPages / 'mojomagnify.js') if hasXspfplayer: videofile = (self.templatesDir / 'xspf_player.swf') videofile.copyfile(contentPages / 'xspf_player.swf') if hasGallery: imageGalleryCSS = (self.cssDir / 'exe_lightbox.css') imageGalleryCSS.copyfile(contentPages / 'exe_lightbox.css') imageGalleryJS = (self.scriptsDir / 'exe_lightbox.js') imageGalleryJS.copyfile(contentPages / 'exe_lightbox.js') self.imagesDir.copylist(('exe_lightbox_close.png', 'exe_lightbox_loading.gif', 'exe_lightbox_next.png', 'exe_lightbox_prev.png'), contentPages) if hasWikipedia: wikipediaCSS = (self.cssDir / 'exe_wikipedia.css') wikipediaCSS.copyfile(contentPages / 'exe_wikipedia.css') if hasInstructions: common.copyFileIfNotInStyle('panel-amusements.png', self, contentPages) common.copyFileIfNotInStyle('stock-stop.png', self, contentPages) my_style = G.application.config.styleStore.getStyle(package.style) if my_style.hasValidConfig: if my_style.get_jquery() == True: jsFile = (self.scriptsDir / 'exe_jquery.js') jsFile.copyfile(contentPages / 'exe_jquery.js') else: jsFile = (self.scriptsDir / 'exe_jquery.js') jsFile.copyfile(contentPages / 'exe_jquery.js') # if hasattr(package, 'exportSource') and package.exportSource: # (G.application.config.webDir / 'templates' / 'content.xsd').copyfile(outputDir / 'content.xsd') # (outputDir / 'content.data').write_bytes(encodeObject(package)) # (outputDir / 'contentv3.xml').write_bytes(encodeObjectToXML(package)) if package.license == "license GFDL": # include a copy of the GNU Free Documentation Licence (self.templatesDir / 'fdl.html').copyfile(contentPages / 'fdl.html') # Create the nav.xhtml file container = NavEpub3(self.pages, contentPages) container.save() publication = self.make_publication_epub3(contentPages, package, cover) publication.save("package.opf") # Create the container file container = ContainerEpub3(metainfPages) container.save("container.xml") # Zip it up! self.filename.safeSave(self.doZip, _(u'EXPORT FAILED!\nLast succesful export is %s.'), outputDir) # Clean up the temporary dir outputDir.rmtree() @classmethod def check_package_identifier(cls, package): """Make sure the package has a dublin core identifier Parameters ---------- package : Package The package to check for an identifier on """ if not package.dublinCore.identifier: package.dublinCore.identifier = str(uuid.uuid4()) def make_cover_page(self, package): """Return a Epub3Cover for the given package Parameters ---------- package : Package Package to create a cover page for """ return Epub3Cover("cover", 1, package.root) def make_publication_epub3(self, contentPagesDir, package, cover): """Return a PublicationEpub3 for this export Call only after self.pages has been generated Parameters ---------- contentPagesDir : Path The directory where the contents of the package have been exported to (e.g. the 'EPUB' dir) package : Package The package being exported cover : Epub3Cover The cover page """ publication = PublicationEpub3(self.config, contentPagesDir, package, self.pages, cover) return publication def doZip(self, fileObj, outputDir): """ Actually does the zipping of the file. Called by 'Path.safeSave' """ zipped = ZipFile(fileObj, "w") mimetype = outputDir / "mimetype" zipped.write(mimetype, "mimetype", ZIP_STORED) for epubFile in outputDir.walkfiles(): if epubFile.basename() == 'mimetype': continue relativePath = epubFile.basename() parentdir = epubFile.splitpath()[0] while (outputDir.basename() != parentdir.basename()): relativePath = parentdir.basename() / relativePath parentdir = parentdir.splitpath()[0] zipped.write(epubFile, relativePath.encode('utf8'), compress_type=ZIP_DEFLATED) zipped.close() def generatePages(self, node, depth): """ Recursive function for exporting a node. 'node' is the node that we are making a page for 'depth' is the number of ancestors that the page has +1 (ie. root is 1) """ pageName = node.titleShort.lower().replace(" ", u"_") pageName = re.sub(r"\W", "", pageName) if not pageName: pageName = u"__" if pageName[0] in [unicode(i) for i in range(0, 10)]: pageName = u'_' + pageName page = Epub3Page(pageName, depth, node) self.pages.append(page) for child in node.children: self.generatePages(child, depth + 1)
class WebsiteExport(object): """ WebsiteExport will export a package as a website of HTML pages """ def __init__(self, config, styleDir, filename): """ 'stylesDir' is the directory where we can copy the stylesheets from 'outputDir' is the directory that will be [over]written with the website """ self.config = config self.imagesDir = config.webDir/"images" self.scriptsDir = config.webDir/"scripts" self.templatesDir = config.webDir/"templates" self.stylesDir = Path(styleDir) self.filename = Path(filename) self.pages = [] def exportZip(self, package): """ Export web site Cleans up the previous packages pages and performs the export """ outputDir = TempDirPath() self.copyFiles(package, outputDir) if (self.stylesDir/"websitepage.py").exists(): global WebsitePage module = imp.load_source("websitepage", self.stylesDir/"websitepage.py") WebsitePage = module.WebsitePage self.pages = [ WebsitePage("index", 1, package.root) ] self.generatePages(package.root, 1) uniquifyNames(self.pages) prevPage = None thisPage = self.pages[0] for nextPage in self.pages[1:]: thisPage.save(outputDir, prevPage, nextPage, self.pages) prevPage = thisPage thisPage = nextPage thisPage.save(outputDir, prevPage, None, self.pages) self.filename.safeSave(self.doZip, _('EXPORT FAILED!\nLast succesful export is %s.'), outputDir) outputDir.rmtree() def doZip(self, fileObj, outputDir): """ Actually saves the zip data. Called by 'Path.safeSave' """ zipped = ZipFile(fileObj, "w") for scormFile in outputDir.files(): zipped.write(scormFile, scormFile.basename().encode('utf8'), ZIP_DEFLATED) zipped.close() def export(self, package): """ Export web site Cleans up the previous packages pages and performs the export """ outputDir = self.filename if not outputDir.exists(): outputDir.mkdir() self.copyFiles(package, outputDir) if (self.stylesDir/"websitepage.py").exists(): global WebsitePage module = imp.load_source("websitepage", self.stylesDir/"websitepage.py") WebsitePage = module.WebsitePage self.pages = [ WebsitePage("index", 1, package.root) ] self.generatePages(package.root, 1) uniquifyNames(self.pages) prevPage = None thisPage = self.pages[0] for nextPage in self.pages[1:]: thisPage.save(outputDir, prevPage, nextPage, self.pages) prevPage = thisPage thisPage = nextPage thisPage.save(outputDir, prevPage, None, self.pages) def copyFiles(self, package, outputDir): """ Copy all the files used by the website. """ styleFiles = [self.stylesDir/'..'/'base.css'] styleFiles += [self.stylesDir/'..'/'popup_bg.gif'] styleFiles += self.stylesDir.files("*.css") styleFiles += self.stylesDir.files("*.jpg") styleFiles += self.stylesDir.files("*.gif") styleFiles += self.stylesDir.files("*.png") styleFiles += self.stylesDir.files("*.js") styleFiles += self.stylesDir.files("*.html") self.stylesDir.copylist(styleFiles, outputDir) package.resourceDir.copyfiles(outputDir) self.scriptsDir.copylist(('libot_drag.js', 'common.js'), outputDir) self.templatesDir.copylist(('videoContainer.swf', 'magnifier.swf', 'xspf_player.swf'), outputDir) (self.templatesDir/'fdl.html').copyfile(outputDir/'fdl.html') def generatePages(self, node, depth): """ Recursively generate pages and store in pages member variable for retrieving later """ for child in node.children: pageName = child.titleShort.lower().replace(" ", "_") pageName = re.sub(r"\W", "", pageName) if not pageName: pageName = "__" self.pages.append(WebsitePage(pageName, depth, child)) self.generatePages(child, depth + 1)
class HandoutExport(object): """ This class transform a exe-package to a DOMPresenatation """ def __init__(self, config, styleDir, filename): """ 'stylesDir' is the directory where we can copy the stylesheets from 'outputDir' is the directory that will be [over]written with the website """ self.config = config self.imagesDir = config.webDir / "images" self.scriptsDir = config.webDir / "scripts" self.templatesDir = config.webDir / "templates" self.stylesDir = Path(styleDir) self.filename = Path(filename) self.pages = [] def export(self, package): """ exports package to a dom presentation """ outputDir = self.filename if not outputDir.exists(): outputDir.mkdir() self.pages = [HandoutPage("Index", 1, package.root)] self.generatePages(package.root, 1) log.debug(map(lambda x: getattr(x, "name"), self.pages)) html = u'''<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd"> <html dir="ltr" lang="en"> <head> <meta http-equiv="Content-Type" content="text/html; charset=utf-8"> <title>%s</title> <style type="text/css" media="screen"> @import url(base.css); @import url(content.css); </style> <script type="text/javascript"> function print_page() { window.print(); window.close(); } </script> </head> <body onload=print_page()> <div id="boundary"> <h1 align="center">%s</h1> ''' % (package.name, package.name) for page in self.pages: slidehtml = page.render() if slidehtml != "": html += u'<div class="page">' html += u'<p id="nodeTitle">%s</p>' % escape( page.node.titleLong) html += slidehtml html += u'</div>' log.debug(type(html)) html = html.encode("utf8") log.debug(type(html)) log.debug(html) output = open(outputDir / "index.html", "w") output.write(html) output.close() self.copyFiles(package, outputDir) def copyFiles(self, package, outputDir): """ Copy all the files used by the website. """ print outputDir # Copy the style sheet files to the output dir styleFiles = [self.stylesDir / '..' / 'base.css'] styleFiles += [self.stylesDir / '..' / 'ds_styles.css'] styleFiles += [self.stylesDir / '..' / 'popup_bg.gif'] styleFiles += self.stylesDir.files("*.css") styleFiles += self.stylesDir.files("*.jpg") styleFiles += self.stylesDir.files("*.gif") styleFiles += self.stylesDir.files("*.png") styleFiles += self.stylesDir.files("*.js") styleFiles += self.stylesDir.files("*.html") self.stylesDir.copylist(styleFiles, outputDir) # copy the package's resource files package.resourceDir.copyfiles(outputDir) def generatePages(self, node, depth): """ recursively generates pages """ for child in node.children: title = child.titleShort if not title: title = "__" self.pages.append(HandoutPage(title, depth, child)) self.generatePages(child, depth + 1)
class ScormExport(object): """ Exports an eXe package as a SCORM package """ def __init__(self, config, styleDir, filename, scormType): """ Initialize 'styleDir' is the directory from which we will copy our style sheets (and some gifs) """ self.config = config self.imagesDir = config.webDir/"images" self.scriptsDir = config.webDir/"scripts" self.cssDir = config.webDir/"css" self.templatesDir = config.webDir/"templates" self.schemasDir = config.webDir/"schemas" self.styleDir = Path(styleDir) self.filename = Path(filename) self.pages = [] self.hasForum = False self.scormType = scormType self.styleSecureMode = config.styleSecureMode def export(self, package): """ Export SCORM package """ # First do the export to a temporary directory outputDir = TempDirPath() self.metadataType = package.exportMetadataType # copy the package's resource files for resourceFile in package.resourceDir.walkfiles(): file = package.resourceDir.relpathto(resourceFile) if ("/" in file): Dir = Path(outputDir/file[:file.rindex("/")]) if not Dir.exists(): Dir.makedirs() resourceFile.copy(outputDir/Dir) else: resourceFile.copy(outputDir) # copy the package's resource files, only non existant in outputDir # outputDirFiles = outputDir.files() # for rfile in package.resourceDir.files(): # if rfile not in outputDirFiles: # rfile.copy(outputDir) # copy the package's resource files, only indexed in package.resources # for md5 in package.resources.values(): # for resource in md5: # resource.path.copy(outputDir) # Export the package content # Import the Scorm Page class , if the secure mode is off. If the style has it's own page class # use that, else use the default one. if self.styleSecureMode=="0": if (self.styleDir/"scormpage.py").exists(): global ScormPage module = imp.load_source("ScormPage",self.styleDir/"scormpage.py") ScormPage = module.ScormPage self.pages = [ ScormPage("index", 1, package.root, scormType=self.scormType, metadataType=self.metadataType) ] self.generatePages(package.root, 2) uniquifyNames(self.pages) for page in self.pages: page.save(outputDir, self.pages) if not self.hasForum: for idevice in page.node.idevices: if hasattr(idevice, "isForum"): if idevice.forum.lms.lms == "moodle": self.hasForum = True break # Create the manifest file manifest = Manifest(self.config, outputDir, package, self.pages, self.scormType, self.metadataType) modifiedMetaData = manifest.save("imsmanifest.xml") # Create lang file langFile = open(outputDir + '/common_i18n.js', "w") langFile.write(common.getJavaScriptStrings(False)) langFile.close() if self.hasForum: manifest.save("discussionforum.xml") # Copy the style files to the output dir styleFiles = [self.styleDir/'..'/'popup_bg.gif'] # And with all the files of the style we avoid problems: styleFiles += self.styleDir.files("*.*") if self.scormType == "commoncartridge": for sf in styleFiles[:]: if sf.basename() not in manifest.dependencies: styleFiles.remove(sf) self.styleDir.copylist(styleFiles, outputDir) listCSSFiles=getFilesCSSToMinify('scorm', self.styleDir) exportMinFileCSS(listCSSFiles, outputDir) # Copy the scripts dT = common.getExportDocType() if dT == "HTML5": #listFiles+=[self.scriptsDir/'exe_html5.js'] #listOutFiles+=[outputDir/'exe_html5.js'] jsFile = (self.scriptsDir/'exe_html5.js') jsFile.copyfile(outputDir/'exe_html5.js') # jQuery my_style = G.application.config.styleStore.getStyle(page.node.package.style) if my_style.hasValidConfig: if my_style.get_jquery() == True: #listFiles+=[self.scriptsDir/'exe_jquery.js'] #listOutFiles+=[outputDir/'exe_jquery.js'] jsFile = (self.scriptsDir/'exe_jquery.js') jsFile.copyfile(outputDir/'exe_jquery.js') else: #listFiles+=[self.scriptsDir/'exe_jquery.js'] #listOutFiles+=[outputDir/'exe_jquery.js'] jsFile = (self.scriptsDir/'exe_jquery.js') jsFile.copyfile(outputDir/'exe_jquery.js') if self.scormType == "commoncartridge" or self.scormType == "scorm2004" or self.scormType == "scorm1.2": listFiles=getFilesJSToMinify('scorm', self.scriptsDir) exportMinFileJS(listFiles, outputDir) if self.scormType == "scorm2004" or self.scormType == "scorm1.2": self.scriptsDir.copylist(('SCORM_API_wrapper.js', 'SCOFunctions.js'), outputDir) # about SCHEMAS: schemasDir = "" if self.scormType == "scorm1.2": schemasDir = self.schemasDir/"scorm1.2" schemasDir.copylist(('imscp_rootv1p1p2.xsd', 'imsmd_rootv1p2p1.xsd', 'adlcp_rootv1p2.xsd', 'lom.xsd', 'lomCustom.xsd', 'ims_xml.xsd'), outputDir) elif self.scormType == "scorm2004": schemasDir = self.schemasDir/"scorm2004" schemasDir.copylist(('adlcp_v1p3.xsd', 'adlnav_v1p3.xsd', 'adlseq_v1p3.xsd', 'datatypes.dtd', 'imscp_v1p1.xsd', 'imsssp_v1p0.xsd', 'imsss_v1p0.xsd', 'imsss_v1p0auxresource.xsd', 'imsss_v1p0control.xsd', 'imsss_v1p0delivery.xsd', 'imsmd_rootv1p2p1.xsd', 'imsss_v1p0limit.xsd', 'imsss_v1p0objective.xsd', 'imsss_v1p0random.xsd', 'imsss_v1p0rollup.xsd', 'imsss_v1p0seqrule.xsd', 'imsss_v1p0util.xsd', 'ims_xml.xsd', 'lom.xsd', 'lomCustom.xsd', 'xml.xsd', 'XMLSchema.dtd'), outputDir) try: import shutil, errno shutil.copytree(schemasDir/"common", outputDir/"common") shutil.copytree(schemasDir/"extend", outputDir/"extend") shutil.copytree(schemasDir/"unique", outputDir/"unique") shutil.copytree(schemasDir/"vocab", outputDir/"vocab") except OSError as exc: if exc.errno == errno.ENOTDIR: shutil.copy(schemasDir, outputDir) else: raise # copy players for media idevices. hasFlowplayer = False hasMagnifier = False hasXspfplayer = False hasGallery = False hasFX = False hasSH = False hasGames = False hasElpLink = False hasWikipedia = False isBreak = False hasInstructions = False hasMediaelement = False hasTooltips = False hasABCMusic = False listIdevicesFiles = [] for page in self.pages: if isBreak: break for idevice in page.node.idevices: if (hasFlowplayer and hasMagnifier and hasXspfplayer and hasGallery and hasFX and hasSH and hasGames and hasElpLink and hasWikipedia and hasInstructions and hasMediaelement and hasTooltips and hasABCMusic): isBreak = True break if not hasFlowplayer: if 'flowPlayer.swf' in idevice.systemResources: hasFlowplayer = True if not hasMagnifier: if 'mojomagnify.js' in idevice.systemResources: hasMagnifier = True if not hasXspfplayer: if 'xspf_player.swf' in idevice.systemResources: hasXspfplayer = True if not hasGallery: hasGallery = common.ideviceHasGallery(idevice) if not hasFX: hasFX = common.ideviceHasFX(idevice) if not hasSH: hasSH = common.ideviceHasSH(idevice) if not hasGames: hasGames = common.ideviceHasGames(idevice) if not hasElpLink: hasElpLink = common.ideviceHasElpLink(idevice,package) if not hasWikipedia: if 'WikipediaIdevice' == idevice.klass: hasWikipedia = True if not hasInstructions: if 'TrueFalseIdevice' == idevice.klass or 'MultichoiceIdevice' == idevice.klass or 'VerdaderofalsofpdIdevice' == idevice.klass or 'EleccionmultiplefpdIdevice' == idevice.klass: hasInstructions = True if not hasMediaelement: hasMediaelement = common.ideviceHasMediaelement(idevice) if not hasTooltips: hasTooltips = common.ideviceHasTooltips(idevice) if not hasABCMusic: hasABCMusic = common.ideviceHasABCMusic(idevice) if hasattr(idevice, "_iDeviceDir"): listIdevicesFiles.append((Path(idevice._iDeviceDir)/'export')) common.exportJavaScriptIdevicesFiles(page.node.idevices, outputDir); if hasFlowplayer: videofile = (self.templatesDir/'flowPlayer.swf') videofile.copyfile(outputDir/'flowPlayer.swf') controlsfile = (self.templatesDir/'flowplayer.controls.swf') controlsfile.copyfile(outputDir/'flowplayer.controls.swf') if hasMagnifier: videofile = (self.templatesDir/'mojomagnify.js') videofile.copyfile(outputDir/'mojomagnify.js') if hasXspfplayer: videofile = (self.templatesDir/'xspf_player.swf') videofile.copyfile(outputDir/'xspf_player.swf') if hasGallery: exeLightbox = (self.scriptsDir/'exe_lightbox') exeLightbox.copyfiles(outputDir) if hasFX: exeEffects = (self.scriptsDir/'exe_effects') exeEffects.copyfiles(outputDir) if hasSH: exeSH = (self.scriptsDir/'exe_highlighter') exeSH.copyfiles(outputDir) if hasGames: exeGames = (self.scriptsDir/'exe_games') exeGames.copyfiles(outputDir) # Add game js string to common_i18n langGameFile = open(outputDir + '/common_i18n.js', "a") langGameFile.write(common.getGamesJavaScriptStrings(False)) langGameFile.close() if hasElpLink or package.get_exportElp(): # Export the elp file currentPackagePath = Path(package.filename) currentPackagePath.copyfile(outputDir/package.name+'.elp') if hasWikipedia: wikipediaCSS = (self.cssDir/'exe_wikipedia.css') wikipediaCSS.copyfile(outputDir/'exe_wikipedia.css') if hasInstructions: common.copyFileIfNotInStyle('panel-amusements.png', self, outputDir) common.copyFileIfNotInStyle('stock-stop.png', self, outputDir) if hasMediaelement: mediaelement = (self.scriptsDir/'mediaelement') mediaelement.copyfiles(outputDir) if dT != "HTML5": jsFile = (self.scriptsDir/'exe_html5.js') if hasTooltips: exe_tooltips = (self.scriptsDir/'exe_tooltips') exe_tooltips.copyfiles(outputDir) if hasABCMusic: pluginScripts = (self.scriptsDir/'tinymce_4/js/tinymce/plugins/abcmusic/export') pluginScripts.copyfiles(outputDir) ext = ".html" if G.application.config.cutFileName == "1": ext = ".htm" if self.scormType == "scorm1.2" or self.scormType == "scorm2004": if package.license == "license GFDL": # include a copy of the GNU Free Documentation Licence (self.templatesDir/'fdl' + ext).copyfile(outputDir/'fdl' + ext) if hasattr(package, 'scowsinglepage') and package.scowsinglepage: page = SinglePage("singlepage_index", 1, package.root) page.save(outputDir/"singlepage_index" + ext) # Incluide eXe's icon if the Style doesn't have one themePath = Path(G.application.config.stylesDir/package.style) themeFavicon = themePath.joinpath("favicon.ico") if not themeFavicon.exists(): faviconFile = (self.imagesDir/'favicon.ico') faviconFile.copyfile(outputDir/'favicon.ico') if hasattr(package, 'scowwebsite') and package.scowwebsite: website = WebsiteExport(self.config, self.styleDir, outputDir, "website_") website.export(package) (self.styleDir/'nav.css').copyfile(outputDir/'nav.css') # Incluide eXe's icon if the Style doesn't have one themePath = Path(G.application.config.stylesDir/package.style) themeFavicon = themePath.joinpath("favicon.ico") if not themeFavicon.exists(): faviconFile = (self.imagesDir/'favicon.ico') faviconFile.copyfile(outputDir/'favicon.ico') if hasattr(package, 'exportSource') and package.exportSource: (G.application.config.webDir/'templates'/'content.xsd').copyfile(outputDir/'content.xsd') (outputDir/'content.data').write_bytes(encodeObject(package)) (outputDir/'contentv3.xml').write_bytes(encodeObjectToXML(package)) # Zip it up! self.filename.safeSave(self.doZip, _('EXPORT FAILED!\nLast succesful export is %s.'), outputDir) # Clean up the temporary dir outputDir.rmtree() return modifiedMetaData def doZip(self, fileObj, outputDir): """ Actually does the zipping of the file. Called by 'Path.safeSave' """ # Zip up the scorm package zipped = ZipFile(fileObj, "w") ## old method: only files could be copied: # for scormFile in outputDir.files(): # zipped.write(scormFile, # scormFile.basename().encode('utf8'), # ZIP_DEFLATED) ## but some folders must be included also, so: outputlen = len(outputDir) + 1 for base, dirs, files in os.walk(outputDir): for file in files: fn = os.path.join(base, file) zipped.write(fn, fn[outputlen:].encode('utf8'), ZIP_DEFLATED) # zipped.close() def generatePages(self, node, depth): """ Recursive function for exporting a node. 'node' is the node that we are making a page for 'depth' is the number of ancestors that the page has +1 (ie. root is 1) """ for child in node.children: pageName = child.titleShort.lower().replace(" ", "_") pageName = re.sub(r"\W", "", pageName) if not pageName: pageName = "__" page = ScormPage(pageName, depth, child, scormType=self.scormType, metadataType=self.metadataType) self.pages.append(page) self.generatePages(child, depth + 1) def hasUncutResources(self): """ Check if any of the resources in the exported package has an uncut filename """ for page in self.pages: for idevice in page.node.idevices: for resource in idevice.userResources: if type(resource) == Resource and len(resource.storageName) > 12: return True return False
class WebsiteExport(object): """ WebsiteExport will export a package as a website of HTML pages """ def __init__(self, config, styleDir, filename, prefix="", report=False): """ 'stylesDir' is the directory where we can copy the stylesheets from 'outputDir' is the directory that will be [over]written with the website """ self.config = config self.imagesDir = config.webDir/"images" self.scriptsDir = config.webDir/"scripts" self.cssDir = config.webDir/"css" self.templatesDir = config.webDir/"templates" self.stylesDir = Path(styleDir) self.filename = Path(filename) self.pages = [] self.prefix = prefix self.report = report self.styleSecureMode = config.styleSecureMode def gDriveNotificationStatus(self, client, mesg): client.sendScript("eXe.controller.eXeViewport.prototype.gDriveNotificationStatus('%s');" % (mesg), filter_func=allSessionClients) def gDriveNotificationNotice(self, client, mesg, type): client.sendScript("eXe.controller.eXeViewport.prototype.gDriveNotificationNotice('%s', '%s');" % (mesg, type), filter_func=allSessionClients) # def exportGoogleDrive(self, package, client, auth_token, user_agent): # """ # Creates an authorized HTTP conexion, exports the current package as # 'webSite' to a temporary directory and uploads the exported files to # Google Drive # """ # num_total = 0; # file_num = 0; # # def finishExport(public_folder, outputDir): # self.gDriveNotificationStatus(client, _(u'Deleting temporary directory')) # rmtree(outputDir) # # link_url = 'http://googledrive.com/host/%s'%(public_folder['id']) # link_text = public_folder['title'] # self.gDriveNotificationStatus(client, _(u'Package exported to <a href="%s" target="_blank" title="Click to visit exported site">%s</a>') %(link_url,link_text)) # return public_folder # # def insertFile(public_folder, drive, upload_file, file_num): # """ # Creates the deferred that will upload files to the public folder # once it is created # """ # upload_content_d = threads.deferToThread(uploadContent, public_folder, drive, upload_file, file_num) # upload_content_d.addCallbacks(uploadContent_onSuccess, uploadContent_onFail) # # return upload_content_d # # def uploadContent(public_folder, drive, upload_file, file_num): # """ # Uploads one file to the given GDrive folder # """ # try : # filepath = os.path.join(self.filename, upload_file) # filetype = mimetypes.guess_type(filepath, False) # # if filetype[0] is None : # # Hard-coded types for special cases not detected by mimetypes.guess_type() # if upload_file == 'content.data' : # filetype = ('application/octet-stream', None) # # # if filetype[0] is not None : # link_url = 'http://googledrive.com/host/%s'%(public_folder['id']) # link_text = public_folder['title'] # #self.gDriveNotificationStatus(client, _(u'Package exported to <a href="%s" target="_blank" title="Click to visit exported site">%s</<a>') %(link_url,link_text)) # self.gDriveNotificationStatus(client, _(u'Uploading <em>%s</em> to public folder <a href="%s" target="_blank" title="Click to visit exported site">%s</a> (%d/%d)') # %(upload_file, link_url, link_text, file_num, num_total)) # mimetype = filetype[0] # meta = { # 'title': upload_file, # 'mimeType': mimetype, # 'parents' : [{'id' : public_folder['id']}] # } # media_body = MediaFileUpload(filepath, mimetype, resumable=True) # drive.files().insert(body=meta, media_body=media_body).execute() # else : # self.gDriveNotificationNotice(client, _(u'File <em>%s</em> skipped, unknown filetype (%d/%d)') %(upload_file, file_num, num_total), 'warning') # except Exception, e : # log.error(str(e)) # self.gDriveNotificationNotice(client, _(u'Failed upload of file %s (%d/%d)') % (upload_file, file_num, num_total), 'error') # # return public_folder # # def uploadContent_onFail(err): # log.error(str(err)) # self.gDriveNotificationNotice(client, _(u'Failed exporting to GoogleDrive'), 'error') # return err # # def uploadContent_onSuccess(public_folder): # # self.gDriveNotificationStatus(client, _(u'Exported to GoogleDrive: %s') % public_folder['title']) # return public_folder # # def publicFolder(drive, folder_name): # """ # Creates a Public Web folder, that can be read as a web site with any # web browser, and populates it with the content of the given directory # """ # # # Create public folder # self.gDriveNotificationStatus(client, _(u'Creating public folder to host published web site')) # body = { # 'title': folder_name, # 'mimeType': 'application/vnd.google-apps.folder' # } # public_folder = drive.files().insert(body=body).execute() # # permission = { # 'value': '', # 'type': 'anyone', # 'role': 'reader' # } # drive.permissions().insert(fileId=public_folder['id'], body=permission).execute() # # return public_folder # # def publicFolder_onFail(err): # log.error(str(err)) # self.gDriveNotificationNotice(client, _(u'Failed exporting to GoogleDrive'), 'error') # return err # # def publicFolder_onSuccess(public_folder): # self.gDriveNotificationStatus(client, _(u'Created public folder to host published web site: %s') % (public_folder['title'])) # return public_folder # # try: # # Creates a new temporary dir to export the package to, it will be deleted # # once the export process is finished # self.filename = Path(mkdtemp()) # self.gDriveNotificationStatus(client, _(u'Exporting package as web site in: %s') % (jquote(self.filename))) # outputDir = self.export(package) # # self.gDriveNotificationStatus(client, _(u'Starting authorized connection to Google Drive API')) # credentials = AccessTokenCredentials(auth_token, user_agent) # ca_certs = None # if hasattr(sys, 'frozen'): # ca_certs = 'cacerts.txt' # http = httplib2.Http(ca_certs=ca_certs) # http = credentials.authorize(http) # drive_service = build('drive', 'v2', http=http) # # publicFolder_d = threads.deferToThread(publicFolder, drive_service, package.name) # publicFolder_d.addCallbacks(publicFolder_onSuccess, publicFolder_onFail) # # # Loop through files in exportDir, each upload will be called from # # a chained callback function. These callbacks will return a # # deferred so the file N upload will start when file N-1 has # # successfully called its own callback # # (Deferred chain, see: http://krondo.com/?p=2159#attachment_2196) # for upload_file in os.listdir(outputDir): # file_num = file_num + 1 # publicFolder_d.addCallback(insertFile, drive_service, upload_file, file_num) # # num_total = file_num # publicFolder_d.addCallback(finishExport, outputDir) # # # TODO clean exportDir after uploading has finished # # except Exception, e: # log.error(str(e)) # self.gDriveNotificationNotice(client, _('EXPORT FAILED!'), 'error') # raise # #client.alert(_(u'Exported to %s') % filename) def exportZip(self, package): """ Export web site Cleans up the previous packages pages and performs the export """ outputDir = TempDirPath() # Import the Website Page class , if the secure mode is off. If the style has it's own page class # use that, else use the default one. if self.styleSecureMode=="0": if (self.stylesDir/"websitepage.py").exists(): global WebsitePage module = imp.load_source("websitepage", self.stylesDir/"websitepage.py") WebsitePage = module.WebsitePage self.pages = [ WebsitePage("index", 0, package.root) ] self.generatePages(package.root, 1) uniquifyNames(self.pages) prevPage = None thisPage = self.pages[0] for nextPage in self.pages[1:]: thisPage.save(outputDir, prevPage, nextPage, self.pages) prevPage = thisPage thisPage = nextPage thisPage.save(outputDir, prevPage, None, self.pages) self.copyFiles(package, outputDir) # Zip up the website package self.filename.safeSave(self.doZip, _('EXPORT FAILED!\nLast succesful export is %s.'), outputDir) # Clean up the temporary dir outputDir.rmtree() def doZip(self, fileObj, outputDir): """ Actually saves the zip data. Called by 'Path.safeSave' """ zipped = ZipFile(fileObj, "w") for scormFile in outputDir.files(): zipped.write(scormFile, scormFile.basename().encode('utf8'), ZIP_DEFLATED) zipped.close() def appendPageReport(self, page, package): if not page.node.idevices:self.report += u'"%s","%s",%d,"%s",,,,,,\n' % (package.filename,page.node.title, page.depth, page.name + '.html') for idevice in page.node.idevices: if not idevice.userResources:self.report += u'"%s","%s",%d,"%s","%s","%s",,,,\n' % (package.filename,page.node.title, page.depth, page.name + '.html', idevice.klass, idevice.title) for resource in idevice.userResources: if type(resource) == Resource: self.report += u'"%s","%s",%d,"%s","%s","%s","%s","%s","%s","%s"\n' % (package.filename,page.node.title, page.depth, page.name + '.html', idevice.klass, idevice.title, resource.storageName, resource.userName, resource.path, resource.checksum) else: self.report += u'"%s",%d,"%s","%s","%s","%s",,,\n' % (package.filename,page.node.title, page.depth, page.name + '.html', idevice.klass, idevice.title, resource) def export(self, package): """ Export web site Cleans up the previous packages pages and performs the export """ if not self.report: outputDir = self.filename if not outputDir.exists(): outputDir.mkdir() # Import the Website Page class. If the style has it's own page class # use that, else use the default one. if (self.stylesDir/"websitepage.py").exists(): global WebsitePage module = imp.load_source("websitepage", self.stylesDir/"websitepage.py") WebsitePage = module.WebsitePage self.pages = [ WebsitePage(self.prefix + "index", 0, package.root) ] self.generatePages(package.root, 1) uniquifyNames(self.pages) prevPage = None thisPage = self.pages[0] if self.report: self.report = u'"%s","%s","%s","%s","%s","%s","%s","%s","%s","%s"\n' % ('File','Page Name', 'Level', 'Page File Name', 'Idevice Type', 'Idevice Title', 'Resource File Name', 'Resource User Name', 'Resource Path', 'Resource Checksum') self.appendPageReport(thisPage,package) for nextPage in self.pages[1:]: if self.report: self.appendPageReport(nextPage,package) else: thisPage.save(outputDir, prevPage, nextPage, self.pages) prevPage = thisPage thisPage = nextPage if not self.report: thisPage.save(outputDir, prevPage, None, self.pages) if self.prefix == "": self.copyFiles(package, outputDir) return outputDir else: self.filename.write_text(self.report, 'utf-8') def copyFiles(self, package, outputDir): """ Copy all the files used by the website. """ if os.path.isdir(self.stylesDir): # Copy the style sheet files to the output dir styleFiles = [self.stylesDir/'..'/'base.css'] styleFiles += [self.stylesDir/'..'/'popup_bg.gif'] styleFiles += self.stylesDir.files("*.css") styleFiles += self.stylesDir.files("*.jpg") styleFiles += self.stylesDir.files("*.gif") styleFiles += self.stylesDir.files("*.png") styleFiles += self.stylesDir.files("*.js") styleFiles += self.stylesDir.files("*.html") styleFiles += self.stylesDir.files("*.ico") styleFiles += self.stylesDir.files("*.ttf") styleFiles += self.stylesDir.files("*.eot") styleFiles += self.stylesDir.files("*.otf") styleFiles += self.stylesDir.files("*.woff") self.stylesDir.copylist(styleFiles, outputDir) # copy the package's resource files package.resourceDir.copyfiles(outputDir) # copy script files. my_style = G.application.config.styleStore.getStyle(package.style) # jQuery if my_style.hasValidConfig: if my_style.get_jquery() == True: jsFile = (self.scriptsDir/'exe_jquery.js') jsFile.copyfile(outputDir/'exe_jquery.js') else: jsFile = (self.scriptsDir/'exe_jquery.js') jsFile.copyfile(outputDir/'exe_jquery.js') jsFile = (self.scriptsDir/'common.js') jsFile.copyfile(outputDir/'common.js') #dT = common.getExportDocType() dT=common.getExportDocType(); if dT == "HTML5": jsFile = (self.scriptsDir/'exe_html5.js') jsFile.copyfile(outputDir/'exe_html5.js') # Incluide eXe's icon if the Style doesn't have one themePath = Path(G.application.config.stylesDir/package.style) themeFavicon = themePath.joinpath("favicon.ico") if not themeFavicon.exists(): faviconFile = (self.imagesDir/'favicon.ico') faviconFile.copyfile(outputDir/'favicon.ico') # copy players for media idevices. hasFlowplayer = False hasMagnifier = False hasXspfplayer = False hasGallery = False hasFX = False hasGames = False hasWikipedia = False isBreak = False hasInstructions = False hasMediaelement = False hasTooltips = False for page in self.pages: if isBreak: break for idevice in page.node.idevices: if (hasFlowplayer and hasMagnifier and hasXspfplayer and hasGallery and hasFX and hasGames and hasWikipedia and hasInstructions and hasMediaelement and hasTooltips): isBreak = True break if not hasFlowplayer: if 'flowPlayer.swf' in idevice.systemResources: hasFlowplayer = True if not hasMagnifier: if 'mojomagnify.js' in idevice.systemResources: hasMagnifier = True if not hasXspfplayer: if 'xspf_player.swf' in idevice.systemResources: hasXspfplayer = True if not hasGallery: hasGallery = common.ideviceHasGallery(idevice) if not hasFX: hasFX = common.ideviceHasFX(idevice) if not hasGames: hasGames = common.ideviceHasGames(idevice) if not hasWikipedia: if 'WikipediaIdevice' == idevice.klass: hasWikipedia = True if not hasInstructions: if 'TrueFalseIdevice' == idevice.klass or 'MultichoiceIdevice' == idevice.klass or 'VerdaderofalsofpdIdevice' == idevice.klass or 'EleccionmultiplefpdIdevice' == idevice.klass: hasInstructions = True if not hasMediaelement: hasMediaelement = common.ideviceHasMediaelement(idevice) if not hasTooltips: hasTooltips = common.ideviceHasTooltips(idevice) if hasFlowplayer: videofile = (self.templatesDir/'flowPlayer.swf') videofile.copyfile(outputDir/'flowPlayer.swf') controlsfile = (self.templatesDir/'flowplayer.controls.swf') controlsfile.copyfile(outputDir/'flowplayer.controls.swf') if hasMagnifier: videofile = (self.templatesDir/'mojomagnify.js') videofile.copyfile(outputDir/'mojomagnify.js') if hasXspfplayer: videofile = (self.templatesDir/'xspf_player.swf') videofile.copyfile(outputDir/'xspf_player.swf') if hasGallery: exeLightbox = (self.scriptsDir/'exe_lightbox') exeLightbox.copyfiles(outputDir) if hasFX: exeEffects = (self.scriptsDir/'exe_effects') exeEffects.copyfiles(outputDir) if hasGames: exeGames = (self.scriptsDir/'exe_games') exeGames.copyfiles(outputDir) if hasWikipedia: wikipediaCSS = (self.cssDir/'exe_wikipedia.css') wikipediaCSS.copyfile(outputDir/'exe_wikipedia.css') if hasInstructions: common.copyFileIfNotInStyle('panel-amusements.png', self, outputDir) common.copyFileIfNotInStyle('stock-stop.png', self, outputDir) if hasMediaelement: mediaelement = (self.scriptsDir/'mediaelement') mediaelement.copyfiles(outputDir) dT = common.getExportDocType() if dT != "HTML5": jsFile = (self.scriptsDir/'exe_html5.js') jsFile.copyfile(outputDir/'exe_html5.js') if hasTooltips: exe_tooltips = (self.scriptsDir/'exe_tooltips') exe_tooltips.copyfiles(outputDir) if hasattr(package, 'exportSource') and package.exportSource: (G.application.config.webDir/'templates'/'content.xsd').copyfile(outputDir/'content.xsd') (outputDir/'content.data').write_bytes(encodeObject(package)) (outputDir/'contentv3.xml').write_bytes(encodeObjectToXML(package)) if package.license == "license GFDL": # include a copy of the GNU Free Documentation Licence (self.templatesDir/'fdl.html').copyfile(outputDir/'fdl.html') def generatePages(self, node, depth): """ Recursively generate pages and store in pages member variable for retrieving later """ for child in node.children: # assure lower pagename, without whitespaces or alphanumeric characters: pageName = child.titleShort.lower().replace(" ", "_") pageName = re.sub(r"\W", "", pageName) if not pageName: pageName = "__" self.pages.append(WebsitePage(self.prefix + pageName, depth, child)) self.generatePages(child, depth + 1)
class Epub3Export(object): """ Exports an eXe package as a epub 3 package The 'Hello World' of a epub 3 publication might contain files: mimetype META-INF/container.xml Content/HelloWorld.opf Content/HelloWorld.xhtml """ def __init__(self, config, styleDir, filename): """ Initialize 'styleDir' is the directory from which we will copy our style sheets (and some gifs) """ self.config = config self.imagesDir = config.webDir / "images" self.scriptsDir = config.webDir / "scripts" self.cssDir = config.webDir / "css" self.templatesDir = config.webDir / "templates" self.schemasDir = config.webDir / "schemas/ims" self.styleDir = Path(styleDir) self.filename = Path(filename) self.pages = [] def export(self, package): """ Export epub 3 package """ # First do the export to a temporary directory outputDir = TempDirPath() ''' fileDir = outputDir/"META-INF" fileDir.mkdir() fileDir = outputDir/"Content" fileDir.mkdir() ''' metainfPages = Path(outputDir.abspath() + '/META-INF') # metainfPages = outputDir/'META-INF' metainfPages.mkdir() contentPages = Path(outputDir.abspath() + '/EPUB') # contentPages = outputDir/'Content' contentPages.mkdir() # print contentPages.abspath() # print outputDir.abspath() # Export the package content self.pages = [Epub3Cover("cover", 1, package.root)] self.generatePages(package.root, 2) uniquifyNames(self.pages) cover = None for page in self.pages: page.save(contentPages, self.pages) if hasattr(page, 'cover'): cover = page.cover # Create mimetype file mimetypeFile = open(outputDir.abspath() + '/mimetype', "w") mimetypeFile.write('application/epub+zip') mimetypeFile.close() # Create common_i18n file langFile = open(contentPages + '/common_i18n.js', "w") langFile.write(common.getJavaScriptStrings(False)) langFile.close() # Copy the style files to the output dir # But not nav.css styleFiles = [self.styleDir /'..'/ 'popup_bg.gif'] styleFiles += [f for f in self.styleDir.files("*.*") if f.basename() not in ['nav.css']] # FIXME for now, only copy files referenced in Common Cartridge # this really should apply to all exports, but without a manifest # of the files needed by an included stylesheet it is too restrictive # Add fallback document for possible image links if Path(self.styleDir/'fallback.xhtml').exists(): styleFiles += [self.styleDir /'fallback.xhtml'] else: styleFiles += [self.styleDir/'..'/'fallback.xhtml'] # copy the package's resource files for resourceFile in package.resourceDir.walkfiles(): fn = package.resourceDir.relpathto(resourceFile) if ("/" in fn): Dir = Path(contentPages/fn[:fn.rindex("/")]) if not Dir.exists(): Dir.makedirs() resourceFile.copy(contentPages/Dir) else: resourceFile.copy(contentPages) self.styleDir.copylist(styleFiles, contentPages) # copy players for media idevices. hasFlowplayer = False hasMagnifier = False hasXspfplayer = False hasGallery = False hasFX = False hasSH = False hasGames = False hasElpLink = False hasWikipedia = False isBreak = False hasInstructions = False hasTooltips = False hasABCMusic = False for page in self.pages: if isBreak: break for idevice in page.node.idevices: if (hasFlowplayer and hasMagnifier and hasXspfplayer and hasGallery and hasFX and hasSH and hasGames and hasElpLink and hasWikipedia and hasInstructions and hasTooltips and hasABCMusic): isBreak = True break if not hasFlowplayer: if 'flowPlayer.swf' in idevice.systemResources: hasFlowplayer = True if not hasMagnifier: if 'mojomagnify.js' in idevice.systemResources: hasMagnifier = True if not hasXspfplayer: if 'xspf_player.swf' in idevice.systemResources: hasXspfplayer = True if not hasGallery: hasGallery = common.ideviceHasGallery(idevice) if not hasFX: hasFX = common.ideviceHasFX(idevice) if not hasSH: hasSH = common.ideviceHasSH(idevice) if not hasGames: hasGames = common.ideviceHasGames(idevice) if not hasElpLink: hasElpLink = common.ideviceHasElpLink(idevice,package) if not hasWikipedia: if 'WikipediaIdevice' == idevice.klass: hasWikipedia = True if not hasInstructions: if 'TrueFalseIdevice' == idevice.klass or 'MultichoiceIdevice' == idevice.klass or 'VerdaderofalsofpdIdevice' == idevice.klass or 'EleccionmultiplefpdIdevice' == idevice.klass: hasInstructions = True if not hasTooltips: hasTooltips = common.ideviceHasTooltips(idevice) if not hasABCMusic: hasABCMusic = common.ideviceHasABCMusic(idevice) common.exportJavaScriptIdevicesFiles(page.node.idevices, contentPages); if hasFlowplayer: videofile = (self.templatesDir / 'flowPlayer.swf') videofile.copyfile(contentPages / 'flowPlayer.swf') controlsfile = (self.templatesDir / 'flowplayer.controls.swf') controlsfile.copyfile(contentPages / 'flowplayer.controls.swf') if hasMagnifier: videofile = (self.templatesDir / 'mojomagnify.js') videofile.copyfile(contentPages / 'mojomagnify.js') if hasXspfplayer: videofile = (self.templatesDir / 'xspf_player.swf') videofile.copyfile(contentPages / 'xspf_player.swf') if hasGallery: exeLightbox = (self.scriptsDir / 'exe_lightbox') exeLightbox.copyfiles(contentPages) if hasFX: exeEffects = (self.scriptsDir / 'exe_effects') exeEffects.copyfiles(contentPages) if hasSH: exeSH = (self.scriptsDir / 'exe_highlighter') exeSH.copyfiles(contentPages) if hasGames: exeGames = (self.scriptsDir / 'exe_games') exeGames.copyfiles(contentPages) # Add game js string to common_i18n langGameFile = open(contentPages + '/common_i18n.js', "a") langGameFile.write(common.getGamesJavaScriptStrings(False)) langGameFile.close() if hasElpLink or package.get_exportElp(): # Export the elp file currentPackagePath = Path(package.filename) currentPackagePath.copyfile(contentPages/package.name+'.elp') if hasWikipedia: wikipediaCSS = (self.cssDir / 'exe_wikipedia.css') wikipediaCSS.copyfile(contentPages / 'exe_wikipedia.css') if hasInstructions: common.copyFileIfNotInStyle('panel-amusements.png', self, contentPages) common.copyFileIfNotInStyle('stock-stop.png', self, contentPages) if hasTooltips: exe_tooltips = (self.scriptsDir / 'exe_tooltips') exe_tooltips.copyfiles(contentPages) if hasABCMusic: pluginScripts = (self.scriptsDir/'tinymce_4/js/tinymce/plugins/abcmusic/export') pluginScripts.copyfiles(contentPages) my_style = G.application.config.styleStore.getStyle(package.style) if my_style.hasValidConfig: if my_style.get_jquery() == True: jsFile = (self.scriptsDir / 'exe_jquery.js') jsFile.copyfile(contentPages / 'exe_jquery.js') else: jsFile = (self.scriptsDir / 'exe_jquery.js') jsFile.copyfile(contentPages / 'exe_jquery.js') # Copy and minify CSS files css_files = getFilesCSSToMinify('epub3', self.styleDir) exportMinFileCSS(css_files, contentPages) # Copy and minify JS files js_files = getFilesJSToMinify('epub3', self.scriptsDir) exportMinFileJS(js_files, contentPages) # if hasattr(package, 'exportSource') and package.exportSource: # (G.application.config.webDir / 'templates' / 'content.xsd').copyfile(outputDir / 'content.xsd') # (outputDir / 'content.data').write_bytes(encodeObject(package)) # (outputDir / 'contentv3.xml').write_bytes(encodeObjectToXML(package)) if package.license == "license GFDL": # include a copy of the GNU Free Documentation Licence (self.templatesDir / 'fdl.html').copyfile(contentPages / 'fdl.html') # Create the nav.xhtml file container = NavEpub3(self.pages, contentPages) container.save() # Create the publication file publication = PublicationEpub3(self.config, contentPages, package, self.pages, cover) publication.save("package.opf") # Create the container file container = ContainerEpub3(metainfPages) container.save("container.xml") # Zip it up! self.filename.safeSave(self.doZip, _(u'EXPORT FAILED!\nLast succesful export is %s.'), outputDir) # Clean up the temporary dir outputDir.rmtree() def doZip(self, fileObj, outputDir): """ Actually does the zipping of the file. Called by 'Path.safeSave' """ zipped = ZipFile(fileObj, "w") mimetype = outputDir / "mimetype" zipped.write(mimetype, "mimetype", ZIP_STORED) for epubFile in outputDir.walkfiles(): if epubFile.basename() == 'mimetype': continue relativePath = epubFile.basename() parentdir = epubFile.splitpath()[0] while (outputDir.basename() != parentdir.basename()): relativePath = parentdir.basename() / relativePath parentdir = parentdir.splitpath()[0] zipped.write(epubFile, relativePath.encode('utf8'), compress_type=ZIP_DEFLATED) zipped.close() def generatePages(self, node, depth): """ Recursive function for exporting a node. 'node' is the node that we are making a page for 'depth' is the number of ancestors that the page has +1 (ie. root is 1) """ pageName = node.titleShort.lower().replace(" ", u"_") pageName = re.sub(r"\W", "", pageName) if not pageName: pageName = u"__" if pageName[0] in [unicode(i) for i in range(0, 10)]: pageName = u'_' + pageName page = Epub3Page(pageName, depth, node) self.pages.append(page) for child in node.children: self.generatePages(child, depth + 1)
class IMSExport(object): """ Exports an eXe package as a SCORM package """ def __init__(self, config, styleDir, filename): """ Initialize 'styleDir' is the directory from which we will copy our style sheets (and some gifs) """ self.config = config self.imagesDir = config.webDir/"images" self.scriptsDir = config.webDir/"scripts" self.templatesDir = config.webDir/"templates" self.schemasDir = config.webDir/"schemas/ims" self.styleDir = Path(styleDir) self.filename = Path(filename) self.pages = [] def export(self, package): """ Export SCORM package """ outputDir = TempDirPath() styleFiles = [self.styleDir/'..'/'base.css'] styleFiles += [self.styleDir/'..'/'popup_bg.gif'] styleFiles += self.styleDir.files("*.css") if "nav.css" in styleFiles: styleFiles.remove("nav.css") styleFiles += self.styleDir.files("*.jpg") styleFiles += self.styleDir.files("*.gif") styleFiles += self.styleDir.files("*.png") styleFiles += self.styleDir.files("*.js") styleFiles += self.styleDir.files("*.html") self.styleDir.copylist(styleFiles, outputDir) package.resourceDir.copyfiles(outputDir) self.pages = [ IMSPage("index", 1, package.root) ] self.generatePages(package.root, 2) uniquifyNames(self.pages) for page in self.pages: page.save(outputDir) manifest = Manifest(self.config, outputDir, package, self.pages) manifest.save() self.scriptsDir.copylist(('libot_drag.js', 'common.js'), outputDir) self.schemasDir.copylist(('imscp_v1p1.xsd', 'imsmd_v1p2p2.xsd', 'ims_xml.xsd'), outputDir) hasFlowplayer = False hasMagnifier = False hasXspfplayer = False isBreak = False for page in self.pages: if isBreak: break for idevice in page.node.idevices: if (hasFlowplayer and hasMagnifier and hasXspfplayer): isBreak = True break if not hasFlowplayer: if 'flowPlayer.swf' in idevice.systemResources: hasFlowplayer = True if not hasMagnifier: if 'magnifier.swf' in idevice.systemResources: hasMagnifier = True if not hasXspfplayer: if 'xspf_player.swf' in idevice.systemResources: hasXspfplayer = True if hasFlowplayer: videofile = (self.templatesDir/'flowPlayer.swf') videofile.copyfile(outputDir/'flowPlayer.swf') if hasMagnifier: videofile = (self.templatesDir/'magnifier.swf') videofile.copyfile(outputDir/'magnifier.swf') if hasXspfplayer: videofile = (self.templatesDir/'xspf_player.swf') videofile.copyfile(outputDir/'xspf_player.swf') (self.templatesDir/'fdl.html').copyfile(outputDir/'fdl.html') self.filename.safeSave(self.doZip, _('EXPORT FAILED!\nLast succesful export is %s.'), outputDir) outputDir.rmtree() def doZip(self, fileObj, outputDir): """ Actually does the zipping of the file. Called by 'Path.safeSave' """ zipped = ZipFile(fileObj, "w") for scormFile in outputDir.files(): zipped.write(scormFile, scormFile.basename().encode('utf8'), ZIP_DEFLATED) zipped.close() def generatePages(self, node, depth): """ Recursive function for exporting a node. 'outputDir' is the temporary directory that we are exporting to before creating zip file """ for child in node.children: pageName = child.titleShort.lower().replace(" ", "_") pageName = re.sub(r"\W", "", pageName) if not pageName: pageName = "__" page = IMSPage(pageName, depth, child) self.pages.append(page) self.generatePages(child, depth + 1)
class WebsiteExport(object): """ WebsiteExport will export a package as a website of HTML pages """ def __init__(self, config, styleDir, filename, prefix="", report=False): """ 'stylesDir' is the directory where we can copy the stylesheets from 'outputDir' is the directory that will be [over]written with the website """ self.config = config self.imagesDir = config.webDir/"images" self.scriptsDir = config.webDir/"scripts" self.cssDir = config.webDir/"css" self.templatesDir = config.webDir/"templates" self.stylesDir = Path(styleDir) self.filename = Path(filename) self.pages = [] self.prefix = prefix self.report = report self.styleSecureMode = config.styleSecureMode def exportZip(self, package): """ Export web site Cleans up the previous packages pages and performs the export """ outputDir = TempDirPath() # Import the Website Page class , if the secure mode is off. If the style has it's own page class # use that, else use the default one. if self.styleSecureMode=="0": if (self.stylesDir/"websitepage.py").exists(): global WebsitePage module = imp.load_source("websitepage", self.stylesDir/"websitepage.py") WebsitePage = module.WebsitePage self.pages = [ WebsitePage("index", 0, package.root) ] self.generatePages(package.root, 1) uniquifyNames(self.pages) prevPage = None thisPage = self.pages[0] for nextPage in self.pages[1:]: thisPage.save(outputDir, prevPage, nextPage, self.pages) prevPage = thisPage thisPage = nextPage thisPage.save(outputDir, prevPage, None, self.pages) self.copyFiles(package, outputDir) # Zip up the website package self.filename.safeSave(self.doZip, _('EXPORT FAILED!\nLast succesful export is %s.'), outputDir) # Clean up the temporary dir outputDir.rmtree() def doZip(self, fileObj, outputDir): """ Actually saves the zip data. Called by 'Path.safeSave' """ zipped = ZipFile(fileObj, "w") for scormFile in outputDir.files(): zipped.write(scormFile, scormFile.basename().encode('utf8'), ZIP_DEFLATED) zipped.close() def appendPageReport(self, page, package): if not page.node.idevices:self.report += u'"%s","%s",%d,"%s",,,,,,\n' % (package.filename,page.node.title, page.depth, page.name + '.html') for idevice in page.node.idevices: if not idevice.userResources:self.report += u'"%s","%s",%d,"%s","%s","%s",,,,\n' % (package.filename,page.node.title, page.depth, page.name + '.html', idevice.klass, idevice.title) for resource in idevice.userResources: if type(resource) == Resource: self.report += u'"%s","%s",%d,"%s","%s","%s","%s","%s","%s","%s"\n' % (package.filename,page.node.title, page.depth, page.name + '.html', idevice.klass, idevice.title, resource.storageName, resource.userName, resource.path, resource.checksum) else: self.report += u'"%s",%d,"%s","%s","%s","%s",,,\n' % (package.filename,page.node.title, page.depth, page.name + '.html', idevice.klass, idevice.title, resource) def export(self, package): """ Export web site Cleans up the previous packages pages and performs the export """ if not self.report: outputDir = self.filename if not outputDir.exists(): outputDir.mkdir() # Import the Website Page class. If the style has it's own page class # use that, else use the default one. if (self.stylesDir/"websitepage.py").exists(): global WebsitePage module = imp.load_source("websitepage", self.stylesDir/"websitepage.py") WebsitePage = module.WebsitePage self.pages = [ WebsitePage(self.prefix + "index", 0, package.root) ] self.generatePages(package.root, 1) uniquifyNames(self.pages) prevPage = None thisPage = self.pages[0] if self.report: self.report = u'"%s","%s","%s","%s","%s","%s","%s","%s","%s","%s"\n' % ('File','Page Name', 'Level', 'Page File Name', 'Idevice Type', 'Idevice Title', 'Resource File Name', 'Resource User Name', 'Resource Path', 'Resource Checksum') self.appendPageReport(thisPage,package) for nextPage in self.pages[1:]: if self.report: self.appendPageReport(nextPage,package) else: thisPage.save(outputDir, prevPage, nextPage, self.pages) prevPage = thisPage thisPage = nextPage if not self.report: thisPage.save(outputDir, prevPage, None, self.pages) if self.prefix == "": self.copyFiles(package, outputDir) return outputDir else: self.filename.write_text(self.report, 'utf-8') def copyFiles(self, package, outputDir): """ Copy all the files used by the website. """ if os.path.isdir(self.stylesDir): # Copy the style sheet files to the output dir styleFiles = [self.stylesDir/'..'/'base.css'] styleFiles += [self.stylesDir/'..'/'popup_bg.gif'] styleFiles += self.stylesDir.files("*.css") styleFiles += self.stylesDir.files("*.jpg") styleFiles += self.stylesDir.files("*.gif") styleFiles += self.stylesDir.files("*.png") styleFiles += self.stylesDir.files("*.js") styleFiles += self.stylesDir.files("*.html") styleFiles += self.stylesDir.files("*.ico") styleFiles += self.stylesDir.files("*.ttf") styleFiles += self.stylesDir.files("*.eot") styleFiles += self.stylesDir.files("*.otf") styleFiles += self.stylesDir.files("*.woff") self.stylesDir.copylist(styleFiles, outputDir) # copy the package's resource files package.resourceDir.copyfiles(outputDir) # copy script files. my_style = G.application.config.styleStore.getStyle(package.style) # jQuery if my_style.hasValidConfig: if my_style.get_jquery() == True: jsFile = (self.scriptsDir/'exe_jquery.js') jsFile.copyfile(outputDir/'exe_jquery.js') else: jsFile = (self.scriptsDir/'exe_jquery.js') jsFile.copyfile(outputDir/'exe_jquery.js') jsFile = (self.scriptsDir/'common.js') jsFile.copyfile(outputDir/'common.js') #dT = common.getExportDocType() dT=common.getExportDocType(); if dT == "HTML5": jsFile = (self.scriptsDir/'exe_html5.js') jsFile.copyfile(outputDir/'exe_html5.js') # Incluide eXe's icon if the Style doesn't have one themePath = Path(G.application.config.stylesDir/package.style) themeFavicon = themePath.joinpath("favicon.ico") if not themeFavicon.exists(): faviconFile = (self.imagesDir/'favicon.ico') faviconFile.copyfile(outputDir/'favicon.ico') # copy players for media idevices. hasFlowplayer = False hasMagnifier = False hasXspfplayer = False hasGallery = False hasFX = False hasSH = False hasGames = False hasWikipedia = False isBreak = False hasInstructions = False hasMediaelement = False hasTooltips = False for page in self.pages: if isBreak: break for idevice in page.node.idevices: if (hasFlowplayer and hasMagnifier and hasXspfplayer and hasGallery and hasFX and hasSH and hasGames and hasWikipedia and hasInstructions and hasMediaelement and hasTooltips): isBreak = True break if not hasFlowplayer: if 'flowPlayer.swf' in idevice.systemResources: hasFlowplayer = True if not hasMagnifier: if 'mojomagnify.js' in idevice.systemResources: hasMagnifier = True if not hasXspfplayer: if 'xspf_player.swf' in idevice.systemResources: hasXspfplayer = True if not hasGallery: hasGallery = common.ideviceHasGallery(idevice) if not hasFX: hasFX = common.ideviceHasFX(idevice) if not hasSH: hasSH = common.ideviceHasSH(idevice) if not hasGames: hasGames = common.ideviceHasGames(idevice) if not hasWikipedia: if 'WikipediaIdevice' == idevice.klass: hasWikipedia = True if not hasInstructions: if 'TrueFalseIdevice' == idevice.klass or 'MultichoiceIdevice' == idevice.klass or 'VerdaderofalsofpdIdevice' == idevice.klass or 'EleccionmultiplefpdIdevice' == idevice.klass: hasInstructions = True if not hasMediaelement: hasMediaelement = common.ideviceHasMediaelement(idevice) if not hasTooltips: hasTooltips = common.ideviceHasTooltips(idevice) if hasFlowplayer: videofile = (self.templatesDir/'flowPlayer.swf') videofile.copyfile(outputDir/'flowPlayer.swf') controlsfile = (self.templatesDir/'flowplayer.controls.swf') controlsfile.copyfile(outputDir/'flowplayer.controls.swf') if hasMagnifier: videofile = (self.templatesDir/'mojomagnify.js') videofile.copyfile(outputDir/'mojomagnify.js') if hasXspfplayer: videofile = (self.templatesDir/'xspf_player.swf') videofile.copyfile(outputDir/'xspf_player.swf') if hasGallery: exeLightbox = (self.scriptsDir/'exe_lightbox') exeLightbox.copyfiles(outputDir) if hasFX: exeEffects = (self.scriptsDir/'exe_effects') exeEffects.copyfiles(outputDir) if hasSH: exeSH = (self.scriptsDir/'exe_highlighter') exeSH.copyfiles(outputDir) if hasGames: exeGames = (self.scriptsDir/'exe_games') exeGames.copyfiles(outputDir) if hasWikipedia: wikipediaCSS = (self.cssDir/'exe_wikipedia.css') wikipediaCSS.copyfile(outputDir/'exe_wikipedia.css') if hasInstructions: common.copyFileIfNotInStyle('panel-amusements.png', self, outputDir) common.copyFileIfNotInStyle('stock-stop.png', self, outputDir) if hasMediaelement: mediaelement = (self.scriptsDir/'mediaelement') mediaelement.copyfiles(outputDir) dT = common.getExportDocType() if dT != "HTML5": jsFile = (self.scriptsDir/'exe_html5.js') jsFile.copyfile(outputDir/'exe_html5.js') if hasTooltips: exe_tooltips = (self.scriptsDir/'exe_tooltips') exe_tooltips.copyfiles(outputDir) if hasattr(package, 'exportSource') and package.exportSource: (G.application.config.webDir/'templates'/'content.xsd').copyfile(outputDir/'content.xsd') (outputDir/'content.data').write_bytes(encodeObject(package)) (outputDir/'contentv3.xml').write_bytes(encodeObjectToXML(package)) if package.license == "license GFDL": # include a copy of the GNU Free Documentation Licence (self.templatesDir/'fdl.html').copyfile(outputDir/'fdl.html') def generatePages(self, node, depth): """ Recursively generate pages and store in pages member variable for retrieving later """ for child in node.children: # assure lower pagename, without whitespaces or alphanumeric characters: pageName = child.titleShort.lower().replace(" ", "_") pageName = re.sub(r"\W", "", pageName) if not pageName: pageName = "__" self.pages.append(WebsitePage(self.prefix + pageName, depth, child)) self.generatePages(child, depth + 1)
class ScormExport(object): """ Exports an eXe package as a SCORM package """ def __init__(self, config, styleDir, filename, scormType): """ Initialize 'styleDir' is the directory from which we will copy our style sheets (and some gifs) """ self.config = config self.imagesDir = config.webDir / "images" self.scriptsDir = config.webDir / "scripts" self.cssDir = config.webDir / "css" self.templatesDir = config.webDir / "templates" self.schemasDir = config.webDir / "schemas" self.styleDir = Path(styleDir) self.filename = Path(filename) self.pages = [] self.hasForum = False self.scormType = scormType self.styleSecureMode = config.styleSecureMode def export(self, package): """ Export SCORM package """ # First do the export to a temporary directory outputDir = TempDirPath() self.metadataType = package.exportMetadataType # copy the package's resource files for resourceFile in package.resourceDir.walkfiles(): file = package.resourceDir.relpathto(resourceFile) if ("/" in file): Dir = Path(outputDir / file[:file.rindex("/")]) if not Dir.exists(): Dir.makedirs() resourceFile.copy(outputDir / Dir) else: resourceFile.copy(outputDir) # copy the package's resource files, only non existant in outputDir # outputDirFiles = outputDir.files() # for rfile in package.resourceDir.files(): # if rfile not in outputDirFiles: # rfile.copy(outputDir) # copy the package's resource files, only indexed in package.resources # for md5 in package.resources.values(): # for resource in md5: # resource.path.copy(outputDir) # Export the package content # Import the Scorm Page class , if the secure mode is off. If the style has it's own page class # use that, else use the default one. if self.styleSecureMode == "0": if (self.styleDir / "scormpage.py").exists(): global ScormPage module = imp.load_source("ScormPage", self.styleDir / "scormpage.py") ScormPage = module.ScormPage self.pages = [ ScormPage("index", 1, package.root, scormType=self.scormType, metadataType=self.metadataType) ] self.generatePages(package.root, 2) uniquifyNames(self.pages) for page in self.pages: page.save(outputDir, self.pages) if not self.hasForum: for idevice in page.node.idevices: if hasattr(idevice, "isForum"): if idevice.forum.lms.lms == "moodle": self.hasForum = True break # Create the manifest file manifest = Manifest(self.config, outputDir, package, self.pages, self.scormType, self.metadataType) modifiedMetaData = manifest.save("imsmanifest.xml") # Create lang file langFile = open(outputDir + '/common_i18n.js', "w") langFile.write(common.getJavaScriptStrings(False)) langFile.close() if self.hasForum: manifest.save("discussionforum.xml") # Copy the style files to the output dir styleFiles = [self.styleDir / '..' / 'popup_bg.gif'] # And with all the files of the style we avoid problems: styleFiles += self.styleDir.files("*.*") if self.scormType == "commoncartridge": for sf in styleFiles[:]: if sf.basename() not in manifest.dependencies: styleFiles.remove(sf) self.styleDir.copylist(styleFiles, outputDir) listCSSFiles = getFilesCSSToMinify('scorm', self.styleDir) exportMinFileCSS(listCSSFiles, outputDir) # Copy the scripts dT = common.getExportDocType() if dT == "HTML5": #listFiles+=[self.scriptsDir/'exe_html5.js'] #listOutFiles+=[outputDir/'exe_html5.js'] jsFile = (self.scriptsDir / 'exe_html5.js') jsFile.copyfile(outputDir / 'exe_html5.js') # jQuery my_style = G.application.config.styleStore.getStyle( page.node.package.style) if my_style.hasValidConfig(): if my_style.get_jquery() == True: #listFiles+=[self.scriptsDir/'exe_jquery.js'] #listOutFiles+=[outputDir/'exe_jquery.js'] jsFile = (self.scriptsDir / 'exe_jquery.js') jsFile.copyfile(outputDir / 'exe_jquery.js') else: #listFiles+=[self.scriptsDir/'exe_jquery.js'] #listOutFiles+=[outputDir/'exe_jquery.js'] jsFile = (self.scriptsDir / 'exe_jquery.js') jsFile.copyfile(outputDir / 'exe_jquery.js') if self.scormType == "commoncartridge" or self.scormType == "scorm2004" or self.scormType == "scorm1.2": listFiles = getFilesJSToMinify('scorm', self.scriptsDir) exportMinFileJS(listFiles, outputDir) if self.scormType == "scorm2004" or self.scormType == "scorm1.2": self.scriptsDir.copylist( ('SCORM_API_wrapper.js', 'SCOFunctions.js'), outputDir) # about SCHEMAS: schemasDir = "" if self.scormType == "scorm1.2": schemasDir = self.schemasDir / "scorm1.2" schemasDir.copylist(('imscp_rootv1p1p2.xsd', 'imsmd_rootv1p2p1.xsd', 'adlcp_rootv1p2.xsd', 'lom.xsd', 'lomCustom.xsd', 'ims_xml.xsd'), outputDir) elif self.scormType == "scorm2004": schemasDir = self.schemasDir / "scorm2004" schemasDir.copylist( ('adlcp_v1p3.xsd', 'adlnav_v1p3.xsd', 'adlseq_v1p3.xsd', 'datatypes.dtd', 'imscp_v1p1.xsd', 'imsssp_v1p0.xsd', 'imsss_v1p0.xsd', 'imsss_v1p0auxresource.xsd', 'imsss_v1p0control.xsd', 'imsss_v1p0delivery.xsd', 'imsmd_rootv1p2p1.xsd', 'imsss_v1p0limit.xsd', 'imsss_v1p0objective.xsd', 'imsss_v1p0random.xsd', 'imsss_v1p0rollup.xsd', 'imsss_v1p0seqrule.xsd', 'imsss_v1p0util.xsd', 'ims_xml.xsd', 'lom.xsd', 'lomCustom.xsd', 'xml.xsd', 'XMLSchema.dtd'), outputDir) try: import shutil, errno shutil.copytree(schemasDir / "common", outputDir / "common") shutil.copytree(schemasDir / "extend", outputDir / "extend") shutil.copytree(schemasDir / "unique", outputDir / "unique") shutil.copytree(schemasDir / "vocab", outputDir / "vocab") except OSError as exc: if exc.errno == errno.ENOTDIR: shutil.copy(schemasDir, outputDir) else: raise # copy players for media idevices. hasFlowplayer = False hasMagnifier = False hasXspfplayer = False hasGallery = False hasFX = False hasSH = False hasGames = False hasElpLink = False hasWikipedia = False isBreak = False hasInstructions = False hasMediaelement = False hasTooltips = False hasABCMusic = False listIdevicesFiles = [] for page in self.pages: if isBreak: break for idevice in page.node.idevices: if (hasFlowplayer and hasMagnifier and hasXspfplayer and hasGallery and hasFX and hasSH and hasGames and hasElpLink and hasWikipedia and hasInstructions and hasMediaelement and hasTooltips and hasABCMusic): isBreak = True break if not hasFlowplayer: if 'flowPlayer.swf' in idevice.systemResources: hasFlowplayer = True if not hasMagnifier: if 'mojomagnify.js' in idevice.systemResources: hasMagnifier = True if not hasXspfplayer: if 'xspf_player.swf' in idevice.systemResources: hasXspfplayer = True if not hasGallery: hasGallery = common.ideviceHasGallery(idevice) if not hasFX: hasFX = common.ideviceHasFX(idevice) if not hasSH: hasSH = common.ideviceHasSH(idevice) if not hasGames: hasGames = common.ideviceHasGames(idevice) if not hasElpLink: hasElpLink = common.ideviceHasElpLink(idevice, package) if not hasWikipedia: if 'WikipediaIdevice' == idevice.klass: hasWikipedia = True if not hasInstructions: if 'TrueFalseIdevice' == idevice.klass or 'MultichoiceIdevice' == idevice.klass or 'VerdaderofalsofpdIdevice' == idevice.klass or 'EleccionmultiplefpdIdevice' == idevice.klass: hasInstructions = True if not hasMediaelement: hasMediaelement = common.ideviceHasMediaelement(idevice) if not hasTooltips: hasTooltips = common.ideviceHasTooltips(idevice) if not hasABCMusic: hasABCMusic = common.ideviceHasABCMusic(idevice) if hasattr(idevice, "_iDeviceDir"): listIdevicesFiles.append( (idevice.get_jsidevice_dir() / 'export')) common.exportJavaScriptIdevicesFiles(page.node.idevices, outputDir) if hasFlowplayer: videofile = (self.templatesDir / 'flowPlayer.swf') videofile.copyfile(outputDir / 'flowPlayer.swf') controlsfile = (self.templatesDir / 'flowplayer.controls.swf') controlsfile.copyfile(outputDir / 'flowplayer.controls.swf') if hasMagnifier: videofile = (self.templatesDir / 'mojomagnify.js') videofile.copyfile(outputDir / 'mojomagnify.js') if hasXspfplayer: videofile = (self.templatesDir / 'xspf_player.swf') videofile.copyfile(outputDir / 'xspf_player.swf') if hasGallery: exeLightbox = (self.scriptsDir / 'exe_lightbox') exeLightbox.copyfiles(outputDir) if hasFX: exeEffects = (self.scriptsDir / 'exe_effects') exeEffects.copyfiles(outputDir) if hasSH: exeSH = (self.scriptsDir / 'exe_highlighter') exeSH.copyfiles(outputDir) if hasGames: exeGames = (self.scriptsDir / 'exe_games') exeGames.copyfiles(outputDir) # Add game js string to common_i18n langGameFile = open(outputDir + '/common_i18n.js', "a") langGameFile.write(common.getGamesJavaScriptStrings(False)) langGameFile.close() if hasElpLink or package.get_exportElp(): # Export the elp file currentPackagePath = Path(package.filename) currentPackagePath.copyfile(outputDir / package.name + '.elp') if hasWikipedia: wikipediaCSS = (self.cssDir / 'exe_wikipedia.css') wikipediaCSS.copyfile(outputDir / 'exe_wikipedia.css') if hasInstructions: common.copyFileIfNotInStyle('panel-amusements.png', self, outputDir) common.copyFileIfNotInStyle('stock-stop.png', self, outputDir) if hasMediaelement: mediaelement = (self.scriptsDir / 'mediaelement') mediaelement.copyfiles(outputDir) if dT != "HTML5": jsFile = (self.scriptsDir / 'exe_html5.js') if hasTooltips: exe_tooltips = (self.scriptsDir / 'exe_tooltips') exe_tooltips.copyfiles(outputDir) if hasABCMusic: pluginScripts = (self.scriptsDir / 'tinymce_4/js/tinymce/plugins/abcmusic/export') pluginScripts.copyfiles(outputDir) ext = ".html" if G.application.config.cutFileName == "1": ext = ".htm" if self.scormType == "scorm1.2" or self.scormType == "scorm2004": if package.license == "license GFDL": # include a copy of the GNU Free Documentation Licence (self.templatesDir / 'fdl' + ext).copyfile(outputDir / 'fdl' + ext) if hasattr(package, 'scowsinglepage') and package.scowsinglepage: page = SinglePage("singlepage_index", 1, package.root) page.save(outputDir / "singlepage_index" + ext) # Incluide eXe's icon if the Style doesn't have one themePath = Path(G.application.config.stylesDir / package.style) themeFavicon = themePath.joinpath("favicon.ico") if not themeFavicon.exists(): faviconFile = (self.imagesDir / 'favicon.ico') faviconFile.copyfile(outputDir / 'favicon.ico') if hasattr(package, 'scowwebsite') and package.scowwebsite: website = WebsiteExport(self.config, self.styleDir, outputDir, "website_") website.export(package) (self.styleDir / 'nav.css').copyfile(outputDir / 'nav.css') # Incluide eXe's icon if the Style doesn't have one themePath = Path(G.application.config.stylesDir / package.style) themeFavicon = themePath.joinpath("favicon.ico") if not themeFavicon.exists(): faviconFile = (self.imagesDir / 'favicon.ico') faviconFile.copyfile(outputDir / 'favicon.ico') if hasattr(package, 'exportSource') and package.exportSource: (G.application.config.webDir / 'templates' / 'content.xsd').copyfile(outputDir / 'content.xsd') (outputDir / 'content.data').write_bytes(encodeObject(package)) (outputDir / 'contentv3.xml').write_bytes( encodeObjectToXML(package)) # Zip it up! self.filename.safeSave( self.doZip, _('EXPORT FAILED!\nLast succesful export is %s.'), outputDir) # Clean up the temporary dir outputDir.rmtree() return modifiedMetaData def doZip(self, fileObj, outputDir): """ Actually does the zipping of the file. Called by 'Path.safeSave' """ # Zip up the scorm package zipped = ZipFile(fileObj, "w") ## old method: only files could be copied: # for scormFile in outputDir.files(): # zipped.write(scormFile, # scormFile.basename().encode('utf8'), # ZIP_DEFLATED) ## but some folders must be included also, so: outputlen = len(outputDir) + 1 for base, dirs, files in os.walk(outputDir): for file in files: fn = os.path.join(base, file) zipped.write(fn, fn[outputlen:].encode('utf8'), ZIP_DEFLATED) # zipped.close() def generatePages(self, node, depth): """ Recursive function for exporting a node. 'node' is the node that we are making a page for 'depth' is the number of ancestors that the page has +1 (ie. root is 1) """ for child in node.children: pageName = child.titleShort.lower().replace(" ", "_") pageName = re.sub(r"\W", "", pageName) if not pageName: pageName = "__" page = ScormPage(pageName, depth, child, scormType=self.scormType, metadataType=self.metadataType) self.pages.append(page) self.generatePages(child, depth + 1) def hasUncutResources(self): """ Check if any of the resources in the exported package has an uncut filename """ for page in self.pages: for idevice in page.node.idevices: for resource in idevice.userResources: if type(resource) == Resource and len( resource.storageName) > 12: return True return False
def renderEdit(self): """ Returns an XHTML string with the form element for editing this field """ from exe.application import application webDir = application.config.webDir greekDir = Path(webDir+'/images/maths/greek letters') oprationDir = Path(webDir+'/images/maths/binary oprations') relationDir = Path(webDir+'/images/maths/relations') html = u'<div class="block">' html += u"<b>"+self.field.name+":</b>\n" html += common.elementInstruc(self.field.instruc) html += u"<br/></div>\n" html += '<div class="maths">\n' for file in greekDir.files(): if file.ext == ".gif" or file.ext == ".png": symbol = file.namebase html += common.insertSymbol("input"+self.id, u"/images/maths/greek letters/%s", "%s", r"\\%s") % (symbol, symbol, file.basename()) html += u"<br/>" for file in oprationDir.files(): if file.ext == ".gif" or file.ext == ".png": symbol = file.namebase html += common.insertSymbol("input"+self.id, u"/images/maths/binary oprations/%s", "%s", r"\\%s") % (symbol, symbol, file.basename()) html += u"<br/>" for file in relationDir.files(): if file.ext == ".gif" or file.ext == ".png": symbol = file.namebase html += common.insertSymbol("input"+self.id, u"/images/maths/relations/%s", "%s", r"\\%s") % (symbol, symbol, file.basename()) html += "<br />" html += common.insertSymbol("input"+self.id, "", "", r"\\begin{verbatim}\\end{verbatim}", _("text"), 14) html += common.insertSymbol("input"+self.id, "", "", r"\\\\\n", _("newline")) html += '<br/>' html += _("Select a font size: ") html += "<select name=\"fontsize%s\">\n" % self.id template = ' <option value="%s"%s>%s</option>\n' for i in range(1, 11): if i == self.field.fontsize: html += template % (str(i), ' selected="selected"', str(i)) else: html += template % (str(i), '', str(i)) html += "</select>\n" html += "</div>\n" html += common.textArea('input'+self.id, self.field.latex) html += '<div class="block">\n' html += common.submitButton('preview'+self.id, _('Preview')) html += common.elementInstruc(self.field.previewInstruc) + '<br/>' if self.field.gifResource: html += '<p>' html += '<img src="resources/%s" /></p>' % (self.field.gifResource.storageName) html += "</div>\n" else: html += '<br/>' return html
class SinglePageExport(object): """ SinglePageExport will export a package as a website of HTML pages """ def __init__(self, stylesDir, outputDir, imagesDir, scriptsDir, cssDir, templatesDir): """ 'stylesDir' is the directory where we can copy the stylesheets from 'outputDir' is the directory that will be [over]written with the website """ self.html = "" self.style = None self.name = None self.stylesDir = Path(stylesDir) self.outputDir = Path(outputDir) self.imagesDir = Path(imagesDir) self.scriptsDir = Path(scriptsDir) self.cssDir = Path(cssDir) self.templatesDir = Path(templatesDir) self.page = None # Create the output dir if it doesn't already exist if not self.outputDir.exists(): self.outputDir.mkdir() def export(self, package, for_print=0): """ Export web site Cleans up the previous packages pages and performs the export """ self.style = package.style self.page = SinglePage("index", 1, package.root) self.page.save(self.outputDir / "index.html", for_print) if hasattr(package, 'exportSource') and package.exportSource and not for_print: (G.application.config.webDir / 'templates' / 'content.xsd').copyfile(self.outputDir / 'content.xsd') (self.outputDir / 'content.data').write_bytes( encodeObject(package)) (self.outputDir / 'contentv3.xml').write_bytes( encodeObjectToXML(package)) self.copyFiles(package) def copyFiles(self, package): """ Copy all the files used by the website. """ # Copy the style sheet files to the output dir # But not nav.css if os.path.isdir(self.stylesDir): # Copy the style sheet files to the output dir styleFiles = [self.stylesDir / '..' / 'base.css'] styleFiles += [self.stylesDir / '..' / 'popup_bg.gif'] styleFiles += self.stylesDir.files("*.css") if "nav.css" in styleFiles: styleFiles.remove("nav.css") styleFiles += self.stylesDir.files("*.jpg") styleFiles += self.stylesDir.files("*.gif") styleFiles += self.stylesDir.files("*.png") styleFiles += self.stylesDir.files("*.js") styleFiles += self.stylesDir.files("*.html") styleFiles += self.stylesDir.files("*.ico") styleFiles += self.stylesDir.files("*.ttf") styleFiles += self.stylesDir.files("*.eot") styleFiles += self.stylesDir.files("*.otf") styleFiles += self.stylesDir.files("*.woff") self.stylesDir.copylist(styleFiles, self.outputDir) # copy the package's resource files package.resourceDir.copyfiles(self.outputDir) # copy script files. my_style = G.application.config.styleStore.getStyle(package.style) # jQuery if my_style.hasValidConfig: if my_style.get_jquery() == True: jsFile = (self.scriptsDir / 'exe_jquery.js') jsFile.copyfile(self.outputDir / 'exe_jquery.js') else: jsFile = (self.scriptsDir / 'exe_jquery.js') jsFile.copyfile(self.outputDir / 'exe_jquery.js') jsFile = (self.scriptsDir / 'common.js') jsFile.copyfile(self.outputDir / 'common.js') jsFile = (self.scriptsDir / 'lernmodule_net.js') jsFile.copyfile(self.outputDir / 'lernmodule_net.js') jsFile = (self.scriptsDir / 'lernmodule_net_custom.js') jsFile.copyfile(self.outputDir / 'lernmodule_net_custom.js') dT = common.getExportDocType() if dT == "HTML5": jsFile = (self.scriptsDir / 'exe_html5.js') jsFile.copyfile(self.outputDir / 'exe_html5.js') # Incluide eXe's icon if the Style doesn't have one themePath = Path(G.application.config.stylesDir / package.style) themeFavicon = themePath.joinpath("favicon.ico") if not themeFavicon.exists(): faviconFile = (self.imagesDir / 'favicon.ico') faviconFile.copyfile(self.outputDir / 'favicon.ico') #JR Metemos los reproductores necesarios self.compruebaReproductores(self.page.node) if package.license == "license GFDL": # include a copy of the GNU Free Documentation Licence (self.templatesDir / 'fdl.html').copyfile(self.outputDir / 'fdl.html') def compruebaReproductores(self, node): """ Comprobamos si hay que meter algun reproductor """ # copy players for media idevices. hasFlowplayer = False hasMagnifier = False hasXspfplayer = False hasGallery = False hasWikipedia = False hasInstructions = False hasMediaelement = False for idevice in node.idevices: if (hasFlowplayer and hasMagnifier and hasXspfplayer and hasGallery and hasWikipedia and hasInstructions and hasMediaelement): break if not hasFlowplayer: if 'flowPlayer.swf' in idevice.systemResources: hasFlowplayer = True if not hasMagnifier: if 'mojomagnify.js' in idevice.systemResources: hasMagnifier = True if not hasXspfplayer: if 'xspf_player.swf' in idevice.systemResources: hasXspfplayer = True if not hasGallery: hasGallery = common.ideviceHasGallery(idevice) if not hasWikipedia: if 'WikipediaIdevice' == idevice.klass: hasWikipedia = True if not hasInstructions: if 'TrueFalseIdevice' == idevice.klass or 'MultichoiceIdevice' == idevice.klass or 'VerdaderofalsofpdIdevice' == idevice.klass or 'EleccionmultiplefpdIdevice' == idevice.klass: hasInstructions = True if not hasMediaelement: hasMediaelement = common.ideviceHasMediaelement(idevice) if hasFlowplayer: videofile = (self.templatesDir / 'flowPlayer.swf') videofile.copyfile(self.outputDir / 'flowPlayer.swf') controlsfile = (self.templatesDir / 'flowplayer.controls.swf') controlsfile.copyfile(self.outputDir / 'flowplayer.controls.swf') if hasMagnifier: videofile = (self.templatesDir / 'mojomagnify.js') videofile.copyfile(self.outputDir / 'mojomagnify.js') if hasXspfplayer: videofile = (self.templatesDir / 'xspf_player.swf') videofile.copyfile(self.outputDir / 'xspf_player.swf') if hasGallery: imageGalleryCSS = (self.cssDir / 'exe_lightbox.css') imageGalleryCSS.copyfile(self.outputDir / 'exe_lightbox.css') imageGalleryJS = (self.scriptsDir / 'exe_lightbox.js') imageGalleryJS.copyfile(self.outputDir / 'exe_lightbox.js') self.imagesDir.copylist( ('exe_lightbox_close.png', 'exe_lightbox_loading.gif', 'exe_lightbox_next.png', 'exe_lightbox_prev.png'), self.outputDir) if hasWikipedia: wikipediaCSS = (self.cssDir / 'exe_wikipedia.css') wikipediaCSS.copyfile(self.outputDir / 'exe_wikipedia.css') if hasInstructions: common.copyFileIfNotInStyle('panel-amusements.png', self, self.outputDir) common.copyFileIfNotInStyle('stock-stop.png', self, self.outputDir) if hasMediaelement: mediaelement = (self.scriptsDir / 'mediaelement') mediaelement.copyfiles(self.outputDir) dT = common.getExportDocType() if dT != "HTML5": jsFile = (self.scriptsDir / 'exe_html5.js') jsFile.copyfile(self.outputDir / 'exe_html5.js') for child in node.children: self.compruebaReproductores(child)
class ScormExport(object): """ Exports an eXe package as a SCORM package """ def __init__(self, config, styleDir, filename, scormType, metadataType='DC'): """ Initialize 'styleDir' is the directory from which we will copy our style sheets (and some gifs) """ self.config = config self.imagesDir = config.webDir/"images" self.scriptsDir = config.webDir/"scripts" self.cssDir = config.webDir/"css" self.templatesDir = config.webDir/"templates" self.schemasDir = config.webDir/"schemas" self.styleDir = Path(styleDir) self.filename = Path(filename) self.pages = [] self.hasForum = False self.scormType = scormType self.metadataType = metadataType def export(self, package): """ Export SCORM package """ # First do the export to a temporary directory outputDir = TempDirPath() # copy the package's resource files package.resourceDir.copyfiles(outputDir) # copy the package's resource files, only non existant in outputDir # outputDirFiles = outputDir.files() # for rfile in package.resourceDir.files(): # if rfile not in outputDirFiles: # rfile.copy(outputDir) # copy the package's resource files, only indexed in package.resources # for md5 in package.resources.values(): # for resource in md5: # resource.path.copy(outputDir) # Export the package content self.pages = [ ScormPage("index", 1, package.root, scormType=self.scormType, metadataType=self.metadataType) ] self.generatePages(package.root, 2) uniquifyNames(self.pages) for page in self.pages: page.save(outputDir) if not self.hasForum: for idevice in page.node.idevices: if hasattr(idevice, "isForum"): if idevice.forum.lms.lms == "moodle": self.hasForum = True break # Create the manifest file manifest = Manifest(self.config, outputDir, package, self.pages, self.scormType, self.metadataType) manifest.save("imsmanifest.xml") if self.hasForum: manifest.save("discussionforum.xml") # Copy the style sheet files to the output dir # But not nav.css styleFiles = [self.styleDir/'..'/'base.css'] styleFiles += [self.styleDir/'..'/'popup_bg.gif'] styleFiles += [f for f in self.styleDir.files("*.css") if f.basename() <> "nav.css"] styleFiles += self.styleDir.files("*.jpg") styleFiles += self.styleDir.files("*.gif") styleFiles += self.styleDir.files("*.png") styleFiles += self.styleDir.files("*.js") styleFiles += self.styleDir.files("*.html") styleFiles += self.styleDir.files("*.ttf") styleFiles += self.styleDir.files("*.eot") styleFiles += self.styleDir.files("*.otf") styleFiles += self.styleDir.files("*.woff") # FIXME for now, only copy files referenced in Common Cartridge # this really should apply to all exports, but without a manifest # of the files needed by an included stylesheet it is too restrictive if self.scormType == "commoncartridge": for sf in styleFiles[:]: if sf.basename() not in manifest.dependencies: styleFiles.remove(sf) self.styleDir.copylist(styleFiles, outputDir) # Copy the scripts if self.scormType == "commoncartridge": self.scriptsDir.copylist(('libot_drag.js', 'common.js'), outputDir) if self.scormType == "scorm2004": self.scriptsDir.copylist(('AC_RunActiveContent.js', 'SCORM_API_wrapper.js', 'SCOFunctions.js', 'libot_drag.js', 'common.js'), outputDir) if self.scormType != "commoncartridge" and self.scormType != "scorm2004": self.scriptsDir.copylist(('APIWrapper.js', 'SCOFunctions.js', 'libot_drag.js', 'common.js'), outputDir) schemasDir = "" if self.scormType == "scorm1.2": schemasDir = self.schemasDir/"scorm1.2" schemasDir.copylist(('imscp_rootv1p1p2.xsd', 'imsmd_rootv1p2p1.xsd', 'adlcp_rootv1p2.xsd', 'ims_xml.xsd'), outputDir) elif self.scormType == "scorm2004": schemasDir = self.schemasDir/"scorm2004" schemasDir.copylist(('adlcp_v1p3.xsd', 'adlnav_v1p3.xsd', 'adlseq_v1p3.xsd', 'datatypes.dtd', 'imscp_v1p1.xsd', 'imsssp_v1p0.xsd', 'imsss_v1p0.xsd', 'imsss_v1p0auxresource.xsd', 'imsss_v1p0control.xsd', 'imsss_v1p0delivery.xsd', 'imsss_v1p0limit.xsd', 'imsss_v1p0objective.xsd', 'imsss_v1p0random.xsd', 'imsss_v1p0rollup.xsd', 'imsss_v1p0seqrule.xsd', 'imsss_v1p0util.xsd', 'ims_xml.xsd', 'lom.xsd', 'lomCustom.xsd', 'xml.xsd', 'XMLSchema.dtd'), outputDir) try: import shutil, errno shutil.copytree(schemasDir/"lom", outputDir/"lom") except OSError as exc: if exc.errno == errno.ENOTDIR: shutil.copy(schemasDir/"lom", outputDir/"lom") else: raise # copy players for media idevices. hasFlowplayer = False hasMagnifier = False hasXspfplayer = False hasGallery = False isBreak = False for page in self.pages: if isBreak: break for idevice in page.node.idevices: if (hasFlowplayer and hasMagnifier and hasXspfplayer and hasGallery): isBreak = True break if not hasFlowplayer: if 'flowPlayer.swf' in idevice.systemResources: hasFlowplayer = True if not hasMagnifier: if 'magnifier.swf' in idevice.systemResources: hasMagnifier = True if not hasXspfplayer: if 'xspf_player.swf' in idevice.systemResources: hasXspfplayer = True if not hasGallery: if 'GalleryIdevice' == idevice.klass: hasGallery = True if hasFlowplayer: videofile = (self.templatesDir/'flowPlayer.swf') videofile.copyfile(outputDir/'flowPlayer.swf') controlsfile = (self.templatesDir/'flowplayer.controls.swf') controlsfile.copyfile(outputDir/'flowplayer.controls.swf') if hasMagnifier: videofile = (self.templatesDir/'magnifier.swf') videofile.copyfile(outputDir/'magnifier.swf') if hasXspfplayer: videofile = (self.templatesDir/'xspf_player.swf') videofile.copyfile(outputDir/'xspf_player.swf') if hasGallery: imageGalleryCSS = (self.cssDir/'exe_lightbox.css') imageGalleryCSS.copyfile(outputDir/'exe_lightbox.css') imageGalleryJS = (self.scriptsDir/'exe_lightbox.js') imageGalleryJS.copyfile(outputDir/'exe_lightbox.js') self.imagesDir.copylist(('exeGallery_actions.png', 'exeGallery_loading.gif', 'stock-insert-image.png'), outputDir) if self.scormType == "scorm1.2" or self.scormType == "scorm2004": if package.license == "GNU Free Documentation License": # include a copy of the GNU Free Documentation Licence (self.templatesDir/'fdl.html').copyfile(outputDir/'fdl.html') if hasattr(package, 'scowsinglepage') and package.scowsinglepage: page = SinglePage("singlepage_index", 1, package.root) page.save(outputDir/"singlepage_index.html") if hasattr(package, 'scowwebsite') and package.scowwebsite: website = WebsiteExport(self.config, self.styleDir, outputDir, "website_") website.export(package) (self.styleDir/'nav.css').copyfile(outputDir/'nav.css') if hasattr(package, 'scowsource') and package.scowsource: (G.application.config.webDir/'templates'/'content.xsd').copyfile(outputDir/'content.xsd') (outputDir/'content.data').write_bytes(encodeObject(package)) (outputDir/'contentv2.xml').write_bytes(encodeObjectToXML(package)) # Zip it up! self.filename.safeSave(self.doZip, _('EXPORT FAILED!\nLast succesful export is %s.'), outputDir) # Clean up the temporary dir outputDir.rmtree() def doZip(self, fileObj, outputDir): """ Actually does the zipping of the file. Called by 'Path.safeSave' """ # Zip up the scorm package zipped = ZipFile(fileObj, "w") ## old method: only files could be copied: # for scormFile in outputDir.files(): # zipped.write(scormFile, # scormFile.basename().encode('utf8'), # ZIP_DEFLATED) ## but some folders must be included also, so: outputlen = len(outputDir) + 1 for base, dirs, files in os.walk(outputDir): for file in files: fn = os.path.join(base, file) zipped.write(fn, fn[outputlen:].encode('utf8'), ZIP_DEFLATED) # zipped.close() def generatePages(self, node, depth): """ Recursive function for exporting a node. 'node' is the node that we are making a page for 'depth' is the number of ancestors that the page has +1 (ie. root is 1) """ for child in node.children: pageName = child.titleShort.lower().replace(" ", "_") pageName = re.sub(r"\W", "", pageName) if not pageName: pageName = "__" page = ScormPage(pageName, depth, child, scormType=self.scormType, metadataType=self.metadataType) self.pages.append(page) self.generatePages(child, depth + 1)
class IMSExport(object): """ Exports an eXe package as a SCORM package """ def __init__(self, config, styleDir, filename): """ Initialize 'styleDir' is the directory from which we will copy our style sheets (and some gifs) """ self.config = config self.imagesDir = config.webDir / "images" self.scriptsDir = config.webDir / "scripts" self.cssDir = config.webDir / "css" self.templatesDir = config.webDir / "templates" self.schemasDir = config.webDir / "schemas/ims" self.styleDir = Path(styleDir) self.filename = Path(filename) self.pages = [] def export(self, package): """ Export SCORM package """ # First do the export to a temporary directory outputDir = TempDirPath() self.metadataType = package.exportMetadataType # Copy the style sheet files to the output dir # But not nav.css styleFiles = [self.styleDir / '..' / 'base.css'] styleFiles += [self.styleDir / '..' / 'popup_bg.gif'] styleFiles += self.styleDir.files("*.css") if "nav.css" in styleFiles: styleFiles.remove("nav.css") styleFiles += self.styleDir.files("*.jpg") styleFiles += self.styleDir.files("*.gif") styleFiles += self.styleDir.files("*.png") styleFiles += self.styleDir.files("*.js") styleFiles += self.styleDir.files("*.html") styleFiles += self.styleDir.files("*.ttf") styleFiles += self.styleDir.files("*.eot") styleFiles += self.styleDir.files("*.otf") styleFiles += self.styleDir.files("*.woff") self.styleDir.copylist(styleFiles, outputDir) # copy the package's resource files package.resourceDir.copyfiles(outputDir) # Export the package content self.pages = [ IMSPage("index", 1, package.root, metadataType=self.metadataType) ] self.generatePages(package.root, 2) uniquifyNames(self.pages) for page in self.pages: page.save(outputDir) # Create the manifest file manifest = Manifest(self.config, outputDir, package, self.pages, self.metadataType) manifest.save("imsmanifest.xml") # Copy the scripts # jQuery my_style = G.application.config.styleStore.getStyle( page.node.package.style) if my_style.hasValidConfig: if my_style.get_jquery() == True: jsFile = (self.scriptsDir / 'exe_jquery.js') jsFile.copyfile(outputDir / 'exe_jquery.js') else: jsFile = (self.scriptsDir / 'exe_jquery.js') jsFile.copyfile(outputDir / 'exe_jquery.js') jsFile = (self.scriptsDir / 'common.js') jsFile.copyfile(outputDir / 'common.js') dT = common.getExportDocType() if dT == "HTML5": jsFile = (self.scriptsDir / 'exe_html5.js') jsFile.copyfile(outputDir / 'exe_html5.js') self.schemasDir.copylist(('imscp_v1p1.xsd', 'imsmd_v1p2p2.xsd', 'lom.xsd', 'lomCustom.xsd', 'ims_xml.xsd'), outputDir) # copy players for media idevices. hasFlowplayer = False hasMagnifier = False hasXspfplayer = False hasGallery = False hasFX = False hasSH = False hasGames = False hasWikipedia = False isBreak = False hasInstructions = False hasMediaelement = False hasTooltips = False for page in self.pages: if isBreak: break for idevice in page.node.idevices: if (hasFlowplayer and hasMagnifier and hasXspfplayer and hasGallery and hasFX and hasSH and hasGames and hasWikipedia and hasInstructions and hasMediaelement and hasTooltips): isBreak = True break if not hasFlowplayer: if 'flowPlayer.swf' in idevice.systemResources: hasFlowplayer = True if not hasMagnifier: if 'mojomagnify.js' in idevice.systemResources: hasMagnifier = True if not hasXspfplayer: if 'xspf_player.swf' in idevice.systemResources: hasXspfplayer = True if not hasGallery: hasGallery = common.ideviceHasGallery(idevice) if not hasFX: hasFX = common.ideviceHasFX(idevice) if not hasSH: hasSH = common.ideviceHasSH(idevice) if not hasGames: hasGames = common.ideviceHasGames(idevice) if not hasWikipedia: if 'WikipediaIdevice' == idevice.klass: hasWikipedia = True if not hasInstructions: if 'TrueFalseIdevice' == idevice.klass or 'MultichoiceIdevice' == idevice.klass or 'VerdaderofalsofpdIdevice' == idevice.klass or 'EleccionmultiplefpdIdevice' == idevice.klass: hasInstructions = True if not hasMediaelement: hasMediaelement = common.ideviceHasMediaelement(idevice) if not hasTooltips: hasTooltips = common.ideviceHasTooltips(idevice) if hasFlowplayer: videofile = (self.templatesDir / 'flowPlayer.swf') videofile.copyfile(outputDir / 'flowPlayer.swf') controlsfile = (self.templatesDir / 'flowplayer.controls.swf') controlsfile.copyfile(outputDir / 'flowplayer.controls.swf') if hasMagnifier: videofile = (self.templatesDir / 'mojomagnify.js') videofile.copyfile(outputDir / 'mojomagnify.js') if hasXspfplayer: videofile = (self.templatesDir / 'xspf_player.swf') videofile.copyfile(outputDir / 'xspf_player.swf') if hasGallery: exeLightbox = (self.scriptsDir / 'exe_lightbox') exeLightbox.copyfiles(outputDir) if hasFX: exeEffects = (self.scriptsDir / 'exe_effects') exeEffects.copyfiles(outputDir) if hasSH: exeSH = (self.scriptsDir / 'exe_highlighter') exeSH.copyfiles(outputDir) if hasGames: exeGames = (self.scriptsDir / 'exe_games') exeGames.copyfiles(outputDir) if hasWikipedia: wikipediaCSS = (self.cssDir / 'exe_wikipedia.css') wikipediaCSS.copyfile(outputDir / 'exe_wikipedia.css') if hasInstructions: common.copyFileIfNotInStyle('panel-amusements.png', self, outputDir) common.copyFileIfNotInStyle('stock-stop.png', self, outputDir) if hasMediaelement: mediaelement = (self.scriptsDir / 'mediaelement') mediaelement.copyfiles(outputDir) if dT != "HTML5": jsFile = (self.scriptsDir / 'exe_html5.js') jsFile.copyfile(outputDir / 'exe_html5.js') if hasTooltips: exe_tooltips = (self.scriptsDir / 'exe_tooltips') exe_tooltips.copyfiles(outputDir) if hasattr(package, 'exportSource') and package.exportSource: (G.application.config.webDir / 'templates' / 'content.xsd').copyfile(outputDir / 'content.xsd') (outputDir / 'content.data').write_bytes(encodeObject(package)) (outputDir / 'contentv3.xml').write_bytes( encodeObjectToXML(package)) if package.license == "license GFDL": # include a copy of the GNU Free Documentation Licence (self.templatesDir / 'fdl.html').copyfile(outputDir / 'fdl.html') # Zip it up! self.filename.safeSave( self.doZip, _('EXPORT FAILED!\nLast succesful export is %s.'), outputDir) # Clean up the temporary dir outputDir.rmtree() def doZip(self, fileObj, outputDir): """ Actually does the zipping of the file. Called by 'Path.safeSave' """ zipped = ZipFile(fileObj, "w") for scormFile in outputDir.files(): zipped.write(scormFile, scormFile.basename().encode('utf8'), ZIP_DEFLATED) zipped.close() def generatePages(self, node, depth): """ Recursive function for exporting a node. 'outputDir' is the temporary directory that we are exporting to before creating zip file """ for child in node.children: pageName = child.titleShort.lower().replace(" ", "_") pageName = re.sub(r"\W", "", pageName) if not pageName: pageName = "__" page = IMSPage(pageName, depth, child, metadataType=self.metadataType) self.pages.append(page) self.generatePages(child, depth + 1)
class SinglePageExport(object): """ SinglePageExport will export a package as a website of HTML pages """ def __init__(self, stylesDir, outputDir, imagesDir, scriptsDir, cssDir, templatesDir): """ 'stylesDir' is the directory where we can copy the stylesheets from 'outputDir' is the directory that will be [over]written with the website """ self.html = "" self.style = None self.name = None self.stylesDir = Path(stylesDir) self.outputDir = Path(outputDir) self.imagesDir = Path(imagesDir) self.scriptsDir = Path(scriptsDir) self.cssDir = Path(cssDir) self.templatesDir = Path(templatesDir) self.page = None # Create the output dir if it doesn't already exist if not self.outputDir.exists(): self.outputDir.mkdir() def export(self, package, for_print=0): """ Export web site Cleans up the previous packages pages and performs the export """ self.style = package.style self.page = SinglePage("index", 1, package.root) ext = 'html' if G.application.config.cutFileName == "1": ext = 'htm' self.page.save(self.outputDir/"index" + '.' + ext, for_print) if hasattr(package, 'exportSource') and package.exportSource and not for_print: (G.application.config.webDir/'templates'/'content.xsd').copyfile(self.outputDir/'content.xsd') (self.outputDir/'content.data').write_bytes(encodeObject(package)) (self.outputDir/'contentv3.xml').write_bytes(encodeObjectToXML(package)) self.copyFiles(package) def copyFiles(self, package): """ Copy all the files used by the website. """ # Copy the style files to the output dir # But not nav.css if os.path.isdir(self.stylesDir): styleFiles = [self.stylesDir/'..'/'popup_bg.gif'] styleFiles += self.stylesDir.files("*.*") if "nav.css" in styleFiles: styleFiles.remove("nav.css") self.stylesDir.copylist(styleFiles, self.outputDir) # copy the package's resource files for resourceFile in package.resourceDir.walkfiles(): file = package.resourceDir.relpathto(resourceFile) if ("/" in file): Dir = Path(self.outputDir/file[:file.rindex("/")]) if not Dir.exists(): Dir.makedirs() resourceFile.copy(self.outputDir/Dir) else: resourceFile.copy(self.outputDir) listCSSFiles=getFilesCSSToMinify('singlepage', self.stylesDir) exportMinFileCSS(listCSSFiles, self.outputDir) # copy script files. my_style = G.application.config.styleStore.getStyle(package.style) # jQuery if my_style.hasValidConfig: if my_style.get_jquery() == True: jsFile = (self.scriptsDir/'exe_jquery.js') jsFile.copyfile(self.outputDir/'exe_jquery.js') else: jsFile = (self.scriptsDir/'exe_jquery.js') jsFile.copyfile(self.outputDir/'exe_jquery.js') dT = common.getExportDocType() if dT == "HTML5": jsFile = (self.scriptsDir/'exe_html5.js') jsFile.copyfile(self.outputDir/'exe_html5.js') # Minify common.js file listFiles=getFilesJSToMinify('singlepage', self.scriptsDir) exportMinFileJS(listFiles, self.outputDir) # Create lang file langFile = open(self.outputDir + '/common_i18n.js', "w") langFile.write(common.getJavaScriptStrings(False)) langFile.close() # Incluide eXe's icon if the Style doesn't have one themePath = Path(G.application.config.stylesDir/package.style) themeFavicon = themePath.joinpath("favicon.ico") if not themeFavicon.exists(): faviconFile = (self.imagesDir/'favicon.ico') faviconFile.copyfile(self.outputDir/'favicon.ico') #JR Metemos los reproductores necesarios self.compruebaReproductores(self.page.node) if package.license == "license GFDL": # include a copy of the GNU Free Documentation Licence ext = 'html' if G.application.config.cutFileName == "1": ext = 'htm' (self.templatesDir/'fdl' + '.' + ext).copyfile(self.outputDir/'fdl' + '.' + ext) def compruebaReproductores(self, node): """ Comprobamos si hay que meter algun reproductor """ # copy players for media idevices. hasFlowplayer = False hasMagnifier = False hasXspfplayer = False hasGallery = False hasFX = False hasSH = False hasGames = False hasElpLink = False hasWikipedia = False hasInstructions = False hasMediaelement = False hasTooltips = False hasABCMusic = False listIdevicesFiles = [] for idevice in node.idevices: if (hasFlowplayer and hasMagnifier and hasXspfplayer and hasGallery and hasFX and hasSH and hasGames and hasElpLink and hasWikipedia and hasInstructions and hasMediaelement and hasTooltips and hasABCMusic): break if not hasFlowplayer: if 'flowPlayer.swf' in idevice.systemResources: hasFlowplayer = True if not hasMagnifier: if 'mojomagnify.js' in idevice.systemResources: hasMagnifier = True if not hasXspfplayer: if 'xspf_player.swf' in idevice.systemResources: hasXspfplayer = True if not hasGallery: hasGallery = common.ideviceHasGallery(idevice) if not hasFX: hasFX = common.ideviceHasFX(idevice) if not hasSH: hasSH = common.ideviceHasSH(idevice) if not hasGames: hasGames = common.ideviceHasGames(idevice) if not hasElpLink: hasElpLink = common.ideviceHasElpLink(idevice,self.page.node.package) if not hasWikipedia: if 'WikipediaIdevice' == idevice.klass: hasWikipedia = True if not hasInstructions: if 'TrueFalseIdevice' == idevice.klass or 'MultichoiceIdevice' == idevice.klass or 'VerdaderofalsofpdIdevice' == idevice.klass or 'EleccionmultiplefpdIdevice' == idevice.klass: hasInstructions = True if not hasMediaelement: hasMediaelement = common.ideviceHasMediaelement(idevice) if not hasTooltips: hasTooltips = common.ideviceHasTooltips(idevice) if not hasABCMusic: hasABCMusic = common.ideviceHasABCMusic(idevice) if hasattr(idevice, "_iDeviceDir"): listIdevicesFiles.append((Path(idevice._iDeviceDir)/'export')) if hasFlowplayer: videofile = (self.templatesDir/'flowPlayer.swf') videofile.copyfile(self.outputDir/'flowPlayer.swf') controlsfile = (self.templatesDir/'flowplayer.controls.swf') controlsfile.copyfile(self.outputDir/'flowplayer.controls.swf') if hasMagnifier: videofile = (self.templatesDir/'mojomagnify.js') videofile.copyfile(self.outputDir/'mojomagnify.js') if hasXspfplayer: videofile = (self.templatesDir/'xspf_player.swf') videofile.copyfile(self.outputDir/'xspf_player.swf') if hasGallery: exeLightbox = (self.scriptsDir/'exe_lightbox') exeLightbox.copyfiles(self.outputDir) if hasFX: exeEffects = (self.scriptsDir/'exe_effects') exeEffects.copyfiles(self.outputDir) if hasSH: exeSH = (self.scriptsDir/'exe_highlighter') exeSH.copyfiles(self.outputDir) if hasGames: exeGames = (self.scriptsDir/'exe_games') exeGames.copyfiles(self.outputDir) # Add game js string to common_i18n langGameFile = open(self.outputDir + '/common_i18n.js', "a") langGameFile.write(common.getGamesJavaScriptStrings(False)) langGameFile.close() if hasElpLink or self.page.node.package.get_exportElp(): # Export the elp file currentPackagePath = Path(self.page.node.package.filename) currentPackagePath.copyfile(self.outputDir/self.page.node.package.name+'.elp') if hasWikipedia: wikipediaCSS = (self.cssDir/'exe_wikipedia.css') wikipediaCSS.copyfile(self.outputDir/'exe_wikipedia.css') if hasInstructions: common.copyFileIfNotInStyle('panel-amusements.png', self, self.outputDir) common.copyFileIfNotInStyle('stock-stop.png', self, self.outputDir) if hasMediaelement: mediaelement = (self.scriptsDir/'mediaelement') mediaelement.copyfiles(self.outputDir) dT = common.getExportDocType() if dT != "HTML5": jsFile = (self.scriptsDir/'exe_html5.js') jsFile.copyfile(self.outputDir/'exe_html5.js') if hasTooltips: exe_tooltips = (self.scriptsDir/'exe_tooltips') exe_tooltips.copyfiles(self.outputDir) if hasABCMusic: pluginScripts = (self.scriptsDir/'tinymce_4/js/tinymce/plugins/abcmusic/export') pluginScripts.copyfiles(self.outputDir) for child in node.children: self.compruebaReproductores(child) common.exportJavaScriptIdevicesFiles(node.idevices, self.outputDir) def hasUncutResources(self): """ Check if any of the resources in the exported package has an uncut filename """ for idevice in self.page.node.idevices: for resource in idevice.userResources: if type(resource) == Resource and len(resource.storageName) > 12: return True return False
class SinglePageExport(object): """ SinglePageExport will export a package as a website of HTML pages """ def __init__(self, stylesDir, outputDir, imagesDir, scriptsDir, cssDir, templatesDir): """ 'stylesDir' is the directory where we can copy the stylesheets from 'outputDir' is the directory that will be [over]written with the website """ self.html = "" self.style = None self.name = None self.stylesDir = Path(stylesDir) self.outputDir = Path(outputDir) self.imagesDir = Path(imagesDir) self.scriptsDir = Path(scriptsDir) self.cssDir = Path(cssDir) self.templatesDir = Path(templatesDir) self.page = None # Create the output dir if it doesn't already exist if not self.outputDir.exists(): self.outputDir.mkdir() def export(self, package, for_print=0): """ Export web site Cleans up the previous packages pages and performs the export """ self.style = package.style self.page = SinglePage("index", 1, package.root) self.page.save(self.outputDir/"index.html", for_print) if hasattr(package, 'exportSource') and package.exportSource and not for_print: (G.application.config.webDir/'templates'/'content.xsd').copyfile(self.outputDir/'content.xsd') (self.outputDir/'content.data').write_bytes(encodeObject(package)) (self.outputDir/'contentv3.xml').write_bytes(encodeObjectToXML(package)) self.copyFiles(package) def copyFiles(self, package): """ Copy all the files used by the website. """ # Copy the style sheet files to the output dir # But not nav.css if os.path.isdir(self.stylesDir): # Copy the style sheet files to the output dir styleFiles = [self.stylesDir/'..'/'base.css'] styleFiles += [self.stylesDir/'..'/'popup_bg.gif'] styleFiles += self.stylesDir.files("*.css") if "nav.css" in styleFiles: styleFiles.remove("nav.css") styleFiles += self.stylesDir.files("*.jpg") styleFiles += self.stylesDir.files("*.gif") styleFiles += self.stylesDir.files("*.png") styleFiles += self.stylesDir.files("*.js") styleFiles += self.stylesDir.files("*.html") styleFiles += self.stylesDir.files("*.ico") styleFiles += self.stylesDir.files("*.ttf") styleFiles += self.stylesDir.files("*.eot") styleFiles += self.stylesDir.files("*.otf") styleFiles += self.stylesDir.files("*.woff") self.stylesDir.copylist(styleFiles, self.outputDir) # copy the package's resource files package.resourceDir.copyfiles(self.outputDir) # copy script files. my_style = G.application.config.styleStore.getStyle(package.style) # jQuery if my_style.hasValidConfig: if my_style.get_jquery() == True: jsFile = (self.scriptsDir/'exe_jquery.js') jsFile.copyfile(self.outputDir/'exe_jquery.js') else: jsFile = (self.scriptsDir/'exe_jquery.js') jsFile.copyfile(self.outputDir/'exe_jquery.js') jsFile = (self.scriptsDir/'common.js') jsFile.copyfile(self.outputDir/'common.js') jsFile = (self.scriptsDir/'lernmodule_net.js') jsFile.copyfile(self.outputDir/'lernmodule_net.js') dT = common.getExportDocType() if dT == "HTML5": jsFile = (self.scriptsDir/'exe_html5.js') jsFile.copyfile(self.outputDir/'exe_html5.js') # Incluide eXe's icon if the Style doesn't have one themePath = Path(G.application.config.stylesDir/package.style) themeFavicon = themePath.joinpath("favicon.ico") if not themeFavicon.exists(): faviconFile = (self.imagesDir/'favicon.ico') faviconFile.copyfile(self.outputDir/'favicon.ico') #JR Metemos los reproductores necesarios self.compruebaReproductores(self.page.node) if package.license == "license GFDL": # include a copy of the GNU Free Documentation Licence (self.templatesDir/'fdl.html').copyfile(self.outputDir/'fdl.html') def compruebaReproductores(self, node): """ Comprobamos si hay que meter algun reproductor """ # copy players for media idevices. hasFlowplayer = False hasMagnifier = False hasXspfplayer = False hasGallery = False hasWikipedia = False hasInstructions = False hasMediaelement = False for idevice in node.idevices: if (hasFlowplayer and hasMagnifier and hasXspfplayer and hasGallery and hasWikipedia and hasInstructions and hasMediaelement): break if not hasFlowplayer: if 'flowPlayer.swf' in idevice.systemResources: hasFlowplayer = True if not hasMagnifier: if 'mojomagnify.js' in idevice.systemResources: hasMagnifier = True if not hasXspfplayer: if 'xspf_player.swf' in idevice.systemResources: hasXspfplayer = True if not hasGallery: hasGallery = common.ideviceHasGallery(idevice) if not hasWikipedia: if 'WikipediaIdevice' == idevice.klass: hasWikipedia = True if not hasInstructions: if 'TrueFalseIdevice' == idevice.klass or 'MultichoiceIdevice' == idevice.klass or 'VerdaderofalsofpdIdevice' == idevice.klass or 'EleccionmultiplefpdIdevice' == idevice.klass: hasInstructions = True if not hasMediaelement: hasMediaelement = common.ideviceHasMediaelement(idevice) if hasFlowplayer: videofile = (self.templatesDir/'flowPlayer.swf') videofile.copyfile(self.outputDir/'flowPlayer.swf') controlsfile = (self.templatesDir/'flowplayer.controls.swf') controlsfile.copyfile(self.outputDir/'flowplayer.controls.swf') if hasMagnifier: videofile = (self.templatesDir/'mojomagnify.js') videofile.copyfile(self.outputDir/'mojomagnify.js') if hasXspfplayer: videofile = (self.templatesDir/'xspf_player.swf') videofile.copyfile(self.outputDir/'xspf_player.swf') if hasGallery: imageGalleryCSS = (self.cssDir/'exe_lightbox.css') imageGalleryCSS.copyfile(self.outputDir/'exe_lightbox.css') imageGalleryJS = (self.scriptsDir/'exe_lightbox.js') imageGalleryJS.copyfile(self.outputDir/'exe_lightbox.js') self.imagesDir.copylist(('exe_lightbox_close.png', 'exe_lightbox_loading.gif', 'exe_lightbox_next.png', 'exe_lightbox_prev.png'), self.outputDir) if hasWikipedia: wikipediaCSS = (self.cssDir/'exe_wikipedia.css') wikipediaCSS.copyfile(self.outputDir/'exe_wikipedia.css') if hasInstructions: common.copyFileIfNotInStyle('panel-amusements.png', self, self.outputDir) common.copyFileIfNotInStyle('stock-stop.png', self, self.outputDir) if hasMediaelement: mediaelement = (self.scriptsDir/'mediaelement') mediaelement.copyfiles(self.outputDir) dT = common.getExportDocType() if dT != "HTML5": jsFile = (self.scriptsDir/'exe_html5.js') jsFile.copyfile(self.outputDir/'exe_html5.js') for child in node.children: self.compruebaReproductores(child)
class IMSExport(object): """ Exports an eXe package as a SCORM package """ def __init__(self, config, styleDir, filename): """ Initialize 'styleDir' is the directory from which we will copy our style sheets (and some gifs) """ self.config = config self.imagesDir = config.webDir/"images" self.scriptsDir = config.webDir/"scripts" self.cssDir = config.webDir/"css" self.templatesDir = config.webDir/"templates" self.schemasDir = config.webDir/"schemas/ims" self.styleDir = Path(styleDir) self.filename = Path(filename) self.pages = [] def export(self, package): """ Export SCORM package """ # First do the export to a temporary directory outputDir = TempDirPath() # Copy the style sheet files to the output dir # But not nav.css styleFiles = [self.styleDir/'..'/'base.css'] styleFiles += [self.styleDir/'..'/'popup_bg.gif'] styleFiles += self.styleDir.files("*.css") if "nav.css" in styleFiles: styleFiles.remove("nav.css") styleFiles += self.styleDir.files("*.jpg") styleFiles += self.styleDir.files("*.gif") styleFiles += self.styleDir.files("*.png") styleFiles += self.styleDir.files("*.js") styleFiles += self.styleDir.files("*.html") styleFiles += self.styleDir.files("*.ttf") styleFiles += self.styleDir.files("*.eot") styleFiles += self.styleDir.files("*.otf") styleFiles += self.styleDir.files("*.woff") self.styleDir.copylist(styleFiles, outputDir) # copy the package's resource files package.resourceDir.copyfiles(outputDir) # Export the package content self.pages = [ IMSPage("index", 1, package.root) ] self.generatePages(package.root, 2) uniquifyNames(self.pages) for page in self.pages: page.save(outputDir) # Create the manifest file manifest = Manifest(self.config, outputDir, package, self.pages) manifest.save() # Copy the scripts self.scriptsDir.copylist(('libot_drag.js', 'common.js'), outputDir) self.schemasDir.copylist(('imscp_v1p1.xsd', 'imsmd_v1p2p2.xsd', 'ims_xml.xsd'), outputDir) # copy players for media idevices. hasFlowplayer = False hasMagnifier = False hasXspfplayer = False hasGallery = False isBreak = False for page in self.pages: if isBreak: break for idevice in page.node.idevices: if (hasFlowplayer and hasMagnifier and hasXspfplayer and hasGallery): isBreak = True break if not hasFlowplayer: if 'flowPlayer.swf' in idevice.systemResources: hasFlowplayer = True if not hasMagnifier: if 'magnifier.swf' in idevice.systemResources: hasMagnifier = True if not hasXspfplayer: if 'xspf_player.swf' in idevice.systemResources: hasXspfplayer = True if not hasGallery: if 'GalleryIdevice' == idevice.klass: hasGallery = True if hasFlowplayer: videofile = (self.templatesDir/'flowPlayer.swf') videofile.copyfile(outputDir/'flowPlayer.swf') controlsfile = (self.templatesDir/'flowplayer.controls.swf') controlsfile.copyfile(outputDir/'flowplayer.controls.swf') if hasMagnifier: videofile = (self.templatesDir/'magnifier.swf') videofile.copyfile(outputDir/'magnifier.swf') if hasXspfplayer: videofile = (self.templatesDir/'xspf_player.swf') videofile.copyfile(outputDir/'xspf_player.swf') if hasGallery: imageGalleryCSS = (self.cssDir/'exe_lightbox.css') imageGalleryCSS.copyfile(outputDir/'exe_lightbox.css') imageGalleryJS = (self.scriptsDir/'exe_lightbox.js') imageGalleryJS.copyfile(outputDir/'exe_lightbox.js') self.imagesDir.copylist(('exeGallery_actions.png', 'exeGallery_loading.gif', 'stock-insert-image.png'), outputDir) if package.license == "GNU Free Documentation License": # include a copy of the GNU Free Documentation Licence (self.templatesDir/'fdl.html').copyfile(outputDir/'fdl.html') # Zip it up! self.filename.safeSave(self.doZip, _('EXPORT FAILED!\nLast succesful export is %s.'), outputDir) # Clean up the temporary dir outputDir.rmtree() def doZip(self, fileObj, outputDir): """ Actually does the zipping of the file. Called by 'Path.safeSave' """ zipped = ZipFile(fileObj, "w") for scormFile in outputDir.files(): zipped.write(scormFile, scormFile.basename().encode('utf8'), ZIP_DEFLATED) zipped.close() def generatePages(self, node, depth): """ Recursive function for exporting a node. 'outputDir' is the temporary directory that we are exporting to before creating zip file """ for child in node.children: pageName = child.titleShort.lower().replace(" ", "_") pageName = re.sub(r"\W", "", pageName) if not pageName: pageName = "__" page = IMSPage(pageName, depth, child) self.pages.append(page) self.generatePages(child, depth + 1)
class ScormExport(object): """ Exports an eXe package as a SCORM package """ def __init__(self, config, styleDir, filename, scormType): """ Initialize 'styleDir' is the directory from which we will copy our style sheets (and some gifs) """ self.config = config self.imagesDir = config.webDir / "images" self.scriptsDir = config.webDir / "scripts" self.cssDir = config.webDir / "css" self.templatesDir = config.webDir / "templates" self.schemasDir = config.webDir / "schemas" self.styleDir = Path(styleDir) self.filename = Path(filename) self.pages = [] self.hasForum = False self.scormType = scormType self.styleSecureMode = config.styleSecureMode def export(self, package): """ Export SCORM package """ # First do the export to a temporary directory outputDir = TempDirPath() self.metadataType = package.exportMetadataType # copy the package's resource files package.resourceDir.copyfiles(outputDir) # copy the package's resource files, only non existant in outputDir # outputDirFiles = outputDir.files() # for rfile in package.resourceDir.files(): # if rfile not in outputDirFiles: # rfile.copy(outputDir) # copy the package's resource files, only indexed in package.resources # for md5 in package.resources.values(): # for resource in md5: # resource.path.copy(outputDir) # Export the package content # Import the Scorm Page class , if the secure mode is off. If the style has it's own page class # use that, else use the default one. if self.styleSecureMode == "0": if (self.styleDir / "scormpage.py").exists(): global ScormPage module = imp.load_source("ScormPage", self.styleDir / "scormpage.py") ScormPage = module.ScormPage self.pages = [ScormPage("index", 1, package.root, scormType=self.scormType, metadataType=self.metadataType)] self.generatePages(package.root, 2) uniquifyNames(self.pages) for page in self.pages: page.save(outputDir) if not self.hasForum: for idevice in page.node.idevices: if hasattr(idevice, "isForum"): if idevice.forum.lms.lms == "moodle": self.hasForum = True break # Create the manifest file manifest = Manifest(self.config, outputDir, package, self.pages, self.scormType, self.metadataType) manifest.save("imsmanifest.xml") if self.hasForum: manifest.save("discussionforum.xml") # Copy the style sheet files to the output dir styleFiles = [self.styleDir / ".." / "base.css"] styleFiles += [self.styleDir / ".." / "popup_bg.gif"] # And with all the files of the style we avoid problems: styleFiles += self.styleDir.files("*.*") if self.scormType == "commoncartridge": for sf in styleFiles[:]: if sf.basename() not in manifest.dependencies: styleFiles.remove(sf) self.styleDir.copylist(styleFiles, outputDir) # Copy the scripts dT = common.getExportDocType() if dT == "HTML5": jsFile = self.scriptsDir / "exe_html5.js" jsFile.copyfile(outputDir / "exe_html5.js") # jQuery my_style = G.application.config.styleStore.getStyle(page.node.package.style) if my_style.hasValidConfig: if my_style.get_jquery() == True: jsFile = self.scriptsDir / "exe_jquery.js" jsFile.copyfile(outputDir / "exe_jquery.js") else: jsFile = self.scriptsDir / "exe_jquery.js" jsFile.copyfile(outputDir / "exe_jquery.js") if self.scormType == "commoncartridge": jsFile = self.scriptsDir / "common.js" jsFile.copyfile(outputDir / "common.js") if self.scormType == "scorm2004" or self.scormType == "scorm1.2": self.scriptsDir.copylist(("SCORM_API_wrapper.js", "SCOFunctions.js", "common.js"), outputDir) # about SCHEMAS: schemasDir = "" if self.scormType == "scorm1.2": schemasDir = self.schemasDir / "scorm1.2" schemasDir.copylist( ( "imscp_rootv1p1p2.xsd", "imsmd_rootv1p2p1.xsd", "adlcp_rootv1p2.xsd", "lom.xsd", "lomCustom.xsd", "ims_xml.xsd", ), outputDir, ) elif self.scormType == "scorm2004": schemasDir = self.schemasDir / "scorm2004" schemasDir.copylist( ( "adlcp_v1p3.xsd", "adlnav_v1p3.xsd", "adlseq_v1p3.xsd", "datatypes.dtd", "imscp_v1p1.xsd", "imsssp_v1p0.xsd", "imsss_v1p0.xsd", "imsss_v1p0auxresource.xsd", "imsss_v1p0control.xsd", "imsss_v1p0delivery.xsd", "imsmd_rootv1p2p1.xsd", "imsss_v1p0limit.xsd", "imsss_v1p0objective.xsd", "imsss_v1p0random.xsd", "imsss_v1p0rollup.xsd", "imsss_v1p0seqrule.xsd", "imsss_v1p0util.xsd", "ims_xml.xsd", "lom.xsd", "lomCustom.xsd", "xml.xsd", "XMLSchema.dtd", ), outputDir, ) try: import shutil, errno shutil.copytree(schemasDir / "common", outputDir / "common") shutil.copytree(schemasDir / "extend", outputDir / "extend") shutil.copytree(schemasDir / "unique", outputDir / "unique") shutil.copytree(schemasDir / "vocab", outputDir / "vocab") except OSError as exc: if exc.errno == errno.ENOTDIR: shutil.copy(schemasDir, outputDir) else: raise # copy players for media idevices. hasFlowplayer = False hasMagnifier = False hasXspfplayer = False hasGallery = False hasWikipedia = False isBreak = False hasInstructions = False hasMediaelement = False for page in self.pages: if isBreak: break for idevice in page.node.idevices: if ( hasFlowplayer and hasMagnifier and hasXspfplayer and hasGallery and hasWikipedia and hasInstructions and hasMediaelement ): isBreak = True break if not hasFlowplayer: if "flowPlayer.swf" in idevice.systemResources: hasFlowplayer = True if not hasMagnifier: if "mojomagnify.js" in idevice.systemResources: hasMagnifier = True if not hasXspfplayer: if "xspf_player.swf" in idevice.systemResources: hasXspfplayer = True if not hasGallery: hasGallery = common.ideviceHasGallery(idevice) if not hasWikipedia: if "WikipediaIdevice" == idevice.klass: hasWikipedia = True if not hasInstructions: if ( "TrueFalseIdevice" == idevice.klass or "MultichoiceIdevice" == idevice.klass or "VerdaderofalsofpdIdevice" == idevice.klass or "EleccionmultiplefpdIdevice" == idevice.klass ): hasInstructions = True if not hasMediaelement: hasMediaelement = common.ideviceHasMediaelement(idevice) if hasFlowplayer: videofile = self.templatesDir / "flowPlayer.swf" videofile.copyfile(outputDir / "flowPlayer.swf") controlsfile = self.templatesDir / "flowplayer.controls.swf" controlsfile.copyfile(outputDir / "flowplayer.controls.swf") if hasMagnifier: videofile = self.templatesDir / "mojomagnify.js" videofile.copyfile(outputDir / "mojomagnify.js") if hasXspfplayer: videofile = self.templatesDir / "xspf_player.swf" videofile.copyfile(outputDir / "xspf_player.swf") if hasGallery: imageGalleryCSS = self.cssDir / "exe_lightbox.css" imageGalleryCSS.copyfile(outputDir / "exe_lightbox.css") imageGalleryJS = self.scriptsDir / "exe_lightbox.js" imageGalleryJS.copyfile(outputDir / "exe_lightbox.js") self.imagesDir.copylist( ( "exe_lightbox_close.png", "exe_lightbox_loading.gif", "exe_lightbox_next.png", "exe_lightbox_prev.png", ), outputDir, ) if hasWikipedia: wikipediaCSS = self.cssDir / "exe_wikipedia.css" wikipediaCSS.copyfile(outputDir / "exe_wikipedia.css") if hasInstructions: common.copyFileIfNotInStyle("panel-amusements.png", self, outputDir) common.copyFileIfNotInStyle("stock-stop.png", self, outputDir) if hasMediaelement: mediaelement = self.scriptsDir / "mediaelement" mediaelement.copyfiles(outputDir) if dT != "HTML5": jsFile = self.scriptsDir / "exe_html5.js" if self.scormType == "scorm1.2" or self.scormType == "scorm2004": if package.license == "license GFDL": # include a copy of the GNU Free Documentation Licence (self.templatesDir / "fdl.html").copyfile(outputDir / "fdl.html") if hasattr(package, "scowsinglepage") and package.scowsinglepage: page = SinglePage("singlepage_index", 1, package.root) page.save(outputDir / "singlepage_index.html") # Incluide eXe's icon if the Style doesn't have one themePath = Path(G.application.config.stylesDir / package.style) themeFavicon = themePath.joinpath("favicon.ico") if not themeFavicon.exists(): faviconFile = self.imagesDir / "favicon.ico" faviconFile.copyfile(outputDir / "favicon.ico") if hasattr(package, "scowwebsite") and package.scowwebsite: website = WebsiteExport(self.config, self.styleDir, outputDir, "website_") website.export(package) (self.styleDir / "nav.css").copyfile(outputDir / "nav.css") # Incluide eXe's icon if the Style doesn't have one themePath = Path(G.application.config.stylesDir / package.style) themeFavicon = themePath.joinpath("favicon.ico") if not themeFavicon.exists(): faviconFile = self.imagesDir / "favicon.ico" faviconFile.copyfile(outputDir / "favicon.ico") if hasattr(package, "exportSource") and package.exportSource: (G.application.config.webDir / "templates" / "content.xsd").copyfile(outputDir / "content.xsd") (outputDir / "content.data").write_bytes(encodeObject(package)) (outputDir / "contentv3.xml").write_bytes(encodeObjectToXML(package)) # Zip it up! self.filename.safeSave(self.doZip, _("EXPORT FAILED!\nLast succesful export is %s."), outputDir) # Clean up the temporary dir outputDir.rmtree() def doZip(self, fileObj, outputDir): """ Actually does the zipping of the file. Called by 'Path.safeSave' """ # Zip up the scorm package zipped = ZipFile(fileObj, "w") ## old method: only files could be copied: # for scormFile in outputDir.files(): # zipped.write(scormFile, # scormFile.basename().encode('utf8'), # ZIP_DEFLATED) ## but some folders must be included also, so: outputlen = len(outputDir) + 1 for base, dirs, files in os.walk(outputDir): for file in files: fn = os.path.join(base, file) zipped.write(fn, fn[outputlen:].encode("utf8"), ZIP_DEFLATED) # zipped.close() def generatePages(self, node, depth): """ Recursive function for exporting a node. 'node' is the node that we are making a page for 'depth' is the number of ancestors that the page has +1 (ie. root is 1) """ for child in node.children: pageName = child.titleShort.lower().replace(" ", "_") pageName = re.sub(r"\W", "", pageName) if not pageName: pageName = "__" page = ScormPage(pageName, depth, child, scormType=self.scormType, metadataType=self.metadataType) self.pages.append(page) self.generatePages(child, depth + 1)
class SinglePageExport(object): """ SinglePageExport will export a package as a website of HTML pages """ def __init__(self, stylesDir, outputDir, imagesDir, scriptsDir, templatesDir): """ 'stylesDir' is the directory where we can copy the stylesheets from 'outputDir' is the directory that will be [over]written with the website """ self.html = "" self.style = None self.name = None self.stylesDir = Path(stylesDir) self.outputDir = Path(outputDir) self.imagesDir = Path(imagesDir) self.scriptsDir = Path(scriptsDir) self.templatesDir = Path(templatesDir) if not self.outputDir.exists(): self.outputDir.mkdir() def export(self, package): """ Export web site Cleans up the previous packages pages and performs the export """ self.style = package.style self.copyFiles(package) self.html = self.renderHeader(package.name) self.html += u"<body>\n" self.html += u"<div id=\"content\">\n" self.html += u"<div id=\"header\">\n" self.html += escape(package.title) self.html += u"</div>\n" self.html += u"<div id=\"main\">\n" self.renderNode(package.root) self.html += u"</div>\n" self.html += u"</div>\n" self.html += u"</body></html>\n" self.save(self.outputDir/"index.html") def copyFiles(self, package): """ Copy all the files used by the website. """ styleFiles = [self.stylesDir/'..'/'base.css'] styleFiles += [self.stylesDir/'..'/'popup_bg.gif'] styleFiles += self.stylesDir.files("*.css") if "nav.css" in styleFiles: styleFiles.remove("nav.css") styleFiles += self.stylesDir.files("*.jpg") styleFiles += self.stylesDir.files("*.gif") styleFiles += self.stylesDir.files("*.png") styleFiles += self.stylesDir.files("*.js") styleFiles += self.stylesDir.files("*.html") self.stylesDir.copylist(styleFiles, self.outputDir) package.resourceDir.copyfiles(self.outputDir) self.scriptsDir.copylist(('libot_drag.js', 'common.js'), self.outputDir) self.templatesDir.copylist(('videoContainer.swf', 'magnifier.swf', 'xspf_player.swf'),self.outputDir) (self.templatesDir/'fdl.html').copyfile(self.outputDir/'fdl.html') def renderHeader(self, name): """ Returns an XHTML string for the header of this page. """ html = u"<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n" html += u'<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 ' html += u'Transitional//EN" ' html += u'"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">\n' html += u"<html xmlns=\"http://www.w3.org/1999/xhtml\">\n" html += u"<head>\n" html += u"<style type=\"text/css\">\n" html += u"@import url(base.css);\n" html += u"@import url(content.css);\n" html += u"</style>" html += u"<title>" html += name html += "</title>\n" html += u"<meta http-equiv=\"Content-Type\" content=\"text/html; " html += u" charset=utf-8\" />\n"; html += u'<script type="text/javascript" src="common.js"></script>\n' html += u"</head>\n" return html def renderNode(self, node): """ Returns an XHTML string for this node and recurse for the children """ self.html += '<div id=\"nodeDecoration\">' self.html += '<p id=\"nodeTitle\">' self.html += escape(node.titleLong) self.html += '</p></div>\n' for idevice in node.idevices: block = g_blockFactory.createBlock(None, idevice) if not block: log.critical("Unable to render iDevice.") raise Error("Unable to render iDevice.") if hasattr(idevice, "isQuiz"): self.html += block.renderJavascriptForWeb() self.html += block.renderView(self.style) for child in node.children: self.renderNode(child) def save(self, filename): """ Save page to a file. 'outputDir' is the directory where the filenames will be saved (a 'path' instance) """ outfile = open(filename, "w") outfile.write(self.html.encode('utf8')) outfile.close()
class IMSExport(object): """ Exports an eXe package as a SCORM package """ def __init__(self, config, styleDir, filename): """ Initialize 'styleDir' is the directory from which we will copy our style sheets (and some gifs) """ self.config = config self.imagesDir = config.webDir/"images" self.scriptsDir = config.webDir/"scripts" self.cssDir = config.webDir/"css" self.templatesDir = config.webDir/"templates" self.schemasDir = config.webDir/"schemas/ims" self.styleDir = Path(styleDir) self.filename = Path(filename) self.pages = [] def export(self, package): """ Export SCORM package """ # First do the export to a temporary directory outputDir = TempDirPath() self.metadataType = package.exportMetadataType # Copy the style sheet files to the output dir # But not nav.css styleFiles = [self.styleDir/'..'/'popup_bg.gif'] styleFiles += self.styleDir.files("*.css") if "nav.css" in styleFiles: styleFiles.remove("nav.css") styleFiles += self.styleDir.files("*.jpg") styleFiles += self.styleDir.files("*.gif") styleFiles += self.styleDir.files("*.png") styleFiles += self.styleDir.files("*.js") styleFiles += self.styleDir.files("*.html") styleFiles += self.styleDir.files("*.ttf") styleFiles += self.styleDir.files("*.eot") styleFiles += self.styleDir.files("*.otf") styleFiles += self.styleDir.files("*.woff") self.styleDir.copylist(styleFiles, outputDir) # copy the package's resource files package.resourceDir.copyfiles(outputDir) listCSSFiles=getFilesCSSToMinify('ims', self.styleDir) exportMinFileCSS(listCSSFiles, outputDir) # Export the package content self.pages = [ IMSPage("index", 1, package.root, metadataType=self.metadataType) ] self.generatePages(package.root, 2) uniquifyNames(self.pages) for page in self.pages: page.save(outputDir) # Create the manifest file manifest = Manifest(self.config, outputDir, package, self.pages, self.metadataType) manifest.save("imsmanifest.xml") # Copy the scripts # jQuery my_style = G.application.config.styleStore.getStyle(page.node.package.style) if my_style.hasValidConfig: if my_style.get_jquery() == True: jsFile = (self.scriptsDir/'exe_jquery.js') jsFile.copyfile(outputDir/'exe_jquery.js') else: jsFile = (self.scriptsDir/'exe_jquery.js') jsFile.copyfile(outputDir/'exe_jquery.js') dT = common.getExportDocType() if dT == "HTML5": jsFile = (self.scriptsDir/'exe_html5.js') jsFile.copyfile(outputDir/'exe_html5.js') listFiles=getFilesJSToMinify('ims', self.scriptsDir) exportMinFileJS(listFiles, outputDir) self.schemasDir.copylist(('imscp_v1p1.xsd', 'imsmd_v1p2p2.xsd', 'lom.xsd', 'lomCustom.xsd', 'ims_xml.xsd'), outputDir) # copy players for media idevices. hasFlowplayer = False hasMagnifier = False hasXspfplayer = False hasGallery = False hasFX = False hasSH = False hasGames = False hasWikipedia = False isBreak = False hasInstructions = False hasMediaelement = False hasTooltips = False for page in self.pages: if isBreak: break for idevice in page.node.idevices: if (hasFlowplayer and hasMagnifier and hasXspfplayer and hasGallery and hasFX and hasSH and hasGames and hasWikipedia and hasInstructions and hasMediaelement and hasTooltips): isBreak = True break if not hasFlowplayer: if 'flowPlayer.swf' in idevice.systemResources: hasFlowplayer = True if not hasMagnifier: if 'mojomagnify.js' in idevice.systemResources: hasMagnifier = True if not hasXspfplayer: if 'xspf_player.swf' in idevice.systemResources: hasXspfplayer = True if not hasGallery: hasGallery = common.ideviceHasGallery(idevice) if not hasFX: hasFX = common.ideviceHasFX(idevice) if not hasSH: hasSH = common.ideviceHasSH(idevice) if not hasGames: hasGames = common.ideviceHasGames(idevice) if not hasWikipedia: if 'WikipediaIdevice' == idevice.klass: hasWikipedia = True if not hasInstructions: if 'TrueFalseIdevice' == idevice.klass or 'MultichoiceIdevice' == idevice.klass or 'VerdaderofalsofpdIdevice' == idevice.klass or 'EleccionmultiplefpdIdevice' == idevice.klass: hasInstructions = True if not hasMediaelement: hasMediaelement = common.ideviceHasMediaelement(idevice) if not hasTooltips: hasTooltips = common.ideviceHasTooltips(idevice) if hasFlowplayer: videofile = (self.templatesDir/'flowPlayer.swf') videofile.copyfile(outputDir/'flowPlayer.swf') controlsfile = (self.templatesDir/'flowplayer.controls.swf') controlsfile.copyfile(outputDir/'flowplayer.controls.swf') if hasMagnifier: videofile = (self.templatesDir/'mojomagnify.js') videofile.copyfile(outputDir/'mojomagnify.js') if hasXspfplayer: videofile = (self.templatesDir/'xspf_player.swf') videofile.copyfile(outputDir/'xspf_player.swf') if hasGallery: exeLightbox = (self.scriptsDir/'exe_lightbox') exeLightbox.copyfiles(outputDir) if hasFX: exeEffects = (self.scriptsDir/'exe_effects') exeEffects.copyfiles(outputDir) if hasSH: exeSH = (self.scriptsDir/'exe_highlighter') exeSH.copyfiles(outputDir) if hasGames: exeGames = (self.scriptsDir/'exe_games') exeGames.copyfiles(outputDir) if hasWikipedia: wikipediaCSS = (self.cssDir/'exe_wikipedia.css') wikipediaCSS.copyfile(outputDir/'exe_wikipedia.css') if hasInstructions: common.copyFileIfNotInStyle('panel-amusements.png', self, outputDir) common.copyFileIfNotInStyle('stock-stop.png', self, outputDir) if hasMediaelement: mediaelement = (self.scriptsDir/'mediaelement') mediaelement.copyfiles(outputDir) if dT != "HTML5": jsFile = (self.scriptsDir/'exe_html5.js') jsFile.copyfile(outputDir/'exe_html5.js') if hasTooltips: exe_tooltips = (self.scriptsDir/'exe_tooltips') exe_tooltips.copyfiles(outputDir) if hasattr(package, 'exportSource') and package.exportSource: (G.application.config.webDir/'templates'/'content.xsd').copyfile(outputDir/'content.xsd') (outputDir/'content.data').write_bytes(encodeObject(package)) (outputDir/'contentv3.xml').write_bytes(encodeObjectToXML(package)) if package.license == "license GFDL": # include a copy of the GNU Free Documentation Licence (self.templatesDir/'fdl.html').copyfile(outputDir/'fdl.html') # Zip it up! self.filename.safeSave(self.doZip, _('EXPORT FAILED!\nLast succesful export is %s.'), outputDir) # Clean up the temporary dir outputDir.rmtree() def doZip(self, fileObj, outputDir): """ Actually does the zipping of the file. Called by 'Path.safeSave' """ zipped = ZipFile(fileObj, "w") for scormFile in outputDir.files(): zipped.write(scormFile, scormFile.basename().encode('utf8'), ZIP_DEFLATED) zipped.close() def generatePages(self, node, depth): """ Recursive function for exporting a node. 'outputDir' is the temporary directory that we are exporting to before creating zip file """ for child in node.children: pageName = child.titleShort.lower().replace(" ", "_") pageName = re.sub(r"\W", "", pageName) if not pageName: pageName = "__" page = IMSPage(pageName, depth, child, metadataType=self.metadataType) self.pages.append(page) self.generatePages(child, depth + 1)
class SinglePageExport(object): """ SinglePageExport will export a package as a website of HTML pages """ def __init__(self, stylesDir, outputDir, imagesDir, scriptsDir, cssDir, templatesDir): """ 'stylesDir' is the directory where we can copy the stylesheets from 'outputDir' is the directory that will be [over]written with the website """ self.html = "" self.style = None self.name = None self.stylesDir = Path(stylesDir) self.outputDir = Path(outputDir) self.imagesDir = Path(imagesDir) self.scriptsDir = Path(scriptsDir) self.cssDir = Path(cssDir) self.templatesDir = Path(templatesDir) self.page = None # Create the output dir if it doesn't already exist if not self.outputDir.exists(): self.outputDir.mkdir() def export(self, package, for_print=0): """ Export web site Cleans up the previous packages pages and performs the export """ self.style = package.style self.page = SinglePage("index", 1, package.root) self.page.save(self.outputDir/"index.html", for_print) self.copyFiles(package) def copyFiles(self, package): """ Copy all the files used by the website. """ # Copy the style sheet files to the output dir # But not nav.css styleFiles = [self.stylesDir/'..'/'base.css'] styleFiles += [self.stylesDir/'..'/'popup_bg.gif'] styleFiles += self.stylesDir.files("*.css") if "nav.css" in styleFiles: styleFiles.remove("nav.css") styleFiles += self.stylesDir.files("*.jpg") styleFiles += self.stylesDir.files("*.gif") styleFiles += self.stylesDir.files("*.png") styleFiles += self.stylesDir.files("*.js") styleFiles += self.stylesDir.files("*.html") styleFiles += self.stylesDir.files("*.ico") styleFiles += self.stylesDir.files("*.ttf") styleFiles += self.stylesDir.files("*.eot") styleFiles += self.stylesDir.files("*.otf") styleFiles += self.stylesDir.files("*.woff") self.stylesDir.copylist(styleFiles, self.outputDir) # copy the package's resource files package.resourceDir.copyfiles(self.outputDir) # copy script files. self.scriptsDir.copylist(('libot_drag.js', 'common.js'), self.outputDir) #JR Metemos los reproductores necesarios self.compruebaReproductores(self.page.node) if package.license == "GNU Free Documentation License": # include a copy of the GNU Free Documentation Licence (self.templatesDir/'fdl.html').copyfile(self.outputDir/'fdl.html') def compruebaReproductores(self, node): """ Comprobamos si hay que meter algun reproductor """ # copy players for media idevices. hasFlowplayer = False hasMagnifier = False hasXspfplayer = False hasGallery = False for idevice in node.idevices: if (hasFlowplayer and hasMagnifier and hasXspfplayer and hasGallery): break if not hasFlowplayer: if 'flowPlayer.swf' in idevice.systemResources: hasFlowplayer = True if not hasMagnifier: if 'magnifier.swf' in idevice.systemResources: hasMagnifier = True if not hasXspfplayer: if 'xspf_player.swf' in idevice.systemResources: hasXspfplayer = True if not hasGallery: if 'GalleryIdevice' == idevice.klass: hasGallery = True if hasFlowplayer: videofile = (self.templatesDir/'flowPlayer.swf') videofile.copyfile(self.outputDir/'flowPlayer.swf') controlsfile = (self.templatesDir/'flowplayer.controls.swf') controlsfile.copyfile(self.outputDir/'flowplayer.controls.swf') if hasMagnifier: videofile = (self.templatesDir/'magnifier.swf') videofile.copyfile(self.outputDir/'magnifier.swf') if hasXspfplayer: videofile = (self.templatesDir/'xspf_player.swf') videofile.copyfile(self.outputDir/'xspf_player.swf') if hasGallery: imageGalleryCSS = (self.cssDir/'exe_lightbox.css') imageGalleryCSS.copyfile(self.outputDir/'exe_lightbox.css') imageGalleryJS = (self.scriptsDir/'exe_lightbox.js') imageGalleryJS.copyfile(self.outputDir/'exe_lightbox.js') self.imagesDir.copylist(('exeGallery_actions.png', 'exeGallery_loading.gif', 'stock-insert-image.png'), self.outputDir) for child in node.children: self.compruebaReproductores(child)
class ScormExport(object): """ Exports an eXe package as a SCORM package """ def __init__(self, config, styleDir, filename, scormType): """ Initialize 'styleDir' is the directory from which we will copy our style sheets (and some gifs) """ self.config = config self.imagesDir = config.webDir/"images" self.scriptsDir = config.webDir/"scripts" self.templatesDir = config.webDir/"templates" self.schemasDir = config.webDir/"schemas" self.styleDir = Path(styleDir) self.filename = Path(filename) self.pages = [] self.hasForum = False self.scormType = scormType def export(self, package): """ Export SCORM package """ # First do the export to a temporary directory outputDir = TempDirPath() # Export the package content self.pages = [ ScormPage("index", 1, package.root, scormType=self.scormType) ] self.generatePages(package.root, 2) uniquifyNames(self.pages) for page in self.pages: page.save(outputDir) if not self.hasForum: for idevice in page.node.idevices: if hasattr(idevice, "isForum"): if idevice.forum.lms.lms == "moodle": self.hasForum = True break # Create the manifest file manifest = Manifest(self.config, outputDir, package, self.pages, self.scormType) manifest.save("imsmanifest.xml") if self.hasForum: manifest.save("discussionforum.xml") # Copy the style sheet files to the output dir # But not nav.css styleFiles = [self.styleDir/'..'/'base.css'] styleFiles += [self.styleDir/'..'/'popup_bg.gif'] styleFiles += [f for f in self.styleDir.files("*.css") if f.basename() <> "nav.css"] styleFiles += self.styleDir.files("*.jpg") styleFiles += self.styleDir.files("*.gif") styleFiles += self.styleDir.files("*.png") styleFiles += self.styleDir.files("*.js") styleFiles += self.styleDir.files("*.html") # FIXME for now, only copy files referenced in Common Cartridge # this really should apply to all exports, but without a manifest # of the files needed by an included stylesheet it is too restrictive if self.scormType == "commoncartridge": for sf in styleFiles[:]: if sf.basename() not in manifest.dependencies: styleFiles.remove(sf) self.styleDir.copylist(styleFiles, outputDir) # copy the package's resource files package.resourceDir.copyfiles(outputDir) # Copy the scripts if self.scormType == "commoncartridge": self.scriptsDir.copylist(('libot_drag.js', 'common.js'), outputDir) else: self.scriptsDir.copylist(('APIWrapper.js', 'SCOFunctions.js', 'libot_drag.js', 'common.js'), outputDir) schemasDir = "" if self.scormType == "scorm1.2": schemasDir = self.schemasDir/"scorm1.2" schemasDir.copylist(('imscp_rootv1p1p2.xsd', 'imsmd_rootv1p2p1.xsd', 'adlcp_rootv1p2.xsd', 'ims_xml.xsd'), outputDir) elif self.scormType == "scorm2004": schemasDir = self.schemasDir/"scorm2004" schemasDir.copylist(('imscp_rootv1p1p2.xsd', 'imsmd_rootv1p2p1.xsd', 'adlcp_rootv1p2.xsd', 'ims_xml.xsd'), outputDir) # copy players for media idevices. hasFlowplayer = False hasMagnifier = False hasXspfplayer = False isBreak = False for page in self.pages: if isBreak: break for idevice in page.node.idevices: if (hasFlowplayer and hasMagnifier and hasXspfplayer): isBreak = True break if not hasFlowplayer: if 'flowPlayer.swf' in idevice.systemResources: hasFlowplayer = True if not hasMagnifier: if 'magnifier.swf' in idevice.systemResources: hasMagnifier = True if not hasXspfplayer: if 'xspf_player.swf' in idevice.systemResources: hasXspfplayer = True if hasFlowplayer: videofile = (self.templatesDir/'flowPlayer.swf') videofile.copyfile(outputDir/'flowPlayer.swf') if hasMagnifier: videofile = (self.templatesDir/'magnifier.swf') videofile.copyfile(outputDir/'magnifier.swf') if hasXspfplayer: videofile = (self.templatesDir/'xspf_player.swf') videofile.copyfile(outputDir/'xspf_player.swf') if self.scormType == "scorm1.2" or self.scormType == "scorm2004": if package.license == "GNU Free Documentation License": # include a copy of the GNU Free Documentation Licence (self.templatesDir/'fdl.html').copyfile(outputDir/'fdl.html') # Zip it up! self.filename.safeSave(self.doZip, _('EXPORT FAILED!\nLast succesful export is %s.'), outputDir) # Clean up the temporary dir outputDir.rmtree() def doZip(self, fileObj, outputDir): """ Actually does the zipping of the file. Called by 'Path.safeSave' """ # Zip up the scorm package zipped = ZipFile(fileObj, "w") for scormFile in outputDir.files(): zipped.write(scormFile, scormFile.basename().encode('utf8'), ZIP_DEFLATED) zipped.close() def generatePages(self, node, depth): """ Recursive function for exporting a node. 'node' is the node that we are making a page for 'depth' is the number of ancestors that the page has +1 (ie. root is 1) """ for child in node.children: pageName = child.titleShort.lower().replace(" ", "_") pageName = re.sub(r"\W", "", pageName) if not pageName: pageName = "__" page = ScormPage(pageName, depth, child, scormType=self.scormType) self.pages.append(page) self.generatePages(child, depth + 1)
class WebsiteExport(object): """ WebsiteExport will export a package as a website of HTML pages """ def __init__(self, config, styleDir, filename, prefix="", report=False): """ 'stylesDir' is the directory where we can copy the stylesheets from 'outputDir' is the directory that will be [over]written with the website """ self.config = config self.imagesDir = config.webDir / "images" self.scriptsDir = config.webDir / "scripts" self.cssDir = config.webDir / "css" self.templatesDir = config.webDir / "templates" self.stylesDir = Path(styleDir) self.filename = Path(filename) self.pages = [] self.prefix = prefix self.report = report self.styleSecureMode = config.styleSecureMode def exportZip(self, package): """ Export web site Cleans up the previous packages pages and performs the export """ outputDir = TempDirPath() # Import the Website Page class , if the secure mode is off. If the style has it's own page class # use that, else use the default one. if self.styleSecureMode == "0": if (self.stylesDir / "websitepage.py").exists(): global WebsitePage module = imp.load_source("websitepage", self.stylesDir / "websitepage.py") WebsitePage = module.WebsitePage self.pages = [WebsitePage("index", 0, package.root)] self.generatePages(package.root, 1) uniquifyNames(self.pages) prevPage = None thisPage = self.pages[0] for nextPage in self.pages[1:]: thisPage.save(outputDir, prevPage, nextPage, self.pages) prevPage = thisPage thisPage = nextPage thisPage.save(outputDir, prevPage, None, self.pages) self.copyFiles(package, outputDir) # Zip up the website package self.filename.safeSave( self.doZip, _('EXPORT FAILED!\nLast succesful export is %s.'), outputDir) # Clean up the temporary dir outputDir.rmtree() def doZip(self, fileObj, outputDir): """ Actually saves the zip data. Called by 'Path.safeSave' """ zipped = ZipFile(fileObj, "w") for scormFile in outputDir.files(): zipped.write(scormFile, scormFile.basename().encode('utf8'), ZIP_DEFLATED) zipped.close() def appendPageReport(self, page, package): if not page.node.idevices: self.report += u'"%s","%s",%d,"%s",,,,,,\n' % ( package.filename, page.node.title, page.depth, page.name + '.html') for idevice in page.node.idevices: if not idevice.userResources: self.report += u'"%s","%s",%d,"%s","%s","%s",,,,\n' % ( package.filename, page.node.title, page.depth, page.name + '.html', idevice.klass, idevice.title) for resource in idevice.userResources: if type(resource) == Resource: self.report += u'"%s","%s",%d,"%s","%s","%s","%s","%s","%s","%s"\n' % ( package.filename, page.node.title, page.depth, page.name + '.html', idevice.klass, idevice.title, resource.storageName, resource.userName, resource.path, resource.checksum) else: self.report += u'"%s",%d,"%s","%s","%s","%s",,,\n' % ( package.filename, page.node.title, page.depth, page.name + '.html', idevice.klass, idevice.title, resource) def export(self, package): """ Export web site Cleans up the previous packages pages and performs the export """ if not self.report: outputDir = self.filename if not outputDir.exists(): outputDir.mkdir() # Import the Website Page class. If the style has it's own page class # use that, else use the default one. if (self.stylesDir / "websitepage.py").exists(): global WebsitePage module = imp.load_source("websitepage", self.stylesDir / "websitepage.py") WebsitePage = module.WebsitePage self.pages = [WebsitePage(self.prefix + "index", 0, package.root)] self.generatePages(package.root, 1) uniquifyNames(self.pages) prevPage = None thisPage = self.pages[0] if self.report: self.report = u'"%s","%s","%s","%s","%s","%s","%s","%s","%s","%s"\n' % ( 'File', 'Page Name', 'Level', 'Page File Name', 'Idevice Type', 'Idevice Title', 'Resource File Name', 'Resource User Name', 'Resource Path', 'Resource Checksum') self.appendPageReport(thisPage, package) for nextPage in self.pages[1:]: if self.report: self.appendPageReport(nextPage, package) else: thisPage.save(outputDir, prevPage, nextPage, self.pages) prevPage = thisPage thisPage = nextPage if not self.report: thisPage.save(outputDir, prevPage, None, self.pages) if self.prefix == "": self.copyFiles(package, outputDir) return outputDir else: self.filename.write_text(self.report, 'utf-8') def copyFiles(self, package, outputDir): """ Copy all the files used by the website. """ if os.path.isdir(self.stylesDir): # Copy the style sheet files to the output dir styleFiles = [self.stylesDir / '..' / 'base.css'] styleFiles += [self.stylesDir / '..' / 'popup_bg.gif'] styleFiles += self.stylesDir.files("*.css") styleFiles += self.stylesDir.files("*.jpg") styleFiles += self.stylesDir.files("*.gif") styleFiles += self.stylesDir.files("*.png") styleFiles += self.stylesDir.files("*.js") styleFiles += self.stylesDir.files("*.html") styleFiles += self.stylesDir.files("*.ico") styleFiles += self.stylesDir.files("*.ttf") styleFiles += self.stylesDir.files("*.eot") styleFiles += self.stylesDir.files("*.otf") styleFiles += self.stylesDir.files("*.woff") self.stylesDir.copylist(styleFiles, outputDir) # copy the package's resource files package.resourceDir.copyfiles(outputDir) # copy script files. my_style = G.application.config.styleStore.getStyle(package.style) # jQuery if my_style.hasValidConfig: if my_style.get_jquery() == True: jsFile = (self.scriptsDir / 'exe_jquery.js') jsFile.copyfile(outputDir / 'exe_jquery.js') else: jsFile = (self.scriptsDir / 'exe_jquery.js') jsFile.copyfile(outputDir / 'exe_jquery.js') jsFile = (self.scriptsDir / 'common.js') jsFile.copyfile(outputDir / 'common.js') #dT = common.getExportDocType() dT = common.getExportDocType() if dT == "HTML5": jsFile = (self.scriptsDir / 'exe_html5.js') jsFile.copyfile(outputDir / 'exe_html5.js') # Incluide eXe's icon if the Style doesn't have one themePath = Path(G.application.config.stylesDir / package.style) themeFavicon = themePath.joinpath("favicon.ico") if not themeFavicon.exists(): faviconFile = (self.imagesDir / 'favicon.ico') faviconFile.copyfile(outputDir / 'favicon.ico') # copy players for media idevices. hasFlowplayer = False hasMagnifier = False hasXspfplayer = False hasGallery = False hasFX = False hasSH = False hasGames = False hasWikipedia = False isBreak = False hasInstructions = False hasMediaelement = False hasTooltips = False for page in self.pages: if isBreak: break for idevice in page.node.idevices: if (hasFlowplayer and hasMagnifier and hasXspfplayer and hasGallery and hasFX and hasSH and hasGames and hasWikipedia and hasInstructions and hasMediaelement and hasTooltips): isBreak = True break if not hasFlowplayer: if 'flowPlayer.swf' in idevice.systemResources: hasFlowplayer = True if not hasMagnifier: if 'mojomagnify.js' in idevice.systemResources: hasMagnifier = True if not hasXspfplayer: if 'xspf_player.swf' in idevice.systemResources: hasXspfplayer = True if not hasGallery: hasGallery = common.ideviceHasGallery(idevice) if not hasFX: hasFX = common.ideviceHasFX(idevice) if not hasSH: hasSH = common.ideviceHasSH(idevice) if not hasGames: hasGames = common.ideviceHasGames(idevice) if not hasWikipedia: if 'WikipediaIdevice' == idevice.klass: hasWikipedia = True if not hasInstructions: if 'TrueFalseIdevice' == idevice.klass or 'MultichoiceIdevice' == idevice.klass or 'VerdaderofalsofpdIdevice' == idevice.klass or 'EleccionmultiplefpdIdevice' == idevice.klass: hasInstructions = True if not hasMediaelement: hasMediaelement = common.ideviceHasMediaelement(idevice) if not hasTooltips: hasTooltips = common.ideviceHasTooltips(idevice) if hasFlowplayer: videofile = (self.templatesDir / 'flowPlayer.swf') videofile.copyfile(outputDir / 'flowPlayer.swf') controlsfile = (self.templatesDir / 'flowplayer.controls.swf') controlsfile.copyfile(outputDir / 'flowplayer.controls.swf') if hasMagnifier: videofile = (self.templatesDir / 'mojomagnify.js') videofile.copyfile(outputDir / 'mojomagnify.js') if hasXspfplayer: videofile = (self.templatesDir / 'xspf_player.swf') videofile.copyfile(outputDir / 'xspf_player.swf') if hasGallery: exeLightbox = (self.scriptsDir / 'exe_lightbox') exeLightbox.copyfiles(outputDir) if hasFX: exeEffects = (self.scriptsDir / 'exe_effects') exeEffects.copyfiles(outputDir) if hasSH: exeSH = (self.scriptsDir / 'exe_highlighter') exeSH.copyfiles(outputDir) if hasGames: exeGames = (self.scriptsDir / 'exe_games') exeGames.copyfiles(outputDir) if hasWikipedia: wikipediaCSS = (self.cssDir / 'exe_wikipedia.css') wikipediaCSS.copyfile(outputDir / 'exe_wikipedia.css') if hasInstructions: common.copyFileIfNotInStyle('panel-amusements.png', self, outputDir) common.copyFileIfNotInStyle('stock-stop.png', self, outputDir) if hasMediaelement: mediaelement = (self.scriptsDir / 'mediaelement') mediaelement.copyfiles(outputDir) dT = common.getExportDocType() if dT != "HTML5": jsFile = (self.scriptsDir / 'exe_html5.js') jsFile.copyfile(outputDir / 'exe_html5.js') if hasTooltips: exe_tooltips = (self.scriptsDir / 'exe_tooltips') exe_tooltips.copyfiles(outputDir) if hasattr(package, 'exportSource') and package.exportSource: (G.application.config.webDir / 'templates' / 'content.xsd').copyfile(outputDir / 'content.xsd') (outputDir / 'content.data').write_bytes(encodeObject(package)) (outputDir / 'contentv3.xml').write_bytes( encodeObjectToXML(package)) if package.license == "license GFDL": # include a copy of the GNU Free Documentation Licence (self.templatesDir / 'fdl.html').copyfile(outputDir / 'fdl.html') def generatePages(self, node, depth): """ Recursively generate pages and store in pages member variable for retrieving later """ for child in node.children: # assure lower pagename, without whitespaces or alphanumeric characters: pageName = child.titleShort.lower().replace(" ", "_") pageName = re.sub(r"\W", "", pageName) if not pageName: pageName = "__" self.pages.append(WebsitePage(self.prefix + pageName, depth, child)) self.generatePages(child, depth + 1)
class SinglePageExport(object): """ SinglePageExport will export a package as a website of HTML pages """ def __init__(self, stylesDir, outputDir, imagesDir, scriptsDir, templatesDir): """ 'stylesDir' is the directory where we can copy the stylesheets from 'outputDir' is the directory that will be [over]written with the website """ self.html = "" self.style = None self.name = None self.stylesDir = Path(stylesDir) self.outputDir = Path(outputDir) self.imagesDir = Path(imagesDir) self.scriptsDir = Path(scriptsDir) self.templatesDir = Path(templatesDir) self.page = None # Create the output dir if it doesn't already exist if not self.outputDir.exists(): self.outputDir.mkdir() def export(self, package, for_print=0): """ Export web site Cleans up the previous packages pages and performs the export """ self.style = package.style self.page = SinglePage("index", 1, package.root) self.page.save(self.outputDir/"index.html", for_print) self.copyFiles(package) def copyFiles(self, package): """ Copy all the files used by the website. """ # Copy the style sheet files to the output dir # But not nav.css styleFiles = [self.stylesDir/'..'/'base.css'] styleFiles += [self.stylesDir/'..'/'popup_bg.gif'] styleFiles += self.stylesDir.files("*.css") if "nav.css" in styleFiles: styleFiles.remove("nav.css") styleFiles += self.stylesDir.files("*.jpg") styleFiles += self.stylesDir.files("*.gif") styleFiles += self.stylesDir.files("*.png") styleFiles += self.stylesDir.files("*.js") styleFiles += self.stylesDir.files("*.html") self.stylesDir.copylist(styleFiles, self.outputDir) # copy the package's resource files package.resourceDir.copyfiles(self.outputDir) # copy script files. - modification by lernmodule.net self.scriptsDir.copylist(('libot_drag.js', 'common.js','lernmodule_net.js'), self.outputDir) # copy players for media idevices. hasFlowplayer = False hasMagnifier = False hasXspfplayer = False for idevice in self.page.node.idevices: if (hasFlowplayer and hasMagnifier and hasXspfplayer): break if not hasFlowplayer: if 'flowPlayer.swf' in idevice.systemResources: hasFlowplayer = True if not hasMagnifier: if 'magnifier.swf' in idevice.systemResources: hasMagnifier = True if not hasXspfplayer: if 'xspf_player.swf' in idevice.systemResources: hasXspfplayer = True if hasFlowplayer: videofile = (self.templatesDir/'flowPlayer.swf') videofile.copyfile(self.outputDir/'flowPlayer.swf') if hasMagnifier: videofile = (self.templatesDir/'magnifier.swf') videofile.copyfile(self.outputDir/'magnifier.swf') if hasXspfplayer: videofile = (self.templatesDir/'xspf_player.swf') videofile.copyfile(self.outputDir/'xspf_player.swf') if package.license == "GNU Free Documentation License": # include a copy of the GNU Free Documentation Licence (self.templatesDir/'fdl.html').copyfile(self.outputDir/'fdl.html')
class IMSExport(object): """ Exports an eXe package as a SCORM package """ def __init__(self, config, styleDir, filename): """ Initialize 'styleDir' is the directory from which we will copy our style sheets (and some gifs) """ self.config = config self.imagesDir = config.webDir/"images" self.scriptsDir = config.webDir/"scripts" self.templatesDir = config.webDir/"templates" self.styleDir = Path(styleDir) self.filename = Path(filename) self.pages = [] def export(self, package): """ Export SCORM package """ outputDir = TempDirPath() styleFiles = [self.styleDir/'..'/'base.css'] styleFiles += [self.styleDir/'..'/'popup_bg.gif'] styleFiles += self.styleDir.files("*.css") if "nav.css" in styleFiles: styleFiles.remove("nav.css") styleFiles += self.styleDir.files("*.jpg") styleFiles += self.styleDir.files("*.gif") styleFiles += self.styleDir.files("*.png") styleFiles += self.styleDir.files("*.js") styleFiles += self.styleDir.files("*.html") self.styleDir.copylist(styleFiles, outputDir) package.resourceDir.copyfiles(outputDir) self.pages = [ IMSPage("index", 1, package.root) ] self.generatePages(package.root, 2) uniquifyNames(self.pages) for page in self.pages: page.save(outputDir) manifest = Manifest(self.config, outputDir, package, self.pages) manifest.save() self.scriptsDir.copylist(('libot_drag.js', 'imscp_v1p1.xsd', 'imsmd_v1p2p2.xsd', 'ims_xml.xsd', 'common.js'), outputDir) self.templatesDir.copylist(('videoContainer.swf', 'magnifier.swf', 'xspf_player.swf'),outputDir) (self.templatesDir/'fdl.html').copyfile(outputDir/'fdl.html') zipped = ZipFile(self.filename, "w") for scormFile in outputDir.files(): zipped.write(scormFile, scormFile.basename().encode('utf8'), ZIP_DEFLATED) zipped.close() outputDir.rmtree() def generatePages(self, node, depth): """ Recursive function for exporting a node. 'outputDir' is the temporary directory that we are exporting to before creating zip file """ for child in node.children: pageName = child.titleShort.lower().replace(" ", "_") pageName = re.sub(r"\W", "", pageName) if not pageName: pageName = "__" page = IMSPage(pageName, depth, child) self.pages.append(page) self.generatePages(child, depth + 1)
class Epub3Export(object): """ Exports an eXe package as a epub 3 package The 'Hello World' of a epub 3 publication might contain files: mimetype META-INF/container.xml Content/HelloWorld.opf Content/HelloWorld.xhtml """ def __init__(self, config, styleDir, filename): """ Initialize 'styleDir' is the directory from which we will copy our style sheets (and some gifs) """ self.config = config self.imagesDir = config.webDir / "images" self.scriptsDir = config.webDir / "scripts" self.cssDir = config.webDir / "css" self.templatesDir = config.webDir / "templates" self.schemasDir = config.webDir / "schemas/ims" self.styleDir = Path(styleDir) self.filename = Path(filename) self.pages = [] def export(self, package): """ Export epub 3 package """ # First do the export to a temporary directory outputDir = TempDirPath() """ fileDir = outputDir/"META-INF" fileDir.mkdir() fileDir = outputDir/"Content" fileDir.mkdir() """ metainfPages = Path(outputDir.abspath() + "/META-INF") # metainfPages = outputDir/'META-INF' metainfPages.mkdir() contentPages = Path(outputDir.abspath() + "/EPUB") # contentPages = outputDir/'Content' contentPages.mkdir() # print contentPages.abspath() # print outputDir.abspath() # Export the package content self.pages = [Epub3Cover("cover", 1, package.root)] self.generatePages(package.root, 2) uniquifyNames(self.pages) cover = None for page in self.pages: page.save(contentPages) if hasattr(page, "cover"): cover = page.cover # Create mimetype file mimetypeFile = open(outputDir.abspath() + "/mimetype", "w") mimetypeFile.write("application/epub+zip") mimetypeFile.close() # Copy the style sheet files to the output dir # But not nav.css styleFiles = [self.styleDir / ".." / "popup_bg.gif"] styleFiles += [f for f in self.styleDir.files("*.css") if f.basename() != "nav.css"] styleFiles += self.styleDir.files("*.jpg") styleFiles += self.styleDir.files("*.gif") styleFiles += self.styleDir.files("*.png") styleFiles += self.styleDir.files("*.js") styleFiles += self.styleDir.files("*.html") styleFiles += self.styleDir.files("*.ttf") styleFiles += self.styleDir.files("*.eot") styleFiles += self.styleDir.files("*.otf") styleFiles += self.styleDir.files("*.woff") # FIXME for now, only copy files referenced in Common Cartridge # this really should apply to all exports, but without a manifest # of the files needed by an included stylesheet it is too restrictive package.resourceDir.copyfiles(contentPages) self.styleDir.copylist(styleFiles, contentPages) listCSSFiles = getFilesCSSToMinify("epub3", self.styleDir) exportMinFileCSS(listCSSFiles, outputDir) listFiles = [] listOutFiles = [] listFiles += [self.scriptsDir / "common.js"] listOutFiles += [outputDir / "common.js"] # copy players for media idevices. hasFlowplayer = False hasMagnifier = False hasXspfplayer = False hasGallery = False hasFX = False hasSH = False hasGames = False hasWikipedia = False isBreak = False hasInstructions = False hasTooltips = False for page in self.pages: if isBreak: break for idevice in page.node.idevices: if ( hasFlowplayer and hasMagnifier and hasXspfplayer and hasGallery and hasFX and hasSH and hasGames and hasWikipedia ): isBreak = True break if not hasFlowplayer: if "flowPlayer.swf" in idevice.systemResources: hasFlowplayer = True if not hasMagnifier: if "mojomagnify.js" in idevice.systemResources: hasMagnifier = True if not hasXspfplayer: if "xspf_player.swf" in idevice.systemResources: hasXspfplayer = True if not hasGallery: hasGallery = common.ideviceHasGallery(idevice) if not hasFX: hasFX = common.ideviceHasFX(idevice) if not hasSH: hasSH = common.ideviceHasSH(idevice) if not hasGames: hasGames = common.ideviceHasGames(idevice) if not hasWikipedia: if "WikipediaIdevice" == idevice.klass: hasWikipedia = True if not hasInstructions: if ( "TrueFalseIdevice" == idevice.klass or "MultichoiceIdevice" == idevice.klass or "VerdaderofalsofpdIdevice" == idevice.klass or "EleccionmultiplefpdIdevice" == idevice.klass ): hasInstructions = True if not hasTooltips: hasTooltips = common.ideviceHasTooltips(idevice) if hasFlowplayer: videofile = self.templatesDir / "flowPlayer.swf" videofile.copyfile(contentPages / "flowPlayer.swf") controlsfile = self.templatesDir / "flowplayer.controls.swf" controlsfile.copyfile(contentPages / "flowplayer.controls.swf") if hasMagnifier: videofile = self.templatesDir / "mojomagnify.js" videofile.copyfile(contentPages / "mojomagnify.js") if hasXspfplayer: videofile = self.templatesDir / "xspf_player.swf" videofile.copyfile(contentPages / "xspf_player.swf") if hasGallery: exeLightbox = self.scriptsDir / "exe_lightbox" exeLightbox.copyfiles(contentPages) if hasFX: exeEffects = self.scriptsDir / "exe_effects" exeEffects.copyfiles(contentPages) if hasSH: exeSH = self.scriptsDir / "exe_highlighter" exeSH.copyfiles(contentPages) if hasGames: exeGames = self.scriptsDir / "exe_games" exeGames.copyfiles(contentPages) if hasWikipedia: wikipediaCSS = self.cssDir / "exe_wikipedia.css" wikipediaCSS.copyfile(contentPages / "exe_wikipedia.css") if hasInstructions: common.copyFileIfNotInStyle("panel-amusements.png", self, contentPages) common.copyFileIfNotInStyle("stock-stop.png", self, contentPages) if hasTooltips: exe_tooltips = self.scriptsDir / "exe_tooltips" exe_tooltips.copyfiles(contentPages) my_style = G.application.config.styleStore.getStyle(package.style) if my_style.hasValidConfig: if my_style.get_jquery() == True: jsFile = self.scriptsDir / "exe_jquery.js" jsFile.copyfile(contentPages / "exe_jquery.js") else: jsFile = self.scriptsDir / "exe_jquery.js" jsFile.copyfile(contentPages / "exe_jquery.js") listFiles = getFilesJSToMinify("epub3", self.scriptsDir) exportMinFileJS(listFiles, outputDir) # if hasattr(package, 'exportSource') and package.exportSource: # (G.application.config.webDir / 'templates' / 'content.xsd').copyfile(outputDir / 'content.xsd') # (outputDir / 'content.data').write_bytes(encodeObject(package)) # (outputDir / 'contentv3.xml').write_bytes(encodeObjectToXML(package)) if package.license == "license GFDL": # include a copy of the GNU Free Documentation Licence (self.templatesDir / "fdl.html").copyfile(contentPages / "fdl.html") # Create the nav.xhtml file container = NavEpub3(self.pages, contentPages) container.save() # Create the publication file publication = PublicationEpub3(self.config, contentPages, package, self.pages, cover) publication.save("package.opf") # Create the container file container = ContainerEpub3(metainfPages) container.save("container.xml") # Zip it up! self.filename.safeSave(self.doZip, _(u"EXPORT FAILED!\nLast succesful export is %s."), outputDir) # Clean up the temporary dir outputDir.rmtree() def doZip(self, fileObj, outputDir): """ Actually does the zipping of the file. Called by 'Path.safeSave' """ zipped = ZipFile(fileObj, "w") mimetype = outputDir / "mimetype" zipped.write(mimetype, "mimetype", ZIP_STORED) for epubFile in outputDir.walkfiles(): if epubFile.basename() == "mimetype": continue relativePath = epubFile.basename() parentdir = epubFile.splitpath()[0] while outputDir.basename() != parentdir.basename(): relativePath = parentdir.basename() / relativePath parentdir = parentdir.splitpath()[0] zipped.write(epubFile, relativePath.encode("utf8"), compress_type=ZIP_DEFLATED) zipped.close() def generatePages(self, node, depth): """ Recursive function for exporting a node. 'node' is the node that we are making a page for 'depth' is the number of ancestors that the page has +1 (ie. root is 1) """ pageName = node.titleShort.lower().replace(" ", u"_") pageName = re.sub(r"\W", "", pageName) if not pageName: pageName = u"__" if pageName[0] in [unicode(i) for i in range(0, 10)]: pageName = u"_" + pageName page = Epub3Page(pageName, depth, node) self.pages.append(page) for child in node.children: self.generatePages(child, depth + 1)
class ScormExport(object): """ Exports an eXe package as a SCORM package """ def __init__(self, config, styleDir, filename, scormType): """ Initialize 'styleDir' is the directory from which we will copy our style sheets (and some gifs) """ self.config = config self.imagesDir = config.webDir/"images" self.scriptsDir = config.webDir/"scripts" self.templatesDir = config.webDir/"templates" self.styleDir = Path(styleDir) self.filename = Path(filename) self.pages = [] self.hasForum = False self.scormType = scormType def export(self, package): """ Export SCORM package """ outputDir = TempDirPath() styleFiles = [self.styleDir/'..'/'base.css'] styleFiles += [self.styleDir/'..'/'popup_bg.gif'] styleFiles += self.styleDir.files("*.css") if "nav.css" in styleFiles: styleFiles.remove("nav.css") styleFiles += self.styleDir.files("*.jpg") styleFiles += self.styleDir.files("*.gif") styleFiles += self.styleDir.files("*.png") styleFiles += self.styleDir.files("*.js") styleFiles += self.styleDir.files("*.html") self.styleDir.copylist(styleFiles, outputDir) package.resourceDir.copyfiles(outputDir) self.pages = [ ScormPage("index", 1, package.root) ] self.generatePages(package.root, 2) uniquifyNames(self.pages) for page in self.pages: page.save(outputDir) if not self.hasForum: for idevice in page.node.idevices: if hasattr(idevice, "isForum"): if idevice.forum.lms.lms == "moodle": self.hasForum = True break manifest = Manifest(self.config, outputDir, package, self.pages, self.scormType) manifest.save("imsmanifest.xml") if self.hasForum: manifest.save("discussionforum.xml") self.scriptsDir.copylist(('APIWrapper.js', 'imscp_rootv1p1p2.xsd', 'imsmd_rootv1p2p1.xsd', 'ims_xml.xsd', 'adlcp_rootv1p2.xsd', 'SCOFunctions.js', 'libot_drag.js', 'common.js'), outputDir) self.templatesDir.copylist(('videoContainer.swf', 'magnifier.swf', 'xspf_player.swf'),outputDir) (self.templatesDir/'fdl.html').copyfile(outputDir/'fdl.html') self.filename.safeSave(self.doZip, _('EXPORT FAILED!\nLast succesful export is %s.'), outputDir) outputDir.rmtree() def doZip(self, fileObj, outputDir): """ Actually does the zipping of the file. Called by 'Path.safeSave' """ zipped = ZipFile(fileObj, "w") for scormFile in outputDir.files(): zipped.write(scormFile, scormFile.basename().encode('utf8'), ZIP_DEFLATED) zipped.close() def generatePages(self, node, depth): """ Recursive function for exporting a node. 'node' is the node that we are making a page for 'depth' is the number of ancestors that the page has +1 (ie. root is 1) """ for child in node.children: pageName = child.titleShort.lower().replace(" ", "_") pageName = re.sub(r"\W", "", pageName) if not pageName: pageName = "__" page = ScormPage(pageName, depth, child) self.pages.append(page) self.generatePages(child, depth + 1)
class WebsiteExport(object): """ WebsiteExport will export a package as a website of HTML pages """ def __init__(self, config, styleDir, filename, prefix=""): """ 'stylesDir' is the directory where we can copy the stylesheets from 'outputDir' is the directory that will be [over]written with the website """ self.config = config self.imagesDir = config.webDir/"images" self.scriptsDir = config.webDir/"scripts" self.cssDir = config.webDir/"css" self.templatesDir = config.webDir/"templates" self.stylesDir = Path(styleDir) self.filename = Path(filename) self.pages = [] self.prefix = prefix def exportZip(self, package): """ Export web site Cleans up the previous packages pages and performs the export """ outputDir = TempDirPath() # Import the Website Page class. If the style has it's own page class # use that, else use the default one. if (self.stylesDir/"websitepage.py").exists(): global WebsitePage module = imp.load_source("websitepage", self.stylesDir/"websitepage.py") WebsitePage = module.WebsitePage self.pages = [ WebsitePage("index", 1, package.root) ] self.generatePages(package.root, 1) uniquifyNames(self.pages) prevPage = None thisPage = self.pages[0] for nextPage in self.pages[1:]: thisPage.save(outputDir, prevPage, nextPage, self.pages) prevPage = thisPage thisPage = nextPage thisPage.save(outputDir, prevPage, None, self.pages) self.copyFiles(package, outputDir) # Zip up the website package self.filename.safeSave(self.doZip, _('EXPORT FAILED!\nLast succesful export is %s.'), outputDir) # Clean up the temporary dir outputDir.rmtree() def doZip(self, fileObj, outputDir): """ Actually saves the zip data. Called by 'Path.safeSave' """ zipped = ZipFile(fileObj, "w") for scormFile in outputDir.files(): zipped.write(scormFile, scormFile.basename().encode('utf8'), ZIP_DEFLATED) zipped.close() def export(self, package): """ Export web site Cleans up the previous packages pages and performs the export """ outputDir = self.filename if not outputDir.exists(): outputDir.mkdir() # Import the Website Page class. If the style has it's own page class # use that, else use the default one. if (self.stylesDir/"websitepage.py").exists(): global WebsitePage module = imp.load_source("websitepage", self.stylesDir/"websitepage.py") WebsitePage = module.WebsitePage self.pages = [ WebsitePage(self.prefix + "index", 1, package.root) ] self.generatePages(package.root, 1) uniquifyNames(self.pages) prevPage = None thisPage = self.pages[0] for nextPage in self.pages[1:]: thisPage.save(outputDir, prevPage, nextPage, self.pages) prevPage = thisPage thisPage = nextPage thisPage.save(outputDir, prevPage, None, self.pages) if self.prefix == "": self.copyFiles(package, outputDir) def copyFiles(self, package, outputDir): """ Copy all the files used by the website. """ # Copy the style sheet files to the output dir styleFiles = [self.stylesDir/'..'/'base.css'] styleFiles += [self.stylesDir/'..'/'popup_bg.gif'] styleFiles += self.stylesDir.files("*.css") styleFiles += self.stylesDir.files("*.jpg") styleFiles += self.stylesDir.files("*.gif") styleFiles += self.stylesDir.files("*.png") styleFiles += self.stylesDir.files("*.js") styleFiles += self.stylesDir.files("*.html") styleFiles += self.stylesDir.files("*.ico") styleFiles += self.stylesDir.files("*.ttf") styleFiles += self.stylesDir.files("*.eot") styleFiles += self.stylesDir.files("*.otf") styleFiles += self.stylesDir.files("*.woff") self.stylesDir.copylist(styleFiles, outputDir) # copy the package's resource files package.resourceDir.copyfiles(outputDir) # copy script files. - with modification by lernmodule.net self.scriptsDir.copylist(('libot_drag.js', 'common.js', 'lernmodule_net.js'), outputDir) # copy players for media idevices. hasFlowplayer = False hasMagnifier = False hasXspfplayer = False hasGallery = False isBreak = False for page in self.pages: if isBreak: break for idevice in page.node.idevices: if (hasFlowplayer and hasMagnifier and hasXspfplayer and hasGallery): isBreak = True break if not hasFlowplayer: if 'flowPlayer.swf' in idevice.systemResources: hasFlowplayer = True if not hasMagnifier: if 'magnifier.swf' in idevice.systemResources: hasMagnifier = True if not hasXspfplayer: if 'xspf_player.swf' in idevice.systemResources: hasXspfplayer = True if not hasGallery: if 'GalleryIdevice' == idevice.klass: hasGallery = True if hasFlowplayer: videofile = (self.templatesDir/'flowPlayer.swf') videofile.copyfile(outputDir/'flowPlayer.swf') controlsfile = (self.templatesDir/'flowplayer.controls.swf') controlsfile.copyfile(outputDir/'flowplayer.controls.swf') if hasMagnifier: videofile = (self.templatesDir/'magnifier.swf') videofile.copyfile(outputDir/'magnifier.swf') if hasXspfplayer: videofile = (self.templatesDir/'xspf_player.swf') videofile.copyfile(outputDir/'xspf_player.swf') if hasGallery: imageGalleryCSS = (self.cssDir/'exe_lightbox.css') imageGalleryCSS.copyfile(outputDir/'exe_lightbox.css') imageGalleryJS = (self.scriptsDir/'exe_lightbox.js') imageGalleryJS.copyfile(outputDir/'exe_lightbox.js') self.imagesDir.copylist(('exeGallery_actions.png', 'exeGallery_loading.gif'), outputDir) if package.license == "GNU Free Documentation License": # include a copy of the GNU Free Documentation Licence (self.templatesDir/'fdl.html').copyfile(outputDir/'fdl.html') def generatePages(self, node, depth): """ Recursively generate pages and store in pages member variable for retrieving later """ for child in node.children: # assure lower pagename, without whitespaces or alphanumeric characters: pageName = child.titleShort.lower().replace(" ", "_") pageName = re.sub(r"\W", "", pageName) if not pageName: pageName = "__" self.pages.append(WebsitePage(self.prefix + pageName, depth, child)) self.generatePages(child, depth + 1)
class IMSExport(object): """ Exports an eXe package as a SCORM package """ def __init__(self, config, styleDir, filename): """ Initialize 'styleDir' is the directory from which we will copy our style sheets (and some gifs) """ self.config = config self.imagesDir = config.webDir / "images" self.scriptsDir = config.webDir / "scripts" self.cssDir = config.webDir / "css" self.templatesDir = config.webDir / "templates" self.schemasDir = config.webDir / "schemas/ims" self.styleDir = Path(styleDir) self.filename = Path(filename) self.pages = [] def export(self, package): """ Export SCORM package """ # First do the export to a temporary directory outputDir = TempDirPath() # Copy the style sheet files to the output dir # But not nav.css styleFiles = [self.styleDir / '..' / 'base.css'] styleFiles += [self.styleDir / '..' / 'popup_bg.gif'] styleFiles += self.styleDir.files("*.css") if "nav.css" in styleFiles: styleFiles.remove("nav.css") styleFiles += self.styleDir.files("*.jpg") styleFiles += self.styleDir.files("*.gif") styleFiles += self.styleDir.files("*.png") styleFiles += self.styleDir.files("*.js") styleFiles += self.styleDir.files("*.html") styleFiles += self.styleDir.files("*.ttf") styleFiles += self.styleDir.files("*.eot") styleFiles += self.styleDir.files("*.otf") styleFiles += self.styleDir.files("*.woff") self.styleDir.copylist(styleFiles, outputDir) # copy the package's resource files package.resourceDir.copyfiles(outputDir) # Export the package content self.pages = [IMSPage("index", 1, package.root)] self.generatePages(package.root, 2) uniquifyNames(self.pages) for page in self.pages: page.save(outputDir) # Create the manifest file manifest = Manifest(self.config, outputDir, package, self.pages) manifest.save() # Copy the scripts - with modification by lernmodule.net self.scriptsDir.copylist( ('libot_drag.js', 'lernmodule_net.js', 'common.js'), outputDir) self.schemasDir.copylist( ('imscp_v1p1.xsd', 'imsmd_v1p2p2.xsd', 'ims_xml.xsd'), outputDir) # copy players for media idevices. hasFlowplayer = False hasMagnifier = False hasXspfplayer = False hasGallery = False isBreak = False for page in self.pages: if isBreak: break for idevice in page.node.idevices: if (hasFlowplayer and hasMagnifier and hasXspfplayer and hasGallery): isBreak = True break if not hasFlowplayer: if 'flowPlayer.swf' in idevice.systemResources: hasFlowplayer = True if not hasMagnifier: if 'magnifier.swf' in idevice.systemResources: hasMagnifier = True if not hasXspfplayer: if 'xspf_player.swf' in idevice.systemResources: hasXspfplayer = True if not hasGallery: if 'GalleryIdevice' == idevice.klass: hasGallery = True if hasFlowplayer: videofile = (self.templatesDir / 'flowPlayer.swf') videofile.copyfile(outputDir / 'flowPlayer.swf') controlsfile = (self.templatesDir / 'flowplayer.controls.swf') controlsfile.copyfile(outputDir / 'flowplayer.controls.swf') if hasMagnifier: videofile = (self.templatesDir / 'magnifier.swf') videofile.copyfile(outputDir / 'magnifier.swf') if hasXspfplayer: videofile = (self.templatesDir / 'xspf_player.swf') videofile.copyfile(outputDir / 'xspf_player.swf') if hasGallery: imageGalleryCSS = (self.cssDir / 'exe_lightbox.css') imageGalleryCSS.copyfile(outputDir / 'exe_lightbox.css') imageGalleryJS = (self.scriptsDir / 'exe_lightbox.js') imageGalleryJS.copyfile(outputDir / 'exe_lightbox.js') self.imagesDir.copylist( ('exeGallery_actions.png', 'exeGallery_loading.gif'), outputDir) if package.license == "GNU Free Documentation License": # include a copy of the GNU Free Documentation Licence (self.templatesDir / 'fdl.html').copyfile(outputDir / 'fdl.html') # Zip it up! self.filename.safeSave( self.doZip, _('EXPORT FAILED!\nLast succesful export is %s.'), outputDir) # Clean up the temporary dir outputDir.rmtree() def doZip(self, fileObj, outputDir): """ Actually does the zipping of the file. Called by 'Path.safeSave' """ zipped = ZipFile(fileObj, "w") for scormFile in outputDir.files(): zipped.write(scormFile, scormFile.basename().encode('utf8'), ZIP_DEFLATED) zipped.close() def generatePages(self, node, depth): """ Recursive function for exporting a node. 'outputDir' is the temporary directory that we are exporting to before creating zip file """ for child in node.children: pageName = child.titleShort.lower().replace(" ", "_") pageName = re.sub(r"\W", "", pageName) if not pageName: pageName = "__" page = IMSPage(pageName, depth, child) self.pages.append(page) self.generatePages(child, depth + 1)
class Epub3Export(object): """ Exports an eXe package as a epub 3 package The 'Hello World' of a epub 3 publication might contain files: mimetype META-INF/container.xml Content/HelloWorld.opf Content/HelloWorld.xhtml """ def __init__(self, config, styleDir, filename): """ Initialize 'styleDir' is the directory from which we will copy our style sheets (and some gifs) """ self.config = config self.imagesDir = config.webDir / "images" self.scriptsDir = config.webDir / "scripts" self.cssDir = config.webDir / "css" self.templatesDir = config.webDir / "templates" self.schemasDir = config.webDir / "schemas/ims" self.styleDir = Path(styleDir) self.filename = Path(filename) self.pages = [] def export(self, package): """ Export epub 3 package """ # First do the export to a temporary directory outputDir = TempDirPath() ''' fileDir = outputDir/"META-INF" fileDir.mkdir() fileDir = outputDir/"Content" fileDir.mkdir() ''' metainfPages = Path(outputDir.abspath() + '/META-INF') # metainfPages = outputDir/'META-INF' metainfPages.mkdir() contentPages = Path(outputDir.abspath() + '/EPUB') # contentPages = outputDir/'Content' contentPages.mkdir() # print contentPages.abspath() # print outputDir.abspath() # Export the package content self.pages = [Epub3Cover("cover", 1, package.root)] self.generatePages(package.root, 2) uniquifyNames(self.pages) cover = None for page in self.pages: page.save(contentPages, self.pages) if hasattr(page, 'cover'): cover = page.cover # Create mimetype file mimetypeFile = open(outputDir.abspath() + '/mimetype', "w") mimetypeFile.write('application/epub+zip') mimetypeFile.close() # Create common_i18n file langFile = open(contentPages + '/common_i18n.js', "w") langFile.write(common.getJavaScriptStrings(False)) langFile.close() # Copy the style files to the output dir # But not nav.css styleFiles = [self.styleDir / '..' / 'popup_bg.gif'] styleFiles += [ f for f in self.styleDir.files("*.*") if f.basename() not in ['nav.css'] ] # FIXME for now, only copy files referenced in Common Cartridge # this really should apply to all exports, but without a manifest # of the files needed by an included stylesheet it is too restrictive # Add fallback document for possible image links if Path(self.styleDir / 'fallback.xhtml').exists(): styleFiles += [self.styleDir / 'fallback.xhtml'] else: styleFiles += [self.styleDir / '..' / 'fallback.xhtml'] # copy the package's resource files for resourceFile in package.resourceDir.walkfiles(): fn = package.resourceDir.relpathto(resourceFile) if ("/" in fn): Dir = Path(contentPages / fn[:fn.rindex("/")]) if not Dir.exists(): Dir.makedirs() resourceFile.copy(contentPages / Dir) else: resourceFile.copy(contentPages) self.styleDir.copylist(styleFiles, contentPages) # copy players for media idevices. hasFlowplayer = False hasMagnifier = False hasXspfplayer = False hasGallery = False hasFX = False hasSH = False hasGames = False hasWikipedia = False isBreak = False hasInstructions = False hasTooltips = False hasABCMusic = False for page in self.pages: if isBreak: break for idevice in page.node.idevices: if (hasFlowplayer and hasMagnifier and hasXspfplayer and hasGallery and hasFX and hasSH and hasGames and hasWikipedia and hasInstructions and hasTooltips and hasABCMusic): isBreak = True break if not hasFlowplayer: if 'flowPlayer.swf' in idevice.systemResources: hasFlowplayer = True if not hasMagnifier: if 'mojomagnify.js' in idevice.systemResources: hasMagnifier = True if not hasXspfplayer: if 'xspf_player.swf' in idevice.systemResources: hasXspfplayer = True if not hasGallery: hasGallery = common.ideviceHasGallery(idevice) if not hasFX: hasFX = common.ideviceHasFX(idevice) if not hasSH: hasSH = common.ideviceHasSH(idevice) if not hasGames: hasGames = common.ideviceHasGames(idevice) if not hasWikipedia: if 'WikipediaIdevice' == idevice.klass: hasWikipedia = True if not hasInstructions: if 'TrueFalseIdevice' == idevice.klass or 'MultichoiceIdevice' == idevice.klass or 'VerdaderofalsofpdIdevice' == idevice.klass or 'EleccionmultiplefpdIdevice' == idevice.klass: hasInstructions = True if not hasTooltips: hasTooltips = common.ideviceHasTooltips(idevice) if not hasABCMusic: hasABCMusic = common.ideviceHasABCMusic(idevice) common.exportJavaScriptIdevicesFiles(page.node.idevices, contentPages) if hasFlowplayer: videofile = (self.templatesDir / 'flowPlayer.swf') videofile.copyfile(contentPages / 'flowPlayer.swf') controlsfile = (self.templatesDir / 'flowplayer.controls.swf') controlsfile.copyfile(contentPages / 'flowplayer.controls.swf') if hasMagnifier: videofile = (self.templatesDir / 'mojomagnify.js') videofile.copyfile(contentPages / 'mojomagnify.js') if hasXspfplayer: videofile = (self.templatesDir / 'xspf_player.swf') videofile.copyfile(contentPages / 'xspf_player.swf') if hasGallery: exeLightbox = (self.scriptsDir / 'exe_lightbox') exeLightbox.copyfiles(contentPages) if hasFX: exeEffects = (self.scriptsDir / 'exe_effects') exeEffects.copyfiles(contentPages) if hasSH: exeSH = (self.scriptsDir / 'exe_highlighter') exeSH.copyfiles(contentPages) if hasGames: exeGames = (self.scriptsDir / 'exe_games') exeGames.copyfiles(contentPages) # Add game js string to common_i18n langGameFile = open(contentPages + '/common_i18n.js', "a") langGameFile.write(common.getGamesJavaScriptStrings(False)) langGameFile.close() if hasWikipedia: wikipediaCSS = (self.cssDir / 'exe_wikipedia.css') wikipediaCSS.copyfile(contentPages / 'exe_wikipedia.css') if hasInstructions: common.copyFileIfNotInStyle('panel-amusements.png', self, contentPages) common.copyFileIfNotInStyle('stock-stop.png', self, contentPages) if hasTooltips: exe_tooltips = (self.scriptsDir / 'exe_tooltips') exe_tooltips.copyfiles(contentPages) if hasABCMusic: pluginScripts = (self.scriptsDir / 'tinymce_4/js/tinymce/plugins/abcmusic/export') pluginScripts.copyfiles(contentPages) my_style = G.application.config.styleStore.getStyle(package.style) if my_style.hasValidConfig: if my_style.get_jquery() == True: jsFile = (self.scriptsDir / 'exe_jquery.js') jsFile.copyfile(contentPages / 'exe_jquery.js') else: jsFile = (self.scriptsDir / 'exe_jquery.js') jsFile.copyfile(contentPages / 'exe_jquery.js') # Copy and minify CSS files css_files = getFilesCSSToMinify('epub3', self.styleDir) exportMinFileCSS(css_files, contentPages) # Copy and minify JS files js_files = getFilesJSToMinify('epub3', self.scriptsDir) exportMinFileJS(js_files, contentPages) # if hasattr(package, 'exportSource') and package.exportSource: # (G.application.config.webDir / 'templates' / 'content.xsd').copyfile(outputDir / 'content.xsd') # (outputDir / 'content.data').write_bytes(encodeObject(package)) # (outputDir / 'contentv3.xml').write_bytes(encodeObjectToXML(package)) if package.license == "license GFDL": # include a copy of the GNU Free Documentation Licence (self.templatesDir / 'fdl.html').copyfile(contentPages / 'fdl.html') # Create the nav.xhtml file container = NavEpub3(self.pages, contentPages) container.save() # Create the publication file publication = PublicationEpub3(self.config, contentPages, package, self.pages, cover) publication.save("package.opf") # Create the container file container = ContainerEpub3(metainfPages) container.save("container.xml") # Zip it up! self.filename.safeSave( self.doZip, _(u'EXPORT FAILED!\nLast succesful export is %s.'), outputDir) # Clean up the temporary dir outputDir.rmtree() def doZip(self, fileObj, outputDir): """ Actually does the zipping of the file. Called by 'Path.safeSave' """ zipped = ZipFile(fileObj, "w") mimetype = outputDir / "mimetype" zipped.write(mimetype, "mimetype", ZIP_STORED) for epubFile in outputDir.walkfiles(): if epubFile.basename() == 'mimetype': continue relativePath = epubFile.basename() parentdir = epubFile.splitpath()[0] while (outputDir.basename() != parentdir.basename()): relativePath = parentdir.basename() / relativePath parentdir = parentdir.splitpath()[0] zipped.write(epubFile, relativePath.encode('utf8'), compress_type=ZIP_DEFLATED) zipped.close() def generatePages(self, node, depth): """ Recursive function for exporting a node. 'node' is the node that we are making a page for 'depth' is the number of ancestors that the page has +1 (ie. root is 1) """ pageName = node.titleShort.lower().replace(" ", u"_") pageName = re.sub(r"\W", "", pageName) if not pageName: pageName = u"__" if pageName[0] in [unicode(i) for i in range(0, 10)]: pageName = u'_' + pageName page = Epub3Page(pageName, depth, node) self.pages.append(page) for child in node.children: self.generatePages(child, depth + 1)
class WebsiteExport(object): """ WebsiteExport will export a package as a website of HTML pages """ def __init__(self, stylesDir, outputDir, imagesDir, scriptsDir, templatesDir): """ 'stylesDir' is the directory where we can copy the stylesheets from 'outputDir' is the directory that will be [over]written with the website """ self.pages = [] self.stylesDir = Path(stylesDir) self.outputDir = Path(outputDir) self.imagesDir = Path(imagesDir) self.scriptsDir = Path(scriptsDir) self.templatesDir = Path(templatesDir) if not self.outputDir.exists(): self.outputDir.mkdir() def export(self, package): """ Export web site Cleans up the previous packages pages and performs the export """ self.copyFiles(package) if (self.stylesDir / "websitepage.py").exists(): global WebsitePage module = imp.load_source("websitepage", self.stylesDir / "websitepage.py") WebsitePage = module.WebsitePage self.pages = [WebsitePage("index", 1, package.root)] self.generatePages(package.root, 1) uniquifyNames(self.pages) prevPage = None thisPage = self.pages[0] for nextPage in self.pages[1:]: thisPage.save(self.outputDir, prevPage, nextPage, self.pages) prevPage = thisPage thisPage = nextPage thisPage.save(self.outputDir, prevPage, None, self.pages) def copyFiles(self, package): """ Copy all the files used by the website. """ styleFiles = [self.stylesDir / ".." / "base.css"] styleFiles += [self.stylesDir / ".." / "popup_bg.gif"] styleFiles += self.stylesDir.files("*.css") styleFiles += self.stylesDir.files("*.jpg") styleFiles += self.stylesDir.files("*.gif") styleFiles += self.stylesDir.files("*.png") styleFiles += self.stylesDir.files("*.js") styleFiles += self.stylesDir.files("*.html") self.stylesDir.copylist(styleFiles, self.outputDir) package.resourceDir.copyfiles(self.outputDir) self.scriptsDir.copylist(("libot_drag.js", "common.js"), self.outputDir) self.templatesDir.copylist(("videoContainer.swf", "magnifier.swf"), self.outputDir) (self.templatesDir / "fdl.html").copyfile(self.outputDir / "fdl.html") def generatePages(self, node, depth): """ Recursively generate pages and store in pages member variable for retrieving later """ for child in node.children: pageName = child.titleShort.lower().replace(" ", "_") pageName = re.sub(r"\W", "", pageName) if not pageName: pageName = "__" self.pages.append(WebsitePage(pageName, depth, child)) self.generatePages(child, depth + 1)