Beispiel #1
0
 def save(self, filename=None, tempFile=False):
     """
     Save package to disk
     pass an optional filename
     """
     self.tempFile = tempFile
     if filename:
         filename = Path(filename)
         name = filename.splitpath()[1]
         if not tempFile:
             self.name = name.basename().splitext()[0]
     elif self.filename:
         filename = Path(self.filename)
     else:
         raise AssertionError(u'No name passed when saving a new package')
     log.debug(u"Will save %s to: %s" % (self.name, filename))
     if tempFile:
         self.nonpersistant.remove('filename')
         oldFilename, self.filename = self.filename, unicode(self.filename)
         try:
             filename.safeSave(self.doSave, _('SAVE FAILED!\nLast succesful save is %s.'))
         finally:
             self.nonpersistant.append('filename')
             self.filename = oldFilename
     else:
         self.filename = filename
         filename.safeSave(self.doSave, _('SAVE FAILED!\nLast succesful save is %s.'))
         self.isChanged = False
         self.updateRecentDocuments(filename)
Beispiel #2
0
 def save(self, filename=None):
     """
     Save package to disk
     pass an optional filename
     """
     if filename:
         filename = Path(filename)
         name = filename.splitpath()[1]
         self.name = name.basename().splitext()[0]
     elif self.filename:
         filename = Path(self.filename)
     else:
         raise AssertionError(u'No name passed when saving a new package')
     self.filename = filename
     log.debug(u"Will save %s to: %s" % (self.name, filename))
     filename.safeSave(self.doSave, _('SAVE FAILED!\nLast succesful save is %s.'))
     self.isChanged = 0
Beispiel #3
0
 def save(self, filename=None, tempFile=False):
     """
     Save package to disk
     pass an optional filename
     """
     self.tempFile = tempFile
     # Get the filename
     if filename:
         filename = Path(filename)
         # If we are being given a new filename...
         # Change our name to match our new filename
         name = filename.splitpath()[1]
         if not tempFile:
             self.name = name.basename().splitext()[0]
     elif self.filename:
         # Otherwise use our last saved/loaded from filename
         filename = Path(self.filename)
     else:
         # If we don't have a last saved/loaded from filename,
         # raise an exception because, we need to have a new
         # file passed when a brand new package is saved
         raise AssertionError(u'No name passed when saving a new package')
     # Store our new filename for next file|save, and save the package
     log.debug(u"Will save %s to: %s" % (self.name, filename))
     if tempFile:
         self.nonpersistant.remove('filename')
         oldFilename, self.filename = self.filename, unicode(self.filename)
         try:
             filename.safeSave(
                 self.doSave, _('SAVE FAILED!\nLast succesful save is %s.'))
         finally:
             self.nonpersistant.append('filename')
             self.filename = oldFilename
     else:
         # Update our new filename for future saves
         self.filename = filename
         filename.safeSave(self.doSave,
                           _('SAVE FAILED!\nLast succesful save is %s.'))
         self.isChanged = False
         self.updateRecentDocuments(filename)
Beispiel #4
0
 def save(self, filename=None, tempFile=False):
     if filename:
         filename = Path(filename)
         # If we are being given a new filename...
         # Change our name to match our new filename
         name = filename.splitpath()[1]
         if not tempFile:
             self.name = name.basename().splitext()[0]
     elif self.filename:
         # Otherwise use our last saved/loaded from filename
         filename = Path(self.filename)
     else:
         # If we don't have a last saved/loaded from filename,
         # raise an exception because, we need to have a new
         # file passed when a brand new package is saved
         raise AssertionError(u'No name passed when saving a new package')
     
     if not tempFile:
         # Update our new filename for future saves
         self.filename = filename
         filename.safeSave(self.doSave, _('SAVE FAILED!\nLast succesful save is %s.'))
         self.isChanged = False
 def save(self, filename=None, tempFile=False):
     """
     Save package to disk
     pass an optional filename
     """
     self.tempFile = tempFile
     # Get the filename
     if filename:
         filename = Path(filename)
         # If we are being given a new filename...
         # Change our name to match our new filename
         name = filename.splitpath()[1]
         if not tempFile:
             self.name = name.basename().splitext()[0]
     elif self.filename:
         # Otherwise use our last saved/loaded from filename
         filename = Path(self.filename)
     else:
         # If we don't have a last saved/loaded from filename,
         # raise an exception because, we need to have a new
         # file passed when a brand new package is saved
         raise AssertionError(u"No name passed when saving a new package")
     # Store our new filename for next file|save, and save the package
     log.debug(u"Will save %s to: %s" % (self.name, filename))
     if tempFile:
         self.nonpersistant.remove("filename")
         oldFilename, self.filename = self.filename, unicode(self.filename)
         try:
             filename.safeSave(self.doSave, _("SAVE FAILED!\nLast succesful save is %s."))
         finally:
             self.nonpersistant.append("filename")
             self.filename = oldFilename
     else:
         # Update our new filename for future saves
         self.filename = filename
         filename.safeSave(self.doSave, _("SAVE FAILED!\nLast succesful save is %s."))
         self.isChanged = False
         self.updateRecentDocuments(filename)
Beispiel #6
0
class ScormExport(object):
    """
    Exports an eXe package as a SCORM package
    """

    def __init__(self, config, styleDir, filename, scormType):
        """ 
        Initialize
        'styleDir' is the directory from which we will copy our style sheets
        (and some gifs)
        """
        self.config = config
        self.imagesDir = config.webDir / "images"
        self.scriptsDir = config.webDir / "scripts"
        self.cssDir = config.webDir / "css"
        self.templatesDir = config.webDir / "templates"
        self.schemasDir = config.webDir / "schemas"
        self.styleDir = Path(styleDir)
        self.filename = Path(filename)
        self.pages = []
        self.hasForum = False
        self.scormType = scormType
        self.styleSecureMode = config.styleSecureMode

    def export(self, package):
        """ 
        Export SCORM package
        """
        # First do the export to a temporary directory
        outputDir = TempDirPath()

        self.metadataType = package.exportMetadataType

        # copy the package's resource files
        package.resourceDir.copyfiles(outputDir)

        # copy the package's resource files, only non existant in outputDir
        #        outputDirFiles = outputDir.files()
        #        for rfile in package.resourceDir.files():
        #            if rfile not in outputDirFiles:
        #                rfile.copy(outputDir)

        # copy the package's resource files, only indexed in package.resources
        #        for md5 in package.resources.values():
        #            for resource in md5:
        #                resource.path.copy(outputDir)

        # Export the package content
        # Import the Scorm Page class , if the secure mode is off.  If the style has it's own page class
        # use that, else use the default one.
        if self.styleSecureMode == "0":
            if (self.styleDir / "scormpage.py").exists():
                global ScormPage
                module = imp.load_source("ScormPage", self.styleDir / "scormpage.py")
                ScormPage = module.ScormPage

        self.pages = [ScormPage("index", 1, package.root, scormType=self.scormType, metadataType=self.metadataType)]

        self.generatePages(package.root, 2)
        uniquifyNames(self.pages)

        for page in self.pages:
            page.save(outputDir)
            if not self.hasForum:
                for idevice in page.node.idevices:
                    if hasattr(idevice, "isForum"):
                        if idevice.forum.lms.lms == "moodle":
                            self.hasForum = True
                            break

        # Create the manifest file
        manifest = Manifest(self.config, outputDir, package, self.pages, self.scormType, self.metadataType)
        manifest.save("imsmanifest.xml")
        if self.hasForum:
            manifest.save("discussionforum.xml")

        # Copy the style sheet files to the output dir
        styleFiles = [self.styleDir / ".." / "base.css"]
        styleFiles += [self.styleDir / ".." / "popup_bg.gif"]
        # And with all the files of the style we avoid problems:
        styleFiles += self.styleDir.files("*.*")
        if self.scormType == "commoncartridge":
            for sf in styleFiles[:]:
                if sf.basename() not in manifest.dependencies:
                    styleFiles.remove(sf)
        self.styleDir.copylist(styleFiles, outputDir)

        # Copy the scripts
        dT = common.getExportDocType()
        if dT == "HTML5":
            jsFile = self.scriptsDir / "exe_html5.js"
            jsFile.copyfile(outputDir / "exe_html5.js")

        # jQuery
        my_style = G.application.config.styleStore.getStyle(page.node.package.style)
        if my_style.hasValidConfig:
            if my_style.get_jquery() == True:
                jsFile = self.scriptsDir / "exe_jquery.js"
                jsFile.copyfile(outputDir / "exe_jquery.js")
        else:
            jsFile = self.scriptsDir / "exe_jquery.js"
            jsFile.copyfile(outputDir / "exe_jquery.js")

        if self.scormType == "commoncartridge":
            jsFile = self.scriptsDir / "common.js"
            jsFile.copyfile(outputDir / "common.js")

        if self.scormType == "scorm2004" or self.scormType == "scorm1.2":
            self.scriptsDir.copylist(("SCORM_API_wrapper.js", "SCOFunctions.js", "common.js"), outputDir)
        # about SCHEMAS:
        schemasDir = ""
        if self.scormType == "scorm1.2":
            schemasDir = self.schemasDir / "scorm1.2"
            schemasDir.copylist(
                (
                    "imscp_rootv1p1p2.xsd",
                    "imsmd_rootv1p2p1.xsd",
                    "adlcp_rootv1p2.xsd",
                    "lom.xsd",
                    "lomCustom.xsd",
                    "ims_xml.xsd",
                ),
                outputDir,
            )
        elif self.scormType == "scorm2004":
            schemasDir = self.schemasDir / "scorm2004"
            schemasDir.copylist(
                (
                    "adlcp_v1p3.xsd",
                    "adlnav_v1p3.xsd",
                    "adlseq_v1p3.xsd",
                    "datatypes.dtd",
                    "imscp_v1p1.xsd",
                    "imsssp_v1p0.xsd",
                    "imsss_v1p0.xsd",
                    "imsss_v1p0auxresource.xsd",
                    "imsss_v1p0control.xsd",
                    "imsss_v1p0delivery.xsd",
                    "imsmd_rootv1p2p1.xsd",
                    "imsss_v1p0limit.xsd",
                    "imsss_v1p0objective.xsd",
                    "imsss_v1p0random.xsd",
                    "imsss_v1p0rollup.xsd",
                    "imsss_v1p0seqrule.xsd",
                    "imsss_v1p0util.xsd",
                    "ims_xml.xsd",
                    "lom.xsd",
                    "lomCustom.xsd",
                    "xml.xsd",
                    "XMLSchema.dtd",
                ),
                outputDir,
            )
            try:
                import shutil, errno

                shutil.copytree(schemasDir / "common", outputDir / "common")
                shutil.copytree(schemasDir / "extend", outputDir / "extend")
                shutil.copytree(schemasDir / "unique", outputDir / "unique")
                shutil.copytree(schemasDir / "vocab", outputDir / "vocab")
            except OSError as exc:
                if exc.errno == errno.ENOTDIR:
                    shutil.copy(schemasDir, outputDir)
                else:
                    raise

        # copy players for media idevices.
        hasFlowplayer = False
        hasMagnifier = False
        hasXspfplayer = False
        hasGallery = False
        hasWikipedia = False
        isBreak = False
        hasInstructions = False
        hasMediaelement = False

        for page in self.pages:
            if isBreak:
                break
            for idevice in page.node.idevices:
                if (
                    hasFlowplayer
                    and hasMagnifier
                    and hasXspfplayer
                    and hasGallery
                    and hasWikipedia
                    and hasInstructions
                    and hasMediaelement
                ):
                    isBreak = True
                    break
                if not hasFlowplayer:
                    if "flowPlayer.swf" in idevice.systemResources:
                        hasFlowplayer = True
                if not hasMagnifier:
                    if "mojomagnify.js" in idevice.systemResources:
                        hasMagnifier = True
                if not hasXspfplayer:
                    if "xspf_player.swf" in idevice.systemResources:
                        hasXspfplayer = True
                if not hasGallery:
                    hasGallery = common.ideviceHasGallery(idevice)
                if not hasWikipedia:
                    if "WikipediaIdevice" == idevice.klass:
                        hasWikipedia = True
                if not hasInstructions:
                    if (
                        "TrueFalseIdevice" == idevice.klass
                        or "MultichoiceIdevice" == idevice.klass
                        or "VerdaderofalsofpdIdevice" == idevice.klass
                        or "EleccionmultiplefpdIdevice" == idevice.klass
                    ):
                        hasInstructions = True
                if not hasMediaelement:
                    hasMediaelement = common.ideviceHasMediaelement(idevice)

        if hasFlowplayer:
            videofile = self.templatesDir / "flowPlayer.swf"
            videofile.copyfile(outputDir / "flowPlayer.swf")
            controlsfile = self.templatesDir / "flowplayer.controls.swf"
            controlsfile.copyfile(outputDir / "flowplayer.controls.swf")
        if hasMagnifier:
            videofile = self.templatesDir / "mojomagnify.js"
            videofile.copyfile(outputDir / "mojomagnify.js")
        if hasXspfplayer:
            videofile = self.templatesDir / "xspf_player.swf"
            videofile.copyfile(outputDir / "xspf_player.swf")
        if hasGallery:
            imageGalleryCSS = self.cssDir / "exe_lightbox.css"
            imageGalleryCSS.copyfile(outputDir / "exe_lightbox.css")
            imageGalleryJS = self.scriptsDir / "exe_lightbox.js"
            imageGalleryJS.copyfile(outputDir / "exe_lightbox.js")
            self.imagesDir.copylist(
                (
                    "exe_lightbox_close.png",
                    "exe_lightbox_loading.gif",
                    "exe_lightbox_next.png",
                    "exe_lightbox_prev.png",
                ),
                outputDir,
            )
        if hasWikipedia:
            wikipediaCSS = self.cssDir / "exe_wikipedia.css"
            wikipediaCSS.copyfile(outputDir / "exe_wikipedia.css")
        if hasInstructions:
            common.copyFileIfNotInStyle("panel-amusements.png", self, outputDir)
            common.copyFileIfNotInStyle("stock-stop.png", self, outputDir)
        if hasMediaelement:
            mediaelement = self.scriptsDir / "mediaelement"
            mediaelement.copyfiles(outputDir)
            if dT != "HTML5":
                jsFile = self.scriptsDir / "exe_html5.js"

        if self.scormType == "scorm1.2" or self.scormType == "scorm2004":
            if package.license == "license GFDL":
                # include a copy of the GNU Free Documentation Licence
                (self.templatesDir / "fdl.html").copyfile(outputDir / "fdl.html")

        if hasattr(package, "scowsinglepage") and package.scowsinglepage:
            page = SinglePage("singlepage_index", 1, package.root)
            page.save(outputDir / "singlepage_index.html")
            # Incluide eXe's icon if the Style doesn't have one
            themePath = Path(G.application.config.stylesDir / package.style)
            themeFavicon = themePath.joinpath("favicon.ico")
            if not themeFavicon.exists():
                faviconFile = self.imagesDir / "favicon.ico"
                faviconFile.copyfile(outputDir / "favicon.ico")
        if hasattr(package, "scowwebsite") and package.scowwebsite:
            website = WebsiteExport(self.config, self.styleDir, outputDir, "website_")
            website.export(package)
            (self.styleDir / "nav.css").copyfile(outputDir / "nav.css")
            # Incluide eXe's icon if the Style doesn't have one
            themePath = Path(G.application.config.stylesDir / package.style)
            themeFavicon = themePath.joinpath("favicon.ico")
            if not themeFavicon.exists():
                faviconFile = self.imagesDir / "favicon.ico"
                faviconFile.copyfile(outputDir / "favicon.ico")
        if hasattr(package, "exportSource") and package.exportSource:
            (G.application.config.webDir / "templates" / "content.xsd").copyfile(outputDir / "content.xsd")
            (outputDir / "content.data").write_bytes(encodeObject(package))
            (outputDir / "contentv3.xml").write_bytes(encodeObjectToXML(package))

        # Zip it up!
        self.filename.safeSave(self.doZip, _("EXPORT FAILED!\nLast succesful export is %s."), outputDir)
        # Clean up the temporary dir
        outputDir.rmtree()

    def doZip(self, fileObj, outputDir):
        """
        Actually does the zipping of the file. Called by 'Path.safeSave'
        """
        # Zip up the scorm package
        zipped = ZipFile(fileObj, "w")
        ## old method: only files could be copied:
        # for scormFile in outputDir.files():
        #    zipped.write(scormFile,
        #                 scormFile.basename().encode('utf8'),
        #                  ZIP_DEFLATED)
        ## but some folders must be included also, so:
        outputlen = len(outputDir) + 1
        for base, dirs, files in os.walk(outputDir):
            for file in files:
                fn = os.path.join(base, file)
                zipped.write(fn, fn[outputlen:].encode("utf8"), ZIP_DEFLATED)
        #
        zipped.close()

    def generatePages(self, node, depth):
        """
        Recursive function for exporting a node.
        'node' is the node that we are making a page for
        'depth' is the number of ancestors that the page has +1 (ie. root is 1)
        """
        for child in node.children:
            pageName = child.titleShort.lower().replace(" ", "_")
            pageName = re.sub(r"\W", "", pageName)
            if not pageName:
                pageName = "__"

            page = ScormPage(pageName, depth, child, scormType=self.scormType, metadataType=self.metadataType)

            self.pages.append(page)
            self.generatePages(child, depth + 1)
class WebsiteExport(object):
    
    
    #Track these variables so we can generate TinCan IDs as we go
    #Initialising the current Course's page's idevice id for the current package.   
    current_page = ""
    current_package_name = ""
    current_idevice_id = ""
    current_xapi_prefix = ""
    current_package_title = ""
    
    """
    WebsiteExport will export a package as a website of HTML pages
    """
    def __init__(self, config, styleDir, filename, prefix="", report=False, skipNavigation=False, ustadMobileMode=False, ustadMobileTestMode=False):
        #Added ustadMobileTestMode for Course Test Mode.
        """
        'stylesDir' is the directory where we can copy the stylesheets from
        'outputDir' is the directory that will be [over]written
        with the website
        """
        

        self.config       = config
        self.imagesDir    = config.webDir/"images"
        self.scriptsDir   = config.webDir/"scripts"
        self.cssDir       = config.webDir/"css"
        self.templatesDir = config.webDir/"templates"
        self.stylesDir    = Path(styleDir)
        self.filename     = Path(filename)
        self.pages        = []
        self.prefix       = prefix
        self.report       = report
        self.skipNavigation = skipNavigation
        self.ustadMobileMode = ustadMobileMode  
        self.ustadMobileTestMode = ustadMobileTestMode  #Added for Course Test Mode
        self.styleSecureMode = config.styleSecureMode

        self.config          = config
        self.imagesDir       = config.webDir/"images"
        self.scriptsDir      = config.webDir/"scripts"
        self.cssDir          = config.webDir/"css"
        self.templatesDir    = config.webDir/"templates"
        self.stylesDir       = Path(styleDir)
        self.filename        = Path(filename)
        self.pages           = []
        self.prefix          = prefix
        self.report          = report
       
       
    @staticmethod
    def getTinCanId(suffix = "", id_type="idevice", pagename = None):
        """Make a tin can activity ID - use a server prefix, the 
        package name, the page name, then the idevice id, and if
        needed another / and a question id or other depending on
        the idevice
        
        suffix: will be added to the tincan string
        id_type: can be idevice (default), page or
        pagename: the page file name (without .html etc). 
        
        """
        server_tincan_prefix = "http://www.ustadmobile.com/tincan"
        if pagename is None:
            pagename = WebsiteExport.current_package_name
        
        tin_can_prefix = "%(urlprefix)s/%(packagename)s" % {
                                "urlprefix" : server_tincan_prefix,
                                "packagename" :  WebsiteExport.current_package_name
                                }
        
        if id_type == EXETinCan.PAGE or id_type == EXETinCan.IDEVICE:
            tin_can_prefix += "/" + pagename
        
        if id_type == EXETinCan.IDEVICE:
            tin_can_prefix += "/" + WebsiteExport.current_idevice_id
        
        if suffix != "":
            tin_can_prefix += "/" + suffix
        
        return tin_can_prefix
 

    def exportZip(self, package):
        """ 
        Export web site
        Cleans up the previous packages pages and performs the export
        """
        
        outputDir = TempDirPath()

        # Import the Website Page class , if the secure mode is off.  If the style has it's own page class
        # use that, else use the default one.
        if self.styleSecureMode=="0":
            if (self.stylesDir/"websitepage.py").exists():
                global WebsitePage
                module = imp.load_source("websitepage", 
                                         self.stylesDir/"websitepage.py")
                WebsitePage = module.WebsitePage

        self.pages = [ WebsitePage("index", 0, package.root) ]
        self.generatePages(package.root, 1)
        uniquifyNames(self.pages)

        prevPage = None
        thisPage = self.pages[0]

        for nextPage in self.pages[1:]:
            thisPage.save(outputDir, prevPage, nextPage, self.pages)
            prevPage = thisPage
            thisPage = nextPage
            

        thisPage.save(outputDir, prevPage, None, self.pages)
        
        
        self.copyFiles(package, outputDir)
        # Zip up the website package
        self.filename.safeSave(self.doZip, _('EXPORT FAILED!\nLast succesful export is %s.'), outputDir)
        # Clean up the temporary dir
        outputDir.rmtree()

    def doZip(self, fileObj, outputDir):
        """
        Actually saves the zip data. Called by 'Path.safeSave'
        """
        zipped = ZipFile(fileObj, "w")
        for scormFile in outputDir.files():
            zipped.write(scormFile, scormFile.basename().encode('utf8'), ZIP_DEFLATED)
        zipped.close()

    def appendPageReport(self, page, package):
        if not page.node.idevices:self.report += u'"%s","%s",%d,"%s",,,,,,\n' % (package.filename,page.node.title, page.depth, page.name + '.html')
        for idevice in page.node.idevices:
            if not idevice.userResources:self.report += u'"%s","%s",%d,"%s","%s","%s",,,,\n' % (package.filename,page.node.title, page.depth, page.name + '.html', idevice.klass, idevice.title)
            for resource in idevice.userResources:
                if type(resource) == Resource:
                    self.report += u'"%s","%s",%d,"%s","%s","%s","%s","%s","%s","%s"\n' % (package.filename,page.node.title, page.depth, page.name + '.html', idevice.klass, idevice.title, resource.storageName, resource.userName, resource.path, resource.checksum)
                else:
                    self.report += u'"%s",%d,"%s","%s","%s","%s",,,\n' % (package.filename,page.node.title, page.depth, page.name + '.html', idevice.klass, idevice.title, resource)

    def export(self, package):
        """ 
        Export web site
        Cleans up the previous packages pages and performs the export
        """
        if not self.report:
            outputDir = self.filename
            if not outputDir.exists():
                outputDir.mkdir()

        WebsiteExport.current_package_name = package.name
        WebsiteExport.current_xapi_prefix = \
            EXETinCan.get_tincan_prefix_for_pkg(package)
        WebsiteExport.current_package_title = \
            package.title 
        
        # Import the Website Page class.  If the style has it's own page class
        # use that, else use the default one.
        if (self.stylesDir/"websitepage.py").exists():
            global WebsitePage
            module = imp.load_source("websitepage", 
                                     self.stylesDir/"websitepage.py")
            WebsitePage = module.WebsitePage

        self.pages = [ WebsitePage(self.prefix + "index", 0, package.root) ]
        self.generatePages(package.root, 1)
        uniquifyNames(self.pages)

        prevPage = None
        thisPage = self.pages[0]
        if self.report:
            self.report = u'"%s","%s","%s","%s","%s","%s","%s","%s","%s","%s"\n' % ('File','Page Name', 'Level', 'Page File Name', 'Idevice Type', 'Idevice Title', 'Resource File Name', 'Resource User Name', 'Resource Path', 'Resource Checksum')
            self.appendPageReport(thisPage,package)

        for nextPage in self.pages[1:]:
            if self.report:
                self.appendPageReport(nextPage,package)
            else:
                thisPage.save(outputDir, prevPage, nextPage, self.pages)
            prevPage = thisPage
            thisPage = nextPage

        
        
        if not self.report:
            thisPage.save(outputDir, prevPage, None, self.pages)

            if self.prefix == "":
                self.copyFiles(package, outputDir)
        else:
            self.filename.write_text(self.report, 'utf-8')

    def copyFiles(self, package, outputDir, um_mode = False):
        """
        Copy all the files used by the website.
        Parameters
        ----------
        package : Package
            package that is being exported
        outputDir : Path
            The end directory being exported to
        """
        package.resourceDir.copyfiles2(outputDir)
        
        copy_list = package.make_system_copy_list(self.stylesDir,
                              self.scriptsDir, self.templatesDir,
                              self.imagesDir, self.cssDir, outputDir,
                              ustad_mobile_mode = um_mode)
        WebsiteExport.run_copy_list(copy_list)
        
        if hasattr(package, 'exportSource') and package.exportSource:
            (outputDir/'content.data').write_bytes(encodeObject(package))
            (outputDir/'contentv3.xml').write_bytes(encodeObjectToXML(package))
        

    
    @classmethod
    def run_copy_list(cls, copy_list):
        """
        Copy a list of files - preserve modification times
        Parameters
        copy_list : list
            List of arrays.  Item 0 of each array should be a source,1 
            should be the dest.  Source can be a list of paths or a path
            object itself.
            
            For a list the dest should be a path representing a directory
            For an individual path the destination should be a file path
        """
        
        for copy_item in copy_list:
            src = copy_item[0]
            dst = copy_item[1]
            
            
            if isinstance(src, Path):
                #this is a straight file to file copy
                src.copyfile2(dst)
            else:
                #this is a list of files to copy to dst which should be
                #a directory
                for src_file in src:
                    if src_file.basename() == "content.css":
                        life = 42
                    src_file.copyfile2(dst/src_file.basename())
    
    
    def generatePages(self, node, depth):
        """
        Recursively generate pages and store in pages member variable
        for retrieving later
        """           
        for child in node.children:
            # assure lower pagename, without whitespaces or alphanumeric characters:
            pageName = child.titleShort.lower().replace(" ", "_")
            pageName = re.sub(r"\W", "", pageName)
            if not pageName:
                pageName = "__"

            self.pages.append(WebsitePage(self.prefix + pageName, depth, child))
            self.generatePages(child, depth + 1)
