def _setupConfigFile(self, configParser): """ Override this to setup any customised config settings """ # Set up the system section system = configParser.addSection('system') system.exePath = 'exe/exe' system.exeDir = 'exe' system.webDir = 'exe/webui' system.localeDir = 'exe/locale' system.configDir = 'tmp' system.port = 8081 # Make a temporary dir where we can save packages and exports etc tmpDir = Path('tmp') if not tmpDir.exists(): tmpDir.mkdir() dataDir = tmpDir / 'data' if not dataDir.exists(): dataDir.mkdir() system.dataDir = dataDir system.browserPath = 'not really used in tests so far' # Setup the logging section logging = configParser.addSection('logging') logging.root = 'DEBUG'
def exportWebSite(self, client, filename, webDir, stylesDir): """ Export 'client' to a web site, 'webDir' is just read from config.webDir 'stylesDir' is where to copy the style sheet information from """ imagesDir = webDir.joinpath('images') scriptsDir = webDir.joinpath('scripts') templatesDir = webDir.joinpath('templates') filename = Path(filename) if filename.basename() != self.package.name: filename /= self.package.name if not filename.exists(): filename.makedirs() elif not filename.isdir(): client.alert(_(u'Filename %s is a file, cannot replace it') % filename) log.error("Couldn't export web page: "+ "Filename %s is a file, cannot replace it" % filename) return else: filename.rmtree() filename.mkdir() websiteExport = WebsiteExport(stylesDir, filename, imagesDir, scriptsDir, templatesDir) websiteExport.export(self.package) self._startFile(filename)
def exportSinglePage(self, client, filename, webDir, stylesDir): """ Export 'client' to a single web page, 'webDir' is just read from config.webDir 'stylesDir' is where to copy the style sheet information from """ imagesDir = webDir.joinpath('images') scriptsDir = webDir.joinpath('scripts') templatesDir = webDir.joinpath('templates') filename = Path(filename) if filename.basename() != self.package.name: filename /= self.package.name if not filename.exists(): filename.makedirs() elif not filename.isdir(): client.alert(_(u'Filename %s is a file, cannot replace it') % filename) log.error("Couldn't export web page: "+ "Filename %s is a file, cannot replace it" % filename) return else: try: filename.rmtree() filename.mkdir() except Exception, e: client.alert(_('There was an error in the export:\n%s') % str(e)) return
def _setupConfigFile(self, configParser): """ Setup our own config file """ utils.SuperTestCase._setupConfigFile(self, configParser) tmp = Path('tmp') if not tmp.exists(): tmp.mkdir() logfn = tmp/'exe.log' if logfn.exists(): try: logfn.remove() except OSError: pass configParser.system.configDir = tmp configParser.logging.root = 'ERROR' configParser.logging.foo = 'DEBUG' configParser.logging.foo = 'DEBUG'
def _setupConfigFile(self, configParser): """ Override this to setup any customised config settings """ system = configParser.addSection('system') system.exePath = '../exe/exe' system.exeDir = '../exe' system.webDir = '../exe/webui' system.port = 8081 tmpDir = Path('tmp') if not tmpDir.exists(): tmpDir.mkdir() dataDir = tmpDir/'data' if not dataDir.exists(): dataDir.mkdir() system.dataDir = dataDir system.browserPath = 'not really used in tests so far' logging = configParser.addSection('logging') logging.root = 'DEBUG'
def _setupConfigFile(self, configParser): """ Setup our own config file """ utils.SuperTestCase._setupConfigFile(self, configParser) # Create an empty dir to stick the config file tmp = Path('tmp') if not tmp.exists(): tmp.mkdir() logfn = tmp / 'exe.log' if logfn.exists(): try: logfn.remove() except OSError: pass configParser.system.configDir = tmp configParser.logging.root = 'ERROR' configParser.logging.foo = 'DEBUG' configParser.logging.foo = 'DEBUG'
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
def export_to_dir(self, package, outputDir): metainfPages = Path(outputDir.abspath() + '/META-INF') metainfPages.mkdir() contentPages = Path(outputDir.abspath() + '/EPUB') contentPages.mkdir() mimetypeFile = open(outputDir.abspath() + '/mimetype', "w") mimetypeFile.write('application/epub+zip') mimetypeFile.close() Epub3Export.current_package_name = package.name Epub3Export.current_xapi_prefix = \ EXETinCan.get_tincan_prefix_for_pkg(package) Epub3Export.current_package_title = \ package.title #Command line option to override language for export if self.langOverride != None: package.dublinCore.language = self.langOverride #track the number of working idevices on a page #if 0 do not put page in TOC numDevicesByPage = {} #track idevices that dont really export nonDevices = [] # #This is passed from the command line export # if self.forceMediaOnly == True: package.mxmlforcemediaonly = "true" mediaConverter = ExportMediaConverter() mediaConverter.setCurrentPackage(package) ExportMediaConverter.autoMediaOnly = package.mxmlforcemediaonly if 'FORCEMEDIAONLY' in os.environ: ExportMediaConverter.autoMediaOnly = True ExportMediaConverter.setWorkingDir(contentPages) indexPageXML = XMLPage("index", 1, package.root) self.pages = [ indexPageXML ] self.pkgNodeToPageDict = self.generatePagesXML(package.root, 1) self.pkgNodeToPageDict[package.root] = indexPageXML uniquifyNames(self.pages, suffix = ".xhtml") self.generateJQueryMobileTOC(package.root, contentPages) self.copyFilesXML(package, contentPages) prevPage = None thisPage = self.pages[0] for nextPage in self.pages[1:]: pageDevCount = thisPage.save(contentPages, prevPage, \ nextPage, self.pages, nonDevices) numDevicesByPage[thisPage.name] = pageDevCount prevPage = thisPage thisPage = nextPage pageDevCount = thisPage.save(contentPages, prevPage, None, self.pages, nonDevices) numDevicesByPage[thisPage.name] = pageDevCount self._writeTOCXML(contentPages, numDevicesByPage, nonDevices, package) #save the tincan.xml file self.write_tincan_xml(outputDir, package) #now go through and make the HTML output common.setExportDocType("HTML5") self.pages = [ Epub3Cover("cover", 1, package.root) ] self.generatePages(package.root, 2) uniquifyNames(self.pages, suffix=".xhtml") cover = None for page in self.pages: page.save(contentPages, ustadmobile_mode = True) if hasattr(page, 'cover'): cover = page.cover # Create the nav.xhtml file container = NavEpub3(self.pages, contentPages) container.save() # Create the publication file publication = self.make_publication_epub3(contentPages, package, cover) publication.save("package.opf") # Create the container file container = ContainerEpub3(metainfPages) container.save("container.xml") self.generateContentListXML(contentPages, package)
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 / '..' / '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 hasFX = 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 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 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 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') # 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 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()
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)
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()
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 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')
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') quizContentPages = Path(outputDir.abspath() + '/EPUB/tools/quiz') quizImagesPages = Path(quizContentPages.abspath() + '/images') quizScriptsPages = Path(quizContentPages.abspath() + '/scripts') quizVideoPages = Path(quizContentPages.abspath() + '/video') quizCssPages = Path(quizContentPages.abspath() + '/css') quizFilesPages = Path(quizContentPages.abspath() + '/css') # contentPages = outputDir/'Content' contentPages.mkdir() quizContentPages.makedirs() quizImagesPages.mkdir() quizScriptsPages.mkdir() quizVideoPages.mkdir() quizCssPages.mkdir() quizFilesPages.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 cssStyleFiles = [self.styleDir / '..' / 'base.css'] cssStyleFiles += [f for f in self.styleDir.files("*.css") if f.basename() != "nav.css"] imgStyleFiles = [self.styleDir / '..' / 'popup_bg.gif'] imgStyleFiles += self.styleDir.files("*.jpg") imgStyleFiles += self.styleDir.files("*.gif") imgStyleFiles += self.styleDir.files("*.png") scriptStyleFiles = self.styleDir.files("*.js") filesStyleFiles = self.styleDir.files("*.html") filesStyleFiles += self.styleDir.files("*.ttf") filesStyleFiles += self.styleDir.files("*.eot") filesStyleFiles += self.styleDir.files("*.otf") filesStyleFiles += 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(cssStyleFiles, quizCssPages) self.styleDir.copylist(imgStyleFiles, quizImagesPages) self.styleDir.copylist(scriptStyleFiles, quizScriptsPages) self.styleDir.copylist(filesStyleFiles, quizFilesPages) self.scriptsDir.copylist(('common.js',), quizScriptsPages) # 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') # 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()
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 Config: """ The Config class contains the configuration information for eXe. """ optionNames = { 'system': ('webDir', 'xulDir', 'port', 'dataDir', 'configDir', 'localeDir', 'browserPath'), 'user': ('locale',), } def __init__(self): """ Initialise """ self.configPath = None self.configParser = ConfigParser(self.onWrite) self.exePath = Path(sys.argv[0]).abspath() self.webDir = self.exePath.dirname() self.xulDir = self.exePath.dirname() self.localeDir = self.exePath.dirname()/"locale" self.port = 51235 self.dataDir = Path(".") self.configDir = Path(".") self.browserPath = Path("firefox") self.locale = chooseDefaultLocale(self.localeDir) self.styles = [] self.recentProjects = [] self.hiddeniDevices = [] self.deprecatediDevices = [ "flash with text", "flash movie", "mp3", \ "attachment"] self.assumeMediaPlugins = False; self._overrideDefaultVals() self.webDir = Path(self.webDir) if not (self.webDir/'scripts').isdir() \ and (self.webDir/'webui').isdir(): self.webDir /= 'webui' self.xulDir = Path(self.xulDir) if not (self.xulDir/'scripts').isdir() \ and (self.xulDir/'xului').isdir(): self.xulDir /= 'xului' self.__setConfigPath() self._writeDefaultConfigFile() self.loadSettings() self.setupLogging() self.loadStyles() self.loadLocales() def _overrideDefaultVals(self): """ Override this to override the default config values """ def _getConfigPathOptions(self): """ Override this to give a list of possible config filenames in order of preference """ return ['exe.conf'] def _writeDefaultConfigFile(self): """ [Over]writes 'self.configPath' with a default config file (auto write is on so we don't need to write the file at the end) """ for sectionName, optionNames in self.optionNames.items(): for optionName in optionNames: defaultVal = getattr(self, optionName) self.configParser.setdefault(sectionName, optionName, defaultVal) self.configParser.setdefault('logging', 'root', 'INFO') def __setConfigPath(self): """ sets self.configPath to the filename of the config file that we'll use. In descendant classes set self.configFileOptions to a list of directories where the configDir should be in order of preference. If no config files can be found in these dirs, it will force creation of the config file in the top dir """ self.configPath = None configFileOptions = map(Path, self._getConfigPathOptions()) if "EXECONF" in os.environ: envconf = Path(os.environ["EXECONF"]) if envconf.isfile(): self.configPath = os.environ["EXECONF"] if self.configPath is None: for confPath in configFileOptions: if confPath.isfile(): self.configPath = confPath break else: self.configPath = configFileOptions[0] folder = self.configPath.abspath().dirname() if not folder.exists(): folder.makedirs() self.configPath.touch() self.configParser.read(self.configPath) self.configParser.autoWrite = True def upgradeFile(self): """ Called before loading the config file, removes or upgrades any old settings. """ if self.configParser.has_section('system'): system = self.configParser.system if system.has_option('appDataDir'): self.configDir = Path(system.appDataDir) system.configDir = self.configDir del system.appDataDir if system.has_option('greDir'): del system.greDir def loadSettings(self): """ Loads the settings from the exe.conf file. Overrides the defaults set in __init__ """ def defVal(dummy, option): """If something is not in the config file, just use the default in 'self'""" return getattr(self, option) self.configParser.defaultValue = defVal self.upgradeFile() if self.configParser.has_section('system'): system = self.configParser.system self.webDir = Path(system.webDir) self.xulDir = Path(system.xulDir) self.localeDir = Path(system.localeDir) self.port = int(system.port) self.browserPath = Path(system.browserPath) self.dataDir = Path(system.dataDir) self.configDir = Path(system.configDir) self.assumeMediaPlugins = False; if self.configParser.has_option('system', \ 'assumeMediaPlugins'): value = system.assumeMediaPlugins.strip().lower() if value == "1" or value == "yes" or value == "true" or \ value == "on": self.assumeMediaPlugins = True; if not self.dataDir.isdir(): self.dataDir = tempfile.gettempdir() self.webDir = self.webDir.expand().abspath() if not self.configDir.exists(): self.configDir.mkdir() self.recentProjects = [] if self.configParser.has_section('recent_projects'): recentProjectsSection = self.configParser.recent_projects for key, path in recentProjectsSection.items(): self.recentProjects.append(path) self.hiddeniDevices = [] if self.configParser.has_section('idevices'): idevicesSection = self.configParser.idevices for key,value in idevicesSection.items(): value = value.strip().lower() if value == "0" or value == "no" or value == "false" or \ value == "off": self.hiddeniDevices.append(key.lower()) if self.configParser.has_section('deprecated'): deprecatedSection = self.configParser.deprecated for key,value in deprecatedSection.items(): value = value.strip().lower() if value == "1" or value == "yes" or value == "true" or \ value == "on": if key.lower() in self.deprecatediDevices: self.deprecatediDevices.remove(key.lower()) if self.configParser.has_section('user'): if self.configParser.user.has_option('locale'): self.locale = self.configParser.user.locale return self.locale = chooseDefaultLocale(self.localeDir) def onWrite(self, configParser): """ Called just before the config file is written. We use it to fill out any settings that are stored here and not in the config parser itself """ self.configParser.delete('recent_projects') recentProjectsSection = self.configParser.addSection('recent_projects') for num, path in enumerate(self.recentProjects): recentProjectsSection[str(num)] = path def setupLogging(self): """ setup logging file """ try: hdlr = RotatingFileHandler(self.configDir/'exe.log', 'a', 500000, 10) hdlr.doRollover() except OSError: hdlr = logging.FileHandler(self.configDir/'exe.log') format = "%(asctime)s %(name)s %(levelname)s %(message)s" log = logging.getLogger() hdlr.setFormatter(logging.Formatter(format)) log.addHandler(hdlr) loggingLevels = {"DEBUG" : logging.DEBUG, "INFO" : logging.INFO, "WARNING" : logging.WARNING, "ERROR" : logging.ERROR, "CRITICAL" : logging.CRITICAL } if self.configParser.has_section('logging'): for logger, level in self.configParser._sections["logging"].items(): if logger == "root": logging.getLogger().setLevel(loggingLevels[level]) else: logging.getLogger(logger).setLevel(loggingLevels[level]) log.info("************** eXe logging started **************") log.info("configPath = %s" % self.configPath) log.info("exePath = %s" % self.exePath) log.info("browserPath = %s" % self.browserPath) log.info("webDir = %s" % self.webDir) log.info("xulDir = %s" % self.xulDir) log.info("localeDir = %s" % self.localeDir) log.info("port = %d" % self.port) log.info("dataDir = %s" % self.dataDir) log.info("configDir = %s" % self.configDir) log.info("locale = %s" % self.locale) def loadStyles(self): """ Scans the eXe style directory and builds a list of styles """ log = logging.getLogger() self.styles = [] styleDir = self.webDir/"style" log.debug("loadStyles from %s" % styleDir) for subDir in styleDir.dirs(): styleSheet = subDir/'content.css' log.debug(" checking %s" % styleSheet) if styleSheet.exists(): style = subDir.basename() log.debug(" loading style %s" % style) self.styles.append(style) def loadLocales(self): """ Scans the eXe locale directory and builds a list of locales """ log = logging.getLogger() log.debug("loadLocales") gettext.install('exe', self.localeDir, True) self.locales = {} for subDir in self.localeDir.dirs(): if (subDir/'LC_MESSAGES'/'exe.mo').exists(): self.locales[subDir.basename()] = \ gettext.translation('exe', self.localeDir, languages=[str(subDir.basename())]) if subDir.basename() == self.locale: locale = subDir.basename() log.debug(" loading locale %s" % locale) self.locales[locale].install(unicode=True)
class Config: """ The Config class contains the configuration information for eXe. """ # Class attributes optionNames = { 'system': ('webDir', 'xulDir', 'port', 'dataDir', 'configDir', 'localeDir', 'browserPath', ), 'user': ('locale', 'latexpath'), } def __init__(self): """ Initialise """ self.configPath = None self.configParser = ConfigParser(self.onWrite) # Set default values # exePath is the whole path and filename of the exe executable self.exePath = Path(sys.argv[0]).abspath() # webDir is the parent directory for styles,scripts and templates self.webDir = self.exePath.dirname() # xulDir is the parent directory for styles,scripts and templates self.xulDir = self.exePath.dirname() # localeDir is the base directory where all the locales are stored self.localeDir = self.exePath.dirname()/"locale" # port is the port the exe webserver will listen on # (previous default, which earlier users might still use, was 8081) self.port = 51235 # dataDir is the default directory that is shown to the user # to save packages and exports in self.dataDir = Path(".") # configDir is the dir for storing user profiles # and user made idevices and the config file self.configDir = Path(".") # browserPath is the entire pathname to firefox self.browserPath = Path("firefox") # locale is the language of the user self.locale = chooseDefaultLocale(self.localeDir) # internalAnchors indicate which exe_tmp_anchor tags to generate for each tinyMCE field # available values = "enable_all", "disable_autotop", or "disable_all" self.internalAnchors = "enable_all" # styles is the list of style names available for loading self.styles = [] # The documents that we've recently looked at self.recentProjects = [] # canonical (English) names of iDevices not to show in the iDevice pane self.hiddeniDevices = [] # likewise, a canonical (English) names of iDevices not to show in the # iDevice pane but, contrary to the hiddens, these are ones that the # configuration can specify to turn ON: self.deprecatediDevices = [ "flash with text", "flash movie", "mp3", \ "attachment"] # by default, only allow embedding of media types for which a # browser plugin is found: self.assumeMediaPlugins = False; # Let our children override our defaults depending # on the OS that we're running on self._overrideDefaultVals() # Try to make the defaults a little intelligent # Under devel trees, webui is the default webdir self.webDir = Path(self.webDir) if not (self.webDir/'scripts').isdir() \ and (self.webDir/'webui').isdir(): self.webDir /= 'webui' # Under devel trees, xului is the default xuldir self.xulDir = Path(self.xulDir) if not (self.xulDir/'scripts').isdir() \ and (self.xulDir/'xului').isdir(): self.xulDir /= 'xului' # Latex distribution path if environment wasn't set properly self.latexpath = "" # Find where the config file will be saved self.__setConfigPath() # Fill in any undefined config options with our defaults self._writeDefaultConfigFile() # Now we are ready to serve the application self.loadSettings() self.setupLogging() self.loadStyles() self.loadLocales() def _overrideDefaultVals(self): """ Override this to override the default config values """ def _getConfigPathOptions(self): """ Override this to give a list of possible config filenames in order of preference """ return ['exe.conf'] def _writeDefaultConfigFile(self): """ [Over]writes 'self.configPath' with a default config file (auto write is on so we don't need to write the file at the end) """ for sectionName, optionNames in self.optionNames.items(): for optionName in optionNames: defaultVal = getattr(self, optionName) self.configParser.setdefault(sectionName, optionName, defaultVal) # Logging can't really be changed from inside the program at the moment... self.configParser.setdefault('logging', 'root', 'INFO') def _getWinFolder(self, code): """ Gets one of the windows famous directorys depending on 'code' Possible values can be found at: http://msdn.microsoft.com/library/default.asp?url=/library/en-us/shellcc/platform/shell/reference/enums/csidl.asp#CSIDL_WINDOWS """ from ctypes import WinDLL, create_unicode_buffer dll = WinDLL('shell32') # The '5' and the '0' from the below call come from # google: "ShellSpecialConstants site:msdn.microsoft.com" result = create_unicode_buffer(260) resource = dll.SHGetFolderPathW(None, code, None, 0, result) if resource != 0: return Path('') else: return Path(result.value) def __setConfigPath(self): """ sets self.configPath to the filename of the config file that we'll use. In descendant classes set self.configFileOptions to a list of directories where the configDir should be in order of preference. If no config files can be found in these dirs, it will force creation of the config file in the top dir """ # If there's an EXECONF environment variable, use it self.configPath = None configFileOptions = map(Path, self._getConfigPathOptions()) if "EXECONF" in os.environ: envconf = Path(os.environ["EXECONF"]) if envconf.isfile(): self.configPath = os.environ["EXECONF"] # Otherwise find the most appropriate existing file if self.configPath is None: for confPath in configFileOptions: if confPath.isfile(): self.configPath = confPath break else: # If no config files exist, create and use the # first one on the list self.configPath = configFileOptions[0] folder = self.configPath.abspath().dirname() if not folder.exists(): folder.makedirs() self.configPath.touch() # Now make our configParser self.configParser.read(self.configPath) self.configParser.autoWrite = True def upgradeFile(self): """ Called before loading the config file, removes or upgrades any old settings. """ if self.configParser.has_section('system'): system = self.configParser.system if system.has_option('appDataDir'): # Older config files had configDir stored as appDataDir self.configDir = Path(system.appDataDir) # We'll just upgrade their config file for them for now... system.configDir = self.configDir del system.appDataDir if system.has_option('greDir'): # No longer used, system should automatically support del system.greDir def loadSettings(self): """ Loads the settings from the exe.conf file. Overrides the defaults set in __init__ """ # Set up the parser so that if a certain value is not in the config # file, it will use the value from our default values def defVal(dummy, option): """If something is not in the config file, just use the default in 'self'""" return getattr(self, option) self.configParser.defaultValue = defVal self.upgradeFile() # System Section if self.configParser.has_section('system'): system = self.configParser.system self.webDir = Path(system.webDir) self.xulDir = Path(system.xulDir) self.localeDir = Path(system.localeDir) self.port = int(system.port) self.browserPath = Path(system.browserPath) self.dataDir = Path(system.dataDir) self.configDir = Path(system.configDir) self.assumeMediaPlugins = False; if self.configParser.has_option('system', \ 'assumeMediaPlugins'): value = system.assumeMediaPlugins.strip().lower() if value == "1" or value == "yes" or value == "true" or \ value == "on": self.assumeMediaPlugins = True; # If the dataDir points to some other dir, fix it if not self.dataDir.isdir(): self.dataDir = tempfile.gettempdir() # make the webDir absolute, to hide path joins of relative paths self.webDir = self.webDir.expand().abspath() # If the configDir doesn't exist (as it may be a default setting with a # new installation) create it if not self.configDir.exists(): self.configDir.mkdir() # Get the list of recently opened projects self.recentProjects = [] if self.configParser.has_section('recent_projects'): recentProjectsSection = self.configParser.recent_projects for key, path in recentProjectsSection.items(): self.recentProjects.append(path) # Load the list of "hidden" iDevices self.hiddeniDevices = [] if self.configParser.has_section('idevices'): idevicesSection = self.configParser.idevices for key,value in idevicesSection.items(): # emulate standard library's getboolean() value = value.strip().lower() if value == "0" or value == "no" or value == "false" or \ value == "off": self.hiddeniDevices.append(key.lower()) #self.deprecatediDevices = [ "flash with text", "flash movie", ...] # and UN-Load from the list of "deprecated" iDevices if self.configParser.has_section('deprecated'): deprecatedSection = self.configParser.deprecated for key,value in deprecatedSection.items(): # emulate standard library's getboolean() value = value.strip().lower() if value == "1" or value == "yes" or value == "true" or \ value == "on": if key.lower() in self.deprecatediDevices: self.deprecatediDevices.remove(key.lower()) # Load the "user" section if self.configParser.has_section('user'): if self.configParser.user.has_option('internalAnchors'): self.internalAnchors = self.configParser.user.internalAnchors if self.configParser.user.has_option('locale'): self.locale = self.configParser.user.locale return self.locale = chooseDefaultLocale(self.localeDir) def onWrite(self, configParser): """ Called just before the config file is written. We use it to fill out any settings that are stored here and not in the config parser itself """ # Recent projects self.configParser.delete('recent_projects') recentProjectsSection = self.configParser.addSection('recent_projects') for num, path in enumerate(self.recentProjects): recentProjectsSection[str(num)] = path def setupLogging(self): """ setup logging file """ try: hdlr = RotatingFileHandler(self.configDir/'exe.log', 'a', 500000, 10) hdlr.doRollover() except OSError: # ignore the error we get if the log file is logged hdlr = logging.FileHandler(self.configDir/'exe.log') format = "%(asctime)s %(name)s %(levelname)s %(message)s" log = logging.getLogger() hdlr.setFormatter(logging.Formatter(format)) log.addHandler(hdlr) loggingLevels = {"DEBUG" : logging.DEBUG, "INFO" : logging.INFO, "WARNING" : logging.WARNING, "ERROR" : logging.ERROR, "CRITICAL" : logging.CRITICAL } if self.configParser.has_section('logging'): for logger, level in self.configParser._sections["logging"].items(): if logger == "root": logging.getLogger().setLevel(loggingLevels[level]) else: logging.getLogger(logger).setLevel(loggingLevels[level]) log.info("************** eXe logging started **************") log.info("configPath = %s" % self.configPath) log.info("exePath = %s" % self.exePath) log.info("browserPath = %s" % self.browserPath) log.info("webDir = %s" % self.webDir) log.info("xulDir = %s" % self.xulDir) log.info("localeDir = %s" % self.localeDir) log.info("port = %d" % self.port) log.info("dataDir = %s" % self.dataDir) log.info("configDir = %s" % self.configDir) log.info("locale = %s" % self.locale) log.info("internalAnchors = %s" % self.internalAnchors) def loadStyles(self): """ Scans the eXe style directory and builds a list of styles """ log = logging.getLogger() self.styles = [] styleDir = self.webDir/"style" localeStyleDir = self.configDir / "style" if not os.path.exists(localeStyleDir): os.makedirs(localeStyleDir) log.debug("loadStyles from %s" % styleDir) for subDir in styleDir.dirs(): if self.__checkStyle(subDir): styleName = subDir.basename() log.debug(" adding style to style/%s" % styleName) self.styles.append(styleName) # adding style from config to style/locale for subDir in localeStyleDir.dirs(): if self.__checkStyle(subDir): styleName = "locale/" + subDir.basename() log.debug(" adding locale style to style/%s" % styleName) self.styles.append(styleName) def __checkStyle(self, style): '''Checks if it's valid style''' styleSheet = style / 'content.css' return styleSheet.exists() def loadLocales(self): """ Scans the eXe locale directory and builds a list of locales """ log = logging.getLogger() log.debug("loadLocales") gettext.install('exe', self.localeDir, True) self.locales = {} for subDir in self.localeDir.dirs(): if (subDir/'LC_MESSAGES'/'exe.mo').exists(): self.locales[subDir.basename()] = \ gettext.translation('exe', self.localeDir, languages=[str(subDir.basename())]) if subDir.basename() == self.locale: locale = subDir.basename() log.debug(" loading locale %s" % locale) self.locales[locale].install(unicode=True)
class Config(object): """ The Config class contains the configuration information for eXe. """ # To build link to git revision baseGitWebURL = 'https://github.com/exelearning/iteexe' # Class attributes optionNames = { 'system': ('webDir', 'jsDir', 'port', 'dataDir', 'configDir', 'localeDir', 'stylesRepository', 'browser', 'mediaProfilePath', 'videoMediaConverter_ogv', 'videoMediaConverter_3gp', 'videoMediaConverter_mpg', 'videoMediaConverter_avi', 'audioMediaConverter_ogg', 'audioMediaConverter_au', 'audioMediaConverter_mp3', 'audioMediaConverter_wav', 'ffmpegPath'), 'user': ('locale', 'lastDir', 'showPreferencesOnStart', 'defaultStyle', 'showIdevicesGrouped', 'docType', 'editorMode', 'editorVersion', 'defaultLicense'), } idevicesCategories = { 'activity': [x_('Non-Interactive Activities')], 'reading activity': [x_('Non-Interactive Activities')], 'dropdown activity': [x_('Interactive Activities')], 'java applet': [x_('Non-Textual Information')], 'wiki article': [x_('Non-Textual Information')], 'case study': [x_('Non-Interactive Activities')], 'preknowledge': [x_('Textual Information')], 'scorm quiz': [x_('Interactive Activities')], 'fpd - multi choice activity': [x_('FPD')], 'fpd - cloze activity': [x_('FPD')], 'fpd - cloze activity (modified)': [x_('FPD')], 'fpd - multi select activity': [x_('FPD')], 'fpd - true/false activity': [x_('FPD')], 'fpd - situation': [x_('FPD')], 'fpd - quotation': [x_('FPD')], 'fpd - you should know': [x_('FPD')], 'fpd - highlighted': [x_('FPD')], 'fpd - translation': [x_('FPD')], 'fpd - guidelines students': [x_('FPD')], 'fpd - guidelines teacher': [x_('FPD')], 'fpd - a step ahead': [x_('FPD')], 'fpd - a piece of advice': [x_('FPD')], 'fpd - think about it (with feedback)': [x_('FPD')], 'fpd - think about it (without feedback)': [x_('FPD')], 'fpd - free text': [x_('FPD')], 'image gallery': [x_('Non-Textual Information')], 'image magnifier': [x_('Non-Textual Information')], 'note': [x_('Textual Information')], 'objectives': [x_('Textual Information')], 'multi-choice': [x_('Interactive Activities')], 'multi-select': [x_('Interactive Activities')], 'true-false question': [x_('Interactive Activities')], 'reflection': [x_('Non-Interactive Activities')], 'cloze activity': [x_('Interactive Activities')], 'rss': [x_('Non-Textual Information')], 'external web site': [x_('Non-Textual Information')], 'free text': [x_('Textual Information')], 'click in order game': [x_('Experimental')], 'hangman game': [x_('Experimental')], 'place the objects': [x_('Interactive Activities')], 'memory match game': [x_('Experimental')], 'file attachments': [x_('Non-Textual Information')], 'sort items': [x_('Experimental')] } @classmethod def getConfigPath(cls): obj = cls.__new__(cls) obj.configParser = ConfigParser() obj._overrideDefaultVals() obj.__setConfigPath() return obj.configPath def __init__(self): """ Initialise """ self.configPath = None self.configParser = ConfigParser(self.onWrite) # Set default values # exePath is the whole path and filename of the exe executable self.exePath = Path(sys.argv[0]).abspath() # webDir is the parent directory for styles,scripts and templates self.webDir = self.exePath.dirname() self.jsDir = self.exePath.dirname() self.locales = {} # localeDir is the base directory where all the locales are stored self.localeDir = self.exePath.dirname()/"locale" # port is the port the exe webserver will listen on # (previous default, which earlier users might still use, was 8081) self.port = 51235 # dataDir is the default directory that is shown to the user # to save packages and exports in self.dataDir = Path(".") # configDir is the dir for storing user profiles # and user made idevices and the config file self.configDir = Path(".") # FM: New Styles Directory path self.stylesDir = Path(self.configDir/'style').abspath() # FM: Default Style name self.defaultStyle = u"INTEF" # Styles repository XML-RPC endpoint # self.stylesRepository = 'http://www.exelearning.es/xmlrpc.php' self.stylesRepository = 'http://www.exelearning.net/xmlrpc.php' # browser is the name of a predefined browser specified # at http://docs.python.org/library/webbrowser.html. # None for system default self.browser = None # docType is the HTML export format self.docType = 'HTML5' # internalAnchors indicate which exe_tmp_anchor tags to generate for each tinyMCE field # available values = "enable_all", "disable_autotop", or "disable_all" self.internalAnchors = "enable_all" self.lastDir = None self.showPreferencesOnStart = "1" self.showIdevicesGrouped = "1" # tinymce option self.editorMode = 'permissive' self.editorVersion = '4' # styleSecureMode : if this [user] key is = 0 , exelearning can run python files in styles # as websitepage.py , ... ( deactivate secure mode ) self.styleSecureMode = "1" # styles is the list of style names available for loading self.styles = [] # The documents that we've recently looked at self.recentProjects = [] # canonical (English) names of iDevices not to show in the iDevice pane self.hiddeniDevices = [] # Media conversion programs used for XML export system self.videoMediaConverter_ogv = "" self.videoMediaConverter_3gp = "" self.videoMediaConverter_avi = "" self.videoMediaConverter_mpg = "" self.audioMediaConverter_ogg = "" self.audioMediaConverter_au = "" self.audioMediaConverter_mp3 = "" self.audioMediaConverter_wav = "" self.ffmpegPath = "" self.mediaProfilePath = self.exePath.dirname()/'mediaprofiles' # likewise, a canonical (English) names of iDevices not to show in the # iDevice pane but, contrary to the hiddens, these are ones that the # configuration can specify to turn ON: self.deprecatediDevices = ["flash with text", "flash movie", "mp3", "attachment"] # by default, only allow embedding of media types for which a # browser plugin is found: self.defaultLicense='creative commons: attribution - share alike 4.0' self.assumeMediaPlugins = False # Let our children override our defaults depending # on the OS that we're running on self._overrideDefaultVals() # locale is the language of the user. localeDir can be overridden # that's why we must set it _after_ the call to _overrideDefaultVals() self.locale = chooseDefaultLocale(self.localeDir) # Try to make the defaults a little intelligent # Under devel trees, webui is the default webdir self.webDir = Path(self.webDir) if not (self.webDir/'scripts').isdir() \ and (self.webDir/'webui').isdir(): self.webDir /= 'webui' self.jsDir = Path(self.jsDir) if not (self.jsDir/'scripts').isdir() \ and (self.jsDir/'jsui').isdir(): self.jsDir /= 'jsui' # Find where the config file will be saved self.__setConfigPath() # Fill in any undefined config options with our defaults self._writeDefaultConfigFile() # Now we are ready to serve the application self.loadSettings() self.setupLogging() self.loadLocales() self.loadStyles() def _overrideDefaultVals(self): """ Override this to override the default config values """ def _getConfigPathOptions(self): """ Override this to give a list of possible config filenames in order of preference """ return ['exe.conf'] def _writeDefaultConfigFile(self): """ [Over]writes 'self.configPath' with a default config file (auto write is on so we don't need to write the file at the end) """ if not G.application.portable: for sectionName, optionNames in self.optionNames.items(): for optionName in optionNames: defaultVal = getattr(self, optionName) self.configParser.setdefault(sectionName, optionName, defaultVal) # Logging can't really be changed from inside the program at the moment... self.configParser.setdefault('logging', 'root', 'INFO') def __setConfigPath(self): """ sets self.configPath to the filename of the config file that we'll use. In descendant classes set self.configFileOptions to a list of directories where the configDir should be in order of preference. If no config files can be found in these dirs, it will force creation of the config file in the top dir """ # If there's an EXECONF environment variable, use it self.configPath = None configFileOptions = map(Path, self._getConfigPathOptions()) if "EXECONF" in os.environ: envconf = Path(os.environ["EXECONF"]) if envconf.isfile(): self.configPath = os.environ["EXECONF"] # Otherwise find the most appropriate existing file if self.configPath is None: for confPath in configFileOptions: if confPath.isfile(): self.configPath = confPath break else: # If no config files exist, create and use the # first one on the list self.configPath = configFileOptions[0] folder = self.configPath.abspath().dirname() if not folder.exists(): folder.makedirs() self.configPath.touch() # Now make our configParser self.configParser.read(self.configPath) self.configParser.autoWrite = True def upgradeFile(self): """ Called before loading the config file, removes or upgrades any old settings. """ if self.configParser.has_section('system'): system = self.configParser.system if system.has_option('appDataDir'): # Older config files had configDir stored as appDataDir self.configDir = Path(system.appDataDir) self.stylesDir = Path(self.configDir)/'style' # We'll just upgrade their config file for them for now... system.configDir = self.configDir system.stylesDir = Path(self.configDir)/'style' del system.appDataDir self.audioMediaConverter_au = system.audioMediaConverter_au self.audioMediaConverter_wav = system.audioMediaConverter_wav self.videoMediaConverter_ogv = system.videoMediaConverter_ogv self.videoMediaConverter_3gp = system.videoMediaConverter_3gp self.videoMediaConverter_avi = system.videoMediaConverter_avi self.videoMediaConverter_mpg = system.videoMediaConverter_mpg self.audioMediaConverter_ogg = system.audioMediaConverter_ogg self.audioMediaConverter_mp3 = system.audioMediaConverter_mp3 self.ffmpegPath = system.ffmpegPath self.mediaProfilePath = system.mediaProfilePath if system.has_option('greDir'): # No longer used, system should automatically support del system.greDir if system.has_option('xulDir'): del system.xulDir # if system.has_option('browser'): # del system.browser def loadSettings(self): """ Loads the settings from the exe.conf file. Overrides the defaults set in __init__ """ # Set up the parser so that if a certain value is not in the config # file, it will use the value from our default values def defVal(dummy, option): """If something is not in the config file, just use the default in 'self'""" return getattr(self, option) self.configParser.defaultValue = defVal self.upgradeFile() # System Section if self.configParser.has_section('system'): system = self.configParser.system self.port = int(system.port) self.browser = None if system.browser == u"None" else system.browser self.stylesRepository = system.stylesRepository if not G.application.portable: self.dataDir = Path(system.dataDir) self.configDir = Path(system.configDir) self.webDir = Path(system.webDir) self.stylesDir = Path(self.configDir)/'style' self.jsDir = Path(system.jsDir) else: self.stylesDir = Path(self.webDir/'style').abspath() self.assumeMediaPlugins = False if self.configParser.has_option('system', 'assumeMediaPlugins'): value = system.assumeMediaPlugins.strip().lower() if value == "1" or value == "yes" or value == "true" or value == "on": self.assumeMediaPlugins = True # If the dataDir points to some other dir, fix it if not self.dataDir.isdir(): self.dataDir = tempfile.gettempdir() # make the webDir absolute, to hide path joins of relative paths self.webDir = self.webDir.expand().abspath() # If the configDir doesn't exist (as it may be a default setting with a # new installation) create it if not self.configDir.exists(): self.configDir.mkdir() if not G.application.standalone: # FM: Copy styles if not os.path.exists(self.stylesDir) or not os.listdir(self.stylesDir): self.copyStyles() else: self.updateStyles() else: if G.application.portable: if os.name == 'posix': self.stylesDir = Path(self.webDir/'..'/'..'/'..'/'style') else: self.stylesDir = Path(self.webDir/'..'/'style') if not os.path.exists(self.stylesDir) or not os.listdir(self.stylesDir): self.copyStyles() else: self.stylesDir = Path(self.webDir/'style').abspath() # Get the list of recently opened projects self.recentProjects = [] if self.configParser.has_section('recent_projects'): recentProjectsSection = self.configParser.recent_projects # recentProjectsSection.items() is in the wrong order, keys are alright. # Sorting list by key before adding to self.recentProjects, to avoid wrong ordering # in Recent Projects menu list recentProjectsItems = recentProjectsSection.items() recentProjectsItems.sort() for key, path in recentProjectsItems: self.recentProjects.append(path) # Load the list of "hidden" iDevices self.hiddeniDevices = [] if self.configParser.has_section('idevices'): idevicesSection = self.configParser.idevices for key, value in idevicesSection.items(): # emulate standard library's getboolean() value = value.strip().lower() if value == "0" or value == "no" or value == "false" or \ value == "off": self.hiddeniDevices.append(key.lower()) # self.deprecatediDevices = [ "flash with text", "flash movie", ...] # and UN-Load from the list of "deprecated" iDevices if self.configParser.has_section('deprecated'): deprecatedSection = self.configParser.deprecated for key, value in deprecatedSection.items(): # emulate standard library's getboolean() value = value.strip().lower() if value == "1" or value == "yes" or value == "true" or \ value == "on": if key.lower() in self.deprecatediDevices: self.deprecatediDevices.remove(key.lower()) # Load the "user" section if self.configParser.has_section('user'): if self.configParser.user.has_option('editorMode'): self.editorMode = self.configParser.user.editorMode if self.configParser.user.has_option('editorVersion'): self.editorVersion = self.configParser.user.editorVersion if self.configParser.user.has_option('docType'): self.docType = self.configParser.user.docType common.setExportDocType(self.configParser.user.docType) if self.configParser.user.has_option('defaultStyle'): self.defaultStyle = self.configParser.user.defaultStyle if self.configParser.user.has_option('styleSecureMode'): self.styleSecureMode = self.configParser.user.styleSecureMode if self.configParser.user.has_option('internalAnchors'): self.internalAnchors = self.configParser.user.internalAnchors if self.configParser.user.has_option('lastDir'): self.lastDir = self.configParser.user.lastDir if self.configParser.user.has_option('showPreferencesOnStart'): self.showPreferencesOnStart = self.configParser.user.showPreferencesOnStart if self.configParser.user.has_option('showIdevicesGrouped'): self.showIdevicesGrouped = self.configParser.user.showIdevicesGrouped if self.configParser.user.has_option('locale'): self.locale = self.configParser.user.locale if self.configParser.user.has_option('defaultLicense'): self.defaultLicense = self.configParser.user.defaultLicense def onWrite(self, configParser): """ Called just before the config file is written. We use it to fill out any settings that are stored here and not in the config parser itself """ # Recent projects self.configParser.delete('recent_projects') recentProjectsSection = self.configParser.addSection('recent_projects') for num, path in enumerate(self.recentProjects): recentProjectsSection[str(num)] = path def setupLogging(self): """ setup logging file """ try: hdlr = RotatingFileHandler(self.configDir/'exe.log', 'a', 500000, 10) hdlr.doRollover() except OSError: # ignore the error we get if the log file is logged hdlr = logging.FileHandler(self.configDir/'exe.log') format = "%(asctime)s %(name)s %(levelname)s %(message)s" log = logging.getLogger() hdlr.setFormatter(logging.Formatter(format)) log.addHandler(hdlr) loggingLevels = {"DEBUG" : logging.DEBUG, "INFO" : logging.INFO, "WARNING" : logging.WARNING, "ERROR" : logging.ERROR, "CRITICAL" : logging.CRITICAL} if self.configParser.has_section('logging'): for logger, level in self.configParser._sections["logging"].items(): if logger == "root": logging.getLogger().setLevel(loggingLevels[level]) else: logging.getLogger(logger).setLevel(loggingLevels[level]) if not G.application.portable: log.info("************** eXe logging started **************") log.info("version = %s" % version.version) log.info("configPath = %s" % self.configPath) log.info("exePath = %s" % self.exePath) log.info("libPath = %s" % Path(twisted.__path__[0]).splitpath()[0]) log.info("browser = %s" % self.browser) log.info("webDir = %s" % self.webDir) log.info("jsDir = %s" % self.jsDir) log.info("localeDir = %s" % self.localeDir) log.info("port = %d" % self.port) log.info("dataDir = %s" % self.dataDir) log.info("configDir = %s" % self.configDir) log.info("locale = %s" % self.locale) log.info("internalAnchors = %s" % self.internalAnchors) log.info("License = %s" % self.defaultLicense) def loadStyles(self): """ Scans the eXe style directory and builds a list of styles """ self.styleStore = StyleStore(self) listStyles = self.styleStore.getStyles() for style in listStyles: self.styles.append(style) # print style def copyStyles(self): bkstyle = self.webDir/'style' dststyle = self.stylesDir if os.path.exists(bkstyle): if os.path.exists(dststyle) and not os.listdir(self.stylesDir): shutil.rmtree(dststyle) shutil.copytree(bkstyle, dststyle) def updateStyles(self): bkstyle = self.webDir/'style' dststyle = self.stylesDir if os.stat(bkstyle).st_mtime - os.stat(dststyle).st_mtime > 1: for name in os.listdir(bkstyle): bksdirstyle = os.path.join(bkstyle, name) dstdirstyle = os.path.join(dststyle, name) if os.path.isdir(bksdirstyle): if os.path.exists(dstdirstyle): shutil.rmtree(dstdirstyle) shutil.copytree(bksdirstyle, dstdirstyle) else: shutil.copy(bksdirstyle, dstdirstyle) def loadLocales(self): """ Scans the eXe locale directory and builds a list of locales """ log = logging.getLogger() log.debug("loadLocales") gettext.install('exe', self.localeDir, True) for subDir in self.localeDir.dirs(): if (subDir/'LC_MESSAGES'/'exe.mo').exists(): self.locales[subDir.basename()] = \ gettext.translation('exe', self.localeDir, languages=[str(subDir.basename())]) if self.locale not in self.locales: self.locale = 'en' log.debug("loading locale %s" % self.locale) self.locales[self.locale].install(unicode=True) __builtins__['c_'] = lambda s: self.locales[self.locale].ugettext(s) if s else s
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 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 Config: """ The Config class contains the configuration information for eXe. """ optionNames = { "system": ("webDir", "xulDir", "port", "dataDir", "configDir", "localeDir", "browserPath"), "user": ("locale",), } def __init__(self): """ Initialise """ self.configPath = None self.configParser = ConfigParser() self.exePath = Path(sys.argv[0]).abspath() self.webDir = self.exePath.dirname() self.xulDir = self.exePath.dirname() self.localeDir = self.exePath.dirname() / "locale" self.port = 51235 self.dataDir = Path(".") self.configDir = Path(".") self.browserPath = Path("firefox") self.locale = chooseDefaultLocale(self.localeDir) self.styles = [] self._overrideDefaultVals() self.webDir = Path(self.webDir) if not (self.webDir / "scripts").isdir() and (self.webDir / "webui").isdir(): self.webDir /= "webui" self.xulDir = Path(self.xulDir) if not (self.xulDir / "scripts").isdir() and (self.xulDir / "xului").isdir(): self.xulDir /= "xului" self.__setConfigPath() self._writeDefaultConfigFile() self.loadSettings() self.setupLogging() self.loadStyles() self.loadLocales() def _overrideDefaultVals(self): """ Override this to override the default config values """ def _getConfigPathOptions(self): """ Override this to give a list of possible config filenames in order of preference """ return ["exe.conf"] def _writeDefaultConfigFile(self): """ [Over]writes 'self.configPath' with a default config file (auto write is on so we don't need to write the file at the end) """ for sectionName, optionNames in self.optionNames.items(): for optionName in optionNames: defaultVal = getattr(self, optionName) self.configParser.setdefault(sectionName, optionName, defaultVal) self.configParser.setdefault("logging", "root", "INFO") def __setConfigPath(self): """ sets self.configPath to the filename of the config file that we'll use. In descendant classes set self.configFileOptions to a list of directories where the configDir should be in order of preference. If no config files can be found in these dirs, it will force creation of the config file in the top dir """ self.configPath = None configFileOptions = map(Path, self._getConfigPathOptions()) if "EXECONF" in os.environ: envconf = Path(os.environ["EXECONF"]) if envconf.isfile(): self.configPath = os.environ["EXECONF"] if self.configPath is None: for confPath in configFileOptions: if confPath.isfile(): self.configPath = confPath break else: self.configPath = configFileOptions[0] folder = self.configPath.abspath().dirname() if not folder.exists(): folder.makedirs() self.configPath.touch() self.configParser.read(self.configPath) self.configParser.autoWrite = True def upgradeFile(self): """ Called before loading the config file, removes or upgrades any old settings. """ if self.configParser.has_section("system"): system = self.configParser.system if system.has_option("appDataDir"): self.configDir = Path(system.appDataDir) system.configDir = self.configDir del system.appDataDir if system.has_option("greDir"): del system.greDir def loadSettings(self): """ Loads the settings from the exe.conf file. Overrides the defaults set in __init__ """ def defVal(dummy, option): """If something is not in the config file, just use the default in 'self'""" return getattr(self, option) self.configParser.defaultValue = defVal self.upgradeFile() if self.configParser.has_section("system"): system = self.configParser.system self.webDir = Path(system.webDir) self.xulDir = Path(system.xulDir) self.localeDir = Path(system.localeDir) self.port = int(system.port) self.browserPath = Path(system.browserPath) self.dataDir = Path(system.dataDir) self.configDir = Path(system.configDir) if not self.dataDir.isdir(): self.dataDir = tempfile.gettempdir() self.webDir = self.webDir.expand().abspath() if not self.configDir.exists(): self.configDir.mkdir() if self.configParser.has_section("user"): if self.configParser.user.has_option("locale"): self.locale = self.configParser.user.locale return self.locale = chooseDefaultLocale(self.localeDir) def setupLogging(self): """ setup logging file """ try: hdlr = RotatingFileHandler(self.configDir / "exe.log", "a", 500000, 10) hdlr.doRollover() except OSError: hdlr = logging.FileHandler(self.configDir / "exe.log") format = "%(asctime)s %(name)s %(levelname)s %(message)s" log = logging.getLogger() hdlr.setFormatter(logging.Formatter(format)) log.addHandler(hdlr) loggingLevels = { "DEBUG": logging.DEBUG, "INFO": logging.INFO, "WARNING": logging.WARNING, "ERROR": logging.ERROR, "CRITICAL": logging.CRITICAL, } if self.configParser.has_section("logging"): for logger, level in self.configParser._sections["logging"].items(): if logger == "root": logging.getLogger().setLevel(loggingLevels[level]) else: logging.getLogger(logger).setLevel(loggingLevels[level]) log.info("************** eXe logging started **************") log.info("configPath = %s" % self.configPath) log.info("exePath = %s" % self.exePath) log.info("browserPath = %s" % self.browserPath) log.info("webDir = %s" % self.webDir) log.info("xulDir = %s" % self.xulDir) log.info("localeDir = %s" % self.localeDir) log.info("port = %d" % self.port) log.info("dataDir = %s" % self.dataDir) log.info("configDir = %s" % self.configDir) log.info("locale = %s" % self.locale) def loadStyles(self): """ Scans the eXe style directory and builds a list of styles """ log = logging.getLogger() self.styles = [] styleDir = self.webDir / "style" log.debug("loadStyles from %s" % styleDir) for subDir in styleDir.dirs(): styleSheet = subDir / "content.css" log.debug(" checking %s" % styleSheet) if styleSheet.exists(): style = subDir.basename() log.debug(" loading style %s" % style) self.styles.append(style) def loadLocales(self): """ Scans the eXe locale directory and builds a list of locales """ log = logging.getLogger() log.debug("loadLocales") gettext.install("exe", self.localeDir, True) self.locales = {} for subDir in self.localeDir.dirs(): if (subDir / "LC_MESSAGES" / "exe.mo").exists(): self.locales[subDir.basename()] = gettext.translation( "exe", self.localeDir, languages=[str(subDir.basename())] ) if subDir.basename() == self.locale: locale = subDir.basename() log.debug(" loading locale %s" % locale) self.locales[locale].install(unicode=True)
class Config(object): """ The Config class contains the configuration information for eXe. """ # To build link to git revision baseGitWebURL = 'https://forja.cenatic.es/plugins/scmgit/cgi-bin/gitweb.cgi?p=iteexe/iteexe.git' # Class attributes optionNames = { 'system': ('webDir', 'jsDir', 'port', 'dataDir', 'configDir', 'localeDir', 'browser', 'mediaProfilePath', 'videoMediaConverter_ogv', 'videoMediaConverter_3gp', 'videoMediaConverter_mpg', 'videoMediaConverter_avi', 'audioMediaConverter_ogg', 'audioMediaConverter_au', 'audioMediaConverter_mp3', 'audioMediaConverter_wav', 'ffmpegPath'), 'user': ('locale', 'lastDir', 'showPreferencesOnStart','defaultStyle', 'showIdevicesGrouped','docType','editorMode'), } idevicesCategories = { 'activity': [x_('Non-Interactive Activities')], 'reading activity': [x_('Non-Interactive Activities')], 'dropdown activity': [x_('Interactive Activities')], 'java applet': [x_('Non-Textual Information')], 'wiki article': [x_('Non-Textual Information')], 'case study': [x_('Non-Interactive Activities')], 'preknowledge': [x_('Textual Information')], 'scorm quiz': [x_('Interactive Activities')], 'fpd - multi choice activity': [x_('FPD')], 'fpd - cloze activity': [x_('FPD')], 'fpd - cloze activity (modified)': [x_('FPD')], 'fpd - multi select activity': [x_('FPD')], 'fpd - true/false activity': [x_('FPD')], 'fpd - situation': [x_('FPD')], 'fpd - quotation': [x_('FPD')], 'fpd - you should know': [x_('FPD')], 'fpd - highlighted': [x_('FPD')], 'fpd - translation': [x_('FPD')], 'fpd - guidelines students': [x_('FPD')], 'fpd - guidelines teacher': [x_('FPD')], 'fpd - a step ahead': [x_('FPD')], 'fpd - a piece of advice': [x_('FPD')], 'fpd - think about it (with feedback)': [x_('FPD')], 'fpd - think about it (without feedback)': [x_('FPD')], 'fpd - free text': [x_('FPD')], 'image gallery': [x_('Non-Textual Information')], 'image magnifier': [x_('Non-Textual Information')], 'note': [x_('Textual Information')], 'objectives': [x_('Textual Information')], 'multi-choice': [x_('Interactive Activities')], 'multi-select': [x_('Interactive Activities')], 'true-false question': [x_('Interactive Activities')], 'reflection': [x_('Non-Interactive Activities')], 'cloze activity': [x_('Interactive Activities')], 'rss': [x_('Non-Textual Information')], 'external web site': [x_('Non-Textual Information')], 'free text': [x_('Textual Information')], 'click in order game': [x_('Experimental')], 'hangman game': [x_('Experimental')], 'place the objects': [x_('Interactive Activities')], 'memory match game': [x_('Experimental')], 'file attachments': [x_('Non-Textual Information')], 'sort items': [x_('Experimental')], 'sort items': [x_('Interactive Activities')], 'scorm test cloze': [x_('Interactive Activities')], 'scorm test cloze (multiple options)': [x_('Interactive Activities')], 'scorm test dropdown': [x_('Interactive Activities')], 'scorm test multiple choice': [x_('Interactive Activities')] } @classmethod def getConfigPath(cls): obj = cls.__new__(cls) obj.configParser = ConfigParser() obj._overrideDefaultVals() obj.__setConfigPath() return obj.configPath def __init__(self): """ Initialise """ self.configPath = None self.configParser = ConfigParser(self.onWrite) # Set default values # exePath is the whole path and filename of the exe executable self.exePath = Path(sys.argv[0]).abspath() # webDir is the parent directory for styles,scripts and templates self.webDir = self.exePath.dirname() self.jsDir = self.exePath.dirname() # localeDir is the base directory where all the locales are stored self.localeDir = self.exePath.dirname()/"locale" # port is the port the exe webserver will listen on # (previous default, which earlier users might still use, was 8081) self.port = 51235 # dataDir is the default directory that is shown to the user # to save packages and exports in self.dataDir = Path(".") # configDir is the dir for storing user profiles # and user made idevices and the config file self.configDir = Path(".") #FM: New Styles Directory path self.stylesDir =Path(self.configDir/'style').abspath() #FM: Default Style name self.defaultStyle= u"standardwhite" # browser is the name of a predefined browser specified at http://docs.python.org/library/webbrowser.html. # None for system default self.browser = None # docType is the HTML export format self.docType = 'XHTML' # locale is the language of the user self.locale = chooseDefaultLocale(self.localeDir) # internalAnchors indicate which exe_tmp_anchor tags to generate for each tinyMCE field # available values = "enable_all", "disable_autotop", or "disable_all" self.internalAnchors = "enable_all" self.lastDir = None self.showPreferencesOnStart = "1" self.showIdevicesGrouped = "1" # tinymce option self.editorMode = 'permissive' # styleSecureMode : if this [user] key is = 0 , exelearning can run python files in styles # as websitepage.py , ... ( deactivate secure mode ) self.styleSecureMode="1" # styles is the list of style names available for loading self.styles = [] # The documents that we've recently looked at self.recentProjects = [] # canonical (English) names of iDevices not to show in the iDevice pane self.hiddeniDevices = [] #Media conversion programs used for XML export system self.videoMediaConverter_ogv = "" self.videoMediaConverter_3gp = "" self.videoMediaConverter_avi = "" self.videoMediaConverter_mpg = "" self.audioMediaConverter_ogg = "" self.audioMediaConverter_au = "" self.audioMediaConverter_mp3 = "" self.audioMediaConverter_wav = "" self.ffmpegPath = "" self.mediaProfilePath = self.exePath.dirname()/'mediaprofiles' # likewise, a canonical (English) names of iDevices not to show in the # iDevice pane but, contrary to the hiddens, these are ones that the # configuration can specify to turn ON: self.deprecatediDevices = [ "flash with text", "flash movie", "mp3", \ "attachment"] # by default, only allow embedding of media types for which a # browser plugin is found: self.assumeMediaPlugins = False; # Let our children override our defaults depending # on the OS that we're running on self._overrideDefaultVals() # Try to make the defaults a little intelligent # Under devel trees, webui is the default webdir self.webDir = Path(self.webDir) if not (self.webDir/'scripts').isdir() \ and (self.webDir/'webui').isdir(): self.webDir /= 'webui' self.jsDir = Path(self.jsDir) if not (self.jsDir/'scripts').isdir() \ and (self.jsDir/'jsui').isdir(): self.jsDir /= 'jsui' # Find where the config file will be saved self.__setConfigPath() # Fill in any undefined config options with our defaults self._writeDefaultConfigFile() # Now we are ready to serve the application self.loadSettings() self.setupLogging() self.loadLocales() self.loadStyles() def _overrideDefaultVals(self): """ Override this to override the default config values """ def _getConfigPathOptions(self): """ Override this to give a list of possible config filenames in order of preference """ return ['exe.conf'] def _writeDefaultConfigFile(self): """ [Over]writes 'self.configPath' with a default config file (auto write is on so we don't need to write the file at the end) """ if not G.application.portable: for sectionName, optionNames in self.optionNames.items(): for optionName in optionNames: defaultVal = getattr(self, optionName) self.configParser.setdefault(sectionName, optionName, defaultVal) # Logging can't really be changed from inside the program at the moment... self.configParser.setdefault('logging', 'root', 'INFO') def __setConfigPath(self): """ sets self.configPath to the filename of the config file that we'll use. In descendant classes set self.configFileOptions to a list of directories where the configDir should be in order of preference. If no config files can be found in these dirs, it will force creation of the config file in the top dir """ # If there's an EXECONF environment variable, use it self.configPath = None configFileOptions = map(Path, self._getConfigPathOptions()) if "EXECONF" in os.environ: envconf = Path(os.environ["EXECONF"]) if envconf.isfile(): self.configPath = os.environ["EXECONF"] # Otherwise find the most appropriate existing file if self.configPath is None: for confPath in configFileOptions: if confPath.isfile(): self.configPath = confPath break else: # If no config files exist, create and use the # first one on the list self.configPath = configFileOptions[0] folder = self.configPath.abspath().dirname() if not folder.exists(): folder.makedirs() self.configPath.touch() # Now make our configParser self.configParser.read(self.configPath) self.configParser.autoWrite = True def upgradeFile(self): """ Called before loading the config file, removes or upgrades any old settings. """ if self.configParser.has_section('system'): system = self.configParser.system if system.has_option('appDataDir'): # Older config files had configDir stored as appDataDir self.configDir = Path(system.appDataDir) self.stylesDir =Path(self.configDir)/'style' # We'll just upgrade their config file for them for now... system.configDir = self.configDir system.stylesDir =Path(self.configDir)/'style' del system.appDataDir self.audioMediaConverter_au = system.audioMediaConverter_au self.audioMediaConverter_wav = system.audioMediaConverter_wav self.videoMediaConverter_ogv = system.videoMediaConverter_ogv self.videoMediaConverter_3gp = system.videoMediaConverter_3gp self.videoMediaConverter_avi = system.videoMediaConverter_avi self.videoMediaConverter_mpg = system.videoMediaConverter_mpg self.audioMediaConverter_ogg = system.audioMediaConverter_ogg self.audioMediaConverter_mp3 = system.audioMediaConverter_mp3 self.ffmpegPath = system.ffmpegPath self.mediaProfilePath = system.mediaProfilePath if system.has_option('greDir'): # No longer used, system should automatically support del system.greDir def loadSettings(self): """ Loads the settings from the exe.conf file. Overrides the defaults set in __init__ """ # Set up the parser so that if a certain value is not in the config # file, it will use the value from our default values def defVal(dummy, option): """If something is not in the config file, just use the default in 'self'""" return getattr(self, option) self.configParser.defaultValue = defVal self.upgradeFile() # System Section if self.configParser.has_section('system'): system = self.configParser.system self.port = int(system.port) self.browser = None if system.browser == u"None" else system.browser if not G.application.portable: self.dataDir = Path(system.dataDir) self.configDir = Path(system.configDir) self.webDir = Path(system.webDir) self.stylesDir = Path(self.configDir)/'style' self.jsDir = Path(system.jsDir) else: self.stylesDir = Path(self.webDir/'style').abspath() self.assumeMediaPlugins = False; if self.configParser.has_option('system', \ 'assumeMediaPlugins'): value = system.assumeMediaPlugins.strip().lower() if value == "1" or value == "yes" or value == "true" or \ value == "on": self.assumeMediaPlugins = True; # If the dataDir points to some other dir, fix it if not self.dataDir.isdir(): self.dataDir = tempfile.gettempdir() # make the webDir absolute, to hide path joins of relative paths self.webDir = self.webDir.expand().abspath() # If the configDir doesn't exist (as it may be a default setting with a # new installation) create it if not self.configDir.exists(): self.configDir.mkdir() if not G.application.standalone: #FM: Copy styles if not os.path.exists(self.stylesDir) or not os.listdir(self.stylesDir): self.copyStyles() else: self.updateStyles() else: if G.application.portable: if os.name == 'posix': self.stylesDir = Path(self.webDir/'..'/'..'/'..'/'style') else: self.stylesDir = Path(self.webDir/'..'/'style') if not os.path.exists(self.stylesDir) or not os.listdir(self.stylesDir): self.copyStyles() else: self.stylesDir = Path(self.webDir/'style').abspath() # Get the list of recently opened projects self.recentProjects = [] if self.configParser.has_section('recent_projects'): recentProjectsSection = self.configParser.recent_projects # recentProjectsSection.items() is in the wrong order, keys are alright. # Sorting list by key before adding to self.recentProjects, to avoid wrong ordering # in Recent Projects menu list recentProjectsItems = recentProjectsSection.items(); recentProjectsItems.sort() for key, path in recentProjectsItems: self.recentProjects.append(path) # Load the list of "hidden" iDevices self.hiddeniDevices = [] if self.configParser.has_section('idevices'): idevicesSection = self.configParser.idevices for key,value in idevicesSection.items(): # emulate standard library's getboolean() value = value.strip().lower() if value == "0" or value == "no" or value == "false" or \ value == "off": self.hiddeniDevices.append(key.lower()) #self.deprecatediDevices = [ "flash with text", "flash movie", ...] # and UN-Load from the list of "deprecated" iDevices if self.configParser.has_section('deprecated'): deprecatedSection = self.configParser.deprecated for key,value in deprecatedSection.items(): # emulate standard library's getboolean() value = value.strip().lower() if value == "1" or value == "yes" or value == "true" or \ value == "on": if key.lower() in self.deprecatediDevices: self.deprecatediDevices.remove(key.lower()) # Load the "user" section if self.configParser.has_section('user'): if self.configParser.user.has_option('editorMode'): self.editorMode = self.configParser.user.editorMode if self.configParser.user.has_option('docType'): self.docType = self.configParser.user.docType common.setExportDocType(self.configParser.user.docType) if self.configParser.user.has_option('defaultStyle'): self.defaultStyle= self.configParser.user.defaultStyle if self.configParser.user.has_option('styleSecureMode'): self.styleSecureMode= self.configParser.user.styleSecureMode if self.configParser.user.has_option('internalAnchors'): self.internalAnchors = self.configParser.user.internalAnchors if self.configParser.user.has_option('lastDir'): self.lastDir = self.configParser.user.lastDir if self.configParser.user.has_option('showPreferencesOnStart'): self.showPreferencesOnStart = self.configParser.user.showPreferencesOnStart if self.configParser.user.has_option('showIdevicesGrouped'): self.showIdevicesGrouped = self.configParser.user.showIdevicesGrouped if self.configParser.user.has_option('locale'): self.locale = self.configParser.user.locale return self.locale = chooseDefaultLocale(self.localeDir) def onWrite(self, configParser): """ Called just before the config file is written. We use it to fill out any settings that are stored here and not in the config parser itself """ # Recent projects self.configParser.delete('recent_projects') recentProjectsSection = self.configParser.addSection('recent_projects') for num, path in enumerate(self.recentProjects): recentProjectsSection[str(num)] = path def setupLogging(self): """ setup logging file """ try: hdlr = RotatingFileHandler(self.configDir/'exe.log', 'a', 500000, 10) hdlr.doRollover() except OSError: # ignore the error we get if the log file is logged hdlr = logging.FileHandler(self.configDir/'exe.log') format = "%(asctime)s %(name)s %(levelname)s %(message)s" log = logging.getLogger() hdlr.setFormatter(logging.Formatter(format)) log.addHandler(hdlr) loggingLevels = {"DEBUG" : logging.DEBUG, "INFO" : logging.INFO, "WARNING" : logging.WARNING, "ERROR" : logging.ERROR, "CRITICAL" : logging.CRITICAL } if self.configParser.has_section('logging'): for logger, level in self.configParser._sections["logging"].items(): if logger == "root": logging.getLogger().setLevel(loggingLevels[level]) else: logging.getLogger(logger).setLevel(loggingLevels[level]) if not G.application.portable: log.info("************** eXe logging started **************") log.info("version = %s" % version.version) log.info("configPath = %s" % self.configPath) log.info("exePath = %s" % self.exePath) log.info("libPath = %s" % Path(twisted.__path__[0]).splitpath()[0]) log.info("browser = %s" % self.browser) log.info("webDir = %s" % self.webDir) log.info("jsDir = %s" % self.jsDir) log.info("localeDir = %s" % self.localeDir) log.info("port = %d" % self.port) log.info("dataDir = %s" % self.dataDir) log.info("configDir = %s" % self.configDir) log.info("locale = %s" % self.locale) log.info("internalAnchors = %s" % self.internalAnchors) def loadStyles(self): """ Scans the eXe style directory and builds a list of styles """ self.styleStore = StyleStore(self) listStyles = self.styleStore.getStyles() for style in listStyles: self.styles.append(style) #print style def copyStyles(self): bkstyle=self.webDir/'style' dststyle=self.stylesDir if os.path.exists(bkstyle): if os.path.exists(dststyle) and not os.listdir(self.stylesDir): shutil.rmtree(dststyle) shutil.copytree(bkstyle,dststyle ) def updateStyles(self): bkstyle=self.webDir/'style' dststyle=self.stylesDir if os.stat(bkstyle).st_mtime - os.stat(dststyle).st_mtime > 1: for name in os.listdir(bkstyle): bksdirstyle=os.path.join(bkstyle, name) dstdirstyle=os.path.join(dststyle, name) if os.path.isdir(bksdirstyle): if os.path.exists(dstdirstyle):shutil.rmtree(dstdirstyle) shutil.copytree(bksdirstyle, dstdirstyle) else: shutil.copy(bksdirstyle, dstdirstyle) def loadLocales(self): """ Scans the eXe locale directory and builds a list of locales """ log = logging.getLogger() log.debug("loadLocales") gettext.install('exe', self.localeDir, True) self.locales = {} for subDir in self.localeDir.dirs(): if (subDir/'LC_MESSAGES'/'exe.mo').exists(): self.locales[subDir.basename()] = \ gettext.translation('exe', self.localeDir, languages=[str(subDir.basename())]) if subDir.basename() == self.locale: locale = subDir.basename() log.debug(" loading locale %s" % locale) self.locales[locale].install(unicode=True) __builtins__['c_'] = lambda s: self.locales[locale].ugettext(s) if s else s
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 Config: """ The Config class contains the configuration information for eXe. """ # Class attributes optionNames = { 'idevices': ('someone', ), 'system': ('webDir', 'xulDir', 'port', 'dataDir', 'configDir', 'localeDir', 'browserPath'), 'user': ('locale', ), } def __init__(self): """ Initialise """ self.configPath = None self.configParser = ConfigParser(self.onWrite) # Set default values # idevices is the list of hidden idevices selected by the user self.someone = 0 # exePath is the whole path and filename of the exe executable self.exePath = Path(sys.argv[0]).abspath() # webDir is the parent directory for styles,scripts and templates self.webDir = self.exePath.dirname() # xulDir is the parent directory for styles,scripts and templates self.xulDir = self.exePath.dirname() # localeDir is the base directory where all the locales are stored self.localeDir = self.exePath.dirname() / "locale" # port is the port the exe webserver will listen on # (previous default, which earlier users might still use, was 8081) self.port = 51235 # dataDir is the default directory that is shown to the user # to save packages and exports in self.dataDir = Path(".") # configDir is the dir for storing user profiles # and user made idevices and the config file self.configDir = Path(".") # browserPath is the entire pathname to firefox self.browserPath = Path("firefox") # locale is the language of the user self.locale = chooseDefaultLocale(self.localeDir) # internalAnchors indicate which exe_tmp_anchor tags to generate for each tinyMCE field # available values = "enable_all", "disable_autotop", or "disable_all" self.internalAnchors = "enable_all" # styles is the list of style names available for loading self.styles = [] # The documents that we've recently looked at self.recentProjects = [] # canonical (English) names of iDevices not to show in the iDevice pane self.hiddeniDevices = [] # likewise, a canonical (English) names of iDevices not to show in the # iDevice pane but, contrary to the hiddens, these are ones that the # configuration can specify to turn ON: self.deprecatediDevices = [ "flash with text", "flash movie", "mp3", \ "attachment"] # by default, only allow embedding of media types for which a # browser plugin is found: self.assumeMediaPlugins = False # Let our children override our defaults depending # on the OS that we're running on self._overrideDefaultVals() # Try to make the defaults a little intelligent # Under devel trees, webui is the default webdir self.webDir = Path(self.webDir) if not (self.webDir/'scripts').isdir() \ and (self.webDir/'webui').isdir(): self.webDir /= 'webui' # Under devel trees, xului is the default xuldir self.xulDir = Path(self.xulDir) if not (self.xulDir/'scripts').isdir() \ and (self.xulDir/'xului').isdir(): self.xulDir /= 'xului' # Find where the config file will be saved self.__setConfigPath() # Fill in any undefined config options with our defaults self._writeDefaultConfigFile() # Now we are ready to serve the application self.loadSettings() self.setupLogging() self.loadStyles() self.loadLocales() def _overrideDefaultVals(self): """ Override this to override the default config values """ def _getConfigPathOptions(self): """ Override this to give a list of possible config filenames in order of preference """ return ['exe.conf'] def _writeDefaultConfigFile(self): """ [Over]writes 'self.configPath' with a default config file (auto write is on so we don't need to write the file at the end) """ for sectionName, optionNames in self.optionNames.items(): for optionName in optionNames: defaultVal = getattr(self, optionName) self.configParser.setdefault(sectionName, optionName, defaultVal) # Logging can't really be changed from inside the program at the moment... self.configParser.setdefault('logging', 'root', 'INFO') def __setConfigPath(self): """ sets self.configPath to the filename of the config file that we'll use. In descendant classes set self.configFileOptions to a list of directories where the configDir should be in order of preference. If no config files can be found in these dirs, it will force creation of the config file in the top dir """ # If there's an EXECONF environment variable, use it self.configPath = None configFileOptions = map(Path, self._getConfigPathOptions()) if "EXECONF" in os.environ: envconf = Path(os.environ["EXECONF"]) if envconf.isfile(): self.configPath = os.environ["EXECONF"] # Otherwise find the most appropriate existing file if self.configPath is None: for confPath in configFileOptions: if confPath.isfile(): self.configPath = confPath break else: # If no config files exist, create and use the # first one on the list self.configPath = configFileOptions[0] folder = self.configPath.abspath().dirname() if not folder.exists(): folder.makedirs() self.configPath.touch() # Now make our configParser self.configParser.read(self.configPath) self.configParser.autoWrite = True def upgradeFile(self): """ Called before loading the config file, removes or upgrades any old settings. """ if self.configParser.has_section('system'): system = self.configParser.system if system.has_option('appDataDir'): # Older config files had configDir stored as appDataDir self.configDir = Path(system.appDataDir) # We'll just upgrade their config file for them for now... system.configDir = self.configDir del system.appDataDir if system.has_option('greDir'): # No longer used, system should automatically support del system.greDir def loadSettings(self): """ Loads the settings from the exe.conf file. Overrides the defaults set in __init__ """ # Set up the parser so that if a certain value is not in the config # file, it will use the value from our default values def defVal(dummy, option): """If something is not in the config file, just use the default in 'self'""" return getattr(self, option) self.configParser.defaultValue = defVal self.upgradeFile() # System Section if self.configParser.has_section('system'): system = self.configParser.system self.webDir = Path(system.webDir) self.xulDir = Path(system.xulDir) self.localeDir = Path(system.localeDir) self.port = int(system.port) self.browserPath = Path(system.browserPath) self.dataDir = Path(system.dataDir) self.configDir = Path(system.configDir) self.assumeMediaPlugins = False if self.configParser.has_option('system', \ 'assumeMediaPlugins'): value = system.assumeMediaPlugins.strip().lower() if value == "1" or value == "yes" or value == "true" or \ value == "on": self.assumeMediaPlugins = True # If the dataDir points to some other dir, fix it if not self.dataDir.isdir(): self.dataDir = tempfile.gettempdir() # make the webDir absolute, to hide path joins of relative paths self.webDir = self.webDir.expand().abspath() # If the configDir doesn't exist (as it may be a default setting with a # new installation) create it if not self.configDir.exists(): self.configDir.mkdir() # Get the list of recently opened projects self.recentProjects = [] if self.configParser.has_section('recent_projects'): recentProjectsSection = self.configParser.recent_projects for key, path in recentProjectsSection.items(): self.recentProjects.append(path) # Load the list of "hidden" iDevices self.hiddeniDevices = [] if self.configParser.has_section('idevices'): idevicesSection = self.configParser.idevices for key, value in idevicesSection.items(): # emulate standard library's getboolean() value = value.strip().lower() if value == "0" or value == "no" or value == "false" or \ value == "off": self.hiddeniDevices.append(key.lower()) #self.deprecatediDevices = [ "flash with text", "flash movie", ...] # and UN-Load from the list of "deprecated" iDevices if self.configParser.has_section('deprecated'): deprecatedSection = self.configParser.deprecated for key, value in deprecatedSection.items(): # emulate standard library's getboolean() value = value.strip().lower() if value == "1" or value == "yes" or value == "true" or \ value == "on": if key.lower() in self.deprecatediDevices: self.deprecatediDevices.remove(key.lower()) # Load the "user" section if self.configParser.has_section('user'): if self.configParser.user.has_option('internalAnchors'): self.internalAnchors = self.configParser.user.internalAnchors if self.configParser.user.has_option('locale'): self.locale = self.configParser.user.locale return self.locale = chooseDefaultLocale(self.localeDir) def onWrite(self, configParser): """ Called just before the config file is written. We use it to fill out any settings that are stored here and not in the config parser itself """ # Recent projects self.configParser.delete('recent_projects') recentProjectsSection = self.configParser.addSection('recent_projects') for num, path in enumerate(self.recentProjects): recentProjectsSection[str(num)] = path def setupLogging(self): """ setup logging file """ try: hdlr = RotatingFileHandler(self.configDir / 'exe.log', 'a', 500000, 10) hdlr.doRollover() except OSError: # ignore the error we get if the log file is logged hdlr = logging.FileHandler(self.configDir / 'exe.log') format = "%(asctime)s %(name)s %(levelname)s %(message)s" log = logging.getLogger() hdlr.setFormatter(logging.Formatter(format)) log.addHandler(hdlr) loggingLevels = { "DEBUG": logging.DEBUG, "INFO": logging.INFO, "WARNING": logging.WARNING, "ERROR": logging.ERROR, "CRITICAL": logging.CRITICAL } if self.configParser.has_section('logging'): for logger, level in self.configParser._sections["logging"].items( ): if logger == "root": logging.getLogger().setLevel(loggingLevels[level]) else: logging.getLogger(logger).setLevel(loggingLevels[level]) log.info("************** eXe logging started **************") log.info("configPath = %s" % self.configPath) log.info("exePath = %s" % self.exePath) log.info("browserPath = %s" % self.browserPath) log.info("webDir = %s" % self.webDir) log.info("xulDir = %s" % self.xulDir) log.info("localeDir = %s" % self.localeDir) log.info("port = %d" % self.port) log.info("dataDir = %s" % self.dataDir) log.info("configDir = %s" % self.configDir) log.info("locale = %s" % self.locale) log.info("internalAnchors = %s" % self.internalAnchors) def loadStyles(self): """ Scans the eXe style directory and builds a list of styles """ log = logging.getLogger() self.styles = [] styleDir = self.webDir / "style" log.debug("loadStyles from %s" % styleDir) for subDir in styleDir.dirs(): styleSheet = subDir / 'content.css' log.debug(" checking %s" % styleSheet) if styleSheet.exists(): style = subDir.basename() log.debug(" loading style %s" % style) self.styles.append(style) def loadLocales(self): """ Scans the eXe locale directory and builds a list of locales """ log = logging.getLogger() log.debug("loadLocales") gettext.install('exe', self.localeDir, True) self.locales = {} for subDir in self.localeDir.dirs(): if (subDir / 'LC_MESSAGES' / 'exe.mo').exists(): self.locales[subDir.basename()] = \ gettext.translation('exe', self.localeDir, languages=[str(subDir.basename())]) if subDir.basename() == self.locale: locale = subDir.basename() log.debug(" loading locale %s" % locale) self.locales[locale].install(unicode=True) # ===========================================================================
def load(filename, newLoad=True, destinationPackage=None, fromxml=None): """ Load package from disk, returns a package. """ if not zipfile.is_zipfile(filename): return None zippedFile = zipfile.ZipFile(filename, "r") xml = None try: xml = zippedFile.read(u"contentv2.xml") except: pass if not xml: try: # Get the jellied package data toDecode = zippedFile.read(u"content.data") except KeyError: log.info("no content.data, trying Common Cartridge/Content Package") newPackage = loadCC(zippedFile, filename) newPackage.tempFile = False newPackage.isChanged = False newPackage.filename = Path(filename) return newPackage # Need to add a TempDirPath because it is a nonpersistant member resourceDir = TempDirPath() # Extract resource files from package to temporary directory for fn in zippedFile.namelist(): if unicode(fn, 'utf8') not in [u"content.data", u"content.xml", u"contentv2.xml", u"content.xsd" ]: #JR: Hacemos las comprobaciones necesarias por si hay directorios if ("/" in fn): dir = fn[:fn.index("/")] Dir = Path(resourceDir/dir) if not Dir.exists(): Dir.mkdir() Fn = Path(resourceDir/fn) if not Fn.isdir(): outFile = open(resourceDir/fn, "wb") outFile.write(zippedFile.read(fn)) outFile.flush() outFile.close() try: validxml = False if fromxml: newPackage, validxml = decodeObjectFromXML(fromxml) elif xml: xmlinfo = zippedFile.getinfo(u"contentv2.xml") datainfo = zippedFile.getinfo(u"content.data") if xmlinfo.date_time >= datainfo.date_time: newPackage, validxml = decodeObjectFromXML(xml) if not validxml: toDecode = zippedFile.read(u"content.data") newPackage = decodeObjectRaw(toDecode) G.application.afterUpgradeHandlers = [] newPackage.resourceDir = resourceDir G.application.afterUpgradeZombies2Delete = [] if not validxml and (xml or fromxml or "content.xml" in zippedFile.namelist()): for key, res in newPackage.resources.items(): if len(res) < 1: newPackage.resources.pop(key) else: res[0].testForAndDeleteZombieResources() if newLoad: # provide newPackage to doUpgrade's versionUpgrade() to # correct old corrupt extracted packages by setting the # any corrupt package references to the new package: log.debug("load() about to doUpgrade newPackage \"" + newPackage._name + "\" " + repr(newPackage) ) if hasattr(newPackage, 'resourceDir'): log.debug("newPackage resourceDir = " + newPackage.resourceDir) else: # even though it was just set above? should not get here: log.error("newPackage resourceDir has NO resourceDir!") doUpgrade(newPackage) # after doUpgrade, compare the largest found field ID: if G.application.maxFieldId >= Field.nextId: Field.nextId = G.application.maxFieldId + 1 else: # and when merging, automatically set package references to # the destinationPackage, into which this is being merged: log.debug("load() about to merge doUpgrade newPackage \"" + newPackage._name + "\" " + repr(newPackage) + " INTO destinationPackage \"" + destinationPackage._name + "\" " + repr(destinationPackage)) log.debug("using their resourceDirs:") if hasattr(newPackage, 'resourceDir'): log.debug(" newPackage resourceDir = " + newPackage.resourceDir) else: log.error("newPackage has NO resourceDir!") if hasattr(destinationPackage, 'resourceDir'): log.debug(" destinationPackage resourceDir = " + destinationPackage.resourceDir) else: log.error("destinationPackage has NO resourceDir!") doUpgrade(destinationPackage, isMerge=True, preMergePackage=newPackage) # after doUpgrade, compare the largest found field ID: if G.application.maxFieldId >= Field.nextId: Field.nextId = G.application.maxFieldId + 1 except: import traceback traceback.print_exc() raise if newPackage.tempFile: # newPackage.filename was stored as it's original filename newPackage.tempFile = False else: # newPackage.filename is the name that the package was last loaded from # or saved to newPackage.filename = Path(filename) # Let idevices and nodes handle any resource upgrading they may need to # Note: Package afterUpgradeHandlers *must* be done after Resources' # and the package should be updated before everything else, # so, prioritize with a 3-pass, 3-level calling setup # in order of: 1) resources, 2) package, 3) anything other objects for handler_priority in range(3): for handler in G.application.afterUpgradeHandlers: if handler_priority == 0 and \ repr(handler.im_class)=="<class 'exe.engine.resource.Resource'>": # level-0 handlers: Resource handler() elif handler_priority == 1 and \ repr(handler.im_class)=="<class 'exe.engine.package.Package'>": # level-1 handlers: Package (requires resources first) if handler.im_self == newPackage: handler() else: log.warn("Extra package object found, " \ + "ignoring its afterUpgradeHandler: " \ + repr(handler)) elif handler_priority == 2 and \ repr(handler.im_class)!="<class 'exe.engine.resource.Resource'>" \ and \ repr(handler.im_class)!="<class 'exe.engine.package.Package'>": # level-2 handlers: all others handler() G.application.afterUpgradeHandlers = [] num_zombies = len(G.application.afterUpgradeZombies2Delete) for i in range(num_zombies-1, -1, -1): zombie = G.application.afterUpgradeZombies2Delete[i] # now, the zombie list can contain nodes OR resources to delete. # if zombie is a node, then also pass in a pruning parameter.. zombie_is_node = False if isinstance(zombie, Node): zombie_is_node = True if zombie_is_node: zombie.delete(pruningZombies=True) else: zombie.delete() del zombie G.application.afterUpgradeZombies2Delete = [] newPackage.updateRecentDocuments(newPackage.filename) newPackage.isChanged = False return newPackage
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()
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)