예제 #1
0
 def __init__(self, config, outputDir, package, pages):
     """
     Initialize
     'outputDir' is the directory that we read the html from and also output
     the mainfest.xml 
     """
     self.config = config
     self.outputDir = outputDir
     self.package = package
     self.idGenerator = UniqueIdGenerator(package.name, config.exePath)
     self.pages = pages
     self.itemStr = ""
     self.resStr = ""
예제 #2
0
class TestUniqueId(unittest.TestCase):
    def setUp(self):
        self.generator = UniqueIdGenerator("David's Gen", sys.argv[0])

    def testGenerate(self):
        howMany = 10000
        values = {}
        for x in range(howMany):
            id = self.generator.generate()
            self.assert_(id.isalnum())
            values[id] = 1
        self.assertEqual(howMany, len(values))
예제 #3
0
class TestUniqueId(unittest.TestCase):
    def setUp(self):
        self.generator = UniqueIdGenerator("David's Gen", sys.argv[0])

    def testGenerate(self):
        howMany = 10000
        values  = {}
        for x in range(howMany):
            id = self.generator.generate()
            self.assert_(id.isalnum())
            values[id] = 1
        self.assertEqual(howMany, len(values))
예제 #4
0
 def __init__(self, config, outputDir, package, pages):
     """
     Initialize
     'outputDir' is the directory that we read the html from and also output
     the mainfest.xml 
     """
     self.config       = config
     self.outputDir    = outputDir
     self.package      = package
     self.idGenerator  = UniqueIdGenerator(package.name, config.exePath)
     self.pages        = pages
     self.itemStr      = ""
     self.resStr       = ""
예제 #5
0
파일: scormexport.py 프로젝트: giorgil2/eXe
class Manifest(object):
    """
    Represents an imsmanifest xml file
    """
    def __init__(self, config, outputDir, package, pages, scormType):
        """
        Initialize
        'outputDir' is the directory that we read the html from and also output
        the mainfest.xml 
        """
        self.config       = config
        self.outputDir    = outputDir
        self.package      = package
        self.idGenerator  = UniqueIdGenerator(package.name, config.exePath)
        self.pages        = pages
        self.itemStr      = ""
        self.resStr       = ""
        self.scormType    = scormType
        self.dependencies = {}


    def createMetaData(self, template):
        """
        if user did not supply metadata title, description or creator
        then use package title, description, or creator in imslrm
        if they did not supply a package title, use the package name
        if they did not supply a date, use today
        """
        lrm = self.package.dublinCore.__dict__.copy()
        if lrm.get('title', '') == '':
            lrm['title'] = self.package.title
        if lrm['title'] == '':
            lrm['title'] = self.package.name
        if lrm.get('description', '') == '':
            lrm['description'] = self.package.description
        if lrm['description'] == '':
            lrm['description'] = self.package.name
        if lrm.get('creator', '') == '':
            lrm['creator'] = self.package.author
        if lrm['date'] == '':
            lrm['date'] = time.strftime('%Y-%m-%d')
        # if they don't look like VCARD entries, coerce to fn:
        for f in ('creator', 'publisher', 'contributors'):
            if re.match('.*[:;]', lrm[f]) == None:
                lrm[f] = u'FN:' + lrm[f]
        xml = template % lrm
        return xml

    def save(self, filename):
        """
        Save a imsmanifest file to self.outputDir
        """
        out = open(self.outputDir/filename, "w")
        if filename == "imsmanifest.xml":
            out.write(self.createXML().encode('utf8'))
        out.close()
        if self.scormType == "scorm1.2":
            templateFilename = self.config.xulDir/'templates'/'imslrm.xml'
            template = open(templateFilename, 'rb').read()
            xml = self.createMetaData(template)
            out = open(self.outputDir/'imslrm.xml', 'wb')
            out.write(xml.encode('utf8'))
            out.close()
    
    def createXML(self):
        """
        returning XLM string for manifest file
        """
        manifestId = unicode(self.idGenerator.generate())
        orgId      = unicode(self.idGenerator.generate())
       
        # Add the namespaces 
        
        if self.scormType == "scorm1.2":
            xmlStr  = u'<?xml version="1.0" encoding="UTF-8"?>\n'
            xmlStr += u'<!-- generated by eXe - http://exelearning.org -->\n'
            xmlStr += u'<manifest identifier="'+manifestId+'" '
            xmlStr += u'xmlns="http://www.imsproject.org/xsd/imscp_rootv1p1p2" '
            xmlStr += u'xmlns:adlcp="http://www.adlnet.org/xsd/adlcp_rootv1p2" '
            xmlStr += u'xmlns:imsmd="http://www.imsglobal.org/xsd/imsmd_v1p2" '
            xmlStr += u'xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" '
            xmlStr += u"xsi:schemaLocation=\"http://www.imsproject.org/xsd/"
            xmlStr += u"imscp_rootv1p1p2 imscp_rootv1p1p2.xsd "        
            xmlStr += u"http://www.imsglobal.org/xsd/imsmd_rootv1p2p1 "
            xmlStr += u"imsmd_rootv1p2p1.xsd "
            xmlStr += u"http://www.adlnet.org/xsd/adlcp_rootv1p2 "
            xmlStr += u"adlcp_rootv1p2.xsd\" "
            xmlStr += u"> \n"
            xmlStr += u"<metadata> \n"
            xmlStr += u" <schema>ADL SCORM</schema> \n"
            xmlStr += u" <schemaversion>1.2</schemaversion> \n"
            xmlStr += u" <adlcp:location>imslrm.xml"
            xmlStr += u"</adlcp:location> \n"
            xmlStr += u"</metadata> \n"
        elif self.scormType == "scorm2004":
            xmlStr  = u'<?xml version="1.0" encoding="UTF-8"?>\n'
            xmlStr += u'<!-- generated by eXe - http://exelearning.org -->\n'
            xmlStr += u'<manifest identifier="'+manifestId+'" '
            xmlStr += u'xmlns="http://www.imsproject.org/xsd/imscp_rootv1p1p2" '
            xmlStr += u'xmlns:adlcp="http://www.adlnet.org/xsd/adlcp_rootv1p2" '
            xmlStr += u'xmlns:imsmd="http://www.imsglobal.org/xsd/imsmd_v1p2" '
            xmlStr += u'xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" '
            xmlStr += u"xsi:schemaLocation=\"http://www.imsproject.org/xsd/"
            xmlStr += u"imscp_rootv1p1p2 imscp_rootv1p1p2.xsd "        
            xmlStr += u"http://www.imsglobal.org/xsd/imsmd_rootv1p2p1 "
            xmlStr += u"imsmd_rootv1p2p1.xsd "
            xmlStr += u"http://www.adlnet.org/xsd/adlcp_rootv1p2 "
            xmlStr += u"adlcp_rootv1p2.xsd\" "
            xmlStr += u"> \n"
        elif self.scormType == "commoncartridge":
            xmlStr  = u'''<?xml version="1.0" encoding="UTF-8"?>
<!-- generated by eXe - http://exelearning.org -->
<manifest identifier="%s"
 xmlns="http://www.imsglobal.org/xsd/imscc/imscp_v1p1"
 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
 xsi:schemaLocation="http://www.imsglobal.org/xsd/imscc/imscp_v1p1 imscp_v1p1.xsd">\n''' % manifestId
            templateFilename = self.config.xulDir/'templates'/'cc.xml'
            template = open(templateFilename, 'rb').read()
            xmlStr += self.createMetaData(template)

        # Metadata

        if self.scormType == "commoncartridge":
            xmlStr += u'''<organizations>
  <organization identifier="%s" structure="rooted-hierarchy">
    <item identifier="eXeCC-%s">\n''' % (orgId,
            unicode(self.idGenerator.generate()))
        else:
            xmlStr += u"<organizations default=\""+orgId+"\">  \n"
            xmlStr += u'  <organization identifier="%s" structure="hierarchical">\n' % orgId

            if self.package.title != '':
                title = escape(self.package.title)
            else:
                title  = escape(self.package.root.titleShort)
            xmlStr += u"<title>"+title+"</title>\n"
        
        if self.scormType == "commoncartridge":
            # FIXME flatten hierarchy
            for page in self.pages:
                self.genItemResStr(page)
                self.itemStr += "</item>\n"
        else:
            depth = 0
            for page in self.pages:
                while depth >= page.depth:
                    self.itemStr += "</item>\n"
                    depth -= 1
                self.genItemResStr(page)
                depth = page.depth

            while depth >= 1:
                self.itemStr += "</item>\n"
                depth -= 1

        xmlStr += self.itemStr
        if self.scormType == "commoncartridge":
            xmlStr += "    </item>\n"
        xmlStr += "  </organization>\n"
        xmlStr += "</organizations>\n"
        xmlStr += "<resources>\n"
        xmlStr += self.resStr
        xmlStr += "</resources>\n"
        xmlStr += "</manifest>\n"
        return xmlStr
        
            
    def genItemResStr(self, page):
        """
        Returning xml string for items and resources
        """
        itemId   = "ITEM-"+unicode(self.idGenerator.generate())
        resId    = "RES-"+unicode(self.idGenerator.generate())
        filename = page.name+".html"
            
        
        self.itemStr += '<item identifier="'+itemId+'" '
        if self.scormType != "commoncartridge":
            self.itemStr += 'isvisible="true" '
        self.itemStr += 'identifierref="'+resId+'">\n'
        self.itemStr += "    <title>"
        self.itemStr += escape(page.node.titleShort)
        self.itemStr += "</title>\n"
        
        self.resStr += "  <resource identifier=\""+resId+"\" "
        self.resStr += "type=\"webcontent\" "

        # FIXME force dependency on popup_bg.gif on every page
        # because it isn't a "resource" so we can't tell which
        # pages will use it from content.css
        if self.scormType == "commoncartridge":
            self.resStr += """href="%s">
    <file href="%s"/>
    <file href="base.css"/>
    <file href="content.css"/>
    <file href="popup_bg.gif"/>""" % (filename, filename)
            if page.node.package.backgroundImg:
                self.resStr += '\n    <file href="%s"/>' % \
                        page.node.package.backgroundImg.basename()
            self.dependencies["base.css"] = True
            self.dependencies["content.css"] = True
            self.dependencies["popup_bg.gif"] = True
        else:
            self.resStr += "adlcp:scormtype=\"sco\" "
            self.resStr += "href=\""+filename+"\"> \n"
            self.resStr += """\
    <file href="%s"/>
    <file href="base.css"/>
    <file href="content.css"/>
    <file href="popup_bg.gif"/>
    <file href="APIWrapper.js"/>
    <file href="SCOFunctions.js"/>""" % filename
        self.resStr += "\n"
        fileStr = ""

        for resource in page.node.getResources():            
            fileStr += "    <file href=\""+escape(resource)+"\"/>\n"
            self.dependencies[resource] = True

        self.resStr += fileStr
        self.resStr += "  </resource>\n"
예제 #6
0
class Manifest(object):
    """
    Represents an imsmanifest xml file
    """
    def __init__(self, config, outputDir, package, pages, metadataType):
        """
        Initialize
        'outputDir' is the directory that we read the html from and also output
        the mainfest.xml
        """
        self.config       = config
        self.outputDir    = outputDir
        self.package      = package
        self.idGenerator  = UniqueIdGenerator(package.name, config.exePath)
        self.pages        = pages
        self.metadataType = metadataType
        self.itemStr      = ""
        self.resStr       = ""


    def createMetaData(self):
        """
        if user did not supply metadata title, description or creator
        then use package title, description, or creator in imslrm
        if they did not supply a package title, use the package name
        if they did not supply a date, use today
        """
        xml = ''
        namespace = 'lom:'
        # depending on (user desired) the metadata type:
        if self.metadataType == 'LOMES':
            output = StringIO.StringIO()
            metadata = copy.deepcopy(self.package.lomEs)
            title = metadata.get_general().get_title() or lomsubs.titleSub([])
            if not title.get_string():
                title.add_string(lomsubs.LangStringSub(self.package.lang.encode('utf-8'), self.package.name))
                metadata.get_general().set_title(title)
            if self.package.exportSource:
                technical = metadata.get_technical()
                if not technical:
                    technical = lomsubs.technicalSub('technical')
                    metadata.set_technical(technical)
                opr = technical.get_otherPlatformRequirements()
                if not opr:
                    opr = lomsubs.otherPlatformRequirementsSub()
                    technical.set_otherPlatformRequirements(opr)
                found = False
                for platform in opr.get_string():
                    if platform.get_valueOf_() == self.package.lomESPlatformMark:
                        found = True
                if not found:
                    opr.add_string(lomsubs.LangStringSub(self.package.lang.encode('utf-8'), self.package.lomESPlatformMark))
            metadata.export(output, 0, namespace_=namespace, pretty_print=False)
            xml = output.getvalue()
        if self.metadataType == 'LOM':
            output = StringIO.StringIO()
            metadata = copy.deepcopy(self.package.lom)
            title = metadata.get_general().get_title() or lomsubs.titleSub([])
            if not title.get_string():
                title.add_string(lomsubs.LangStringSub(self.package.lang.encode('utf-8'), self.package.name))
                metadata.get_general().set_title(title)
            metadata.export(output, 0, namespace_=namespace, pretty_print=False)
            xml = output.getvalue()
        if self.metadataType == 'DC':
            lrm = self.package.dublinCore.__dict__.copy()
            # use package values in absentia:
            if lrm.get('title', '') == '':
                lrm['title'] = self.package.title
            if lrm['title'] == '':
                lrm['title'] = self.package.name
            if lrm.get('description', '') == '':
                lrm['description'] = self.package.description
            if lrm['description'] == '':
                lrm['description'] = self.package.name
            if lrm.get('creator', '') == '':
                lrm['creator'] = self.package.author
            if lrm['date'] == '':
                lrm['date'] = time.strftime('%Y-%m-%d')
            # if they don't look like VCARD entries, coerce to fn:
            for f in ('creator', 'publisher', 'contributors'):
                if re.match('.*[:;]', lrm[f]) == None:
                    lrm[f] = u'FN:' + lrm[f]
            templateFilename = self.config.webDir/'templates'/'imslrm.xml'
            template = open(templateFilename, 'rb').read()
            xml = template % lrm
            out = open(self.outputDir/'imslrm.xml', 'wb')
            out.write(xml.encode('utf8'))
            out.close()
            xml = '<adlcp:location>imslrm.xml</adlcp:location>'
        return xml


    def save(self, filename):
        """
        Save a imsmanifest file to self.outputDir
        """
        out = open(self.outputDir/filename, "w")
        if filename == "imsmanifest.xml":
            out.write(self.createXML().encode('utf8'))
        out.close()


    def createXML(self):
        """
        returning XLM string for manifest file
        """
        manifestId = self.idGenerator.generate()
        orgId      = self.idGenerator.generate()

        xmlStr = u"""<?xml version="1.0" encoding="UTF-8"?>
        <!-- Generated by eXe - http://exelearning.net -->
        <manifest identifier="%s"
        xmlns="http://www.imsglobal.org/xsd/imscp_v1p1"
        xmlns:imsmd="http://www.imsglobal.org/xsd/imsmd_v1p2"
        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xmlns:lom="http://ltsc.ieee.org/xsd/LOM"
        """ % manifestId
        xmlStr += "\n "
        xmlStr += "xsi:schemaLocation=\"http://www.imsglobal.org/xsd/"
        xmlStr += "imscp_v1p1 imscp_v1p1.xsd "
        xmlStr += "http://www.imsglobal.org/xsd/imsmd_v1p2 imsmd_v1p2p2.xsd\""
        xmlStr += "> \n"
        xmlStr += "<metadata> \n"
        xmlStr += " <schema>IMS Content</schema> \n"
        xmlStr += " <schemaversion>1.1.3</schemaversion> \n"
        xmlStr += " %(metadata)s\n"
        xmlStr += "</metadata> \n"
        xmlStr += "<organizations default=\""+orgId+"\">  \n"
        xmlStr += "<organization identifier=\""+orgId
        xmlStr += "\" structure=\"hierarchical\">  \n"

        xmlStr = xmlStr % {'metadata': self.createMetaData()}
        if self.package.title != '':
            title = escape(self.package.title)
        else:
            title  = escape(self.package.root.titleShort)
        xmlStr += u"<title>"+title+"</title>\n"

        depth = 0
        for page in self.pages:
            while depth >= page.depth:
                self.itemStr += "</item>\n"
                depth -= 1
            self.genItemResStr(page)
            depth = page.depth

        while depth >= 1:
            self.itemStr += "</item>\n"
            depth -= 1

        xmlStr += self.itemStr
        xmlStr += "</organization>\n"
        xmlStr += "</organizations>\n"
        xmlStr += "<resources>\n"
        xmlStr += self.resStr
        xmlStr += "</resources>\n"
        xmlStr += "</manifest>\n"
        return xmlStr


    def genItemResStr(self, page):
        """
        Returning xml string for items and resources
        """
        itemId   = "ITEM-"+unicode(self.idGenerator.generate())
        resId    = "RES-"+unicode(self.idGenerator.generate())
        # If ISO9660 compatible mode is active, we want '.htm' as the extension
        ext = 'html'
        if G.application.config.cutFileName == '1':
            ext = 'htm'

        filename = page.name + '.' + ext


        self.itemStr += "<item identifier=\""+itemId+"\" isvisible=\"true\" "
        self.itemStr += "identifierref=\""+resId+"\">\n"
        self.itemStr += "    <title>"
        self.itemStr += escape(page.node.titleShort)
        self.itemStr += "</title>\n"

        self.resStr += "<resource identifier=\""+resId+"\" "
        self.resStr += "type=\"webcontent\" "

        self.resStr += "href=\""+filename+"\"> \n"
        self.resStr += """\
    <file href="%s"/>
    <file href="base.css"/>
    <file href="content.css"/>""" % filename
        self.resStr += "\n"
        fileStr = ""

        dT = common.getExportDocType()
        if dT == "HTML5" or common.nodeHasMediaelement(page.node):
            self.resStr += '    <file href="exe_html5.js"/>\n'

        resources = page.node.getResources()
        my_style = G.application.config.styleStore.getStyle(page.node.package.style)
        if common.nodeHasMediaelement(page.node):
            resources = resources + [f.basename() for f in (self.config.webDir/"scripts"/'mediaelement').files()]
        if common.nodeHasTooltips(page.node):
            resources = resources + [f.basename() for f in (self.config.webDir/"scripts"/'exe_tooltips').files()]
        if common.hasGalleryIdevice(page.node):
            resources = resources + [f.basename() for f in (self.config.webDir/"scripts"/'exe_lightbox').files()]
        if common.hasFX(page.node):
            resources = resources + [f.basename() for f in (self.config.webDir/"scripts"/'exe_effects').files()]
        if common.hasSH(page.node):
            resources = resources + [f.basename() for f in (self.config.webDir/"scripts"/'exe_highlighter').files()]
        if common.hasGames(page.node):
            resources = resources + [f.basename() for f in (self.config.webDir/"scripts"/'exe_games').files()]
        if common.hasABCMusic(page.node):
            resources = resources + [f.basename() for f in (self.config.webDir/"scripts"/'tinymce_4'/'js'/'tinymce'/'plugins'/'abcmusic'/'export').files()]
        if my_style.hasValidConfig():
            if my_style.get_jquery() == True:
                self.resStr += '    <file href="exe_jquery.js"/>\n'
        else:
            self.resStr += '    <file href="exe_jquery.js"/>\n'

        for resource in resources:
            fileStr += "    <file href=\""+escape(resource)+"\"/>\n"

        if common.hasElpLink(page.node):
            fileStr += "    <file href=\""+page.node.package.name+".elp\"/>\n"

        # Get all JS iDevices resources
        fileStr += common.getJavascriptIdevicesResources(page, xmlOutput = True)

        self.resStr += fileStr
        self.resStr += "</resource>\n"