Beispiel #8
0
class WebsiteExport(object):
    """
    WebsiteExport will export a package as a website of HTML pages
    """
    def __init__(self, config, styleDir, filename, prefix="", report=False):
        """
        'stylesDir' is the directory where we can copy the stylesheets from
        'outputDir' is the directory that will be [over]written
        with the website
        """
        self.config          = config
        self.imagesDir       = config.webDir/"images"
        self.scriptsDir      = config.webDir/"scripts"
        self.cssDir          = config.webDir/"css"
        self.templatesDir    = config.webDir/"templates"
        self.stylesDir       = Path(styleDir)
        self.filename        = Path(filename)
        self.pages           = []
        self.prefix          = prefix
        self.report          = report
        self.styleSecureMode = config.styleSecureMode

        
    def exportZip(self, package):
        """ 
        Export web site
        Cleans up the previous packages pages and performs the export
        """
        
        outputDir = TempDirPath()

        # Import the Website Page class , if the secure mode is off.  If the style has it's own page class
        # use that, else use the default one.
        if self.styleSecureMode=="0":
            if (self.stylesDir/"websitepage.py").exists():
                global WebsitePage
                module = imp.load_source("websitepage", 
                                         self.stylesDir/"websitepage.py")
                WebsitePage = module.WebsitePage

        self.pages = [ WebsitePage("index", 0, package.root) ]
        self.generatePages(package.root, 1)
        uniquifyNames(self.pages)

        prevPage = None
        thisPage = self.pages[0]

        for nextPage in self.pages[1:]:
            thisPage.save(outputDir, prevPage, nextPage, self.pages)
            prevPage = thisPage
            thisPage = nextPage
            

        thisPage.save(outputDir, prevPage, None, self.pages)
        self.copyFiles(package, outputDir)
        # Zip up the website package
        self.filename.safeSave(self.doZip, _('EXPORT FAILED!\nLast succesful export is %s.'), outputDir)
        # Clean up the temporary dir
        outputDir.rmtree()

    def doZip(self, fileObj, outputDir):
        """
        Actually saves the zip data. Called by 'Path.safeSave'
        """
        zipped = ZipFile(fileObj, "w")
        for scormFile in outputDir.files():
            zipped.write(scormFile, scormFile.basename().encode('utf8'), ZIP_DEFLATED)
        zipped.close()

    def appendPageReport(self, page, package):
        if not page.node.idevices:self.report += u'"%s","%s",%d,"%s",,,,,,\n' % (package.filename,page.node.title, page.depth, page.name + '.html')
        for idevice in page.node.idevices:
            if not idevice.userResources:self.report += u'"%s","%s",%d,"%s","%s","%s",,,,\n' % (package.filename,page.node.title, page.depth, page.name + '.html', idevice.klass, idevice.title)
            for resource in idevice.userResources:
                if type(resource) == Resource:
                    self.report += u'"%s","%s",%d,"%s","%s","%s","%s","%s","%s","%s"\n' % (package.filename,page.node.title, page.depth, page.name + '.html', idevice.klass, idevice.title, resource.storageName, resource.userName, resource.path, resource.checksum)
                else:
                    self.report += u'"%s",%d,"%s","%s","%s","%s",,,\n' % (package.filename,page.node.title, page.depth, page.name + '.html', idevice.klass, idevice.title, resource)

    def export(self, package):
        """ 
        Export web site
        Cleans up the previous packages pages and performs the export
        """
        if not self.report:
            outputDir = self.filename
            if not outputDir.exists():
                outputDir.mkdir()

        # Import the Website Page class.  If the style has it's own page class
        # use that, else use the default one.
        if (self.stylesDir/"websitepage.py").exists():
            global WebsitePage
            module = imp.load_source("websitepage", 
                                     self.stylesDir/"websitepage.py")
            WebsitePage = module.WebsitePage

        self.pages = [ WebsitePage(self.prefix + "index", 0, package.root) ]
        self.generatePages(package.root, 1)
        uniquifyNames(self.pages)

        prevPage = None
        thisPage = self.pages[0]
        if self.report:
            self.report = u'"%s","%s","%s","%s","%s","%s","%s","%s","%s","%s"\n' % ('File','Page Name', 'Level', 'Page File Name', 'Idevice Type', 'Idevice Title', 'Resource File Name', 'Resource User Name', 'Resource Path', 'Resource Checksum')
            self.appendPageReport(thisPage,package)

        for nextPage in self.pages[1:]:
            if self.report:
                self.appendPageReport(nextPage,package)
            else:
                thisPage.save(outputDir, prevPage, nextPage, self.pages)
            prevPage = thisPage
            thisPage = nextPage

        if not self.report:
            thisPage.save(outputDir, prevPage, None, self.pages)

            if self.prefix == "":
                self.copyFiles(package, outputDir)
                
            return outputDir
            
        else:
            self.filename.write_text(self.report, 'utf-8')            


    def copyFiles(self, package, outputDir):
        """
        Copy all the files used by the website.
        """
       
        if os.path.isdir(self.stylesDir):
            # Copy the style sheet files to the output dir
            styleFiles  = [self.stylesDir/'..'/'base.css']
            styleFiles += [self.stylesDir/'..'/'popup_bg.gif']
            styleFiles += self.stylesDir.files("*.css")
            styleFiles += self.stylesDir.files("*.jpg")
            styleFiles += self.stylesDir.files("*.gif")
            styleFiles += self.stylesDir.files("*.png")
            styleFiles += self.stylesDir.files("*.js")
            styleFiles += self.stylesDir.files("*.html")
            styleFiles += self.stylesDir.files("*.ico")
            styleFiles += self.stylesDir.files("*.ttf")
            styleFiles += self.stylesDir.files("*.eot")
            styleFiles += self.stylesDir.files("*.otf")
            styleFiles += self.stylesDir.files("*.woff")
            self.stylesDir.copylist(styleFiles, outputDir)

        # copy the package's resource files
        package.resourceDir.copyfiles(outputDir)
            
        # copy script files.
        my_style = G.application.config.styleStore.getStyle(package.style)
        # jQuery
        if my_style.hasValidConfig:
            if my_style.get_jquery() == True:
                jsFile = (self.scriptsDir/'exe_jquery.js')
                jsFile.copyfile(outputDir/'exe_jquery.js')
        else:
            jsFile = (self.scriptsDir/'exe_jquery.js')
            jsFile.copyfile(outputDir/'exe_jquery.js')
            
        jsFile = (self.scriptsDir/'common.js')
        jsFile.copyfile(outputDir/'common.js')
        #dT = common.getExportDocType()
        dT=common.getExportDocType();
        if dT == "HTML5":
            jsFile = (self.scriptsDir/'exe_html5.js')
            jsFile.copyfile(outputDir/'exe_html5.js')

        # Incluide eXe's icon if the Style doesn't have one
        themePath = Path(G.application.config.stylesDir/package.style)
        themeFavicon = themePath.joinpath("favicon.ico")
        if not themeFavicon.exists():
            faviconFile = (self.imagesDir/'favicon.ico')
            faviconFile.copyfile(outputDir/'favicon.ico')
        
        # copy players for media idevices.                
        hasFlowplayer     = False
        hasMagnifier      = False
        hasXspfplayer     = False
        hasGallery        = False
        hasFX             = False
        hasSH             = False
        hasGames          = False
        hasWikipedia      = False
        isBreak           = False
        hasInstructions   = False
        hasMediaelement   = False
        hasTooltips       = False
        
        for page in self.pages:
            if isBreak:
                break
            for idevice in page.node.idevices:
                if (hasFlowplayer and hasMagnifier and hasXspfplayer and hasGallery and hasFX and hasSH and hasGames and hasWikipedia and hasInstructions and hasMediaelement and hasTooltips):
                    isBreak = True
                    break
                if not hasFlowplayer:
                    if 'flowPlayer.swf' in idevice.systemResources:
                        hasFlowplayer = True
                if not hasMagnifier:
                    if 'mojomagnify.js' in idevice.systemResources:
                        hasMagnifier = True
                if not hasXspfplayer:
                    if 'xspf_player.swf' in idevice.systemResources:
                        hasXspfplayer = True
                if not hasGallery:
                    hasGallery = common.ideviceHasGallery(idevice)
                if not hasFX:
                    hasFX = common.ideviceHasFX(idevice)
                if not hasSH:
                    hasSH = common.ideviceHasSH(idevice)
                if not hasGames:
                    hasGames = common.ideviceHasGames(idevice)
                if not hasWikipedia:
                    if 'WikipediaIdevice' == idevice.klass:
                        hasWikipedia = True
                if not hasInstructions:
                    if 'TrueFalseIdevice' == idevice.klass or 'MultichoiceIdevice' == idevice.klass or 'VerdaderofalsofpdIdevice' == idevice.klass or 'EleccionmultiplefpdIdevice' == idevice.klass:
                        hasInstructions = True
                if not hasMediaelement:
                    hasMediaelement = common.ideviceHasMediaelement(idevice)
                if not hasTooltips:
                    hasTooltips = common.ideviceHasTooltips(idevice)

        if hasFlowplayer:
            videofile = (self.templatesDir/'flowPlayer.swf')
            videofile.copyfile(outputDir/'flowPlayer.swf')
            controlsfile = (self.templatesDir/'flowplayer.controls.swf')
            controlsfile.copyfile(outputDir/'flowplayer.controls.swf')
        if hasMagnifier:
            videofile = (self.templatesDir/'mojomagnify.js')
            videofile.copyfile(outputDir/'mojomagnify.js')
        if hasXspfplayer:
            videofile = (self.templatesDir/'xspf_player.swf')
            videofile.copyfile(outputDir/'xspf_player.swf')
        if hasGallery:
            exeLightbox = (self.scriptsDir/'exe_lightbox')
            exeLightbox.copyfiles(outputDir)
        if hasFX:
            exeEffects = (self.scriptsDir/'exe_effects')
            exeEffects.copyfiles(outputDir)
        if hasSH:
            exeSH = (self.scriptsDir/'exe_highlighter')
            exeSH.copyfiles(outputDir)
        if hasGames:
            exeGames = (self.scriptsDir/'exe_games')
            exeGames.copyfiles(outputDir)
        if hasWikipedia:
            wikipediaCSS = (self.cssDir/'exe_wikipedia.css')
            wikipediaCSS.copyfile(outputDir/'exe_wikipedia.css')
        if hasInstructions:
            common.copyFileIfNotInStyle('panel-amusements.png', self, outputDir)
            common.copyFileIfNotInStyle('stock-stop.png', self, outputDir)
        if hasMediaelement:
            mediaelement = (self.scriptsDir/'mediaelement')
            mediaelement.copyfiles(outputDir)
            dT = common.getExportDocType()
            if dT != "HTML5":
                jsFile = (self.scriptsDir/'exe_html5.js')
                jsFile.copyfile(outputDir/'exe_html5.js')
        if hasTooltips:
            exe_tooltips = (self.scriptsDir/'exe_tooltips')
            exe_tooltips.copyfiles(outputDir)

        if hasattr(package, 'exportSource') and package.exportSource:
            (G.application.config.webDir/'templates'/'content.xsd').copyfile(outputDir/'content.xsd')
            (outputDir/'content.data').write_bytes(encodeObject(package))
            (outputDir/'contentv3.xml').write_bytes(encodeObjectToXML(package))

        if package.license == "license GFDL":
            # include a copy of the GNU Free Documentation Licence
            (self.templatesDir/'fdl.html').copyfile(outputDir/'fdl.html')


    def generatePages(self, node, depth):
        """
        Recursively generate pages and store in pages member variable
        for retrieving later
        """           
        for child in node.children:
            # assure lower pagename, without whitespaces or alphanumeric characters:
            pageName = child.titleShort.lower().replace(" ", "_")
            pageName = re.sub(r"\W", "", pageName)
            if not pageName:
                pageName = "__"

            self.pages.append(WebsitePage(self.prefix + pageName, depth, child))
            self.generatePages(child, depth + 1)
Beispiel #9
0
class WebsiteExport(object):
    """
    WebsiteExport will export a package as a website of HTML pages
    """
    def __init__(self, config, styleDir, filename, prefix="", report=False):
        """
        'stylesDir' is the directory where we can copy the stylesheets from
        'outputDir' is the directory that will be [over]written
        with the website
        """
        self.config          = config
        self.imagesDir       = config.webDir/"images"
        self.scriptsDir      = config.webDir/"scripts"
        self.cssDir          = config.webDir/"css"
        self.templatesDir    = config.webDir/"templates"
        self.stylesDir       = Path(styleDir)
        self.filename        = Path(filename)
        self.pages           = []
        self.prefix          = prefix
        self.report          = report
        self.styleSecureMode = config.styleSecureMode
        
    def gDriveNotificationStatus(self, client, mesg):
        client.sendScript("eXe.controller.eXeViewport.prototype.gDriveNotificationStatus('%s');" % (mesg), filter_func=allSessionClients)
        
    def gDriveNotificationNotice(self, client, mesg, type):
        client.sendScript("eXe.controller.eXeViewport.prototype.gDriveNotificationNotice('%s', '%s');" % (mesg, type), filter_func=allSessionClients)
        
#     def exportGoogleDrive(self, package, client, auth_token, user_agent):
#         """
#         Creates an authorized HTTP conexion, exports the current package as
#         'webSite' to a temporary directory and uploads the exported files to
#         Google Drive
#         """
#         num_total = 0;
#         file_num = 0;
#         
#         def finishExport(public_folder, outputDir):
#             self.gDriveNotificationStatus(client, _(u'Deleting temporary directory'))
#             rmtree(outputDir)
#             
#             link_url = 'http://googledrive.com/host/%s'%(public_folder['id'])
#             link_text = public_folder['title']
#             self.gDriveNotificationStatus(client, _(u'Package exported to <a href="%s" target="_blank" title="Click to visit exported site">%s</a>') %(link_url,link_text))
#             return public_folder
#         
#         def insertFile(public_folder, drive, upload_file, file_num):
#             """
#             Creates the deferred that will upload files to the public folder
#             once it is created
#             """
#             upload_content_d = threads.deferToThread(uploadContent, public_folder, drive, upload_file, file_num)
#             upload_content_d.addCallbacks(uploadContent_onSuccess, uploadContent_onFail)
#             
#             return upload_content_d
#         
#         def uploadContent(public_folder, drive, upload_file, file_num):
#             """
#             Uploads one file to the given GDrive folder
#             """ 
#             try :
#                 filepath = os.path.join(self.filename, upload_file)
#                 filetype = mimetypes.guess_type(filepath, False)
#                 
#                 if filetype[0] is None :
#                     # Hard-coded types for special cases not detected by mimetypes.guess_type() 
#                     if upload_file == 'content.data' :
#                         filetype = ('application/octet-stream', None)
#                     
#                     
#                 if filetype[0] is not None :
#                     link_url = 'http://googledrive.com/host/%s'%(public_folder['id'])
#                     link_text = public_folder['title']
#                     #self.gDriveNotificationStatus(client, _(u'Package exported to <a href="%s" target="_blank" title="Click to visit exported site">%s</<a>') %(link_url,link_text))
#                     self.gDriveNotificationStatus(client, _(u'Uploading <em>%s</em> to public folder <a href="%s" target="_blank" title="Click to visit exported site">%s</a> (%d/%d)') 
#                                                              %(upload_file, link_url, link_text, file_num, num_total))
#                     mimetype = filetype[0]
#                     meta = {
#                       'title': upload_file,
#                       'mimeType': mimetype,
#                       'parents' : [{'id' : public_folder['id']}]
#                     }
#                     media_body = MediaFileUpload(filepath, mimetype, resumable=True)
#                     drive.files().insert(body=meta, media_body=media_body).execute()
#                 else :
#                     self.gDriveNotificationNotice(client, _(u'File <em>%s</em> skipped, unknown filetype (%d/%d)') %(upload_file, file_num, num_total), 'warning')
#             except Exception, e :
#                 log.error(str(e))
#                 self.gDriveNotificationNotice(client, _(u'Failed upload of file %s (%d/%d)') % (upload_file, file_num, num_total), 'error')
#             
#             return public_folder
#             
#         def uploadContent_onFail(err):
#             log.error(str(err))
#             self.gDriveNotificationNotice(client, _(u'Failed exporting to GoogleDrive'), 'error')
#             return err
#             
#         def uploadContent_onSuccess(public_folder):
#             # self.gDriveNotificationStatus(client, _(u'Exported to GoogleDrive: %s') % public_folder['title'])
#             return public_folder
#                 
#         def publicFolder(drive, folder_name):
#             """
#             Creates a Public Web folder, that can be read as a web site with any
#             web browser, and populates it with the content of the given directory
#             """
#             
#             # Create public folder
#             self.gDriveNotificationStatus(client, _(u'Creating public folder to host published web site'))
#             body = {
#                 'title': folder_name,
#                 'mimeType': 'application/vnd.google-apps.folder'
#             }
#             public_folder = drive.files().insert(body=body).execute()
#             
#             permission = {
#                 'value': '',
#                 'type': 'anyone',
#                 'role': 'reader'
#             }
#             drive.permissions().insert(fileId=public_folder['id'], body=permission).execute()
#             
#             return public_folder
#             
#         def publicFolder_onFail(err):
#             log.error(str(err))
#             self.gDriveNotificationNotice(client, _(u'Failed exporting to GoogleDrive'), 'error')
#             return err
#             
#         def publicFolder_onSuccess(public_folder):
#             self.gDriveNotificationStatus(client, _(u'Created public folder to host published web site: %s') % (public_folder['title']))
#             return public_folder
#             
#         try:
#             # Creates a new temporary dir to export the package to, it will be deleted
#             # once the export process is finished
#             self.filename = Path(mkdtemp())
#             self.gDriveNotificationStatus(client, _(u'Exporting package as web site in: %s') % (jquote(self.filename)))
#             outputDir = self.export(package)
#             
#             self.gDriveNotificationStatus(client, _(u'Starting authorized connection to Google Drive API'))
#             credentials = AccessTokenCredentials(auth_token, user_agent)
#             ca_certs = None
#             if hasattr(sys, 'frozen'):
#                 ca_certs = 'cacerts.txt'
#             http = httplib2.Http(ca_certs=ca_certs)
#             http = credentials.authorize(http)
#             drive_service = build('drive', 'v2', http=http)
#             
#             publicFolder_d = threads.deferToThread(publicFolder, drive_service, package.name)
#             publicFolder_d.addCallbacks(publicFolder_onSuccess, publicFolder_onFail)
#             
#             # Loop through files in exportDir, each upload will be called from
#             # a chained callback function. These callbacks will return a 
#             # deferred so the file N upload will start when file N-1 has 
#             # successfully called its own callback 
#             # (Deferred chain, see: http://krondo.com/?p=2159#attachment_2196)
#             for upload_file in os.listdir(outputDir):
#                 file_num = file_num + 1
#                 publicFolder_d.addCallback(insertFile, drive_service, upload_file, file_num)
#                 
#             num_total = file_num
#             publicFolder_d.addCallback(finishExport, outputDir)
#             
#             # TODO clean exportDir after uploading has finished
#             
#         except Exception, e:
#             log.error(str(e))
#             self.gDriveNotificationNotice(client, _('EXPORT FAILED!'), 'error')
#             raise
#         #client.alert(_(u'Exported to %s') % filename)

    def exportZip(self, package):
        """ 
        Export web site
        Cleans up the previous packages pages and performs the export
        """
        
        outputDir = TempDirPath()

        # Import the Website Page class , if the secure mode is off.  If the style has it's own page class
        # use that, else use the default one.
        if self.styleSecureMode=="0":
            if (self.stylesDir/"websitepage.py").exists():
                global WebsitePage
                module = imp.load_source("websitepage", 
                                         self.stylesDir/"websitepage.py")
                WebsitePage = module.WebsitePage

        self.pages = [ WebsitePage("index", 0, package.root) ]
        self.generatePages(package.root, 1)
        uniquifyNames(self.pages)

        prevPage = None
        thisPage = self.pages[0]

        for nextPage in self.pages[1:]:
            thisPage.save(outputDir, prevPage, nextPage, self.pages)
            prevPage = thisPage
            thisPage = nextPage
            

        thisPage.save(outputDir, prevPage, None, self.pages)
        self.copyFiles(package, outputDir)
        # Zip up the website package
        self.filename.safeSave(self.doZip, _('EXPORT FAILED!\nLast succesful export is %s.'), outputDir)
        # Clean up the temporary dir
        outputDir.rmtree()

    def doZip(self, fileObj, outputDir):
        """
        Actually saves the zip data. Called by 'Path.safeSave'
        """
        zipped = ZipFile(fileObj, "w")
        for scormFile in outputDir.files():
            zipped.write(scormFile, scormFile.basename().encode('utf8'), ZIP_DEFLATED)
        zipped.close()

    def appendPageReport(self, page, package):
        if not page.node.idevices:self.report += u'"%s","%s",%d,"%s",,,,,,\n' % (package.filename,page.node.title, page.depth, page.name + '.html')
        for idevice in page.node.idevices:
            if not idevice.userResources:self.report += u'"%s","%s",%d,"%s","%s","%s",,,,\n' % (package.filename,page.node.title, page.depth, page.name + '.html', idevice.klass, idevice.title)
            for resource in idevice.userResources:
                if type(resource) == Resource:
                    self.report += u'"%s","%s",%d,"%s","%s","%s","%s","%s","%s","%s"\n' % (package.filename,page.node.title, page.depth, page.name + '.html', idevice.klass, idevice.title, resource.storageName, resource.userName, resource.path, resource.checksum)
                else:
                    self.report += u'"%s",%d,"%s","%s","%s","%s",,,\n' % (package.filename,page.node.title, page.depth, page.name + '.html', idevice.klass, idevice.title, resource)

    def export(self, package):
        """ 
        Export web site
        Cleans up the previous packages pages and performs the export
        """
        if not self.report:
            outputDir = self.filename
            if not outputDir.exists():
                outputDir.mkdir()

        # Import the Website Page class.  If the style has it's own page class
        # use that, else use the default one.
        if (self.stylesDir/"websitepage.py").exists():
            global WebsitePage
            module = imp.load_source("websitepage", 
                                     self.stylesDir/"websitepage.py")
            WebsitePage = module.WebsitePage

        self.pages = [ WebsitePage(self.prefix + "index", 0, package.root) ]
        self.generatePages(package.root, 1)
        uniquifyNames(self.pages)

        prevPage = None
        thisPage = self.pages[0]
        if self.report:
            self.report = u'"%s","%s","%s","%s","%s","%s","%s","%s","%s","%s"\n' % ('File','Page Name', 'Level', 'Page File Name', 'Idevice Type', 'Idevice Title', 'Resource File Name', 'Resource User Name', 'Resource Path', 'Resource Checksum')
            self.appendPageReport(thisPage,package)

        for nextPage in self.pages[1:]:
            if self.report:
                self.appendPageReport(nextPage,package)
            else:
                thisPage.save(outputDir, prevPage, nextPage, self.pages)
            prevPage = thisPage
            thisPage = nextPage

        if not self.report:
            thisPage.save(outputDir, prevPage, None, self.pages)

            if self.prefix == "":
                self.copyFiles(package, outputDir)
                
            return outputDir
            
        else:
            self.filename.write_text(self.report, 'utf-8')            


    def copyFiles(self, package, outputDir):
        """
        Copy all the files used by the website.
        """
       
        if os.path.isdir(self.stylesDir):
            # Copy the style sheet files to the output dir
            styleFiles  = [self.stylesDir/'..'/'base.css']
            styleFiles += [self.stylesDir/'..'/'popup_bg.gif']
            styleFiles += self.stylesDir.files("*.css")
            styleFiles += self.stylesDir.files("*.jpg")
            styleFiles += self.stylesDir.files("*.gif")
            styleFiles += self.stylesDir.files("*.png")
            styleFiles += self.stylesDir.files("*.js")
            styleFiles += self.stylesDir.files("*.html")
            styleFiles += self.stylesDir.files("*.ico")
            styleFiles += self.stylesDir.files("*.ttf")
            styleFiles += self.stylesDir.files("*.eot")
            styleFiles += self.stylesDir.files("*.otf")
            styleFiles += self.stylesDir.files("*.woff")
            self.stylesDir.copylist(styleFiles, outputDir)

        # copy the package's resource files
        package.resourceDir.copyfiles(outputDir)
            
        # copy script files.
        my_style = G.application.config.styleStore.getStyle(package.style)
        # jQuery
        if my_style.hasValidConfig:
            if my_style.get_jquery() == True:
                jsFile = (self.scriptsDir/'exe_jquery.js')
                jsFile.copyfile(outputDir/'exe_jquery.js')
        else:
            jsFile = (self.scriptsDir/'exe_jquery.js')
            jsFile.copyfile(outputDir/'exe_jquery.js')
            
        jsFile = (self.scriptsDir/'common.js')
        jsFile.copyfile(outputDir/'common.js')
        #dT = common.getExportDocType()
        dT=common.getExportDocType();
        if dT == "HTML5":
            jsFile = (self.scriptsDir/'exe_html5.js')
            jsFile.copyfile(outputDir/'exe_html5.js')

        # Incluide eXe's icon if the Style doesn't have one
        themePath = Path(G.application.config.stylesDir/package.style)
        themeFavicon = themePath.joinpath("favicon.ico")
        if not themeFavicon.exists():
            faviconFile = (self.imagesDir/'favicon.ico')
            faviconFile.copyfile(outputDir/'favicon.ico')
        
        # copy players for media idevices.                
        hasFlowplayer     = False
        hasMagnifier      = False
        hasXspfplayer     = False
        hasGallery        = False
        hasFX             = False
        hasGames          = False
        hasWikipedia      = False
        isBreak           = False
        hasInstructions   = False
        hasMediaelement   = False
        hasTooltips       = False
        
        for page in self.pages:
            if isBreak:
                break
            for idevice in page.node.idevices:
                if (hasFlowplayer and hasMagnifier and hasXspfplayer and hasGallery and hasFX and hasGames and hasWikipedia and hasInstructions and hasMediaelement and hasTooltips):
                    isBreak = True
                    break
                if not hasFlowplayer:
                    if 'flowPlayer.swf' in idevice.systemResources:
                        hasFlowplayer = True
                if not hasMagnifier:
                    if 'mojomagnify.js' in idevice.systemResources:
                        hasMagnifier = True
                if not hasXspfplayer:
                    if 'xspf_player.swf' in idevice.systemResources:
                        hasXspfplayer = True
                if not hasGallery:
                    hasGallery = common.ideviceHasGallery(idevice)
                if not hasFX:
                    hasFX = common.ideviceHasFX(idevice)
                if not hasGames:
                    hasGames = common.ideviceHasGames(idevice)
                if not hasWikipedia:
                    if 'WikipediaIdevice' == idevice.klass:
                        hasWikipedia = True
                if not hasInstructions:
                    if 'TrueFalseIdevice' == idevice.klass or 'MultichoiceIdevice' == idevice.klass or 'VerdaderofalsofpdIdevice' == idevice.klass or 'EleccionmultiplefpdIdevice' == idevice.klass:
                        hasInstructions = True
                if not hasMediaelement:
                    hasMediaelement = common.ideviceHasMediaelement(idevice)
                if not hasTooltips:
                    hasTooltips = common.ideviceHasTooltips(idevice)

        if hasFlowplayer:
            videofile = (self.templatesDir/'flowPlayer.swf')
            videofile.copyfile(outputDir/'flowPlayer.swf')
            controlsfile = (self.templatesDir/'flowplayer.controls.swf')
            controlsfile.copyfile(outputDir/'flowplayer.controls.swf')
        if hasMagnifier:
            videofile = (self.templatesDir/'mojomagnify.js')
            videofile.copyfile(outputDir/'mojomagnify.js')
        if hasXspfplayer:
            videofile = (self.templatesDir/'xspf_player.swf')
            videofile.copyfile(outputDir/'xspf_player.swf')
        if hasGallery:
            exeLightbox = (self.scriptsDir/'exe_lightbox')
            exeLightbox.copyfiles(outputDir)
        if hasFX:
            exeEffects = (self.scriptsDir/'exe_effects')
            exeEffects.copyfiles(outputDir)
        if hasGames:
            exeGames = (self.scriptsDir/'exe_games')
            exeGames.copyfiles(outputDir)
        if hasWikipedia:
            wikipediaCSS = (self.cssDir/'exe_wikipedia.css')
            wikipediaCSS.copyfile(outputDir/'exe_wikipedia.css')
        if hasInstructions:
            common.copyFileIfNotInStyle('panel-amusements.png', self, outputDir)
            common.copyFileIfNotInStyle('stock-stop.png', self, outputDir)
        if hasMediaelement:
            mediaelement = (self.scriptsDir/'mediaelement')
            mediaelement.copyfiles(outputDir)
            dT = common.getExportDocType()
            if dT != "HTML5":
                jsFile = (self.scriptsDir/'exe_html5.js')
                jsFile.copyfile(outputDir/'exe_html5.js')
        if hasTooltips:
            exe_tooltips = (self.scriptsDir/'exe_tooltips')
            exe_tooltips.copyfiles(outputDir)

        if hasattr(package, 'exportSource') and package.exportSource:
            (G.application.config.webDir/'templates'/'content.xsd').copyfile(outputDir/'content.xsd')
            (outputDir/'content.data').write_bytes(encodeObject(package))
            (outputDir/'contentv3.xml').write_bytes(encodeObjectToXML(package))

        if package.license == "license GFDL":
            # include a copy of the GNU Free Documentation Licence
            (self.templatesDir/'fdl.html').copyfile(outputDir/'fdl.html')


    def generatePages(self, node, depth):
        """
        Recursively generate pages and store in pages member variable
        for retrieving later
        """           
        for child in node.children:
            # assure lower pagename, without whitespaces or alphanumeric characters:
            pageName = child.titleShort.lower().replace(" ", "_")
            pageName = re.sub(r"\W", "", pageName)
            if not pageName:
                pageName = "__"

            self.pages.append(WebsitePage(self.prefix + pageName, depth, child))
            self.generatePages(child, depth + 1)
