{"version":3,"file":"connect-BjVtJz2K.js","sources":["../../../client/app/bundles/Shared/quill-marking-logic/src/libs/matchers/words_out_of_order_match.ts","../../../client/app/bundles/Shared/quill-marking-logic/src/libs/matchers/min_length_match.ts","../../../client/app/bundles/Shared/quill-marking-logic/src/libs/matchers/max_length_match.ts","../../../client/app/bundles/Shared/quill-marking-logic/src/libs/graders/sentence_combining.ts","../../../client/app/bundles/Shared/quill-marking-logic/src/libs/matchers/spacy_pos_match.ts","../../../client/app/bundles/Shared/quill-marking-logic/src/libs/graders/sentence_fragment.ts","../../../client/app/bundles/Shared/components/studentLessons/multipleChoice.tsx","../../../client/app/bundles/Shared/components/studentLessons/register.tsx","../../../client/app/bundles/Connect/actions/concepts.js","../../../client/app/bundles/Connect/libs/concept_feedback_api.ts","../../../client/app/bundles/Connect/actions/concepts-feedback.ts","../../../client/app/bundles/Connect/actions/fillInBlank.ts","../../../client/app/bundles/Connect/actions/sentenceFragments.ts","../../../client/app/bundles/Connect/actions/titleCards.ts","../../../client/app/bundles/Connect/components/navbar/navbar.tsx","../../../client/app/bundles/Connect/components/fillInBlank/fillInBlankForm.jsx","../../../client/app/bundles/Connect/components/fillInBlank/editFillInBlank.jsx","../../../client/app/bundles/Connect/components/renderForQuestions/cues.jsx","../../../client/app/bundles/Connect/components/renderForQuestions/answerState.ts","../../../client/app/bundles/Connect/components/renderForQuestions/feedback.tsx","../../../client/app/bundles/Connect/components/renderForQuestions/feedbackStatements.jsx","../../../client/app/bundles/Connect/components/renderForQuestions/updateResponseResource.js","../../../client/app/bundles/Connect/components/studentLessons/fillInBlank.tsx","../../../client/app/bundles/Connect/components/fillInBlank/testFillInBlankQuestionContainer.jsx","../../../client/app/bundles/Connect/actions/display.js","../../../client/app/bundles/Connect/actions/massEdit.js","../../../client/app/bundles/Connect/components/questions/boilerplateFeedback.jsx","../../../client/app/bundles/Connect/components/questions/conceptResultList.jsx","../../../client/app/bundles/Connect/components/questions/massEditContainer.jsx","../../../client/app/bundles/Connect/actions/filters.js","../../../client/app/bundles/Connect/libs/grading/rematching.ts","../../../client/app/bundles/Connect/libs/partsOfSpeechTagging.js","../../../client/app/bundles/Connect/libs/algorithms/changeObjects.js","../../../client/app/bundles/Connect/libs/algorithms/joiningWords.js","../../../client/app/bundles/Connect/libs/algorithms/spacingBeforePunctuation.js","../../../client/app/bundles/Connect/libs/quillNormalizer.js","../../../client/app/bundles/Connect/libs/requiredWords.js","../../../client/app/bundles/Connect/libs/sharedResponseFunctions.js","../../../client/app/bundles/Connect/libs/question.js","../../../client/app/bundles/Connect/libs/validEndingPunctuation.js","../../../client/app/bundles/Connect/libs/sentenceFragment.js","../../../client/app/bundles/Connect/components/questions/POSForResponse.jsx","../../../client/app/bundles/Connect/components/questions/POSIndex.jsx","../../../client/app/bundles/Connect/components/questions/POSForResponsesList.jsx","../../../client/app/bundles/Connect/components/questions/response.tsx","../../../client/app/bundles/Connect/components/questions/responseList.jsx","../../../client/app/bundles/Connect/components/questions/responseComponent.jsx","../../../client/app/bundles/Connect/components/questions/responseRouteWrapper.jsx","../../../client/app/bundles/Connect/components/fillInBlank/fillInBlankQuestion.jsx","../../../client/app/bundles/Connect/components/focusPoints/editFocusPointsContainer.jsx","../../../client/app/bundles/Connect/components/focusPoints/focusPointsContainer.jsx","../../../client/app/bundles/Connect/components/focusPoints/newFocusPointsContainer.jsx","../../../client/app/bundles/Connect/components/incorrectSequence/editIncorrectSequenceContainer.jsx","../../../client/app/bundles/Connect/components/incorrectSequence/incorrectSequenceContainer.jsx","../../../client/app/bundles/Connect/components/incorrectSequence/newIncorrectSequenceContainer.jsx","../../../client/app/bundles/Connect/components/questions/chooseModelContainer.jsx","../../../client/app/bundles/Connect/components/questions/questionForm.jsx","../../../client/app/bundles/Connect/libs/EditCaretPositioning.ts","../../../client/app/bundles/Connect/components/renderForQuestions/checkAnswer.ts","../../../client/app/bundles/Connect/components/renderForQuestions/renderEndState.jsx","../../../client/app/bundles/Connect/libs/markupUserResponses.js","../../../client/app/bundles/Connect/components/renderForQuestions/renderTextEditor.jsx","../../../client/app/bundles/Connect/components/renderForQuestions/renderFormForAnswer.jsx","../../../client/app/bundles/Connect/components/renderForQuestions/submitResponse.js","../../../client/app/bundles/Connect/components/studentLessons/question.tsx","../../../client/app/bundles/Connect/components/questions/testQuestion.jsx","../../../client/app/bundles/Connect/components/questions/question.jsx","../../../client/app/bundles/Connect/components/sentenceFragments/chooseModelContainer.jsx","../../../client/app/bundles/Connect/components/sentenceFragments/sentenceFragmentForm.jsx","../../../client/app/bundles/Connect/components/sentenceFragments/sentenceFragmentTemplateComponentML.tsx","../../../client/app/bundles/Connect/components/studentLessons/sentenceFragment.jsx","../../../client/app/bundles/Connect/components/sentenceFragments/testSentenceFragmentContainer.jsx","../../../client/app/bundles/Connect/components/sentenceFragments/sentenceFragment.jsx","../../../client/app/bundles/Connect/components/titleCards/showTitleCard.tsx","../../../client/app/bundles/Connect/components/titleCards/titleCardForm.tsx","../../../client/app/bundles/Connect/libs/flagArray.js","../../../client/app/bundles/Connect/components/lessons/chooseModelContainer.jsx","../../../client/app/bundles/Connect/components/lessons/lessonForm.jsx","../../../client/app/bundles/Connect/components/lessons/lesson.jsx","../../../client/app/bundles/Connect/components/admin/adminLessonSidebar.jsx","../../../client/app/bundles/Connect/components/admin/adminLesson.jsx","../../../client/app/bundles/Connect/components/admin/adminMainSidebar.jsx","../../../client/app/bundles/Connect/components/activityHealth/promptHealth.tsx","../../../client/app/bundles/Connect/actions/activityHealth.ts","../../../client/app/bundles/Connect/components/activityHealth/activityHealth.tsx","../../../client/app/bundles/Connect/components/concepts/concept.tsx","../../../client/app/bundles/Connect/components/shared/linkListItem.tsx","../../../client/app/bundles/Connect/components/concepts/concepts.jsx","../../../client/app/bundles/Connect/components/feedback/concept-feedback.jsx","../../../client/app/bundles/Connect/components/feedback/concepts-feedback.jsx","../../../client/app/bundles/Connect/components/shared/questionList.tsx","../../../client/app/bundles/Connect/components/fillInBlank/fillInBlankQuestions.jsx","../../../client/app/bundles/Connect/components/lessons/expandLessonQuestions.tsx","../../../client/app/bundles/Connect/components/lessons/lessons.jsx","../../../client/app/bundles/Connect/components/shared/questionListByConcept.tsx","../../../client/app/bundles/Connect/components/questions/questions.jsx","../../../client/app/bundles/Connect/components/sentenceFragments/sentenceFragments.jsx","../../../client/app/bundles/Connect/components/titleCards/titleCards.tsx","../../../client/app/bundles/Connect/components/admin/admin.jsx","../../../client/app/bundles/Connect/components/studentLessons/finished.jsx","../../../client/app/bundles/Connect/libs/sessions_api.ts","../../../client/app/bundles/Connect/actions/sessions.js","../../../client/app/bundles/Connect/libs/calculateProgress.ts","../../../client/app/bundles/Connect/libs/formattedCues.js","../../../client/app/bundles/Connect/libs/conceptResults/sharedConceptResultsFunctions.js","../../../client/app/bundles/Connect/libs/conceptResults/sentenceCombiningLessonQuestion.js","../../../client/app/bundles/Connect/libs/conceptResults/sentenceFragment.js","../../../client/app/bundles/Connect/libs/conceptResults/fillInTheBlanks.js","../../../client/app/bundles/Connect/libs/conceptResults/lesson.js","../../../client/app/bundles/Connect/components/studentLessons/lesson.jsx","../../../client/app/bundles/Connect/actions/turk.js","../../../client/app/bundles/Connect/libs/conceptResults/sentenceCombining.js","../../../client/app/bundles/Connect/libs/conceptResults/diagnostic.js","../../../client/app/bundles/Connect/components/turk/diagnosticQuestions.jsx","../../../client/app/bundles/Connect/components/turk/fillInBlank.tsx","../../../client/app/bundles/Connect/components/turk/finishedDiagnostic.jsx","../../../client/app/bundles/Connect/components/turk/landing.jsx","../../../client/app/bundles/Connect/components/turk/question.tsx","../../../client/app/bundles/Connect/components/turk/sentenceFragment.jsx","../../../client/app/bundles/Connect/components/turk/turkActivity.jsx","../../../client/app/bundles/Connect/routes.tsx","../../../client/app/bundles/Connect/components/home.tsx","../../../client/app/bundles/Connect/utils/backOff.js","../../../client/app/bundles/Connect/reducers/activityHealth.js","../../../client/app/bundles/Connect/reducers/classroomLesson.js","../../../client/app/bundles/Connect/reducers/classroomLessons.js","../../../client/app/bundles/Connect/reducers/classroomLessonsReviews.js","../../../client/app/bundles/Connect/reducers/classroomSessions.js","../../../client/app/bundles/Connect/reducers/concepts.js","../../../client/app/bundles/Connect/reducers/concepts-feedback.js","../../../client/app/bundles/Connect/reducers/customize.js","../../../client/app/bundles/Connect/reducers/display.js","../../../client/app/bundles/Connect/reducers/fillInBlank.js","../../../client/app/bundles/Connect/reducers/filtersReducer.js","../../../client/app/bundles/Connect/reducers/generatedIncorrectSequences.js","../../../client/app/bundles/Connect/reducers/item-levels.js","../../../client/app/bundles/Connect/reducers/lessons.js","../../../client/app/bundles/Connect/reducers/massEdit.js","../../../client/app/bundles/Connect/reducers/questionReducer.js","../../../client/app/bundles/Connect/reducers/questionReducerV2.js","../../../client/app/bundles/Connect/reducers/questions.js","../../../client/app/bundles/Connect/reducers/responsesReducer.js","../../../client/app/bundles/Connect/reducers/sentenceFragments.js","../../../client/app/bundles/Connect/reducers/sessions.js","../../../client/app/bundles/Connect/reducers/titleCards.js","../../../client/app/bundles/Connect/reducers/turk.js","../../../client/app/bundles/Connect/reducers/combined.js","../../../client/app/bundles/Connect/utils/configureStore.js","../../../client/app/bundles/Connect/app.tsx","../../../client/app/bundles/Connect/clientRegistration.js"],"sourcesContent":["import * as _ from 'underscore'\nimport {getOptimalResponses} from '../sharedResponseFunctions'\nimport {stringNormalize} from 'quill-string-normalizer'\nimport {Response, PartialResponse} from '../../interfaces'\nimport {conceptResultTemplate} from '../helpers/concept_result_template'\nimport {feedbackStrings} from '../constants/feedback_strings'\nimport {removePunctuation} from './punctuation_and_case_insensitive_match'\n\nexport function wordsOutOfOrderMatch (response:string, responses: Array): Response|undefined {\n return _.find(getOptimalResponses(responses), resp => {\n const normalizedSubmittedResponse = stringNormalize(response);\n const normalizedStoredResponse = stringNormalize(resp.text);\n return identicalWordMaps(mapWordCounts(normalizedSubmittedResponse), mapWordCounts(normalizedStoredResponse))\n });\n}\n\nfunction mapWordCounts(sentenceString: string): Object {\n const wordsArray = sentenceString.split(' ');\n return wordsArray.reduce((wordMap, word) => {\n const noPunctWord = removePunctuation(word).toLowerCase();\n if (!wordMap[noPunctWord]) wordMap[noPunctWord] = 0;\n wordMap[noPunctWord]+=1;\n return wordMap;\n }, {});\n}\n\nfunction identicalWordMaps(wordMap1: object, wordMap2: object): boolean {\n const keys1 = Object.keys(wordMap1);\n const keys2 = Object.keys(wordMap2);\n if (keys1.length !== keys2.length) return false;\n return keys1.every((key) => wordMap1[key] === wordMap2[key]);\n}\n\nexport function wordsOutOfOrderChecker(responseString: string, responses:Array):PartialResponse|undefined {\n const match = wordsOutOfOrderMatch(responseString, responses);\n if (match) {\n const parent_id = match.id\n return wordsOutOfOrderResponseBuilder(responses, parent_id)\n }\n}\n\nexport function wordsOutOfOrderResponseBuilder(responses:Array, parent_id: string|number): PartialResponse {\n const res = {\n feedback: feedbackStrings.wordsOutOfOrderError,\n author: 'Words Out of Order Hint',\n parent_id,\n concept_results: [\n conceptResultTemplate('i491sVpiemTqA5Q0VAqTxA')\n ]\n }\n return res\n}\n\n","import * as _ from 'underscore'\nimport {stringNormalize} from 'quill-string-normalizer'\n\nimport {getOptimalResponses} from '../sharedResponseFunctions'\nimport {Response, PartialResponse} from '../../interfaces'\nimport {feedbackStrings} from '../constants/feedback_strings'\nimport {conceptResultTemplate} from '../helpers/concept_result_template'\n\nexport function minLengthMatch(responseString:string, responses:Array):Boolean {\n const optimalResponses = getOptimalResponses(responses);\n const lengthsOfResponses = optimalResponses.map(resp => stringNormalize(resp.text).split(' ').length);\n const minLength = _.min(lengthsOfResponses) - 3;\n return responseString.split(' ').length < minLength\n}\n\nexport function minLengthChecker(responseString: string, responses:Array, noConceptResults:Boolean=false):PartialResponse|undefined {\n const match = minLengthMatch(responseString, responses);\n if (match) {\n return minLengthResponseBuilder(responses, noConceptResults)\n }\n}\n\nexport function minLengthResponseBuilder(responses:Array, noConceptResults:Boolean): PartialResponse {\n const optimalResponses = getOptimalResponses(responses);\n const shortestOptimalResponse = _.sortBy(optimalResponses, resp => stringNormalize(resp.text).length)[0];\n const res = {\n feedback: feedbackStrings.minLengthError,\n author: 'Missing Details Hint',\n parent_id: shortestOptimalResponse.key,\n concept_results: noConceptResults ? undefined : [\n conceptResultTemplate('N5VXCdTAs91gP46gATuvPQ')\n ]\n }\n return res\n}\n","import * as _ from 'underscore'\nimport {stringNormalize} from 'quill-string-normalizer'\nimport {getOptimalResponses} from '../sharedResponseFunctions'\nimport {Response, PartialResponse} from '../../interfaces'\nimport {feedbackStrings} from '../constants/feedback_strings'\nimport {conceptResultTemplate} from '../helpers/concept_result_template'\n\nexport function maxLengthMatch(responseString:string, responses:Array):Boolean {\n const optimalResponses = getOptimalResponses(responses);\n if (optimalResponses.length < 2) {\n return false;\n }\n const lengthsOfResponses = optimalResponses.map(resp => stringNormalize(resp.text).split(' ').length);\n const maxLength = _.max(lengthsOfResponses) + 1;\n return responseString.split(' ').length > maxLength\n}\n\nexport function maxLengthChecker(responseString: string, responses:Array):PartialResponse|undefined {\n const match = maxLengthMatch(responseString, responses);\n if (match) {\n return maxLengthResponseBuilder(responses)\n }\n}\n\nexport function maxLengthResponseBuilder(responses:Array): PartialResponse {\n const optimalResponses = getOptimalResponses(responses);\n const longestOptimalResponse = _.sortBy(optimalResponses, resp => stringNormalize(resp.text).length).reverse()[0];\n const res = {\n feedback: feedbackStrings.maxLengthError,\n author: 'Not Concise Hint',\n parent_id: longestOptimalResponse.key,\n concept_results: [\n conceptResultTemplate('QYHg1tpDghy5AHWpsIodAg')\n ]\n }\n return res\n}\n","import * as _ from 'underscore';\n\nimport {Response, PartialResponse, IncorrectSequence, FocusPoint, GradingObject} from '../../interfaces';\nimport {correctSentenceFromSamples} from '../spellchecker/main';\nimport {getOptimalResponses} from '../sharedResponseFunctions';\nimport {conceptResultTemplate} from '../helpers/concept_result_template'\nimport {removePunctuation} from '../helpers/remove_punctuation'\nimport {exactMatch} from '../matchers/exact_match';\nimport {focusPointChecker} from '../matchers/focus_point_match';\nimport {incorrectSequenceChecker} from '../matchers/incorrect_sequence_match';\nimport {caseInsensitiveChecker} from '../matchers/case_insensitive_match';\nimport {punctuationInsensitiveChecker} from '../matchers/punctuation_insensitive_match';\nimport {punctuationAndCaseInsensitiveChecker} from '../matchers/punctuation_and_case_insensitive_match';\nimport {quotationMarkChecker} from '../matchers/quotation_mark_match';\nimport {spacingBeforePunctuationChecker} from '../matchers/spacing_before_punctuation_match';\nimport {spacingAfterCommaChecker} from '../matchers/spacing_after_comma_match';\nimport {whitespaceChecker} from '../matchers/whitespace_match';\nimport {wordsOutOfOrderChecker} from '../matchers/words_out_of_order_match';\nimport {rigidChangeObjectChecker, flexibleChangeObjectChecker} from '../matchers/change_object_match';\nimport {requiredWordsChecker} from '../matchers/required_words_match';\nimport {minLengthChecker} from '../matchers/min_length_match';\nimport {maxLengthChecker} from '../matchers/max_length_match';\nimport {caseStartChecker} from '../matchers/case_start_match';\nimport {punctuationEndChecker} from '../matchers/punctuation_end_match';\nimport {spellingFeedbackStrings} from '../constants/feedback_strings';\n\nconst MISSING_WORD_HINT = 'Missing Word Hint'\n\nexport function checkSentenceCombining(\n question_uid: string,\n response: string,\n responses: Array,\n focusPoints: Array|null,\n incorrectSequences: Array|null,\n defaultConceptUID?: string\n): Response {\n const data = {\n response: response.trim().replace(/\\s{2,}/g, ' '),\n responses,\n focusPoints,\n incorrectSequences,\n };\n\n const responseTemplate = {\n text: data.response,\n question_uid,\n count: 1,\n concept_results: defaultConceptUID ? [conceptResultTemplate(defaultConceptUID)] : []\n };\n\n const firstPass = checkForMatches(data, firstPassMatchers); // returns partial response or null\n if (firstPass) {\n return Object.assign(responseTemplate, firstPass)\n };\n\n const spellCheckedData = prepareSpellingData(data);\n const spellingPass = checkForMatches(spellCheckedData, firstPassMatchers, true); // check for a match w the spelling corrected\n const misspelledWords = getMisspelledWords(data.response, spellCheckedData.spellCorrectedResponse)\n if (spellingPass) {\n let foundConcepts = spellingPass.conceptResults || spellingPass.concept_results\n //convert concept results to an array if it's not already\n if (typeof foundConcepts === 'object' && foundConcepts.constructor === Object) {\n spellingPass.conceptResults =\n Object.keys(foundConcepts).map((k) => foundConcepts[k])\n }\n if (Array.isArray(spellingPass.conceptResults)) {\n spellingPass.conceptResults.push(conceptResultTemplate('H-2lrblngQAQ8_s-ctye4g'));\n } else if (Array.isArray(spellingPass.concept_results)) {\n spellingPass.concept_results.push(conceptResultTemplate('H-2lrblngQAQ8_s-ctye4g'));\n }\n const spellingAwareFeedback = getSpellingFeedback(spellingPass);\n const spellingFeedbackObj = getSpellingFeedbackObj(spellingPass, data, misspelledWords)\n\n return Object.assign(responseTemplate, spellingAwareFeedback, spellingFeedbackObj);\n };\n\n const secondPass = checkForMatches(spellCheckedData, secondPassMatchers);\n if (secondPass) {\n return Object.assign(responseTemplate, secondPass);\n };\n\n return responseTemplate;\n}\n\nfunction* firstPassMatchers(data: GradingObject, spellCorrected=false) {\n const {response, spellCorrectedResponse, responses, focusPoints, incorrectSequences} = data;\n const submission = spellCorrected ? spellCorrectedResponse : response;\n yield exactMatch(submission, responses);\n if (!spellCorrected) {\n // we don't want to run the focus point checker and the incorrect sequence checker on spell-checked strings because our spellcheck library strips out a lot of punctuation that is sometimes included in those regexes\n yield focusPointChecker(submission, focusPoints, responses);\n yield incorrectSequenceChecker(submission, incorrectSequences, responses);\n }\n yield caseInsensitiveChecker(submission, responses);\n yield quotationMarkChecker(submission, responses);\n yield punctuationInsensitiveChecker(submission, responses);\n yield punctuationAndCaseInsensitiveChecker(submission, responses);\n yield spacingBeforePunctuationChecker(submission, responses);\n yield spacingAfterCommaChecker(submission, responses);\n yield whitespaceChecker(submission, responses);\n yield rigidChangeObjectChecker(submission, responses);\n}\n\nfunction* secondPassMatchers(data: GradingObject, spellCorrected=false) {\n const {response, spellCorrectedResponse, responses, focusPoints, incorrectSequences} = data;\n yield flexibleChangeObjectChecker(response, responses);\n yield requiredWordsChecker(spellCorrectedResponse, responses);\n yield minLengthChecker(response, responses);\n yield maxLengthChecker(response, responses);\n yield caseStartChecker(response, responses);\n yield wordsOutOfOrderChecker(spellCorrectedResponse, responses);\n yield punctuationEndChecker(response, responses);\n}\n\nfunction checkForMatches(data: GradingObject, matchingFunction: Function, spellCorrected=false): PartialResponse|null {\n const gen = matchingFunction(data, spellCorrected);\n let next = gen.next();\n while (true) {\n if (next.value || next.done) {\n break;\n }\n next = gen.next();\n }\n if (next.value) {\n return next.value;\n }\n\n}\n\nfunction prepareSpellingData(data: GradingObject) {\n const spellingData = Object.assign({}, data);\n const optimalAnswerStrings = getOptimalResponses(data.responses).map(resp => resp.text);\n spellingData.spellCorrectedResponse = correctSentenceFromSamples(optimalAnswerStrings, data.response, false);\n return spellingData;\n}\n\nfunction getSpellingFeedback(spellingMatch: Response|PartialResponse): PartialResponse {\n // build a hash of the spelling aware feedback from the google doc to your right ->\n // find the error type of the partial response, fetch the feedback from the hash,\n // and apply it to the passed match value (spellingMatch)\n const match = _.omit(spellingMatch, 'count', 'child_count', 'created_at', 'first_attempt_count', 'key', 'optimal');\n if (match.parent_id) {\n match.feedback = spellingFeedbackStrings[match.author];\n } else {\n match.author = 'Spelling Hint';\n match.feedback = spellingFeedbackStrings['Spelling Hint'];\n match.parent_id = match.id;\n delete match.id;\n }\n match.feedback = match.feedback ? match.feedback : spellingMatch.feedback\n return match;\n}\n\nfunction getMisspelledWords(text: string, spellCheckedText: string) {\n const textArray: Array = removePunctuation(text).split(' ')\n const spellCheckedTextArray: Array = removePunctuation(spellCheckedText).split(' ')\n const misspelledWords = textArray.filter(word => !spellCheckedTextArray.includes(word))\n return misspelledWords\n}\n\nfunction getSpellingFeedbackObj(spellingPass, data, misspelledWords) {\n // missing word hint should not return any highlighted words\n if (spellingPass.author == MISSING_WORD_HINT) {\n return {\n text: data.response,\n spelling_error: true\n }\n } else {\n return {\n text: data.response,\n spelling_error: true,\n misspelled_words: misspelledWords\n }\n }\n}\n","import {Response, PartialResponse } from '../../interfaces'\n\nexport function spacyPOSSentenceMatch(response: string, question_uid: string, link: string): Promise {\n const options = {\n method: 'POST',\n body: JSON.stringify({\n text: response,\n question_id: question_uid\n }),\n // mode: 'cors',\n // credentials: 'include',\n headers: { \"Content-Type\": \"application/json\" }\n };\n const url = `${link}/get_pos_match`;\n return fetch(url, options)\n .then((response) => response.json())\n .then(json => json.match);\n}\n\nexport async function spacyPOSSentenceChecker(responseString: string, question_uid: string, link: string, matcherFunction: Function=spacyPOSSentenceMatch): Promise {\n const match = await matcherFunction(responseString, question_uid, link);\n const val = match ? spacyPOSSentenceResponseBuilder(match) : undefined;\n if (val) {\n return val;\n }\n}\n\nexport function spacyPOSSentenceResponseBuilder(match: Response): PartialResponse {\n const res: PartialResponse = {\n author: 'Parts of Speech',\n parent_id: match.id,\n optimal: match.optimal,\n feedback: match.feedback\n };\n return res;\n}\n","import * as _ from 'underscore'\n\nimport {Response, IncorrectSequence, FocusPoint} from '../../interfaces'\nimport {conceptResultTemplate} from '../helpers/concept_result_template'\nimport {exactMatch} from '../matchers/exact_match';\nimport {incorrectSequenceChecker} from '../matchers/incorrect_sequence_match'\nimport {focusPointChecker} from '../matchers/focus_point_match';\nimport {lengthChecker} from '../matchers/length_match'\nimport {punctuationEndChecker} from '../matchers/punctuation_end_match'\nimport {caseStartChecker} from '../matchers/case_start_match'\nimport {caseInsensitiveChecker} from '../matchers/case_insensitive_match'\nimport {punctuationInsensitiveChecker} from '../matchers/punctuation_insensitive_match'\nimport {punctuationAndCaseInsensitiveChecker} from '../matchers/punctuation_and_case_insensitive_match'\nimport {spacingBeforePunctuationChecker} from '../matchers/spacing_before_punctuation_match'\nimport {spacingAfterCommaChecker} from '../matchers/spacing_after_comma_match'\nimport {requiredWordsChecker} from '../matchers/required_words_match'\nimport {spacyPOSSentenceChecker} from '../matchers/spacy_pos_match'\n\nexport async function checkSentenceFragment(hash:{\n question_uid: string,\n response: string,\n responses: Array,\n wordCountChange?: Object,\n ignoreCaseAndPunc?: Boolean,\n incorrectSequences?: Array,\n focusPoints?: Array,\n prompt: string,\n checkML?: Boolean,\n mlUrl?: string,\n defaultConceptUID?: string\n}): Promise {\n\n const data = {\n response: hash.response.trim().replace(/\\s{2,}/g, ' '),\n responses: _.sortBy(hash.responses, r => r.count).reverse(),\n incorrectSequences: hash.incorrectSequences,\n focusPoints: hash.focusPoints,\n wordCountChange: hash.wordCountChange,\n ignoreCaseAndPunc: hash.ignoreCaseAndPunc,\n prompt: hash.prompt,\n mlUrl: hash.mlUrl,\n checkML: hash.checkML,\n question_uid: hash.question_uid\n }\n\n const responseTemplate = {\n text: data.response,\n question_uid: hash.question_uid,\n count: 1,\n concept_results: hash.defaultConceptUID ? [conceptResultTemplate(hash.defaultConceptUID)] : []\n };\n\n const firstPass = checkForMatches(data, firstPassMatchers)\n if (firstPass) {\n return Object.assign(responseTemplate, firstPass)\n }\n\n const spacyPOS = await spacyPOSSentenceChecker(data.response, data.question_uid, data.mlUrl)\n\n // if (checkML) {\n // yield machineLearningSentenceChecker(submission, responses, mlUrl)\n // }\n\n if (spacyPOS) {\n return Object.assign(responseTemplate, spacyPOS)\n } else {\n return responseTemplate;\n }\n}\n\nfunction* firstPassMatchers(data, spellCorrected=false) {\n const {response, responses, incorrectSequences, focusPoints, ignoreCaseAndPunc, wordCountChange, prompt, checkML, mlUrl} = data;\n const submission = response;\n\n yield exactMatch(submission, responses)\n yield focusPointChecker(submission, focusPoints, responses)\n yield incorrectSequenceChecker(submission, incorrectSequences, responses)\n if (!ignoreCaseAndPunc) {\n yield lengthChecker(submission, responses, prompt, wordCountChange)\n yield punctuationEndChecker(submission, responses)\n yield caseStartChecker(submission, responses)\n yield caseInsensitiveChecker(submission, responses)\n yield punctuationInsensitiveChecker(submission, responses)\n yield punctuationAndCaseInsensitiveChecker(submission, responses)\n yield spacingBeforePunctuationChecker(submission, responses)\n yield spacingAfterCommaChecker(submission, responses)\n yield requiredWordsChecker(submission, responses)\n }\n}\n\nfunction checkForMatches(data, matchingFunction: Function) {\n const gen = matchingFunction(data)\n let next = gen.next();\n while (true) {\n if (next.value || next.done) {\n break;\n }\n next = gen.next();\n }\n if (next.value) {\n return next.value;\n }\n}\n","import * as React from 'react';\nimport { Feedback } from '../renderForQuestions/feedback';\n\nconst renderOptions = (next, answers) => {\n const components = answers.map(answer => (\n \n )\n );\n return
{components}
\n}\n\nconst MultipleChoice = ({ prompt, answers, next, showTranslation, translate }) => (\n
\n
\n {prompt}\n Select a strong answer. There may be more than one.

}\n feedbackType=\"override\"\n key=\"multiple-choice\"\n showTranslation={showTranslation}\n translate={translate}\n />\n {renderOptions(next, answers)}\n
\n
\n)\n\nexport { MultipleChoice };\n\n","import * as React from 'react';\n\nconst FILL_IN_BLANK = 'fillInBlank'\n\nclass Register extends React.Component {\n constructor(props) {\n super(props)\n\n this.state = {\n showIntro: false,\n hasSentenceFragment: this.hasSentenceFragment(),\n }\n }\n\n componentDidMount() {\n const { previewMode, lesson } = this.props;\n if (lesson?.questionType === FILL_IN_BLANK) {\n this.handleSetShowIntro()\n }\n if (previewMode) {\n this.startActivity();\n }\n }\n\n handleSetShowIntro = () => {\n this.setState({ showIntro: true, });\n }\n\n landingPageHtmlHasText(){\n const { lesson, } = this.props\n // strips out everything nested betwee < and >.\n // we should also not allow draft js to send text-less answers from\n // the lp editor\n return lesson.landingPageHtml.replace(/(<([^>]+)>)/ig, \"\").length > 0;\n }\n\n startActivity = () => {\n const { showIntro, } = this.state\n const { lesson, startActivity, } = this.props\n if (lesson.landingPageHtml && this.landingPageHtmlHasText() && !showIntro) {\n this.setState({ showIntro: true, });\n } else {\n startActivity();\n }\n }\n\n resume = () => {\n const { resumeActivity, session, } = this.props\n resumeActivity(session);\n }\n\n hasSentenceFragment = () => {\n const { lesson, } = this.props\n const { questions } = lesson;\n for (let i = 0; i < questions.length; i+=1) {\n if (questions[i].questionType === \"sentenceFragments\") {\n return true;\n }\n }\n return false;\n }\n\n renderButton = (showIntro) => {\n const { session, translate, showTranslation } = this.props\n let onClickFn, text;\n\n if (session) {\n // resume session if one is passed\n onClickFn = this.resume;\n text = showTranslation ? translate('buttons^resume') : 'Resume'\n } else if (showIntro) {\n // this and the following conditional have the same action because the function handles what should happen next\n onClickFn = this.startActivity;\n text = showTranslation ? translate('buttons^begin') : 'Begin'\n } else {\n // otherwise begin new session\n onClickFn = this.startActivity;\n text = showTranslation ? translate('buttons^start activity') : 'Start activity'\n }\n return (\n \n );\n }\n\n translatedText = (): string => {\n const { lesson, language} = this.props;\n const { translations, } = lesson;\n return translations && translations[language];\n }\n\n renderSentenceFragmentIntro = () => {\n const { showTranslation, translate } = this.props\n const { showIntro } = this.state\n if(showTranslation) {\n return (\n
\n

\n {translate('Quill Connect Fragments Intro^Welcome to Quill Connect Fragments!')}\n

\n
\n
    \n
  • {translate('Quill Connect Fragments Intro^Add to the group of words to make a complete sentence.')}
  • \n
  • {translate('Quill Connect Fragments Intro^Add the number of words shown in the directions.')}
  • \n
  • {translate('Quill Connect Fragments Intro^There is often more than one correct answer.')}
  • \n
  • {translate('Quill Connect Fragments Intro^Remember to use correct spelling, capitalization, and punctuation!')}
  • \n
\n {this.renderButton(showIntro)}\n
\n
\n
\n );\n }\n return (\n
\n

\n Welcome to Quill Connect Fragments!\n

\n
\n
    \n
  • Add to the group of words to make a complete sentence.
  • \n
  • Add the number of words shown in the directions.
  • \n
  • There is often more than one correct answer.
  • \n
  • Remember to use correct spelling, capitalization, and punctuation!
  • \n
\n {this.renderButton(showIntro)}\n
\n
\n
\n );\n }\n\n renderConnectIntro = () => {\n const { showTranslation, translate } = this.props\n const { showIntro } = this.state\n\n if(showTranslation) {\n return (\n
\n

\n {translate('Quill Connect Intro^Welcome to Quill Connect!')}\n

\n
\n
    \n
  • {translate('Quill Connect Intro^Combine the sentences together into one sentence.')}
  • \n
  • {translate('Quill Connect Intro^You may add or remove words.')}
  • \n
  • {translate('Quill Connect Intro^There is often more than one correct answer.')}
  • \n
  • {translate('Quill Connect Intro^Remember to use correct spelling, capitalization, and punctuation!')}
  • \n
\n {this.renderButton(showIntro)}\n
\n
\n
\n );\n }\n return (\n
\n

\n Welcome to Quill Connect!\n

\n
\n
    \n
  • Combine the sentences together into one sentence.
  • \n
  • You may add or remove words.
  • \n
  • There is often more than one correct answer.
  • \n
  • Remember to use correct spelling, capitalization, and punctuation!
  • \n
\n {this.renderButton(showIntro)}\n
\n
\n
\n );\n }\n\n renderIntro = () => {\n const { lesson } = this.props\n const { showIntro, hasSentenceFragment, } = this.state\n const translatedText = this.translatedText()\n if (showIntro) {\n return (\n
\n
\n {translatedText && (\n \n
\n
\n \n )}\n {this.renderButton(showIntro)}\n
\n );\n } else if (hasSentenceFragment) {\n return this.renderSentenceFragmentIntro()\n } else {\n return this.renderConnectIntro()\n }\n }\n\n render() {\n return (\n \n {this.renderIntro()}\n \n );\n }\n}\n\nexport { Register };\n","import _ from 'underscore';\n\nimport { requestGet, } from '../../../modules/request/index';\n\nimport C from '../constants';\n\nconst conceptsEndpoint = `${window.postbuildEnv.DEFAULT_URL}/api/v1/concepts.json`;\n\n\nfunction splitInLevels(concepts) {\n return _.groupBy(concepts, 'level');\n}\n\nfunction getParentName(concept, concepts) {\n const parent = _.find(concepts['1'], { id: concept.parent_id, });\n const grandParent = _.find(concepts['2'], { id: parent.parent_id, });\n return `${grandParent.name} | ${parent.name}`;\n}\n\nconst actions = {\n startListeningToConcepts() {\n return (dispatch) => {\n requestGet(conceptsEndpoint, (body) => {\n const concepts = splitInLevels(body.concepts);\n concepts['0'] = concepts['0'].map((concept) => {\n concept.displayName = `${getParentName(concept, concepts)} | ${concept.name}`;\n return concept;\n });\n dispatch({ type: C.RECEIVE_CONCEPTS_DATA, data: concepts, });\n });\n };\n },\n};\n\nexport default actions;\n","import { requestDelete, requestGet, requestPost, requestPut } from '../../../modules/request/index';\nimport { languageToLocale } from '../../Shared';\nimport { ConceptFeedback, ConceptFeedbackCollection } from '../interfaces/concept_feedback';\n\nconst CONNECT_TYPE = 'connect'\n\nconst conceptFeedbackApiBaseUrl = `${window.postbuildEnv.DEFAULT_URL}/api/v1/activity_type/${CONNECT_TYPE}/concept_feedback`;\n\nclass ConceptFeedbackApi {\n static getAll(language?: string): Promise {\n const language_string = language ? `/translations/${languageToLocale[language]}` : ''\n return requestGet(`${conceptFeedbackApiBaseUrl}${language_string}.json`, null, (error) => {throw(error)});\n }\n\n static get(uid: string): Promise {\n return requestGet(`${conceptFeedbackApiBaseUrl}/${uid}.json`, null, (error) => {throw(error)});\n }\n\n static create(data: ConceptFeedback): Promise {\n return requestPost(`${conceptFeedbackApiBaseUrl}.json`, {concept_feedback: data}, null, (error) => {throw(error)});\n }\n\n static update(uid: string, data: ConceptFeedback): Promise {\n return requestPut(`${conceptFeedbackApiBaseUrl}/${uid}.json`, {concept_feedback: data}, null, (error) => {throw(error)});\n }\n\n static remove(uid: string): Promise {\n return requestDelete(`${conceptFeedbackApiBaseUrl}/${uid}.json`, null, null, (error) => {throw(error)});\n }\n}\n\nexport {\n CONNECT_TYPE,\n ConceptFeedbackApi,\n conceptFeedbackApiBaseUrl\n};\n\n","import { push } from 'react-router-redux';\nimport C from '../constants';\nimport { ConceptFeedbackApi, } from '../libs/concept_feedback_api.ts';\n\nconst actions = {\n // called when the app starts. this means we immediately download all quotes, and\n // then receive all quotes again as soon as anyone changes anything.\n startListeningToConceptsFeedback() {\n return function (dispatch, getState) {\n dispatch(actions.loadConceptsFeedback())\n };\n },\n loadConceptsFeedback() {\n return function (dispatch, getState) {\n ConceptFeedbackApi.getAll().then((data) => {\n dispatch({ type: C.RECEIVE_CONCEPTS_FEEDBACK_DATA, data: data, });\n });\n };\n },\n loadTranslatedConceptsFeedback(language) {\n return function (dispatch, getState) {\n ConceptFeedbackApi.getAll(language).then((data) => {\n dispatch({ type: C.RECEIVE_TRANSLATED_CONCEPTS_FEEDBACK_DATA, data: data, });\n });\n };\n },\n loadConceptFeedback(uid) {\n return function (dispatch, getState) {\n ConceptFeedbackApi.get(uid).then((data) => {\n dispatch({ type: C.RECEIVE_CONCEPT_FEEDBACK_DATA, uid: uid, data: data, });\n });\n };\n },\n startConceptsFeedbackEdit(cid) {\n return { type: C.START_CONCEPTS_FEEDBACK_EDIT, cid, };\n },\n cancelConceptsFeedbackEdit(cid) {\n return { type: C.FINISH_CONCEPTS_FEEDBACK_EDIT, cid, };\n },\n deleteConceptsFeedback(cid) {\n return function (dispatch, getState) {\n dispatch({ type: C.SUBMIT_CONCEPTS_FEEDBACK_EDIT, cid, });\n ConceptFeedbackApi.remove(cid).then(() => {\n dispatch({ type: C.FINISH_CONCEPTS_FEEDBACK_EDIT, cid, });\n dispatch({ type: C.DISPLAY_MESSAGE, message: 'ConceptsFeedback successfully deleted!', });\n dispatch(actions.loadConceptsFeedback())\n }).catch((error) => {\n dispatch({ type: C.FINISH_CONCEPTS_FEEDBACK_EDIT, cid, });\n dispatch({ type: C.DISPLAY_ERROR, error: `Deletion failed! ${error}`, });\n })\n };\n },\n submitConceptsFeedbackEdit(cid, content) {\n return function (dispatch, getState) {\n dispatch({ type: C.SUBMIT_CONCEPTS_FEEDBACK_EDIT, cid, });\n ConceptFeedbackApi.update(cid, content).then(() => {\n dispatch(actions.loadConceptFeedback(cid))\n dispatch({ type: C.FINISH_CONCEPTS_FEEDBACK_EDIT, cid, });\n alert(\"Update successfully saved!\");\n }).catch((error) => {\n dispatch({ type: C.FINISH_CONCEPTS_FEEDBACK_EDIT, cid, });\n dispatch({ type: C.DISPLAY_ERROR, error: `Update failed! ${error}`, });\n })\n };\n },\n toggleNewConceptsFeedbackModal() {\n return { type: C.TOGGLE_NEW_CONCEPTS_FEEDBACK_MODAL, };\n },\n testFeedback() {\n },\n submitNewConceptsFeedback(content) {\n return function (dispatch, getState) {\n dispatch({ type: C.AWAIT_NEW_CONCEPTS_FEEDBACK_RESPONSE, });\n ConceptFeedbackApi.create(content).then((conceptFeedback) => {\n dispatch({ type: C.RECEIVE_NEW_CONCEPTS_FEEDBACK_RESPONSE, });\n dispatch({ type: C.DISPLAY_MESSAGE, message: 'Submission successfully saved!', });\n const uid = Object.keys(conceptFeedback)[0]\n const action = push(`/admin/concepts-feedback/${uid}`);\n dispatch(action);\n }).catch((error) => {\n dispatch({ type: C.RECEIVE_NEW_CONCEPTS_FEEDBACK_RESPONSE, });\n dispatch({ type: C.DISPLAY_ERROR, error: `Submission failed! ${error}`, });\n })\n };\n },\n};\n\nexport default actions;\n","import C from '../constants';\n\n\n// Put 'pusher' on global window for TypeScript validation\ndeclare global {\n interface Window { pusher: any }\n}\n\nimport { goBack } from 'react-router-redux';\nimport lessonActions from '../actions/lessons';\nimport { Question } from '../interfaces/questions';\nimport { LessonApi, TYPE_CONNECT_LESSON } from '../libs/lessons_api';\nimport {\n FILL_IN_BLANKS_TYPE,\n FocusPointApi,\n IncorrectSequenceApi,\n QuestionApi\n} from '../libs/questions_api';\nimport { submitResponse } from './responses';\n\n// called when the app starts. this means we immediately download all questions, and\n// then receive all questions again as soon as anyone changes anything.\nfunction startListeningToQuestions() {\n return loadQuestions();\n}\n\nfunction loadQuestions() {\n return (dispatch, getState) => {\n QuestionApi.getAll(FILL_IN_BLANKS_TYPE).then((questions) => {\n dispatch({ type: C.RECEIVE_FILL_IN_BLANK_QUESTIONS_DATA, data: questions, });\n });\n };\n}\n\nfunction loadQuestion(uid) {\n return (dispatch, getState) => {\n QuestionApi.get(uid).then((question: Question) => {\n dispatch({ type: C.RECEIVE_FILL_IN_BLANK_QUESTION_DATA, uid: uid, data: question, });\n });\n }\n}\n\nfunction startQuestionEdit(qid) {\n return { type: C.START_FILL_IN_BLANK_QUESTION_EDIT, qid, };\n}\n\nfunction cancelQuestionEdit(qid) {\n return { type: C.FINISH_FILL_IN_BLANK_QUESTION_EDIT, qid, };\n}\n\nfunction submitQuestionEdit(qid, content) {\n return (dispatch, getState) => {\n dispatch({ type: C.SUBMIT_FILL_IN_BLANK_QUESTION_EDIT, qid, });\n QuestionApi.update(qid, content).then(() => {\n dispatch({ type: C.FINISH_FILL_IN_BLANK_QUESTION_EDIT, qid, });\n dispatch(loadQuestion(qid));\n dispatch({ type: C.DISPLAY_MESSAGE, message: 'Update successfully saved!', });\n const action = goBack();\n dispatch(action);\n }).catch((error) => {\n dispatch({ type: C.FINISH_FILL_IN_BLANK_QUESTION_EDIT, qid, });\n dispatch({ type: C.DISPLAY_ERROR, error: `Update failed! ${error}`, });\n })\n };\n}\nfunction toggleNewQuestionModal() {\n return { type: C.TOGGLE_NEW_FILL_IN_BLANK_QUESTION_MODAL, };\n}\n\nfunction submitNewQuestion(content, response, lessonID) {\n return (dispatch, getState) => {\n dispatch({ type: C.AWAIT_NEW_FILL_IN_BLANK_QUESTION_RESPONSE, });\n QuestionApi.create(FILL_IN_BLANKS_TYPE, content).then((question) => {\n dispatch({ type: C.RECEIVE_NEW_FILL_IN_BLANK_QUESTION_RESPONSE, });\n response.questionUID = Object.keys(question)[0];\n response.gradeIndex = `human${response.questionUID}`;\n dispatch(submitResponse(response));\n dispatch(loadQuestion(response.questionUID));\n dispatch({ type: C.DISPLAY_MESSAGE, message: 'Submission successfully saved!', });\n const lessonQuestion = { key: response.questionUID, questionType: C.INTERNAL_FILL_IN_BLANK_TYPE }\n dispatch({ type: C.SUBMIT_LESSON_EDIT, cid: lessonID, });\n LessonApi.addQuestion(TYPE_CONNECT_LESSON, lessonID, lessonQuestion).then(() => {\n dispatch({ type: C.FINISH_LESSON_EDIT, cid: lessonID, });\n dispatch(lessonActions.loadLesson(lessonID));\n dispatch({ type: C.DISPLAY_MESSAGE, message: 'Question successfully added to lesson!', });\n }).catch((error) => {\n dispatch({ type: C.FINISH_LESSON_EDIT, cid: lessonID, });\n dispatch({ type: C.DISPLAY_ERROR, error: `Add to lesson failed! ${error}`, });\n });\n }, (error) => {\n dispatch({ type: C.RECEIVE_NEW_FILL_IN_BLANK_QUESTION_RESPONSE, });\n dispatch({ type: C.DISPLAY_ERROR, error: `Submission failed! ${error}`, });\n });\n };\n}\n\nfunction submitNewFocusPoint(qid, data) {\n return (dispatch, getState) => {\n FocusPointApi.create(qid, data).then(() => {\n dispatch(loadQuestion(qid));\n }, (error) => {\n alert(`Submission failed! ${error}`);\n });\n }\n}\n\nfunction submitEditedFocusPoint(qid, data, fpid) {\n return (dispatch, getState) => {\n FocusPointApi.update(qid, fpid, data).then(() => {\n dispatch(loadQuestion(qid));\n }).catch((error) => {\n alert(`Submission failed! ${error}`);\n });\n };\n}\n\nfunction submitBatchEditedFocusPoint(qid, data) {\n return (dispatch, getState) => {\n FocusPointApi.updateAllForQuestion(qid, data).then(() => {\n dispatch(loadQuestion(qid));\n }).catch((error) => {\n alert(`Submission failed! ${error}`);\n });\n };\n}\n\nfunction deleteFocusPoint(qid, fpid) {\n return (dispatch, getState) => {\n FocusPointApi.remove(qid, fpid).then(() => {\n dispatch(loadQuestion(qid));\n }, (error) => {\n alert(`Delete failed! ${error}`);\n });\n };\n}\n\nfunction submitNewIncorrectSequence(qid, data) {\n return (dispatch, getState) => {\n IncorrectSequenceApi.create(qid, data).then(() => {\n dispatch(loadQuestion(qid));\n }, (error) => {\n alert(`Submission failed! ${error}`);\n });\n };\n}\n\nfunction submitEditedIncorrectSequence(qid, data, seqid) {\n return (dispatch, getState) => {\n IncorrectSequenceApi.update(qid, seqid, data).then(() => {\n dispatch(loadQuestion(qid));\n }).catch((error) => {\n alert(`Submission failed! ${error}`);\n });\n };\n}\n\nfunction deleteIncorrectSequence(qid, seqid) {\n return (dispatch, getState) => {\n IncorrectSequenceApi.remove(qid, seqid).then(() => {\n dispatch(loadQuestion(qid));\n }, (error) => {\n alert(`Delete failed! ${error}`);\n });\n };\n}\n\nexport default {\n startListeningToQuestions,\n loadQuestions,\n loadQuestion,\n startQuestionEdit,\n cancelQuestionEdit,\n submitQuestionEdit,\n toggleNewQuestionModal,\n submitNewQuestion,\n submitNewFocusPoint,\n submitEditedFocusPoint,\n submitBatchEditedFocusPoint,\n deleteFocusPoint,\n submitNewIncorrectSequence,\n submitEditedIncorrectSequence,\n deleteIncorrectSequence\n}\n","import lessonActions from '../actions/lessons';\nimport C from '../constants';\nimport { Question } from '../interfaces/questions';\nimport { LessonApi, TYPE_CONNECT_LESSON } from '../libs/lessons_api';\nimport {\n FocusPointApi,\n IncorrectSequenceApi,\n QuestionApi,\n SENTENCE_FRAGMENTS_TYPE\n} from '../libs/questions_api';\nimport { submitResponse } from './responses';\n\nfunction startListeningToSentenceFragments() {\n return loadSentenceFragments();\n}\n\nfunction loadSentenceFragments() {\n return (dispatch, getState) => {\n QuestionApi.getAll(SENTENCE_FRAGMENTS_TYPE).then((questions) => {\n dispatch({ type: C.RECEIVE_SENTENCE_FRAGMENTS_DATA, data: questions, });\n });\n };\n}\n\nfunction loadSentenceFragment(uid) {\n return (dispatch, getState) => {\n QuestionApi.get(uid).then((question: Question) => {\n dispatch({ type: C.RECEIVE_SENTENCE_FRAGMENT_DATA, uid: uid, data: question, });\n });\n }\n}\n\nfunction startSentenceFragmentEdit(sfid) {\n return { type: C.START_SENTENCE_FRAGMENT_EDIT, sfid, };\n}\nfunction cancelSentenceFragmentEdit(sfid) {\n return { type: C.FINISH_SENTENCE_FRAGMENT_EDIT, sfid, };\n}\n\nfunction submitSentenceFragmentEdit(sfid, content) {\n return (dispatch, getState) => {\n dispatch({ type: C.SUBMIT_SENTENCE_FRAGMENT_EDIT, sfid, });\n QuestionApi.update(sfid, content).then( () => {\n dispatch({ type: C.FINISH_SENTENCE_FRAGMENT_EDIT, sfid, });\n dispatch(loadSentenceFragment(sfid));\n dispatch({ type: C.DISPLAY_MESSAGE, message: 'Update successfully saved!', });\n }).catch( (error) => {\n dispatch({ type: C.FINISH_QUESTION_EDIT, sfid, });\n dispatch({ type: C.DISPLAY_ERROR, error: `Update failed! ${error}`, });\n });\n };\n}\n\nfunction submitNewIncorrectSequence(sfid, data) {\n return (dispatch, getState) => {\n IncorrectSequenceApi.create(sfid, data).then(() => {\n dispatch(loadSentenceFragment(sfid));\n }, (error) => {\n alert(`Submission failed! ${error}`);\n });\n };\n}\n\nfunction submitEditedIncorrectSequence(sfid, data, sesfid) {\n return (dispatch, getState) => {\n IncorrectSequenceApi.update(sfid, sesfid, data).then(() => {\n dispatch(loadSentenceFragment(sfid));\n }).catch( (error) => {\n alert(`Submission failed! ${error}`);\n });\n };\n}\n\nfunction deleteIncorrectSequence(sfid, sesfid) {\n return (dispatch, getState) => {\n IncorrectSequenceApi.remove(sfid, sesfid).then(() => {\n dispatch(loadSentenceFragment(sfid));\n }, (error) => {\n alert(`Delete failed! ${error}`);\n });\n };\n}\n\nfunction toggleNewSentenceFeedbackModal() {\n return { type: C.TOGGLE_NEW_SENTENCE_FRAGMENT_MODAL, };\n}\n\nfunction submitNewSentenceFragment(content, response, lessonID) {\n return (dispatch, getState) => {\n dispatch({ type: C.AWAIT_NEW_QUESTION_RESPONSE, });\n QuestionApi.create(SENTENCE_FRAGMENTS_TYPE, content).then((question) => {\n dispatch({ type: C.RECEIVE_NEW_QUESTION_RESPONSE, });\n response.questionUID = Object.keys(question)[0];\n response.gradeIndex = `human${response.questionUID}`;\n dispatch(submitResponse(response));\n dispatch(loadSentenceFragment(response.questionUID));\n dispatch({ type: C.DISPLAY_MESSAGE, message: 'Submission successfully saved!', });\n const lessonQuestion = {key: response.questionUID, questionType: C.INTERNAL_SENTENCE_FRAGMENTS_TYPE}\n dispatch({ type: C.SUBMIT_LESSON_EDIT, cid: lessonID, });\n LessonApi.addQuestion(TYPE_CONNECT_LESSON, lessonID, lessonQuestion).then( () => {\n dispatch({ type: C.FINISH_LESSON_EDIT, cid: lessonID, });\n dispatch(lessonActions.loadLesson(lessonID));\n dispatch({ type: C.DISPLAY_MESSAGE, message: 'Question successfully added to lesson!', });\n }).catch( (error) => {\n dispatch({ type: C.FINISH_LESSON_EDIT, cid: lessonID, });\n dispatch({ type: C.DISPLAY_ERROR, error: `Add to lesson failed! ${error}`, });\n });\n }, (error) => {\n dispatch({ type: C.RECEIVE_NEW_QUESTION_RESPONSE, });\n dispatch({ type: C.DISPLAY_ERROR, error: `Submission failed! ${error}`, });\n });\n };\n}\n\nfunction submitNewFocusPoint(sfid, data) {\n return (dispatch, getState) => {\n FocusPointApi.create(sfid, data).then(() => {\n dispatch(loadSentenceFragment(sfid));\n }, (error) => {\n alert(`Submission failed! ${error}`);\n });\n }\n}\n\nfunction submitEditedFocusPoint(sfid, data, fpid) {\n return (dispatch, getState) => {\n FocusPointApi.update(sfid, fpid, data).then(() => {\n dispatch(loadSentenceFragment(sfid));\n }).catch( (error) => {\n alert(`Submission failed! ${error}`);\n });\n };\n}\n\nfunction submitBatchEditedFocusPoint(sfid, data) {\n return (dispatch, getState) => {\n FocusPointApi.updateAllForQuestion(sfid, data).then(() => {\n dispatch(loadSentenceFragment(sfid));\n }).catch( (error) => {\n alert(`Submission failed! ${error}`);\n });\n };\n}\n\nfunction deleteFocusPoint(sfid, fpid) {\n return (dispatch, getState) => {\n FocusPointApi.remove(sfid, fpid).then(() => {\n dispatch(loadSentenceFragment(sfid));\n }, (error) => {\n alert(`Delete failed! ${error}`);\n });\n };\n}\n\nfunction startResponseEdit(sfid, rid) {\n return { type: C.START_RESPONSE_EDIT, sfid, rid, };\n}\nfunction cancelResponseEdit(sfid, rid) {\n return { type: C.FINISH_RESPONSE_EDIT, sfid, rid, };\n}\nfunction startChildResponseView(sfid, rid) {\n return { type: C.START_CHILD_RESPONSE_VIEW, sfid, rid, };\n}\nfunction cancelChildResponseView(sfid, rid) {\n return { type: C.CANCEL_CHILD_RESPONSE_VIEW, sfid, rid, };\n}\nfunction startFromResponseView(sfid, rid) {\n return { type: C.START_FROM_RESPONSE_VIEW, sfid, rid, };\n}\nfunction cancelFromResponseView(sfid, rid) {\n return { type: C.CANCEL_FROM_RESPONSE_VIEW, sfid, rid, };\n}\nfunction startToResponseView(sfid, rid) {\n return { type: C.START_TO_RESPONSE_VIEW, sfid, rid, };\n}\nfunction cancelToResponseView(sfid, rid) {\n return { type: C.CANCEL_TO_RESPONSE_VIEW, sfid, rid, };\n}\n\nexport default {\n startListeningToSentenceFragments,\n loadSentenceFragments,\n loadSentenceFragment,\n startSentenceFragmentEdit,\n cancelSentenceFragmentEdit,\n submitSentenceFragmentEdit,\n submitNewIncorrectSequence,\n submitEditedIncorrectSequence,\n deleteIncorrectSequence,\n toggleNewSentenceFeedbackModal,\n submitNewSentenceFragment,\n submitNewFocusPoint,\n submitEditedFocusPoint,\n submitBatchEditedFocusPoint,\n deleteFocusPoint,\n startResponseEdit,\n cancelResponseEdit,\n startChildResponseView,\n cancelChildResponseView,\n startFromResponseView,\n cancelFromResponseView,\n startToResponseView,\n cancelToResponseView\n};\n","import { goBack, push } from 'react-router-redux';\nimport lessonActions from '../actions/lessons';\nimport { LessonApi, TYPE_CONNECT_LESSON } from '../libs/lessons_api';\nimport { CONNECT_TITLE_CARD_TYPE, TitleCardApi } from '../libs/title_cards_api';\n\nimport C from '../constants';\n\n\nfunction startListeningToTitleCards() {\n return loadTitleCards();\n}\n\nfunction loadTitleCards(): (any) => void {\n return (dispatch) => {\n TitleCardApi.getAll(CONNECT_TITLE_CARD_TYPE).then((body) => {\n let titleCards = body.title_cards || []\n const titleCardsObject = titleCards.reduce((obj, item) => {\n return Object.assign(obj, {[item.uid]: item});\n }, {});\n dispatch({ type: C.RECEIVE_TITLE_CARDS_DATA, data: titleCardsObject, });\n });\n };\n}\n\nfunction submitNewTitleCard(content, response, lessonID) {\n return (dispatch) => {\n TitleCardApi.create(CONNECT_TITLE_CARD_TYPE, content).then((body) => {\n dispatch({ type: C.RECEIVE_TITLE_CARDS_DATA_UPDATE, data: {[body.uid]: body} });\n if (lessonID) {\n const lessonQuestion = {key: body['uid'], questionType: C.INTERNAL_TITLE_CARDS_TYPE}\n dispatch({ type: C.SUBMIT_LESSON_EDIT, cid: lessonID, });\n LessonApi.addQuestion(TYPE_CONNECT_LESSON, lessonID, lessonQuestion).then( () => {\n dispatch({ type: C.FINISH_LESSON_EDIT, cid: lessonID, });\n dispatch(lessonActions.loadLesson(lessonID));\n dispatch({ type: C.DISPLAY_MESSAGE, message: 'Question successfully added to lesson!', });\n }).catch( (error) => {\n dispatch({ type: C.FINISH_LESSON_EDIT, cid: lessonID, });\n dispatch({ type: C.DISPLAY_ERROR, error: `Add to lesson failed! ${error}`, });\n });\n } else {\n const action = push(`/admin/title-cards/${body.uid}`);\n dispatch(action);\n }\n })\n .catch((body) => {\n dispatch({ type: C.DISPLAY_ERROR, error: `Submission failed! ${body}`, });\n });\n };\n}\n\nfunction submitTitleCardEdit(uid, content) {\n return (dispatch, getState) => {\n TitleCardApi.update(CONNECT_TITLE_CARD_TYPE, uid, content).then((body) => {\n dispatch({ type: C.RECEIVE_TITLE_CARDS_DATA_UPDATE, data: {[body.uid]: body} });\n dispatch({ type: C.DISPLAY_MESSAGE, message: 'Update successfully saved!', });\n const action = goBack();\n dispatch(action);\n }).catch((body) => {\n dispatch({ type: C.DISPLAY_ERROR, error: `Update failed! ${body}`, });\n });\n };\n}\n\nexport default {\n submitNewTitleCard,\n loadTitleCards,\n startListeningToTitleCards,\n submitTitleCardEdit,\n}\n","import * as React from \"react\";\n\nimport { LanguagePicker, TeacherPreviewMenuButton, renderSaveAndExitButton, showTranslations } from '../../../Shared/index';\nconst quillLogoSrc = `${window.postbuildEnv.CDN_URL}/images/logos/quill-logo-white-2022.svg`;\n\ninterface NavBarProps {\n isOnMobile?: boolean;\n isTeacher?: boolean;\n previewShowing?: boolean;\n onTogglePreview?: () => void;\n language: string;\n languageOptions?: any;\n translate: (language: string) => string;\n updateLanguage: (language: string) => void;\n}\n\nexport const NavBar: React.SFC = ({ isOnMobile, isTeacher, previewShowing, onTogglePreview, language, languageOptions, updateLanguage, translate }) => {\n const handleTogglePreview = () => {\n onTogglePreview();\n }\n\n return (\n
\n
\n {isTeacher && !previewShowing && !isOnMobile && }\n \"Quill\n
\n {showTranslations(language, languageOptions) && }\n {renderSaveAndExitButton({ language, languageOptions, translate })}\n
\n
\n
\n );\n};\n","import React, { Component } from 'react';\nimport { FlagDropdown, TextEditor, ConceptSelector, } from '../../../Shared/index';\nimport C from '../../constants.js';\n\nclass FillInBlankForm extends Component {\n constructor(props) {\n super(props);\n const { blankAllowed, caseInsensitive, conceptID, cues, cuesLabel, flag, instructions, prompt} = props\n this.state = {\n blankAllowed: blankAllowed || false,\n caseInsensitive: caseInsensitive || false,\n conceptID: conceptID || '',\n cues: cues || '',\n cuesLabel: cuesLabel || '',\n flag: flag || 'alpha',\n instructions: instructions || '',\n newQuestionOptimalResponse: '',\n prompt: prompt || '',\n showDefaultInstructions: false,\n };\n }\n\n clearForm = () => {\n this.setState({\n blankAllowed: false,\n caseInsensitive: false,\n newQuestionPrompt: '',\n newQuestionOptimalResponse: '',\n instructions: '',\n conceptID: null,\n flag: 'alpha',\n cuesLabel: '',\n showDefaultInstructions: false,\n });\n }\n\n handleCuesChange = e => {\n this.setState({cues: e.target.value});\n };\n\n handleCuesLabelChange = e => {\n this.setState({ cuesLabel: e.target.value, });\n };\n\n handleFlagChange = e => {\n this.setState({ flag: e.target.value, });\n };\n\n handleInstructionsChange = e => {\n this.setState({instructions: e.target.value});\n if (e.target.value == '/') {\n this.setState({ showDefaultInstructions: true})\n } else {\n this.setState({ showDefaultInstructions: false})\n }\n };\n\n handleNewQuestionOptimalResponseChange = e => {\n this.setState({newQuestionOptimalResponse: e.target.value});\n };\n\n handlePromptChange = prompt => {\n this.setState({ prompt });\n };\n\n handleSelectorChange = e => {\n this.setState({conceptID: e.value});\n };\n\n renderDefaultInstructions = () => {\n const { showDefaultInstructions } = this.state\n const defaultInstructionsDiv = C.DEFAULT_FILL_IN_BLANKS_INSTRUCTIONS.map((item, i) =>\n (\n {item}\n )\n )\n if (showDefaultInstructions) {\n return (\n
\n
\n {defaultInstructionsDiv}\n
\n
\n )\n }\n };\n\n submit = () => {\n const { questionID, newQuestionOptimalResponse, prompt, blankAllowed, caseInsensitive, cues, instructions, conceptID, flag, cuesLabel } = this.state\n const { action } = this.props\n const data = {\n prompt: prompt,\n blankAllowed: blankAllowed ? blankAllowed : false,\n caseInsensitive: caseInsensitive ? caseInsensitive : false,\n cues: cues.split(','),\n instructions: instructions,\n conceptID: conceptID,\n flag: flag ? flag : 'alpha',\n cuesLabel: cuesLabel\n };\n if (this.props.new && data.prompt != '') {\n action(\n data,\n {\n text: newQuestionOptimalResponse.trim(),\n optimal: true,\n count: 0,\n feedback: \"That's a strong sentence!\",\n concept_results: [{conceptUID: conceptID, correct: true}]\n }\n );\n } else {\n action(data, newQuestionOptimalResponse);\n }\n };\n\n toggleQuestionBlankAllowed = () => {\n this.setState({blankAllowed: !this.state.blankAllowed});\n };\n\n toggleQuestionCaseInsensitive = () => {\n this.setState(prevState => ({caseInsensitive: !prevState.caseInsensitive}));\n };\n\n renderButtonText = () => {\n return this.props.editing ? 'Submit Edit' : 'Add Question';\n }\n\n renderOptimalField = () => {\n if(!this.props.editing) {\n return(\n
\n \n

\n \n

\n
\n );\n }\n }\n\n render() {\n const { instructions } = this.state\n return(\n
\n
Create a new question
\n \n \n
\n \n

\n