예제 #7
0
class Manifest(object):
    """
    Represents an imsmanifest xml file
    """
    def __init__(self, config, outputDir, package, pages, metadataType):
        """
        Initialize
        'outputDir' is the directory that we read the html from and also output
        the mainfest.xml 
        """
        self.config       = config
        self.outputDir    = outputDir
        self.package      = package
        self.idGenerator  = UniqueIdGenerator(package.name, config.exePath)
        self.pages        = pages
        self.metadataType = metadataType
        self.itemStr      = ""
        self.resStr       = ""


    def createMetaData(self):
        """
        if user did not supply metadata title, description or creator
        then use package title, description, or creator in imslrm
        if they did not supply a package title, use the package name
        if they did not supply a date, use today
        """
        xml = ''
        namespace = 'lom:'
        # depending on (user desired) the metadata type:
        if self.metadataType == 'LOMES':
            output = StringIO.StringIO()
            metadata = copy.deepcopy(self.package.lomEs)
            title = metadata.get_general().get_title() or lomsubs.titleSub([])
            if not title.get_string():
                title.add_string(lomsubs.LangStringSub(self.package.lang.encode('utf-8'), self.package.name))
                metadata.get_general().set_title(title)
            metadata.export(output, 0, namespace_=namespace, pretty_print=False)
            xml = output.getvalue()
        if self.metadataType == 'LOM':
            output = StringIO.StringIO()
            metadata = copy.deepcopy(self.package.lom)
            title = metadata.get_general().get_title() or lomsubs.titleSub([])
            if not title.get_string():
                title.add_string(lomsubs.LangStringSub(self.package.lang.encode('utf-8'), self.package.name))
                metadata.get_general().set_title(title)
            metadata.export(output, 0, namespace_=namespace, pretty_print=False)
            xml = output.getvalue()
        if self.metadataType == 'DC':
            lrm = self.package.dublinCore.__dict__.copy()
            # use package values in absentia:
            if lrm.get('title', '') == '':
                lrm['title'] = self.package.title
            if lrm['title'] == '':
                lrm['title'] = self.package.name
            if lrm.get('description', '') == '':
                lrm['description'] = self.package.description
            if lrm['description'] == '':
                lrm['description'] = self.package.name
            if lrm.get('creator', '') == '':
                lrm['creator'] = self.package.author
            if lrm['date'] == '':
                lrm['date'] = time.strftime('%Y-%m-%d')
            # if they don't look like VCARD entries, coerce to fn:
            for f in ('creator', 'publisher', 'contributors'):
                if re.match('.*[:;]', lrm[f]) == None:
                    lrm[f] = u'FN:' + lrm[f]
            templateFilename = self.config.webDir/'templates'/'imslrm.xml'
            template = open(templateFilename, 'rb').read()
            xml = template % lrm
            out = open(self.outputDir/'imslrm.xml', 'wb')
            out.write(xml.encode('utf8'))
            out.close()
            xml = '<adlcp:location>imslrm.xml</adlcp:location>'
        return xml


    def save(self, filename):
        """
        Save a imsmanifest file to self.outputDir
        """
        out = open(self.outputDir/filename, "w")
        if filename == "imsmanifest.xml":
            out.write(self.createXML().encode('utf8'))
        out.close()


    def createXML(self):
        """
        returning XLM string for manifest file
        """
        manifestId = self.idGenerator.generate()
        orgId      = self.idGenerator.generate()
        
        xmlStr = u"""<?xml version="1.0" encoding="UTF-8"?>
        <!-- Generated by eXe - http://exelearning.net -->
        <manifest identifier="%s" 
        xmlns="http://www.imsglobal.org/xsd/imscp_v1p1"
        xmlns:imsmd="http://www.imsglobal.org/xsd/imsmd_v1p2" 
        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xmlns:lom="http://ltsc.ieee.org/xsd/LOM"
        """ % manifestId 
        xmlStr += "\n "
        xmlStr += "xsi:schemaLocation=\"http://www.imsglobal.org/xsd/"
        xmlStr += "imscp_v1p1 imscp_v1p1.xsd "        
        xmlStr += "http://www.imsglobal.org/xsd/imsmd_v1p2 imsmd_v1p2p2.xsd\""
        xmlStr += "> \n"
        xmlStr += "<metadata> \n"
        xmlStr += " <schema>IMS Content</schema> \n"
        xmlStr += " <schemaversion>1.1.3</schemaversion> \n"
        xmlStr += " %(metadata)s\n" 
        xmlStr += "</metadata> \n"
        xmlStr += "<organizations default=\""+orgId+"\">  \n"
        xmlStr += "<organization identifier=\""+orgId
        xmlStr += "\" structure=\"hierarchical\">  \n"

        xmlStr = xmlStr % {'metadata': self.createMetaData()}
        if self.package.title != '':
            title = escape(self.package.title)
        else:
            title  = escape(self.package.root.titleShort)
        xmlStr += u"<title>"+title+"</title>\n"
        
        depth = 0
        for page in self.pages:
            while depth >= page.depth:
                self.itemStr += "</item>\n"
                depth -= 1
            self.genItemResStr(page)
            depth = page.depth

        while depth >= 1:
            self.itemStr += "</item>\n"
            depth -= 1

        xmlStr += self.itemStr
        xmlStr += "</organization>\n"
        xmlStr += "</organizations>\n"
        xmlStr += "<resources>\n"
        xmlStr += self.resStr
        xmlStr += "</resources>\n"
        xmlStr += "</manifest>\n"
        return xmlStr
        
            
    def genItemResStr(self, page):
        """
        Returning xml string for items and resources
        """
        itemId   = "ITEM-"+unicode(self.idGenerator.generate())
        resId    = "RES-"+unicode(self.idGenerator.generate())
        filename = page.name+".html"
            
        
        self.itemStr += "<item identifier=\""+itemId+"\" isvisible=\"true\" "
        self.itemStr += "identifierref=\""+resId+"\">\n"
        self.itemStr += "    <title>"
        self.itemStr += escape(page.node.titleShort)
        self.itemStr += "</title>\n"
        
        self.resStr += "<resource identifier=\""+resId+"\" "
        self.resStr += "type=\"webcontent\" "

        self.resStr += "href=\""+filename+"\"> \n"
        self.resStr += """\
    <file href="%s"/>
    <file href="base.css"/>
    <file href="content.css"/>""" % filename
        self.resStr += "\n"
        fileStr = ""
        
        dT = common.getExportDocType()
        if dT == "HTML5" or common.nodeHasMediaelement(page.node):
            self.resStr += '    <file href="exe_html5.js"/>\n'

        resources = page.node.getResources()
        my_style = G.application.config.styleStore.getStyle(page.node.package.style)
        if common.nodeHasMediaelement(page.node):
            resources = resources + [f.basename() for f in (self.config.webDir/"scripts"/'mediaelement').files()]
        if common.nodeHasTooltips(page.node):
            resources = resources + [f.basename() for f in (self.config.webDir/"scripts"/'exe_tooltips').files()]
        if common.hasGalleryIdevice(page.node):
            resources = resources + [f.basename() for f in (self.config.webDir/"scripts"/'exe_lightbox').files()]
        if common.hasFX(page.node):
            resources = resources + [f.basename() for f in (self.config.webDir/"scripts"/'exe_effects').files()]
        if common.hasSH(page.node):
            resources = resources + [f.basename() for f in (self.config.webDir/"scripts"/'exe_highlighter').files()]
        if common.hasGames(page.node):
            resources = resources + [f.basename() for f in (self.config.webDir/"scripts"/'exe_games').files()]
        if my_style.hasValidConfig:
            if my_style.get_jquery() == True:
                self.resStr += '    <file href="exe_jquery.js"/>\n'
        else:
            self.resStr += '    <file href="exe_jquery.js"/>\n'

        for resource in resources:
            fileStr += "    <file href=\""+escape(resource)+"\"/>\n"

        self.resStr += fileStr
        self.resStr += "</resource>\n"
예제 #8
0
파일: scormexport.py 프로젝트: RichDijk/eXe
class Manifest(object):
    """
    Represents an imsmanifest xml file
    """

    def __init__(self, config, outputDir, package, pages, scormType, metadataType):
        """
        Initialize
        'outputDir' is the directory that we read the html from and also output
        the mainfest.xml 
        """
        self.config = config
        self.outputDir = outputDir
        self.package = package
        self.idGenerator = UniqueIdGenerator(package.name, config.exePath)
        self.pages = pages
        self.itemStr = ""
        self.resStr = ""
        self.scormType = scormType
        self.metadataType = metadataType
        self.dependencies = {}

    def createMetaData(self, template):
        """
        if user did not supply metadata title, description or creator
        then use package title, description, or creator in imslrm
        if they did not supply a package title, use the package name
        if they did not supply a date, use today
        """
        xml = '<?xml version="1.0" encoding="UTF-8"?>\n'
        namespace = 'xmlns="http://ltsc.ieee.org/xsd/LOM" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://ltsc.ieee.org/xsd/LOM lomCustom.xsd"'
        # depending on (user desired) the metadata type:
        if self.metadataType == "LOMES":
            output = StringIO.StringIO()
            metadata = copy.deepcopy(self.package.lomEs)
            title = metadata.get_general().get_title() or lomsubs.titleSub([])
            if not title.get_string():
                title.add_string(lomsubs.LangStringSub(self.package.lang.encode("utf-8"), self.package.name))
                metadata.get_general().set_title(title)
            metadata.export(output, 0, namespacedef_=namespace, pretty_print=False)
            xml += output.getvalue()
        if self.metadataType == "LOM":
            output = StringIO.StringIO()
            metadata = copy.deepcopy(self.package.lom)
            title = metadata.get_general().get_title() or lomsubs.titleSub([])
            if not title.get_string():
                title.add_string(lomsubs.LangStringSub(self.package.lang.encode("utf-8"), self.package.name))
                metadata.get_general().set_title(title)
            metadata.export(output, 0, namespacedef_=namespace, pretty_print=False)
            xml += output.getvalue()
        if self.metadataType == "DC":
            lrm = self.package.dublinCore.__dict__.copy()
            # use package values in absentia:
            if lrm.get("title", "") == "":
                lrm["title"] = self.package.title
            if lrm["title"] == "":
                lrm["title"] = self.package.name
            if lrm.get("description", "") == "":
                lrm["description"] = self.package.description
            if lrm["description"] == "":
                lrm["description"] = self.package.name
            if lrm.get("creator", "") == "":
                lrm["creator"] = self.package.author
            if lrm["date"] == "":
                lrm["date"] = time.strftime("%Y-%m-%d")
            # if they don't look like VCARD entries, coerce to fn:
            for f in ("creator", "publisher", "contributors"):
                if re.match(".*[:;]", lrm[f]) == None:
                    lrm[f] = u"FN:" + lrm[f]
            xml = template % lrm
        return xml

    def save(self, filename):
        """
        Save a imsmanifest file to self.outputDir
        Two works: createXML and createMetaData
        """
        out = open(self.outputDir / filename, "w")
        if filename == "imsmanifest.xml":
            out.write(self.createXML().encode("utf8"))
        out.close()
        # now depending on metadataType, <metadata> content is diferent:
        if self.scormType == "scorm1.2" or self.scormType == "scorm2004":
            if self.metadataType == "DC":
                # if old template is desired, select imslrm.xml file:\r
                # anything else, yoy should select:
                templateFilename = self.config.webDir / "templates" / "imslrm.xml"
                template = open(templateFilename, "rb").read()
            elif self.metadataType == "LOMES":
                template = None
            elif self.metadataType == "LOM":
                template = None
            # Now the file with metadatas.
            # Notice that its name is independent of metadataType:
            xml = self.createMetaData(template)
            out = open(self.outputDir / "imslrm.xml", "wb")
            out.write(xml.encode("utf8"))
            out.close()

    def createXML(self):
        """
        returning XLM string for manifest file
        """
        manifestId = unicode(self.idGenerator.generate())
        orgId = unicode(self.idGenerator.generate())

        # Add the namespaces

        if self.scormType == "scorm1.2":
            xmlStr = u'<?xml version="1.0" encoding="UTF-8"?>\n'
            xmlStr += u"<!-- Generated by eXe - http://exelearning.net -->\n"
            xmlStr += u'<manifest identifier="' + manifestId + '" '
            xmlStr += u'xmlns="http://www.imsproject.org/xsd/imscp_rootv1p1p2" '
            xmlStr += u'xmlns:adlcp="http://www.adlnet.org/xsd/adlcp_rootv1p2" '
            xmlStr += u'xmlns:imsmd="http://www.imsglobal.org/xsd/imsmd_v1p2" '
            xmlStr += u'xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" '
            xmlStr += u'xsi:schemaLocation="http://www.imsproject.org/xsd/'
            xmlStr += u"imscp_rootv1p1p2 imscp_rootv1p1p2.xsd "
            xmlStr += u"http://www.imsglobal.org/xsd/imsmd_rootv1p2p1 "
            xmlStr += u"imsmd_rootv1p2p1.xsd "
            xmlStr += u"http://www.adlnet.org/xsd/adlcp_rootv1p2 "
            xmlStr += u'adlcp_rootv1p2.xsd" '
            xmlStr += u"> \n"
            xmlStr += u"<metadata> \n"
            xmlStr += u" <schema>ADL SCORM</schema> \n"
            xmlStr += u" <schemaversion>1.2</schemaversion> \n"
            xmlStr += u" <adlcp:location>imslrm.xml"
            xmlStr += u"</adlcp:location> \n"
            xmlStr += u"</metadata> \n"
        elif self.scormType == "scorm2004":
            xmlStr = u'<?xml version="1.0" encoding="UTF-8"?>\n'
            xmlStr += u"<!-- Generated by eXe - http://exelearning.net -->\n"
            xmlStr += u'<manifest identifier="' + manifestId + '" \n'
            xmlStr += u'xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" \n'
            xmlStr += u'xmlns:adlcp="http://www.adlnet.org/xsd/adlcp_v1p3" \n'
            xmlStr += u'xmlns:adlseq="http://www.adlnet.org/xsd/adlseq_v1p3" \n'
            xmlStr += u'xmlns:adlnav="http://www.adlnet.org/xsd/adlnav_v1p3" \n'
            xmlStr += u'xmlns:imsss="http://www.imsglobal.org/xsd/imsss" \n'
            xmlStr += u'xmlns:lom="http://ltsc.ieee.org/xsd/LOM" \n'
            xmlStr += u'xmlns:lomes="http://ltsc.ieee.org/xsd/LOM" \n'
            xmlStr += u'xmlns="http://www.imsglobal.org/xsd/imscp_v1p1" \n'
            xmlStr += u'xsi:schemaLocation="http://www.imsglobal.org/xsd/imscp_v1p1 imscp_v1p1.xsd '
            xmlStr += u"http://ltsc.ieee.org/xsd/LOM lomCustom.xsd "
            xmlStr += u"http://www.adlnet.org/xsd/adlcp_v1p3 adlcp_v1p3.xsd  "
            xmlStr += u"http://www.imsglobal.org/xsd/imsss imsss_v1p0.xsd  "
            xmlStr += u"http://www.adlnet.org/xsd/adlseq_v1p3 adlseq_v1p3.xsd "
            xmlStr += u"http://www.adlnet.org/xsd/adlnav_v1p3 adlnav_v1p3.xsd"
            xmlStr += u'"> \n'
            xmlStr += u"<metadata> \n"
            xmlStr += u" <schema>ADL SCORM</schema> \n"
            xmlStr += u" <schemaversion>2004 3rd Edition</schemaversion> \n"
            xmlStr += u" <adlcp:location>imslrm.xml"
            xmlStr += u"</adlcp:location> \n"
            xmlStr += u"</metadata> \n"
        elif self.scormType == "commoncartridge":
            xmlStr = (
                u"""<?xml version="1.0" encoding="UTF-8"?>
<!-- generated by eXe - http://exelearning.net -->
<manifest identifier="%s"
xmlns="http://www.imsglobal.org/xsd/imscc/imscp_v1p1"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.imsglobal.org/xsd/imscc/imscp_v1p1 imscp_v1p1.xsd">\n"""
                % manifestId
            )
            templateFilename = self.config.webDir / "templates" / "cc.xml"
            template = open(templateFilename, "rb").read()
            xmlStr += self.createMetaData(template)

        # ORGANIZATION

        if self.scormType == "commoncartridge":
            xmlStr += u"""<organizations>
    <organization identifier="%s" structure="rooted-hierarchy">
    <item identifier="eXeCC-%s">\n""" % (
                orgId,
                unicode(self.idGenerator.generate()),
            )
        else:
            xmlStr += u'<organizations default="' + orgId + '">  \n'
            xmlStr += u'    <organization identifier="%s" structure="hierarchical">\n' % orgId

            if self.package.title != "":
                title = escape(self.package.title)
            else:
                title = escape(self.package.root.titleShort)
            xmlStr += u"        <title>" + title + "</title>\n"

        if self.scormType == "commoncartridge":
            # FIXME flatten hierarchy
            for page in self.pages:
                self.genItemResStr(page)
                self.itemStr += " </item>\n"
            self.itemStr += "    </item>\n"
        else:
            depth = 0
            for page in self.pages:
                while depth >= page.depth:
                    self.itemStr += "</item>\n"
                    if depth > page.depth and self.scormType == "scorm2004":
                        self.itemStr += """  <imsss:sequencing>
    <imsss:controlMode choice="true" choiceExit="true" flow="true" forwardOnly="false"/>
  </imsss:sequencing>"""
                    depth -= 1
                if page.node.children and self.scormType == "scorm2004":
                    # Add fake node with original title
                    itemId = "ITEM-" + unicode(self.idGenerator.generate())
                    self.itemStr += '<item identifier="' + itemId + '" '
                    self.itemStr += 'isvisible="true">\n'
                    self.itemStr += "    <title>"
                    self.itemStr += escape(page.node.titleShort)
                    self.itemStr += "</title>\n"

                    # Increase actual depth because fake node added. Next iteration closes the fake node
                    depth = page.depth + 1
                else:
                    depth = page.depth
                self.genItemResStr(page)

            while depth >= 1:
                self.itemStr += "</item>\n"
                if depth > 1 and self.scormType == "scorm2004":
                    self.itemStr += """  <imsss:sequencing>
    <imsss:controlMode choice="true" choiceExit="true" flow="true" forwardOnly="false"/>
  </imsss:sequencing>"""
                depth -= 1

        xmlStr += self.itemStr

        if self.scormType == "scorm2004":
            xmlStr += """  <imsss:sequencing>
    <imsss:controlMode choice="true" choiceExit="true" flow="true" forwardOnly="false"/>
  </imsss:sequencing>"""
        xmlStr += "  </organization>\n"
        xmlStr += "</organizations>\n"

        # RESOURCES

        xmlStr += "<resources>\n"
        xmlStr += self.resStr

        # If NOT commoncartridge, finally, special resource with
        # all the common files, as binded with de active style ones:
        if self.scormType != "commoncartridge":
            if self.scormType == "scorm1.2":
                xmlStr += """  <resource identifier="COMMON_FILES" type="webcontent" adlcp:scormtype="asset">\n"""
            else:
                xmlStr += """  <resource identifier="COMMON_FILES" type="webcontent" adlcp:scormType="asset">\n"""
            my_style = G.application.config.styleStore.getStyle(page.node.package.style)
            for x in my_style.get_style_dir().files("*.*"):
                xmlStr += """    <file href="%s"/>\n""" % x.basename()
            # we do want base.css and (for short time), popup_bg.gif, also:
            xmlStr += """    <file href="base.css"/>\n"""
            xmlStr += """    <file href="popup_bg.gif"/>\n"""
            # now the javascript files:
            xmlStr += """    <file href="SCORM_API_wrapper.js"/>\n"""
            xmlStr += """    <file href="SCOFunctions.js"/>\n"""
            if my_style.hasValidConfig:
                if my_style.get_jquery() == True:
                    xmlStr += """    <file href="exe_jquery.js"/>\n"""
            else:
                xmlStr += """    <file href="exe_jquery.js"/>\n"""
            xmlStr += "  </resource>\n"

        # no more resources:
        xmlStr += "</resources>\n"
        xmlStr += "</manifest>\n"
        return xmlStr

    def genItemResStr(self, page):
        """
        Returning xml string for items and resources
        """
        itemId = "ITEM-" + unicode(self.idGenerator.generate())
        resId = "RES-" + unicode(self.idGenerator.generate())
        filename = page.name + ".html"

        self.itemStr += '<item identifier="' + itemId + '" '
        if self.scormType != "commoncartridge":
            self.itemStr += 'isvisible="true" '
        self.itemStr += 'identifierref="' + resId + '">\n'
        self.itemStr += "    <title>"
        if self.scormType == "scorm2004" and page.node.children:
            self.itemStr += escape("<-")
        else:
            self.itemStr += escape(page.node.titleShort)
        self.itemStr += "</title>\n"

        ## RESOURCES

        self.resStr += '  <resource identifier="' + resId + '" '
        self.resStr += 'type="webcontent" '

        # FIXME force dependency on popup_bg.gif on every page
        # because it isn't a "resource" so we can't tell which
        # pages will use it from content.css
        if self.scormType == "commoncartridge":
            fileStr = ""
            self.resStr += """href="%s">
    <file href="%s"/>
    <file href="base.css"/>
    <file href="content.css"/>
    <file href="popup_bg.gif"/>
    <file href="exe_jquery.js"/>
    <file href="common.js"/>""" % (
                filename,
                filename,
            )
            # CC export require content.* any place inside the manifest:
            if page.node.package.exportSource and page.depth == 1:
                self.resStr += '    <file href="content.xsd"/>\n'
                self.resStr += '    <file href="content.data"/>\n'
                self.resStr += '    <file href="contentv3.xml"/>\n'
            if page.node.package.backgroundImg:
                self.resStr += '\n    <file href="%s"/>' % page.node.package.backgroundImg.basename()
            self.dependencies["base.css"] = True
            self.dependencies["content.css"] = True
            self.dependencies["popup_bg.gif"] = True
        else:
            if self.scormType == "scorm2004":
                self.resStr += 'adlcp:scormType="sco" '
                self.resStr += 'href="' + filename + '"> \n'
                self.resStr += '    <file href="' + filename + '"/> \n'
                fileStr = ""
            if self.scormType == "scorm1.2":
                self.resStr += 'adlcp:scormtype="sco" '
                self.resStr += 'href="' + filename + '"> \n'
                self.resStr += '    <file href="' + filename + '"/> \n'
                fileStr = ""

        dT = common.getExportDocType()
        if dT == "HTML5" or common.nodeHasMediaelement(page.node):
            self.resStr += '    <file href="exe_html5.js"/>\n'

        resources = page.node.getResources()

        if common.nodeHasMediaelement(page.node):
            resources = resources + [f.basename() for f in (self.config.webDir / "scripts" / "mediaelement").files()]
            if dT != "HTML5":
                self.scriptsDir = self.config.webDir / "scripts"
                jsFile = self.scriptsDir / "exe_html5.js"
                jsFile.copyfile(self.outputDir / "exe_html5.js")

        if common.hasGalleryIdevice(page.node):
            self.resStr += "\n"
            self.resStr += '    <file href="exe_lightbox.js"/>\n'
            self.resStr += '    <file href="exe_lightbox.css"/>\n'
            self.resStr += '    <file href="exe_lightbox_close.png"/>\n'
            self.resStr += '    <file href="exe_lightbox_loading.gif"/>\n'
            self.resStr += '    <file href="exe_lightbox_next.png"/>\n'
            self.resStr += '    <file href="exe_lightbox_prev.png"/>\n'

        for resource in resources:
            fileStr += '    <file href="' + escape(resource) + '"/>\n'
            self.dependencies[resource] = True

        self.resStr += fileStr

        # adding the dependency with the common files collected:
        if self.scormType != "commoncartridge":
            self.resStr += """    <dependency identifierref="COMMON_FILES"/>"""

        # and no more:
        self.resStr += "\n"
        self.resStr += "  </resource>\n"