class Epub3Export(object):
    """
    Exports an eXe package as a epub 3 package
    The 'Hello World' of a epub 3 publication might contain files:
        mimetype
        META-INF/container.xml
        Content/HelloWorld.opf
        Content/HelloWorld.xhtml
    """
    def __init__(self, config, styleDir, filename):
        """
        Initialize
        'styleDir' is the directory from which we will copy our style sheets
        (and some gifs)
        """
        self.config = config
        self.imagesDir = config.webDir / "images"
        self.scriptsDir = config.webDir / "scripts"
        self.cssDir = config.webDir / "css"
        self.templatesDir = config.webDir / "templates"
        self.schemasDir = config.webDir / "schemas/ims"
        self.styleDir = Path(styleDir)
        self.filename = Path(filename)
        self.pages = []

    def export(self, package):
        """
        Export epub 3 package
        """
        # First do the export to a temporary directory
        outputDir = TempDirPath()

        '''
        fileDir = outputDir/"META-INF"
        fileDir.mkdir()
        fileDir = outputDir/"Content"
        fileDir.mkdir()
        '''

        metainfPages = Path(outputDir.abspath() + '/META-INF')
        # metainfPages = outputDir/'META-INF'
        metainfPages.mkdir()
        contentPages = Path(outputDir.abspath() + '/EPUB')
        # contentPages = outputDir/'Content'
        contentPages.mkdir()
        # print contentPages.abspath()
        # print outputDir.abspath()

        # Export the package content
        self.pages = [self.make_cover_page(package)]

        self.generatePages(package.root, 2)
        uniquifyNames(self.pages, suffix = ".xhtml")

        cover = None
        for page in self.pages:
            page.save(contentPages)
            if hasattr(page, 'cover'):
                cover = page.cover

        # Create mimetype file
        mimetypeFile = open(outputDir.abspath() + '/mimetype', "w")
        mimetypeFile.write('application/epub+zip')
        mimetypeFile.close()

        # Copy the style sheet files to the output dir
        # But not nav.css
        styleFiles = [self.styleDir / '..' / 'base.css']
        styleFiles += [self.styleDir / '..' / 'popup_bg.gif']
        styleFiles += [f for f in self.styleDir.files("*.css") if f.basename() != "nav.css"]
        styleFiles += self.styleDir.files("*.jpg")
        styleFiles += self.styleDir.files("*.gif")
        styleFiles += self.styleDir.files("*.png")
        styleFiles += self.styleDir.files("*.js")
        styleFiles += self.styleDir.files("*.html")
        styleFiles += self.styleDir.files("*.ttf")
        styleFiles += self.styleDir.files("*.eot")
        styleFiles += self.styleDir.files("*.otf")
        styleFiles += self.styleDir.files("*.woff")
        # FIXME for now, only copy files referenced in Common Cartridge
        # this really should apply to all exports, but without a manifest
        # of the files needed by an included stylesheet it is too restrictive

        package.resourceDir.copyfiles(contentPages)

        self.styleDir.copylist(styleFiles, contentPages)
        self.scriptsDir.copylist(('common.js',), contentPages)

        # copy players for media idevices.
        hasFlowplayer = False
        hasMagnifier = False
        hasXspfplayer = False
        hasGallery = False
        hasWikipedia = False
        isBreak = False
        hasInstructions = False

        for page in self.pages:
            if isBreak:
                break
            for idevice in page.node.idevices:
                if (hasFlowplayer and hasMagnifier and hasXspfplayer and hasGallery and hasWikipedia):
                    isBreak = True
                    break
                if not hasFlowplayer:
                    if 'flowPlayer.swf' in idevice.systemResources:
                        hasFlowplayer = True
                if not hasMagnifier:
                    if 'mojomagnify.js' in idevice.systemResources:
                        hasMagnifier = True
                if not hasXspfplayer:
                    if 'xspf_player.swf' in idevice.systemResources:
                        hasXspfplayer = True
                if not hasGallery:
                    hasGallery = common.ideviceHasGallery(idevice)
                if not hasWikipedia:
                    if 'WikipediaIdevice' == idevice.klass:
                        hasWikipedia = True
                if not hasInstructions:
                    if 'TrueFalseIdevice' == idevice.klass or 'MultichoiceIdevice' == idevice.klass or 'VerdaderofalsofpdIdevice' == idevice.klass or 'EleccionmultiplefpdIdevice' == idevice.klass:
                        hasInstructions = True

        if hasFlowplayer:
            videofile = (self.templatesDir / 'flowPlayer.swf')
            videofile.copyfile(contentPages / 'flowPlayer.swf')
            controlsfile = (self.templatesDir / 'flowplayer.controls.swf')
            controlsfile.copyfile(contentPages / 'flowplayer.controls.swf')
        if hasMagnifier:
            videofile = (self.templatesDir / 'mojomagnify.js')
            videofile.copyfile(contentPages / 'mojomagnify.js')
        if hasXspfplayer:
            videofile = (self.templatesDir / 'xspf_player.swf')
            videofile.copyfile(contentPages / 'xspf_player.swf')
        if hasGallery:
            imageGalleryCSS = (self.cssDir / 'exe_lightbox.css')
            imageGalleryCSS.copyfile(contentPages / 'exe_lightbox.css')
            imageGalleryJS = (self.scriptsDir / 'exe_lightbox.js')
            imageGalleryJS.copyfile(contentPages / 'exe_lightbox.js')
            self.imagesDir.copylist(('exe_lightbox_close.png', 'exe_lightbox_loading.gif', 'exe_lightbox_next.png', 'exe_lightbox_prev.png'), contentPages)
        if hasWikipedia:
            wikipediaCSS = (self.cssDir / 'exe_wikipedia.css')
            wikipediaCSS.copyfile(contentPages / 'exe_wikipedia.css')
        if hasInstructions:
            common.copyFileIfNotInStyle('panel-amusements.png', self, contentPages)
            common.copyFileIfNotInStyle('stock-stop.png', self, contentPages)

        my_style = G.application.config.styleStore.getStyle(package.style)
        if my_style.hasValidConfig:
            if my_style.get_jquery() == True:
                jsFile = (self.scriptsDir / 'exe_jquery.js')
                jsFile.copyfile(contentPages / 'exe_jquery.js')
        else:
            jsFile = (self.scriptsDir / 'exe_jquery.js')
            jsFile.copyfile(contentPages / 'exe_jquery.js')

#         if hasattr(package, 'exportSource') and package.exportSource:
#             (G.application.config.webDir / 'templates' / 'content.xsd').copyfile(outputDir / 'content.xsd')
#             (outputDir / 'content.data').write_bytes(encodeObject(package))
#             (outputDir / 'contentv3.xml').write_bytes(encodeObjectToXML(package))

        if package.license == "license GFDL":
            # include a copy of the GNU Free Documentation Licence
            (self.templatesDir / 'fdl.html').copyfile(contentPages / 'fdl.html')

        # Create the nav.xhtml file
        container = NavEpub3(self.pages, contentPages)
        container.save()

        
        publication = self.make_publication_epub3(contentPages, package, cover)
        publication.save("package.opf")

        # Create the container file
        container = ContainerEpub3(metainfPages)
        container.save("container.xml")

        # Zip it up!
        self.filename.safeSave(self.doZip, _(u'EXPORT FAILED!\nLast succesful export is %s.'), outputDir)
        # Clean up the temporary dir

        outputDir.rmtree()

    @classmethod
    def check_package_identifier(cls, package):
        """Make sure the package has a dublin core identifier
        Parameters
        ----------
        package : Package
            The package to check for an identifier on
        """
        if not package.dublinCore.identifier:
            package.dublinCore.identifier = str(uuid.uuid4())

    def make_cover_page(self, package):
        """Return a Epub3Cover for the given package
        Parameters
        ----------
        package : Package
            Package to create a cover page for
        """
        return Epub3Cover("cover", 1, package.root)

    def make_publication_epub3(self, contentPagesDir, package, cover):
        """Return a PublicationEpub3 for this export
        Call only after self.pages has been generated
        
        Parameters
        ----------
        contentPagesDir : Path
            The directory where the contents of the package have been 
            exported to (e.g. the 'EPUB' dir) 
        package : Package
            The package being exported
        cover : Epub3Cover
            The cover page
        """
        publication = PublicationEpub3(self.config, contentPagesDir, package, self.pages, cover)
        return publication

    def doZip(self, fileObj, outputDir):
        """
        Actually does the zipping of the file. Called by 'Path.safeSave'
        """
        zipped = ZipFile(fileObj, "w")

        mimetype = outputDir / "mimetype"
        zipped.write(mimetype, "mimetype", ZIP_STORED)

        for epubFile in outputDir.walkfiles():
            if epubFile.basename() == 'mimetype':
                continue
            relativePath = epubFile.basename()
            parentdir = epubFile.splitpath()[0]
            while (outputDir.basename() != parentdir.basename()):
                relativePath = parentdir.basename() / relativePath
                parentdir = parentdir.splitpath()[0]

            zipped.write(epubFile,
                             relativePath.encode('utf8'),
                             compress_type=ZIP_DEFLATED)
        zipped.close()

    def generatePages(self, node, depth):
        """
        Recursive function for exporting a node.
        'node' is the node that we are making a page for
        'depth' is the number of ancestors that the page has +1 (ie. root is 1)
        """
        pageName = node.titleShort.lower().replace(" ", u"_")
        pageName = re.sub(r"\W", "", pageName)
        if not pageName:
            pageName = u"__"

        if pageName[0] in [unicode(i) for i in range(0, 10)]:
            pageName = u'_' + pageName

        page = Epub3Page(pageName, depth, node)

        self.pages.append(page)
        for child in node.children:
            self.generatePages(child, depth + 1)
Beispiel #11
0
class ScormExport(object):
    """
    Exports an eXe package as a SCORM package
    """
    def __init__(self, config, styleDir, filename, scormType):
        """ 
        Initialize
        'styleDir' is the directory from which we will copy our style sheets
        (and some gifs)
        """
        self.config = config
        self.imagesDir = config.webDir / "images"
        self.scriptsDir = config.webDir / "scripts"
        self.templatesDir = config.webDir / "templates"
        self.schemasDir = config.webDir / "schemas"
        self.styleDir = Path(styleDir)
        self.filename = Path(filename)
        self.pages = []
        self.hasForum = False
        self.scormType = scormType

    def export(self, package):
        """ 
        Export SCORM package
        """
        # First do the export to a temporary directory
        outputDir = TempDirPath()

        # Export the package content
        self.pages = [
            ScormPage("index", 1, package.root, scormType=self.scormType)
        ]

        self.generatePages(package.root, 2)
        uniquifyNames(self.pages)

        for page in self.pages:
            page.save(outputDir)
            if not self.hasForum:
                for idevice in page.node.idevices:
                    if hasattr(idevice, "isForum"):
                        if idevice.forum.lms.lms == "moodle":
                            self.hasForum = True
                            break

        # Create the manifest file
        manifest = Manifest(self.config, outputDir, package, self.pages,
                            self.scormType)
        manifest.save("imsmanifest.xml")
        if self.hasForum:
            manifest.save("discussionforum.xml")

        # Copy the style sheet files to the output dir
        # But not nav.css
        styleFiles = [self.styleDir / '..' / 'base.css']
        styleFiles += [self.styleDir / '..' / 'popup_bg.gif']
        styleFiles += [
            f for f in self.styleDir.files("*.css")
            if f.basename() <> "nav.css"
        ]
        styleFiles += self.styleDir.files("*.jpg")
        styleFiles += self.styleDir.files("*.gif")
        styleFiles += self.styleDir.files("*.png")
        styleFiles += self.styleDir.files("*.js")
        styleFiles += self.styleDir.files("*.html")
        # FIXME for now, only copy files referenced in Common Cartridge
        # this really should apply to all exports, but without a manifest
        # of the files needed by an included stylesheet it is too restrictive
        if self.scormType == "commoncartridge":
            for sf in styleFiles[:]:
                if sf.basename() not in manifest.dependencies:
                    styleFiles.remove(sf)
        self.styleDir.copylist(styleFiles, outputDir)

        # copy the package's resource files
        package.resourceDir.copyfiles(outputDir)

        # Copy the scripts
        if self.scormType == "commoncartridge":
            self.scriptsDir.copylist(('libot_drag.js', 'common.js'), outputDir)
        else:
            self.scriptsDir.copylist(('APIWrapper.js', 'SCOFunctions.js',
                                      'libot_drag.js', 'common.js'), outputDir)
        schemasDir = ""
        if self.scormType == "scorm1.2":
            schemasDir = self.schemasDir / "scorm1.2"
            schemasDir.copylist(
                ('imscp_rootv1p1p2.xsd', 'imsmd_rootv1p2p1.xsd',
                 'adlcp_rootv1p2.xsd', 'ims_xml.xsd'), outputDir)
        elif self.scormType == "scorm2004":
            schemasDir = self.schemasDir / "scorm2004"
            schemasDir.copylist(
                ('imscp_rootv1p1p2.xsd', 'imsmd_rootv1p2p1.xsd',
                 'adlcp_rootv1p2.xsd', 'ims_xml.xsd'), outputDir)

        # copy players for media idevices.
        hasFlowplayer = False
        hasMagnifier = False
        hasXspfplayer = False
        isBreak = False

        for page in self.pages:
            if isBreak:
                break
            for idevice in page.node.idevices:
                if (hasFlowplayer and hasMagnifier and hasXspfplayer):
                    isBreak = True
                    break
                if not hasFlowplayer:
                    if 'flowPlayer.swf' in idevice.systemResources:
                        hasFlowplayer = True
                if not hasMagnifier:
                    if 'magnifier.swf' in idevice.systemResources:
                        hasMagnifier = True
                if not hasXspfplayer:
                    if 'xspf_player.swf' in idevice.systemResources:
                        hasXspfplayer = True

        if hasFlowplayer:
            videofile = (self.templatesDir / 'flowPlayer.swf')
            videofile.copyfile(outputDir / 'flowPlayer.swf')
        if hasMagnifier:
            videofile = (self.templatesDir / 'magnifier.swf')
            videofile.copyfile(outputDir / 'magnifier.swf')
        if hasXspfplayer:
            videofile = (self.templatesDir / 'xspf_player.swf')
            videofile.copyfile(outputDir / 'xspf_player.swf')

        if self.scormType == "scorm1.2" or self.scormType == "scorm2004":
            if package.license == "GNU Free Documentation License":
                # include a copy of the GNU Free Documentation Licence
                (self.templatesDir / 'fdl.html').copyfile(outputDir /
                                                          'fdl.html')
        # Zip it up!
        self.filename.safeSave(
            self.doZip, _('EXPORT FAILED!\nLast succesful export is %s.'),
            outputDir)
        # Clean up the temporary dir
        outputDir.rmtree()

    def doZip(self, fileObj, outputDir):
        """
        Actually does the zipping of the file. Called by 'Path.safeSave'
        """
        # Zip up the scorm package
        zipped = ZipFile(fileObj, "w")
        for scormFile in outputDir.files():
            zipped.write(scormFile,
                         scormFile.basename().encode('utf8'), ZIP_DEFLATED)
        zipped.close()

    def generatePages(self, node, depth):
        """
        Recursive function for exporting a node.
        'node' is the node that we are making a page for
        'depth' is the number of ancestors that the page has +1 (ie. root is 1)
        """
        for child in node.children:
            pageName = child.titleShort.lower().replace(" ", "_")
            pageName = re.sub(r"\W", "", pageName)
            if not pageName:
                pageName = "__"

            page = ScormPage(pageName, depth, child, scormType=self.scormType)

            self.pages.append(page)
            self.generatePages(child, depth + 1)
Beispiel #12
0
class ScormExport(object):
    """
    Exports an eXe package as a SCORM package
    """
    def __init__(self, config, styleDir, filename, scormType):
        """ 
        Initialize
        'styleDir' is the directory from which we will copy our style sheets
        (and some gifs)
        """
        self.config       = config
        self.imagesDir    = config.webDir/"images"
        self.scriptsDir   = config.webDir/"scripts"
        self.templatesDir = config.webDir/"templates"
        self.schemasDir   = config.webDir/"schemas"
        self.styleDir     = Path(styleDir)
        self.filename     = Path(filename)
        self.pages        = []
        self.hasForum     = False
        self.scormType    = scormType


    def export(self, package):
        """ 
        Export SCORM package
        """
        # First do the export to a temporary directory
        outputDir = TempDirPath()

        # Export the package content
        self.pages = [ ScormPage("index", 1, package.root,
            scormType=self.scormType) ]

        self.generatePages(package.root, 2)
        uniquifyNames(self.pages)

        for page in self.pages:
            page.save(outputDir)
            if not self.hasForum:
                for idevice in page.node.idevices:
                    if hasattr(idevice, "isForum"):
                        if idevice.forum.lms.lms == "moodle":
                            self.hasForum = True
                            break

        # Create the manifest file
        manifest = Manifest(self.config, outputDir, package, self.pages, self.scormType)
        manifest.save("imsmanifest.xml")
        if self.hasForum:
            manifest.save("discussionforum.xml")
        
        # Copy the style sheet files to the output dir
        # But not nav.css
        styleFiles  = [self.styleDir/'..'/'base.css']
        styleFiles += [self.styleDir/'..'/'popup_bg.gif']
        styleFiles += [f for f in self.styleDir.files("*.css")
                if f.basename() <> "nav.css"] 
        styleFiles += self.styleDir.files("*.jpg")
        styleFiles += self.styleDir.files("*.gif")
        styleFiles += self.styleDir.files("*.png")
        styleFiles += self.styleDir.files("*.js")
        styleFiles += self.styleDir.files("*.html")
        # FIXME for now, only copy files referenced in Common Cartridge
        # this really should apply to all exports, but without a manifest
        # of the files needed by an included stylesheet it is too restrictive
        if self.scormType == "commoncartridge":
            for sf in styleFiles[:]:
                if sf.basename() not in manifest.dependencies:
                    styleFiles.remove(sf)
        self.styleDir.copylist(styleFiles, outputDir)

        # copy the package's resource files
        package.resourceDir.copyfiles(outputDir)

        # Copy the scripts
        if self.scormType == "commoncartridge":
            self.scriptsDir.copylist(('libot_drag.js',
                                      'common.js'), outputDir)
        else:
            self.scriptsDir.copylist(('APIWrapper.js', 
                                      'SCOFunctions.js', 
                                      'libot_drag.js',
                                      'common.js'), outputDir)
        schemasDir = ""
        if self.scormType == "scorm1.2":
            schemasDir = self.schemasDir/"scorm1.2"
            schemasDir.copylist(('imscp_rootv1p1p2.xsd',
                                'imsmd_rootv1p2p1.xsd',
                                'adlcp_rootv1p2.xsd',
                                'ims_xml.xsd'), outputDir)
        elif self.scormType == "scorm2004":
            schemasDir = self.schemasDir/"scorm2004"
            schemasDir.copylist(('imscp_rootv1p1p2.xsd',
                                'imsmd_rootv1p2p1.xsd',
                                'adlcp_rootv1p2.xsd',
                                'ims_xml.xsd'), outputDir)
 

        # copy players for media idevices.                
        hasFlowplayer     = False
        hasMagnifier      = False
        hasXspfplayer     = False
        isBreak           = False
        
        for page in self.pages:
            if isBreak:
                break
            for idevice in page.node.idevices:
                if (hasFlowplayer and hasMagnifier and hasXspfplayer):
                    isBreak = True
                    break
                if not hasFlowplayer:
                    if 'flowPlayer.swf' in idevice.systemResources:
                        hasFlowplayer = True
                if not hasMagnifier:
                    if 'magnifier.swf' in idevice.systemResources:
                        hasMagnifier = True
                if not hasXspfplayer:
                    if 'xspf_player.swf' in idevice.systemResources:
                        hasXspfplayer = True
                        
        if hasFlowplayer:
            videofile = (self.templatesDir/'flowPlayer.swf')
            videofile.copyfile(outputDir/'flowPlayer.swf')
        if hasMagnifier:
            videofile = (self.templatesDir/'magnifier.swf')
            videofile.copyfile(outputDir/'magnifier.swf')
        if hasXspfplayer:
            videofile = (self.templatesDir/'xspf_player.swf')
            videofile.copyfile(outputDir/'xspf_player.swf')

        if self.scormType == "scorm1.2" or self.scormType == "scorm2004":
            if package.license == "GNU Free Documentation License":
                # include a copy of the GNU Free Documentation Licence
                (self.templatesDir/'fdl.html').copyfile(outputDir/'fdl.html')
        # Zip it up!
        self.filename.safeSave(self.doZip, _('EXPORT FAILED!\nLast succesful export is %s.'), outputDir)
        # Clean up the temporary dir
        outputDir.rmtree()

    def doZip(self, fileObj, outputDir):
        """
        Actually does the zipping of the file. Called by 'Path.safeSave'
        """
        # Zip up the scorm package
        zipped = ZipFile(fileObj, "w")
        for scormFile in outputDir.files():
            zipped.write(scormFile,
                         scormFile.basename().encode('utf8'),
                         ZIP_DEFLATED)
        zipped.close()

    def generatePages(self, node, depth):
        """
        Recursive function for exporting a node.
        'node' is the node that we are making a page for
        'depth' is the number of ancestors that the page has +1 (ie. root is 1)
        """
        for child in node.children:
            pageName = child.titleShort.lower().replace(" ", "_")
            pageName = re.sub(r"\W", "", pageName)
            if not pageName:
                pageName = "__"

            page = ScormPage(pageName, depth, child, scormType=self.scormType)

            self.pages.append(page)
            self.generatePages(child, depth + 1)
Beispiel #13
0
class Epub3Export(object):
    """
    Exports an eXe package as a epub 3 package
    The 'Hello World' of a epub 3 publication might contain files:
        mimetype
        META-INF/container.xml
        Content/HelloWorld.opf
        Content/HelloWorld.xhtml
    """
    def __init__(self, config, styleDir, filename):
        """
        Initialize
        'styleDir' is the directory from which we will copy our style sheets
        (and some gifs)
        """
        self.config = config
        self.imagesDir = config.webDir / "images"
        self.scriptsDir = config.webDir / "scripts"
        self.cssDir = config.webDir / "css"
        self.templatesDir = config.webDir / "templates"
        self.schemasDir = config.webDir / "schemas/ims"
        self.styleDir = Path(styleDir)
        self.filename = Path(filename)
        self.pages = []

    def export(self, package):
        """
        Export epub 3 package
        """
        # First do the export to a temporary directory
        outputDir = TempDirPath()

        '''
        fileDir = outputDir/"META-INF"
        fileDir.mkdir()
        fileDir = outputDir/"Content"
        fileDir.mkdir()
        '''

        metainfPages = Path(outputDir.abspath() + '/META-INF')
        # metainfPages = outputDir/'META-INF'
        metainfPages.mkdir()
        contentPages = Path(outputDir.abspath() + '/EPUB')
        # contentPages = outputDir/'Content'
        contentPages.mkdir()
        # print contentPages.abspath()
        # print outputDir.abspath()

        # Export the package content
        self.pages = [Epub3Cover("cover", 1, package.root)]

        self.generatePages(package.root, 2)
        uniquifyNames(self.pages)

        cover = None
        for page in self.pages:
            page.save(contentPages, self.pages)
            if hasattr(page, 'cover'):
                cover = page.cover

        # Create mimetype file
        mimetypeFile = open(outputDir.abspath() + '/mimetype', "w")
        mimetypeFile.write('application/epub+zip')
        mimetypeFile.close()

        # Create common_i18n file
        langFile = open(contentPages + '/common_i18n.js', "w")
        langFile.write(common.getJavaScriptStrings(False))
        langFile.close()

        # Copy the style files to the output dir
        # But not nav.css
        styleFiles = [self.styleDir /'..'/ 'popup_bg.gif']
        styleFiles += [f for f in self.styleDir.files("*.*") if f.basename() not in ['nav.css']]

        # FIXME for now, only copy files referenced in Common Cartridge
        # this really should apply to all exports, but without a manifest
        # of the files needed by an included stylesheet it is too restrictive

        # Add fallback document for possible image links
        if Path(self.styleDir/'fallback.xhtml').exists():
            styleFiles += [self.styleDir /'fallback.xhtml']
        else:
            styleFiles += [self.styleDir/'..'/'fallback.xhtml']

        # copy the package's resource files
        for resourceFile in package.resourceDir.walkfiles():
            fn = package.resourceDir.relpathto(resourceFile)

            if ("/" in fn):
                Dir = Path(contentPages/fn[:fn.rindex("/")])
                if not Dir.exists():
                    Dir.makedirs()

                resourceFile.copy(contentPages/Dir)
            else:
                resourceFile.copy(contentPages)

        self.styleDir.copylist(styleFiles, contentPages)

        # copy players for media idevices.
        hasFlowplayer = False
        hasMagnifier = False
        hasXspfplayer = False
        hasGallery = False
        hasFX = False
        hasSH = False
        hasGames = False
        hasElpLink = False
        hasWikipedia = False
        isBreak = False
        hasInstructions = False
        hasTooltips = False
        hasABCMusic = False

        for page in self.pages:
            if isBreak:
                break
            for idevice in page.node.idevices:
                if (hasFlowplayer and hasMagnifier and hasXspfplayer and hasGallery and hasFX and hasSH and hasGames and hasElpLink and hasWikipedia and hasInstructions and hasTooltips and hasABCMusic):
                    isBreak = True
                    break
                if not hasFlowplayer:
                    if 'flowPlayer.swf' in idevice.systemResources:
                        hasFlowplayer = True
                if not hasMagnifier:
                    if 'mojomagnify.js' in idevice.systemResources:
                        hasMagnifier = True
                if not hasXspfplayer:
                    if 'xspf_player.swf' in idevice.systemResources:
                        hasXspfplayer = True
                if not hasGallery:
                    hasGallery = common.ideviceHasGallery(idevice)
                if not hasFX:
                    hasFX = common.ideviceHasFX(idevice)
                if not hasSH:
                    hasSH = common.ideviceHasSH(idevice)
                if not hasGames:
                    hasGames = common.ideviceHasGames(idevice)
                if not hasElpLink:
                    hasElpLink = common.ideviceHasElpLink(idevice,package)
                if not hasWikipedia:
                    if 'WikipediaIdevice' == idevice.klass:
                        hasWikipedia = True
                if not hasInstructions:
                    if 'TrueFalseIdevice' == idevice.klass or 'MultichoiceIdevice' == idevice.klass or 'VerdaderofalsofpdIdevice' == idevice.klass or 'EleccionmultiplefpdIdevice' == idevice.klass:
                        hasInstructions = True
                if not hasTooltips:
                    hasTooltips = common.ideviceHasTooltips(idevice)
                if not hasABCMusic:
                    hasABCMusic = common.ideviceHasABCMusic(idevice)

            common.exportJavaScriptIdevicesFiles(page.node.idevices, contentPages);

        if hasFlowplayer:
            videofile = (self.templatesDir / 'flowPlayer.swf')
            videofile.copyfile(contentPages / 'flowPlayer.swf')
            controlsfile = (self.templatesDir / 'flowplayer.controls.swf')
            controlsfile.copyfile(contentPages / 'flowplayer.controls.swf')
        if hasMagnifier:
            videofile = (self.templatesDir / 'mojomagnify.js')
            videofile.copyfile(contentPages / 'mojomagnify.js')
        if hasXspfplayer:
            videofile = (self.templatesDir / 'xspf_player.swf')
            videofile.copyfile(contentPages / 'xspf_player.swf')
        if hasGallery:
            exeLightbox = (self.scriptsDir / 'exe_lightbox')
            exeLightbox.copyfiles(contentPages)
        if hasFX:
            exeEffects = (self.scriptsDir / 'exe_effects')
            exeEffects.copyfiles(contentPages)
        if hasSH:
            exeSH = (self.scriptsDir / 'exe_highlighter')
            exeSH.copyfiles(contentPages)
        if hasGames:
            exeGames = (self.scriptsDir / 'exe_games')
            exeGames.copyfiles(contentPages)
            # Add game js string to common_i18n
            langGameFile = open(contentPages + '/common_i18n.js', "a")
            langGameFile.write(common.getGamesJavaScriptStrings(False))
            langGameFile.close()
        if hasElpLink or package.get_exportElp():
            # Export the elp file
            currentPackagePath = Path(package.filename)
            currentPackagePath.copyfile(contentPages/package.name+'.elp')
        if hasWikipedia:
            wikipediaCSS = (self.cssDir / 'exe_wikipedia.css')
            wikipediaCSS.copyfile(contentPages / 'exe_wikipedia.css')
        if hasInstructions:
            common.copyFileIfNotInStyle('panel-amusements.png', self, contentPages)
            common.copyFileIfNotInStyle('stock-stop.png', self, contentPages)
        if hasTooltips:
            exe_tooltips = (self.scriptsDir / 'exe_tooltips')
            exe_tooltips.copyfiles(contentPages)
        if hasABCMusic:
            pluginScripts = (self.scriptsDir/'tinymce_4/js/tinymce/plugins/abcmusic/export')
            pluginScripts.copyfiles(contentPages)

        my_style = G.application.config.styleStore.getStyle(package.style)
        if my_style.hasValidConfig:
            if my_style.get_jquery() == True:
                jsFile = (self.scriptsDir / 'exe_jquery.js')
                jsFile.copyfile(contentPages / 'exe_jquery.js')
        else:
            jsFile = (self.scriptsDir / 'exe_jquery.js')
            jsFile.copyfile(contentPages / 'exe_jquery.js')


        # Copy and minify CSS files
        css_files = getFilesCSSToMinify('epub3', self.styleDir)
        exportMinFileCSS(css_files, contentPages)

        # Copy and minify JS files
        js_files = getFilesJSToMinify('epub3', self.scriptsDir)
        exportMinFileJS(js_files, contentPages)

#         if hasattr(package, 'exportSource') and package.exportSource:
#             (G.application.config.webDir / 'templates' / 'content.xsd').copyfile(outputDir / 'content.xsd')
#             (outputDir / 'content.data').write_bytes(encodeObject(package))
#             (outputDir / 'contentv3.xml').write_bytes(encodeObjectToXML(package))

        if package.license == "license GFDL":
            # include a copy of the GNU Free Documentation Licence
            (self.templatesDir / 'fdl.html').copyfile(contentPages / 'fdl.html')

        # Create the nav.xhtml file
        container = NavEpub3(self.pages, contentPages)
        container.save()

        # Create the publication file
        publication = PublicationEpub3(self.config, contentPages, package, self.pages, cover)
        publication.save("package.opf")

        # Create the container file
        container = ContainerEpub3(metainfPages)
        container.save("container.xml")

        # Zip it up!
        self.filename.safeSave(self.doZip, _(u'EXPORT FAILED!\nLast succesful export is %s.'), outputDir)
        # Clean up the temporary dir

        outputDir.rmtree()

    def doZip(self, fileObj, outputDir):
        """
        Actually does the zipping of the file. Called by 'Path.safeSave'
        """
        zipped = ZipFile(fileObj, "w")

        mimetype = outputDir / "mimetype"
        zipped.write(mimetype, "mimetype", ZIP_STORED)

        for epubFile in outputDir.walkfiles():
            if epubFile.basename() == 'mimetype':
                continue
            relativePath = epubFile.basename()
            parentdir = epubFile.splitpath()[0]
            while (outputDir.basename() != parentdir.basename()):
                relativePath = parentdir.basename() / relativePath
                parentdir = parentdir.splitpath()[0]

            zipped.write(epubFile,
                             relativePath.encode('utf8'),
                             compress_type=ZIP_DEFLATED)
        zipped.close()

    def generatePages(self, node, depth):
        """
        Recursive function for exporting a node.
        'node' is the node that we are making a page for
        'depth' is the number of ancestors that the page has +1 (ie. root is 1)
        """
        pageName = node.titleShort.lower().replace(" ", u"_")
        pageName = re.sub(r"\W", "", pageName)
        if not pageName:
            pageName = u"__"

        if pageName[0] in [unicode(i) for i in range(0, 10)]:
            pageName = u'_' + pageName

        page = Epub3Page(pageName, depth, node)

        self.pages.append(page)
        for child in node.children:
            self.generatePages(child, depth + 1)
