diff --git a/flashcards/flashcards.py b/flashcards/flashcards.py index 17bb80b..937a6bf 100644 --- a/flashcards/flashcards.py +++ b/flashcards/flashcards.py @@ -1,19 +1,18 @@ """ - Flashcards XBlock allowes the editor to add a list of quesitions and - answers (separated by a semicolon) which are then displayed as flashcards. +Flashcards XBlock allowes the editor to add a list of quesitions and +answers (separated by a semicolon) which are then displayed as flashcards. """ import pkg_resources from xblock.core import XBlock -from xblock.fields import Scope, Dict, String -from xblock.fragment import Fragment - -from lxml import etree +from xblock.fields import Scope, Dict, String, List +from web_fragments.fragment import Fragment +from xblock.utils.resources import ResourceLoader from jinja2 import Environment, PackageLoader -env = Environment(loader=PackageLoader('flashcards', 'static/html')) +env = Environment(loader=PackageLoader("flashcards", "static/html")) class FlashcardsXBlock(XBlock): @@ -21,38 +20,37 @@ class FlashcardsXBlock(XBlock): The content (the values between the tags) is saved as a dictionary and passed as a dictionary to the HTML template """ - title = String( - default=u"Flashcards title", - scope=Scope.settings, - help=u"Title of the flashcards block" - ) - content = Dict( - default={}, - scope=Scope.settings, - help=u"List of items" - ) + loader = ResourceLoader(__name__) + title = String( + default="", + scope=Scope.settings, + help="Title of the flashcards block", + ) + content = List(default=[], scope=Scope.settings, help="List of items") def resource_string(self, path): """Handy helper for getting resources from our kit.""" data = pkg_resources.resource_string(__name__, path) return data.decode("utf8") - def student_view(self, context=None): """Create fragment and send the appropriate context.""" context = { - 'flashcards': self.content, - 'title': self.title, + "flashcards": self.content, + "title": self.title, } - frag = Fragment() - template = env.get_template("flashcards.html") - frag.add_content(template.render(**context)) + frag = Fragment( + self.loader.render_django_template( + "static/html/flashcards.html", context=context + ) + ) + # frag.add_content() frag.add_css(self.resource_string("static/css/flashcards.css")) frag.add_javascript(self.resource_string("static/js/src/flashcards.js")) - frag.initialize_js('FlashcardsXBlock') + frag.initialize_js("FlashcardsXBlock", context) return frag @classmethod @@ -74,53 +72,44 @@ def parse_xml(cls, node, runtime, keys, id_generator): flashcards[element.attrib["front"]] = element.attrib["back"] block.content = flashcards - block.title = node.attrib['title'] + block.title = node.attrib["title"] return block - @staticmethod def workbench_scenarios(): """A canned scenario for display in the workbench.""" return [ - ("FlashcardsXBlock", - """ + ( + "FlashcardsXBlock", + """ - """), + """, + ), ] def studio_view(self, context): """Create a fragment used to display the edit view in the Studio.""" context = { - 'flashcards': self.content, - 'title': self.title, + "flashcards": self.content, + "title": self.title, } frag = Fragment() - template = env.get_template('flashcards_edit.html') + template = env.get_template("flashcards_edit.html") frag.add_content(template.render(**context)) frag.add_css(self.resource_string("static/css/flashcards_edit.css")) frag.add_javascript(self.resource_string("static/js/src/flashcards_edit.js")) - frag.initialize_js('FlashcardsEditXBlock') + frag.initialize_js("FlashcardsEditXBlock", context) return frag @XBlock.json_handler - def studio_submit(self, data, suffix=''): + def studio_submit(self, data, suffix=""): """Called when submitting the form in Studio.""" - self.title = data.get('title') - - flashcards = {} - - fclist = data.get('flashcards').items() - fclist.reverse() # print out the list in the same order as entered - for item in fclist: - front, back = item - flashcards[front] = back - - self.content = flashcards - - return {'result':'success'} \ No newline at end of file + self.title = data.get("title") + self.content = data.get("flashcards") + return {"result": "success"} diff --git a/flashcards/static/css/flashcards.css b/flashcards/static/css/flashcards.css index fcab905..887fdd1 100644 --- a/flashcards/static/css/flashcards.css +++ b/flashcards/static/css/flashcards.css @@ -1,10 +1,4 @@ /* CSS for FlashcardsXBlock */ -.flashcards_block { - width:100%; - display:inline-block; - text-align:center; -} - .fc-title { display:block; width:100%; @@ -30,41 +24,53 @@ text-align:center; } -.flashcards_block ul { - padding:0; +.fc-number { + text-align: center; } -.flashcards_block li { - list-style: none; +.fc-container { + perspective: 900px; + width: 60%; + height: 653px; + display:inline-block; + text-align:center; } -.fc-question { - display:inline-block; - width:40%; - padding:5% 3%; - text-align:center; - font-weight:600; - font-size:2em; - border:1px solid #000; - border-radius:20px; - margin-right:2%; +.fc-card { + position: relative; + width: 100%; + height: 100%; + cursor: pointer; + transform-style: preserve-3d; + transform-origin: center right; + transition: transform 1s; + border: 1px solid rgba(236, 236, 236, 1); + box-shadow: 0px 2px 6px 0px rgba(0, 0, 0, 0.1); + margin-left: 35%; } -.fc-question:hover { - cursor: pointer; +.fc-card-face { + position: absolute; + width: 100%; + height: 100%; + line-height: 260px; + color: black; + text-align: center; + font-weight: bold; + font-size: 40px; + backface-visibility: hidden; } -.fc-answer { - visibility: hidden; - display:inline-block; - width:40%; - padding:5% 3%; - text-align:center; - font-weight:600; - font-size:2em; - border:1px solid #000; - border-radius:20px; - margin-left:2%; +.fc-card-face-back { + transform: rotateY(180deg); +} + +.fc-card.is-flipped { + transform: translateX(-100%) rotateY(-180deg); +} + +#fc-question:hover { + cursor: pointer; } .next-btn { @@ -103,4 +109,4 @@ cursor: default; background-image: none; border: none; -} \ No newline at end of file +} diff --git a/flashcards/static/html/flashcards.html b/flashcards/static/html/flashcards.html index ba736fb..33a684e 100644 --- a/flashcards/static/html/flashcards.html +++ b/flashcards/static/html/flashcards.html @@ -1,21 +1,12 @@ -
-
0 / {{ flashcards|length }}
-
{{ title }}
-
-
    - {% for question, answer in flashcards.items() %} -
  • -
    -

    Question

    - {{ question }} -
    -
    -

    Answer

    - {{ answer }} -
    -
  • - {% endfor %} - -
+
+
0 / {{ flashcards|length }}
+
{{ title }}
+
+
+
+
+
+
+
START
diff --git a/flashcards/static/html/flashcards_edit.html b/flashcards/static/html/flashcards_edit.html index e8f5162..230bd3d 100644 --- a/flashcards/static/html/flashcards_edit.html +++ b/flashcards/static/html/flashcards_edit.html @@ -1,36 +1,13 @@ - -
  • - +
  • -
    - - - -
  • @@ -45,4 +22,4 @@
-
\ No newline at end of file + diff --git a/flashcards/static/js/src/flashcards.js b/flashcards/static/js/src/flashcards.js index bf67487..c5c68ce 100644 --- a/flashcards/static/js/src/flashcards.js +++ b/flashcards/static/js/src/flashcards.js @@ -1,36 +1,30 @@ /* Javascript for FlashcardsXBlock. */ -function FlashcardsXBlock(runtime, element) { - /* Show the answer of the question by cliking on the question */ - $('.fc-question').click(function() { - $('.fc-answer').css('visibility', 'visible'); - }); +function FlashcardsXBlock(runtime, element, params) { + /* Initializing the variables for displaying the current question + and total questions. + */ + var currentNumber = -1; + var totalNumber = params.flashcards.length; + $('.fc-container').hide(); - /* Initializing the variables for displaying the current question - and total questions. - */ - var current_number = parseInt($('.current-fc').text())+1; - var total_number = parseInt($('.fc-total').text()); + /* Show the answer of the question by cliking on the question */ + $('.fc-card').click(function () { + $('.fc-card').toggleClass('is-flipped'); + }); - /* Hide all elements for the first iteration */ - $('.flashcards_block li').hide(); - $('.next-btn').click(function() { - - /* Hide the answer again */ - $('.fc-answer').css('visibility', 'hidden'); - - /* Removing the previous question. Have trouble figuring out how to - make it work without removing the previous question. - TO-DO: Figure this out! - */ - $('.flashcards_block > ul > li:visible:first').remove(); - $('.flashcards_block > ul > li:hidden:first').show(); - $('.next-btn').html('NEXT'); - $('.current-fc').html(current_number++); - - /* If the student reaches the end say FINISHED and disable going further */ - if (current_number == total_number+1) { - $('.btn').html('FINISHED!'); - $('.btn').addClass('finished-btn').removeClass('next-btn').off('click'); - } - }); + $('.next-btn').click(function () { + currentNumber++; + $('.fc-card').removeClass('is-flipped'); + $('.fc-container').show(); + $('#fc-question').html(`${params.flashcards[currentNumber]["front"]}`); + $('#fc-answer').html(`${params.flashcards[currentNumber]["back"]}`) + $('#current-fc').html(`${currentNumber + 1}`); + $('.next-btn').html('Nextt'); + /* If the student reaches the end say FINISHED and disable going further */ + if (currentNumber == totalNumber - 1) { + $('.next-btn').html('You did it!'); + $('.next-btn').addClass('finished-btn').removeClass('next-btn').off('click'); + } + }); } + diff --git a/flashcards/static/js/src/flashcards_edit.js b/flashcards/static/js/src/flashcards_edit.js index f3fae5a..616a51c 100644 --- a/flashcards/static/js/src/flashcards_edit.js +++ b/flashcards/static/js/src/flashcards_edit.js @@ -1,32 +1,64 @@ -function FlashcardsEditXBlock(runtime, element) { - $(element).find('.save-button').bind('click', function() { - var handlerUrl = runtime.handlerUrl(element, 'studio_submit'); +function FlashcardsEditXBlock(runtime, element, params) { + var addFieldButton = document.getElementById("more_fields"); + var flashCardList = document.getElementById('flashcard-list') + var flashcardNumber = params.flashcards.length || 1; + $('#flashcard-title').val(params.title); + /* Re-populate filed with the available data */ + if (params.flashcards.length > 0) { + for (var i = 0; i < flashcardNumber; i++) { + var front = params.flashcards[i].front; + var back = params.flashcards[i].back; + var fields = `
+ + + +
`; + flashCardList.insertAdjacentHTML("beforeend", fields); + } + } - /* Every flashcard (fc-item) has two input fields, "front" and "back" */ - var flashcard_list = {}; - var items = document.getElementsByClassName('fc-item'); + function add_fields() { + var fields = '
\n\ + \n\ + \n\ + \n\ +
'; + flashCardList.insertAdjacentHTML("beforeend", fields); + flashcardNumber++; + } - for (var i = 0; i < items.length; i++) { - /* Read every flashcard and save input values to a dictionary object */ - var inputs = items[i].getElementsByTagName('input'); - flashcard_list[inputs[0].value] = inputs[1].value; - } + addFieldButton.addEventListener("click", add_fields); - var data = { - title: $(element).find('input[name=title]').val(), - flashcards: flashcard_list - }; + $(element).find('.save-button').bind('click', function () { + var saveFlashCardsEndpoint = runtime.handlerUrl(element, 'studio_submit'); + /* Every flashcard (fc-item) has two input fields, "front" and "back" */ + var flashcardArray = []; + var items = document.getElementsByClassName('fc-item'); - var test = JSON.stringify(data); + for (var i = 0; i < items.length; i++) { + /* Read every flashcard and save input values to a dictionary object */ + var flashCardObject = {} + var inputs = items[i].getElementsByTagName('input'); + flashCardObject = { + "front": inputs[0].value, + "back": inputs[1].value + } + flashcardArray.push(flashCardObject); + } - runtime.notify('save', {state: 'start'}); - $.post(handlerUrl, JSON.stringify(data)).done(function(response) { - runtime.notify('save', {state:'end'}); - }); - }); + var data = { + title: $('#flashcard-title').val(), + flashcards: flashcardArray + }; - $(element).find('.cancel-button').bind('click', function() { - runtime.notify('cancel', {}); + runtime.notify('save', { state: 'start' }); + $.post(saveFlashCardsEndpoint, JSON.stringify(data)).done(function (response) { + runtime.notify('save', { state: 'end' }); }); + }); + + $(element).find('.cancel-button').bind('click', function () { + runtime.notify('cancel', {}); + }); }