예제 #9
0
 def setUp(self):
     self.generator = UniqueIdGenerator("David's Gen", sys.argv[0])
예제 #10
0
class Manifest(object):
    """
    Represents an imsmanifest xml file
    """

    def __init__(self, config, outputDir, package, pages, scormType):
        """
        Initialize
        'outputDir' is the directory that we read the html from and also output
        the mainfest.xml 
        """
        self.config = config
        self.outputDir = outputDir
        self.package = package
        self.idGenerator = UniqueIdGenerator(package.name, config.exePath)
        self.pages = pages
        self.itemStr = ""
        self.resStr = ""
        self.scormType = scormType

    def createMetaData(self, template):
        lrm = self.package.dublinCore.__dict__.copy()
        if lrm.get("title", "") == "":
            lrm["title"] = self.package.title
        if lrm["title"] == "":
            lrm["title"] = self.package.name
        if lrm.get("description", "") == "":
            lrm["description"] = self.package.description
        if lrm["description"] == "":
            lrm["description"] = self.package.name
        if lrm.get("creator", "") == "":
            lrm["creator"] = self.package.author
        for f in ("creator", "publisher", "contributors"):
            if re.match(".*[:;]", lrm[f]) == None:
                lrm[f] = u"FN:" + lrm[f]
        xml = template % lrm
        return xml

    def save(self, filename):
        """
        Save a imsmanifest file to self.outputDir
        """
        out = open(self.outputDir / filename, "w")
        if filename == "imsmanifest.xml":
            out.write(self.createXML().encode("utf8"))
        out.close()
        if self.scormType == "scorm1.2":
            templateFilename = self.config.xulDir / "templates" / "imslrm.xml"
            template = open(templateFilename, "rb").read()
            xml = self.createMetaData(template)
            out = open(self.outputDir / "imslrm.xml", "wb")
            out.write(xml.encode("utf8"))
            out.close()

    def createXML(self):
        """
        returning XLM string for manifest file
        """
        manifestId = unicode(self.idGenerator.generate())
        orgId = unicode(self.idGenerator.generate())
        if self.scormType == "scorm1.2":
            xmlStr = u'<?xml version="1.0" encoding="UTF-8"?>\n'
            xmlStr += u"<!-- generated by eXe - http://exelearning.org -->\n"
            xmlStr += u'<manifest identifier="' + manifestId + '" '
            xmlStr += u'xmlns="http://www.imsproject.org/xsd/imscp_rootv1p1p2" '
            xmlStr += u'xmlns:adlcp="http://www.adlnet.org/xsd/adlcp_rootv1p2" '
            xmlStr += u'xmlns:imsmd="http://www.imsglobal.org/xsd/imsmd_v1p2" '
            xmlStr += u'xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" '
            xmlStr += u'xsi:schemaLocation="http://www.imsproject.org/xsd/'
            xmlStr += u"imscp_rootv1p1p2 imscp_rootv1p1p2.xsd "
            xmlStr += u"http://www.imsglobal.org/xsd/imsmd_rootv1p2p1 "
            xmlStr += u"imsmd_rootv1p2p1.xsd "
            xmlStr += u"http://www.adlnet.org/xsd/adlcp_rootv1p2 "
            xmlStr += u'adlcp_rootv1p2.xsd" '
            xmlStr += u"> \n"
            xmlStr += u"<metadata> \n"
            xmlStr += u" <schema>ADL SCORM</schema> \n"
            xmlStr += u" <schemaversion>1.2</schemaversion> \n"
            xmlStr += u" <adlcp:location>imslrm.xml"
            xmlStr += u"</adlcp:location> \n"
            xmlStr += u"</metadata> \n"
        elif self.scormType == "scorm2004":
            xmlStr = u'<?xml version="1.0" encoding="UTF-8"?>\n'
            xmlStr += u"<!-- generated by eXe - http://exelearning.org -->\n"
            xmlStr += u'<manifest identifier="' + manifestId + '" '
            xmlStr += u'xmlns="http://www.imsproject.org/xsd/imscp_rootv1p1p2" '
            xmlStr += u'xmlns:adlcp="http://www.adlnet.org/xsd/adlcp_rootv1p2" '
            xmlStr += u'xmlns:imsmd="http://www.imsglobal.org/xsd/imsmd_v1p2" '
            xmlStr += u'xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" '
            xmlStr += u'xsi:schemaLocation="http://www.imsproject.org/xsd/'
            xmlStr += u"imscp_rootv1p1p2 imscp_rootv1p1p2.xsd "
            xmlStr += u"http://www.imsglobal.org/xsd/imsmd_rootv1p2p1 "
            xmlStr += u"imsmd_rootv1p2p1.xsd "
            xmlStr += u"http://www.adlnet.org/xsd/adlcp_rootv1p2 "
            xmlStr += u'adlcp_rootv1p2.xsd" '
            xmlStr += u"> \n"
        elif self.scormType == "commoncartridge":
            xmlStr = (
                u"""<?xml version="1.0" encoding="UTF-8"?>
<!-- generated by eXe - http://exelearning.org -->
<manifest identifier="%s"
 xmlns="http://www.imsglobal.org/xsd/imscp_v1p1"
 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
 xsi:schemaLocation="http://www.imsglobal.org/xsd/imscp_v1p1 ..\imscc_cam0p04\derived_schema\imscp_v1p1.xsd">\n"""
                % manifestId
            )
            templateFilename = self.config.xulDir / "templates" / "cc.xml"
            template = open(templateFilename, "rb").read()
            xmlStr += self.createMetaData(template)
        if self.scormType == "commoncartridge":
            xmlStr += u"<organizations>\n"
            xmlStr += u'  <organization identifier="%s" structure="rooted-heirarchy">' % orgId
        else:
            xmlStr += u'<organizations default="' + orgId + '">  \n'
            xmlStr += u'  <organization identifier="%s" structure="hierarchical">' % orgId
            if self.package.title != "":
                title = escape(self.package.title)
            else:
                title = escape(self.package.root.titleShort)
            xmlStr += u"<title>" + title + "</title>\n"
        depth = 0
        for page in self.pages:
            while depth >= page.depth:
                self.itemStr += "</item>\n"
                depth -= 1
            self.genItemResStr(page)
            depth = page.depth
        while depth >= 1:
            self.itemStr += "</item>\n"
            depth -= 1
        xmlStr += self.itemStr
        xmlStr += "</organization>\n"
        xmlStr += "</organizations>\n"
        xmlStr += "<resources>\n"
        xmlStr += self.resStr
        xmlStr += "</resources>\n"
        xmlStr += "</manifest>\n"
        return xmlStr

    def genItemResStr(self, page):
        """
        Returning xlm string for items and resources
        """
        itemId = "ITEM-" + unicode(self.idGenerator.generate())
        resId = "RES-" + unicode(self.idGenerator.generate())
        filename = page.name + ".html"
        self.itemStr += '<item identifier="' + itemId + '" isvisible="true" '
        self.itemStr += 'identifierref="' + resId + '">\n'
        self.itemStr += "    <title>"
        self.itemStr += escape(page.node.titleShort)
        self.itemStr += "</title>\n"
        self.resStr += '  <resource identifier="' + resId + '" '
        self.resStr += 'type="webcontent" '
        if self.scormType == "commoncartridge":
            self.resStr += (
                """>
    <file href="%s"/>
    <file href="base.css"/>
    <file href="content.css"/>"""
                % filename
            )
        else:
            self.resStr += 'adlcp:scormtype="sco" '
            self.resStr += 'href="' + filename + '"> \n'
            self.resStr += (
                """\
    <file href="%s"/>
    <file href="base.css"/>
    <file href="content.css"/>
    <file href="APIWrapper.js"/>
    <file href="SCOFunctions.js"/>"""
                % filename
            )
        self.resStr += "\n"
        fileStr = ""
        for resource in page.node.getResources():
            fileStr += '    <file href="' + escape(resource) + '"/>\n'
        self.resStr += fileStr
        self.resStr += "</resource>\n"
예제 #11
0
 def setUp(self):
     self.generator = UniqueIdGenerator("David's Gen", sys.argv[0])