Beispiel #14
0
class IMSExport(object):
    """
    Exports an eXe package as a SCORM package
    """
    def __init__(self, config, styleDir, filename):
        """ Initialize
        'styleDir' is the directory from which we will copy our style sheets
        (and some gifs)
        """
        self.config = config
        self.imagesDir = config.webDir / "images"
        self.scriptsDir = config.webDir / "scripts"
        self.cssDir = config.webDir / "css"
        self.templatesDir = config.webDir / "templates"
        self.schemasDir = config.webDir / "schemas/ims"
        self.styleDir = Path(styleDir)
        self.filename = Path(filename)
        self.pages = []

    def export(self, package):
        """ 
        Export SCORM package
        """
        # First do the export to a temporary directory
        outputDir = TempDirPath()

        self.metadataType = package.exportMetadataType

        # Copy the style sheet files to the output dir
        # But not nav.css
        styleFiles = [self.styleDir / '..' / 'base.css']
        styleFiles += [self.styleDir / '..' / 'popup_bg.gif']
        styleFiles += self.styleDir.files("*.css")
        if "nav.css" in styleFiles:
            styleFiles.remove("nav.css")
        styleFiles += self.styleDir.files("*.jpg")
        styleFiles += self.styleDir.files("*.gif")
        styleFiles += self.styleDir.files("*.png")
        styleFiles += self.styleDir.files("*.js")
        styleFiles += self.styleDir.files("*.html")
        styleFiles += self.styleDir.files("*.ttf")
        styleFiles += self.styleDir.files("*.eot")
        styleFiles += self.styleDir.files("*.otf")
        styleFiles += self.styleDir.files("*.woff")
        self.styleDir.copylist(styleFiles, outputDir)

        # copy the package's resource files
        package.resourceDir.copyfiles(outputDir)

        # Export the package content
        self.pages = [
            IMSPage("index", 1, package.root, metadataType=self.metadataType)
        ]

        self.generatePages(package.root, 2)
        uniquifyNames(self.pages)

        for page in self.pages:
            page.save(outputDir)

        # Create the manifest file
        manifest = Manifest(self.config, outputDir, package, self.pages,
                            self.metadataType)
        manifest.save("imsmanifest.xml")

        # Copy the scripts

        # jQuery
        my_style = G.application.config.styleStore.getStyle(
            page.node.package.style)
        if my_style.hasValidConfig:
            if my_style.get_jquery() == True:
                jsFile = (self.scriptsDir / 'exe_jquery.js')
                jsFile.copyfile(outputDir / 'exe_jquery.js')
        else:
            jsFile = (self.scriptsDir / 'exe_jquery.js')
            jsFile.copyfile(outputDir / 'exe_jquery.js')

        jsFile = (self.scriptsDir / 'common.js')
        jsFile.copyfile(outputDir / 'common.js')
        dT = common.getExportDocType()
        if dT == "HTML5":
            jsFile = (self.scriptsDir / 'exe_html5.js')
            jsFile.copyfile(outputDir / 'exe_html5.js')

        self.schemasDir.copylist(('imscp_v1p1.xsd', 'imsmd_v1p2p2.xsd',
                                  'lom.xsd', 'lomCustom.xsd', 'ims_xml.xsd'),
                                 outputDir)

        # copy players for media idevices.
        hasFlowplayer = False
        hasMagnifier = False
        hasXspfplayer = False
        hasGallery = False
        hasFX = False
        hasSH = False
        hasGames = False
        hasWikipedia = False
        isBreak = False
        hasInstructions = False
        hasMediaelement = False
        hasTooltips = False

        for page in self.pages:
            if isBreak:
                break
            for idevice in page.node.idevices:
                if (hasFlowplayer and hasMagnifier and hasXspfplayer
                        and hasGallery and hasFX and hasSH and hasGames
                        and hasWikipedia and hasInstructions
                        and hasMediaelement and hasTooltips):
                    isBreak = True
                    break
                if not hasFlowplayer:
                    if 'flowPlayer.swf' in idevice.systemResources:
                        hasFlowplayer = True
                if not hasMagnifier:
                    if 'mojomagnify.js' in idevice.systemResources:
                        hasMagnifier = True
                if not hasXspfplayer:
                    if 'xspf_player.swf' in idevice.systemResources:
                        hasXspfplayer = True
                if not hasGallery:
                    hasGallery = common.ideviceHasGallery(idevice)
                if not hasFX:
                    hasFX = common.ideviceHasFX(idevice)
                if not hasSH:
                    hasSH = common.ideviceHasSH(idevice)
                if not hasGames:
                    hasGames = common.ideviceHasGames(idevice)
                if not hasWikipedia:
                    if 'WikipediaIdevice' == idevice.klass:
                        hasWikipedia = True
                if not hasInstructions:
                    if 'TrueFalseIdevice' == idevice.klass or 'MultichoiceIdevice' == idevice.klass or 'VerdaderofalsofpdIdevice' == idevice.klass or 'EleccionmultiplefpdIdevice' == idevice.klass:
                        hasInstructions = True
                if not hasMediaelement:
                    hasMediaelement = common.ideviceHasMediaelement(idevice)
                if not hasTooltips:
                    hasTooltips = common.ideviceHasTooltips(idevice)

        if hasFlowplayer:
            videofile = (self.templatesDir / 'flowPlayer.swf')
            videofile.copyfile(outputDir / 'flowPlayer.swf')
            controlsfile = (self.templatesDir / 'flowplayer.controls.swf')
            controlsfile.copyfile(outputDir / 'flowplayer.controls.swf')
        if hasMagnifier:
            videofile = (self.templatesDir / 'mojomagnify.js')
            videofile.copyfile(outputDir / 'mojomagnify.js')
        if hasXspfplayer:
            videofile = (self.templatesDir / 'xspf_player.swf')
            videofile.copyfile(outputDir / 'xspf_player.swf')
        if hasGallery:
            exeLightbox = (self.scriptsDir / 'exe_lightbox')
            exeLightbox.copyfiles(outputDir)
        if hasFX:
            exeEffects = (self.scriptsDir / 'exe_effects')
            exeEffects.copyfiles(outputDir)
        if hasSH:
            exeSH = (self.scriptsDir / 'exe_highlighter')
            exeSH.copyfiles(outputDir)
        if hasGames:
            exeGames = (self.scriptsDir / 'exe_games')
            exeGames.copyfiles(outputDir)
        if hasWikipedia:
            wikipediaCSS = (self.cssDir / 'exe_wikipedia.css')
            wikipediaCSS.copyfile(outputDir / 'exe_wikipedia.css')
        if hasInstructions:
            common.copyFileIfNotInStyle('panel-amusements.png', self,
                                        outputDir)
            common.copyFileIfNotInStyle('stock-stop.png', self, outputDir)
        if hasMediaelement:
            mediaelement = (self.scriptsDir / 'mediaelement')
            mediaelement.copyfiles(outputDir)
            if dT != "HTML5":
                jsFile = (self.scriptsDir / 'exe_html5.js')
                jsFile.copyfile(outputDir / 'exe_html5.js')
        if hasTooltips:
            exe_tooltips = (self.scriptsDir / 'exe_tooltips')
            exe_tooltips.copyfiles(outputDir)
        if hasattr(package, 'exportSource') and package.exportSource:
            (G.application.config.webDir / 'templates' /
             'content.xsd').copyfile(outputDir / 'content.xsd')
            (outputDir / 'content.data').write_bytes(encodeObject(package))
            (outputDir / 'contentv3.xml').write_bytes(
                encodeObjectToXML(package))

        if package.license == "license GFDL":
            # include a copy of the GNU Free Documentation Licence
            (self.templatesDir / 'fdl.html').copyfile(outputDir / 'fdl.html')
        # Zip it up!
        self.filename.safeSave(
            self.doZip, _('EXPORT FAILED!\nLast succesful export is %s.'),
            outputDir)
        # Clean up the temporary dir
        outputDir.rmtree()

    def doZip(self, fileObj, outputDir):
        """
        Actually does the zipping of the file. Called by 'Path.safeSave'
        """
        zipped = ZipFile(fileObj, "w")
        for scormFile in outputDir.files():
            zipped.write(scormFile,
                         scormFile.basename().encode('utf8'), ZIP_DEFLATED)
        zipped.close()

    def generatePages(self, node, depth):
        """
        Recursive function for exporting a node.
        'outputDir' is the temporary directory that we are exporting to
        before creating zip file
        """
        for child in node.children:
            pageName = child.titleShort.lower().replace(" ", "_")
            pageName = re.sub(r"\W", "", pageName)
            if not pageName:
                pageName = "__"

            page = IMSPage(pageName,
                           depth,
                           child,
                           metadataType=self.metadataType)

            self.pages.append(page)
            self.generatePages(child, depth + 1)
Beispiel #15
0
class WebsiteExport(object):
    """
    WebsiteExport will export a package as a website of HTML pages
    """
    def __init__(self, config, styleDir, filename):
        """
        'stylesDir' is the directory where we can copy the stylesheets from
        'outputDir' is the directory that will be [over]written
        with the website
        """
        self.config       = config
        self.imagesDir    = config.webDir/"images"
        self.scriptsDir   = config.webDir/"scripts"
        self.templatesDir = config.webDir/"templates"
        self.stylesDir    = Path(styleDir)
        self.filename     = Path(filename)
        self.pages        = []
    def exportZip(self, package):
        """ 
        Export web site
        Cleans up the previous packages pages and performs the export
        """
        outputDir = TempDirPath()
        self.copyFiles(package, outputDir)
        if (self.stylesDir/"websitepage.py").exists():
            global WebsitePage
            module = imp.load_source("websitepage", 
                                     self.stylesDir/"websitepage.py")
            WebsitePage = module.WebsitePage
        self.pages = [ WebsitePage("index", 1, package.root) ]
        self.generatePages(package.root, 1)
        uniquifyNames(self.pages)
        prevPage = None
        thisPage = self.pages[0]
        for nextPage in self.pages[1:]:
            thisPage.save(outputDir, prevPage, nextPage, self.pages)
            prevPage = thisPage
            thisPage = nextPage
        thisPage.save(outputDir, prevPage, None, self.pages)
        self.filename.safeSave(self.doZip, _('EXPORT FAILED!\nLast succesful export is %s.'), outputDir)
        outputDir.rmtree()
    def doZip(self, fileObj, outputDir):
        """
        Actually saves the zip data. Called by 'Path.safeSave'
        """
        zipped = ZipFile(fileObj, "w")
        for scormFile in outputDir.files():
            zipped.write(scormFile, scormFile.basename().encode('utf8'), ZIP_DEFLATED)
        zipped.close()
    def export(self, package):
        """ 
        Export web site
        Cleans up the previous packages pages and performs the export
        """
        outputDir = self.filename
        if not outputDir.exists(): 
            outputDir.mkdir()
        self.copyFiles(package, outputDir)
        if (self.stylesDir/"websitepage.py").exists():
            global WebsitePage
            module = imp.load_source("websitepage", 
                                     self.stylesDir/"websitepage.py")
            WebsitePage = module.WebsitePage
        self.pages = [ WebsitePage("index", 1, package.root) ]
        self.generatePages(package.root, 1)
        uniquifyNames(self.pages)
        prevPage = None
        thisPage = self.pages[0]
        for nextPage in self.pages[1:]:
            thisPage.save(outputDir, prevPage, nextPage, self.pages)
            prevPage = thisPage
            thisPage = nextPage
        thisPage.save(outputDir, prevPage, None, self.pages)
    def copyFiles(self, package, outputDir):
        """
        Copy all the files used by the website.
        """
        styleFiles  = [self.stylesDir/'..'/'base.css']
        styleFiles += [self.stylesDir/'..'/'popup_bg.gif']
        styleFiles += self.stylesDir.files("*.css")
        styleFiles += self.stylesDir.files("*.jpg")
        styleFiles += self.stylesDir.files("*.gif")
        styleFiles += self.stylesDir.files("*.png")
        styleFiles += self.stylesDir.files("*.js")
        styleFiles += self.stylesDir.files("*.html")
        self.stylesDir.copylist(styleFiles, outputDir)
        package.resourceDir.copyfiles(outputDir)
        self.scriptsDir.copylist(('libot_drag.js', 'common.js'), 
                                  outputDir)
        self.templatesDir.copylist(('videoContainer.swf', 'magnifier.swf',
                                    'xspf_player.swf'), outputDir)
        (self.templatesDir/'fdl.html').copyfile(outputDir/'fdl.html')
    def generatePages(self, node, depth):
        """
        Recursively generate pages and store in pages member variable
        for retrieving later
        """           
        for child in node.children:
            pageName = child.titleShort.lower().replace(" ", "_")
            pageName = re.sub(r"\W", "", pageName)
            if not pageName:
                pageName = "__"
            self.pages.append(WebsitePage(pageName, depth, child))
            self.generatePages(child, depth + 1)
Beispiel #16
0
class ScormExport(object):
    """
    Exports an eXe package as a SCORM package
    """
    def __init__(self, config, styleDir, filename, scormType):
        """
        Initialize
        'styleDir' is the directory from which we will copy our style sheets
        (and some gifs)
        """
        self.config          = config
        self.imagesDir       = config.webDir/"images"
        self.scriptsDir      = config.webDir/"scripts"
        self.cssDir          = config.webDir/"css"
        self.templatesDir    = config.webDir/"templates"
        self.schemasDir      = config.webDir/"schemas"
        self.styleDir        = Path(styleDir)
        self.filename        = Path(filename)
        self.pages           = []
        self.hasForum        = False
        self.scormType       = scormType
        self.styleSecureMode = config.styleSecureMode


    def export(self, package):
        """
        Export SCORM package
        """
        # First do the export to a temporary directory
        outputDir = TempDirPath()

        self.metadataType = package.exportMetadataType

        # copy the package's resource files
        for resourceFile in package.resourceDir.walkfiles():
            file = package.resourceDir.relpathto(resourceFile)

            if ("/" in file):
                Dir = Path(outputDir/file[:file.rindex("/")])

                if not Dir.exists():
                    Dir.makedirs()

                resourceFile.copy(outputDir/Dir)
            else:
                resourceFile.copy(outputDir)

        # copy the package's resource files, only non existant in outputDir
#        outputDirFiles = outputDir.files()
#        for rfile in package.resourceDir.files():
#            if rfile not in outputDirFiles:
#                rfile.copy(outputDir)

        # copy the package's resource files, only indexed in package.resources
#        for md5 in package.resources.values():
#            for resource in md5:
#                resource.path.copy(outputDir)

        # Export the package content
        # Import the Scorm Page class , if the secure mode is off.  If the style has it's own page class
        # use that, else use the default one.
        if self.styleSecureMode=="0":
            if (self.styleDir/"scormpage.py").exists():
                global ScormPage
                module = imp.load_source("ScormPage",self.styleDir/"scormpage.py")
                ScormPage = module.ScormPage


        self.pages = [ ScormPage("index", 1, package.root,
            scormType=self.scormType, metadataType=self.metadataType) ]

        self.generatePages(package.root, 2)
        uniquifyNames(self.pages)

        for page in self.pages:
            page.save(outputDir, self.pages)
            if not self.hasForum:
                for idevice in page.node.idevices:
                    if hasattr(idevice, "isForum"):
                        if idevice.forum.lms.lms == "moodle":
                            self.hasForum = True
                            break

        # Create the manifest file
        manifest = Manifest(self.config, outputDir, package, self.pages, self.scormType, self.metadataType)
        modifiedMetaData = manifest.save("imsmanifest.xml")

        # Create lang file
        langFile = open(outputDir + '/common_i18n.js', "w")
        langFile.write(common.getJavaScriptStrings(False))
        langFile.close()

        if self.hasForum:
            manifest.save("discussionforum.xml")

        # Copy the style files to the output dir

        styleFiles = [self.styleDir/'..'/'popup_bg.gif']
        # And with all the files of the style we avoid problems:
        styleFiles += self.styleDir.files("*.*")
        if self.scormType == "commoncartridge":
            for sf in styleFiles[:]:
                if sf.basename() not in manifest.dependencies:
                    styleFiles.remove(sf)
        self.styleDir.copylist(styleFiles, outputDir)

        listCSSFiles=getFilesCSSToMinify('scorm', self.styleDir)
        exportMinFileCSS(listCSSFiles, outputDir)

        # Copy the scripts

        dT = common.getExportDocType()
        if dT == "HTML5":
            #listFiles+=[self.scriptsDir/'exe_html5.js']
            #listOutFiles+=[outputDir/'exe_html5.js']
            jsFile = (self.scriptsDir/'exe_html5.js')
            jsFile.copyfile(outputDir/'exe_html5.js')

        # jQuery
        my_style = G.application.config.styleStore.getStyle(page.node.package.style)
        if my_style.hasValidConfig:
            if my_style.get_jquery() == True:
                #listFiles+=[self.scriptsDir/'exe_jquery.js']
                #listOutFiles+=[outputDir/'exe_jquery.js']
                jsFile = (self.scriptsDir/'exe_jquery.js')
                jsFile.copyfile(outputDir/'exe_jquery.js')
        else:
            #listFiles+=[self.scriptsDir/'exe_jquery.js']
            #listOutFiles+=[outputDir/'exe_jquery.js']
            jsFile = (self.scriptsDir/'exe_jquery.js')
            jsFile.copyfile(outputDir/'exe_jquery.js')

        if self.scormType == "commoncartridge" or self.scormType == "scorm2004" or self.scormType == "scorm1.2":
            listFiles=getFilesJSToMinify('scorm', self.scriptsDir)

        exportMinFileJS(listFiles, outputDir)

        if self.scormType == "scorm2004" or self.scormType == "scorm1.2":
            self.scriptsDir.copylist(('SCORM_API_wrapper.js',
                                      'SCOFunctions.js'), outputDir)

        # about SCHEMAS:
        schemasDir = ""
        if self.scormType == "scorm1.2":
            schemasDir = self.schemasDir/"scorm1.2"
            schemasDir.copylist(('imscp_rootv1p1p2.xsd',
                                'imsmd_rootv1p2p1.xsd',
                                'adlcp_rootv1p2.xsd',
                                'lom.xsd',
                                'lomCustom.xsd',
                                'ims_xml.xsd'), outputDir)
        elif self.scormType == "scorm2004":
            schemasDir = self.schemasDir/"scorm2004"
            schemasDir.copylist(('adlcp_v1p3.xsd',
                                'adlnav_v1p3.xsd',
                                'adlseq_v1p3.xsd',
                                'datatypes.dtd',
                                'imscp_v1p1.xsd',
                                'imsssp_v1p0.xsd',
                                'imsss_v1p0.xsd',
                                'imsss_v1p0auxresource.xsd',
                                'imsss_v1p0control.xsd',
                                'imsss_v1p0delivery.xsd',
                                'imsmd_rootv1p2p1.xsd',
                                'imsss_v1p0limit.xsd',
                                'imsss_v1p0objective.xsd',
                                'imsss_v1p0random.xsd',
                                'imsss_v1p0rollup.xsd',
                                'imsss_v1p0seqrule.xsd',
                                'imsss_v1p0util.xsd',
                                'ims_xml.xsd',
                                'lom.xsd',
                                'lomCustom.xsd',
                                'xml.xsd',
                                'XMLSchema.dtd'), outputDir)
            try:
                import shutil, errno
                shutil.copytree(schemasDir/"common", outputDir/"common")
                shutil.copytree(schemasDir/"extend", outputDir/"extend")
                shutil.copytree(schemasDir/"unique", outputDir/"unique")
                shutil.copytree(schemasDir/"vocab", outputDir/"vocab")
            except OSError as exc:
                if exc.errno == errno.ENOTDIR:
                    shutil.copy(schemasDir, outputDir)
                else: raise

        # copy players for media idevices.
        hasFlowplayer     = False
        hasMagnifier      = False
        hasXspfplayer     = False
        hasGallery        = False
        hasFX             = False
        hasSH             = False
        hasGames          = False
        hasElpLink        = False
        hasWikipedia      = False
        isBreak           = False
        hasInstructions   = False
        hasMediaelement   = False
        hasTooltips       = False
        hasABCMusic       = False
        listIdevicesFiles = []

        for page in self.pages:
            if isBreak:
                break
            for idevice in page.node.idevices:
                if (hasFlowplayer and hasMagnifier and hasXspfplayer and hasGallery and hasFX and hasSH and hasGames and hasElpLink and hasWikipedia and hasInstructions and hasMediaelement and hasTooltips and hasABCMusic):
                    isBreak = True
                    break
                if not hasFlowplayer:
                    if 'flowPlayer.swf' in idevice.systemResources:
                        hasFlowplayer = True
                if not hasMagnifier:
                    if 'mojomagnify.js' in idevice.systemResources:
                        hasMagnifier = True
                if not hasXspfplayer:
                    if 'xspf_player.swf' in idevice.systemResources:
                        hasXspfplayer = True
                if not hasGallery:
                    hasGallery = common.ideviceHasGallery(idevice)
                if not hasFX:
                    hasFX = common.ideviceHasFX(idevice)
                if not hasSH:
                    hasSH = common.ideviceHasSH(idevice)
                if not hasGames:
                    hasGames = common.ideviceHasGames(idevice)
                if not hasElpLink:
                    hasElpLink = common.ideviceHasElpLink(idevice,package)
                if not hasWikipedia:
                    if 'WikipediaIdevice' == idevice.klass:
                        hasWikipedia = True
                if not hasInstructions:
                    if 'TrueFalseIdevice' == idevice.klass or 'MultichoiceIdevice' == idevice.klass or 'VerdaderofalsofpdIdevice' == idevice.klass or 'EleccionmultiplefpdIdevice' == idevice.klass:
                        hasInstructions = True
                if not hasMediaelement:
                    hasMediaelement = common.ideviceHasMediaelement(idevice)
                if not hasTooltips:
                    hasTooltips = common.ideviceHasTooltips(idevice)
                if not hasABCMusic:
                    hasABCMusic = common.ideviceHasABCMusic(idevice)
                if hasattr(idevice, "_iDeviceDir"):
                    listIdevicesFiles.append((Path(idevice._iDeviceDir)/'export'))

            common.exportJavaScriptIdevicesFiles(page.node.idevices, outputDir);

        if hasFlowplayer:
            videofile = (self.templatesDir/'flowPlayer.swf')
            videofile.copyfile(outputDir/'flowPlayer.swf')
            controlsfile = (self.templatesDir/'flowplayer.controls.swf')
            controlsfile.copyfile(outputDir/'flowplayer.controls.swf')
        if hasMagnifier:
            videofile = (self.templatesDir/'mojomagnify.js')
            videofile.copyfile(outputDir/'mojomagnify.js')
        if hasXspfplayer:
            videofile = (self.templatesDir/'xspf_player.swf')
            videofile.copyfile(outputDir/'xspf_player.swf')
        if hasGallery:
            exeLightbox = (self.scriptsDir/'exe_lightbox')
            exeLightbox.copyfiles(outputDir)
        if hasFX:
            exeEffects = (self.scriptsDir/'exe_effects')
            exeEffects.copyfiles(outputDir)
        if hasSH:
            exeSH = (self.scriptsDir/'exe_highlighter')
            exeSH.copyfiles(outputDir)
        if hasGames:
            exeGames = (self.scriptsDir/'exe_games')
            exeGames.copyfiles(outputDir)
            # Add game js string to common_i18n
            langGameFile = open(outputDir + '/common_i18n.js', "a")
            langGameFile.write(common.getGamesJavaScriptStrings(False))
            langGameFile.close()
        if hasElpLink or package.get_exportElp():
            # Export the elp file
            currentPackagePath = Path(package.filename)
            currentPackagePath.copyfile(outputDir/package.name+'.elp')
        if hasWikipedia:
            wikipediaCSS = (self.cssDir/'exe_wikipedia.css')
            wikipediaCSS.copyfile(outputDir/'exe_wikipedia.css')
        if hasInstructions:
            common.copyFileIfNotInStyle('panel-amusements.png', self, outputDir)
            common.copyFileIfNotInStyle('stock-stop.png', self, outputDir)
        if hasMediaelement:
            mediaelement = (self.scriptsDir/'mediaelement')
            mediaelement.copyfiles(outputDir)
            if dT != "HTML5":
                jsFile = (self.scriptsDir/'exe_html5.js')
        if hasTooltips:
            exe_tooltips = (self.scriptsDir/'exe_tooltips')
            exe_tooltips.copyfiles(outputDir)
        if hasABCMusic:
            pluginScripts = (self.scriptsDir/'tinymce_4/js/tinymce/plugins/abcmusic/export')
            pluginScripts.copyfiles(outputDir)
        ext = ".html"
        if G.application.config.cutFileName == "1":
            ext = ".htm"

        if self.scormType == "scorm1.2" or self.scormType == "scorm2004":
            if package.license == "license GFDL":
                # include a copy of the GNU Free Documentation Licence
                (self.templatesDir/'fdl' + ext).copyfile(outputDir/'fdl' + ext)

        if hasattr(package, 'scowsinglepage') and package.scowsinglepage:
            page = SinglePage("singlepage_index", 1, package.root)
            page.save(outputDir/"singlepage_index" + ext)
            # Incluide eXe's icon if the Style doesn't have one
            themePath = Path(G.application.config.stylesDir/package.style)
            themeFavicon = themePath.joinpath("favicon.ico")
            if not themeFavicon.exists():
                faviconFile = (self.imagesDir/'favicon.ico')
                faviconFile.copyfile(outputDir/'favicon.ico')
        if hasattr(package, 'scowwebsite') and package.scowwebsite:
            website = WebsiteExport(self.config, self.styleDir, outputDir, "website_")
            website.export(package)
            (self.styleDir/'nav.css').copyfile(outputDir/'nav.css')
            # Incluide eXe's icon if the Style doesn't have one
            themePath = Path(G.application.config.stylesDir/package.style)
            themeFavicon = themePath.joinpath("favicon.ico")
            if not themeFavicon.exists():
                faviconFile = (self.imagesDir/'favicon.ico')
                faviconFile.copyfile(outputDir/'favicon.ico')
        if hasattr(package, 'exportSource') and package.exportSource:
            (G.application.config.webDir/'templates'/'content.xsd').copyfile(outputDir/'content.xsd')
            (outputDir/'content.data').write_bytes(encodeObject(package))
            (outputDir/'contentv3.xml').write_bytes(encodeObjectToXML(package))

        # Zip it up!
        self.filename.safeSave(self.doZip, _('EXPORT FAILED!\nLast succesful export is %s.'), outputDir)
        # Clean up the temporary dir
        outputDir.rmtree()


        return modifiedMetaData

    def doZip(self, fileObj, outputDir):
        """
        Actually does the zipping of the file. Called by 'Path.safeSave'
        """
        # Zip up the scorm package
        zipped = ZipFile(fileObj, "w")
        ## old method: only files could be copied:
        # for scormFile in outputDir.files():
        #    zipped.write(scormFile,
        #                 scormFile.basename().encode('utf8'),
        #                  ZIP_DEFLATED)
        ## but some folders must be included also, so:
        outputlen = len(outputDir) + 1
        for base, dirs, files in os.walk(outputDir):
            for file in files:
                fn = os.path.join(base, file)
                zipped.write(fn, fn[outputlen:].encode('utf8'), ZIP_DEFLATED)
        #
        zipped.close()

    def generatePages(self, node, depth):
        """
        Recursive function for exporting a node.
        'node' is the node that we are making a page for
        'depth' is the number of ancestors that the page has +1 (ie. root is 1)
        """
        for child in node.children:
            pageName = child.titleShort.lower().replace(" ", "_")
            pageName = re.sub(r"\W", "", pageName)
            if not pageName:
                pageName = "__"

            page = ScormPage(pageName, depth, child, scormType=self.scormType, metadataType=self.metadataType)

            self.pages.append(page)
            self.generatePages(child, depth + 1)

    def hasUncutResources(self):
        """
        Check if any of the resources in the exported package has an uncut filename
        """
        for page in self.pages:
            for idevice in page.node.idevices:
                for resource in idevice.userResources:
                    if type(resource) == Resource and len(resource.storageName) > 12:
                        return True
        return False
Beispiel #17
0
class ScormExport(object):
    """
    Exports an eXe package as a SCORM package
    """
    def __init__(self, config, styleDir, filename, scormType, metadataType='DC'):
        """ 
        Initialize
        'styleDir' is the directory from which we will copy our style sheets
        (and some gifs)
        """
        self.config       = config
        self.imagesDir    = config.webDir/"images"
        self.scriptsDir   = config.webDir/"scripts"
        self.cssDir       = config.webDir/"css"
        self.templatesDir = config.webDir/"templates"
        self.schemasDir   = config.webDir/"schemas"
        self.styleDir     = Path(styleDir)
        self.filename     = Path(filename)
        self.pages        = []
        self.hasForum     = False
        self.scormType    = scormType
        self.metadataType = metadataType


    def export(self, package):
        """ 
        Export SCORM package
        """
        # First do the export to a temporary directory
        outputDir = TempDirPath()

        # copy the package's resource files
        package.resourceDir.copyfiles(outputDir)

        # copy the package's resource files, only non existant in outputDir
#        outputDirFiles = outputDir.files()
#        for rfile in package.resourceDir.files():
#            if rfile not in outputDirFiles:
#                rfile.copy(outputDir)

        # copy the package's resource files, only indexed in package.resources
