import {substrex, randNumber as RandNumber, randNumber} from "@App/internal/utils/utils"; import { Question, TopicStatus, TopicStatusString, TopicType, SwitchTopicType, Option, Answer, PushAnswer } from "@App/internal/app/question"; import {CreateNoteLine} from "./utils"; //TODO: 优化 export class CxQuestionFactory { public static CreateCourseQuestion(el: HTMLElement): Question { let ret = SwitchTopicType(substrex(el.innerText, '【', '】')); return this.CreateCourseQuestionByTopicType(ret, el); } public static CreateExamQuestion(type: TopicType, el: HTMLElement): Question { let processor = new ExamQuestionProcessor(); let ret: Question = null; this.RemoveNotice(el); switch (type) { case 1: case 2: { ret = new cxExamSelectQuestion(el, type, processor); break; } case 3: { ret = new cxExamJudgeQuestion(el, type, processor); break; } case 4: { ret = new cxExamFillQuestion(el, type, processor); break; } default: { this.AddNotice(el, "不支持的类型"); return null } } return ret; } public static CreateCourseQuestionByTopicType(type: TopicType, el: HTMLElement): Question { let ret: Question = null; let processor = new CourseQuestionProcessor(); this.RemoveNotice(el); switch (type) { case 1: case 2: { ret = new cxSelectQuestion(el, type, processor); break; } case 3: { ret = new cxJudgeQuestion(el, type, processor); break; } case 4: { ret = new cxFillQuestion(el, type, processor); break; } default: { this.AddNotice(el, "不支持的类型"); return null } } return ret; } protected static getBeforeType(el: HTMLElement): HTMLElement { let before = el.previousElementSibling; do { if (before.className == "Cy_TItle1") { return before; } before = before.previousElementSibling; } while (before != null) return null; } public static CreateHomeWorkQuestion(el: HTMLElement): Question { let ret = CxQuestionFactory.getBeforeType(el); return this.CreateCourseQuestionByTopicType(SwitchTopicType(substrex(ret.innerText, ".", "(")), el); } public static CreateExamCollectQuestion(el: HTMLElement): Question { let ret = CxQuestionFactory.getBeforeType(el.parentElement); let txt = ret.innerText.match(/、(.*?)[\s|(]/)[1]; return this.CreateCourseQuestionByTopicType(SwitchTopicType(txt), el); } public static RemoveNotice(el: HTMLElement) { let tmpel = el.querySelector(".clearfix > ul,.clearfix > .Py_tk,.Zy_ulTk"); if (tmpel == undefined) { tmpel = el; } tmpel.querySelectorAll(".prompt-line-answer").forEach((v) => { v.remove() }); } public static AddNotice(el: HTMLElement, str: string) { let tmpel = el.querySelector(".clearfix > ul,.clearfix > .Py_tk,.Zy_ulTk"); if (tmpel == undefined) { tmpel = el; } CreateNoteLine(str, "answer", tmpel); } } //TODO: 优化 export interface QuestionProcessor { GetTopic(el: HTMLElement): string } class CourseQuestionProcessor implements QuestionProcessor { public GetTopic(el: HTMLElement): string { let ret = el.querySelector(".Zy_TItle > .clearfix").innerHTML; ret = ret.substring(ret.indexOf('】') + 1); if (/((.+?)分)($|\s)/.test(ret)) { ret = ret.substring(0, ret.lastIndexOf("(")); } return ret; } } class ExamQuestionProcessor implements QuestionProcessor { public GetTopic(el: HTMLElement): string { let ret = el.querySelector(".Cy_TItle.clearfix .clearfix").innerHTML; ret = ret.substr(0, ret.lastIndexOf('分)')); ret = ret.substr(0, ret.lastIndexOf('(')); return ret; } } abstract class cxQuestion implements Question { protected el: HTMLElement; protected type: TopicType; protected processor: QuestionProcessor; constructor(el: HTMLElement, type: TopicType, processor: QuestionProcessor) { this.el = el; this.type = type; this.processor = processor; } public abstract Random(): TopicStatus; public abstract Correct(): Answer; public abstract Fill(answer: Answer): TopicStatus; public SetStatus(status: TopicStatus) { this.AddNotice(TopicStatusString(status)); } public GetTopic(): string { return this.processor.GetTopic(this.el); } public RemoveNotice() { CxQuestionFactory.RemoveNotice(this.el); } public AddNotice(str: string) { CxQuestionFactory.AddNotice(this.el, str); } public GetType(): TopicType { return this.type; } protected options(): NodeListOf { let tmpel = this.el.querySelector(".clearfix > ul,.clearfix ul.Zy_ulBottom.clearfix,ul.Zy_ulTk"); let list = tmpel.querySelectorAll("li"); return list; } protected isCorrect(): Element { let el = this.el.querySelector(".Py_answer.clearfix,.Py_tk"); if (el.innerHTML.indexOf('正确答案') < 0) { if (el.querySelectorAll('.fr.dui').length <= 0 && el.querySelectorAll('.fr.bandui').length <= 0) { return null; } } return el; } protected defaultAnswer(): Answer { let ret = new PushAnswer(); ret.topic = this.GetTopic(); ret.type = this.GetType(); ret.correct = new Array(); ret.answers = new Array(); return ret; } } class cxSelectQuestion extends cxQuestion implements Question { protected getContent(el: HTMLElement): string { el = el.querySelector("a"); return el.innerHTML; } protected getOption(el: HTMLElement): string { return el.querySelector("input").value; } protected click(el: HTMLElement, content: string) { let ipt = (el.querySelector("label > input")); if (!ipt.checked) { ipt.click(); } this.AddNotice(this.getOption(el) + ":" + content); } public Random(): TopicStatus { let options = this.options(); let pos = RandNumber(0, options.length - 1); this.click(options[pos], this.getContent(options[pos])); return "random"; } public Fill(s: Answer): TopicStatus { let options = this.options(); let flag = false; for (let i = 0; i < s.correct.length; i++) { for (let j = 0; j < options.length; j++) { if (s.correct[i].content.trim() == "") { if (this.getOption(options[j]) == s.correct[i].option) { this.click(options[j], this.getContent(options[j])); flag = true; } } else if (s.Equal(this.getContent(options[j]), s.correct[i].content)) { this.click(options[j], s.correct[i].content); flag = true; } } } if (flag) { return "ok"; } return "no_match"; } public Correct(): Answer { let correct = this.isCorrect(); if (correct == null) { return null; } let ret = this.defaultAnswer(); let options = this.el.querySelectorAll(".Zy_ulTop > li.clearfix"); let correctText = correct.querySelector("span").innerText; for (let i = 0; i < options.length; i++) { let optionText = (options[i].querySelector("i.fl")).innerText; let option = { option: optionText.substring(0, 1), content: options[i].querySelector("a.fl").innerHTML, }; ret.answers.push(option); if (correctText.indexOf(option.option) > 0) { ret.correct.push(option); } } return ret; } } class cxJudgeQuestion extends cxSelectQuestion implements Question { protected getContent(el: HTMLElement): string { let tmpel = el.querySelector("label > input,input"); if (tmpel.value == "true") { return "对√"; } return "错×"; } protected click(el: HTMLElement) { let tmpel = (el.querySelector("label > input,input")); if (!tmpel.checked) { tmpel.click(); } this.AddNotice(this.getContent(el)); } public Random(): TopicStatus { let options = this.options(); let pos = RandNumber(0, 1); this.click(options[pos]); return "random"; } public Fill(answer: Answer): TopicStatus { let options = this.options(); this.click(options[answer.correct[0].content ? 0 : 1]); return "ok"; } public Correct(): Answer { let el = this.el.querySelector(".Py_answer.clearfix"); if (el.innerHTML.indexOf('正确答案') < 0) { if (el.querySelectorAll('.fr.dui').length <= 0 && el.querySelectorAll('.fr.cuo').length <= 0) { return null; } } let ret = this.defaultAnswer(); let correctText = el.querySelector("span").innerText; if (correctText.indexOf('×') >= 0) { ret.correct.push({option: false, content: false}); } else { ret.correct.push({option: true, content: true}); } return ret; } } class cxFillQuestion extends cxQuestion implements Question { protected getOption(el: HTMLElement): string { let tmpel = el.querySelector("span.fb"); return substrex(tmpel.innerHTML, "第", "空"); } public Random(): TopicStatus { return "no_support_random"; } public Correct(): Answer { let correct = this.isCorrect(); if (correct == null) { return null; } let ret = this.defaultAnswer(); let options = this.el.querySelectorAll(".Py_tk span.font14"); let isMy = false; if (options.length <= 0) { isMy = true; options = this.el.querySelectorAll(".Py_answer.clearfix .font14"); } for (let i = 0; i < options.length; i++) { if (isMy && options[i].querySelectorAll(".fr.dui").length <= 0) { continue; } let optionEl = options[i].querySelector("i.fl"); let option = { option: substrex(optionEl.innerHTML, "第", "空"), content: (options[i].querySelector(".clearfix")).innerText, }; ret.correct.push(option); } return ret; } public Fill(answer: Answer): TopicStatus { let options = this.options(); let flag = 0; for (let i = 0; i < answer.correct.length; i++) { for (let j = 0; j < options.length; j++) { if (this.getOption(options[j]) == answer.correct[i].option) { flag++; let el = options[j].querySelector("input.inp"); el.value = answer.correct[i].content; this.AddNotice(this.getOption(options[j]) + ":" + answer.correct[i].content); } } } if (flag == options.length) { return "ok"; } return "no_match"; } } //TODO: 优化 class cxExamSelectQuestion extends cxSelectQuestion { protected options(): NodeListOf { return this.el.querySelectorAll(".Cy_ulBottom.clearfix.w-buttom li input"); } protected getContent(el: HTMLElement): string { let textOption = this.el.querySelectorAll(".Cy_ulTop.w-top li div.clearfix a"); let tmpli = el.parentElement.parentElement; let pos = -1; do { tmpli = tmpli.previousElementSibling pos++; } while (tmpli != null) return textOption[pos].innerHTML; } protected getOption(el: HTMLElement): string { return el.parentElement.innerText; } protected click(el: HTMLElement, content: string) { el.click(); this.AddNotice(this.getOption(el) + ":" + content); } } class cxExamFillQuestion extends cxFillQuestion { protected options(): NodeListOf { return this.el.querySelectorAll(".Cy_ulTk .XztiHover1"); } protected getOption(el: HTMLElement): string { let tmpel = el.querySelector(".fb.font14"); return substrex(tmpel.innerHTML, "第", "空"); } public Fill(answer: Answer): TopicStatus { let options = this.options(); let flag = 0; for (let i = 0; i < answer.correct.length; i++) { for (let j = 0; j < options.length; j++) { if (this.getOption(options[j]) == answer.correct[i].option) { flag++; let uedit = (window).$(options[j]).find('textarea'); if (uedit.length <= 0) { this.AddNotice(this.getOption(options[j]) + "空发生了一个错误"); continue; } (window).UE.getEditor(uedit.attr('name')).setContent(answer.correct[i].content); this.AddNotice(this.getOption(options[j]) + ":" + answer.correct[i].content); } } } if (flag == options.length) { return "ok"; } return "no_match"; } } class cxExamJudgeQuestion extends cxJudgeQuestion { protected options(): NodeListOf { return this.el.querySelectorAll(".Cy_ulBottom.clearfix li"); } }