예제 #12
0
파일: imsexport.py 프로젝트: RichDijk/eXe
class Manifest(object):
    """
    Represents an imsmanifest xml file
    """

    def __init__(self, config, outputDir, package, pages, metadataType):
        """
        Initialize
        'outputDir' is the directory that we read the html from and also output
        the mainfest.xml 
        """
        self.config = config
        self.outputDir = outputDir
        self.package = package
        self.idGenerator = UniqueIdGenerator(package.name, config.exePath)
        self.pages = pages
        self.metadataType = metadataType
        self.itemStr = ""
        self.resStr = ""

    def createMetaData(self):
        """
        if user did not supply metadata title, description or creator
        then use package title, description, or creator in imslrm
        if they did not supply a package title, use the package name
        if they did not supply a date, use today
        """
        xml = ""
        namespace = "lom:"
        # depending on (user desired) the metadata type:
        if self.metadataType == "LOMES":
            output = StringIO.StringIO()
            metadata = copy.deepcopy(self.package.lomEs)
            title = metadata.get_general().get_title() or lomsubs.titleSub([])
            if not title.get_string():
                title.add_string(lomsubs.LangStringSub(self.package.lang.encode("utf-8"), self.package.name))
                metadata.get_general().set_title(title)
            metadata.export(output, 0, namespace_=namespace, pretty_print=False)
            xml = output.getvalue()
        if self.metadataType == "LOM":
            output = StringIO.StringIO()
            metadata = copy.deepcopy(self.package.lom)
            title = metadata.get_general().get_title() or lomsubs.titleSub([])
            if not title.get_string():
                title.add_string(lomsubs.LangStringSub(self.package.lang.encode("utf-8"), self.package.name))
                metadata.get_general().set_title(title)
            metadata.export(output, 0, namespace_=namespace, pretty_print=False)
            xml = output.getvalue()
        if self.metadataType == "DC":
            lrm = self.package.dublinCore.__dict__.copy()
            # use package values in absentia:
            if lrm.get("title", "") == "":
                lrm["title"] = self.package.title
            if lrm["title"] == "":
                lrm["title"] = self.package.name
            if lrm.get("description", "") == "":
                lrm["description"] = self.package.description
            if lrm["description"] == "":
                lrm["description"] = self.package.name
            if lrm.get("creator", "") == "":
                lrm["creator"] = self.package.author
            if lrm["date"] == "":
                lrm["date"] = time.strftime("%Y-%m-%d")
            # if they don't look like VCARD entries, coerce to fn:
            for f in ("creator", "publisher", "contributors"):
                if re.match(".*[:;]", lrm[f]) == None:
                    lrm[f] = u"FN:" + lrm[f]
            templateFilename = self.config.webDir / "templates" / "imslrm.xml"
            template = open(templateFilename, "rb").read()
            xml = template % lrm
            out = open(self.outputDir / "imslrm.xml", "wb")
            out.write(xml.encode("utf8"))
            out.close()
            xml = "<adlcp:location>imslrm.xml</adlcp:location>"
        return xml

    def save(self, filename):
        """
        Save a imsmanifest file to self.outputDir
        """
        out = open(self.outputDir / filename, "w")
        if filename == "imsmanifest.xml":
            out.write(self.createXML().encode("utf8"))
        out.close()

    def createXML(self):
        """
        returning XLM string for manifest file
        """
        manifestId = self.idGenerator.generate()
        orgId = self.idGenerator.generate()

        xmlStr = (
            u"""<?xml version="1.0" encoding="UTF-8"?>
        <!-- Generated by eXe - http://exelearning.net -->
        <manifest identifier="%s" 
        xmlns="http://www.imsglobal.org/xsd/imscp_v1p1"
        xmlns:imsmd="http://www.imsglobal.org/xsd/imsmd_v1p2" 
        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xmlns:lom="http://ltsc.ieee.org/xsd/LOM"
        """
            % manifestId
        )
        xmlStr += "\n "
        xmlStr += 'xsi:schemaLocation="http://www.imsglobal.org/xsd/'
        xmlStr += "imscp_v1p1 imscp_v1p1.xsd "
        xmlStr += 'http://www.imsglobal.org/xsd/imsmd_v1p2 imsmd_v1p2p2.xsd"'
        xmlStr += "> \n"
        xmlStr += "<metadata> \n"
        xmlStr += " <schema>IMS Content</schema> \n"
        xmlStr += " <schemaversion>1.1.3</schemaversion> \n"
        xmlStr += " %(metadata)s\n"
        xmlStr += "</metadata> \n"
        xmlStr += '<organizations default="' + orgId + '">  \n'
        xmlStr += '<organization identifier="' + orgId
        xmlStr += '" structure="hierarchical">  \n'

        xmlStr = xmlStr % {"metadata": self.createMetaData()}
        if self.package.title != "":
            title = escape(self.package.title)
        else:
            title = escape(self.package.root.titleShort)
        xmlStr += u"<title>" + title + "</title>\n"

        depth = 0
        for page in self.pages:
            while depth >= page.depth:
                self.itemStr += "</item>\n"
                depth -= 1
            self.genItemResStr(page)
            depth = page.depth

        while depth >= 1:
            self.itemStr += "</item>\n"
            depth -= 1

        xmlStr += self.itemStr
        xmlStr += "</organization>\n"
        xmlStr += "</organizations>\n"
        xmlStr += "<resources>\n"
        xmlStr += self.resStr
        xmlStr += "</resources>\n"
        xmlStr += "</manifest>\n"
        return xmlStr

    def genItemResStr(self, page):
        """
        Returning xml string for items and resources
        """
        itemId = "ITEM-" + unicode(self.idGenerator.generate())
        resId = "RES-" + unicode(self.idGenerator.generate())
        filename = page.name + ".html"

        self.itemStr += '<item identifier="' + itemId + '" isvisible="true" '
        self.itemStr += 'identifierref="' + resId + '">\n'
        self.itemStr += "    <title>"
        self.itemStr += escape(page.node.titleShort)
        self.itemStr += "</title>\n"

        self.resStr += '<resource identifier="' + resId + '" '
        self.resStr += 'type="webcontent" '

        self.resStr += 'href="' + filename + '"> \n'
        self.resStr += (
            """\
    <file href="%s"/>
    <file href="base.css"/>
    <file href="content.css"/>"""
            % filename
        )
        self.resStr += "\n"
        fileStr = ""

        dT = common.getExportDocType()
        if dT == "HTML5" or common.nodeHasMediaelement(page.node):
            self.resStr += '    <file href="exe_html5.js"/>\n'

        resources = page.node.getResources()
        my_style = G.application.config.styleStore.getStyle(page.node.package.style)
        if common.nodeHasMediaelement(page.node):
            resources = resources + [f.basename() for f in (self.config.webDir / "scripts" / "mediaelement").files()]
        if common.hasGalleryIdevice(page.node):
            self.resStr += '    <file href="exe_lightbox.js"/>\n'
            self.resStr += '    <file href="exe_lightbox.css"/>\n'
            self.resStr += '    <file href="exe_lightbox_close.png"/>\n'
            self.resStr += '    <file href="exe_lightbox_loading.gif"/>\n'
            self.resStr += '    <file href="exe_lightbox_next.png"/>\n'
            self.resStr += '    <file href="exe_lightbox_prev.png"/>\n'
        if my_style.hasValidConfig:
            if my_style.get_jquery() == True:
                self.resStr += '    <file href="exe_jquery.js"/>\n'
        else:
            self.resStr += '    <file href="exe_jquery.js"/>\n'

        for resource in resources:
            fileStr += '    <file href="' + escape(resource) + '"/>\n'

        self.resStr += fileStr
        self.resStr += "</resource>\n"
예제 #13
0
class Manifest(object):
    """
    Represents an imsmanifest xml file
    """
    def __init__(self, config, outputDir, package, pages, scormType, metadataType):
        """
        Initialize
        'outputDir' is the directory that we read the html from and also output
        the mainfest.xml 
        """
        self.config       = config
        self.outputDir    = outputDir
        self.package      = package
        self.idGenerator  = UniqueIdGenerator(package.name, config.exePath)
        self.pages        = pages
        self.itemStr      = ""
        self.resStr       = ""
        self.scormType    = scormType
        self.metadataType = metadataType
        self.dependencies = {}


    def createMetaData(self, template):
        """
        if user did not supply metadata title, description or creator
        then use package title, description, or creator in imslrm
        if they did not supply a package title, use the package name
        if they did not supply a date, use today
        """
        xml = '<?xml version="1.0" encoding="UTF-8"?>\n'
        namespace = 'xmlns="http://ltsc.ieee.org/xsd/LOM" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://ltsc.ieee.org/xsd/LOM lomCustom.xsd"'          
        # depending on (user desired) the metadata type:
        if self.metadataType == 'LOMES':
            output = StringIO.StringIO()
            self.package.lomEs.export(output, 0, namespacedef_=namespace, pretty_print=False)
            xml += output.getvalue()
        if self.metadataType == 'LOM':
            output = StringIO.StringIO()
            self.package.lom.export(output, 0, namespacedef_=namespace, pretty_print=False)
            xml += output.getvalue()
        if self.metadataType == 'DC':
            lrm = self.package.dublinCore.__dict__.copy()
            # use package values in absentia:
            if lrm.get('title', '') == '':
                lrm['title'] = self.package.title
            if lrm['title'] == '':
                lrm['title'] = self.package.name
            if lrm.get('description', '') == '':
                lrm['description'] = self.package.description
            if lrm['description'] == '':
                lrm['description'] = self.package.name
            if lrm.get('creator', '') == '':
                lrm['creator'] = self.package.author
            if lrm['date'] == '':
                lrm['date'] = time.strftime('%Y-%m-%d')
            # if they don't look like VCARD entries, coerce to fn:
            for f in ('creator', 'publisher', 'contributors'):
                if re.match('.*[:;]', lrm[f]) == None:
                    lrm[f] = u'FN:' + lrm[f]
            xml = template % lrm
        return xml

    def save(self, filename):
        """
        Save a imsmanifest file to self.outputDir
        Two works: createXML and createMetaData
        """
        out = open(self.outputDir/filename, "w")
        if filename == "imsmanifest.xml":
            out.write(self.createXML().encode('utf8'))
        out.close()
        # now depending on metadataType, <metadata> content is diferent:     
        if self.scormType == "scorm1.2" or self.scormType == "scorm2004":
            if self.metadataType == 'DC':
                # if old template is desired, select imslrm.xml file:\r
                # anything else, yoy should select:    
                templateFilename = self.config.webDir/'templates'/'imslrm.xml'
                template = open(templateFilename, 'rb').read()            
            elif self.metadataType == 'LOMES':
                template = None
            elif self.metadataType == 'LOM':
                template = None
            # Now the file with metadatas. 
            # Notice that its name is independent of metadataType:  
            xml = self.createMetaData(template)
            out = open(self.outputDir/'imslrm.xml', 'wb')
            out.write(xml.encode('utf8'))
            out.close()
         
    
    def createXML(self):
        """
        returning XLM string for manifest file
        """
        manifestId = unicode(self.idGenerator.generate())
        orgId      = unicode(self.idGenerator.generate())
       
        # Add the namespaces 
        
        if self.scormType == "scorm1.2":
            xmlStr  = u'<?xml version="1.0" encoding="UTF-8"?>\n'
            xmlStr += u'<!-- Generated by eXe - http://exelearning.net -->\n'
            xmlStr += u'<manifest identifier="'+manifestId+'" '
            xmlStr += u'xmlns="http://www.imsproject.org/xsd/imscp_rootv1p1p2" '
            xmlStr += u'xmlns:adlcp="http://www.adlnet.org/xsd/adlcp_rootv1p2" '
            xmlStr += u'xmlns:imsmd="http://www.imsglobal.org/xsd/imsmd_v1p2" '
            xmlStr += u'xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" '
            xmlStr += u"xsi:schemaLocation=\"http://www.imsproject.org/xsd/"
            xmlStr += u"imscp_rootv1p1p2 imscp_rootv1p1p2.xsd "        
            xmlStr += u"http://www.imsglobal.org/xsd/imsmd_rootv1p2p1 "
            xmlStr += u"imsmd_rootv1p2p1.xsd "
            xmlStr += u"http://www.adlnet.org/xsd/adlcp_rootv1p2 "
            xmlStr += u"adlcp_rootv1p2.xsd\" "
            xmlStr += u"> \n"
            xmlStr += u"<metadata> \n"
            xmlStr += u" <schema>ADL SCORM</schema> \n"
            xmlStr += u" <schemaversion>1.2</schemaversion> \n"
            xmlStr += u" <adlcp:location>imslrm.xml"
            xmlStr += u"</adlcp:location> \n"
            xmlStr += u"</metadata> \n"
        elif self.scormType == "scorm2004":
            xmlStr  = u'<?xml version="1.0" encoding="UTF-8"?>\n'
            xmlStr += u'<!-- Generated by eXe - http://exelearning.net -->\n'
            xmlStr += u'<manifest identifier="'+manifestId+'" \n'
            xmlStr += u'xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" \n'
            xmlStr += u'xmlns:adlcp="http://www.adlnet.org/xsd/adlcp_v1p3" \n'
            xmlStr += u'xmlns:adlseq="http://www.adlnet.org/xsd/adlseq_v1p3" \n'
            xmlStr += u'xmlns:adlnav="http://www.adlnet.org/xsd/adlnav_v1p3" \n'
            xmlStr += u'xmlns:imsss="http://www.imsglobal.org/xsd/imsss" \n'
            xmlStr += u'xmlns:lom="http://ltsc.ieee.org/xsd/LOM" \n'
            xmlStr += u'xmlns:lomes="http://ltsc.ieee.org/xsd/LOM" \n'
            xmlStr += u'xmlns="http://www.imsglobal.org/xsd/imscp_v1p1" \n'
            xmlStr += u"xsi:schemaLocation=\"http://www.imsglobal.org/xsd/imscp_v1p1 imscp_v1p1.xsd " 
            xmlStr += u"http://ltsc.ieee.org/xsd/LOM lomCustom.xsd " 
            xmlStr += u"http://www.adlnet.org/xsd/adlcp_v1p3 adlcp_v1p3.xsd  "
            xmlStr += u"http://www.imsglobal.org/xsd/imsss imsss_v1p0.xsd  "
            xmlStr += u"http://www.adlnet.org/xsd/adlseq_v1p3 adlseq_v1p3.xsd "
            xmlStr += u"http://www.adlnet.org/xsd/adlnav_v1p3 adlnav_v1p3.xsd"
            xmlStr += u'"> \n'
            xmlStr += u"<metadata> \n"
            xmlStr += u" <schema>ADL SCORM</schema> \n"
            xmlStr += u" <schemaversion>2004 3rd Edition</schemaversion> \n"
            xmlStr += u" <adlcp:location>imslrm.xml"
            xmlStr += u"</adlcp:location> \n"
            xmlStr += u"</metadata> \n"
        elif self.scormType == "commoncartridge":
            xmlStr = u'''<?xml version="1.0" encoding="UTF-8"?>
<!-- generated by eXe - http://exelearning.net -->
<manifest identifier="%s"
xmlns="http://www.imsglobal.org/xsd/imscc/imscp_v1p1"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.imsglobal.org/xsd/imscc/imscp_v1p1 imscp_v1p1.xsd">\n''' % manifestId
            templateFilename = self.config.webDir/'templates'/'cc.xml'
            template = open(templateFilename, 'rb').read()
            xmlStr += self.createMetaData(template)
        
        # ORGANIZATION

        if self.scormType == "commoncartridge":
            xmlStr += u'''<organizations>
    <organization identifier="%s" structure="rooted-hierarchy">
    <item identifier="eXeCC-%s">\n''' % (orgId,
            unicode(self.idGenerator.generate()))
        else:
            xmlStr += u"<organizations default=\""+orgId+"\">  \n"
            xmlStr += u'    <organization identifier="%s" structure="hierarchical">\n' % orgId

            if self.package.title != '':
                title = escape(self.package.title)
            else:
                title  = escape(self.package.root.titleShort)
            xmlStr += u"        <title>"+title+"</title>\n"

        if self.scormType == "commoncartridge":
            # FIXME flatten hierarchy
            for page in self.pages:
                self.genItemResStr(page)    
                self.itemStr += " </item>\n"
            self.itemStr += "    </item>\n"
        else:
            # initial depth: 
            depth = 0
            depthold = 0
            oldnodeleaf = 0
            for page in self.pages:        
                while depth > page.depth:
                    if self.scormType == "scorm2004":
                        self.itemStr += u"    <imsss:sequencing>\n"
                        self.itemStr += u"        <imsss:controlMode flow=\"true\"/>\n"
                        self.itemStr += u"    </imsss:sequencing>\n"
                        if page.node.children:
                            self.itemStr += "    </item>\n"                      
                        else:
                            if oldnodeleaf and depthold - 1 > page.depth:
                                self.itemStr += "    </item>\n"                    
                    if self.scormType == "scorm1.2":
                        if page.node.children:
                            self.itemStr += "    </item>\n"
                        else:
                            if oldnodeleaf and depthold - 1 > page.depth:
                                self.itemStr += "    </item>\n"    
                    depth -= 1
                    oldnodeleaf = not page.node.children                         
                else:                 
                    if self.scormType == "scorm1.2" and depthold - 1 >= page.depth:                                     
                        if not page.node.children:
                            self.itemStr += "    </item>\n"  
                    # we will compare depth with the actual page.depth...
                    # we look for decreasing depths -it means we are ending a branch: 
                    if self.scormType == "scorm2004" and depthold - 1 >= page.depth:                                     
                        if not page.node.children:
                            self.itemStr += "    </item>\n"                                                                                 
                    # go on with the items:
                    self.genItemResStr(page)
                    # do not forget update depth before going on with the list:                                 
                depthold = page.depth
                depth = page.depth    
            
            if self.scormType != "scorm2004":    
                while depth > 1:               
                    self.itemStr += "        </item>\n"                                 
                    depth -= 1   
                # the LAST </item> of navigation block must disappear in CC exports:
                if self.scormType == "commoncartridge" and self.itemStr.endswith("   </item>\n"):
                    self.itemStr = self.itemStr[:-12] 
                
            # finally the last page (leaf) must also include sequencing:  
            if self.scormType == "scorm2004" and not page.node.children:
                for x in range(1,page.depth):
                    self.itemStr += u"    <imsss:sequencing>\n"
                    self.itemStr += u"        <imsss:controlMode flow=\"true\"/>\n"
                    self.itemStr += u"    </imsss:sequencing>\n"    
                    self.itemStr += "   </item>\n"
                # the LAST </item> of navigation block must disappear:
                if self.itemStr.endswith("   </item>\n") and page.depth > 1:
                    self.itemStr = self.itemStr[:-12] 
                    self.itemStr += "\n"
            # that's all for itemStr
                    
        xmlStr += self.itemStr   
        
        xmlStr += "  </organization>\n"
        xmlStr += "</organizations>\n"
 
        # RESOURCES
 
        xmlStr += "<resources>\n"
        xmlStr += self.resStr

        
        # If NOT commoncartridge, finally, special resource with
        # all the common files, as binded with de active style ones:    
        if self.scormType != "commoncartridge":
            if self.scormType == "scorm1.2":
                xmlStr += """  <resource identifier="COMMON_FILES" type="webcontent" adlcp:scormtype="asset">\n"""
            else:
                xmlStr += """  <resource identifier="COMMON_FILES" type="webcontent" adlcp:scormType="asset">\n"""
            directory = Path(self.config.webDir).joinpath('style', self.package.style.encode('utf-8'))
            liststylesfiles = os.listdir(directory)
            for x in liststylesfiles:
                if os.path.isfile(directory + '/' + x):
                    xmlStr += """    <file href="%s"/>\n""" % x 
            # we do want base.css and (for short time), popup_bg.gif, also:    
            xmlStr += """    <file href="base.css"/>\n"""
            xmlStr += """    <file href="popup_bg.gif"/>\n"""
            # now the javascript files:
            xmlStr += """    <file href="SCORM_API_wrapper.js"/>\n"""
            xmlStr += """    <file href="SCOFunctions.js"/>\n"""
            resources = page.node.getResources()
            my_style = G.application.config.styleStore.getStyle(page.node.package.style)
            if my_style.hasValidConfig:
                if my_style.get_jquery() == True:
                    xmlStr += """    <file href="exe_jquery.js"/>\n"""
            else:
                xmlStr += """    <file href="exe_jquery.js"/>\n"""
            xmlStr += "  </resource>\n"
       
        # no more resources:
        xmlStr += "</resources>\n"
        xmlStr += "</manifest>\n"
        return xmlStr
        
             
    def genItemResStr(self, page):
        """
        Returning xml string for items and resources
        Notice, please: items AND resources 
        """
        itemId   = "ITEM-"+unicode(self.idGenerator.generate())
        control = itemId
        resId    = "RES-"+unicode(self.idGenerator.generate())
        filename = page.name+".html"
            
        ## ITEMS INSIDE ORGANIZATIONS
        
        # CC do not requires if each section is visible or not, but SCORM yes:
        if self.scormType == "scorm1.2":
            self.itemStr += '        <item identifier="'+itemId+'" '
            self.itemStr += 'isvisible="true" '
        if self.scormType == "scorm2004" and page.depth > 1: 
            self.itemStr += '        <item identifier="'+itemId+'" '
            self.itemStr += 'isvisible="true" '    
        else:
            if self.scormType == "scorm2004" and page.depth == 1 and not page.node.children:
                self.itemStr += '        <item identifier="'+itemId+'" '
                self.itemStr += 'isvisible="true" '    
        if self.scormType == "commoncartridge":
            self.itemStr += '  <item identifier="'+itemId+'" '
            self.itemStr += 'identifierref="'+resId+'">\n'
            self.itemStr += "  <title>"
            self.itemStr += escape(page.node.titleShort)
            self.itemStr += "</title>\n"       
        # If self.scormType == "scorm2004" the identifierref shall not 
        # be used on <item> elements that contain other <item> elements, 
        # so:
        if self.scormType == "scorm2004":
            if not page.node.children:
                self.itemStr += 'identifierref="'+resId+'">\n'
                self.itemStr += "            <title>"
                self.itemStr += escape(page.node.titleShort)
                self.itemStr += "</title>\n"
                self.itemStr += "        </item>\n"
            else:
                if page.depth > 1:
                    self.itemStr += ">\n"
                    self.itemStr += "            <title>"
                    # an innocent title by the moment:
                    self.itemStr += "->"
                    self.itemStr += "</title>\n"     
                
                # create a leaf item with this resource one level beyond,
                if control == itemId:
                    itemIdleaf   = "ITEM-"+unicode(self.idGenerator.generate())
                    self.itemStr += '        <item identifier="'+itemIdleaf+'" '
                    self.itemStr += 'identifierref="'+resId+'">\n'
                    self.itemStr += "            <title>"
                    self.itemStr += escape(page.node.titleShort)
                    self.itemStr += "</title>\n"
                    self.itemStr += "        </item>\n" 
                    control = 0                  
        
        # at SCORM1.2, ALL the items at organizations 
        # must include identifierref attribute:
        if self.scormType == "scorm1.2":                 
            self.itemStr += 'identifierref="'+resId+'">\n'
            self.itemStr += "            <title>"
            self.itemStr += escape(page.node.titleShort)
            self.itemStr += "</title>\n"    
            if not page.node.children:
                self.itemStr += "        </item>\n"        


        ## RESOURCES
        
        self.resStr += "  <resource identifier=\""+resId+"\" "
        self.resStr += "type=\"webcontent\" "

        # FIXME force dependency on popup_bg.gif on every page
        # because it isn't a "resource" so we can't tell which
        # pages will use it from content.css
        if self.scormType == "commoncartridge":
            fileStr = ""
            self.resStr += """href="%s">
    <file href="%s"/>
    <file href="base.css"/>
    <file href="content.css"/>
    <file href="popup_bg.gif"/>
    <file href="exe_jquery.js"/>
    <file href="common.js"/>""" % (filename, filename)
            # CC export require content.* any place inside the manifest:
            if page.node.package.exportSource and page.depth == 1:
                self.resStr += '    <file href="content.xsd"/>\n'
                self.resStr += '    <file href="content.data"/>\n'
                self.resStr += '    <file href="contentv3.xml"/>\n'       
            if page.node.package.backgroundImg:
                self.resStr += '\n    <file href="%s"/>' % \
                        page.node.package.backgroundImg.basename()
            self.dependencies["base.css"] = True
            self.dependencies["content.css"] = True
            self.dependencies["popup_bg.gif"] = True
        else:
            if self.scormType == "scorm2004":
                self.resStr += "adlcp:scormType=\"sco\" "
                self.resStr += "href=\""+filename+"\"> \n"
                self.resStr += "    <file href=\""+filename+"\"/> \n"
                fileStr = ""
            if self.scormType == "scorm1.2":
                self.resStr += "adlcp:scormtype=\"sco\" "    
                self.resStr += "href=\""+filename+"\"> \n"              
                self.resStr += "    <file href=\""+filename+"\"/> \n"
                fileStr = ""

        dT = common.getExportDocType()
        if dT == "HTML5" or common.nodeHasMediaelement(page.node):
            self.resStr += '    <file href="exe_html5.js"/>\n'

        resources = page.node.getResources()
        my_style = G.application.config.styleStore.getStyle(page.node.package.style)
        
        if common.nodeHasMediaelement(page.node):
            resources = resources + [f.basename() for f in (self.config.webDir/"scripts"/'mediaelement').files()]
            if dT != "HTML5":
                self.scriptsDir = self.config.webDir/"scripts"
                jsFile = (self.scriptsDir/'exe_html5.js')
                jsFile.copyfile(self.outputDir/'exe_html5.js')
        
        if common.hasGalleryIdevice(page.node):
            self.resStr += '\n'
            self.resStr += '    <file href="exe_lightbox.js"/>\n'
            self.resStr += '    <file href="exe_lightbox.css"/>\n'
            self.resStr += '    <file href="exe_lightbox_close.png"/>\n'
            self.resStr += '    <file href="exe_lightbox_loading.gif"/>\n'
            self.resStr += '    <file href="exe_lightbox_next.png"/>\n'
            self.resStr += '    <file href="exe_lightbox_prev.png"/>\n'

        for resource in resources:            
            fileStr += "    <file href=\""+escape(resource)+"\"/>\n"
            self.dependencies[resource] = True

        self.resStr += fileStr

        # adding the dependency with the common files collected:
        if self.scormType != "commoncartridge":
            self.resStr += """    <dependency identifierref="COMMON_FILES"/>"""
            
        # and no more:
        self.resStr += '\n'
        self.resStr += "  </resource>\n"