#        for md5 in package.resources.values():
#            for resource in md5:
#                resource.path.copy(outputDir)

        # Export the package content
        self.pages = [ ScormPage("index", 1, package.root,
            scormType=self.scormType, metadataType=self.metadataType) ]

        self.generatePages(package.root, 2)
        uniquifyNames(self.pages)

        for page in self.pages:
            page.save(outputDir)
            if not self.hasForum:
                for idevice in page.node.idevices:
                    if hasattr(idevice, "isForum"):
                        if idevice.forum.lms.lms == "moodle":
                            self.hasForum = True
                            break

        # Create the manifest file
        manifest = Manifest(self.config, outputDir, package, self.pages, self.scormType, self.metadataType)
        manifest.save("imsmanifest.xml")
        if self.hasForum:
            manifest.save("discussionforum.xml")
        
        # Copy the style sheet files to the output dir
        # But not nav.css
        styleFiles  = [self.styleDir/'..'/'base.css']
        styleFiles += [self.styleDir/'..'/'popup_bg.gif']
        styleFiles += [f for f in self.styleDir.files("*.css")
                if f.basename() <> "nav.css"] 
        styleFiles += self.styleDir.files("*.jpg")
        styleFiles += self.styleDir.files("*.gif")
        styleFiles += self.styleDir.files("*.png")
        styleFiles += self.styleDir.files("*.js")
        styleFiles += self.styleDir.files("*.html")
        styleFiles += self.styleDir.files("*.ttf")
        styleFiles += self.styleDir.files("*.eot")
        styleFiles += self.styleDir.files("*.otf")
        styleFiles += self.styleDir.files("*.woff")
        # FIXME for now, only copy files referenced in Common Cartridge
        # this really should apply to all exports, but without a manifest
        # of the files needed by an included stylesheet it is too restrictive
        if self.scormType == "commoncartridge":
            for sf in styleFiles[:]:
                if sf.basename() not in manifest.dependencies:
                    styleFiles.remove(sf)
        self.styleDir.copylist(styleFiles, outputDir)

        # Copy the scripts
        if self.scormType == "commoncartridge":
            self.scriptsDir.copylist(('libot_drag.js',
                                      'common.js'), outputDir)
        if self.scormType == "scorm2004":
            self.scriptsDir.copylist(('AC_RunActiveContent.js',
                                      'SCORM_API_wrapper.js',
                                      'SCOFunctions.js', 
                                      'libot_drag.js',
                                      'common.js'), outputDir)     
        if self.scormType != "commoncartridge" and self.scormType != "scorm2004":
            self.scriptsDir.copylist(('APIWrapper.js', 
                                      'SCOFunctions.js', 
                                      'libot_drag.js',
                                      'common.js'), outputDir)
        schemasDir = ""
        if self.scormType == "scorm1.2":
            schemasDir = self.schemasDir/"scorm1.2"
            schemasDir.copylist(('imscp_rootv1p1p2.xsd',
                                'imsmd_rootv1p2p1.xsd',
                                'adlcp_rootv1p2.xsd',
                                'ims_xml.xsd'), outputDir)
        elif self.scormType == "scorm2004":
            schemasDir = self.schemasDir/"scorm2004"
            schemasDir.copylist(('adlcp_v1p3.xsd',
                                'adlnav_v1p3.xsd',
                                'adlseq_v1p3.xsd', 
                                'datatypes.dtd', 
                                'imscp_v1p1.xsd',
                                'imsssp_v1p0.xsd',
                                'imsss_v1p0.xsd',
                                'imsss_v1p0auxresource.xsd',
                                'imsss_v1p0control.xsd',
                                'imsss_v1p0delivery.xsd',
                                'imsss_v1p0limit.xsd',
                                'imsss_v1p0objective.xsd',
                                'imsss_v1p0random.xsd',
                                'imsss_v1p0rollup.xsd',
                                'imsss_v1p0seqrule.xsd',
                                'imsss_v1p0util.xsd',
                                'ims_xml.xsd',
                                'lom.xsd',
                                'lomCustom.xsd',
                                'xml.xsd',
                                'XMLSchema.dtd'), outputDir)
            try:
                import shutil, errno
                shutil.copytree(schemasDir/"lom", outputDir/"lom")
            except OSError as exc:
                if exc.errno == errno.ENOTDIR:
                    shutil.copy(schemasDir/"lom", outputDir/"lom")
                else: raise

        # copy players for media idevices.                
        hasFlowplayer     = False
        hasMagnifier      = False
        hasXspfplayer     = False
        hasGallery        = False
        isBreak           = False
        
        for page in self.pages:
            if isBreak:
                break
            for idevice in page.node.idevices:
                if (hasFlowplayer and hasMagnifier and hasXspfplayer and hasGallery):
                    isBreak = True
                    break
                if not hasFlowplayer:
                    if 'flowPlayer.swf' in idevice.systemResources:
                        hasFlowplayer = True
                if not hasMagnifier:
                    if 'magnifier.swf' in idevice.systemResources:
                        hasMagnifier = True
                if not hasXspfplayer:
                    if 'xspf_player.swf' in idevice.systemResources:
                        hasXspfplayer = True
                if not hasGallery:
                    if 'GalleryIdevice' == idevice.klass:
                        hasGallery = True
                        
        if hasFlowplayer:
            videofile = (self.templatesDir/'flowPlayer.swf')
            videofile.copyfile(outputDir/'flowPlayer.swf')
            controlsfile = (self.templatesDir/'flowplayer.controls.swf')
            controlsfile.copyfile(outputDir/'flowplayer.controls.swf')
        if hasMagnifier:
            videofile = (self.templatesDir/'magnifier.swf')
            videofile.copyfile(outputDir/'magnifier.swf')
        if hasXspfplayer:
            videofile = (self.templatesDir/'xspf_player.swf')
            videofile.copyfile(outputDir/'xspf_player.swf')
        if hasGallery:
            imageGalleryCSS = (self.cssDir/'exe_lightbox.css')
            imageGalleryCSS.copyfile(outputDir/'exe_lightbox.css') 
            imageGalleryJS = (self.scriptsDir/'exe_lightbox.js')
            imageGalleryJS.copyfile(outputDir/'exe_lightbox.js') 
            self.imagesDir.copylist(('exeGallery_actions.png', 'exeGallery_loading.gif', 'stock-insert-image.png'), outputDir)

        if self.scormType == "scorm1.2" or self.scormType == "scorm2004":
            if package.license == "GNU Free Documentation License":
                # include a copy of the GNU Free Documentation Licence
                (self.templatesDir/'fdl.html').copyfile(outputDir/'fdl.html')
        
        if hasattr(package, 'scowsinglepage') and package.scowsinglepage:
            page = SinglePage("singlepage_index", 1, package.root)
            page.save(outputDir/"singlepage_index.html")
        if hasattr(package, 'scowwebsite') and package.scowwebsite:
            website = WebsiteExport(self.config, self.styleDir, outputDir, "website_")
            website.export(package)
            (self.styleDir/'nav.css').copyfile(outputDir/'nav.css')
        if hasattr(package, 'scowsource') and package.scowsource:
            (G.application.config.webDir/'templates'/'content.xsd').copyfile(outputDir/'content.xsd')
            (outputDir/'content.data').write_bytes(encodeObject(package))
            (outputDir/'contentv2.xml').write_bytes(encodeObjectToXML(package))

        # Zip it up!
        self.filename.safeSave(self.doZip, _('EXPORT FAILED!\nLast succesful export is %s.'), outputDir)
        # Clean up the temporary dir
        outputDir.rmtree()

    def doZip(self, fileObj, outputDir):
        """
        Actually does the zipping of the file. Called by 'Path.safeSave'
        """
        # Zip up the scorm package
        zipped = ZipFile(fileObj, "w")
        ## old method: only files could be copied:
        # for scormFile in outputDir.files():
        #    zipped.write(scormFile,
        #                 scormFile.basename().encode('utf8'),
        #                  ZIP_DEFLATED)
        ## but some folders must be included also, so:
        outputlen = len(outputDir) + 1
        for base, dirs, files in os.walk(outputDir):
            for file in files:
                fn = os.path.join(base, file)
                zipped.write(fn, fn[outputlen:].encode('utf8'), ZIP_DEFLATED)
        #
        zipped.close()

    def generatePages(self, node, depth):
        """
        Recursive function for exporting a node.
        'node' is the node that we are making a page for
        'depth' is the number of ancestors that the page has +1 (ie. root is 1)
        """
        for child in node.children:
            pageName = child.titleShort.lower().replace(" ", "_")
            pageName = re.sub(r"\W", "", pageName)
            if not pageName:
                pageName = "__"

            page = ScormPage(pageName, depth, child, scormType=self.scormType, metadataType=self.metadataType)

            self.pages.append(page)
            self.generatePages(child, depth + 1)
Beispiel #18
0
class IMSExport(object):
    """
    Exports an eXe package as a SCORM package
    """
    def __init__(self, config, styleDir, filename):
        """ Initialize
        'styleDir' is the directory from which we will copy our style sheets
        (and some gifs)
        """
        self.config       = config
        self.imagesDir    = config.webDir/"images"
        self.scriptsDir   = config.webDir/"scripts"
        self.cssDir       = config.webDir/"css"
        self.templatesDir = config.webDir/"templates"
        self.schemasDir   = config.webDir/"schemas/ims"
        self.styleDir     = Path(styleDir)
        self.filename     = Path(filename)
        self.pages        = []


    def export(self, package):
        """ 
        Export SCORM package
        """
        # First do the export to a temporary directory
        outputDir = TempDirPath()

        self.metadataType = package.exportMetadataType


        # Copy the style sheet files to the output dir
        # But not nav.css
        styleFiles = [self.styleDir/'..'/'popup_bg.gif']
        styleFiles += self.styleDir.files("*.css")
        if "nav.css" in styleFiles:
            styleFiles.remove("nav.css")
        styleFiles += self.styleDir.files("*.jpg")
        styleFiles += self.styleDir.files("*.gif")
        styleFiles += self.styleDir.files("*.png")
        styleFiles += self.styleDir.files("*.js")
        styleFiles += self.styleDir.files("*.html")
        styleFiles += self.styleDir.files("*.ttf")
        styleFiles += self.styleDir.files("*.eot")
        styleFiles += self.styleDir.files("*.otf")
        styleFiles += self.styleDir.files("*.woff")
        self.styleDir.copylist(styleFiles, outputDir)

        # copy the package's resource files
        package.resourceDir.copyfiles(outputDir)
        
        listCSSFiles=getFilesCSSToMinify('ims', self.styleDir)
        exportMinFileCSS(listCSSFiles, outputDir)
            
        # Export the package content
        self.pages = [ IMSPage("index", 1, package.root,
           metadataType=self.metadataType) ]

        self.generatePages(package.root, 2)
        uniquifyNames(self.pages)

        for page in self.pages:
            page.save(outputDir)

        # Create the manifest file
        manifest = Manifest(self.config, outputDir, package, self.pages, self.metadataType)
        manifest.save("imsmanifest.xml")
        
        # Copy the scripts
        
        # jQuery
        my_style = G.application.config.styleStore.getStyle(page.node.package.style)
        if my_style.hasValidConfig:
            if my_style.get_jquery() == True:
                jsFile = (self.scriptsDir/'exe_jquery.js')
                jsFile.copyfile(outputDir/'exe_jquery.js')
                
        else:
            jsFile = (self.scriptsDir/'exe_jquery.js')
            jsFile.copyfile(outputDir/'exe_jquery.js')   
                
        dT = common.getExportDocType()
        if dT == "HTML5":
            jsFile = (self.scriptsDir/'exe_html5.js')
            jsFile.copyfile(outputDir/'exe_html5.js')

        listFiles=getFilesJSToMinify('ims', self.scriptsDir)        
        exportMinFileJS(listFiles, outputDir)
        
        self.schemasDir.copylist(('imscp_v1p1.xsd',
                                  'imsmd_v1p2p2.xsd',
                                  'lom.xsd',
                                  'lomCustom.xsd',
                                  'ims_xml.xsd'), outputDir)

        # copy players for media idevices.                
        hasFlowplayer     = False
        hasMagnifier      = False
        hasXspfplayer     = False
        hasGallery        = False
        hasFX             = False
        hasSH             = False
        hasGames          = False
        hasWikipedia      = False
        isBreak           = False
        hasInstructions   = False
        hasMediaelement   = False
        hasTooltips       = False
        
        for page in self.pages:
            if isBreak:
                break
            for idevice in page.node.idevices:
                if (hasFlowplayer and hasMagnifier and hasXspfplayer and hasGallery and hasFX and hasSH and hasGames and hasWikipedia and hasInstructions and hasMediaelement and hasTooltips):
                    isBreak = True
                    break
                if not hasFlowplayer:
                    if 'flowPlayer.swf' in idevice.systemResources:
                        hasFlowplayer = True
                if not hasMagnifier:
                    if 'mojomagnify.js' in idevice.systemResources:
                        hasMagnifier = True
                if not hasXspfplayer:
                    if 'xspf_player.swf' in idevice.systemResources:
                        hasXspfplayer = True
                if not hasGallery:
                    hasGallery = common.ideviceHasGallery(idevice)
                if not hasFX:
                    hasFX = common.ideviceHasFX(idevice)
                if not hasSH:
                    hasSH = common.ideviceHasSH(idevice)
                if not hasGames:
                    hasGames = common.ideviceHasGames(idevice)
                if not hasWikipedia:
                    if 'WikipediaIdevice' == idevice.klass:
                        hasWikipedia = True
                if not hasInstructions:
                    if 'TrueFalseIdevice' == idevice.klass or 'MultichoiceIdevice' == idevice.klass or 'VerdaderofalsofpdIdevice' == idevice.klass or 'EleccionmultiplefpdIdevice' == idevice.klass:
                        hasInstructions = True
                if not hasMediaelement:
                    hasMediaelement = common.ideviceHasMediaelement(idevice)
                if not hasTooltips:
                    hasTooltips = common.ideviceHasTooltips(idevice)

        if hasFlowplayer:
            videofile = (self.templatesDir/'flowPlayer.swf')
            videofile.copyfile(outputDir/'flowPlayer.swf')
            controlsfile = (self.templatesDir/'flowplayer.controls.swf')
            controlsfile.copyfile(outputDir/'flowplayer.controls.swf')
        if hasMagnifier:
            videofile = (self.templatesDir/'mojomagnify.js')
            videofile.copyfile(outputDir/'mojomagnify.js')
        if hasXspfplayer:
            videofile = (self.templatesDir/'xspf_player.swf')
            videofile.copyfile(outputDir/'xspf_player.swf')
        if hasGallery:
            exeLightbox = (self.scriptsDir/'exe_lightbox')
            exeLightbox.copyfiles(outputDir)
        if hasFX:
            exeEffects = (self.scriptsDir/'exe_effects')
            exeEffects.copyfiles(outputDir)
        if hasSH:
            exeSH = (self.scriptsDir/'exe_highlighter')
            exeSH.copyfiles(outputDir)
        if hasGames:
            exeGames = (self.scriptsDir/'exe_games')
            exeGames.copyfiles(outputDir)
        if hasWikipedia:
            wikipediaCSS = (self.cssDir/'exe_wikipedia.css')
            wikipediaCSS.copyfile(outputDir/'exe_wikipedia.css')
        if hasInstructions:
            common.copyFileIfNotInStyle('panel-amusements.png', self, outputDir)
            common.copyFileIfNotInStyle('stock-stop.png', self, outputDir)
        if hasMediaelement:
            mediaelement = (self.scriptsDir/'mediaelement')
            mediaelement.copyfiles(outputDir)
            if dT != "HTML5":
                jsFile = (self.scriptsDir/'exe_html5.js')
                jsFile.copyfile(outputDir/'exe_html5.js')
        if hasTooltips:
            exe_tooltips = (self.scriptsDir/'exe_tooltips')
            exe_tooltips.copyfiles(outputDir)
        if hasattr(package, 'exportSource') and package.exportSource:
            (G.application.config.webDir/'templates'/'content.xsd').copyfile(outputDir/'content.xsd')
            (outputDir/'content.data').write_bytes(encodeObject(package))
            (outputDir/'contentv3.xml').write_bytes(encodeObjectToXML(package))


        if package.license == "license GFDL":
            # include a copy of the GNU Free Documentation Licence
            (self.templatesDir/'fdl.html').copyfile(outputDir/'fdl.html')
        # Zip it up!
        self.filename.safeSave(self.doZip, _('EXPORT FAILED!\nLast succesful export is %s.'), outputDir)
        # Clean up the temporary dir
        outputDir.rmtree()

    def doZip(self, fileObj, outputDir):
        """
        Actually does the zipping of the file. Called by 'Path.safeSave'
        """
        zipped = ZipFile(fileObj, "w")
        for scormFile in outputDir.files():
            zipped.write(scormFile,
                    scormFile.basename().encode('utf8'), ZIP_DEFLATED)
        zipped.close()

    def generatePages(self, node, depth):
        """
        Recursive function for exporting a node.
        'outputDir' is the temporary directory that we are exporting to
        before creating zip file
        """
        for child in node.children:
            pageName = child.titleShort.lower().replace(" ", "_")
            pageName = re.sub(r"\W", "", pageName)
            if not pageName:
                pageName = "__"

            page = IMSPage(pageName, depth, child, metadataType=self.metadataType)

            self.pages.append(page)
            self.generatePages(child, depth + 1)
Beispiel #19
0
class IMSExport(object):
    """
    Exports an eXe package as a SCORM package
    """
    def __init__(self, config, styleDir, filename):
        """ Initialize
        'styleDir' is the directory from which we will copy our style sheets
        (and some gifs)
        """
        self.config       = config
        self.imagesDir    = config.webDir/"images"
        self.scriptsDir   = config.webDir/"scripts"
        self.templatesDir = config.webDir/"templates"
        self.schemasDir   = config.webDir/"schemas/ims"
        self.styleDir     = Path(styleDir)
        self.filename     = Path(filename)
        self.pages        = []
    def export(self, package):
        """ 
        Export SCORM package
        """
        outputDir = TempDirPath()
        styleFiles  = [self.styleDir/'..'/'base.css']
        styleFiles += [self.styleDir/'..'/'popup_bg.gif']
        styleFiles += self.styleDir.files("*.css")
        if "nav.css" in styleFiles:
            styleFiles.remove("nav.css")
        styleFiles += self.styleDir.files("*.jpg")
        styleFiles += self.styleDir.files("*.gif")
        styleFiles += self.styleDir.files("*.png")
        styleFiles += self.styleDir.files("*.js")
        styleFiles += self.styleDir.files("*.html")
        self.styleDir.copylist(styleFiles, outputDir)
        package.resourceDir.copyfiles(outputDir)
        self.pages = [ IMSPage("index", 1, package.root) ]
        self.generatePages(package.root, 2)
        uniquifyNames(self.pages)
        for page in self.pages:
            page.save(outputDir)
        manifest = Manifest(self.config, outputDir, package, self.pages)
        manifest.save()
        self.scriptsDir.copylist(('libot_drag.js',
                                  'common.js'), outputDir)
        self.schemasDir.copylist(('imscp_v1p1.xsd',
                                  'imsmd_v1p2p2.xsd',
                                  'ims_xml.xsd'), outputDir)
        hasFlowplayer     = False
        hasMagnifier      = False
        hasXspfplayer     = False
        isBreak           = False
        for page in self.pages:
            if isBreak:
                break
            for idevice in page.node.idevices:
                if (hasFlowplayer and hasMagnifier and hasXspfplayer):
                    isBreak = True
                    break
                if not hasFlowplayer:
                    if 'flowPlayer.swf' in idevice.systemResources:
                        hasFlowplayer = True
                if not hasMagnifier:
                    if 'magnifier.swf' in idevice.systemResources:
                        hasMagnifier = True
                if not hasXspfplayer:
                    if 'xspf_player.swf' in idevice.systemResources:
                        hasXspfplayer = True
        if hasFlowplayer:
            videofile = (self.templatesDir/'flowPlayer.swf')
            videofile.copyfile(outputDir/'flowPlayer.swf')
        if hasMagnifier:
            videofile = (self.templatesDir/'magnifier.swf')
            videofile.copyfile(outputDir/'magnifier.swf')
        if hasXspfplayer:
            videofile = (self.templatesDir/'xspf_player.swf')
            videofile.copyfile(outputDir/'xspf_player.swf')
        (self.templatesDir/'fdl.html').copyfile(outputDir/'fdl.html')
        self.filename.safeSave(self.doZip, _('EXPORT FAILED!\nLast succesful export is %s.'), outputDir)
        outputDir.rmtree()
    def doZip(self, fileObj, outputDir):
        """
        Actually does the zipping of the file. Called by 'Path.safeSave'
        """
        zipped = ZipFile(fileObj, "w")
        for scormFile in outputDir.files():
            zipped.write(scormFile,
                    scormFile.basename().encode('utf8'), ZIP_DEFLATED)
        zipped.close()
    def generatePages(self, node, depth):
        """
        Recursive function for exporting a node.
        'outputDir' is the temporary directory that we are exporting to
        before creating zip file
        """
        for child in node.children:
            pageName = child.titleShort.lower().replace(" ", "_")
            pageName = re.sub(r"\W", "", pageName)
            if not pageName:
                pageName = "__"
            page = IMSPage(pageName, depth, child)
            self.pages.append(page)
            self.generatePages(child, depth + 1)
Beispiel #20
0
class IMSExport(object):
    """
    Exports an eXe package as a SCORM package
    """
    def __init__(self, config, styleDir, filename):
        """ Initialize
        'styleDir' is the directory from which we will copy our style sheets
        (and some gifs)
        """
        self.config       = config
        self.imagesDir    = config.webDir/"images"
        self.scriptsDir   = config.webDir/"scripts"
        self.cssDir       = config.webDir/"css"
        self.templatesDir = config.webDir/"templates"
        self.schemasDir   = config.webDir/"schemas/ims"
        self.styleDir     = Path(styleDir)
        self.filename     = Path(filename)
        self.pages        = []


    def export(self, package):
        """
        Export SCORM package
        """
        # First do the export to a temporary directory
        outputDir = TempDirPath()

        self.metadataType = package.exportMetadataType


        # Copy the style files to the output dir
        # But not nav.css
        styleFiles = [self.styleDir/'..'/'popup_bg.gif']
        styleFiles += self.styleDir.files("*.*")
        if "nav.css" in styleFiles:
            styleFiles.remove("nav.css")
        self.styleDir.copylist(styleFiles, outputDir)

        # copy the package's resource files
        for resourceFile in package.resourceDir.walkfiles():
            file = package.resourceDir.relpathto(resourceFile)

            if ("/" in file):
                Dir = Path(outputDir/file[:file.rindex("/")])
                if not Dir.exists():
                    Dir.makedirs()

                resourceFile.copy(outputDir/Dir)
            else:
                resourceFile.copy(outputDir)

        listCSSFiles=getFilesCSSToMinify('ims', self.styleDir)
        exportMinFileCSS(listCSSFiles, outputDir)

        # Export the package content
        self.pages = [ IMSPage("index", 1, package.root,
           metadataType=self.metadataType) ]

        self.generatePages(package.root, 2)
        uniquifyNames(self.pages)

        for page in self.pages:
            page.save(outputDir, self.pages)

        # Create the manifest file
        manifest = Manifest(self.config, outputDir, package, self.pages, self.metadataType)
        manifest.save("imsmanifest.xml")

        # Create lang file
        langGameFile = open(outputDir + '/common_i18n.js', "w")
        langGameFile.write(common.getJavaScriptStrings(False))
        langGameFile.close()

        # jQuery
        my_style = G.application.config.styleStore.getStyle(page.node.package.style)
        if my_style.hasValidConfig():
            if my_style.get_jquery() == True:
                jsFile = (self.scriptsDir/'exe_jquery.js')
                jsFile.copyfile(outputDir/'exe_jquery.js')

        else:
            jsFile = (self.scriptsDir/'exe_jquery.js')
            jsFile.copyfile(outputDir/'exe_jquery.js')

        dT = common.getExportDocType()
        if dT == "HTML5":
            jsFile = (self.scriptsDir/'exe_html5.js')
            jsFile.copyfile(outputDir/'exe_html5.js')

        listFiles=getFilesJSToMinify('ims', self.scriptsDir)
        exportMinFileJS(listFiles, outputDir)

        self.schemasDir.copylist(('imscp_v1p1.xsd',
                                  'imsmd_v1p2p2.xsd',
                                  'lom.xsd',
                                  'lomCustom.xsd',
                                  'ims_xml.xsd'), outputDir)

        # copy players for media idevices.
        hasFlowplayer     = False
        hasMagnifier      = False
        hasXspfplayer     = False
        hasGallery        = False
        hasFX             = False
        hasSH             = False
        hasGames          = False
        hasElpLink        = False
        hasWikipedia      = False
        isBreak           = False
        hasInstructions   = False
        hasMediaelement   = False
        hasTooltips       = False
        hasABCMusic       = False
        listIdevicesFiles = []

        for page in self.pages:
            if isBreak:
                break
            for idevice in page.node.idevices:
                if (hasFlowplayer and hasMagnifier and hasXspfplayer and hasGallery and hasFX and hasSH and hasGames and hasElpLink and hasWikipedia and hasInstructions and hasMediaelement and hasTooltips and hasABCMusic):
                    isBreak = True
                    break
                if not hasFlowplayer:
                    if 'flowPlayer.swf' in idevice.systemResources:
                        hasFlowplayer = True
                if not hasMagnifier:
                    if 'mojomagnify.js' in idevice.systemResources:
                        hasMagnifier = True
                if not hasXspfplayer:
                    if 'xspf_player.swf' in idevice.systemResources:
                        hasXspfplayer = True
                if not hasGallery:
                    hasGallery = common.ideviceHasGallery(idevice)
                if not hasFX:
                    hasFX = common.ideviceHasFX(idevice)
                if not hasSH:
                    hasSH = common.ideviceHasSH(idevice)
                if not hasGames:
                    hasGames = common.ideviceHasGames(idevice)
                if not hasElpLink:
                    hasElpLink = common.ideviceHasElpLink(idevice,package)
                if not hasWikipedia:
                    if 'WikipediaIdevice' == idevice.klass:
                        hasWikipedia = True
                if not hasInstructions:
                    if 'TrueFalseIdevice' == idevice.klass or 'MultichoiceIdevice' == idevice.klass or 'VerdaderofalsofpdIdevice' == idevice.klass or 'EleccionmultiplefpdIdevice' == idevice.klass:
                        hasInstructions = True
                if not hasMediaelement:
                    hasMediaelement = common.ideviceHasMediaelement(idevice)
                if not hasTooltips:
                    hasTooltips = common.ideviceHasTooltips(idevice)
                if not hasABCMusic:
                    hasABCMusic = common.ideviceHasABCMusic(idevice)
                if hasattr(idevice, "_iDeviceDir"):
                    listIdevicesFiles.append((idevice.get_jsidevice_dir()/'export'))

            common.exportJavaScriptIdevicesFiles(page.node.idevices, outputDir);

        if hasFlowplayer:
            videofile = (self.templatesDir/'flowPlayer.swf')
            videofile.copyfile(outputDir/'flowPlayer.swf')
            controlsfile = (self.templatesDir/'flowplayer.controls.swf')
            controlsfile.copyfile(outputDir/'flowplayer.controls.swf')
        if hasMagnifier:
            videofile = (self.templatesDir/'mojomagnify.js')
            videofile.copyfile(outputDir/'mojomagnify.js')
        if hasXspfplayer:
            videofile = (self.templatesDir/'xspf_player.swf')
            videofile.copyfile(outputDir/'xspf_player.swf')
        if hasGallery:
            exeLightbox = (self.scriptsDir/'exe_lightbox')
            exeLightbox.copyfiles(outputDir)
        if hasFX:
            exeEffects = (self.scriptsDir/'exe_effects')
            exeEffects.copyfiles(outputDir)
        if hasSH:
            exeSH = (self.scriptsDir/'exe_highlighter')
            exeSH.copyfiles(outputDir)
        if hasGames:
            exeGames = (self.scriptsDir/'exe_games')
            exeGames.copyfiles(outputDir)
            # Add game js string to common_i18n
            langGameFile = open(outputDir + '/common_i18n.js', "a")
            langGameFile.write(common.getGamesJavaScriptStrings(False))
            langGameFile.close()
        if hasElpLink or package.get_exportElp():
            # Export the elp file
            currentPackagePath = Path(package.filename)
            currentPackagePath.copyfile(outputDir/package.name+'.elp')
        if hasWikipedia:
            wikipediaCSS = (self.cssDir/'exe_wikipedia.css')
            wikipediaCSS.copyfile(outputDir/'exe_wikipedia.css')
        if hasInstructions:
            common.copyFileIfNotInStyle('panel-amusements.png', self, outputDir)
            common.copyFileIfNotInStyle('stock-stop.png', self, outputDir)
        if hasMediaelement:
            mediaelement = (self.scriptsDir/'mediaelement')
            mediaelement.copyfiles(outputDir)
            if dT != "HTML5":
                jsFile = (self.scriptsDir/'exe_html5.js')
                jsFile.copyfile(outputDir/'exe_html5.js')
        if hasTooltips:
            exe_tooltips = (self.scriptsDir/'exe_tooltips')
            exe_tooltips.copyfiles(outputDir)
        if hasABCMusic:
            pluginScripts = (self.scriptsDir/'tinymce_4/js/tinymce/plugins/abcmusic/export')
            pluginScripts.copyfiles(outputDir)
        if hasattr(package, 'exportSource') and package.exportSource:
            (G.application.config.webDir/'templates'/'content.xsd').copyfile(outputDir/'content.xsd')
            (outputDir/'content.data').write_bytes(encodeObject(package))
            (outputDir/'contentv3.xml').write_bytes(encodeObjectToXML(package))


        if package.license == "license GFDL":
            # include a copy of the GNU Free Documentation Licence
            (self.templatesDir/'fdl.html').copyfile(outputDir/'fdl.html')

        # Zip it up!
        self.filename.safeSave(self.doZip, _('EXPORT FAILED!\nLast succesful export is %s.'), outputDir)
        # Clean up the temporary dir
        outputDir.rmtree()

    def doZip(self, fileObj, outputDir):
        """
        Actually does the zipping of the file. Called by 'Path.safeSave'
        """
        zipped = ZipFile(fileObj, "w")
        for scormFile in outputDir.walkfiles():
            zipped.write(scormFile,
                    outputDir.relpathto(scormFile), ZIP_DEFLATED)
        zipped.close()

    def generatePages(self, node, depth):
        """
        Recursive function for exporting a node.
        'outputDir' is the temporary directory that we are exporting to
        before creating zip file
        """
        for child in node.children:
            pageName = child.titleShort.lower().replace(" ", "_")
            pageName = re.sub(r"\W", "", pageName)
            if G.application.config.cutFileName == "1":
                pageName = pageName[0:8]
            if not pageName:
                pageName = "__"

            page = IMSPage(pageName, depth, child, metadataType=self.metadataType)

            self.pages.append(page)
            self.generatePages(child, depth + 1)

    def hasUncutResources(self):
        """
        Check if any of the resources in the exported package has an uncut filename
        """
        for page in self.pages:
            for idevice in page.node.idevices:
                for resource in idevice.userResources:
                    if type(resource) == Resource and len(resource.storageName) > 12:
                        return True
        return False
