class ReflectionIdevice(Idevice): """ A Reflection Idevice presents question/s for the student to think about before they look at the answer/s """ persistenceVersion = 8 def __init__(self, activity = "", answer = ""): """ Initialize """ Idevice.__init__(self, x_(u"Reflection"), x_(u"University of Auckland"), x_(u"""Reflection is a teaching method often used to connect theory to practice. Reflection tasks often provide learners with an opportunity to observe and reflect on their observations before presenting these as a piece of academic work. Journals, diaries, profiles and portfolios are useful tools for collecting observation data. Rubrics and guides can be effective feedback tools."""), u"", u"reflection") self.emphasis = Idevice.SomeEmphasis self.group = Idevice.Content self._activityInstruc = x_(u"""Enter a question for learners to reflect upon.""") self._answerInstruc = x_(u"""Describe how learners will assess how they have done in the exercise. (Rubrics are useful devices for providing reflective feedback.)""") self.systemResources += ["common.js"] self.activityTextArea = TextAreaField(x_(u'Reflective question:'), self._activityInstruc, activity) self.activityTextArea.idevice = self self.answerTextArea = TextAreaField(x_(u'Feedback:'), self._answerInstruc, answer) self.answerTextArea.idevice = self # Properties activityInstruc = lateTranslate('activityInstruc') answerInstruc = lateTranslate('answerInstruc') def getResourcesField(self, this_resource): """ implement the specific resource finding mechanism for this iDevice: """ # be warned that before upgrading, this iDevice field could not exist: if hasattr(self, 'activityTextArea')\ and hasattr(self.activityTextArea, 'images'): for this_image in self.activityTextArea.images: if hasattr(this_image, '_imageResource') \ and this_resource == this_image._imageResource: return self.activityTextArea # be warned that before upgrading, this iDevice field could not exist: if hasattr(self, 'answerTextArea')\ and hasattr(self.answerTextArea, 'images'): for this_image in self.answerTextArea.images: if hasattr(this_image, '_imageResource') \ and this_resource == this_image._imageResource: return self.answerTextArea return None def getRichTextFields(self): """ Like getResourcesField(), a general helper to allow nodes to search through all of their fields without having to know the specifics of each iDevice type. """ fields_list = [] if hasattr(self, 'activityTextArea'): fields_list.append(self.activityTextArea) if hasattr(self, 'answerTextArea'): fields_list.append(self.answerTextArea) return fields_list def burstHTML(self, i): """ takes a BeautifulSoup fragment (i) and bursts its contents to import this idevice from a CommonCartridge export """ # Reflection Idevice: title = i.find(name='span', attrs={'class' : 'iDeviceTitle' }) self.title = title.renderContents().decode('utf-8') reflections = i.findAll(name='div', attrs={'id' : re.compile('^ta') }) # should be exactly two of these: # 1st = field[0] == Activity if len(reflections) >= 1: self.activityTextArea.content_wo_resourcePaths = \ reflections[0].renderContents().decode('utf-8') # and add the LOCAL resource paths back in: self.activityTextArea.content_w_resourcePaths = \ self.activityTextArea.MassageResourceDirsIntoContent( \ self.activityTextArea.content_wo_resourcePaths) self.activityTextArea.content = \ self.activityTextArea.content_w_resourcePaths # 2nd = field[1] == Answer if len(reflections) >= 2: self.answerTextArea.content_wo_resourcePaths = \ reflections[1].renderContents().decode('utf-8') # and add the LOCAL resource paths back in: self.answerTextArea.content_w_resourcePaths = \ self.answerTextArea.MassageResourceDirsIntoContent( \ self.answerTextArea.content_wo_resourcePaths) self.answerTextArea.content = \ self.answerTextArea.content_w_resourcePaths def upgradeToVersion1(self): """ Upgrades the node from version 0 to 1. """ log.debug(u"Upgrading iDevice") self.icon = u"reflection" def upgradeToVersion2(self): """ Upgrades the node from 1 (v0.5) to 2 (v0.6). Old packages will loose their icons, but they will load. """ log.debug(u"Upgrading iDevice") self.emphasis = Idevice.SomeEmphasis def upgradeToVersion3(self): """ Upgrades v0.6 to v0.7. """ self.lastIdevice = False def upgradeToVersion4(self): """ Upgrades to exe v0.10 """ self._upgradeIdeviceToVersion1() self._activityInstruc = self.__dict__['activityInstruc'] self._answerInstruc = self.__dict__['answerInstruc'] def upgradeToVersion5(self): """ Upgrades to exe v0.10 """ self._upgradeIdeviceToVersion1() def upgradeToVersion6(self): """ Upgrades to v0.12 """ self._upgradeIdeviceToVersion2() self.systemResources += ["common.js"] def upgradeToVersion7(self): """ Upgrades to somewhere before version 0.25 (post-v0.24) Taking the old unicode string fields, and converting them into image-enabled TextAreaFields: """ self.activityTextArea = TextAreaField(x_(u'Reflective question:'), self._activityInstruc, self.activity) self.activityTextArea.idevice = self self.answerTextArea = TextAreaField(x_(u'Feedback:'), self._answerInstruc, self.answer) self.answerTextArea.idevice = self def upgradeToVersion9(self): """ Adds group to idevice """ self.group = Idevice.Content
class ClozefpdIdevice(Idevice): """ Holds a paragraph with words missing that the student must fill in """ persistenceVersion = 7 def __init__(self, parentNode=None): """ Sets up the idevice title and instructions etc """ Idevice.__init__(self, x_(u"FPD - Cloze Activity"), x_(u"University of Auckland"), x_(u"<p>Cloze exercises are texts or " "sentences where students must fill in " "missing words. They are often used for the " "following purposes:</p>" "<ol>" "<li>To check knowledge of core course " "concepts (this could be a pre-check, " "formative exercise, or summative check).</li>" "<li>To check reading comprehension.</li>" "<li>To check vocabulary knowledge.</li>" "<li>To check word formation and/or grammatical " "competence. </li></ol>"), x_(u"<dl>" " <dt>If your goal is to test understanding " "of core concepts or reading comprehension" " </dt>" " <dd>" " <p>" " Write a summary of the concept or reading long " " enough to adequately test the target's " "knowledge, but short enough not to " "induce fatigue. Less than one typed page is " "probably adequate, but probably " "considerably less for young students or " "beginners." " </p>" " <p>" "Select words in the text that" "are key to understanding the concepts. These" "will probably be verbs, nouns, and key adverbs." "Choose alternatives with one clear answer." " </p>" " </dd>" " <dt>" "If your goal is to test vocabulary knowledge" " </dt>" " <dd>" "<p>Write a text using the target vocabulary. This " "text should be coherent and cohesive, and be of " "an appropriate length. Highlight the target " "words in the text. Choose alternatives with one " "clear answer.</p>" " </dd>" " <dt>" "If your goal is to test word " "formation/grammar:" " </dt>" " <dd>" " <p>" "Write a text using the " "target forms. This text should be coherent and " "cohesive, and be of an appropriate length. " "Remember that the goal is not vocabulary " "knowledge, so the core meanings of the stem " "words should be well known to the students." " </p>" " <p>" "Highlight the target words in the text. Provide " "alternatives with the same word stem, but " "different affixes. It is a good idea to get a " "colleague to test the test/exercise to make " "sure there are no surprises!" " </p>" " </dd>" "</dl>"), u"autoevaluacionfpd", parentNode) self.instructionsForLearners = TextAreaField( x_(u'Instructions'), x_(u"""Provide instruction on how the cloze activity should be completed. Default text will be entered if there are no changes to this field. """), "") # x_(u'Read the paragraph below and fill in the missing words.')) self.instructionsForLearners.idevice = self self._content = ClozeField(x_(u'Cloze'), x_(u"""<p>Enter the text for the cloze activity in to the cloze field by either pasting text from another source or by typing text directly into the field.</p><p> To select words to hide, double click on the word to select it and click on the Hide/Show Word button below.</p><p>More than one possible answer can be defined enclosing them with pipes (|). I.e.: |dog|cat|bird|</p>""")) self._content.idevice = self self.feedback = TextAreaField(x_(u'Feedback'), x_(u'Enter any feedback you wish to provide the learner ' 'with-in the feedback field. This field can be left blank.')) self.feedback.idevice = self # self.emphasis = Idevice.SomeEmphasis self.emphasis = "_autoevaluacionfpd" self.systemResources += ["common.js"] self.isCloze = True # Properties content = property(lambda self: self._content, doc="Read only, use 'self.content.encodedContent = x' " "instead") def getResourcesField(self, this_resource): """ implement the specific resource finding mechanism for this iDevice: """ # be warned that before upgrading, this iDevice field could not exist: if hasattr(self, '_content') and hasattr(self._content, 'images'): for this_image in self._content.images: if hasattr(this_image, '_imageResource') \ and this_resource == this_image._imageResource: return self._content # be warned that before upgrading, this iDevice field could not exist: if hasattr(self, 'instructionsForLearners')\ and hasattr(self.instructionsForLearners, 'images'): for this_image in self.instructionsForLearners.images: if hasattr(this_image, '_imageResource') \ and this_resource == this_image._imageResource: return self.instructionsForLearners # be warned that before upgrading, this iDevice field could not exist: if hasattr(self, 'feedback') and hasattr(self.feedback, 'images'): for this_image in self.feedback.images: if hasattr(this_image, '_imageResource') \ and this_resource == this_image._imageResource: return self.feedback return None def getRichTextFields(self): """ Like getResourcesField(), a general helper to allow nodes to search through all of their fields without having to know the specifics of each iDevice type. """ fields_list = [] if hasattr(self, '_content'): fields_list.append(self._content) if hasattr(self, 'instructionsForLearners'): fields_list.append(self.instructionsForLearners) if hasattr(self, 'feedback'): fields_list.append(self.feedback) return fields_list def burstHTML(self, i): """ takes a BeautifulSoup fragment (i) and bursts its contents to import this idevice from a CommonCartridge export """ # Cloze Idevice: title = i.find(name='span', attrs={'class' : 'iDeviceTitle' }) self.title = title.renderContents().decode('utf-8') inner = i.find(name='div', attrs={'class' : 'iDevice_inner' }) instruct = inner.find(name='div', attrs={'class' : 'block' , 'style' : 'display:block' }) self.instructionsForLearners.content_wo_resourcePaths = \ instruct.renderContents().decode('utf-8') # and add the LOCAL resource paths back in: self.instructionsForLearners.content_w_resourcePaths = \ self.instructionsForLearners.MassageResourceDirsIntoContent( \ self.instructionsForLearners.content_wo_resourcePaths) self.instructionsForLearners.content = \ self.instructionsForLearners.content_w_resourcePaths content = inner.find(name='div', attrs={'id' : re.compile('^cloze') }) rebuilt_contents = "" for this_content in content.contents: if not this_content.__str__().startswith('<input'): if this_content.__str__().startswith('<span'): # Now, decode the answer # with code reverse-engineered from: # a) Cloze's $exe.cloze.getAnswer() in common.js # b) ClozeElement's renderView() + encrypt() answer = "" code_key = 'X' code = this_content.renderContents() code = code.decode('base64') # now in the form %uABCD%uEFGH%uIJKL.... char_pos = 0 while char_pos < len(code): # first 2 chars = %u, replace with 0x to get int # next 4 = the encoded unichr this_code_char = "0x" + code[char_pos+2 : char_pos+6] this_code_ord = int(this_code_char, 16) letter = chr(ord(code_key)^this_code_ord) answer += letter # key SHOULD be ^'d by letter, but seems to be: code_key = letter char_pos += 6 rebuilt_contents += "<U>" + answer + "</U>" elif not this_content.__str__().startswith('<div'): # this should be the un-clozed text: rebuilt_contents += this_content.__str__() self._content.content_wo_resourcePaths = rebuilt_contents # and add the LOCAL resource paths back in: self._content.content_w_resourcePaths = \ self._content.MassageResourceDirsIntoContent( \ self._content.content_wo_resourcePaths) self._content.content = self._content.content_w_resourcePaths feedback = inner.find(name='div', attrs={'class' : 'feedback' }) self.feedback.content_wo_resourcePaths = \ feedback.renderContents().decode('utf-8') # and add the LOCAL resource paths back in: self.feedback.content_w_resourcePaths = \ self.feedback.MassageResourceDirsIntoContent( \ self.feedback.content_wo_resourcePaths) self.feedback.content = self.feedback.content_w_resourcePaths # and each cloze flag field (strict, case, instant): flag_strict = inner.find(name='input', attrs={'id' : re.compile('^clozeFlag.*strictMarking$') }) if flag_strict.attrMap['value']=="true": self._content.strictMarking = True flag_caps = inner.find(name='input', attrs={'id' : re.compile('^clozeFlag.*checkCaps$') }) if flag_caps.attrMap['value']=="true": self._content.checkCaps = True flag_instant = inner.find(name='input', attrs={'id' : re.compile('^clozeFlag.*instantMarking$') }) if flag_instant.attrMap['value']=="true": self._content.instantMarking = True def upgradeToVersion1(self): """ Upgrades exe to v0.10 """ self._upgradeIdeviceToVersion1() self.instructionsForLearners = TextAreaField( x_(u'Instructions For Learners'), x_(u'Put instructions for learners here'), x_(u'Read the paragraph below and fill in the missing words')) self.instructionsForLearners.idevice = self self.feedback = TextAreaField(x_(u'Feedback')) self.feedback.idevice = self def upgradeToVersion2(self): """ Upgrades exe to v0.11 """ self.content.autoCompletion = True self.content.autoCompletionInstruc = _(u"Allow auto completion when " u"user filling the gaps.") def upgradeToVersion3(self): """ Upgrades to v0.12 """ self._upgradeIdeviceToVersion2() self.systemResources += ["common.js"] def upgradeToVersion4(self): """ Upgrades to v0.20.3 """ self.isCloze = True def upgradeToVersion5(self): self._content._instruc = x_(u"""<p>Enter the text for the cloze activity in to the cloze field by either pasting text from another source or by typing text directly into the field.</p><p> To select words to hide, double click on the word to select it and click on the Hide/Show Word button below.</p><p>More than one possible answer can be defined enclosing them with pipes (|). I.e.: |dog|cat|bird|</p>""") def upgradeToVersion6(self): """ Delete icon from system resources """ self._upgradeIdeviceToVersion3() def upgradeToVersion7(self): if self._title == u"FPD - Actividad de Espacios en Blanco": self._title = u"FPD - Cloze Activity" if self._title == u"Actividad de Espacios en Blanco": self._title = u"Cloze Activity"
class ParasabermasfpdIdevice(Idevice): """ El iDevice Para saber permite al alumnado ampliar conocimientos voluntarios para su aprendizaje """ persistenceVersion = 9 def __init__(self, activity="", answer=""): """ Initialize """ Idevice.__init__( self, x_(u"FPD - A Step Ahead"), x_(u"Jose Ramon Jimenez Reyes"), x_(u"""A Step Ahead is an iDevice that permits students widen their knowledge with further contents.""" ), u"", u"parasabermasfpd") # self.emphasis = Idevice.SomeEmphasis self.emphasis = "_parasabermasfpd" self._activityInstruc = x_( u"""Enter the text that will appear on this iDevice""") # self.systemResources += ["common.js"] self.activityTextArea = TextAreaField(x_(u'A Step Ahead Text'), self._activityInstruc, activity) self.activityTextArea.idevice = self # Properties activityInstruc = lateTranslate('activityInstruc') def getResourcesField(self, this_resource): """ implement the specific resource finding mechanism for this iDevice: """ # be warned that before upgrading, this iDevice field could not exist: if hasattr(self, 'activityTextArea')\ and hasattr(self.activityTextArea, 'images'): for this_image in self.activityTextArea.images: if hasattr(this_image, '_imageResource') \ and this_resource == this_image._imageResource: return self.activityTextArea return None def getRichTextFields(self): fields_list = [] if hasattr(self, 'activityTextArea'): fields_list.append(self.activityTextArea) return fields_list def burstHTML(self, i): # Parasabermasfpd Idevice: title = i.find(name='span', attrs={'class': 'iDeviceTitle'}) self.title = title.renderContents().decode('utf-8') reflections = i.findAll(name='div', attrs={'id': re.compile('^ta')}) # should be exactly two of these: # 1st = field[0] == Activity if len(reflections) >= 1: self.activityTextArea.content_wo_resourcePaths = \ reflections[0].renderContents().decode('utf-8') # and add the LOCAL resource paths back in: self.activityTextArea.content_w_resourcePaths = \ self.activityTextArea.MassageResourceDirsIntoContent( \ self.activityTextArea.content_wo_resourcePaths) self.activityTextArea.content = \ self.activityTextArea.content_w_resourcePaths def upgradeToVersion1(self): """ Upgrades the node from version 0 to 1. """ log.debug(u"Upgrading iDevice") self.icon = u"activity" def upgradeToVersion2(self): """ Upgrades the node from 1 (v0.5) to 2 (v0.6). Old packages will loose their icons, but they will load. """ log.debug(u"Upgrading iDevice") # self.emphasis = Idevice.SomeEmphasis self.emphasis = "_parasabermasfpd" def upgradeToVersion3(self): """ Upgrades v0.6 to v0.7. """ self.lastIdevice = False def upgradeToVersion4(self): """ Upgrades to exe v0.10 """ self._upgradeIdeviceToVersion1() self._activityInstruc = self.__dict__['activityInstruc'] def upgradeToVersion5(self): """ Upgrades to exe v0.10 """ self._upgradeIdeviceToVersion1() def upgradeToVersion6(self): """ Upgrades to v0.12 """ self._upgradeIdeviceToVersion2() # self.systemResources += ["common.js"] def upgradeToVersion7(self): """ Upgrades to somewhere before version 0.25 (post-v0.24) Taking the old unicode string fields, and converting them into image-enabled TextAreaFields: """ self.activityTextArea = TextAreaField(x_(u'A Step Ahead Text'), self._activityInstruc, self.activity) self.activityTextArea.idevice = self def upgradeToVersion8(self): """ Delete icon from system resources """ self._upgradeIdeviceToVersion3() def upgradeToVersion9(self): if self._title == u"FPD - Para Saber Mas": self._title = u"FPD - A Step Ahead" if self._purpose == u"""Para saber más es un iDevice que permite al alumnado ampliar conocimientos, siendo estos voluntarios para su aprendizaje.""": self._purpose = u"""A Step Ahead is an iDevice that permits students widen their knowledge with further contents.""" if self._activityInstruc == u"""Introduce el texto que aparecerá en este iDevice""": self._activityInstruc = u"""Enter the text that will appear on this iDevice""" if self.activityTextArea._name == u'Texto Para saber más': self.activityTextArea._name = u'A Step Ahead Text'
class OpinionIdevice(Idevice): """ A TrueFalse Idevice is one built up from question and options """ persistenceVersion = 9 def __init__(self): """ Initialize """ Idevice.__init__( self, x_(u"Opinion Question"), x_(u"University of Auckland"), x_(u"""Opinion questions present a statement where the learner must decide if he agrees or disagrees."""), u"", u"question") self.emphasis = Idevice.SomeEmphasis self._hintInstruc = x_(u"""A hint may be provided to assist the learner in answering the question.""") self.questions = [] self._questionInstruc = x_(u"""Type the question stem. The question should be clear and unambiguous. Avoid negative premises as these can tend to be ambiguous.""") self._keyInstruc = "" self._feedbackInstruc = x_(u"""Enter any feedback you wish to provide to the learner. This field may be left blank. if this field is left blank default feedback will be provided.""") self.questions.append(OpinionQuestion(self)) self.systemResources += [ "common.js", "libot_drag.js", "panel-amusements.png", "stock-stop.png" ] self.instructionsForLearners = TextAreaField( x_(u'Instructions'), x_(u"""Provide instruction on how the Opinion Question should be completed."""), u'') self.instructionsForLearners.idevice = self self.icon = u"activity" # Properties hintInstruc = lateTranslate('hintInstruc') questionInstruc = lateTranslate('questionInstruc') keyInstruc = lateTranslate('keyInstruc') feedbackInstruc = lateTranslate('feedbackInstruc') def addQuestion(self): """ Add a new question to this iDevice. """ self.questions.append(OpinionQuestion(self)) def getResourcesField(self, this_resource): """ implement the specific resource finding mechanism for this iDevice: """ # be warned that before upgrading, this iDevice field could not exist: if hasattr(self, 'instructionsForLearners')\ and hasattr(self.instructionsForLearners, 'images'): for this_image in self.instructionsForLearners.images: if hasattr(this_image, '_imageResource') \ and this_resource == this_image._imageResource: return self.instructionsForLearners for this_question in self.questions: this_field = this_question.getResourcesField(this_resource) if this_field is not None: return this_field return None def getRichTextFields(self): """ Like getResourcesField(), a general helper to allow nodes to search through all of their fields without having to know the specifics of each iDevice type. """ fields_list = [] if hasattr(self, 'instructionsForLearners'): fields_list.append(self.instructionsForLearners) for this_question in self.questions: fields_list.extend(this_question.getRichTextFields()) return fields_list def burstHTML(self, i): """ takes a BeautifulSoup fragment (i) and bursts its contents to import this idevice from a CommonCartridge export """ # True-False Idevice: title = i.find(name='h2', attrs={'class': 'iDeviceTitle'}) self.title = title.renderContents().decode('utf-8') inner = i.find(name='div', attrs={'class': 'iDevice_inner'}) instruct = inner.find(name='div', attrs={ 'class': 'block', 'style': 'display:block' }) self.instructionsForLearners.content_wo_resourcePaths = \ instruct.renderContents().decode('utf-8') # and add the LOCAL resource paths back in: self.instructionsForLearners.content_w_resourcePaths = \ self.instructionsForLearners.MassageResourceDirsIntoContent( \ self.instructionsForLearners.content_wo_resourcePaths) self.instructionsForLearners.content = \ self.instructionsForLearners.content_w_resourcePaths # copied and modified from Multi-Select, and others :-) : tf_questions = inner.findAll(name='div', attrs={'class': 'question'}) if len(tf_questions) < 1: # need to remove the default 1st question del self.questions[0] for question_num in range(len(tf_questions)): if question_num > 0: # only created with the first question, add others: self.addQuestion() question = tf_questions[question_num] questions = question.findAll(name='div', attrs={ 'class': 'block', 'id': re.compile('^taquestion') }) if len(questions) == 1: # ELSE: should warn of unexpected result! inner_question = questions[0] self.questions[question_num].questionTextArea.content_wo_resourcePaths \ = inner_question.renderContents().decode('utf-8') # and add the LOCAL resource paths back in: self.questions[question_num].questionTextArea.content_w_resourcePaths \ = self.questions[question_num].questionTextArea.MassageResourceDirsIntoContent( \ self.questions[question_num].questionTextArea.content_wo_resourcePaths) self.questions[question_num].questionTextArea.content = \ self.questions[question_num].questionTextArea.content_w_resourcePaths answer_true = question.find(name='div', attrs={'id': re.compile('^s0b')}) answer_false = question.find(name='div', attrs={'id': re.compile('^s1b')}) # true-false only has 1 feedback per question: feedbacks = question.findAll(name='div', attrs={'id': re.compile('^sfb')}) # true-false only has 1 hint per question: hints = question.findAll(name='div', attrs={'id': re.compile('^tahint')}) # and finally, see if this is a correct answer: even_score = int(answer_true.attrMap['even_steven']) if not (even_score % 2): # i.e., if it IS even, then this is correct: self.questions[question_num].isCorrect = True if len(hints) >= 1: inner_hint = hints[0] self.questions[question_num].hintTextArea.content_wo_resourcePaths \ = inner_hint.renderContents().decode('utf-8') # and add the LOCAL resource paths back in: self.questions[question_num].hintTextArea.content_w_resourcePaths \ = self.questions[question_num].hintTextArea.MassageResourceDirsIntoContent( \ self.questions[question_num].hintTextArea.content_wo_resourcePaths) self.questions[question_num].hintTextArea.content = \ self.questions[question_num].hintTextArea.content_w_resourcePaths else: # no user-defined feedback, just using the default: self.questions[question_num].hintTextArea.content = "" self.questions[question_num].hintTextArea.content_w_resourcePaths \ = "" self.questions[question_num].hintTextArea.content_wo_resourcePaths \ = "" if len(feedbacks) >= 1: inner_feedback = feedbacks[0] self.questions[question_num].feedbackTextArea.content_wo_resourcePaths \ = inner_feedback.renderContents().decode('utf-8') # and add the LOCAL resource paths back in: self.questions[question_num].feedbackTextArea.content_w_resourcePaths \ = self.questions[question_num].feedbackTextArea.MassageResourceDirsIntoContent( \ self.questions[question_num].feedbackTextArea.content_wo_resourcePaths) self.questions[question_num].feedbackTextArea.content = \ self.questions[question_num].feedbackTextArea.content_w_resourcePaths else: # no user-defined feedback, just using the default: self.questions[question_num].feedbackTextArea.content = "" self.questions[question_num].feedbackTextArea.content_w_resourcePaths \ = "" self.questions[question_num].feedbackTextArea.content_wo_resourcePaths \ = "" def upgradeToVersion1(self): """ Upgrades the node from version 0 to 1. Old packages will loose their icons, but they will load. """ log.debug(u"Upgrading iDevice") self.icon = u"multichoice" def upgradeToVersion2(self): """ Upgrades the node from 1 (v0.5) to 2 (v0.6). Old packages will loose their icons, but they will load. """ log.debug(u"Upgrading iDevice") self.emphasis = Idevice.SomeEmphasis def upgradeToVersion3(self): """ Upgrades the node from 1 (v0.6) to 2 (v0.7). Change icon from 'multichoice' to 'question' """ log.debug(u"Upgrading iDevice icon") self.icon = "question" def upgradeToVersion4(self): """ Upgrades v0.6 to v0.7. """ self.lastIdevice = False def upgradeToVersion5(self): """ Upgrades exe to v0.10 """ self._upgradeIdeviceToVersion1() self._hintInstruc = self.__dict__['hintInstruc'] self._questionInstruc = self.__dict__['questionInstruc'] self._keyInstruc = self.__dict__['keyInstruc'] def upgradeToVersion6(self): """ Upgrades exe to v0.11 """ self._feedbackInstruc = x_(u"""Type in the feedback that you want the student to see when selecting the particular question. If you don't complete this box, eXe will automatically provide default feedback as follows: "Correct answer" as indicated by the selection for the correct answer; or "Wrong answer" for the other alternatives.""") def upgradeToVersion7(self): """ Upgrades to v0.12 """ self._upgradeIdeviceToVersion2() self.systemResources += [ "common.js", "libot_drag.js", "panel-amusements.png", "stock-stop.png" ] def upgradeToVersion8(self): """ Upgrades to v0.15 """ self.instructionsForLearners = TextAreaField( x_(u'Instructions'), x_(u"""Provide instruction on how the True/False Question should be completed."""), x_(u'Read the paragraph below and ' 'fill in the missing words.')) self.instructionsForLearners.idevice = self def upgradeToVersion9(self): """ Upgrades to somewhere before version 0.25 (post-v0.24) Taking the TrueFalseQuestions' old unicode string fields, and converting them into a image-enabled TextAreaFields: """ for question in self.questions: question.upgrade_setIdevice(self)
class CasestudyIdevice(Idevice): """ A multichoice Idevice is one built up from question and options """ persistenceVersion = 8 def __init__(self, story="", defaultImage=None): """ Initialize """ Idevice.__init__(self, x_(u"Case Study"), x_(u"University of Auckland"), x_(u"""A case study is a device that provides learners with a simulation that has an educational basis. It takes a situation, generally based in reality, and asks learners to demonstrate or describe what action they would take to complete a task or resolve a situation. The case study allows learners apply their own knowledge and experience to completing the tasks assigned. when designing a case study consider the following:<ul> <li> What educational points are conveyed in the story</li> <li> What preparation will the learners need to do prior to working on the case study</li> <li> Where the case study fits into the rest of the course</li> <li> How the learners will interact with the materials and each other e.g. if run in a classroom situation can teams be setup to work on different aspects of the case and if so how are ideas feed back to the class</li></ul>"""), "", u"casestudy") self.emphasis = Idevice.SomeEmphasis self._storyInstruc = x_(u"""Create the case story. A good case is one that describes a controversy or sets the scene by describing the characters involved and the situation. It should also allow for some action to be taken in order to gain resolution of the situation.""") self.storyTextArea = TextAreaField(x_(u'Story:'), self._storyInstruc, story) self.storyTextArea.idevice = self self.questions = [] self._questionInstruc = x_(u"""Describe the activity tasks relevant to the case story provided. These could be in the form of questions or instructions for activity which may lead the learner to resolving a dilemma presented. """) self._feedbackInstruc = x_(u"""Provide relevant feedback on the situation.""") if defaultImage is None: defaultImage = G.application.config.webDir/'images'/DEFAULT_IMAGE self.defaultImage = toUnicode(defaultImage) self.addQuestion() # Properties storyInstruc = lateTranslate('storyInstruc') questionInstruc = lateTranslate('questionInstruc') feedbackInstruc = lateTranslate('feedbackInstruc') storyInstruc = lateTranslate('storyInstruc') questionInstruc = lateTranslate('questionInstruc') feedbackInstruc = lateTranslate('feedbackInstruc') def addQuestion(self): """ Add a new question to this iDevice. """ self.questions.append(Question(self)) def getResourcesField(self, this_resource): """ implement the specific resource finding mechanism for this iDevice: """ # be warned that before upgrading, this iDevice field could not exist: if hasattr(self, 'storyTextArea')\ and hasattr(self.storyTextArea, 'images'): for this_image in self.storyTextArea.images: if hasattr(this_image, '_imageResource') \ and this_resource == this_image._imageResource: return self.storyTextArea for this_question in self.questions: this_field = this_question.getResourcesField(this_resource) if this_field is not None: return this_field return None def getRichTextFields(self): """ Like getResourcesField(), a general helper to allow nodes to search through all of their fields without having to know the specifics of each iDevice type. """ fields_list = [] if hasattr(self, 'storyTextArea'): fields_list.append(self.storyTextArea) for this_question in self.questions: fields_list.extend(this_question.getRichTextFields()) return fields_list def burstHTML(self, i): """ takes a BeautifulSoup fragment (i) and bursts its contents to import this idevice from a CommonCartridge export """ # CaseStudy Idevice: title = i.find(name='h2', attrs={'class' : 'iDeviceTitle' }) self.title = title.renderContents().decode('utf-8') inner = i.find(name='div', attrs={'class' : 'iDevice_inner' }) story = inner.find(name='div', attrs={'class' : 'block' , 'id' : re.compile('^ta') }) self.storyTextArea.content_wo_resourcePaths = \ story.renderContents().decode('utf-8') # and add the LOCAL resource paths back in: self.storyTextArea.content_w_resourcePaths = \ self.storyTextArea.MassageResourceDirsIntoContent( \ self.storyTextArea.content_wo_resourcePaths) self.storyTextArea.content = self.storyTextArea.content_w_resourcePaths case_questions = inner.findAll(name='div', attrs={'class' : 'question'}) for question_num in range(len(case_questions)): if question_num > 0: # only created with the first question, add others: self.addQuestion() question = case_questions[question_num] case_stories = question.findAll(name='div', attrs={'class' : 'block' , 'id' : re.compile('^taquesQuestion') }) if len(case_stories) == 1: # ELSE: should warn of unexpected result! inner_question = case_stories[0] self.questions[question_num].questionTextArea.content = \ inner_question.renderContents().decode('utf-8') self.questions[question_num].questionTextArea.content_w_resourcePaths \ = inner_question.renderContents().decode('utf-8') self.questions[question_num].questionTextArea.content_wo_resourcePaths \ = inner_question.renderContents().decode('utf-8') # and add the LOCAL resource paths back in: self.questions[question_num].questionTextArea.content_w_resourcePaths \ = self.questions[question_num].questionTextArea.MassageResourceDirsIntoContent( \ self.questions[question_num].questionTextArea.content_wo_resourcePaths) self.questions[question_num].questionTextArea.content = \ self.questions[question_num].questionTextArea.content_w_resourcePaths case_feedbacks = question.findAll(name='div', attrs={'class' : 'feedback' , 'id' : re.compile('^sq') }) if len(case_feedbacks) == 1: # no warning otherwise, since feedback is optional inner_feedback = case_feedbacks[0] self.questions[question_num].feedbackTextArea.content_wo_resourcePaths \ = inner_feedback.renderContents().decode('utf-8') # and add the LOCAL resource paths back in: self.questions[question_num].feedbackTextArea.content_w_resourcePaths \ = self.questions[question_num].feedbackTextArea.MassageResourceDirsIntoContent( \ self.questions[question_num].feedbackTextArea.content_wo_resourcePaths) self.questions[question_num].feedbackTextArea.content = \ self.questions[question_num].feedbackTextArea.content_w_resourcePaths else: self.questions[question_num].feedbackTextArea.content = "" self.questions[question_num].feedbackTextArea.content_w_resourcePaths \ = "" self.questions[question_num].feedbackTextArea.content_wo_resourcePaths \ = "" def upgradeToVersion1(self): """ Upgrades the node from version 0 to 1. Old packages will loose their icons, but they will load. """ log.debug(u"Upgrading iDevice") self.icon = "casestudy" def upgradeToVersion2(self): """ Upgrades the node from 1 (v0.5) to 2 (v0.6). Old packages will loose their icons, but they will load. """ log.debug(u"Upgrading iDevice") self.emphasis = Idevice.SomeEmphasis def upgradeToVersion3(self): """ Upgrades v0.6 to v0.7. """ self.lastIdevice = False def upgradeToVersion4(self): """ Upgrades to exe v0.10 """ self._upgradeIdeviceToVersion1() self._storyInstruc = self.__dict__['storyInstruc'] self._questionInstruc = self.__dict__['questionInstruc'] self._feedbackInstruc = self.__dict__['feedbackInstruc'] def upgradeToVersion5(self): """ Upgrades to v0.12 """ self._upgradeIdeviceToVersion2() def upgradeToVersion6(self): """ Upgrades for v0.18 """ self.defaultImage = toUnicode(G.application.config.webDir/'images'/DEFAULT_IMAGE) for question in self.questions: question.setupImage(self) def upgradeToVersion7(self): """ Upgrades to somewhere before version 0.25 (post-v0.24) Taking the old unicode string fields, and converting them into a image-enabled TextAreaFields: """ self.storyTextArea = TextAreaField(x_(u'Story:'), self._storyInstruc, self.story) self.storyTextArea.idevice = self for question in self.questions: question.questionTextArea = TextAreaField(u'', u'', question.question) question.questionTextArea.idevice = self question.feedbackTextArea = TextAreaField(u'', u'', question.feedback) question.feedbackTextArea.idevice = self def upgradeToVersion8(self): """ Converting CaseStudyIdevice's image -> embedded image in its feedback field, a TextField than can now hold embedded images. BUT - due to the inconsistent loading of the objects via unpickling, since the resources aren't necessarily properly loaded and upgraded, NOR is the package necessarily, as it might not even have a list of resources yet, all of this conversion code must be done in an afterUpgradeHandler (as perhaps should have been done for the previous upgradeToVersion7) """ G.application.afterUpgradeHandlers.append(self.embedImagesInFeedback) def embedImagesInFeedback(self): """ Loop through each question, to call their conversion: CaseStudyIdevice's image -> embedded in its feedback field, now that its TextField can hold embeddded images. """ for question in self.questions: question.embedImageInFeedback()
class DestacadofpdIdevice(Idevice): """ El iDevice Destacado permite resaltar texto para llamar la atención del alumnado """ persistenceVersion = 7 def __init__(self, activity="", answer=""): """ Initialize """ Idevice.__init__( self, x_(u"FPD - Destacado"), x_(u"Jose Ramon Jimenez Reyes"), x_(u"""Destacado es un iDevice que permite resaltar texto para llamar la atención del alumnado.""" ), u"", u"destacadofpd") self.emphasis = Idevice.NoEmphasis self._activityInstruc = x_( u"""Introduce el texto que aparecerá en este iDevice""") self.systemResources += ["common.js"] self.activityTextArea = TextAreaField(x_(u'Texto Destacado:'), self._activityInstruc, activity) self.activityTextArea.idevice = self # Properties activityInstruc = lateTranslate('activityInstruc') def getResourcesField(self, this_resource): """ implement the specific resource finding mechanism for this iDevice: """ # be warned that before upgrading, this iDevice field could not exist: if hasattr(self, 'activityTextArea')\ and hasattr(self.activityTextArea, 'images'): for this_image in self.activityTextArea.images: if hasattr(this_image, '_imageResource') \ and this_resource == this_image._imageResource: return self.activityTextArea return None def getRichTextFields(self): fields_list = [] if hasattr(self, 'activityTextArea'): fields_list.append(self.activityTextArea) return fields_list def burstHTML(self, i): # Destacadofpd Idevice: title = i.find(name='span', attrs={'class': 'iDeviceTitle'}) self.title = title.renderContents().decode('utf-8') reflections = i.findAll(name='div', attrs={'id': re.compile('^ta')}) # should be exactly two of these: # 1st = field[0] == Activity if len(reflections) >= 1: self.activityTextArea.content_wo_resourcePaths = \ reflections[0].renderContents().decode('utf-8') # and add the LOCAL resource paths back in: self.activityTextArea.content_w_resourcePaths = \ self.activityTextArea.MassageResourceDirsIntoContent( \ self.activityTextArea.content_wo_resourcePaths) self.activityTextArea.content = \ self.activityTextArea.content_w_resourcePaths def upgradeToVersion1(self): """ Upgrades the node from version 0 to 1. """ log.debug(u"Upgrading iDevice") self.icon = u"destacadofpd" def upgradeToVersion2(self): """ Upgrades the node from 1 (v0.5) to 2 (v0.6). Old packages will loose their icons, but they will load. """ log.debug(u"Upgrading iDevice") self.emphasis = Idevice.NoEmphasis def upgradeToVersion3(self): """ Upgrades v0.6 to v0.7. """ self.lastIdevice = False def upgradeToVersion4(self): """ Upgrades to exe v0.10 """ self._upgradeIdeviceToVersion1() self._activityInstruc = self.__dict__['activityInstruc'] def upgradeToVersion5(self): """ Upgrades to exe v0.10 """ self._upgradeIdeviceToVersion1() def upgradeToVersion6(self): """ Upgrades to v0.12 """ self._upgradeIdeviceToVersion2() # self.systemResources += ["common.js"] def upgradeToVersion7(self): """ Upgrades to somewhere before version 0.25 (post-v0.24) Taking the old unicode string fields, and converting them into image-enabled TextAreaFields: """ self.activityTextArea = TextAreaField(x_(u'Texto Destacado:'), self._activityInstruc, self.activity) self.activityTextArea.idevice = self
class HintIdevice(Idevice): """ HintIdevice: just has a block of text don't exporting """ persistenceVersion = 9 def __init__(self, content=""): Idevice.__init__( self, x_(u"Remark"), x_(u"University of Auckland"), x_(u"""Leave a commentary for others who work on this package."""), "", "") self.emphasis = Idevice.SomeEmphasis self.icon = u"summary" self.group = Idevice.Didactics self.content = TextAreaField( x_(u"Hint"), x_(u"""Use this field to leave a comment for people who works on this package with you. This iDevice won't be exported"""), content) self.content.idevice = self if content: self.edit = False # determines if the element is exported to presentation self.presentable = 'False' def getResourcesField(self, this_resource): """ implement the specific resource finding mechanism for this iDevice: """ # be warned that before upgrading, this iDevice field could not exist: if hasattr(self, 'content') and hasattr(self.content, 'images'): for this_image in self.content.images: if hasattr(this_image, '_imageResource') \ and this_resource == this_image._imageResource: return self.content return None def getRichTextFields(self): """ Like getResourcesField(), a general helper to allow nodes to search through all of their fields without having to know the specifics of each iDevice type. """ fields_list = [] if hasattr(self, 'content'): fields_list.append(self.content) return fields_list def burstHTML(self, i): """ takes a BeautifulSoup fragment (i) and bursts its contents to import this idevice from a CommonCartridge export """ # Free Text Idevice: #title = i.find(name='span', attrs={'class' : 'iDeviceTitle' }) #idevice.title = title.renderContents().decode('utf-8') # no title for this iDevice. # FreeText is also a catch-all idevice for any other which # is unable to be burst on its own. if i.attrMap['class'] == "FreeTextIdevice": # For a REAL FreeText, just read the inner div with class: inner = i.find(name='div', attrs={ 'class': 'block', 'style': 'display:block' }) else: # But for all others, read the whole thing: inner = i self.content.content_wo_resourcePaths = \ inner.renderContents().decode('utf-8') # and add the LOCAL resource paths back in: self.content.content_w_resourcePaths = \ self.content.MassageResourceDirsIntoContent( \ self.content.content_wo_resourcePaths) self.content.content = self.content.content_w_resourcePaths def upgradeToVersion1(self): """ Upgrades the node from version 0 (eXe version 0.4) to 1. Adds icon """ self.icon = "" def upgradeToVersion2(self): """ Upgrades the node from version 1 (not released) to 2 Use new Field classes """ self.content = TextAreaField( "content", x_(u"This is a free text field general learning content can be entered." ), self.content) def upgradeToVersion3(self): """ Upgrades the node from 2 (v0.5) to 3 (v0.6). Old packages will loose their icons, but they will load. """ log.debug(u"Upgrading iDevice") self.emphasis = Idevice.NoEmphasis def upgradeToVersion4(self): """ Upgrades v0.6 to v0.7. """ self.lastIdevice = False def upgradeToVersion5(self): """ Upgrades v0.6 to v0.7. """ self._upgradeIdeviceToVersion1() def upgradeToVersion6(self): """ Upgrades to v0.12 """ self._upgradeIdeviceToVersion2() def upgradeToVersion7(self): """ Attach the idevice to the TextAreaField for tinyMCE image embedding: """ self.content.idevice = self def upgradeToVersion8(self): """ Attach presentable to idevice Tum changes """ self.presentable = 'False' def upgradeToVersion9(self): """ Adds group to idevice """ self.group = Idevice.Content
class ScormDropDownIdevice(Idevice): """ Holds a paragraph with words missing that the student must fill in """ persistenceVersion = 4 def __init__(self, parentNode=None): """ Sets up the idevice title and instructions etc """ Idevice.__init__(self, x_(u"SCORM Test Dropdown"), x_(u"University of Auckland"), x_(u"<p>Cloze exercises are texts or " "sentences where students must fill in " "missing words. They are often used for the " "following purposes:</p>" "<ol>" "<li>To check knowledge of core course " "concepts (this could be a pre-check, " "formative exercise, or summative check).</li>" "<li>To check reading comprehension.</li>" "<li>To check vocabulary knowledge.</li>" "<li>To check word formation and/or grammatical " "competence. </li></ol>"), x_(u"<dl>" " <dt>If your goal is to test understanding " "of core concepts or reading comprehension" " </dt>" " <dd>" " <p>" " Write a summary of the concept or reading long " " enough to adequately test the target's " "knowledge, but short enough not to " "induce fatigue. Less than one typed page is " "probably adequate, but probably " "considerably less for young students or " "beginners." " </p>" " <p>" "Select words in the text that" "are key to understanding the concepts. These" "will probably be verbs, nouns, and key adverbs." "Choose alternatives with one clear answer." " </p>" " </dd>" " <dt>" "If your goal is to test vocabulary knowledge" " </dt>" " <dd>" "<p>Write a text using the target vocabulary. This " "text should be coherent and cohesive, and be of " "an appropriate length. Highlight the target " "words in the text. Choose alternatives with one " "clear answer.</p>" " </dd>" " <dt>" "If your goal is to test word " "formation/grammar:" " </dt>" " <dd>" " <p>" "Write a text using the " "target forms. This text should be coherent and " "cohesive, and be of an appropriate length. " "Remember that the goal is not vocabulary " "knowledge, so the core meanings of the stem " "words should be well known to the students." " </p>" " <p>" "Highlight the target words in the text. Provide " "alternatives with the same word stem, but " "different affixes. It is a good idea to get a " "colleague to test the test/exercise to make " "sure there are no surprises!" " </p>" " </dd>" "</dl>"), u"question", parentNode) self.instructionsForLearners = TextAreaField( x_(u'Instructions'), #translated # x_(u"""Hier können Sie eine Aufgabenstellung eingeben oder die Standardanweisung übernehmen."""), x_(u"""Provide instruction how to complete the exercise or take the default text."""), # x_(u"""Wähle im folgenden Abschnitt die richtigen Antworten aus!""")) x_(u'Choose the correct answers in the paragraph below.')) self.instructionsForLearners.idevice = self self._content = ClozeField(x_(u'Cloze'), x_(u"""<p>To create a gap with answer options, write the correct answer and then separated by '|' the wrong answers: true|false|false|false ... Mark all answer options and click on the 'Hide/Show Word' button below. Hint: answers may contain spaces.</p>""")) # x_(u"""<p>Um eine Lücke mit Antwortmöglichkeiten zu erzeugen, # schreiben sie zuerst die richtige Antwort und dann getrennt # mit '|' die falschen Antworten, also folgendermaßen: # richtig|falsch|falsch|falsch... # Markieren Sie die gesamten Antworten und klicken sie # auf den Button 'Wort verbergen/anzeigen'. # Hinweise:<br>In Antworten können Leerzeichen enthalten # sein<br>Das Zeichen '|' erhalten Sie, indem Sie die # 'Alt Gr'-Taste gedrückt halten und dann auf die Taste # mit dem Zeichen '|' tippen (auf deutschen Tastaturen meist # neben dem 'Y'). # </p>""")) self._content.idevice = self self.feedback = TextAreaField(x_(u'Feedback'), x_(u'Enter any feedback you wish to provide the learner ' 'with-in the feedback field. This field can be left blank.')) self.feedback.idevice = self self.emphasis = Idevice.SomeEmphasis self.systemResources += ["common.js"] self.isCloze = True # Properties content = property(lambda self: self._content, doc="Read only, use 'self.content.encodedContent = x' " "instead") def getResourcesField(self, this_resource): """ implement the specific resource finding mechanism for this iDevice: """ # be warned that before upgrading, this iDevice field could not exist: if hasattr(self, '_content') and hasattr(self._content, 'images'): for this_image in self._content.images: if hasattr(this_image, '_imageResource') \ and this_resource == this_image._imageResource: return self._content # be warned that before upgrading, this iDevice field could not exist: if hasattr(self, 'instructionsForLearners')\ and hasattr(self.instructionsForLearners, 'images'): for this_image in self.instructionsForLearners.images: if hasattr(this_image, '_imageResource') \ and this_resource == this_image._imageResource: return self.instructionsForLearners # be warned that before upgrading, this iDevice field could not exist: if hasattr(self, 'feedback') and hasattr(self.feedback, 'images'): for this_image in self.feedback.images: if hasattr(this_image, '_imageResource') \ and this_resource == this_image._imageResource: return self.feedback return None def getRichTextFields(self): """ Like getResourcesField(), a general helper to allow nodes to search through all of their fields without having to know the specifics of each iDevice type. """ fields_list = [] if hasattr(self, '_content'): fields_list.append(self._content) if hasattr(self, 'instructionsForLearners'): fields_list.append(self.instructionsForLearners) if hasattr(self, 'feedback'): fields_list.append(self.feedback) return fields_list def burstHTML(self, i): """ takes a BeautifulSoup fragment (i) and bursts its contents to import this idevice from a CommonCartridge export """ # Cloze Idevice: title = i.find(name='span', attrs={'class' : 'iDeviceTitle' }) self.title = title.renderContents().decode('utf-8') inner = i.find(name='div', attrs={'class' : 'iDevice_inner' }) instruct = inner.find(name='div', attrs={'class' : 'block' , 'style' : 'display:block' }) self.instructionsForLearners.content_wo_resourcePaths = \ instruct.renderContents().decode('utf-8') # and add the LOCAL resource paths back in: self.instructionsForLearners.content_w_resourcePaths = \ self.instructionsForLearners.MassageResourceDirsIntoContent( \ self.instructionsForLearners.content_wo_resourcePaths) self.instructionsForLearners.content = \ self.instructionsForLearners.content_w_resourcePaths content = inner.find(name='div', attrs={'id' : re.compile('^cloze') }) rebuilt_contents = "" for this_content in content.contents: if not this_content.__str__().startswith('<input'): if this_content.__str__().startswith('<span'): # Now, decode the answer # with code reverse-engineered from: # a) Cloze's getClozeAnswer() in common.js # b) ClozeElement's renderView() + encrypt() answer = "" code_key = 'X' code = this_content.renderContents() code = code.decode('base64') # now in the form %uABCD%uEFGH%uIJKL.... char_pos = 0 while char_pos < len(code): # first 2 chars = %u, replace with 0x to get int # next 4 = the encoded unichr this_code_char = "0x" + code[char_pos+2 : char_pos+6] this_code_ord = int(this_code_char, 16) letter = chr(ord(code_key)^this_code_ord) answer += letter # key SHOULD be ^'d by letter, but seems to be: code_key = letter char_pos += 6 rebuilt_contents += "<U>" + answer + "</U>" elif not this_content.__str__().startswith('<div'): # this should be the un-clozed text: rebuilt_contents += this_content.__str__() self._content.content_wo_resourcePaths = rebuilt_contents # and add the LOCAL resource paths back in: self._content.content_w_resourcePaths = \ self._content.MassageResourceDirsIntoContent( \ self._content.content_wo_resourcePaths) self._content.content = self._content.content_w_resourcePaths feedback = inner.find(name='div', attrs={'class' : 'feedback' }) self.feedback.content_wo_resourcePaths = \ feedback.renderContents().decode('utf-8') # and add the LOCAL resource paths back in: self.feedback.content_w_resourcePaths = \ self.feedback.MassageResourceDirsIntoContent( \ self.feedback.content_wo_resourcePaths) self.feedback.content = self.feedback.content_w_resourcePaths # and each cloze flag field (strict, case, instant): flag_strict = inner.find(name='input', attrs={'id' : re.compile('^clozeFlag.*strictMarking$') }) if flag_strict.attrMap['value']=="true": self._content.strictMarking = True flag_caps = inner.find(name='input', attrs={'id' : re.compile('^clozeFlag.*checkCaps$') }) if flag_caps.attrMap['value']=="true": self._content.checkCaps = True flag_instant = inner.find(name='input', attrs={'id' : re.compile('^clozeFlag.*instantMarking$') }) if flag_instant.attrMap['value']=="true": self._content.instantMarking = True def upgradeToVersion1(self): """ Upgrades exe to v0.10 """ self._upgradeIdeviceToVersion1() self.instructionsForLearners = TextAreaField( x_(u'Instructions For Learners'), x_(u'Put instructions for learners here'), x_(u'Read the paragraph below and ' 'fill in the missing words')) self.instructionsForLearners.idevice = self self.feedback = TextAreaField(x_(u'Feedback')) self.feedback.idevice = self def upgradeToVersion2(self): """ Upgrades exe to v0.11 """ self.content.autoCompletion = True self.content.autoCompletionInstruc = _(u"Allow auto completion when " u"user filling the gaps.") def upgradeToVersion3(self): """ Upgrades to v0.12 """ self._upgradeIdeviceToVersion2() self.systemResources += ["common.js"] def upgradeToVersion4(self): """ Upgrades to v0.20.3 """ self.isCloze = True
class FreeTextIdevice(Idevice): """ FreeTextIdevice: just has a block of text """ persistenceVersion = 7 def __init__(self, content="", type=None, parent=None): Idevice.__init__( self, x_(u"Free Text"), x_(u"University of Auckland"), x_(u"""The majority of a learning resource will be establishing context, delivering instructions and providing general information. This provides the framework within which the learning activities are built and delivered."""), "", "") self.emphasis = Idevice.NoEmphasis self.content = TextAreaField( x_(u"Free Text"), x_(u"""Use this field to enter text. This iDevice has no emphasis applied although limited formatting can be applied to text through the text editing buttons associated with the field."""), content) self.content.idevice = self if content: self.edit = False self.type = type self.parent = parent self.childs = [] if parent: self.parent.childs.append(self) def setContent(self, content_w_resourcePaths="", content_wo_resourcePaths=""): self.content.content = content_w_resourcePaths self.content.content_w_resourcePaths = content_w_resourcePaths self.content.content_wo_resourcePaths = content_wo_resourcePaths def getResourcesField(self, this_resource): """ implement the specific resource finding mechanism for this iDevice: """ # be warned that before upgrading, this iDevice field could not exist: if hasattr(self, 'content') and hasattr(self.content, 'images'): for this_image in self.content.images: if hasattr(this_image, '_imageResource') \ and this_resource == this_image._imageResource: return self.content return None def getRichTextFields(self): """ Like getResourcesField(), a general helper to allow nodes to search through all of their fields without having to know the specifics of each iDevice type. """ fields_list = [] if hasattr(self, 'content'): fields_list.append(self.content) return fields_list def burstHTML(self, i): """ takes a BeautifulSoup fragment (i) and bursts its contents to import this idevice from a CommonCartridge export """ # Free Text Idevice: #title = i.find(name='span', attrs={'class' : 'iDeviceTitle' }) #idevice.title = title.renderContents().decode('utf-8') # no title for this iDevice. # FreeText is also a catch-all idevice for any other which # is unable to be burst on its own. if i.attrMap['class'] == "FreeTextIdevice": # For a REAL FreeText, just read the inner div with class: inner = i.find(name='div', attrs={ 'class': 'block', 'style': 'display:block' }) else: # But for all others, read the whole thing: inner = i self.content.content_wo_resourcePaths = \ inner.renderContents().decode('utf-8') # and add the LOCAL resource paths back in: self.content.content_w_resourcePaths = \ self.content.MassageResourceDirsIntoContent( \ self.content.content_wo_resourcePaths) self.content.content = self.content.content_w_resourcePaths def upgradeToVersion1(self): """ Upgrades the node from version 0 (eXe version 0.4) to 1. Adds icon """ self.icon = "" def upgradeToVersion2(self): """ Upgrades the node from version 1 (not released) to 2 Use new Field classes """ self.content = TextAreaField( "content", x_(u"This is a free text field general learning content can be entered." ), self.content) def upgradeToVersion3(self): """ Upgrades the node from 2 (v0.5) to 3 (v0.6). Old packages will loose their icons, but they will load. """ log.debug(u"Upgrading iDevice") self.emphasis = Idevice.NoEmphasis def upgradeToVersion4(self): """ Upgrades v0.6 to v0.7. """ self.lastIdevice = False def upgradeToVersion5(self): """ Upgrades v0.6 to v0.7. """ self._upgradeIdeviceToVersion1() def upgradeToVersion6(self): """ Upgrades to v0.12 """ self._upgradeIdeviceToVersion2() def upgradeToVersion7(self): """ Attach the idevice to the TextAreaField for tinyMCE image embedding: """ self.content.idevice = self
class TOCIdevice(Idevice): """ Build a table of content """ persistenceVersion = 9 def __init__(self): Idevice.__init__(self, x_(u"TOC"), x_(u"TUM"), x_(u"""Insert a table of content"""), u"", u"") self.emphasis = Idevice.NoEmphasis self.group = Idevice.Content self.source = u"" self.article = TextAreaField(x_(u"Article")) self.article.idevice = self self.images = {} self.icon = u"inter" def generateTOC(self): '''Generates toc like as we were exporting''' root = self.parentNode.package.root pageNumbers = {} html = self.generateTOCEntry(root, pageNumbers) self.article.content_w_resourcePaths = html self.article.content_wo_resourcePaths = html def generateTOCEntry(self, page, pageNumbers): '''recursively generates a TOC entry for a page''' html = u'<ul class="toc">\n' pageName = page.titleShort.lower().replace(" ", "_") pageName = re.sub(r"\W", "", pageName) if pageName in pageNumbers: pageNumbers[pageName] += 1 pageName += str(pageNumbers[pageName]) else: pageNumbers[pageName] = 0 html += u'<a href="%s.html">%s</a>\n' % \ (quote(pageName), escape(page.titleShort)) if page.children: for child in page.children: html += u'<li>\n' + self.\ generateTOCEntry(child, pageNumbers) + '</li>\n' html += u'</ul>\n' return html def getRichTextFields(self): """ Like getResourcesField(), a general helper to allow nodes to search through all of their fields without having to know the specifics of each iDevice type. """ fields_list = [] if hasattr(self, 'article'): fields_list.append(self.article) return fields_list def burstHTML(self, i): """ takes a BeautifulSoup fragment (i) and bursts its contents to import this idevice from a CommonCartridge export """ # Wiki Article Idevice: # option title for Wikipedia, with mode emphasis: title = i.find(name='span', attrs={'class' : 'iDeviceTitle' }) if title is not None: self.title = title.renderContents().decode('utf-8') self.emphasis=Idevice.SomeEmphasis wiki = i.find(name='div', attrs={'id' : re.compile('^ta') }) self.article.content_wo_resourcePaths = \ wiki.renderContents().decode('utf-8') # and add the LOCAL resource paths back in: self.article.content_w_resourcePaths = \ self.article.MassageResourceDirsIntoContent( \ self.article.content_wo_resourcePaths) self.article.content = self.article.content_w_resourcePaths site = i.find(name='div', attrs={'class' : 'wiki_site' }) if site is not None: self.site = site.attrMap['value'].decode('utf-8') name = i.find(name='div', attrs={'class' : 'article_name' }) if name is not None: # WARNING: the following crashes on accented characters, eg: # 'ascii' codec can't encode character u'\xe8' in # position 11: ordinal not in range(128) self.articleName = name.attrMap['value'].decode('utf-8') own_url = i.find(name='div', attrs={'class' : 'own_url' }) if own_url is not None: self.own_url = own_url.attrMap['value'].decode('utf-8')