예제 #14
0
class Manifest(object):
    """
    Represents an imsmanifest xml file
    """
    def __init__(self, config, outputDir, package, pages, scormType, metadataType):
        """
        Initialize
        'outputDir' is the directory that we read the html from and also output
        the mainfest.xml
        """
        self.config       = config
        self.outputDir    = outputDir
        self.package      = package
        self.idGenerator  = UniqueIdGenerator(package.name, config.exePath)
        self.pages        = pages
        self.itemStr      = ""
        self.resStr       = ""
        self.scormType    = scormType
        self.metadataType = metadataType
        self.dependencies = {}

    def _validateMetaData(self, metadata):

        modifiedMetaData = False
        fieldsModified = []

        if metadata.get_general().get_description():
            for description in metadata.get_general().get_description():
                strings = description.get_string()
                for string in strings:
                    value = string.get_valueOf_()
#                     general description: The field must be 1000 characters maximum, standard SCORM 2.1
                    if len(value) > 1000:
                        string.set_valueOf_(value[:1000])
                        modifiedMetaData = True
                        fieldsModified.append(_('general description'))

        if metadata.get_educational():
            for educational in metadata.get_educational():
                if educational.get_description():
                    for description in educational.get_description():
                        strings = description.get_string()
                        for string in strings:
                            value = string.get_valueOf_()
#                     educational description: The field must be 1000 characters maximum, standard SCORM 2.1
                            if len(value) > 1000:
                                string.set_valueOf_(value[:1000])
                                modifiedMetaData = True
                                fieldsModified.append(_('educational description'))

        return {'modifiedMetaData': modifiedMetaData, 'fieldsModified': fieldsModified}

    def createMetaData(self, template):
        """
        if user did not supply metadata title, description or creator
        then use package title, description, or creator in imslrm
        if they did not supply a package title, use the package name
        if they did not supply a date, use today
        """
        xml = '<?xml version="1.0" encoding="UTF-8"?>\n'
        namespace = 'xmlns="http://ltsc.ieee.org/xsd/LOM" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://ltsc.ieee.org/xsd/LOM lomCustom.xsd"'

        modifiedMetaData = False

        # depending on (user desired) the metadata type:
        if self.metadataType == 'LOMES':
            output = StringIO.StringIO()
            metadata = copy.deepcopy(self.package.lomEs)
            title = metadata.get_general().get_title() or lomsubs.titleSub([])
            if not title.get_string():
                title.add_string(lomsubs.LangStringSub(self.package.lang.encode('utf-8'), self.package.name))
                metadata.get_general().set_title(title)
            if self.scormType == "scorm1.2":
                modifiedMetaData = self._validateMetaData(metadata)

            if self.package.exportSource:
                technical = metadata.get_technical()
                if not technical:
                    technical = lomsubs.technicalSub('technical')
                    metadata.set_technical(technical)
                opr = technical.get_otherPlatformRequirements()
                if not opr:
                    opr = lomsubs.otherPlatformRequirementsSub()
                    technical.set_otherPlatformRequirements(opr)
                opr.add_string(lomsubs.LangStringSub(self.package.lang.encode('utf-8'), 'editor: eXe Learning'))

                found = False
                for platform in opr.get_string():
                    if platform.get_valueOf_() == self.package.lomESPlatformMark:
                        found = True
                if not found:
                    opr.add_string(lomsubs.LangStringSub(self.package.lang.encode('utf-8'), self.package.lomESPlatformMark))

            metadata.export(output, 0, namespacedef_=namespace, pretty_print=False)
            xml += output.getvalue()
        if self.metadataType == 'LOM':
            output = StringIO.StringIO()
            metadata = copy.deepcopy(self.package.lom)
            title = metadata.get_general().get_title() or lomsubs.titleSub([])
            if not title.get_string():
                title.add_string(lomsubs.LangStringSub(self.package.lang.encode('utf-8'), self.package.name))
                metadata.get_general().set_title(title)

            if self.scormType == "scorm1.2":
                modifiedMetaData = self._validateMetaData(metadata)

            metadata.export(output, 0, namespacedef_=namespace, pretty_print=False)
            xml += output.getvalue()
        if self.metadataType == 'DC':
            lrm = self.package.dublinCore.__dict__.copy()
            # use package values in absentia:
            if lrm.get('title', '') == '':
                lrm['title'] = self.package.title
            if lrm['title'] == '':
                lrm['title'] = self.package.name
            if lrm.get('description', '') == '':
                lrm['description'] = self.package.description
            if lrm['description'] == '':
                lrm['description'] = self.package.name
            if lrm.get('creator', '') == '':
                lrm['creator'] = self.package.author
            if lrm['date'] == '':
                lrm['date'] = time.strftime('%Y-%m-%d')
            # if they don't look like VCARD entries, coerce to fn:
            for f in ('creator', 'publisher', 'contributors'):
                if re.match('.*[:;]', lrm[f]) == None:
                    lrm[f] = u'FN:' + lrm[f]
            xml = template % lrm

        return {'xml': xml, 'modifiedMetaData' : modifiedMetaData}

    def save(self, filename):
        """
        Save a imsmanifest file to self.outputDir
        Two works: createXML and createMetaData
        """
        modifiedMetaData = False

        out = open(self.outputDir/filename, "w")
        if filename == "imsmanifest.xml":
            out.write(self.createXML().encode('utf8'))
        out.close()
        # now depending on metadataType, <metadata> content is diferent:
        if self.scormType == "scorm1.2" or self.scormType == "scorm2004":
            if self.metadataType == 'DC':
                # if old template is desired, select imslrm.xml file:\r
                # anything else, yoy should select:
                templateFilename = self.config.webDir/'templates'/'imslrm.xml'
                template = open(templateFilename, 'rb').read()
            elif self.metadataType == 'LOMES':
                template = None
            elif self.metadataType == 'LOM':
                template = None
            # Now the file with metadatas.
            # Notice that its name is independent of metadataType:
            metaData = self.createMetaData(template)
            xml = metaData['xml']
            modifiedMetaData = metaData['modifiedMetaData']
            out = open(self.outputDir/'imslrm.xml', 'wb')
            out.write(xml.encode('utf8'))
            out.close()

        return modifiedMetaData

    def createXML(self):
        """
        returning XLM string for manifest file
        """
        manifestId = unicode(self.idGenerator.generate())
        orgId      = unicode(self.idGenerator.generate())

        # Add the namespaces

        if self.scormType == "scorm1.2":
            xmlStr  = u'<?xml version="1.0" encoding="UTF-8"?>\n'
            xmlStr += u'<!-- Generated by eXe - http://exelearning.net -->\n'
            xmlStr += u'<manifest identifier="'+manifestId+'" '
            xmlStr += u'xmlns="http://www.imsproject.org/xsd/imscp_rootv1p1p2" '
            xmlStr += u'xmlns:adlcp="http://www.adlnet.org/xsd/adlcp_rootv1p2" '
            xmlStr += u'xmlns:imsmd="http://www.imsglobal.org/xsd/imsmd_v1p2" '
            xmlStr += u'xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" '
            xmlStr += u"xsi:schemaLocation=\"http://www.imsproject.org/xsd/"
            xmlStr += u"imscp_rootv1p1p2 imscp_rootv1p1p2.xsd "
            xmlStr += u"http://www.imsglobal.org/xsd/imsmd_rootv1p2p1 "
            xmlStr += u"imsmd_rootv1p2p1.xsd "
            xmlStr += u"http://www.adlnet.org/xsd/adlcp_rootv1p2 "
            xmlStr += u"adlcp_rootv1p2.xsd\" "
            xmlStr += u"> \n"
            xmlStr += u"<metadata> \n"
            xmlStr += u" <schema>ADL SCORM</schema> \n"
            xmlStr += u" <schemaversion>1.2</schemaversion> \n"
            xmlStr += u" <adlcp:location>imslrm.xml"
            xmlStr += u"</adlcp:location> \n"
            xmlStr += u"</metadata> \n"
        elif self.scormType == "scorm2004":
            xmlStr  = u'<?xml version="1.0" encoding="UTF-8"?>\n'
            xmlStr += u'<!-- Generated by eXe - http://exelearning.net -->\n'
            xmlStr += u'<manifest identifier="'+manifestId+'" \n'
            xmlStr += u'xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" \n'
            xmlStr += u'xmlns:adlcp="http://www.adlnet.org/xsd/adlcp_v1p3" \n'
            xmlStr += u'xmlns:adlseq="http://www.adlnet.org/xsd/adlseq_v1p3" \n'
            xmlStr += u'xmlns:adlnav="http://www.adlnet.org/xsd/adlnav_v1p3" \n'
            xmlStr += u'xmlns:imsss="http://www.imsglobal.org/xsd/imsss" \n'
            xmlStr += u'xmlns:lom="http://ltsc.ieee.org/xsd/LOM" \n'
            xmlStr += u'xmlns:lomes="http://ltsc.ieee.org/xsd/LOM" \n'
            xmlStr += u'xmlns="http://www.imsglobal.org/xsd/imscp_v1p1" \n'
            xmlStr += u"xsi:schemaLocation=\"http://www.imsglobal.org/xsd/imscp_v1p1 imscp_v1p1.xsd "
            xmlStr += u"http://ltsc.ieee.org/xsd/LOM lomCustom.xsd "
            xmlStr += u"http://www.adlnet.org/xsd/adlcp_v1p3 adlcp_v1p3.xsd  "
            xmlStr += u"http://www.imsglobal.org/xsd/imsss imsss_v1p0.xsd  "
            xmlStr += u"http://www.adlnet.org/xsd/adlseq_v1p3 adlseq_v1p3.xsd "
            xmlStr += u"http://www.adlnet.org/xsd/adlnav_v1p3 adlnav_v1p3.xsd"
            xmlStr += u'"> \n'
            xmlStr += u"<metadata> \n"
            xmlStr += u" <schema>ADL SCORM</schema> \n"
            xmlStr += u" <schemaversion>2004 3rd Edition</schemaversion> \n"
            xmlStr += u" <adlcp:location>imslrm.xml"
            xmlStr += u"</adlcp:location> \n"
            xmlStr += u"</metadata> \n"
        elif self.scormType == "commoncartridge":
            xmlStr = u'''<?xml version="1.0" encoding="UTF-8"?>
<!-- generated by eXe - http://exelearning.net -->
<manifest identifier="%s"
xmlns="http://www.imsglobal.org/xsd/imscc/imscp_v1p1"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.imsglobal.org/xsd/imscc/imscp_v1p1 imscp_v1p1.xsd">\n''' % manifestId
            templateFilename = self.config.webDir/'templates'/'cc.xml'
            template = open(templateFilename, 'rb').read()
            metaData = self.createMetaData(template)
            xmlStr += metaData['xml']

        # ORGANIZATION

        if self.scormType == "commoncartridge":
            xmlStr += u'''<organizations>
    <organization identifier="%s" structure="rooted-hierarchy">
    <item identifier="eXeCC-%s">\n''' % (orgId,
            unicode(self.idGenerator.generate()))
        else:
            xmlStr += u"<organizations default=\""+orgId+"\">  \n"
            xmlStr += u'    <organization identifier="%s" structure="hierarchical">\n' % orgId

            if self.package.title != '':
                title = escape(self.package.title)
            else:
                title  = escape(self.package.root.titleShort)
            xmlStr += u"        <title>"+title+"</title>\n"

        if self.scormType == "commoncartridge":
            # FIXME flatten hierarchy
            for page in self.pages:
                self.genItemResStr(page)
                self.itemStr += " </item>\n"
            self.itemStr += "    </item>\n"
        else:
            depth = 0
            for page in self.pages:
                while depth >= page.depth:
                    self.itemStr += "</item>\n"
                    if depth > page.depth and self.scormType == "scorm2004":
                            self.itemStr += '''  <imsss:sequencing>
    <imsss:controlMode choice="true" choiceExit="true" flow="true" forwardOnly="false"/>
  </imsss:sequencing>'''
                    depth -= 1
                if page.node.children and self.scormType == "scorm2004":
                    # Add fake node with original title
                    itemId   = "ITEM-"+unicode(self.idGenerator.generate())
                    self.itemStr += '<item identifier="'+itemId+'" '
                    self.itemStr += 'isvisible="true">\n'
                    self.itemStr += "    <title>"
                    self.itemStr += escape(page.node.titleShort)
                    self.itemStr += "</title>\n"

                    # Increase actual depth because fake node added. Next iteration closes the fake node
                    depth = page.depth + 1
                else:
                    depth = page.depth
                self.genItemResStr(page)

            while depth >= 1:
                self.itemStr += "</item>\n"
                if depth > 1 and self.scormType == "scorm2004":
                    self.itemStr += '''  <imsss:sequencing>
    <imsss:controlMode choice="true" choiceExit="true" flow="true" forwardOnly="false"/>
  </imsss:sequencing>'''
                depth -= 1

        xmlStr += self.itemStr

        if self.scormType == "scorm2004":
            xmlStr += '''  <imsss:sequencing>
    <imsss:controlMode choice="true" choiceExit="true" flow="true" forwardOnly="false"/>
  </imsss:sequencing>'''
        xmlStr += "  </organization>\n"
        xmlStr += "</organizations>\n"

        # RESOURCES

        xmlStr += "<resources>\n"
        xmlStr += self.resStr


        # If NOT commoncartridge, finally, special resource with
        # all the common files, as binded with de active style ones:
        if self.scormType != "commoncartridge":
            if self.scormType == "scorm1.2":
                xmlStr += """  <resource identifier="COMMON_FILES" type="webcontent" adlcp:scormtype="asset">\n"""
            else:
                xmlStr += """  <resource identifier="COMMON_FILES" type="webcontent" adlcp:scormType="asset">\n"""
            my_style = G.application.config.styleStore.getStyle(page.node.package.style)
            for x in my_style.get_style_dir().files('*.*'):
                xmlStr += """    <file href="%s"/>\n""" % x.basename()
            # we do want base.css and (for short time), popup_bg.gif, also:
            xmlStr += """    <file href="base.css"/>\n"""
            xmlStr += """    <file href="popup_bg.gif"/>\n"""
            # now the javascript files:
            xmlStr += """    <file href="SCORM_API_wrapper.js"/>\n"""
            xmlStr += """    <file href="SCOFunctions.js"/>\n"""
            xmlStr += """    <file href="common.js"/>\n"""
            xmlStr += """    <file href="common_i18n.js"/>\n"""
            if my_style.hasValidConfig:
                if my_style.get_jquery() == True:
                    xmlStr += """    <file href="exe_jquery.js"/>\n"""
            else:
                xmlStr += """    <file href="exe_jquery.js"/>\n"""

            xmlStr += "  </resource>\n"

        # no more resources:
        xmlStr += "</resources>\n"
        xmlStr += "</manifest>\n"
        return xmlStr


    def genItemResStr(self, page):
        """
        Returning xml string for items and resources
        """
        itemId   = "ITEM-"+unicode(self.idGenerator.generate())
        resId    = "RES-"+unicode(self.idGenerator.generate())
        ext = 'html'
        if G.application.config.cutFileName == "1":
                ext = 'htm'

        filename = page.name + '.' + ext


        self.itemStr += '<item identifier="'+itemId+'" '
        if self.scormType != "commoncartridge":
            self.itemStr += 'isvisible="true" '
        self.itemStr += 'identifierref="'+resId+'">\n'
        self.itemStr += "    <title>"
        self.itemStr += escape(page.node.titleShort)
        self.itemStr += "</title>\n"

        ## SCORM 12 specific metadata: Mastery Score is an ADL extension to the IMS Content Packaging Information Model
        ## Added for FR [#2501] Add masteryscore to manifest in evaluable nodes
        if self.scormType == "scorm1.2" and common.hasQuizTest(page.node):
            self.itemStr += "    <adlcp:masteryscore>%s</adlcp:masteryscore>\n" % common.getQuizTestPassRate(page.node)

        ## RESOURCES

        self.resStr += "  <resource identifier=\""+resId+"\" "
        self.resStr += "type=\"webcontent\" "

        # FIXME force dependency on popup_bg.gif on every page
        # because it isn't a "resource" so we can't tell which
        # pages will use it from content.css
        if self.scormType == "commoncartridge":
            fileStr = ""
            self.resStr += """href="%s">
    <file href="%s"/>
    <file href="base.css"/>
    <file href="content.css"/>
    <file href="popup_bg.gif"/>
    <file href="exe_jquery.js"/>
    <file href="common_i18n.js"/>
    <file href="common.js"/>\n""" % (filename, filename)
            # CC export require content.* any place inside the manifest:
            if page.node.package.exportSource and page.depth == 1:
                self.resStr += '    <file href="content.xsd"/>\n'
                self.resStr += '    <file href="content.data"/>\n'
                self.resStr += '    <file href="contentv3.xml"/>\n'
            if page.node.package.backgroundImg:
                self.resStr += '\n    <file href="%s"/>' % \
                        page.node.package.backgroundImg.basename()
            self.dependencies["base.css"] = True
            self.dependencies["content.css"] = True
            self.dependencies["popup_bg.gif"] = True
        else:
            if self.scormType == "scorm2004":
                self.resStr += "adlcp:scormType=\"sco\" "
                self.resStr += "href=\""+filename+"\"> \n"
                self.resStr += "    <file href=\""+filename+"\"/> \n"
                fileStr = ""
            if self.scormType == "scorm1.2":
                self.resStr += "adlcp:scormtype=\"sco\" "
                self.resStr += "href=\""+filename+"\"> \n"
                self.resStr += "    <file href=\""+filename+"\"/> \n"
                fileStr = ""

        dT = common.getExportDocType()
        if dT == "HTML5" or common.nodeHasMediaelement(page.node):
            self.resStr += '    <file href="exe_html5.js"/>\n'

        resources = page.node.getResources()

        if common.nodeHasMediaelement(page.node):
            resources = resources + [f.basename() for f in (self.config.webDir/"scripts"/'mediaelement').files()]
            if dT != "HTML5":
                self.scriptsDir = self.config.webDir/"scripts"
                jsFile = (self.scriptsDir/'exe_html5.js')
                jsFile.copyfile(self.outputDir/'exe_html5.js')

        if common.nodeHasTooltips(page.node):
            resources = resources + [f.basename() for f in (self.config.webDir/"scripts"/'exe_tooltips').files()]

        if common.hasGalleryIdevice(page.node):
            resources = resources + [f.basename() for f in (self.config.webDir/"scripts"/'exe_lightbox').files()]

        if common.hasFX(page.node):
            resources = resources + [f.basename() for f in (self.config.webDir/"scripts"/'exe_effects').files()]

        if common.hasSH(page.node):
            resources = resources + [f.basename() for f in (self.config.webDir/"scripts"/'exe_highlighter').files()]

        if common.hasGames(page.node):
            resources = resources + [f.basename() for f in (self.config.webDir/"scripts"/'exe_games').files()]

        if common.hasABCMusic(page.node):
            resources = resources + [f.basename() for f in (self.config.webDir/"scripts"/'tinymce_4'/'js'/'tinymce'/'plugins'/'abcmusic'/'export').files()]

        for resource in resources:
            fileStr += "    <file href=\""+escape(resource)+"\"/>\n"
            self.dependencies[resource] = True

        if common.hasElpLink(page.node):
            fileStr += "    <file href=\""+page.node.package.name+".elp\"/>\n"

        self.resStr += fileStr

        self.resStr += common.getJavascriptIdevicesResources(page, xmlOutput = True)

        # adding the dependency with the common files collected:
        if self.scormType != "commoncartridge":
            self.resStr += """    <dependency identifierref="COMMON_FILES"/>"""

        # and no more:
        self.resStr += '\n'
        self.resStr += "  </resource>\n"