Beispiel #21
0
class ScormExport(object):
    """
    Exports an eXe package as a SCORM package
    """
    def __init__(self, config, styleDir, filename, scormType):
        """
        Initialize
        'styleDir' is the directory from which we will copy our style sheets
        (and some gifs)
        """
        self.config = config
        self.imagesDir = config.webDir / "images"
        self.scriptsDir = config.webDir / "scripts"
        self.cssDir = config.webDir / "css"
        self.templatesDir = config.webDir / "templates"
        self.schemasDir = config.webDir / "schemas"
        self.styleDir = Path(styleDir)
        self.filename = Path(filename)
        self.pages = []
        self.hasForum = False
        self.scormType = scormType
        self.styleSecureMode = config.styleSecureMode

    def export(self, package):
        """
        Export SCORM package
        """
        # First do the export to a temporary directory
        outputDir = TempDirPath()

        self.metadataType = package.exportMetadataType

        # copy the package's resource files
        for resourceFile in package.resourceDir.walkfiles():
            file = package.resourceDir.relpathto(resourceFile)

            if ("/" in file):
                Dir = Path(outputDir / file[:file.rindex("/")])

                if not Dir.exists():
                    Dir.makedirs()

                resourceFile.copy(outputDir / Dir)
            else:
                resourceFile.copy(outputDir)

        # copy the package's resource files, only non existant in outputDir
#        outputDirFiles = outputDir.files()
#        for rfile in package.resourceDir.files():
#            if rfile not in outputDirFiles:
#                rfile.copy(outputDir)

# copy the package's resource files, only indexed in package.resources
#        for md5 in package.resources.values():
#            for resource in md5:
#                resource.path.copy(outputDir)

# Export the package content
# Import the Scorm Page class , if the secure mode is off.  If the style has it's own page class
# use that, else use the default one.
        if self.styleSecureMode == "0":
            if (self.styleDir / "scormpage.py").exists():
                global ScormPage
                module = imp.load_source("ScormPage",
                                         self.styleDir / "scormpage.py")
                ScormPage = module.ScormPage

        self.pages = [
            ScormPage("index",
                      1,
                      package.root,
                      scormType=self.scormType,
                      metadataType=self.metadataType)
        ]

        self.generatePages(package.root, 2)
        uniquifyNames(self.pages)

        for page in self.pages:
            page.save(outputDir, self.pages)
            if not self.hasForum:
                for idevice in page.node.idevices:
                    if hasattr(idevice, "isForum"):
                        if idevice.forum.lms.lms == "moodle":
                            self.hasForum = True
                            break

        # Create the manifest file
        manifest = Manifest(self.config, outputDir, package, self.pages,
                            self.scormType, self.metadataType)
        modifiedMetaData = manifest.save("imsmanifest.xml")

        # Create lang file
        langFile = open(outputDir + '/common_i18n.js', "w")
        langFile.write(common.getJavaScriptStrings(False))
        langFile.close()

        if self.hasForum:
            manifest.save("discussionforum.xml")

        # Copy the style files to the output dir

        styleFiles = [self.styleDir / '..' / 'popup_bg.gif']
        # And with all the files of the style we avoid problems:
        styleFiles += self.styleDir.files("*.*")
        if self.scormType == "commoncartridge":
            for sf in styleFiles[:]:
                if sf.basename() not in manifest.dependencies:
                    styleFiles.remove(sf)
        self.styleDir.copylist(styleFiles, outputDir)

        listCSSFiles = getFilesCSSToMinify('scorm', self.styleDir)
        exportMinFileCSS(listCSSFiles, outputDir)

        # Copy the scripts

        dT = common.getExportDocType()
        if dT == "HTML5":
            #listFiles+=[self.scriptsDir/'exe_html5.js']
            #listOutFiles+=[outputDir/'exe_html5.js']
            jsFile = (self.scriptsDir / 'exe_html5.js')
            jsFile.copyfile(outputDir / 'exe_html5.js')

        # jQuery
        my_style = G.application.config.styleStore.getStyle(
            page.node.package.style)
        if my_style.hasValidConfig():
            if my_style.get_jquery() == True:
                #listFiles+=[self.scriptsDir/'exe_jquery.js']
                #listOutFiles+=[outputDir/'exe_jquery.js']
                jsFile = (self.scriptsDir / 'exe_jquery.js')
                jsFile.copyfile(outputDir / 'exe_jquery.js')
        else:
            #listFiles+=[self.scriptsDir/'exe_jquery.js']
            #listOutFiles+=[outputDir/'exe_jquery.js']
            jsFile = (self.scriptsDir / 'exe_jquery.js')
            jsFile.copyfile(outputDir / 'exe_jquery.js')

        if self.scormType == "commoncartridge" or self.scormType == "scorm2004" or self.scormType == "scorm1.2":
            listFiles = getFilesJSToMinify('scorm', self.scriptsDir)

        exportMinFileJS(listFiles, outputDir)

        if self.scormType == "scorm2004" or self.scormType == "scorm1.2":
            self.scriptsDir.copylist(
                ('SCORM_API_wrapper.js', 'SCOFunctions.js'), outputDir)

        # about SCHEMAS:
        schemasDir = ""
        if self.scormType == "scorm1.2":
            schemasDir = self.schemasDir / "scorm1.2"
            schemasDir.copylist(('imscp_rootv1p1p2.xsd',
                                 'imsmd_rootv1p2p1.xsd', 'adlcp_rootv1p2.xsd',
                                 'lom.xsd', 'lomCustom.xsd', 'ims_xml.xsd'),
                                outputDir)
        elif self.scormType == "scorm2004":
            schemasDir = self.schemasDir / "scorm2004"
            schemasDir.copylist(
                ('adlcp_v1p3.xsd', 'adlnav_v1p3.xsd', 'adlseq_v1p3.xsd',
                 'datatypes.dtd', 'imscp_v1p1.xsd', 'imsssp_v1p0.xsd',
                 'imsss_v1p0.xsd', 'imsss_v1p0auxresource.xsd',
                 'imsss_v1p0control.xsd', 'imsss_v1p0delivery.xsd',
                 'imsmd_rootv1p2p1.xsd', 'imsss_v1p0limit.xsd',
                 'imsss_v1p0objective.xsd', 'imsss_v1p0random.xsd',
                 'imsss_v1p0rollup.xsd', 'imsss_v1p0seqrule.xsd',
                 'imsss_v1p0util.xsd', 'ims_xml.xsd', 'lom.xsd',
                 'lomCustom.xsd', 'xml.xsd', 'XMLSchema.dtd'), outputDir)
            try:
                import shutil, errno
                shutil.copytree(schemasDir / "common", outputDir / "common")
                shutil.copytree(schemasDir / "extend", outputDir / "extend")
                shutil.copytree(schemasDir / "unique", outputDir / "unique")
                shutil.copytree(schemasDir / "vocab", outputDir / "vocab")
            except OSError as exc:
                if exc.errno == errno.ENOTDIR:
                    shutil.copy(schemasDir, outputDir)
                else:
                    raise

        # copy players for media idevices.
        hasFlowplayer = False
        hasMagnifier = False
        hasXspfplayer = False
        hasGallery = False
        hasFX = False
        hasSH = False
        hasGames = False
        hasElpLink = False
        hasWikipedia = False
        isBreak = False
        hasInstructions = False
        hasMediaelement = False
        hasTooltips = False
        hasABCMusic = False
        listIdevicesFiles = []

        for page in self.pages:
            if isBreak:
                break
            for idevice in page.node.idevices:
                if (hasFlowplayer and hasMagnifier and hasXspfplayer
                        and hasGallery and hasFX and hasSH and hasGames
                        and hasElpLink and hasWikipedia and hasInstructions
                        and hasMediaelement and hasTooltips and hasABCMusic):
                    isBreak = True
                    break
                if not hasFlowplayer:
                    if 'flowPlayer.swf' in idevice.systemResources:
                        hasFlowplayer = True
                if not hasMagnifier:
                    if 'mojomagnify.js' in idevice.systemResources:
                        hasMagnifier = True
                if not hasXspfplayer:
                    if 'xspf_player.swf' in idevice.systemResources:
                        hasXspfplayer = True
                if not hasGallery:
                    hasGallery = common.ideviceHasGallery(idevice)
                if not hasFX:
                    hasFX = common.ideviceHasFX(idevice)
                if not hasSH:
                    hasSH = common.ideviceHasSH(idevice)
                if not hasGames:
                    hasGames = common.ideviceHasGames(idevice)
                if not hasElpLink:
                    hasElpLink = common.ideviceHasElpLink(idevice, package)
                if not hasWikipedia:
                    if 'WikipediaIdevice' == idevice.klass:
                        hasWikipedia = True
                if not hasInstructions:
                    if 'TrueFalseIdevice' == idevice.klass or 'MultichoiceIdevice' == idevice.klass or 'VerdaderofalsofpdIdevice' == idevice.klass or 'EleccionmultiplefpdIdevice' == idevice.klass:
                        hasInstructions = True
                if not hasMediaelement:
                    hasMediaelement = common.ideviceHasMediaelement(idevice)
                if not hasTooltips:
                    hasTooltips = common.ideviceHasTooltips(idevice)
                if not hasABCMusic:
                    hasABCMusic = common.ideviceHasABCMusic(idevice)
                if hasattr(idevice, "_iDeviceDir"):
                    listIdevicesFiles.append(
                        (idevice.get_jsidevice_dir() / 'export'))

            common.exportJavaScriptIdevicesFiles(page.node.idevices, outputDir)

        if hasFlowplayer:
            videofile = (self.templatesDir / 'flowPlayer.swf')
            videofile.copyfile(outputDir / 'flowPlayer.swf')
            controlsfile = (self.templatesDir / 'flowplayer.controls.swf')
            controlsfile.copyfile(outputDir / 'flowplayer.controls.swf')
        if hasMagnifier:
            videofile = (self.templatesDir / 'mojomagnify.js')
            videofile.copyfile(outputDir / 'mojomagnify.js')
        if hasXspfplayer:
            videofile = (self.templatesDir / 'xspf_player.swf')
            videofile.copyfile(outputDir / 'xspf_player.swf')
        if hasGallery:
            exeLightbox = (self.scriptsDir / 'exe_lightbox')
            exeLightbox.copyfiles(outputDir)
        if hasFX:
            exeEffects = (self.scriptsDir / 'exe_effects')
            exeEffects.copyfiles(outputDir)
        if hasSH:
            exeSH = (self.scriptsDir / 'exe_highlighter')
            exeSH.copyfiles(outputDir)
        if hasGames:
            exeGames = (self.scriptsDir / 'exe_games')
            exeGames.copyfiles(outputDir)
            # Add game js string to common_i18n
            langGameFile = open(outputDir + '/common_i18n.js', "a")
            langGameFile.write(common.getGamesJavaScriptStrings(False))
            langGameFile.close()
        if hasElpLink or package.get_exportElp():
            # Export the elp file
            currentPackagePath = Path(package.filename)
            currentPackagePath.copyfile(outputDir / package.name + '.elp')
        if hasWikipedia:
            wikipediaCSS = (self.cssDir / 'exe_wikipedia.css')
            wikipediaCSS.copyfile(outputDir / 'exe_wikipedia.css')
        if hasInstructions:
            common.copyFileIfNotInStyle('panel-amusements.png', self,
                                        outputDir)
            common.copyFileIfNotInStyle('stock-stop.png', self, outputDir)
        if hasMediaelement:
            mediaelement = (self.scriptsDir / 'mediaelement')
            mediaelement.copyfiles(outputDir)
            if dT != "HTML5":
                jsFile = (self.scriptsDir / 'exe_html5.js')
        if hasTooltips:
            exe_tooltips = (self.scriptsDir / 'exe_tooltips')
            exe_tooltips.copyfiles(outputDir)
        if hasABCMusic:
            pluginScripts = (self.scriptsDir /
                             'tinymce_4/js/tinymce/plugins/abcmusic/export')
            pluginScripts.copyfiles(outputDir)
        ext = ".html"
        if G.application.config.cutFileName == "1":
            ext = ".htm"

        if self.scormType == "scorm1.2" or self.scormType == "scorm2004":
            if package.license == "license GFDL":
                # include a copy of the GNU Free Documentation Licence
                (self.templatesDir / 'fdl' + ext).copyfile(outputDir / 'fdl' +
                                                           ext)

        if hasattr(package, 'scowsinglepage') and package.scowsinglepage:
            page = SinglePage("singlepage_index", 1, package.root)
            page.save(outputDir / "singlepage_index" + ext)
            # Incluide eXe's icon if the Style doesn't have one
            themePath = Path(G.application.config.stylesDir / package.style)
            themeFavicon = themePath.joinpath("favicon.ico")
            if not themeFavicon.exists():
                faviconFile = (self.imagesDir / 'favicon.ico')
                faviconFile.copyfile(outputDir / 'favicon.ico')
        if hasattr(package, 'scowwebsite') and package.scowwebsite:
            website = WebsiteExport(self.config, self.styleDir, outputDir,
                                    "website_")
            website.export(package)
            (self.styleDir / 'nav.css').copyfile(outputDir / 'nav.css')
            # Incluide eXe's icon if the Style doesn't have one
            themePath = Path(G.application.config.stylesDir / package.style)
            themeFavicon = themePath.joinpath("favicon.ico")
            if not themeFavicon.exists():
                faviconFile = (self.imagesDir / 'favicon.ico')
                faviconFile.copyfile(outputDir / 'favicon.ico')
        if hasattr(package, 'exportSource') and package.exportSource:
            (G.application.config.webDir / 'templates' /
             'content.xsd').copyfile(outputDir / 'content.xsd')
            (outputDir / 'content.data').write_bytes(encodeObject(package))
            (outputDir / 'contentv3.xml').write_bytes(
                encodeObjectToXML(package))

        # Zip it up!
        self.filename.safeSave(
            self.doZip, _('EXPORT FAILED!\nLast succesful export is %s.'),
            outputDir)
        # Clean up the temporary dir
        outputDir.rmtree()

        return modifiedMetaData

    def doZip(self, fileObj, outputDir):
        """
        Actually does the zipping of the file. Called by 'Path.safeSave'
        """
        # Zip up the scorm package
        zipped = ZipFile(fileObj, "w")
        ## old method: only files could be copied:
        # for scormFile in outputDir.files():
        #    zipped.write(scormFile,
        #                 scormFile.basename().encode('utf8'),
        #                  ZIP_DEFLATED)
        ## but some folders must be included also, so:
        outputlen = len(outputDir) + 1
        for base, dirs, files in os.walk(outputDir):
            for file in files:
                fn = os.path.join(base, file)
                zipped.write(fn, fn[outputlen:].encode('utf8'), ZIP_DEFLATED)
        #
        zipped.close()

    def generatePages(self, node, depth):
        """
        Recursive function for exporting a node.
        'node' is the node that we are making a page for
        'depth' is the number of ancestors that the page has +1 (ie. root is 1)
        """
        for child in node.children:
            pageName = child.titleShort.lower().replace(" ", "_")
            pageName = re.sub(r"\W", "", pageName)
            if not pageName:
                pageName = "__"

            page = ScormPage(pageName,
                             depth,
                             child,
                             scormType=self.scormType,
                             metadataType=self.metadataType)

            self.pages.append(page)
            self.generatePages(child, depth + 1)

    def hasUncutResources(self):
        """
        Check if any of the resources in the exported package has an uncut filename
        """
        for page in self.pages:
            for idevice in page.node.idevices:
                for resource in idevice.userResources:
                    if type(resource) == Resource and len(
                            resource.storageName) > 12:
                        return True
        return False
Beispiel #22
0
class IMSExport(object):
    """
    Exports an eXe package as a SCORM package
    """
    def __init__(self, config, styleDir, filename):
        """ Initialize
        'styleDir' is the directory from which we will copy our style sheets
        (and some gifs)
        """
        self.config       = config
        self.imagesDir    = config.webDir/"images"
        self.scriptsDir   = config.webDir/"scripts"
        self.cssDir       = config.webDir/"css"
        self.templatesDir = config.webDir/"templates"
        self.schemasDir   = config.webDir/"schemas/ims"
        self.styleDir     = Path(styleDir)
        self.filename     = Path(filename)
        self.pages        = []


    def export(self, package):
        """ 
        Export SCORM package
        """
        # First do the export to a temporary directory
        outputDir = TempDirPath()

        # Copy the style sheet files to the output dir
        # But not nav.css
        styleFiles  = [self.styleDir/'..'/'base.css']
        styleFiles += [self.styleDir/'..'/'popup_bg.gif']
        styleFiles += self.styleDir.files("*.css")
        if "nav.css" in styleFiles:
            styleFiles.remove("nav.css")
        styleFiles += self.styleDir.files("*.jpg")
        styleFiles += self.styleDir.files("*.gif")
        styleFiles += self.styleDir.files("*.png")
        styleFiles += self.styleDir.files("*.js")
        styleFiles += self.styleDir.files("*.html")
        styleFiles += self.styleDir.files("*.ttf")
        styleFiles += self.styleDir.files("*.eot")
        styleFiles += self.styleDir.files("*.otf")
        styleFiles += self.styleDir.files("*.woff")
        self.styleDir.copylist(styleFiles, outputDir)

        # copy the package's resource files
        package.resourceDir.copyfiles(outputDir)
            
        # Export the package content
        self.pages = [ IMSPage("index", 1, package.root) ]

        self.generatePages(package.root, 2)
        uniquifyNames(self.pages)

        for page in self.pages:
            page.save(outputDir)

        # Create the manifest file
        manifest = Manifest(self.config, outputDir, package, self.pages)
        manifest.save()
        
        # Copy the scripts
        self.scriptsDir.copylist(('libot_drag.js',
                                  'common.js'), outputDir)
        
        self.schemasDir.copylist(('imscp_v1p1.xsd',
                                  'imsmd_v1p2p2.xsd',
                                  'ims_xml.xsd'), outputDir)

        # copy players for media idevices.                
        hasFlowplayer     = False
        hasMagnifier      = False
        hasXspfplayer     = False
        hasGallery        = False
        isBreak           = False
        
        for page in self.pages:
            if isBreak:
                break
            for idevice in page.node.idevices:
                if (hasFlowplayer and hasMagnifier and hasXspfplayer and hasGallery):
                    isBreak = True
                    break
                if not hasFlowplayer:
                    if 'flowPlayer.swf' in idevice.systemResources:
                        hasFlowplayer = True
                if not hasMagnifier:
                    if 'magnifier.swf' in idevice.systemResources:
                        hasMagnifier = True
                if not hasXspfplayer:
                    if 'xspf_player.swf' in idevice.systemResources:
                        hasXspfplayer = True
                if not hasGallery:
                    if 'GalleryIdevice' == idevice.klass:
                        hasGallery = True
                        
        if hasFlowplayer:
            videofile = (self.templatesDir/'flowPlayer.swf')
            videofile.copyfile(outputDir/'flowPlayer.swf')
            controlsfile = (self.templatesDir/'flowplayer.controls.swf')
            controlsfile.copyfile(outputDir/'flowplayer.controls.swf')
        if hasMagnifier:
            videofile = (self.templatesDir/'magnifier.swf')
            videofile.copyfile(outputDir/'magnifier.swf')
        if hasXspfplayer:
            videofile = (self.templatesDir/'xspf_player.swf')
            videofile.copyfile(outputDir/'xspf_player.swf')
        if hasGallery:
            imageGalleryCSS = (self.cssDir/'exe_lightbox.css')
            imageGalleryCSS.copyfile(outputDir/'exe_lightbox.css') 
            imageGalleryJS = (self.scriptsDir/'exe_lightbox.js')
            imageGalleryJS.copyfile(outputDir/'exe_lightbox.js') 
            self.imagesDir.copylist(('exeGallery_actions.png', 'exeGallery_loading.gif', 'stock-insert-image.png'), outputDir)

        if package.license == "GNU Free Documentation License":
            # include a copy of the GNU Free Documentation Licence
            (self.templatesDir/'fdl.html').copyfile(outputDir/'fdl.html')
        # Zip it up!
        self.filename.safeSave(self.doZip, _('EXPORT FAILED!\nLast succesful export is %s.'), outputDir)
        # Clean up the temporary dir
        outputDir.rmtree()

    def doZip(self, fileObj, outputDir):
        """
        Actually does the zipping of the file. Called by 'Path.safeSave'
        """
        zipped = ZipFile(fileObj, "w")
        for scormFile in outputDir.files():
            zipped.write(scormFile,
                    scormFile.basename().encode('utf8'), ZIP_DEFLATED)
        zipped.close()

    def generatePages(self, node, depth):
        """
        Recursive function for exporting a node.
        'outputDir' is the temporary directory that we are exporting to
        before creating zip file
        """
        for child in node.children:
            pageName = child.titleShort.lower().replace(" ", "_")
            pageName = re.sub(r"\W", "", pageName)
            if not pageName:
                pageName = "__"

            page = IMSPage(pageName, depth, child)

            self.pages.append(page)
            self.generatePages(child, depth + 1)
Beispiel #23
0
class WebsiteExport(object):
    """
    WebsiteExport will export a package as a website of HTML pages
    """
    def __init__(self, config, styleDir, filename, prefix="", report=False):
        """
        'stylesDir' is the directory where we can copy the stylesheets from
        'outputDir' is the directory that will be [over]written
        with the website
        """
        self.config = config
        self.imagesDir = config.webDir / "images"
        self.scriptsDir = config.webDir / "scripts"
        self.cssDir = config.webDir / "css"
        self.templatesDir = config.webDir / "templates"
        self.stylesDir = Path(styleDir)
        self.filename = Path(filename)
        self.pages = []
        self.prefix = prefix
        self.report = report
        self.styleSecureMode = config.styleSecureMode

    def gDriveNotificationStatus(self, client, mesg):
        client.sendScript(
            "eXe.controller.eXeViewport.prototype.gDriveNotificationStatus('%s');"
            % (mesg),
            filter_func=allSessionClients)

    def gDriveNotificationNotice(self, client, mesg, type):
        client.sendScript(
            "eXe.controller.eXeViewport.prototype.gDriveNotificationNotice('%s', '%s');"
            % (mesg, type),
            filter_func=allSessionClients)

