Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

convert blackboard image references

refs #4514

Change-Id: Ib112b42a2508bed98a04ad84b5923753f3b6280f
Reviewed-on: https://gerrit.instructure.com/3648
Reviewed-by: Jon Jensen <jon@instructure.com>
Tested-by: Bracken Mosbacker <bracken@instructure.com>
  • Loading branch information...
commit efd44e878e8268738d509300196d761da7f8d750 1 parent 65787af
Bracken Mosbacker bracken authored
Showing with 123 additions and 39 deletions.
  1. +9 −8 lib/imscp.py
  2. +20 −2 lib/imsqti.py
  3. +77 −18 lib/imsqtiv1.py
  4. +17 −11 migrate.py
17 lib/imscp.py
View
@@ -96,7 +96,7 @@ def GetLOM (self):
self.lom=LOM()
return self.lom
- def DumpToDirectory (self,path):
+ def DumpToDirectory (self,path, create_error_files=None):
if not os.path.exists(path):
os.makedirs(path)
temp_path = os.path.join(path,"assessmentTests")
@@ -112,7 +112,7 @@ def DumpToDirectory (self,path):
self.WriteManifestXML(f)
f.close()
for r in self.resources:
- r.DumpToDirectory(path)
+ r.DumpToDirectory(path, create_error_files)
def WriteManifestXML (self,f):
f.write('<?xml version="1.0"?>')
@@ -197,9 +197,9 @@ def AddFile (self,cpf,entryPoint=0):
if entryPoint:
self.entryPoint=cpf
- def DumpToDirectory (self,path):
+ def DumpToDirectory (self,path,create_error_files=None):
for f in self.files:
- f.DumpToDirectory(path)
+ f.DumpToDirectory(path,create_error_files)
def WriteManifestXML (self,f):
f.write('\n\t<resource identifier="'+self.id+'"')
@@ -240,7 +240,7 @@ def SetData (self,data):
def SetDataPath (self,dataPath):
self.dataPath=dataPath
- def DumpToDirectory (self,path):
+ def DumpToDirectory (self,path,create_error_files=None):
if RelativeURL(self.href):
filepath=ResolveCPURI(path,self.href)
print "Writing file: "+filepath
@@ -253,9 +253,10 @@ def DumpToDirectory (self,path):
copyfile(self.dataPath,filepath)
except IOError:
print 'Problem copying "%s" -> "%s"'%(self.dataPath,filepath)
- f=codecs.open(filepath,'w',"utf8")
- f.write("Data Missing\n")
- f.close()
+ if create_error_files:
+ f=codecs.open(filepath,'w',"utf8")
+ f.write("Data Missing\n")
+ f.close()
def WriteResourceHREF (self,f):
if self.href:
22 lib/imsqti.py
View
@@ -693,7 +693,9 @@ class Block(Flow): pass
class Inline(Flow): pass
-class HTML: pass
+class HTML:
+ def __init__ (self):
+ self.escaped = False
SimpleInlineNames=['a','abbr','acronym','b','big','cite','code','dfn','em','i','kbd',
'q','samp','small','span','strong','sub','sup','tt','var']
@@ -701,6 +703,7 @@ class HTML: pass
class SimpleInline(Inline,HTML):
def __init__ (self,name):
BodyElement.__init__(self)
+ HTML.__init__(self)
self.name=name
self.elements=[]
@@ -728,6 +731,7 @@ def ExtractImages (self):
class AtomicBlock(Block,HTML):
def __init__ (self):
BodyElement.__init__(self)
+ HTML.__init__(self)
self.elements=[]
def AppendElement(self,element):
@@ -746,6 +750,7 @@ def ExtractImages (self):
class SimpleBlock(Block,HTML):
def __init__ (self):
BodyElement.__init__(self)
+ HTML.__init__(self)
self.elements=[]
def AppendElement(self,element):
@@ -861,8 +866,9 @@ def ExtractImages (elements):
class xhtml_div(Block,HTML):
def __init__ (self):
BodyElement.__init__(self)
+ HTML.__init__(self)
self.elements=[]
-
+
def AppendElement (self,element):
assert not (element is None),"Adding None to xhtml_div"
self.elements.append(element)
@@ -895,6 +901,7 @@ def WriteXML (self,f):
class xhtml_ul(Block,HTML):
def __init__ (self,name="ul"):
BodyElement.__init__(self)
+ HTML.__init__(self)
self.listItems=[]
self.name=name
@@ -916,6 +923,7 @@ def WriteXML (self,f):
class xhtml_li(BodyElement,HTML):
def __init__ (self):
BodyElement.__init__(self)
+ HTML.__init__(self)
self.elements=[]
def AppendElement (self,element):
@@ -957,6 +965,7 @@ def WriteXML (self,f):
class xhtml_object(Inline,HTML):
def __init__ (self):
+ HTML.__init__(self)
self.data=None
self.type=None
self.height=None
@@ -989,6 +998,7 @@ def WriteXML (self,f):
class xhtml_table(Block,HTML):
def __init__(self):
BodyElement.__init__(self)
+ HTML.__init__(self)
self.tableBody=[]
self.summary=None
@@ -1020,6 +1030,7 @@ def WriteXML (self,f):
class xhtml_tbody(BodyElement,HTML):
def __init__(self):
BodyElement.__init__(self)
+ HTML.__init__(self)
self.rows=[]
def AppendElement (self,element):
@@ -1040,6 +1051,7 @@ def WriteXML (self,f):
class xhtml_tr(BodyElement,HTML):
def __init__(self):
BodyElement.__init__(self)
+ HTML.__init__(self)
self.cells=[]
def AppendElement (self,element):
@@ -1060,6 +1072,7 @@ def WriteXML (self,f):
class TableCell(BodyElement,HTML):
def __init__(self,name="td"):
BodyElement.__init__(self)
+ HTML.__init__(self)
self.name=name
self.elements=[]
@@ -1078,6 +1091,7 @@ def WriteXML (self,f):
class xhtml_img(Inline,HTML):
def __init__ (self):
BodyElement.__init__(self)
+ HTML.__init__(self)
self.src=None
self.alt=""
self.longdesc=None
@@ -1113,11 +1127,15 @@ def WriteXML (self,f):
f.write("/>")
class xhtml_br(Inline,HTML):
+ def __init__ (self):
+ HTML.__init__(self)
+
def WriteXML (self,f):
f.write("<br/>\n")
class xhtml_text(Inline,HTML):
def __init__ (self,text=""):
+ HTML.__init__(self)
self.text=text
def SetText (self, text):
95 lib/imsqtiv1.py
View
@@ -34,7 +34,7 @@
from types import *
import string
-import os, sys
+import os, sys, re
from xml.sax import make_parser, handler, SAXParseException
import StringIO
from random import randint
@@ -71,6 +71,8 @@ def __init__(self):
self.noComment=0
self.dtdDir=''
self.cpPath=''
+ self.prepend_path=None
+ self.create_error_files=None
# QTIException Class
@@ -1882,7 +1884,7 @@ def SetStatus(self,source,value):
def AddContributor(self,contributor):
self.resource.GetLOM().GetLifecycle().AddContributor(contributor)
- def AddCPFile (self,uri):
+ def AddCPFile (self,uri, prepend_path=None):
uri = string.replace(uri, "%%LINKPATH%%", "")
if self.files.has_key(uri):
# We've already added this file to the content package
@@ -1891,15 +1893,21 @@ def AddCPFile (self,uri):
if RelativeURL(uri):
root=self.GetRoot()
path=root.ResolveURI(uri)
- # find the last path component
- dName,fName=os.path.split(path)
- # Use this file name in the content package
- fName=root.cp.GetUniqueFileName(fName)
- cpLocation=EncodePathSegment(fName)
- # But, what about the data!!
cpf.SetDataPath(path)
+ if os.path.exists(cpf.dataPath):
+ # find the last path component
+ dName,fName=os.path.split(path)
+ # Use this file name in the content package
+ fName=root.cp.GetUniqueFileName(fName)
+ cpLocation=EncodePathSegment(fName)
+ else:
+ # if the file doesn't exist in this package just leave the path alone
+ cpLocation=uri
else:
cpLocation=uri
+ #todo - add prepend path if set
+ if prepend_path:
+ cpLocation = "%s/%s" % (prepend_path, cpLocation)
cpf.SetHREF(cpLocation)
self.resource.AddFile(cpf,0)
self.files[uri]=cpLocation
@@ -3024,6 +3032,7 @@ def GetFlowLevel (self):
def AppendHTMLContainer (self,content):
container=xhtml_div()
+ container.escaped = True
container.SetClass('html')
container.AppendElement(xhtml_text(content))
self.parent.AppendElement(container)
@@ -3031,7 +3040,7 @@ def AppendHTMLContainer (self,content):
def CloseObject (self):
buffer=None
for child in self.children:
- if isinstance(child,HTML):
+ if isinstance(child,HTML) and not child.escaped:
if not buffer:
buffer=StringIO.StringIO()
if isinstance(child,xhtml_text):
@@ -3155,6 +3164,7 @@ def __init__(self,name,attrs,parent):
self.data=""
self.width=None
self.height=None
+ self.prepend_path=None
self.ParseAttributes(attrs)
# material, altmaterial, reference
self.CheckLocation((Material, WCTMatchingTextExt),"<"+name+">")
@@ -3187,7 +3197,7 @@ def MakeObject (self):
return element
def AddCPFile (self):
- self.uri=self.GetItemV1().AddCPFile(self.uri)
+ self.uri=self.GetItemV1().AddCPFile(self.uri,self.prepend_path)
def MakeImage (self):
element=xhtml_img()
@@ -3197,6 +3207,8 @@ def MakeImage (self):
element.SetWidth(self.width)
if self.height:
element.SetHeight(self.height)
+ if self.label:
+ element.SetAlt(self.label)
return element
def ParseTextTokens(self,tokens):
@@ -3564,10 +3576,55 @@ def CloseObject (self):
# MatImage
# --------
#
+class MatApplication(MatThing):
+ """
+ <!ELEMENT matapplication (#PCDATA)>
+
+ <!ATTLIST matapplication apptype
+ %I_Apptype;
+ %I_Label;
+ %I_Uri;
+ %I_Entityref;
+ %I_Embedded; >
+
+ MatApplication isn't actually supported. Some BB QTI uses this
+ for images so it'll try to make an image if the extension is
+ recognized as an image extension
+ """
+ def __init__(self,name,attrs,parent):
+ MatThing.__init__(self,name,attrs,parent)
+ if not self.type:
+ self.type="image/jpeg"
+ self.embedded='Inline'
+
+ def SetAttribute_apptype (self,value):
+ pass
+
+ def SetAttribute_embedded (self,value):
+ self.embedded=value
+
+ def CloseObject (self):
+ if self.uri and not re.search(r'\.(jpg|png|gif)$', self.uri, re.I):
+ self.PrintWarning("matapplication elements not supported")
+ return
+
+ element=None
+ if self.entityRef:
+ self.PrintWarning("Unsupported: inclusion of material through external entities: ignored "+self.entityRef)
+ elif not self.uri:
+ self.PrintWarning("Unsupported: inclusion of inline images")
+ else:
+ element=self.MakeImage()
+ if element:
+ self.parent.AppendElement(element)
+
+# MatImage
+# --------
+#
class MatImage(MatThing):
"""
<!ELEMENT matimage (#PCDATA)>
-
+
<!ATTLIST matimage imagtype CDATA 'image/jpeg'
%I_Label;
%I_Height;
@@ -3583,13 +3640,13 @@ def __init__(self,name,attrs,parent):
if not self.type:
self.type="image/jpeg"
self.embedded='base64'
-
+
def SetAttribute_imagtype (self,value):
self.type=value
-
+
def SetAttribute_y0 (self,value):
self.PrintWarning("Warning: discarding y0 coordinate on matimage")
-
+
def SetAttribute_x0 (self,value):
self.PrintWarning("Warning: discarding x0 coordinate on matimage")
@@ -3601,7 +3658,7 @@ def SetAttribute_height (self,value):
def SetAttribute_embedded (self,value):
self.embedded=value
-
+
def CloseObject (self):
element=None
if self.entityRef:
@@ -3613,7 +3670,7 @@ def CloseObject (self):
element=self.MakeObject()
else:
element=self.MakeImage()
- if element:
+ if element:
self.parent.AppendElement(element)
@@ -5472,7 +5529,7 @@ def CloseObject (self):
'mat_extension':WCTMatExtension,
'mat_formattedtext':BBMatFormattedText,
'matapplet':Unsupported,
- 'matapplication':Unsupported,
+ 'matapplication':MatApplication,
'mataudio':MatAudio,
'matbreak':MatBreak,
'matemtext':MatEmText,
@@ -5641,7 +5698,7 @@ def ProcessFiles (self,basepath,files):
def DumpCP (self):
if self.options.cpPath:
- self.cp.DumpToDirectory(self.options.cpPath)
+ self.cp.DumpToDirectory(self.options.cpPath, self.options.create_error_files)
def Parse (self,f,path):
global CURRENT_FILE_NAME
@@ -5687,6 +5744,8 @@ def startElement(self, name, attrs):
self.cObject.SetCP(self.cp)
self.cObject.SetPath(self.currPath)
self.cObject.SetParser(self)
+ if self.options.prepend_path and isinstance(self.cObject,(MatThing)):
+ self.cObject.prepend_path = self.options.prepend_path
else:
self.cObject=Unsupported(name,attrs,parent)
if isinstance(self.cObject,Unsupported):
28 migrate.py
View
@@ -52,16 +52,18 @@
"Usage: migrate.py [options] [--cpout=output directory] [input file|directory]",
"",
"Recognized options:",
- " --ucvars : force upper case variable names",
- " --qmdextensions : allows metadata extension fields",
- " --lang=<language> : set default language",
- " --dtdloc=<path> : set the directory containing the QTI DTD",
- " --forcefibfloat : force all fib's to float type",
- " --nocomment : suppress comments in version 2 output",
- " --nogui : run in batch mode only",
- " --help : display this message (implies --nogui)",
- " --version : display version information only (implies --nogui)"
- " --overwrite : If the files already exist overwrite them"
+ " --ucvars : force upper case variable names",
+ " --qmdextensions : allows metadata extension fields",
+ " --lang=<language> : set default language",
+ " --dtdloc=<path> : set the directory containing the QTI DTD",
+ " --forcefibfloat : force all fib's to float type",
+ " --nocomment : suppress comments in version 2 output",
+ " --nogui : run in batch mode only",
+ " --help : display this message (implies --nogui)",
+ " --version : display version information only (implies --nogui)"
+ " --overwrite : If the files already exist overwrite them"
+ " --pathprepend : A path to prepend to file references"
+ " --createerrorfiles : If a referenced file is not found create a dummy file in its place"
]
@@ -110,6 +112,10 @@
NO_GUI=1
elif x.lower()=="--overwrite":
OVERWRITE=1
+ elif x[:14].lower()=="--pathprepend=":
+ options.prepend_path = x[14:]
+ elif x.lower()=="--createerrorfiles":
+ options.create_error_files = 1
else:
fileNames.append(x)
@@ -148,4 +154,4 @@
filenames=None
parser=None
sys.exit(0)
-
+
Please sign in to comment.
Something went wrong with that request. Please try again.