예제 #15
0
class Manifest(object):
    """
    Represents an imsmanifest xml file
    """
    def __init__(self, config, outputDir, package, pages, scormType):
        """
        Initialize
        'outputDir' is the directory that we read the html from and also output
        the mainfest.xml 
        """
        self.config = config
        self.outputDir = outputDir
        self.package = package
        self.idGenerator = UniqueIdGenerator(package.name, config.exePath)
        self.pages = pages
        self.itemStr = ""
        self.resStr = ""
        self.scormType = scormType
        self.dependencies = {}

    def createMetaData(self, template):
        """
        if user did not supply metadata title, description or creator
        then use package title, description, or creator in imslrm
        if they did not supply a package title, use the package name
        if they did not supply a date, use today
        """
        lrm = self.package.dublinCore.__dict__.copy()
        if lrm.get('title', '') == '':
            lrm['title'] = self.package.title
        if lrm['title'] == '':
            lrm['title'] = self.package.name
        if lrm.get('description', '') == '':
            lrm['description'] = self.package.description
        if lrm['description'] == '':
            lrm['description'] = self.package.name
        if lrm.get('creator', '') == '':
            lrm['creator'] = self.package.author
        if lrm['date'] == '':
            lrm['date'] = time.strftime('%Y-%m-%d')
        # if they don't look like VCARD entries, coerce to fn:
        for f in ('creator', 'publisher', 'contributors'):
            if re.match('.*[:;]', lrm[f]) == None:
                lrm[f] = u'FN:' + lrm[f]
        xml = template % lrm
        return xml

    def save(self, filename):
        """
        Save a imsmanifest file to self.outputDir
        """
        out = open(self.outputDir / filename, "w")
        if filename == "imsmanifest.xml":
            out.write(self.createXML().encode('utf8'))
        out.close()
        if self.scormType == "scorm1.2":
            templateFilename = self.config.xulDir / 'templates' / 'imslrm.xml'
            template = open(templateFilename, 'rb').read()
            xml = self.createMetaData(template)
            out = open(self.outputDir / 'imslrm.xml', 'wb')
            out.write(xml.encode('utf8'))
            out.close()

    def createXML(self):
        """
        returning XLM string for manifest file
        """
        manifestId = unicode(self.idGenerator.generate())
        orgId = unicode(self.idGenerator.generate())

        # Add the namespaces

        if self.scormType == "scorm1.2":
            xmlStr = u'<?xml version="1.0" encoding="UTF-8"?>\n'
            xmlStr += u'<!-- generated by eXe - http://exelearning.org -->\n'
            xmlStr += u'<manifest identifier="' + manifestId + '" '
            xmlStr += u'xmlns="http://www.imsproject.org/xsd/imscp_rootv1p1p2" '
            xmlStr += u'xmlns:adlcp="http://www.adlnet.org/xsd/adlcp_rootv1p2" '
            xmlStr += u'xmlns:imsmd="http://www.imsglobal.org/xsd/imsmd_v1p2" '
            xmlStr += u'xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" '
            xmlStr += u"xsi:schemaLocation=\"http://www.imsproject.org/xsd/"
            xmlStr += u"imscp_rootv1p1p2 imscp_rootv1p1p2.xsd "
            xmlStr += u"http://www.imsglobal.org/xsd/imsmd_rootv1p2p1 "
            xmlStr += u"imsmd_rootv1p2p1.xsd "
            xmlStr += u"http://www.adlnet.org/xsd/adlcp_rootv1p2 "
            xmlStr += u"adlcp_rootv1p2.xsd\" "
            xmlStr += u"> \n"
            xmlStr += u"<metadata> \n"
            xmlStr += u" <schema>ADL SCORM</schema> \n"
            xmlStr += u" <schemaversion>1.2</schemaversion> \n"
            # commented out to work with tum online plattform
            # kinda dirty, but it HAVE to work with it, so uncomment
            # if you want a full SCORM1.2 compliance
            #xmlStr += u" <adlcp:location>imslrm.xml"
            #xmlStr += u"</adlcp:location> \n"
            xmlStr += u"</metadata> \n"
        elif self.scormType == "scorm2004":
            xmlStr = u'<?xml version="1.0" encoding="UTF-8"?>\n'
            xmlStr += u'<!-- generated by eXe - http://exelearning.org -->\n'
            xmlStr += u'<manifest identifier="' + manifestId + '" '
            xmlStr += u'xmlns="http://www.imsproject.org/xsd/imscp_rootv1p1p2" '
            xmlStr += u'xmlns:adlcp="http://www.adlnet.org/xsd/adlcp_rootv1p2" '
            xmlStr += u'xmlns:imsmd="http://www.imsglobal.org/xsd/imsmd_v1p2" '
            xmlStr += u'xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" '
            xmlStr += u"xsi:schemaLocation=\"http://www.imsproject.org/xsd/"
            xmlStr += u"imscp_rootv1p1p2 imscp_rootv1p1p2.xsd "
            xmlStr += u"http://www.imsglobal.org/xsd/imsmd_rootv1p2p1 "
            xmlStr += u"imsmd_rootv1p2p1.xsd "
            xmlStr += u"http://www.adlnet.org/xsd/adlcp_rootv1p2 "
            xmlStr += u"adlcp_rootv1p2.xsd\" "
            xmlStr += u"> \n"
        elif self.scormType == "commoncartridge":
            xmlStr = u'''<?xml version="1.0" encoding="UTF-8"?>
<!-- generated by eXe - http://exelearning.org -->
<manifest identifier="%s"
 xmlns="http://www.imsglobal.org/xsd/imscc/imscp_v1p1"
 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
 xsi:schemaLocation="http://www.imsglobal.org/xsd/imscc/imscp_v1p1 imscp_v1p1.xsd">\n''' % manifestId
            templateFilename = self.config.xulDir / 'templates' / 'cc.xml'
            template = open(templateFilename, 'rb').read()
            xmlStr += self.createMetaData(template)

        # Metadata

        if self.scormType == "commoncartridge":
            xmlStr += u'''<organizations>
  <organization identifier="%s" structure="rooted-hierarchy">
    <item identifier="eXeCC-%s">\n''' % (orgId,
                                         unicode(self.idGenerator.generate()))
        else:
            xmlStr += u"<organizations default=\"" + orgId + "\">  \n"
            xmlStr += u'  <organization identifier="%s" structure="hierarchical">\n' % orgId

            if self.package.title != '':
                title = escape(self.package.title)
            else:
                title = escape(self.package.root.titleShort)
            xmlStr += u"<title>" + title + "</title>\n"

        if self.scormType == "commoncartridge":
            # FIXME flatten hierarchy
            for page in self.pages:
                self.genItemResStr(page)
                self.itemStr += "</item>\n"
        else:
            depth = 0
            for page in self.pages:
                while depth >= page.depth:
                    self.itemStr += "</item>\n"
                    depth -= 1
                self.genItemResStr(page)
                depth = page.depth

            while depth >= 1:
                self.itemStr += "</item>\n"
                depth -= 1

        xmlStr += self.itemStr
        if self.scormType == "commoncartridge":
            xmlStr += "    </item>\n"
        xmlStr += "  </organization>\n"
        xmlStr += "</organizations>\n"
        xmlStr += "<resources>\n"
        xmlStr += self.resStr
        xmlStr += "</resources>\n"
        xmlStr += "</manifest>\n"
        return xmlStr

    def genItemResStr(self, page):
        """
        Returning xml string for items and resources
        """
        itemId = "ITEM-" + unicode(self.idGenerator.generate())
        resId = "RES-" + unicode(self.idGenerator.generate())
        filename = page.name + ".html"

        self.itemStr += '<item identifier="' + itemId + '" '
        if self.scormType != "commoncartridge":
            self.itemStr += 'isvisible="true" '
        self.itemStr += 'identifierref="' + resId + '">\n'
        self.itemStr += "    <title>"
        self.itemStr += escape(page.node.titleShort)
        self.itemStr += "</title>\n"

        self.resStr += "  <resource identifier=\"" + resId + "\" "
        self.resStr += "type=\"webcontent\" "

        # FIXME force dependency on popup_bg.gif on every page
        # because it isn't a "resource" so we can't tell which
        # pages will use it from content.css
        if self.scormType == "commoncartridge":
            self.resStr += """href="%s">
    <file href="%s"/>
    <file href="base.css"/>
    <file href="content.css"/>
    <file href="popup_bg.gif"/>""" % (filename, filename)
            if page.node.package.backgroundImg:
                self.resStr += '\n    <file href="%s"/>' % \
                        page.node.package.backgroundImg.basename()
            self.dependencies["base.css"] = True
            self.dependencies["content.css"] = True
            self.dependencies["popup_bg.gif"] = True
        else:
            self.resStr += "adlcp:scormtype=\"sco\" "
            self.resStr += "href=\"" + filename + "\"> \n"
            self.resStr += """\
    <file href="%s"/>
    <file href="base.css"/>
    <file href="content.css"/>
    <file href="popup_bg.gif"/>
    <file href="APIWrapper.js"/>
    <file href="SCOFunctions.js"/>""" % filename
        self.resStr += "\n"
        fileStr = ""

        for resource in page.node.getResources():
            fileStr += "    <file href=\"" + escape(resource) + "\"/>\n"
            self.dependencies[resource] = True

        self.resStr += fileStr
        self.resStr += "  </resource>\n"