#     def exportGoogleDrive(self, package, client, auth_token, user_agent):
#         """
#         Creates an authorized HTTP conexion, exports the current package as
#         'webSite' to a temporary directory and uploads the exported files to
#         Google Drive
#         """
#         num_total = 0;
#         file_num = 0;
#
#         def finishExport(public_folder, outputDir):
#             self.gDriveNotificationStatus(client, _(u'Deleting temporary directory'))
#             rmtree(outputDir)
#
#             link_url = 'http://googledrive.com/host/%s'%(public_folder['id'])
#             link_text = public_folder['title']
#             self.gDriveNotificationStatus(client, _(u'Package exported to <a href="%s" target="_blank" title="Click to visit exported site">%s</a>') %(link_url,link_text))
#             return public_folder
#
#         def insertFile(public_folder, drive, upload_file, file_num):
#             """
#             Creates the deferred that will upload files to the public folder
#             once it is created
#             """
#             upload_content_d = threads.deferToThread(uploadContent, public_folder, drive, upload_file, file_num)
#             upload_content_d.addCallbacks(uploadContent_onSuccess, uploadContent_onFail)
#
#             return upload_content_d
#
#         def uploadContent(public_folder, drive, upload_file, file_num):
#             """
#             Uploads one file to the given GDrive folder
#             """
#             try :
#                 filepath = os.path.join(self.filename, upload_file)
#                 filetype = mimetypes.guess_type(filepath, False)
#
#                 if filetype[0] is None :
#                     # Hard-coded types for special cases not detected by mimetypes.guess_type()
#                     if upload_file == 'content.data' :
#                         filetype = ('application/octet-stream', None)
#
#
#                 if filetype[0] is not None :
#                     link_url = 'http://googledrive.com/host/%s'%(public_folder['id'])
#                     link_text = public_folder['title']
#                     #self.gDriveNotificationStatus(client, _(u'Package exported to <a href="%s" target="_blank" title="Click to visit exported site">%s</<a>') %(link_url,link_text))
#                     self.gDriveNotificationStatus(client, _(u'Uploading <em>%s</em> to public folder <a href="%s" target="_blank" title="Click to visit exported site">%s</a> (%d/%d)')
#                                                              %(upload_file, link_url, link_text, file_num, num_total))
#                     mimetype = filetype[0]
#                     meta = {
#                       'title': upload_file,
#                       'mimeType': mimetype,
#                       'parents' : [{'id' : public_folder['id']}]
#                     }
#                     media_body = MediaFileUpload(filepath, mimetype, resumable=True)
#                     drive.files().insert(body=meta, media_body=media_body).execute()
#                 else :
#                     self.gDriveNotificationNotice(client, _(u'File <em>%s</em> skipped, unknown filetype (%d/%d)') %(upload_file, file_num, num_total), 'warning')
#             except Exception, e :
#                 log.error(str(e))
#                 self.gDriveNotificationNotice(client, _(u'Failed upload of file %s (%d/%d)') % (upload_file, file_num, num_total), 'error')
#
#             return public_folder
#
#         def uploadContent_onFail(err):
#             log.error(str(err))
#             self.gDriveNotificationNotice(client, _(u'Failed exporting to GoogleDrive'), 'error')
#             return err
#
#         def uploadContent_onSuccess(public_folder):
#             # self.gDriveNotificationStatus(client, _(u'Exported to GoogleDrive: %s') % public_folder['title'])
#             return public_folder
#
#         def publicFolder(drive, folder_name):
#             """
#             Creates a Public Web folder, that can be read as a web site with any
#             web browser, and populates it with the content of the given directory
#             """
#
#             # Create public folder
#             self.gDriveNotificationStatus(client, _(u'Creating public folder to host published web site'))
#             body = {
#                 'title': folder_name,
#                 'mimeType': 'application/vnd.google-apps.folder'
#             }
#             public_folder = drive.files().insert(body=body).execute()
#
#             permission = {
#                 'value': '',
#                 'type': 'anyone',
#                 'role': 'reader'
#             }
#             drive.permissions().insert(fileId=public_folder['id'], body=permission).execute()
#
#             return public_folder
#
#         def publicFolder_onFail(err):
#             log.error(str(err))
#             self.gDriveNotificationNotice(client, _(u'Failed exporting to GoogleDrive'), 'error')
#             return err
#
#         def publicFolder_onSuccess(public_folder):
#             self.gDriveNotificationStatus(client, _(u'Created public folder to host published web site: %s') % (public_folder['title']))
#             return public_folder
#
#         try:
#             # Creates a new temporary dir to export the package to, it will be deleted
#             # once the export process is finished
#             self.filename = Path(mkdtemp())
#             self.gDriveNotificationStatus(client, _(u'Exporting package as web site in: %s') % (jquote(self.filename)))
#             outputDir = self.export(package)
#
#             self.gDriveNotificationStatus(client, _(u'Starting authorized connection to Google Drive API'))
#             credentials = AccessTokenCredentials(auth_token, user_agent)
#             ca_certs = None
#             if hasattr(sys, 'frozen'):
#                 ca_certs = 'cacerts.txt'
#             http = httplib2.Http(ca_certs=ca_certs)
#             http = credentials.authorize(http)
#             drive_service = build('drive', 'v2', http=http)
#
#             publicFolder_d = threads.deferToThread(publicFolder, drive_service, package.name)
#             publicFolder_d.addCallbacks(publicFolder_onSuccess, publicFolder_onFail)
#
#             # Loop through files in exportDir, each upload will be called from
#             # a chained callback function. These callbacks will return a
#             # deferred so the file N upload will start when file N-1 has
#             # successfully called its own callback
#             # (Deferred chain, see: http://krondo.com/?p=2159#attachment_2196)
#             for upload_file in os.listdir(outputDir):
#                 file_num = file_num + 1
#                 publicFolder_d.addCallback(insertFile, drive_service, upload_file, file_num)
#
#             num_total = file_num
#             publicFolder_d.addCallback(finishExport, outputDir)
#
#             # TODO clean exportDir after uploading has finished
#
#         except Exception, e:
#             log.error(str(e))
#             self.gDriveNotificationNotice(client, _('EXPORT FAILED!'), 'error')
#             raise
#         #client.alert(_(u'Exported to %s') % filename)

    def exportZip(self, package):
        """ 
        Export web site
        Cleans up the previous packages pages and performs the export
        """

        outputDir = TempDirPath()

        # Import the Website Page class , if the secure mode is off.  If the style has it's own page class
        # use that, else use the default one.
        if self.styleSecureMode == "0":
            if (self.stylesDir / "websitepage.py").exists():
                global WebsitePage
                module = imp.load_source("websitepage",
                                         self.stylesDir / "websitepage.py")
                WebsitePage = module.WebsitePage

        self.pages = [WebsitePage("index", 0, package.root)]
        self.generatePages(package.root, 1)
        uniquifyNames(self.pages)

        prevPage = None
        thisPage = self.pages[0]

        for nextPage in self.pages[1:]:
            thisPage.save(outputDir, prevPage, nextPage, self.pages)
            prevPage = thisPage
            thisPage = nextPage

        thisPage.save(outputDir, prevPage, None, self.pages)
        self.copyFiles(package, outputDir)
        # Zip up the website package
        self.filename.safeSave(
            self.doZip, _('EXPORT FAILED!\nLast succesful export is %s.'),
            outputDir)
        # Clean up the temporary dir
        outputDir.rmtree()

    def doZip(self, fileObj, outputDir):
        """
        Actually saves the zip data. Called by 'Path.safeSave'
        """
        zipped = ZipFile(fileObj, "w")
        for scormFile in outputDir.files():
            zipped.write(scormFile,
                         scormFile.basename().encode('utf8'), ZIP_DEFLATED)
        zipped.close()

    def appendPageReport(self, page, package):
        if not page.node.idevices:
            self.report += u'"%s","%s",%d,"%s",,,,,,\n' % (
                package.filename, page.node.title, page.depth,
                page.name + '.html')
        for idevice in page.node.idevices:
            if not idevice.userResources:
                self.report += u'"%s","%s",%d,"%s","%s","%s",,,,\n' % (
                    package.filename, page.node.title, page.depth,
                    page.name + '.html', idevice.klass, idevice.title)
            for resource in idevice.userResources:
                if type(resource) == Resource:
                    self.report += u'"%s","%s",%d,"%s","%s","%s","%s","%s","%s","%s"\n' % (
                        package.filename, page.node.title, page.depth,
                        page.name + '.html', idevice.klass, idevice.title,
                        resource.storageName, resource.userName, resource.path,
                        resource.checksum)
                else:
                    self.report += u'"%s",%d,"%s","%s","%s","%s",,,\n' % (
                        package.filename, page.node.title, page.depth,
                        page.name + '.html', idevice.klass, idevice.title,
                        resource)

    def export(self, package):
        """ 
        Export web site
        Cleans up the previous packages pages and performs the export
        """
        if not self.report:
            outputDir = self.filename
            if not outputDir.exists():
                outputDir.mkdir()

        # Import the Website Page class.  If the style has it's own page class
        # use that, else use the default one.
        if (self.stylesDir / "websitepage.py").exists():
            global WebsitePage
            module = imp.load_source("websitepage",
                                     self.stylesDir / "websitepage.py")
            WebsitePage = module.WebsitePage

        self.pages = [WebsitePage(self.prefix + "index", 0, package.root)]
        self.generatePages(package.root, 1)
        uniquifyNames(self.pages)

        prevPage = None
        thisPage = self.pages[0]
        if self.report:
            self.report = u'"%s","%s","%s","%s","%s","%s","%s","%s","%s","%s"\n' % (
                'File', 'Page Name', 'Level', 'Page File Name', 'Idevice Type',
                'Idevice Title', 'Resource File Name', 'Resource User Name',
                'Resource Path', 'Resource Checksum')
            self.appendPageReport(thisPage, package)

        for nextPage in self.pages[1:]:
            if self.report:
                self.appendPageReport(nextPage, package)
            else:
                thisPage.save(outputDir, prevPage, nextPage, self.pages)
            prevPage = thisPage
            thisPage = nextPage

        if not self.report:
            thisPage.save(outputDir, prevPage, None, self.pages)

            if self.prefix == "":
                self.copyFiles(package, outputDir)

            return outputDir

        else:
            self.filename.write_text(self.report, 'utf-8')

    def copyFiles(self, package, outputDir):
        """
        Copy all the files used by the website.
        """

        if os.path.isdir(self.stylesDir):
            # Copy the style sheet files to the output dir
            styleFiles = [self.stylesDir / '..' / 'base.css']
            styleFiles += [self.stylesDir / '..' / 'popup_bg.gif']
            styleFiles += self.stylesDir.files("*.css")
            styleFiles += self.stylesDir.files("*.jpg")
            styleFiles += self.stylesDir.files("*.gif")
            styleFiles += self.stylesDir.files("*.png")
            styleFiles += self.stylesDir.files("*.js")
            styleFiles += self.stylesDir.files("*.html")
            styleFiles += self.stylesDir.files("*.ico")
            styleFiles += self.stylesDir.files("*.ttf")
            styleFiles += self.stylesDir.files("*.eot")
            styleFiles += self.stylesDir.files("*.otf")
            styleFiles += self.stylesDir.files("*.woff")
            self.stylesDir.copylist(styleFiles, outputDir)

        # copy the package's resource files
        package.resourceDir.copyfiles(outputDir)

        # copy script files.
        my_style = G.application.config.styleStore.getStyle(package.style)
        # jQuery
        if my_style.hasValidConfig:
            if my_style.get_jquery() == True:
                jsFile = (self.scriptsDir / 'exe_jquery.js')
                jsFile.copyfile(outputDir / 'exe_jquery.js')
        else:
            jsFile = (self.scriptsDir / 'exe_jquery.js')
            jsFile.copyfile(outputDir / 'exe_jquery.js')

        jsFile = (self.scriptsDir / 'common.js')
        jsFile.copyfile(outputDir / 'common.js')
        #dT = common.getExportDocType()
        dT = common.getExportDocType()
        if dT == "HTML5":
            jsFile = (self.scriptsDir / 'exe_html5.js')
            jsFile.copyfile(outputDir / 'exe_html5.js')

        # Incluide eXe's icon if the Style doesn't have one
        themePath = Path(G.application.config.stylesDir / package.style)
        themeFavicon = themePath.joinpath("favicon.ico")
        if not themeFavicon.exists():
            faviconFile = (self.imagesDir / 'favicon.ico')
            faviconFile.copyfile(outputDir / 'favicon.ico')

        # copy players for media idevices.
        hasFlowplayer = False
        hasMagnifier = False
        hasXspfplayer = False
        hasGallery = False
        hasFX = False
        hasGames = False
        hasWikipedia = False
        isBreak = False
        hasInstructions = False
        hasMediaelement = False
        hasTooltips = False

        for page in self.pages:
            if isBreak:
                break
            for idevice in page.node.idevices:
                if (hasFlowplayer and hasMagnifier and hasXspfplayer
                        and hasGallery and hasFX and hasGames and hasWikipedia
                        and hasInstructions and hasMediaelement
                        and hasTooltips):
                    isBreak = True
                    break
                if not hasFlowplayer:
                    if 'flowPlayer.swf' in idevice.systemResources:
                        hasFlowplayer = True
                if not hasMagnifier:
                    if 'mojomagnify.js' in idevice.systemResources:
                        hasMagnifier = True
                if not hasXspfplayer:
                    if 'xspf_player.swf' in idevice.systemResources:
                        hasXspfplayer = True
                if not hasGallery:
                    hasGallery = common.ideviceHasGallery(idevice)
                if not hasFX:
                    hasFX = common.ideviceHasFX(idevice)
                if not hasGames:
                    hasGames = common.ideviceHasGames(idevice)
                if not hasWikipedia:
                    if 'WikipediaIdevice' == idevice.klass:
                        hasWikipedia = True
                if not hasInstructions:
                    if 'TrueFalseIdevice' == idevice.klass or 'MultichoiceIdevice' == idevice.klass or 'VerdaderofalsofpdIdevice' == idevice.klass or 'EleccionmultiplefpdIdevice' == idevice.klass:
                        hasInstructions = True
                if not hasMediaelement:
                    hasMediaelement = common.ideviceHasMediaelement(idevice)
                if not hasTooltips:
                    hasTooltips = common.ideviceHasTooltips(idevice)

        if hasFlowplayer:
            videofile = (self.templatesDir / 'flowPlayer.swf')
            videofile.copyfile(outputDir / 'flowPlayer.swf')
            controlsfile = (self.templatesDir / 'flowplayer.controls.swf')
            controlsfile.copyfile(outputDir / 'flowplayer.controls.swf')
        if hasMagnifier:
            videofile = (self.templatesDir / 'mojomagnify.js')
            videofile.copyfile(outputDir / 'mojomagnify.js')
        if hasXspfplayer:
            videofile = (self.templatesDir / 'xspf_player.swf')
            videofile.copyfile(outputDir / 'xspf_player.swf')
        if hasGallery:
            exeLightbox = (self.scriptsDir / 'exe_lightbox')
            exeLightbox.copyfiles(outputDir)
        if hasFX:
            exeEffects = (self.scriptsDir / 'exe_effects')
            exeEffects.copyfiles(outputDir)
        if hasGames:
            exeGames = (self.scriptsDir / 'exe_games')
            exeGames.copyfiles(outputDir)
        if hasWikipedia:
            wikipediaCSS = (self.cssDir / 'exe_wikipedia.css')
            wikipediaCSS.copyfile(outputDir / 'exe_wikipedia.css')
        if hasInstructions:
            common.copyFileIfNotInStyle('panel-amusements.png', self,
                                        outputDir)
            common.copyFileIfNotInStyle('stock-stop.png', self, outputDir)
        if hasMediaelement:
            mediaelement = (self.scriptsDir / 'mediaelement')
            mediaelement.copyfiles(outputDir)
            dT = common.getExportDocType()
            if dT != "HTML5":
                jsFile = (self.scriptsDir / 'exe_html5.js')
                jsFile.copyfile(outputDir / 'exe_html5.js')
        if hasTooltips:
            exe_tooltips = (self.scriptsDir / 'exe_tooltips')
            exe_tooltips.copyfiles(outputDir)

        if hasattr(package, 'exportSource') and package.exportSource:
            (G.application.config.webDir / 'templates' /
             'content.xsd').copyfile(outputDir / 'content.xsd')
            (outputDir / 'content.data').write_bytes(encodeObject(package))
            (outputDir / 'contentv3.xml').write_bytes(
                encodeObjectToXML(package))

        if package.license == "license GFDL":
            # include a copy of the GNU Free Documentation Licence
            (self.templatesDir / 'fdl.html').copyfile(outputDir / 'fdl.html')

    def generatePages(self, node, depth):
        """
        Recursively generate pages and store in pages member variable
        for retrieving later
        """
        for child in node.children:
            # assure lower pagename, without whitespaces or alphanumeric characters:
            pageName = child.titleShort.lower().replace(" ", "_")
            pageName = re.sub(r"\W", "", pageName)
            if not pageName:
                pageName = "__"

            self.pages.append(WebsitePage(self.prefix + pageName, depth,
                                          child))
            self.generatePages(child, depth + 1)
Beispiel #24
0
class Epub3Export(object):
    """
    Exports an eXe package as a epub 3 package
    The 'Hello World' of a epub 3 publication might contain files:
        mimetype
        META-INF/container.xml
        Content/HelloWorld.opf
        Content/HelloWorld.xhtml
    """

    def __init__(self, config, styleDir, filename):
        """
        Initialize
        'styleDir' is the directory from which we will copy our style sheets
        (and some gifs)
        """
        self.config = config
        self.imagesDir = config.webDir / "images"
        self.scriptsDir = config.webDir / "scripts"
        self.cssDir = config.webDir / "css"
        self.templatesDir = config.webDir / "templates"
        self.schemasDir = config.webDir / "schemas/ims"
        self.styleDir = Path(styleDir)
        self.filename = Path(filename)
        self.pages = []

    def export(self, package):
        """
        Export epub 3 package
        """
        # First do the export to a temporary directory
        outputDir = TempDirPath()

        """
        fileDir = outputDir/"META-INF"
        fileDir.mkdir()
        fileDir = outputDir/"Content"
        fileDir.mkdir()
        """

        metainfPages = Path(outputDir.abspath() + "/META-INF")
        # metainfPages = outputDir/'META-INF'
        metainfPages.mkdir()
        contentPages = Path(outputDir.abspath() + "/EPUB")
        # contentPages = outputDir/'Content'
        contentPages.mkdir()
        # print contentPages.abspath()
        # print outputDir.abspath()

        # Export the package content
        self.pages = [Epub3Cover("cover", 1, package.root)]

        self.generatePages(package.root, 2)
        uniquifyNames(self.pages)

        cover = None
        for page in self.pages:
            page.save(contentPages)
            if hasattr(page, "cover"):
                cover = page.cover

        # Create mimetype file
        mimetypeFile = open(outputDir.abspath() + "/mimetype", "w")
        mimetypeFile.write("application/epub+zip")
        mimetypeFile.close()

        # Copy the style sheet files to the output dir
        # But not nav.css
        styleFiles = [self.styleDir / ".." / "popup_bg.gif"]
        styleFiles += [f for f in self.styleDir.files("*.css") if f.basename() != "nav.css"]
        styleFiles += self.styleDir.files("*.jpg")
        styleFiles += self.styleDir.files("*.gif")
        styleFiles += self.styleDir.files("*.png")
        styleFiles += self.styleDir.files("*.js")
        styleFiles += self.styleDir.files("*.html")
        styleFiles += self.styleDir.files("*.ttf")
        styleFiles += self.styleDir.files("*.eot")
        styleFiles += self.styleDir.files("*.otf")
        styleFiles += self.styleDir.files("*.woff")
        # FIXME for now, only copy files referenced in Common Cartridge
        # this really should apply to all exports, but without a manifest
        # of the files needed by an included stylesheet it is too restrictive

        package.resourceDir.copyfiles(contentPages)

        self.styleDir.copylist(styleFiles, contentPages)

        listCSSFiles = getFilesCSSToMinify("epub3", self.styleDir)
        exportMinFileCSS(listCSSFiles, outputDir)

        listFiles = []
        listOutFiles = []

        listFiles += [self.scriptsDir / "common.js"]
        listOutFiles += [outputDir / "common.js"]

        # copy players for media idevices.
        hasFlowplayer = False
        hasMagnifier = False
        hasXspfplayer = False
        hasGallery = False
        hasFX = False
        hasSH = False
        hasGames = False
        hasWikipedia = False
        isBreak = False
        hasInstructions = False
        hasTooltips = False

        for page in self.pages:
            if isBreak:
                break
            for idevice in page.node.idevices:
                if (
                    hasFlowplayer
                    and hasMagnifier
                    and hasXspfplayer
                    and hasGallery
                    and hasFX
                    and hasSH
                    and hasGames
                    and hasWikipedia
                ):
                    isBreak = True
                    break
                if not hasFlowplayer:
                    if "flowPlayer.swf" in idevice.systemResources:
                        hasFlowplayer = True
                if not hasMagnifier:
                    if "mojomagnify.js" in idevice.systemResources:
                        hasMagnifier = True
                if not hasXspfplayer:
                    if "xspf_player.swf" in idevice.systemResources:
                        hasXspfplayer = True
                if not hasGallery:
                    hasGallery = common.ideviceHasGallery(idevice)
                if not hasFX:
                    hasFX = common.ideviceHasFX(idevice)
                if not hasSH:
                    hasSH = common.ideviceHasSH(idevice)
                if not hasGames:
                    hasGames = common.ideviceHasGames(idevice)
                if not hasWikipedia:
                    if "WikipediaIdevice" == idevice.klass:
                        hasWikipedia = True
                if not hasInstructions:
                    if (
                        "TrueFalseIdevice" == idevice.klass
                        or "MultichoiceIdevice" == idevice.klass
                        or "VerdaderofalsofpdIdevice" == idevice.klass
                        or "EleccionmultiplefpdIdevice" == idevice.klass
                    ):
                        hasInstructions = True
                if not hasTooltips:
                    hasTooltips = common.ideviceHasTooltips(idevice)

        if hasFlowplayer:
            videofile = self.templatesDir / "flowPlayer.swf"
            videofile.copyfile(contentPages / "flowPlayer.swf")
            controlsfile = self.templatesDir / "flowplayer.controls.swf"
            controlsfile.copyfile(contentPages / "flowplayer.controls.swf")
        if hasMagnifier:
            videofile = self.templatesDir / "mojomagnify.js"
            videofile.copyfile(contentPages / "mojomagnify.js")
        if hasXspfplayer:
            videofile = self.templatesDir / "xspf_player.swf"
            videofile.copyfile(contentPages / "xspf_player.swf")
        if hasGallery:
            exeLightbox = self.scriptsDir / "exe_lightbox"
            exeLightbox.copyfiles(contentPages)
        if hasFX:
            exeEffects = self.scriptsDir / "exe_effects"
            exeEffects.copyfiles(contentPages)
        if hasSH:
            exeSH = self.scriptsDir / "exe_highlighter"
            exeSH.copyfiles(contentPages)
        if hasGames:
            exeGames = self.scriptsDir / "exe_games"
            exeGames.copyfiles(contentPages)
        if hasWikipedia:
            wikipediaCSS = self.cssDir / "exe_wikipedia.css"
            wikipediaCSS.copyfile(contentPages / "exe_wikipedia.css")
        if hasInstructions:
            common.copyFileIfNotInStyle("panel-amusements.png", self, contentPages)
            common.copyFileIfNotInStyle("stock-stop.png", self, contentPages)
        if hasTooltips:
            exe_tooltips = self.scriptsDir / "exe_tooltips"
            exe_tooltips.copyfiles(contentPages)

        my_style = G.application.config.styleStore.getStyle(package.style)
        if my_style.hasValidConfig:
            if my_style.get_jquery() == True:
                jsFile = self.scriptsDir / "exe_jquery.js"
                jsFile.copyfile(contentPages / "exe_jquery.js")
        else:
            jsFile = self.scriptsDir / "exe_jquery.js"
            jsFile.copyfile(contentPages / "exe_jquery.js")

        listFiles = getFilesJSToMinify("epub3", self.scriptsDir)
        exportMinFileJS(listFiles, outputDir)

        #         if hasattr(package, 'exportSource') and package.exportSource:
        #             (G.application.config.webDir / 'templates' / 'content.xsd').copyfile(outputDir / 'content.xsd')
        #             (outputDir / 'content.data').write_bytes(encodeObject(package))
        #             (outputDir / 'contentv3.xml').write_bytes(encodeObjectToXML(package))

        if package.license == "license GFDL":
            # include a copy of the GNU Free Documentation Licence
            (self.templatesDir / "fdl.html").copyfile(contentPages / "fdl.html")

        # Create the nav.xhtml file
        container = NavEpub3(self.pages, contentPages)
        container.save()

        # Create the publication file
        publication = PublicationEpub3(self.config, contentPages, package, self.pages, cover)
        publication.save("package.opf")

        # Create the container file
        container = ContainerEpub3(metainfPages)
        container.save("container.xml")

        # Zip it up!
        self.filename.safeSave(self.doZip, _(u"EXPORT FAILED!\nLast succesful export is %s."), outputDir)
        # Clean up the temporary dir

        outputDir.rmtree()

    def doZip(self, fileObj, outputDir):
        """
        Actually does the zipping of the file. Called by 'Path.safeSave'
        """
        zipped = ZipFile(fileObj, "w")

        mimetype = outputDir / "mimetype"
        zipped.write(mimetype, "mimetype", ZIP_STORED)

        for epubFile in outputDir.walkfiles():
            if epubFile.basename() == "mimetype":
                continue
            relativePath = epubFile.basename()
            parentdir = epubFile.splitpath()[0]
            while outputDir.basename() != parentdir.basename():
                relativePath = parentdir.basename() / relativePath
                parentdir = parentdir.splitpath()[0]

            zipped.write(epubFile, relativePath.encode("utf8"), compress_type=ZIP_DEFLATED)
        zipped.close()

    def generatePages(self, node, depth):
        """
        Recursive function for exporting a node.
        'node' is the node that we are making a page for
        'depth' is the number of ancestors that the page has +1 (ie. root is 1)
        """
        pageName = node.titleShort.lower().replace(" ", u"_")
        pageName = re.sub(r"\W", "", pageName)
        if not pageName:
            pageName = u"__"

        if pageName[0] in [unicode(i) for i in range(0, 10)]:
            pageName = u"_" + pageName

        page = Epub3Page(pageName, depth, node)

        self.pages.append(page)
        for child in node.children:
            self.generatePages(child, depth + 1)
Beispiel #25
0
class WebsiteExport(object):
    """
    WebsiteExport will export a package as a website of HTML pages
    """
    def __init__(self, config, styleDir, filename, prefix="", report=False):
        """
        'stylesDir' is the directory where we can copy the stylesheets from
        'outputDir' is the directory that will be [over]written
        with the website
        """
        self.config = config
        self.imagesDir = config.webDir / "images"
        self.scriptsDir = config.webDir / "scripts"
        self.cssDir = config.webDir / "css"
        self.templatesDir = config.webDir / "templates"
        self.stylesDir = Path(styleDir)
        self.filename = Path(filename)
        self.pages = []
        self.prefix = prefix
        self.report = report
        self.styleSecureMode = config.styleSecureMode

    def exportZip(self, package):
        """ 
        Export web site
        Cleans up the previous packages pages and performs the export
        """

        outputDir = TempDirPath()

        # Import the Website Page class , if the secure mode is off.  If the style has it's own page class
        # use that, else use the default one.
        if self.styleSecureMode == "0":
            if (self.stylesDir / "websitepage.py").exists():
                global WebsitePage
                module = imp.load_source("websitepage",
                                         self.stylesDir / "websitepage.py")
                WebsitePage = module.WebsitePage

        self.pages = [WebsitePage("index", 0, package.root)]
        self.generatePages(package.root, 1)
        uniquifyNames(self.pages)

        prevPage = None
        thisPage = self.pages[0]

        for nextPage in self.pages[1:]:
            thisPage.save(outputDir, prevPage, nextPage, self.pages)
            prevPage = thisPage
            thisPage = nextPage

        thisPage.save(outputDir, prevPage, None, self.pages)
        self.copyFiles(package, outputDir)
        # Zip up the website package
        self.filename.safeSave(
            self.doZip, _('EXPORT FAILED!\nLast succesful export is %s.'),
            outputDir)
        # Clean up the temporary dir
        outputDir.rmtree()

    def doZip(self, fileObj, outputDir):
        """
        Actually saves the zip data. Called by 'Path.safeSave'
        """
        zipped = ZipFile(fileObj, "w")
        for scormFile in outputDir.files():
            zipped.write(scormFile,
                         scormFile.basename().encode('utf8'), ZIP_DEFLATED)
        zipped.close()

    def appendPageReport(self, page, package):
        if not page.node.idevices:
            self.report += u'"%s","%s",%d,"%s",,,,,,\n' % (
                package.filename, page.node.title, page.depth,
                page.name + '.html')
        for idevice in page.node.idevices:
            if not idevice.userResources:
                self.report += u'"%s","%s",%d,"%s","%s","%s",,,,\n' % (
                    package.filename, page.node.title, page.depth,
                    page.name + '.html', idevice.klass, idevice.title)
            for resource in idevice.userResources:
                if type(resource) == Resource:
                    self.report += u'"%s","%s",%d,"%s","%s","%s","%s","%s","%s","%s"\n' % (
                        package.filename, page.node.title, page.depth,
                        page.name + '.html', idevice.klass, idevice.title,
                        resource.storageName, resource.userName, resource.path,
                        resource.checksum)
                else:
                    self.report += u'"%s",%d,"%s","%s","%s","%s",,,\n' % (
                        package.filename, page.node.title, page.depth,
                        page.name + '.html', idevice.klass, idevice.title,
                        resource)

    def export(self, package):
        """ 
        Export web site
        Cleans up the previous packages pages and performs the export
        """
        if not self.report:
            outputDir = self.filename
            if not outputDir.exists():
                outputDir.mkdir()

        # Import the Website Page class.  If the style has it's own page class
        # use that, else use the default one.
        if (self.stylesDir / "websitepage.py").exists():
            global WebsitePage
            module = imp.load_source("websitepage",
                                     self.stylesDir / "websitepage.py")
            WebsitePage = module.WebsitePage

        self.pages = [WebsitePage(self.prefix + "index", 0, package.root)]
        self.generatePages(package.root, 1)
        uniquifyNames(self.pages)

        prevPage = None
        thisPage = self.pages[0]
        if self.report:
            self.report = u'"%s","%s","%s","%s","%s","%s","%s","%s","%s","%s"\n' % (
                'File', 'Page Name', 'Level', 'Page File Name', 'Idevice Type',
                'Idevice Title', 'Resource File Name', 'Resource User Name',
                'Resource Path', 'Resource Checksum')
            self.appendPageReport(thisPage, package)

        for nextPage in self.pages[1:]:
            if self.report:
                self.appendPageReport(nextPage, package)
            else:
                thisPage.save(outputDir, prevPage, nextPage, self.pages)
            prevPage = thisPage
            thisPage = nextPage

        if not self.report:
            thisPage.save(outputDir, prevPage, None, self.pages)

            if self.prefix == "":
                self.copyFiles(package, outputDir)

            return outputDir

        else:
            self.filename.write_text(self.report, 'utf-8')

    def copyFiles(self, package, outputDir):
        """
        Copy all the files used by the website.
        """

        if os.path.isdir(self.stylesDir):
            # Copy the style sheet files to the output dir
            styleFiles = [self.stylesDir / '..' / 'base.css']
            styleFiles += [self.stylesDir / '..' / 'popup_bg.gif']
            styleFiles += self.stylesDir.files("*.css")
            styleFiles += self.stylesDir.files("*.jpg")
            styleFiles += self.stylesDir.files("*.gif")
            styleFiles += self.stylesDir.files("*.png")
            styleFiles += self.stylesDir.files("*.js")
            styleFiles += self.stylesDir.files("*.html")
            styleFiles += self.stylesDir.files("*.ico")
            styleFiles += self.stylesDir.files("*.ttf")
            styleFiles += self.stylesDir.files("*.eot")
            styleFiles += self.stylesDir.files("*.otf")
            styleFiles += self.stylesDir.files("*.woff")
            self.stylesDir.copylist(styleFiles, outputDir)

        # copy the package's resource files
        package.resourceDir.copyfiles(outputDir)

        # copy script files.
        my_style = G.application.config.styleStore.getStyle(package.style)
        # jQuery
        if my_style.hasValidConfig:
            if my_style.get_jquery() == True:
                jsFile = (self.scriptsDir / 'exe_jquery.js')
                jsFile.copyfile(outputDir / 'exe_jquery.js')
        else:
            jsFile = (self.scriptsDir / 'exe_jquery.js')
            jsFile.copyfile(outputDir / 'exe_jquery.js')

        jsFile = (self.scriptsDir / 'common.js')
        jsFile.copyfile(outputDir / 'common.js')
        #dT = common.getExportDocType()
        dT = common.getExportDocType()
        if dT == "HTML5":
            jsFile = (self.scriptsDir / 'exe_html5.js')
            jsFile.copyfile(outputDir / 'exe_html5.js')

        # Incluide eXe's icon if the Style doesn't have one
        themePath = Path(G.application.config.stylesDir / package.style)
        themeFavicon = themePath.joinpath("favicon.ico")
        if not themeFavicon.exists():
            faviconFile = (self.imagesDir / 'favicon.ico')
            faviconFile.copyfile(outputDir / 'favicon.ico')

        # copy players for media idevices.
        hasFlowplayer = False
        hasMagnifier = False
        hasXspfplayer = False
        hasGallery = False
        hasFX = False
        hasSH = False
        hasGames = False
        hasWikipedia = False
        isBreak = False
        hasInstructions = False
        hasMediaelement = False
        hasTooltips = False

        for page in self.pages:
            if isBreak:
                break
            for idevice in page.node.idevices:
                if (hasFlowplayer and hasMagnifier and hasXspfplayer
                        and hasGallery and hasFX and hasSH and hasGames
                        and hasWikipedia and hasInstructions
                        and hasMediaelement and hasTooltips):
                    isBreak = True
                    break
                if not hasFlowplayer:
                    if 'flowPlayer.swf' in idevice.systemResources:
                        hasFlowplayer = True
                if not hasMagnifier:
                    if 'mojomagnify.js' in idevice.systemResources:
                        hasMagnifier = True
                if not hasXspfplayer:
                    if 'xspf_player.swf' in idevice.systemResources:
                        hasXspfplayer = True
                if not hasGallery:
                    hasGallery = common.ideviceHasGallery(idevice)
                if not hasFX:
                    hasFX = common.ideviceHasFX(idevice)
                if not hasSH:
                    hasSH = common.ideviceHasSH(idevice)
                if not hasGames:
                    hasGames = common.ideviceHasGames(idevice)
                if not hasWikipedia:
                    if 'WikipediaIdevice' == idevice.klass:
                        hasWikipedia = True
                if not hasInstructions:
                    if 'TrueFalseIdevice' == idevice.klass or 'MultichoiceIdevice' == idevice.klass or 'VerdaderofalsofpdIdevice' == idevice.klass or 'EleccionmultiplefpdIdevice' == idevice.klass:
                        hasInstructions = True
                if not hasMediaelement:
                    hasMediaelement = common.ideviceHasMediaelement(idevice)
                if not hasTooltips:
                    hasTooltips = common.ideviceHasTooltips(idevice)

        if hasFlowplayer:
            videofile = (self.templatesDir / 'flowPlayer.swf')
            videofile.copyfile(outputDir / 'flowPlayer.swf')
            controlsfile = (self.templatesDir / 'flowplayer.controls.swf')
            controlsfile.copyfile(outputDir / 'flowplayer.controls.swf')
        if hasMagnifier:
            videofile = (self.templatesDir / 'mojomagnify.js')
            videofile.copyfile(outputDir / 'mojomagnify.js')
        if hasXspfplayer:
            videofile = (self.templatesDir / 'xspf_player.swf')
            videofile.copyfile(outputDir / 'xspf_player.swf')
        if hasGallery:
            exeLightbox = (self.scriptsDir / 'exe_lightbox')
            exeLightbox.copyfiles(outputDir)
        if hasFX:
            exeEffects = (self.scriptsDir / 'exe_effects')
            exeEffects.copyfiles(outputDir)
        if hasSH:
            exeSH = (self.scriptsDir / 'exe_highlighter')
            exeSH.copyfiles(outputDir)
        if hasGames:
            exeGames = (self.scriptsDir / 'exe_games')
            exeGames.copyfiles(outputDir)
        if hasWikipedia:
            wikipediaCSS = (self.cssDir / 'exe_wikipedia.css')
            wikipediaCSS.copyfile(outputDir / 'exe_wikipedia.css')
        if hasInstructions:
            common.copyFileIfNotInStyle('panel-amusements.png', self,
                                        outputDir)
            common.copyFileIfNotInStyle('stock-stop.png', self, outputDir)
        if hasMediaelement:
            mediaelement = (self.scriptsDir / 'mediaelement')
            mediaelement.copyfiles(outputDir)
            dT = common.getExportDocType()
            if dT != "HTML5":
                jsFile = (self.scriptsDir / 'exe_html5.js')
                jsFile.copyfile(outputDir / 'exe_html5.js')
        if hasTooltips:
            exe_tooltips = (self.scriptsDir / 'exe_tooltips')
            exe_tooltips.copyfiles(outputDir)

        if hasattr(package, 'exportSource') and package.exportSource:
            (G.application.config.webDir / 'templates' /
             'content.xsd').copyfile(outputDir / 'content.xsd')
            (outputDir / 'content.data').write_bytes(encodeObject(package))
            (outputDir / 'contentv3.xml').write_bytes(
                encodeObjectToXML(package))

        if package.license == "license GFDL":
            # include a copy of the GNU Free Documentation Licence
            (self.templatesDir / 'fdl.html').copyfile(outputDir / 'fdl.html')

    def generatePages(self, node, depth):
        """
        Recursively generate pages and store in pages member variable
        for retrieving later
        """
        for child in node.children:
            # assure lower pagename, without whitespaces or alphanumeric characters:
            pageName = child.titleShort.lower().replace(" ", "_")
            pageName = re.sub(r"\W", "", pageName)
            if not pageName:
                pageName = "__"

            self.pages.append(WebsitePage(self.prefix + pageName, depth,
                                          child))
            self.generatePages(child, depth + 1)
