diff --git a/src/main/webapp/app/internationalization.js b/src/main/webapp/app/internationalization.js index d44c394a8975d53957e89027e7ccac5e4bfdc342..0d2422873945a95ad6f0b5fc78e5c2ca28404555 100755 --- a/src/main/webapp/app/internationalization.js +++ b/src/main/webapp/app/internationalization.js @@ -373,6 +373,8 @@ ARE_YOU_SURE: "Sind Sie sicher?", DELETE_QUESTION_TITLE: "Frage löschen", DELETE_QUESTIONS_TITLE: "Fragen löschen", + DELETE_FLASHCARD_TITLE: "Lernkarte löschen", + DELETE_FLASHCARDS_TITLE: "Lernkarten löschen", DELETE_SESSION_TITLE: "Session löschen", DELETE_SESSION_NOTICE: "Es werden alle Fragen und Antworten der Session gelöscht", CATEGORY: "Thema", @@ -404,12 +406,16 @@ STATISTICS: "Statistiken", ALL_CORRECT: "Komplett richtig", ALL_WRONG: "Komplett falsch", - LEARNING_STATUS: "Lernstand des Kurses", + LEARNING_STATUS: "Lernstand des Kurses", DELETE_ALL: "Alle löschen", DELETE_ANSWERS_REQUEST: "Antworten löschen?", DELETE_ALL_ANSWERS_REQUEST: "Alle Antworten löschen?", + DELETE_VIEWS_REQUEST: "Ansichten löschen?", + DELETE_ALL_VIEWS_REQUEST: "Alle Ansichten löschen?", ALL_QUESTIONS_REMAIN: "Alle Fragen bleiben erhalten", + ALL_FLASHCARDS_REMAIN: "Alle Lernkarten bleiben erhalten", QUESTION_REMAINS: "Die Frage bleibt erhalten", + FLASHCARD_REMAINS: "Die Lernkarte bleibt erhalten", INCOMPLETE_INPUTS: "Ihre Eingaben sind unvollständig", DELETE_ALL_ANSWERS_INFO: "Es werden auch alle bisher gegebenen Antworten gelöscht", DELETE_ROUND_ANSWERS_COMPLETED: "Die Antworten der aktuellen Runde wurden gelöscht", @@ -793,18 +799,21 @@ IMP_ERROR_SAVE: "Session konnte nicht gespeichert werden", IMP_ERROR_IMAGE: "Session konnte nicht gespeichert werden. Bild überschreitet maximale Größe.", - /* CSV export*/ - QUESTIONS_CSV_EXPORT_BUTTON: "Fragen<br>exportieren", - QUESTIONS_CSV_EXPORT_MSBOX_TITLE: "Inhalte exportieren", - QUESTIONS_CSV_EXPORT_MSBOX_INFO: "Die Inhalte werden als CSV-Datei exportiert. Fragen vom Typ \"Hot Spots\" werden übersprungen. Für den gesamten Export der Session steht der Export auf der Sessionübersichtseite zur Verfügung. <br>Fragen exportieren?", - - /* CSV import*/ - QUESTIONS_CSV_IMPORT_BUTTON: "Fragen<br>importieren", - QUESTIONS_CSV_IMPORT_MSBOX_TITLE: "Inhalte importieren", - QUESTIONS_CSV_IMPORT_ERR_IN_ROW: "in Zeile", - QUESTIONS_CSV_IMPORT_TYPE_ERROR: "Ungültiger Fragentyp", - QUESTIONS_CSV_IMPORT_ABSTENTION_ERROR: "Fehler im Feld 'abstention'", - QUESTIONS_CSV_IMPORT_INVALID_FORMAT: "Ungültiges Dateiformat" + /* content export*/ + QUESTIONS_EXPORT_BUTTON: "Fragen<br>exportieren", + QUESTIONS_EXPORT_MSBOX_TITLE: "Inhalte exportieren", + QUESTIONS_EXPORT_MSBOX_INFO: "Die Inhalte können wahlweise als CSV-Datei oder für den Import in ARSnova-Cards als JSON-Datei exportiert werden. Fragen vom Typ \"Hot Spots\" werden übersprungen. Für den gesamten Export der Session steht der Export auf der Sessionübersichtseite zur Verfügung.", + ARSNOVA_CARDS: "ARSnova.cards", + CSV_FILE: "CSV-Datei", + + /* content import*/ + QUESTIONS_IMPORT_BUTTON: "Fragen<br>importieren", + QUESTIONS_IMPORT_MSBOX_TITLE: "Inhalte importieren", + QUESTIONS_IMPORT_ERR_IN_ROW: "in Zeile", + QUESTIONS_IMPORT_TYPE_ERROR: "Ungültiger Fragentyp", + QUESTIONS_IMPORT_ABSTENTION_ERROR: "Fehler im Feld 'abstention'", + QUESTIONS_IMPORT_INVALID_FORMAT: "Ungültiges Dateiformat", + FLASHCARDS_CHOOSE_SUBJECT: "Legen Sie ein Thema für das zu importierende Lernkarten-Set fest" }; switch (variation) { @@ -1218,6 +1227,8 @@ ARE_YOU_SURE: "Are you sure?", DELETE_QUESTION_TITLE: "Delete question", DELETE_QUESTIONS_TITLE: "Delete questions", + DELETE_FLASHCARD_TITLE: "Delete flashcard", + DELETE_FLASHCARDS_TITLE: "Delete flashcards", DELETE_SESSION_TITLE: "Delete session", DELETE_SESSION_NOTICE: "All questions and answers of this session will be deleted.", CATEGORY: "Subject", @@ -1253,12 +1264,16 @@ DELETE_ALL: "Delete all", DELETE_ANSWERS_REQUEST: "Delete answers?", DELETE_ALL_ANSWERS_REQUEST: "Delete all answers?", + DELETE_VIEWS_REQUEST: "Delete views?", + DELETE_ALL_VIEWS_REQUEST: "Delete all views?", DELETE_ROUND_ANSWERS_COMPLETED: "All answers of the actual round have been deleted.", RELEASE_LIVE_VOTING: "Release voting", CLOSE_LIVE_VOTING: "Freeze voting", QUESTION_REMAINS: "The question itself stays unaffected.", + FLASHCARD_REMAINS: "The flashcard itself stays unaffected.", INCOMPLETE_INPUTS: "Your inputs are incomplete.", ALL_QUESTIONS_REMAIN: "The questions themselves stay unaffected.", + ALL_FLASHCARDS_REMAIN: "The flashcards themselves stay unaffected", DELETE_ALL_ANSWERS_INFO: "This will also delete all previously given answers.", CHANGE_RELEASE: "Changing the release...", TYPE: 'Type', @@ -1644,18 +1659,21 @@ IMP_ERROR_SAVE: "Could not save session to database.", IMP_ERROR_IMAGE: "Could not save session, image exceeds maximal size.", - /* CSV export */ - QUESTIONS_CSV_EXPORT_BUTTON: "Export<br>questions", - QUESTIONS_CSV_EXPORT_MSBOX_TITLE: "Export content", - QUESTIONS_CSV_EXPORT_MSBOX_INFO: "The questions will be exported as a CSV file. \"Hot Spots\" questions won't be exported. For exporting the whole session please use the export function on the session overview.<br>Export questions?", - - /* CSV import */ - QUESTIONS_CSV_IMPORT_BUTTON: "Import<br>questions", - QUESTIONS_CSV_IMPORT_MSBOX_TITLE: "Import content", - QUESTIONS_CSV_IMPORT_ERR_IN_ROW: "at line", - QUESTIONS_CSV_IMPORT_TYPE_ERROR: "Invalid question type", - QUESTIONS_CSV_IMPORT_ABSTENTION_ERROR: "Error in field 'abstention'", - QUESTIONS_CSV_IMPORT_INVALID_FORMAT: "Invalid file format" + /* content export */ + QUESTIONS_EXPORT_BUTTON: "Export<br>content", + QUESTIONS_EXPORT_MSBOX_TITLE: "Export content", + QUESTIONS_EXPORT_MSBOX_INFO: "The content can be exported as a CSV file or preformatted for ARSnova.cards as a JSON file. \"Hot Spots\" questions won't be exported. For exporting the whole session please use the export function on the session overview.", + ARSNOVA_CARDS: "ARSnova.cards", + CSV_FILE: "CSV file", + + /* content import */ + QUESTIONS_IMPORT_BUTTON: "Import<br>content", + QUESTIONS_IMPORT_MSBOX_TITLE: "Import content", + QUESTIONS_IMPORT_ERR_IN_ROW: "at line", + QUESTIONS_IMPORT_TYPE_ERROR: "Invalid question type", + QUESTIONS_IMPORT_ABSTENTION_ERROR: "Error in field 'abstention'", + QUESTIONS_IMPORT_INVALID_FORMAT: "Invalid file format", + FLASHCARDS_CHOOSE_SUBJECT: "Enter a subject for the imported flashcard-set" }; switch (variation) { diff --git a/src/main/webapp/app/view/speaker/AudienceQuestionPanel.js b/src/main/webapp/app/view/speaker/AudienceQuestionPanel.js index 7d5afaece0601bd89dbead3ac227fe86441cdd5f..8f9f8e126b79a4df7b298711bbe951a1869161f3 100644 --- a/src/main/webapp/app/view/speaker/AudienceQuestionPanel.js +++ b/src/main/webapp/app/view/speaker/AudienceQuestionPanel.js @@ -50,9 +50,7 @@ Ext.define('ARSnova.view.speaker.AudienceQuestionPanel', { questions: null, newQuestionButton: null, - questionStore: null, - reader: new FileReader(), updateAnswerCount: { name: 'refresh the number of answers inside the badges', @@ -71,16 +69,6 @@ Ext.define('ARSnova.view.speaker.AudienceQuestionPanel', { var actionButtonCls = screenWidth < 410 ? 'smallerActionButton' : 'actionButton'; this.screenWidth = screenWidth; - this.reader.onload = function (event) { - ARSnova.app.getController('QuestionImport').importCsvFile(self.reader.result); - var field = self.loadFilePanel.query('filefield')[0]; - // field.setValue currently has no effect - Sencha bug? - field.setValue(null); - // Workaround: Directly reset value on DOM element - field.element.query('input')[0].value = null; - field.enable(); - }; - this.questionStore = Ext.create('Ext.data.JsonStore', { model: 'ARSnova.model.Question', sorters: { @@ -210,7 +198,7 @@ Ext.define('ARSnova.view.speaker.AudienceQuestionPanel', { }); this.questionsImport = Ext.create('ARSnova.view.MatrixButton', { - text: Messages.QUESTIONS_CSV_IMPORT_BUTTON, + text: Messages.QUESTIONS_IMPORT_BUTTON, buttonConfig: 'icon', imageCls: 'icon-cloud-upload', cls: 'actionButton', @@ -224,49 +212,113 @@ Ext.define('ARSnova.view.speaker.AudienceQuestionPanel', { centered: true }); - this.loadFilePanel = Ext.create('Ext.Panel', { - modal: true, - centered: true, - ui: 'light', - items: [ - { - xtype: 'toolbar', - docked: 'top', - title: Messages.QUESTIONS_CSV_IMPORT_MSBOX_TITLE, - ui: 'light', - items: [{ - xtype: 'spacer' - }, { - xtype: 'button', - ui: 'plain', - iconCls: 'delete', - iconMask: true, - text: '', - action: 'hideModal' + this.uploadField = Ext.create('Ext.ux.Fileup', { + xtype: 'fileupload', + autoUpload: true, + loadAsDataUrl: true, + cls: 'importFileField', + flex: 0, + listeners: { + loadsuccess: function (data) { + if (!Ext.os.is.iOS) { + // remove prefix and decode + var str = data.substring(data.indexOf("base64,") + 7); + data = decodeURIComponent(window.escape(atob(str))); + + if (self.getVariant() === 'flashcard') { + self.loadFilePanel.hide(); + if (this.importCsv) { + ARSnova.app.getController('FlashcardImport').importCsvFile(data); + } else if (this.importFlashcards) { + ARSnova.app.getController('FlashcardImport').importJsonFile(data); + } + } else { + ARSnova.app.getController('QuestionImport').importCsvFile(data); } - ] + + this.importCsv = false; + this.importFlashcards = false; + } }, - { - xtype: 'filefield', - accept: 'text/csv', - listeners: { - change: function (element, newValue, oldValue) { - // Workaround: The change event is triggered twice in Chrome - if (element.isDisabled()) { - return; - } - element.disable(); + loadfailure: function (message) {} + } + }); - var path = element.getValue(); - var fileType = path.substring(path.lastIndexOf('.')); - if (fileType === '.csv') { - var file = element.bodyElement.dom.firstElementChild.firstElementChild.files[0]; - self.reader.readAsText(file); - } - } + this.loadFilePanel = Ext.create('Ext.MessageBox', { + hideOnMaskTap: true, + cls: 'importExportFilePanel', + title: Messages.QUESTIONS_IMPORT_MSBOX_TITLE, + items: [{ + xtype: 'button', + iconCls: 'icon-close', + cls: 'closeButton', + handler: function () { this.getParent().hide(); } + }, { + xtype: 'container', + layout: 'hbox', + defaults: { + xtype: 'button', + cls: 'overlayButton', + ui: 'action', + scope: this, + flex: 1 + }, + items: [this.uploadField, { + text: Messages.CSV_FILE, + handler: function () { + this.uploadField.importCsv = true; + this.uploadField.fileElement.dom.accept = 'text/csv'; + this.uploadField.fileElement.dom.click(); } - } - ] + }, { + text: Messages.ARSNOVA_CARDS, + itemId: 'flashcardImportButton', + handler: function () { + this.uploadField.importFlashcards = true; + this.uploadField.fileElement.dom.accept = 'application/json'; + this.uploadField.fileElement.dom.click(); + } + }] + }] + }); + + this.exportFilePanel = Ext.create('Ext.MessageBox', { + hideOnMaskTap: true, + cls: 'importExportFilePanel', + title: Messages.QUESTIONS_EXPORT_MSBOX_TITLE, + items: [{ + xtype: 'button', + iconCls: 'icon-close', + cls: 'closeButton', + handler: function () { this.getParent().hide(); } + }, { + html: Messages.QUESTIONS_EXPORT_MSBOX_INFO, + cls: 'x-msgbox-text' + }, { + xtype: 'container', + layout: 'hbox', + defaults: { + xtype: 'button', + ui: 'action', + scope: this, + flex: 1 + }, + items: [{ + text: Messages.CSV_FILE, + handler: function () { + ARSnova.app.getController('QuestionExport') + .exportQuestions(this.getController()); + this.exportFilePanel.hide(); + } + }, { + text: Messages.ARSNOVA_CARDS, + handler: function () { + ARSnova.app.getController('FlashcardExport') + .exportFlashcards(this.getController()); + this.exportFilePanel.hide(); + } + }] + }] }); this.actionButtonPanel = Ext.create('Ext.Panel', { @@ -319,10 +371,17 @@ Ext.define('ARSnova.view.speaker.AudienceQuestionPanel', { cls: actionButtonCls, scope: this, handler: function () { - var me = this; - Ext.Msg.confirm(Messages.DELETE_ALL_ANSWERS_REQUEST, Messages.ALL_QUESTIONS_REMAIN, function (answer) { + var title = Messages.DELETE_ALL_ANSWERS_REQUEST; + var message = Messages.ALL_QUESTIONS_REMAIN; + + if (this.getVariant() === 'flashcard') { + title = Messages.DELETE_ALL_VIEWS_REQUEST; + message = Messages.ALL_FLASHCARDS_REMAIN; + } + + Ext.Msg.confirm(title, message, function (answer) { if (answer === 'yes') { - me.getController().deleteAllQuestionsAnswers({ + this.getController().deleteAllQuestionsAnswers({ success: Ext.bind(this.handleDeleteAnswers, this), failure: Ext.emptyFn }); @@ -340,8 +399,15 @@ Ext.define('ARSnova.view.speaker.AudienceQuestionPanel', { scope: this, handler: function () { var msg = Messages.ARE_YOU_SURE; - msg += "<br>" + Messages.DELETE_ALL_ANSWERS_INFO; - Ext.Msg.confirm(Messages.DELETE_QUESTIONS_TITLE, msg, function (answer) { + var title = Messages.DELETE_QUESTIONS_TITLE; + + if (this.getVariant() === 'flashcard') { + title = Messages.DELETE_FLASHCARDS_TITLE; + } else { + msg += "<br>" + Messages.DELETE_ALL_ANSWERS_INFO; + } + + Ext.Msg.confirm(title, msg, function (answer) { if (answer === 'yes') { this.getController().destroyAll(sessionStorage.getItem("keyword"), { success: Ext.bind(this.onActivate, this), @@ -357,23 +423,14 @@ Ext.define('ARSnova.view.speaker.AudienceQuestionPanel', { this.exportCsvQuestionsButton = Ext.create('ARSnova.view.MatrixButton', { hidden: true, buttonConfig: 'icon', - text: Messages.QUESTIONS_CSV_EXPORT_BUTTON, + text: Messages.QUESTIONS_EXPORT_BUTTON, imageCls: 'icon-cloud-download', cls: 'actionButton', scope: this, handler: function () { - var msg = Messages.QUESTIONS_CSV_EXPORT_MSBOX_INFO; - - Ext.Msg.confirm(Messages.QUESTIONS_CSV_EXPORT_MSBOX_TITLE, msg, function (answer) { - if (answer === 'yes') { - this.getController().getQuestions(sessionStorage.getItem('keyword'), { - success: function (response) { - var questions = Ext.decode(response.responseText); - ARSnova.app.getController('QuestionExport').parseJsonToCsv(questions); - } - }); - } - }, this); + var msg = Messages.QUESTIONS_EXPORT_MSBOX_INFO; + Ext.Viewport.add(this.exportFilePanel); + this.exportFilePanel.show(); } }); @@ -427,6 +484,7 @@ Ext.define('ARSnova.view.speaker.AudienceQuestionPanel', { return; } ARSnova.app.taskManager.start(this.updateAnswerCount); + this.flashcardImportButton = Ext.ComponentQuery.query('#flashcardImportButton')[0]; this.applyUIChanges(); this.questionStore.removeAll(); this.getQuestions(); @@ -686,6 +744,7 @@ Ext.define('ARSnova.view.speaker.AudienceQuestionPanel', { questionListText = Messages.CONTENT_MANAGEMENT; deleteAnswersText = Messages.DELETE_FLASHCARD_VIEWS; deleteQuestionsText = Messages.DELETE_ALL_FLASHCARDS; + this.flashcardImportButton.show(); this.questionStatusButton.setFlashcardsWording(); @@ -701,6 +760,8 @@ Ext.define('ARSnova.view.speaker.AudienceQuestionPanel', { questions: "", answers: Messages.FLASHCARD_VIEWS }; + } else { + this.flashcardImportButton.hide(); } this.toolbar.setTitle(toolbarTitle); diff --git a/src/main/webapp/app/view/speaker/QuestionDetailsPanel.js b/src/main/webapp/app/view/speaker/QuestionDetailsPanel.js index 30464927db99f62422eb8eb5ebb7482fcd2194b8..4fdcc0300cff46dd2c3f6a5d51a675b1c5e60449 100644 --- a/src/main/webapp/app/view/speaker/QuestionDetailsPanel.js +++ b/src/main/webapp/app/view/speaker/QuestionDetailsPanel.js @@ -704,7 +704,9 @@ Ext.define('ARSnova.view.speaker.QuestionDetailsPanel', { imageCls: 'icon-close warningIconColor', scope: this, handler: function () { - Ext.Msg.confirm(Messages.DELETE_ANSWERS_REQUEST, Messages.QUESTION_REMAINS, function (answer) { + var title = this.isFlashcard ? Messages.DELETE_VIEWS_REQUEST : Messages.DELETE_ANSWERS_REQUEST; + var message = this.isFlashcard ? Messages.FLASHCARD_REMAINS : Messages.QUESTION_REMAINS; + Ext.Msg.confirm(title, message, function (answer) { if (answer === 'yes') { var panel = ARSnova.app.mainTabPanel.tabPanel.speakerTabPanel.questionDetailsPanel; ARSnova.app.questionModel.deleteAnswers(panel.questionObj._id, { @@ -742,10 +744,14 @@ Ext.define('ARSnova.view.speaker.QuestionDetailsPanel', { scope: this, handler: function () { var msg = Messages.ARE_YOU_SURE; - if (this.questionObj.active) { + var title = this.isFlashcard ? Messages.DELETE_FLASHCARD_TITLE : + Messages.DELETE_QUESTION_TITLE; + + if (this.questionObj.active && !this.isFlashcard) { msg += "<br>" + Messages.DELETE_ALL_ANSWERS_INFO; } - Ext.Msg.confirm(Messages.DELETE_QUESTION_TITLE, msg, function (answer) { + + Ext.Msg.confirm(title, msg, function (answer) { if (answer === 'yes') { var sTP = ARSnova.app.mainTabPanel.tabPanel.speakerTabPanel; ARSnova.app.questionModel.destroy(sTP.questionDetailsPanel.questionObj, { diff --git a/src/main/webapp/resources/sass/app/_general.scss b/src/main/webapp/resources/sass/app/_general.scss index cc1b87e31df92645ba6b33d704649afcdeb5b138..8155b5e20184ace4258d6e7869a7315e81f5da85 100644 --- a/src/main/webapp/resources/sass/app/_general.scss +++ b/src/main/webapp/resources/sass/app/_general.scss @@ -680,3 +680,49 @@ code { font-size: 0.75em; opacity: 0.75; } + +.importFileField { + opacity: 0; + width: 0px; + height: 0px; + padding: 0px; + margin: 0 !important; +} + +.importSubjectPrompt { + input { + border-radius: 8px; + text-align: center; + } + + .x-field-input { + padding-right: 0px; + } + + .x-container.x-field-text { + margin: 2px 5px 5px 5px; + } +} + +.importExportFilePanel { + .x-dock-body { + overflow: visible; + } + + .x-button.closeButton { + margin: 0; + height: 30px; + font-size: 0.6em; + padding: 0 0.4em; + border: none; + color: $label-font-color; + background: transparent; + position: absolute; + right: 2px; + top: -28px; + } + + .x-button { + margin: 8px; + } +}