예제 #16
0
class Manifest(object):
    """
    Represents an imsmanifest xml file
    """
    def __init__(self, config, outputDir, package, pages):
        """
        Initialize
        'outputDir' is the directory that we read the html from and also output
        the mainfest.xml 
        """
        self.config       = config
        self.outputDir    = outputDir
        self.package      = package
        self.idGenerator  = UniqueIdGenerator(package.name, config.exePath)
        self.pages        = pages
        self.itemStr      = ""
        self.resStr       = ""
    def save(self):
        """
        Save a imsmanifest file and metadata to self.outputDir
        """
        filename = "imsmanifest.xml"
        out = open(self.outputDir/filename, "wb")
        out.write(self.createXML().encode('utf8'))
        out.close()
        lrm = self.package.dublinCore.__dict__.copy()
        if lrm.get('title', '') == '':
            lrm['title'] = self.package.title
        if lrm['title'] == '':
            lrm['title'] = self.package.name
        if lrm.get('description', '') == '':
            lrm['description'] = self.package.description
        if lrm['description'] == '':
            lrm['description'] = self.package.name
        if lrm.get('creator', '') == '':
            lrm['creator'] = self.package.author
        templateFilename = self.config.xulDir/'templates'/'dublincore.xml'
        template = open(templateFilename, 'rb').read()
        xml = template % lrm
        out = open(self.outputDir/'dublincore.xml', 'wb')
        out.write(xml.encode('utf8'))
        out.close()
    def createXML(self):
        """
        returning XLM string for manifest file
        """
        manifestId = self.idGenerator.generate()
        orgId      = self.idGenerator.generate()
        xmlStr = u"""<?xml version="1.0" encoding="UTF-8"?>
        <!-- generated by eXe - http://exelearning.org -->
        <manifest identifier="%s" 
        xmlns="http://www.imsglobal.org/xsd/imscp_v1p1"
        xmlns:adlcp="http://www.adlnet.org/xsd/adlcp_rootv1p2" 
        xmlns:imsmd="http://www.imsglobal.org/xsd/imsmd_v1p2" 
        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
        """ % manifestId 
        xmlStr += "\n "
        xmlStr += "xsi:schemaLocation=\"http://www.imsglobal.org/xsd/"
        xmlStr += "imscp_v1p1 imscp_v1p1.xsd "        
        xmlStr += "http://www.imsglobal.org/xsd/imsmd_v1p2 imsmd_v1p2p2.xsd\""
        xmlStr += "> \n"
        xmlStr += "<metadata> \n"
        xmlStr += " <schema>IMS Content</schema> \n"
        xmlStr += " <schemaversion>1.1.3</schemaversion> \n"
        xmlStr += " <adlcp:location>dublincore.xml"
        xmlStr += "</adlcp:location> \n" 
        xmlStr += "</metadata> \n"
        xmlStr += "<organizations default=\""+orgId+"\">  \n"
        xmlStr += "<organization identifier=\""+orgId
        xmlStr += "\" structure=\"hierarchical\">  \n"
        if self.package.title != '':
            title = escape(self.package.title)
        else:
            title  = escape(self.package.root.titleShort)
        xmlStr += u"<title>"+title+"</title>\n"
        depth = 0
        for page in self.pages:
            while depth >= page.depth:
                self.itemStr += "</item>\n"
                depth -= 1
            self.genItemResStr(page)
            depth = page.depth
        while depth >= 1:
            self.itemStr += "</item>\n"
            depth -= 1
        xmlStr += self.itemStr
        xmlStr += "</organization>\n"
        xmlStr += "</organizations>\n"
        xmlStr += "<resources>\n"
        xmlStr += self.resStr
        xmlStr += "</resources>\n"
        xmlStr += "</manifest>\n"
        return xmlStr
    def genItemResStr(self, page):
        """
        Returning xml string for items and resources
        """
        itemId   = "ITEM-"+unicode(self.idGenerator.generate())
        resId    = "RES-"+unicode(self.idGenerator.generate())
        filename = page.name+".html"
        self.itemStr += "<item identifier=\""+itemId+"\" isvisible=\"true\" "
        self.itemStr += "identifierref=\""+resId+"\">\n"
        self.itemStr += "    <title>"
        self.itemStr += escape(page.node.titleShort)
        self.itemStr += "</title>\n"
        self.resStr += "<resource identifier=\""+resId+"\" "
        self.resStr += "type=\"webcontent\" "
        self.resStr += "href=\""+filename+"\"> \n"
        self.resStr += """\
    <file href="%s"/>
    <file href="base.css"/>
    <file href="content.css"/>""" % filename
        self.resStr += "\n"
        fileStr = ""
        for resource in page.node.getResources():
            fileStr += "    <file href=\""+escape(resource)+"\"/>\n"
        self.resStr += fileStr
        self.resStr += "</resource>\n"
예제 #17
0
class Manifest(object):
    """
    Represents an imsmanifest xml file
    """
    def __init__(self, config, outputDir, package, pages, scormType):
        """
        Initialize
        'outputDir' is the directory that we read the html from and also output
        the mainfest.xml 
        """
        self.config       = config
        self.outputDir    = outputDir
        self.package      = package
        self.idGenerator  = UniqueIdGenerator(package.name, config.exePath)
        self.pages        = pages
        self.itemStr      = ""
        self.resStr       = ""
        self.scormType    = scormType
    def save(self, filename):
        """
        Save a imsmanifest file to self.outputDir
        """
        out = open(self.outputDir/filename, "w")
        if filename == "imsmanifest.xml":
            out.write(self.createXML().encode('utf8'))
        if filename == "discussionforum.xml":
            out.write(self.createForumXML().encode('utf8'))
        out.close()
        templateFilename = self.config.xulDir/'templates'/'dublincore.xml'
        template = open(templateFilename, 'rb').read()
        xml = template % self.package.dublinCore.__dict__
        out = open(self.outputDir/'dublincore.xml', 'wb')
        out.write(xml.encode('utf8'))
        out.close()
    def createForumXML(self):
        """
        returning forum XLM string for manifest file
        """  
        xmlStr  = "<?xml version = \"1.0\"?>\n"
        xmlStr += "<forums>\n"
        for page in self.pages:
            for idevice in page.node.idevices:
               if hasattr(idevice, "isForum"):
                    forums = idevice.forumsCache.getForums()
                    xmlStr += self.moodleForums(forums)
                    break
        xmlStr += "</forums>\n"
        return xmlStr
    def moodleForums(self, forums):
        """
        returning moodle forum XLM string for manifest file
        """ 
        forumStr      = ""
        discussionStr = ""
        for forum in forums:
            if forum.lms.lms == "moodle":
                forumStr += u"<forum><name>%s</name>" % forum.forumName
                forumStr += u"<id>%s</id>" % escape(forum.forumName)
                introduction = forum.introduction
                forumStr += u"<introduction>%s</introduction>" % \
                escape(introduction).replace( '<','&lt;' ).replace( '>', '&gt;' )
                forumStr += u"<type>%s</type>" % forum.lms.type.encode()
                forumStr += u"<studentpost>%s</studentpost>\n" % \
                            forum.lms.studentpost
                forumStr += u"<subscription>%s</subscription>\n" % \
                            forum.lms.subscription
                forumStr += u"<tracking>1</tracking>\n"
                forumStr += u"<attachmentsize></attachmentsize>\n"
                forumStr += u"<ratings>0</ratings>\n"
                forumStr += u"<groupmode>%s</groupmode>\n" % forum.lms.groupmode
                forumStr += u"<visible>%s</visible>\n" % forum.lms.visible
                forumStr += u"</forum>"
                for discussion in forum.discussions:
                    discussionStr += u"<discussion>"
                    discussionStr += u"<discussionId>%s</discussionId>" % \
                                     escape(forum.forumName)
                    discussionStr += u"<subject>%s</subject>" \
                                  % escape(discussion.topic)
                    discussionStr += u"<message>%s</message>" \
                    % escape(discussion.intro).replace('<',
                                                    '&lt;').replace('>','&gt;')
                    discussionStr += u"<subscription>send me</subscription>\n"
                    discussionStr += u"</discussion>"
        xml = forumStr + discussionStr
        return xml
    def createXML(self):
        """
        returning XLM string for manifest file
        """
        manifestId = unicode(self.idGenerator.generate())
        orgId      = unicode(self.idGenerator.generate())
        if self.scormType == "scorm1.2":
            xmlStr  = u'<?xml version="1.0" encoding="UTF-8"?>\n'
            xmlStr += u'<!-- generated by eXe - http://exelearning.org -->\n'
            xmlStr += u'<manifest identifier="'+manifestId+'" '
            xmlStr += u'xmlns="http://www.imsproject.org/xsd/imscp_rootv1p1p2" '
            xmlStr += u'xmlns:adlcp="http://www.adlnet.org/xsd/adlcp_rootv1p2" '
            xmlStr += u'xmlns:imsmd="http://www.imsglobal.org/xsd/imsmd_v1p2" '
            xmlStr += u'xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" '
            xmlStr += u"xsi:schemaLocation=\"http://www.imsproject.org/xsd/"
            xmlStr += u"imscp_rootv1p1p2 imscp_rootv1p1p2.xsd "        
            xmlStr += u"http://www.imsglobal.org/xsd/imsmd_rootv1p2p1 "
            xmlStr += u"imsmd_rootv1p2p1.xsd "
            xmlStr += u"http://www.adlnet.org/xsd/adlcp_rootv1p2 "
            xmlStr += u"adlcp_rootv1p2.xsd\" "
            xmlStr += u"> \n"
            xmlStr += u"<metadata> \n"
            xmlStr += u" <schema>ADL SCORM</schema> \n"
            xmlStr += u" <schemaversion>1.2</schemaversion> \n"
            xmlStr += u" <adlcp:location>dublincore.xml"
            xmlStr += u"</adlcp:location> \n"
            xmlStr += u"</metadata> \n"
        else:
            xmlStr  = u'<?xml version="1.0" encoding="UTF-8"?>\n'
            xmlStr += u'<!-- generated by eXe - http://exelearning.org -->\n'
            xmlStr += u'<manifest identifier="'+manifestId+'" '
            xmlStr += u'xmlns="http://www.imsproject.org/xsd/imscp_rootv1p1p2" '
            xmlStr += u'xmlns:adlcp="http://www.adlnet.org/xsd/adlcp_rootv1p2" '
            xmlStr += u'xmlns:imsmd="http://www.imsglobal.org/xsd/imsmd_v1p2" '
            xmlStr += u'xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" '
            xmlStr += u"xsi:schemaLocation=\"http://www.imsproject.org/xsd/"
            xmlStr += u"imscp_rootv1p1p2 imscp_rootv1p1p2.xsd "        
            xmlStr += u"http://www.imsglobal.org/xsd/imsmd_rootv1p2p1 "
            xmlStr += u"imsmd_rootv1p2p1.xsd "
            xmlStr += u"http://www.adlnet.org/xsd/adlcp_rootv1p2 "
            xmlStr += u"adlcp_rootv1p2.xsd\" "
            xmlStr += u"> \n"
        xmlStr += u"<organizations default=\""+orgId+"\">  \n"
        xmlStr += u"<organization identifier=\""+orgId
        xmlStr += u"\" structure=\"hierarchical\">  \n"
        title  = escape(self.package.root.titleShort)
        xmlStr += u"<title>"+title+"</title>\n"
        depth = 0
        for page in self.pages:
            while depth >= page.depth:
                self.itemStr += "</item>\n"
                depth -= 1
            self.genItemResStr(page)
            depth = page.depth
        while depth >= 1:
            self.itemStr += "</item>\n"
            depth -= 1
        xmlStr += self.itemStr
        xmlStr += "</organization>\n"
        xmlStr += "</organizations>\n"
        xmlStr += "<resources>\n"
        xmlStr += self.resStr
        xmlStr += "</resources>\n"
        xmlStr += "</manifest>\n"
        return xmlStr
    def genItemResStr(self, page):
        """
        Returning xlm string for items and resources
        """
        itemId   = "ITEM-"+unicode(self.idGenerator.generate())
        resId    = "RES-"+unicode(self.idGenerator.generate())
        filename = page.name+".html"
        self.itemStr += "<item identifier=\""+itemId+"\" isvisible=\"true\" "
        self.itemStr += "identifierref=\""+resId+"\">\n"
        self.itemStr += "    <title>"
        self.itemStr += escape(page.node.titleShort)
        self.itemStr += "</title>\n"
        self.resStr += "<resource identifier=\""+resId+"\" "
        self.resStr += "type=\"webcontent\" "
        self.resStr += "adlcp:scormtype=\"sco\" "
        self.resStr += "href=\""+filename+"\"> \n"
        self.resStr += """\
    <file href="%s"/>
    <file href="base.css"/>
    <file href="content.css"/>
    <file href="APIWrapper.js"/>
    <file href="SCOFunctions.js"/>""" %filename
        self.resStr += "\n"
        fileStr = ""
        for resource in page.node.getResources():
            fileStr += "    <file href=\""+resource+"\"/>\n"
        self.resStr += fileStr
        self.resStr += "</resource>\n"