class WebsiteExport(object):
    """
    WebsiteExport will export a package as a website of HTML pages
    """
    def __init__(self, config, styleDir, filename, prefix=""):
        """
        'stylesDir' is the directory where we can copy the stylesheets from
        'outputDir' is the directory that will be [over]written
        with the website
        """
        self.config       = config
        self.imagesDir    = config.webDir/"images"
        self.scriptsDir   = config.webDir/"scripts"
        self.cssDir       = config.webDir/"css"
        self.templatesDir = config.webDir/"templates"
        self.stylesDir    = Path(styleDir)
        self.filename     = Path(filename)
        self.pages        = []
        self.prefix       = prefix

    def exportZip(self, package):
        """ 
        Export web site
        Cleans up the previous packages pages and performs the export
        """
        
        outputDir = TempDirPath()

        # Import the Website Page class.  If the style has it's own page class
        # use that, else use the default one.
        if (self.stylesDir/"websitepage.py").exists():
            global WebsitePage
            module = imp.load_source("websitepage", 
                                     self.stylesDir/"websitepage.py")
            WebsitePage = module.WebsitePage

        self.pages = [ WebsitePage("index", 1, package.root) ]
        self.generatePages(package.root, 1)
        uniquifyNames(self.pages)

        prevPage = None
        thisPage = self.pages[0]

        for nextPage in self.pages[1:]:
            thisPage.save(outputDir, prevPage, nextPage, self.pages)
            prevPage = thisPage
            thisPage = nextPage
            

        thisPage.save(outputDir, prevPage, None, self.pages)
        self.copyFiles(package, outputDir)
        # Zip up the website package
        self.filename.safeSave(self.doZip, _('EXPORT FAILED!\nLast succesful export is %s.'), outputDir)
        # Clean up the temporary dir
        outputDir.rmtree()

    def doZip(self, fileObj, outputDir):
        """
        Actually saves the zip data. Called by 'Path.safeSave'
        """
        zipped = ZipFile(fileObj, "w")
        for scormFile in outputDir.files():
            zipped.write(scormFile, scormFile.basename().encode('utf8'), ZIP_DEFLATED)
        zipped.close()
        
    def export(self, package):
        """ 
        Export web site
        Cleans up the previous packages pages and performs the export
        """
        outputDir = self.filename
        if not outputDir.exists(): 
            outputDir.mkdir()
        
        # Import the Website Page class.  If the style has it's own page class
        # use that, else use the default one.
        if (self.stylesDir/"websitepage.py").exists():
            global WebsitePage
            module = imp.load_source("websitepage", 
                                     self.stylesDir/"websitepage.py")
            WebsitePage = module.WebsitePage

        self.pages = [ WebsitePage(self.prefix + "index", 1, package.root) ]
        self.generatePages(package.root, 1)
        uniquifyNames(self.pages)

        prevPage = None
        thisPage = self.pages[0]

        for nextPage in self.pages[1:]:
            thisPage.save(outputDir, prevPage, nextPage, self.pages)
            prevPage = thisPage
            thisPage = nextPage

        thisPage.save(outputDir, prevPage, None, self.pages)
        
        if self.prefix == "":
            self.copyFiles(package, outputDir)


    def copyFiles(self, package, outputDir):
        """
        Copy all the files used by the website.
        """
        # Copy the style sheet files to the output dir
        styleFiles  = [self.stylesDir/'..'/'base.css']
        styleFiles += [self.stylesDir/'..'/'popup_bg.gif']
        styleFiles += self.stylesDir.files("*.css")
        styleFiles += self.stylesDir.files("*.jpg")
        styleFiles += self.stylesDir.files("*.gif")
        styleFiles += self.stylesDir.files("*.png")
        styleFiles += self.stylesDir.files("*.js")
        styleFiles += self.stylesDir.files("*.html")
        styleFiles += self.stylesDir.files("*.ico")
        styleFiles += self.stylesDir.files("*.ttf")
        styleFiles += self.stylesDir.files("*.eot")
        styleFiles += self.stylesDir.files("*.otf")
        styleFiles += self.stylesDir.files("*.woff")
        self.stylesDir.copylist(styleFiles, outputDir)

        # copy the package's resource files
        package.resourceDir.copyfiles(outputDir)
            
        # copy script files. - with modification by lernmodule.net
        self.scriptsDir.copylist(('libot_drag.js', 'common.js', 'lernmodule_net.js'),
                                 outputDir)

        # copy players for media idevices.                
        hasFlowplayer     = False
        hasMagnifier      = False
        hasXspfplayer     = False
        hasGallery        = False
        isBreak           = False
        
        for page in self.pages:
            if isBreak:
                break
            for idevice in page.node.idevices:
                if (hasFlowplayer and hasMagnifier and hasXspfplayer and hasGallery):
                    isBreak = True
                    break
                if not hasFlowplayer:
                    if 'flowPlayer.swf' in idevice.systemResources:
                        hasFlowplayer = True
                if not hasMagnifier:
                    if 'magnifier.swf' in idevice.systemResources:
                        hasMagnifier = True
                if not hasXspfplayer:
                    if 'xspf_player.swf' in idevice.systemResources:
                        hasXspfplayer = True
                if not hasGallery:
                    if 'GalleryIdevice' == idevice.klass:
                        hasGallery = True
                        
        if hasFlowplayer:
            videofile = (self.templatesDir/'flowPlayer.swf')
            videofile.copyfile(outputDir/'flowPlayer.swf')
            controlsfile = (self.templatesDir/'flowplayer.controls.swf')
            controlsfile.copyfile(outputDir/'flowplayer.controls.swf')
        if hasMagnifier:
            videofile = (self.templatesDir/'magnifier.swf')
            videofile.copyfile(outputDir/'magnifier.swf')
        if hasXspfplayer:
            videofile = (self.templatesDir/'xspf_player.swf')
            videofile.copyfile(outputDir/'xspf_player.swf')
        if hasGallery:
            imageGalleryCSS = (self.cssDir/'exe_lightbox.css')
            imageGalleryCSS.copyfile(outputDir/'exe_lightbox.css') 
            imageGalleryJS = (self.scriptsDir/'exe_lightbox.js')
            imageGalleryJS.copyfile(outputDir/'exe_lightbox.js') 
            self.imagesDir.copylist(('exeGallery_actions.png', 'exeGallery_loading.gif'), outputDir)        

        if package.license == "GNU Free Documentation License":
            # include a copy of the GNU Free Documentation Licence
            (self.templatesDir/'fdl.html').copyfile(outputDir/'fdl.html')


    def generatePages(self, node, depth):
        """
        Recursively generate pages and store in pages member variable
        for retrieving later
        """           
        for child in node.children:
            # assure lower pagename, without whitespaces or alphanumeric characters:
            pageName = child.titleShort.lower().replace(" ", "_")
            pageName = re.sub(r"\W", "", pageName)
            if not pageName:
                pageName = "__"

            self.pages.append(WebsitePage(self.prefix + pageName, depth, child))
            self.generatePages(child, depth + 1)
Beispiel #27
0
class ScormExport(object):
    """
    Exports an eXe package as a SCORM package
    """
    def __init__(self, config, styleDir, filename, scormType):
        """ 
        Initialize
        'styleDir' is the directory from which we will copy our style sheets
        (and some gifs)
        """
        self.config       = config
        self.imagesDir    = config.webDir/"images"
        self.scriptsDir   = config.webDir/"scripts"
        self.templatesDir = config.webDir/"templates"
        self.styleDir     = Path(styleDir)
        self.filename     = Path(filename)
        self.pages        = []
        self.hasForum     = False
        self.scormType    = scormType
    def export(self, package):
        """ 
        Export SCORM package
        """
        outputDir = TempDirPath()
        styleFiles  = [self.styleDir/'..'/'base.css']
        styleFiles += [self.styleDir/'..'/'popup_bg.gif']
        styleFiles += self.styleDir.files("*.css")
        if "nav.css" in styleFiles:
            styleFiles.remove("nav.css")
        styleFiles += self.styleDir.files("*.jpg")
        styleFiles += self.styleDir.files("*.gif")
        styleFiles += self.styleDir.files("*.png")
        styleFiles += self.styleDir.files("*.js")
        styleFiles += self.styleDir.files("*.html")
        self.styleDir.copylist(styleFiles, outputDir)
        package.resourceDir.copyfiles(outputDir)
        self.pages = [ ScormPage("index", 1, package.root) ]
        self.generatePages(package.root, 2)
        uniquifyNames(self.pages)
        for page in self.pages:
            page.save(outputDir)
            if not self.hasForum:
                for idevice in page.node.idevices:
                    if hasattr(idevice, "isForum"):
                        if idevice.forum.lms.lms == "moodle":
                            self.hasForum = True
                            break
        manifest = Manifest(self.config, outputDir, package, self.pages, self.scormType)
        manifest.save("imsmanifest.xml")
        if self.hasForum:
            manifest.save("discussionforum.xml")
        self.scriptsDir.copylist(('APIWrapper.js', 
                                  'imscp_rootv1p1p2.xsd',
                                  'imsmd_rootv1p2p1.xsd',
                                  'ims_xml.xsd',
                                  'adlcp_rootv1p2.xsd',
                                  'SCOFunctions.js', 
                                  'libot_drag.js',
                                  'common.js'), outputDir)
        self.templatesDir.copylist(('videoContainer.swf', 'magnifier.swf',
                                    'xspf_player.swf'),outputDir)
        (self.templatesDir/'fdl.html').copyfile(outputDir/'fdl.html')
        self.filename.safeSave(self.doZip, _('EXPORT FAILED!\nLast succesful export is %s.'), outputDir)
        outputDir.rmtree()
    def doZip(self, fileObj, outputDir):
        """
        Actually does the zipping of the file. Called by 'Path.safeSave'
        """
        zipped = ZipFile(fileObj, "w")
        for scormFile in outputDir.files():
            zipped.write(scormFile,
                         scormFile.basename().encode('utf8'),
                         ZIP_DEFLATED)
        zipped.close()
    def generatePages(self, node, depth):
        """
        Recursive function for exporting a node.
        'node' is the node that we are making a page for
        'depth' is the number of ancestors that the page has +1 (ie. root is 1)
        """
        for child in node.children:
            pageName = child.titleShort.lower().replace(" ", "_")
            pageName = re.sub(r"\W", "", pageName)
            if not pageName:
                pageName = "__"
            page = ScormPage(pageName, depth, child)
            self.pages.append(page)
            self.generatePages(child, depth + 1)
Beispiel #28
0
class Epub3Export(object):
    """
    Exports an eXe package as a epub 3 package
    The 'Hello World' of a epub 3 publication might contain files:
        mimetype
        META-INF/container.xml
        Content/HelloWorld.opf
        Content/HelloWorld.xhtml
    """
    def __init__(self, config, styleDir, filename):
        """
        Initialize
        'styleDir' is the directory from which we will copy our style sheets
        (and some gifs)
        """
        self.config = config
        self.imagesDir = config.webDir / "images"
        self.scriptsDir = config.webDir / "scripts"
        self.cssDir = config.webDir / "css"
        self.templatesDir = config.webDir / "templates"
        self.schemasDir = config.webDir / "schemas/ims"
        self.styleDir = Path(styleDir)
        self.filename = Path(filename)
        self.pages = []

    def export(self, package):
        """
        Export epub 3 package
        """
        # First do the export to a temporary directory
        outputDir = TempDirPath()
        '''
        fileDir = outputDir/"META-INF"
        fileDir.mkdir()
        fileDir = outputDir/"Content"
        fileDir.mkdir()
        '''

        metainfPages = Path(outputDir.abspath() + '/META-INF')
        # metainfPages = outputDir/'META-INF'
        metainfPages.mkdir()
        contentPages = Path(outputDir.abspath() + '/EPUB')
        # contentPages = outputDir/'Content'
        contentPages.mkdir()
        # print contentPages.abspath()
        # print outputDir.abspath()

        # Export the package content
        self.pages = [Epub3Cover("cover", 1, package.root)]

        self.generatePages(package.root, 2)
        uniquifyNames(self.pages)

        cover = None
        for page in self.pages:
            page.save(contentPages, self.pages)
            if hasattr(page, 'cover'):
                cover = page.cover

        # Create mimetype file
        mimetypeFile = open(outputDir.abspath() + '/mimetype', "w")
        mimetypeFile.write('application/epub+zip')
        mimetypeFile.close()

        # Create common_i18n file
        langFile = open(contentPages + '/common_i18n.js', "w")
        langFile.write(common.getJavaScriptStrings(False))
        langFile.close()

        # Copy the style files to the output dir
        # But not nav.css
        styleFiles = [self.styleDir / '..' / 'popup_bg.gif']
        styleFiles += [
            f for f in self.styleDir.files("*.*")
            if f.basename() not in ['nav.css']
        ]

        # FIXME for now, only copy files referenced in Common Cartridge
        # this really should apply to all exports, but without a manifest
        # of the files needed by an included stylesheet it is too restrictive

        # Add fallback document for possible image links
        if Path(self.styleDir / 'fallback.xhtml').exists():
            styleFiles += [self.styleDir / 'fallback.xhtml']
        else:
            styleFiles += [self.styleDir / '..' / 'fallback.xhtml']

        # copy the package's resource files
        for resourceFile in package.resourceDir.walkfiles():
            fn = package.resourceDir.relpathto(resourceFile)

            if ("/" in fn):
                Dir = Path(contentPages / fn[:fn.rindex("/")])
                if not Dir.exists():
                    Dir.makedirs()

                resourceFile.copy(contentPages / Dir)
            else:
                resourceFile.copy(contentPages)

        self.styleDir.copylist(styleFiles, contentPages)

        # copy players for media idevices.
        hasFlowplayer = False
        hasMagnifier = False
        hasXspfplayer = False
        hasGallery = False
        hasFX = False
        hasSH = False
        hasGames = False
        hasWikipedia = False
        isBreak = False
        hasInstructions = False
        hasTooltips = False
        hasABCMusic = False

        for page in self.pages:
            if isBreak:
                break
            for idevice in page.node.idevices:
                if (hasFlowplayer and hasMagnifier and hasXspfplayer
                        and hasGallery and hasFX and hasSH and hasGames
                        and hasWikipedia and hasInstructions and hasTooltips
                        and hasABCMusic):
                    isBreak = True
                    break
                if not hasFlowplayer:
                    if 'flowPlayer.swf' in idevice.systemResources:
                        hasFlowplayer = True
                if not hasMagnifier:
                    if 'mojomagnify.js' in idevice.systemResources:
                        hasMagnifier = True
                if not hasXspfplayer:
                    if 'xspf_player.swf' in idevice.systemResources:
                        hasXspfplayer = True
                if not hasGallery:
                    hasGallery = common.ideviceHasGallery(idevice)
                if not hasFX:
                    hasFX = common.ideviceHasFX(idevice)
                if not hasSH:
                    hasSH = common.ideviceHasSH(idevice)
                if not hasGames:
                    hasGames = common.ideviceHasGames(idevice)
                if not hasWikipedia:
                    if 'WikipediaIdevice' == idevice.klass:
                        hasWikipedia = True
                if not hasInstructions:
                    if 'TrueFalseIdevice' == idevice.klass or 'MultichoiceIdevice' == idevice.klass or 'VerdaderofalsofpdIdevice' == idevice.klass or 'EleccionmultiplefpdIdevice' == idevice.klass:
                        hasInstructions = True
                if not hasTooltips:
                    hasTooltips = common.ideviceHasTooltips(idevice)
                if not hasABCMusic:
                    hasABCMusic = common.ideviceHasABCMusic(idevice)

            common.exportJavaScriptIdevicesFiles(page.node.idevices,
                                                 contentPages)

        if hasFlowplayer:
            videofile = (self.templatesDir / 'flowPlayer.swf')
            videofile.copyfile(contentPages / 'flowPlayer.swf')
            controlsfile = (self.templatesDir / 'flowplayer.controls.swf')
            controlsfile.copyfile(contentPages / 'flowplayer.controls.swf')
        if hasMagnifier:
            videofile = (self.templatesDir / 'mojomagnify.js')
            videofile.copyfile(contentPages / 'mojomagnify.js')
        if hasXspfplayer:
            videofile = (self.templatesDir / 'xspf_player.swf')
            videofile.copyfile(contentPages / 'xspf_player.swf')
        if hasGallery:
            exeLightbox = (self.scriptsDir / 'exe_lightbox')
            exeLightbox.copyfiles(contentPages)
        if hasFX:
            exeEffects = (self.scriptsDir / 'exe_effects')
            exeEffects.copyfiles(contentPages)
        if hasSH:
            exeSH = (self.scriptsDir / 'exe_highlighter')
            exeSH.copyfiles(contentPages)
        if hasGames:
            exeGames = (self.scriptsDir / 'exe_games')
            exeGames.copyfiles(contentPages)
            # Add game js string to common_i18n
            langGameFile = open(contentPages + '/common_i18n.js', "a")
            langGameFile.write(common.getGamesJavaScriptStrings(False))
            langGameFile.close()
        if hasWikipedia:
            wikipediaCSS = (self.cssDir / 'exe_wikipedia.css')
            wikipediaCSS.copyfile(contentPages / 'exe_wikipedia.css')
        if hasInstructions:
            common.copyFileIfNotInStyle('panel-amusements.png', self,
                                        contentPages)
            common.copyFileIfNotInStyle('stock-stop.png', self, contentPages)
        if hasTooltips:
            exe_tooltips = (self.scriptsDir / 'exe_tooltips')
            exe_tooltips.copyfiles(contentPages)
        if hasABCMusic:
            pluginScripts = (self.scriptsDir /
                             'tinymce_4/js/tinymce/plugins/abcmusic/export')
            pluginScripts.copyfiles(contentPages)

        my_style = G.application.config.styleStore.getStyle(package.style)
        if my_style.hasValidConfig:
            if my_style.get_jquery() == True:
                jsFile = (self.scriptsDir / 'exe_jquery.js')
                jsFile.copyfile(contentPages / 'exe_jquery.js')
        else:
            jsFile = (self.scriptsDir / 'exe_jquery.js')
            jsFile.copyfile(contentPages / 'exe_jquery.js')

        # Copy and minify CSS files
        css_files = getFilesCSSToMinify('epub3', self.styleDir)
        exportMinFileCSS(css_files, contentPages)

        # Copy and minify JS files
        js_files = getFilesJSToMinify('epub3', self.scriptsDir)
        exportMinFileJS(js_files, contentPages)

        #         if hasattr(package, 'exportSource') and package.exportSource:
        #             (G.application.config.webDir / 'templates' / 'content.xsd').copyfile(outputDir / 'content.xsd')
        #             (outputDir / 'content.data').write_bytes(encodeObject(package))
        #             (outputDir / 'contentv3.xml').write_bytes(encodeObjectToXML(package))

        if package.license == "license GFDL":
            # include a copy of the GNU Free Documentation Licence
            (self.templatesDir / 'fdl.html').copyfile(contentPages /
                                                      'fdl.html')

        # Create the nav.xhtml file
        container = NavEpub3(self.pages, contentPages)
        container.save()

        # Create the publication file
        publication = PublicationEpub3(self.config, contentPages, package,
                                       self.pages, cover)
        publication.save("package.opf")

        # Create the container file
        container = ContainerEpub3(metainfPages)
        container.save("container.xml")

        # Zip it up!
        self.filename.safeSave(
            self.doZip, _(u'EXPORT FAILED!\nLast succesful export is %s.'),
            outputDir)
        # Clean up the temporary dir

        outputDir.rmtree()

    def doZip(self, fileObj, outputDir):
        """
        Actually does the zipping of the file. Called by 'Path.safeSave'
        """
        zipped = ZipFile(fileObj, "w")

        mimetype = outputDir / "mimetype"
        zipped.write(mimetype, "mimetype", ZIP_STORED)

        for epubFile in outputDir.walkfiles():
            if epubFile.basename() == 'mimetype':
                continue
            relativePath = epubFile.basename()
            parentdir = epubFile.splitpath()[0]
            while (outputDir.basename() != parentdir.basename()):
                relativePath = parentdir.basename() / relativePath
                parentdir = parentdir.splitpath()[0]

            zipped.write(epubFile,
                         relativePath.encode('utf8'),
                         compress_type=ZIP_DEFLATED)
        zipped.close()

    def generatePages(self, node, depth):
        """
        Recursive function for exporting a node.
        'node' is the node that we are making a page for
        'depth' is the number of ancestors that the page has +1 (ie. root is 1)
        """
        pageName = node.titleShort.lower().replace(" ", u"_")
        pageName = re.sub(r"\W", "", pageName)
        if not pageName:
            pageName = u"__"

        if pageName[0] in [unicode(i) for i in range(0, 10)]:
            pageName = u'_' + pageName

        page = Epub3Page(pageName, depth, node)

        self.pages.append(page)
        for child in node.children:
            self.generatePages(child, depth + 1)
Beispiel #29
0
class IMSExport(object):
    """
    Exports an eXe package as a SCORM package
    """
    def __init__(self, config, styleDir, filename):
        """ Initialize
        'styleDir' is the directory from which we will copy our style sheets
        (and some gifs)
        """
        self.config = config
        self.imagesDir = config.webDir / "images"
        self.scriptsDir = config.webDir / "scripts"
        self.cssDir = config.webDir / "css"
        self.templatesDir = config.webDir / "templates"
        self.schemasDir = config.webDir / "schemas/ims"
        self.styleDir = Path(styleDir)
        self.filename = Path(filename)
        self.pages = []

    def export(self, package):
        """ 
        Export SCORM package
        """
        # First do the export to a temporary directory
        outputDir = TempDirPath()

        # Copy the style sheet files to the output dir
        # But not nav.css
        styleFiles = [self.styleDir / '..' / 'base.css']
        styleFiles += [self.styleDir / '..' / 'popup_bg.gif']
        styleFiles += self.styleDir.files("*.css")
        if "nav.css" in styleFiles:
            styleFiles.remove("nav.css")
        styleFiles += self.styleDir.files("*.jpg")
        styleFiles += self.styleDir.files("*.gif")
        styleFiles += self.styleDir.files("*.png")
        styleFiles += self.styleDir.files("*.js")
        styleFiles += self.styleDir.files("*.html")
        styleFiles += self.styleDir.files("*.ttf")
        styleFiles += self.styleDir.files("*.eot")
        styleFiles += self.styleDir.files("*.otf")
        styleFiles += self.styleDir.files("*.woff")
        self.styleDir.copylist(styleFiles, outputDir)

        # copy the package's resource files
        package.resourceDir.copyfiles(outputDir)

        # Export the package content
        self.pages = [IMSPage("index", 1, package.root)]

        self.generatePages(package.root, 2)
        uniquifyNames(self.pages)

        for page in self.pages:
            page.save(outputDir)

        # Create the manifest file
        manifest = Manifest(self.config, outputDir, package, self.pages)
        manifest.save()

        # Copy the scripts - with modification by lernmodule.net
        self.scriptsDir.copylist(
            ('libot_drag.js', 'lernmodule_net.js', 'common.js'), outputDir)

        self.schemasDir.copylist(
            ('imscp_v1p1.xsd', 'imsmd_v1p2p2.xsd', 'ims_xml.xsd'), outputDir)

        # copy players for media idevices.
        hasFlowplayer = False
        hasMagnifier = False
        hasXspfplayer = False
        hasGallery = False
        isBreak = False

        for page in self.pages:
            if isBreak:
                break
            for idevice in page.node.idevices:
                if (hasFlowplayer and hasMagnifier and hasXspfplayer
                        and hasGallery):
                    isBreak = True
                    break
                if not hasFlowplayer:
                    if 'flowPlayer.swf' in idevice.systemResources:
                        hasFlowplayer = True
                if not hasMagnifier:
                    if 'magnifier.swf' in idevice.systemResources:
                        hasMagnifier = True
                if not hasXspfplayer:
                    if 'xspf_player.swf' in idevice.systemResources:
                        hasXspfplayer = True
                if not hasGallery:
                    if 'GalleryIdevice' == idevice.klass:
                        hasGallery = True

        if hasFlowplayer:
            videofile = (self.templatesDir / 'flowPlayer.swf')
            videofile.copyfile(outputDir / 'flowPlayer.swf')
            controlsfile = (self.templatesDir / 'flowplayer.controls.swf')
            controlsfile.copyfile(outputDir / 'flowplayer.controls.swf')
        if hasMagnifier:
            videofile = (self.templatesDir / 'magnifier.swf')
            videofile.copyfile(outputDir / 'magnifier.swf')
        if hasXspfplayer:
            videofile = (self.templatesDir / 'xspf_player.swf')
            videofile.copyfile(outputDir / 'xspf_player.swf')
        if hasGallery:
            imageGalleryCSS = (self.cssDir / 'exe_lightbox.css')
            imageGalleryCSS.copyfile(outputDir / 'exe_lightbox.css')
            imageGalleryJS = (self.scriptsDir / 'exe_lightbox.js')
            imageGalleryJS.copyfile(outputDir / 'exe_lightbox.js')
            self.imagesDir.copylist(
                ('exeGallery_actions.png', 'exeGallery_loading.gif'),
                outputDir)

        if package.license == "GNU Free Documentation License":
            # include a copy of the GNU Free Documentation Licence
            (self.templatesDir / 'fdl.html').copyfile(outputDir / 'fdl.html')
        # Zip it up!
        self.filename.safeSave(
            self.doZip, _('EXPORT FAILED!\nLast succesful export is %s.'),
            outputDir)
        # Clean up the temporary dir
        outputDir.rmtree()

    def doZip(self, fileObj, outputDir):
        """
        Actually does the zipping of the file. Called by 'Path.safeSave'
        """
        zipped = ZipFile(fileObj, "w")
        for scormFile in outputDir.files():
            zipped.write(scormFile,
                         scormFile.basename().encode('utf8'), ZIP_DEFLATED)
        zipped.close()

    def generatePages(self, node, depth):
        """
        Recursive function for exporting a node.
        'outputDir' is the temporary directory that we are exporting to
        before creating zip file
        """
        for child in node.children:
            pageName = child.titleShort.lower().replace(" ", "_")
            pageName = re.sub(r"\W", "", pageName)
            if not pageName:
                pageName = "__"

            page = IMSPage(pageName, depth, child)

            self.pages.append(page)
            self.generatePages(child, depth + 1)