예제 #18
0
class Manifest(object):
    """
    Represents an imsmanifest xml file
    """
    def __init__(self, config, outputDir, package, pages, scormType,
                 metadataType):
        """
        Initialize
        'outputDir' is the directory that we read the html from and also output
        the mainfest.xml
        """
        self.config = config
        self.outputDir = outputDir
        self.package = package
        self.idGenerator = UniqueIdGenerator(package.name, config.exePath)
        self.pages = pages
        self.itemStr = ""
        self.resStr = ""
        self.scormType = scormType
        self.metadataType = metadataType
        self.dependencies = {}

    def _validateMetaData(self, metadata):

        modifiedMetaData = False
        fieldsModified = []

        if metadata.get_general().get_description():
            for description in metadata.get_general().get_description():
                strings = description.get_string()
                for string in strings:
                    value = string.get_valueOf_()
                    #                     general description: The field must be 1000 characters maximum, standard SCORM 2.1
                    if len(value) > 1000:
                        string.set_valueOf_(value[:1000])
                        modifiedMetaData = True
                        fieldsModified.append(_('general description'))

        if metadata.get_educational():
            for educational in metadata.get_educational():
                if educational.get_description():
                    for description in educational.get_description():
                        strings = description.get_string()
                        for string in strings:
                            value = string.get_valueOf_()
                            #                     educational description: The field must be 1000 characters maximum, standard SCORM 2.1
                            if len(value) > 1000:
                                string.set_valueOf_(value[:1000])
                                modifiedMetaData = True
                                fieldsModified.append(
                                    _('educational description'))

        return {
            'modifiedMetaData': modifiedMetaData,
            'fieldsModified': fieldsModified
        }

    def createMetaData(self, template):
        """
        if user did not supply metadata title, description or creator
        then use package title, description, or creator in imslrm
        if they did not supply a package title, use the package name
        if they did not supply a date, use today
        """
        xml = '<?xml version="1.0" encoding="UTF-8"?>\n'
        namespace = 'xmlns="http://ltsc.ieee.org/xsd/LOM" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://ltsc.ieee.org/xsd/LOM lomCustom.xsd"'

        modifiedMetaData = False

        # depending on (user desired) the metadata type:
        if self.metadataType == 'LOMES':
            output = StringIO.StringIO()
            metadata = copy.deepcopy(self.package.lomEs)
            title = metadata.get_general().get_title() or lomsubs.titleSub([])
            if not title.get_string():
                title.add_string(
                    lomsubs.LangStringSub(self.package.lang.encode('utf-8'),
                                          self.package.name))
                metadata.get_general().set_title(title)
            if self.scormType == "scorm1.2":
                modifiedMetaData = self._validateMetaData(metadata)

            if self.package.exportSource:
                technical = metadata.get_technical()
                if not technical:
                    technical = lomsubs.technicalSub('technical')
                    metadata.set_technical(technical)
                opr = technical.get_otherPlatformRequirements()
                if not opr:
                    opr = lomsubs.otherPlatformRequirementsSub()
                    technical.set_otherPlatformRequirements(opr)
                opr.add_string(
                    lomsubs.LangStringSub(self.package.lang.encode('utf-8'),
                                          'editor: eXe Learning'))

                found = False
                for platform in opr.get_string():
                    if platform.get_valueOf_(
                    ) == self.package.lomESPlatformMark:
                        found = True
                if not found:
                    opr.add_string(
                        lomsubs.LangStringSub(
                            self.package.lang.encode('utf-8'),
                            self.package.lomESPlatformMark))

            metadata.export(output,
                            0,
                            namespacedef_=namespace,
                            pretty_print=False)
            xml += output.getvalue()
        if self.metadataType == 'LOM':
            output = StringIO.StringIO()
            metadata = copy.deepcopy(self.package.lom)
            title = metadata.get_general().get_title() or lomsubs.titleSub([])
            if not title.get_string():
                title.add_string(
                    lomsubs.LangStringSub(self.package.lang.encode('utf-8'),
                                          self.package.name))
                metadata.get_general().set_title(title)

            if self.scormType == "scorm1.2":
                modifiedMetaData = self._validateMetaData(metadata)

            metadata.export(output,
                            0,
                            namespacedef_=namespace,
                            pretty_print=False)
            xml += output.getvalue()
        if self.metadataType == 'DC':
            lrm = self.package.dublinCore.__dict__.copy()
            # use package values in absentia:
            if lrm.get('title', '') == '':
                lrm['title'] = self.package.title
            if lrm['title'] == '':
                lrm['title'] = self.package.name
            if lrm.get('description', '') == '':
                lrm['description'] = self.package.description
            if lrm['description'] == '':
                lrm['description'] = self.package.name
            if lrm.get('creator', '') == '':
                lrm['creator'] = self.package.author
            if lrm['date'] == '':
                lrm['date'] = time.strftime('%Y-%m-%d')
            # if they don't look like VCARD entries, coerce to fn:
            for f in ('creator', 'publisher', 'contributors'):
                if re.match('.*[:;]', lrm[f]) == None:
                    lrm[f] = u'FN:' + lrm[f]
            xml = template % lrm

        return {'xml': xml, 'modifiedMetaData': modifiedMetaData}

    def save(self, filename):
        """
        Save a imsmanifest file to self.outputDir
        Two works: createXML and createMetaData
        """
        modifiedMetaData = False

        out = open(self.outputDir / filename, "w")
        if filename == "imsmanifest.xml":
            out.write(self.createXML().encode('utf8'))
        out.close()
        # now depending on metadataType, <metadata> content is diferent:
        if self.scormType == "scorm1.2" or self.scormType == "scorm2004":
            if self.metadataType == 'DC':
                # if old template is desired, select imslrm.xml file:\r
                # anything else, yoy should select:
                templateFilename = self.config.webDir / 'templates' / 'imslrm.xml'
                template = open(templateFilename, 'rb').read()
            elif self.metadataType == 'LOMES':
                template = None
            elif self.metadataType == 'LOM':
                template = None
            # Now the file with metadatas.
            # Notice that its name is independent of metadataType:
            metaData = self.createMetaData(template)
            xml = metaData['xml']
            modifiedMetaData = metaData['modifiedMetaData']
            out = open(self.outputDir / 'imslrm.xml', 'wb')
            out.write(xml.encode('utf8'))
            out.close()

        return modifiedMetaData

    def createXML(self):
        """
        returning XLM string for manifest file
        """
        manifestId = unicode(self.idGenerator.generate())
        orgId = unicode(self.idGenerator.generate())

        # Add the namespaces

        if self.scormType == "scorm1.2":
            xmlStr = u'<?xml version="1.0" encoding="UTF-8"?>\n'
            xmlStr += u'<!-- Generated by eXe - http://exelearning.net -->\n'
            xmlStr += u'<manifest identifier="' + manifestId + '" '
            xmlStr += u'xmlns="http://www.imsproject.org/xsd/imscp_rootv1p1p2" '
            xmlStr += u'xmlns:adlcp="http://www.adlnet.org/xsd/adlcp_rootv1p2" '
            xmlStr += u'xmlns:imsmd="http://www.imsglobal.org/xsd/imsmd_v1p2" '
            xmlStr += u'xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" '
            xmlStr += u"xsi:schemaLocation=\"http://www.imsproject.org/xsd/"
            xmlStr += u"imscp_rootv1p1p2 imscp_rootv1p1p2.xsd "
            xmlStr += u"http://www.imsglobal.org/xsd/imsmd_rootv1p2p1 "
            xmlStr += u"imsmd_rootv1p2p1.xsd "
            xmlStr += u"http://www.adlnet.org/xsd/adlcp_rootv1p2 "
            xmlStr += u"adlcp_rootv1p2.xsd\" "
            xmlStr += u"> \n"
            xmlStr += u"<metadata> \n"
            xmlStr += u" <schema>ADL SCORM</schema> \n"
            xmlStr += u" <schemaversion>1.2</schemaversion> \n"
            xmlStr += u" <adlcp:location>imslrm.xml"
            xmlStr += u"</adlcp:location> \n"
            xmlStr += u"</metadata> \n"
        elif self.scormType == "scorm2004":
            xmlStr = u'<?xml version="1.0" encoding="UTF-8"?>\n'
            xmlStr += u'<!-- Generated by eXe - http://exelearning.net -->\n'
            xmlStr += u'<manifest identifier="' + manifestId + '" \n'
            xmlStr += u'xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" \n'
            xmlStr += u'xmlns:adlcp="http://www.adlnet.org/xsd/adlcp_v1p3" \n'
            xmlStr += u'xmlns:adlseq="http://www.adlnet.org/xsd/adlseq_v1p3" \n'
            xmlStr += u'xmlns:adlnav="http://www.adlnet.org/xsd/adlnav_v1p3" \n'
            xmlStr += u'xmlns:imsss="http://www.imsglobal.org/xsd/imsss" \n'
            xmlStr += u'xmlns:lom="http://ltsc.ieee.org/xsd/LOM" \n'
            xmlStr += u'xmlns:lomes="http://ltsc.ieee.org/xsd/LOM" \n'
            xmlStr += u'xmlns="http://www.imsglobal.org/xsd/imscp_v1p1" \n'
            xmlStr += u"xsi:schemaLocation=\"http://www.imsglobal.org/xsd/imscp_v1p1 imscp_v1p1.xsd "
            xmlStr += u"http://ltsc.ieee.org/xsd/LOM lomCustom.xsd "
            xmlStr += u"http://www.adlnet.org/xsd/adlcp_v1p3 adlcp_v1p3.xsd  "
            xmlStr += u"http://www.imsglobal.org/xsd/imsss imsss_v1p0.xsd  "
            xmlStr += u"http://www.adlnet.org/xsd/adlseq_v1p3 adlseq_v1p3.xsd "
            xmlStr += u"http://www.adlnet.org/xsd/adlnav_v1p3 adlnav_v1p3.xsd"
            xmlStr += u'"> \n'
            xmlStr += u"<metadata> \n"
            xmlStr += u" <schema>ADL SCORM</schema> \n"
            xmlStr += u" <schemaversion>2004 4th Edition</schemaversion> \n"
            xmlStr += u" <adlcp:location>imslrm.xml"
            xmlStr += u"</adlcp:location> \n"
            xmlStr += u"</metadata> \n"
        elif self.scormType == "commoncartridge":
            xmlStr = u'''<?xml version="1.0" encoding="UTF-8"?>
<!-- generated by eXe - http://exelearning.net -->
<manifest identifier="%s"
xmlns="http://www.imsglobal.org/xsd/imscc/imscp_v1p1"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.imsglobal.org/xsd/imscc/imscp_v1p1 imscp_v1p1.xsd">\n''' % manifestId
            templateFilename = self.config.webDir / 'templates' / 'cc.xml'
            template = open(templateFilename, 'rb').read()
            metaData = self.createMetaData(template)
            xmlStr += metaData['xml']

        # ORGANIZATION

        if self.scormType == "commoncartridge":
            xmlStr += u'''<organizations>
    <organization identifier="%s" structure="rooted-hierarchy">
    <item identifier="eXeCC-%s">\n''' % (orgId,
                                         unicode(self.idGenerator.generate()))
        else:
            xmlStr += u"<organizations default=\"" + orgId + "\">  \n"
            xmlStr += u'    <organization identifier="%s" structure="hierarchical">\n' % orgId

            if self.package.title != '':
                title = escape(self.package.title)
            else:
                title = escape(self.package.root.titleShort)
            xmlStr += u"        <title>" + title + "</title>\n"

        if self.scormType == "commoncartridge":
            # FIXME flatten hierarchy
            for page in self.pages:
                self.genItemResStr(page)
                self.itemStr += " </item>\n"
            self.itemStr += "    </item>\n"
        else:
            depth = 0
            for page in self.pages:
                while depth >= page.depth:
                    self.itemStr += "</item>\n"
                    if depth > page.depth and self.scormType == "scorm2004":
                        self.itemStr += '''  <imsss:sequencing>
    <imsss:controlMode choice="true" choiceExit="true" flow="true" forwardOnly="false"/>
  </imsss:sequencing>'''
                    depth -= 1
                if page.node.children and self.scormType == "scorm2004":
                    # Add fake node with original title
                    itemId = "ITEM-" + unicode(self.idGenerator.generate())
                    self.itemStr += '<item identifier="' + itemId + '" '
                    self.itemStr += 'isvisible="true">\n'
                    self.itemStr += "    <title>"
                    self.itemStr += escape(page.node.titleShort)
                    self.itemStr += "</title>\n"

                    # Increase actual depth because fake node added. Next iteration closes the fake node
                    depth = page.depth + 1
                else:
                    depth = page.depth
                self.genItemResStr(page)

            while depth >= 1:
                self.itemStr += "</item>\n"
                if depth > 1 and self.scormType == "scorm2004":
                    self.itemStr += '''  <imsss:sequencing>
    <imsss:controlMode choice="true" choiceExit="true" flow="true" forwardOnly="false"/>
  </imsss:sequencing>'''
                depth -= 1

        xmlStr += self.itemStr

        if self.scormType == "scorm2004":
            xmlStr += '''  <imsss:sequencing>
    <imsss:controlMode choice="true" choiceExit="true" flow="true" forwardOnly="false"/>
  </imsss:sequencing>'''
        xmlStr += "  </organization>\n"
        xmlStr += "</organizations>\n"

        # RESOURCES

        xmlStr += "<resources>\n"
        xmlStr += self.resStr

        # If NOT commoncartridge, finally, special resource with
        # all the common files, as binded with de active style ones:
        if self.scormType != "commoncartridge":
            if self.scormType == "scorm1.2":
                xmlStr += """  <resource identifier="COMMON_FILES" type="webcontent" adlcp:scormtype="asset">\n"""
            else:
                xmlStr += """  <resource identifier="COMMON_FILES" type="webcontent" adlcp:scormType="asset">\n"""
            my_style = G.application.config.styleStore.getStyle(
                page.node.package.style)
            for x in my_style.get_style_dir().files('*.*'):
                xmlStr += """    <file href="%s"/>\n""" % x.basename()
            # we do want base.css and (for short time), popup_bg.gif, also:
            xmlStr += """    <file href="base.css"/>\n"""
            xmlStr += """    <file href="popup_bg.gif"/>\n"""
            # now the javascript files:
            xmlStr += """    <file href="SCORM_API_wrapper.js"/>\n"""
            xmlStr += """    <file href="SCOFunctions.js"/>\n"""
            xmlStr += """    <file href="common.js"/>\n"""
            xmlStr += """    <file href="common_i18n.js"/>\n"""
            if my_style.hasValidConfig():
                if my_style.get_jquery() == True:
                    xmlStr += """    <file href="exe_jquery.js"/>\n"""
            else:
                xmlStr += """    <file href="exe_jquery.js"/>\n"""

            # SCORM 1.2 and SCORM 2004:
            # So that certain platforms do not delete the necessary files so that the resources can be editable
            if page.node.package.exportSource:
                xmlStr += """    <file href="content.xsd"/>\n"""
                xmlStr += """    <file href="content.data"/>\n"""
                xmlStr += """    <file href="contentv3.xml"/>\n"""
                xmlStr += """    <file href="imslrm.xml"/>\n"""

            xmlStr += "  </resource>\n"

        # no more resources:
        xmlStr += "</resources>\n"
        xmlStr += "</manifest>\n"
        return xmlStr

    def genItemResStr(self, page):
        """
        Returning xml string for items and resources
        """
        itemId = "ITEM-" + unicode(self.idGenerator.generate())
        resId = "RES-" + unicode(self.idGenerator.generate())
        ext = 'html'
        if G.application.config.cutFileName == "1":
            ext = 'htm'

        filename = page.name + '.' + ext

        self.itemStr += '<item identifier="' + itemId + '" '
        if self.scormType != "commoncartridge":
            self.itemStr += 'isvisible="true" '
        self.itemStr += 'identifierref="' + resId + '">\n'
        self.itemStr += "    <title>"
        self.itemStr += escape(page.node.titleShort)
        self.itemStr += "</title>\n"

        ## SCORM 12 specific metadata: Mastery Score is an ADL extension to the IMS Content Packaging Information Model
        ## Added for FR [#2501] Add masteryscore to manifest in evaluable nodes
        if self.scormType == "scorm1.2" and common.hasQuizTest(page.node):
            self.itemStr += "    <adlcp:masteryscore>%s</adlcp:masteryscore>\n" % common.getQuizTestPassRate(
                page.node)

        ## RESOURCES

        self.resStr += "  <resource identifier=\"" + resId + "\" "
        self.resStr += "type=\"webcontent\" "

        # FIXME force dependency on popup_bg.gif on every page
        # because it isn't a "resource" so we can't tell which
        # pages will use it from content.css
        if self.scormType == "commoncartridge":
            fileStr = ""
            self.resStr += """href="%s">
    <file href="%s"/>
    <file href="base.css"/>
    <file href="popup_bg.gif"/>
    <file href="exe_jquery.js"/>
    <file href="common_i18n.js"/>
    <file href="common.js"/>\n""" % (filename, filename)
            my_style = G.application.config.styleStore.getStyle(
                page.node.package.style)
            for x in my_style.get_style_dir().files('*.*'):
                fileStr += """    <file href="%s"/>\n""" % x.basename()
                self.dependencies[x.basename()] = True
            # CC export require content.* any place inside the manifest:
            if page.node.package.exportSource and page.depth == 1:
                self.resStr += '    <file href="content.xsd"/>\n'
                self.resStr += '    <file href="content.data"/>\n'
                self.resStr += '    <file href="contentv3.xml"/>\n'
            if page.node.package.backgroundImg:
                self.resStr += '\n    <file href="%s"/>' % \
                        page.node.package.backgroundImg.basename()
            self.dependencies["base.css"] = True
            self.dependencies["content.css"] = True
            self.dependencies["popup_bg.gif"] = True
        else:
            if self.scormType == "scorm2004":
                self.resStr += "adlcp:scormType=\"sco\" "
                self.resStr += "href=\"" + filename + "\"> \n"
                self.resStr += "    <file href=\"" + filename + "\"/> \n"
                fileStr = ""
            if self.scormType == "scorm1.2":
                self.resStr += "adlcp:scormtype=\"sco\" "
                self.resStr += "href=\"" + filename + "\"> \n"
                self.resStr += "    <file href=\"" + filename + "\"/> \n"
                fileStr = ""

        dT = common.getExportDocType()
        if dT == "HTML5" or common.nodeHasMediaelement(page.node):
            self.resStr += '    <file href="exe_html5.js"/>\n'

        resources = page.node.getResources()

        if common.nodeHasMediaelement(page.node):
            resources = resources + [
                f.basename() for f in (self.config.webDir / "scripts" /
                                       'mediaelement').files()
            ]
            if dT != "HTML5":
                self.scriptsDir = self.config.webDir / "scripts"
                jsFile = (self.scriptsDir / 'exe_html5.js')
                jsFile.copyfile(self.outputDir / 'exe_html5.js')

        if common.nodeHasTooltips(page.node):
            resources = resources + [
                f.basename() for f in (self.config.webDir / "scripts" /
                                       'exe_tooltips').files()
            ]

        if common.hasGalleryIdevice(page.node):
            resources = resources + [
                f.basename() for f in (self.config.webDir / "scripts" /
                                       'exe_lightbox').files()
            ]

        if common.hasFX(page.node):
            resources = resources + [
                f.basename() for f in (self.config.webDir / "scripts" /
                                       'exe_effects').files()
            ]

        if common.hasSH(page.node):
            resources = resources + [
                f.basename() for f in (self.config.webDir / "scripts" /
                                       'exe_highlighter').files()
            ]

        if common.hasGames(page.node):
            resources = resources + [
                f.basename() for f in (self.config.webDir / "scripts" /
                                       'exe_games').files()
            ]

        if common.hasABCMusic(page.node):
            resources = resources + [
                f.basename()
                for f in (self.config.webDir / "scripts" / 'tinymce_4' / 'js' /
                          'tinymce' / 'plugins' / 'abcmusic' /
                          'export').files()
            ]

        for resource in resources:
            fileStr += "    <file href=\"" + escape(resource) + "\"/>\n"
            self.dependencies[resource] = True

        if common.hasElpLink(page.node):
            fileStr += "    <file href=\"" + page.node.package.name + ".elp\"/>\n"

        self.resStr += fileStr

        self.resStr += common.getJavascriptIdevicesResources(page,
                                                             xmlOutput=True)

        # adding the dependency with the common files collected:
        if self.scormType != "commoncartridge":
            self.resStr += """    <dependency identifierref="COMMON_FILES"/>"""

        # and no more:
        self.resStr += '\n'
        self.resStr += "  </resource>\n"
예제 #19
0
class Manifest(object):
    """
    Represents an imsmanifest xml file
    """
    def __init__(self, config, outputDir, package, pages):
        """
        Initialize
        'outputDir' is the directory that we read the html from and also output
        the mainfest.xml 
        """
        self.config = config
        self.outputDir = outputDir
        self.package = package
        self.idGenerator = UniqueIdGenerator(package.name, config.exePath)
        self.pages = pages
        self.itemStr = ""
        self.resStr = ""

    def save(self):
        """
        Save a imsmanifest file and metadata to self.outputDir
        """
        filename = "imsmanifest.xml"
        out = open(self.outputDir / filename, "wb")
        out.write(self.createXML().encode('utf8'))
        out.close()
        # if user did not supply metadata title, description or creator
        #  then use package title, description, or creator in imslrm
        #  if they did not supply a package title, use the package name
        lrm = self.package.dublinCore.__dict__.copy()
        if lrm.get('title', '') == '':
            lrm['title'] = self.package.title
        if lrm['title'] == '':
            lrm['title'] = self.package.name
        if lrm.get('description', '') == '':
            lrm['description'] = self.package.description
        if lrm['description'] == '':
            lrm['description'] = self.package.name
        if lrm.get('creator', '') == '':
            lrm['creator'] = self.package.author
        # Metadata
        templateFilename = self.config.xulDir / 'templates' / 'dublincore.xml'
        template = open(templateFilename, 'rb').read()
        xml = template % lrm
        out = open(self.outputDir / 'dublincore.xml', 'wb')
        out.write(xml.encode('utf8'))
        out.close()

    def createXML(self):
        """
        returning XLM string for manifest file
        """
        manifestId = self.idGenerator.generate()
        orgId = self.idGenerator.generate()

        xmlStr = u"""<?xml version="1.0" encoding="UTF-8"?>
        <!-- generated by eXe - http://exelearning.org -->
        <manifest identifier="%s" 
        xmlns="http://www.imsglobal.org/xsd/imscp_v1p1"
        xmlns:adlcp="http://www.adlnet.org/xsd/adlcp_rootv1p2" 
        xmlns:imsmd="http://www.imsglobal.org/xsd/imsmd_v1p2" 
        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
        """ % manifestId

        xmlStr += "\n "
        xmlStr += "xsi:schemaLocation=\"http://www.imsglobal.org/xsd/"
        xmlStr += "imscp_v1p1 imscp_v1p1.xsd "
        xmlStr += "http://www.imsglobal.org/xsd/imsmd_v1p2 imsmd_v1p2p2.xsd\""
        xmlStr += "> \n"
        xmlStr += "<metadata> \n"
        xmlStr += " <schema>IMS Content</schema> \n"
        xmlStr += " <schemaversion>1.1.3</schemaversion> \n"
        xmlStr += " <adlcp:location>dublincore.xml"
        xmlStr += "</adlcp:location> \n"
        xmlStr += "</metadata> \n"
        xmlStr += "<organizations default=\"" + orgId + "\">  \n"
        xmlStr += "<organization identifier=\"" + orgId
        xmlStr += "\" structure=\"hierarchical\">  \n"

        if self.package.title != '':
            title = escape(self.package.title)
        else:
            title = escape(self.package.root.titleShort)
        xmlStr += u"<title>" + title + "</title>\n"

        depth = 0
        for page in self.pages:
            while depth >= page.depth:
                self.itemStr += "</item>\n"
                depth -= 1
            self.genItemResStr(page)
            depth = page.depth

        while depth >= 1:
            self.itemStr += "</item>\n"
            depth -= 1

        xmlStr += self.itemStr
        xmlStr += "</organization>\n"
        xmlStr += "</organizations>\n"
        xmlStr += "<resources>\n"
        xmlStr += self.resStr
        xmlStr += "</resources>\n"
        xmlStr += "</manifest>\n"
        return xmlStr

    def genItemResStr(self, page):
        """
        Returning xml string for items and resources
        """
        itemId = "ITEM-" + unicode(self.idGenerator.generate())
        resId = "RES-" + unicode(self.idGenerator.generate())
        filename = page.name + ".html"

        self.itemStr += "<item identifier=\"" + itemId + "\" isvisible=\"true\" "
        self.itemStr += "identifierref=\"" + resId + "\">\n"
        self.itemStr += "    <title>"
        self.itemStr += escape(page.node.titleShort)
        self.itemStr += "</title>\n"

        self.resStr += "<resource identifier=\"" + resId + "\" "
        self.resStr += "type=\"webcontent\" "

        self.resStr += "href=\"" + filename + "\"> \n"
        self.resStr += """\
    <file href="%s"/>
    <file href="base.css"/>
    <file href="content.css"/>""" % filename
        self.resStr += "\n"
        fileStr = ""

        for resource in page.node.getResources():
            fileStr += "    <file href=\"" + escape(resource) + "\"/>\n"

        self.resStr += fileStr
        self.resStr += "</resource>\n"