forked from MapComplete/MapComplete
		
	
		
			
				
	
	
		
			132 lines
		
	
	
		
			No EOL
		
	
	
		
			4.8 KiB
		
	
	
	
		
			TypeScript
		
	
	
	
	
	
			
		
		
	
	
			132 lines
		
	
	
		
			No EOL
		
	
	
		
			4.8 KiB
		
	
	
	
		
			TypeScript
		
	
	
	
	
	
| import {Store, UIEventSource} from "../../Logic/UIEventSource";
 | |
| import TagRenderingQuestion from "./TagRenderingQuestion";
 | |
| import Translations from "../i18n/Translations";
 | |
| import Combine from "../Base/Combine";
 | |
| import BaseUIElement from "../BaseUIElement";
 | |
| import {VariableUiElement} from "../Base/VariableUIElement";
 | |
| import TagRenderingConfig from "../../Models/ThemeConfig/TagRenderingConfig";
 | |
| import {Unit} from "../../Models/Unit";
 | |
| import Lazy from "../Base/Lazy";
 | |
| 
 | |
| 
 | |
| /**
 | |
|  * Generates all the questions, one by one
 | |
|  */
 | |
| export default class QuestionBox extends VariableUiElement {
 | |
|     public readonly skippedQuestions: UIEventSource<number[]>;
 | |
|     public readonly restingQuestions: Store<BaseUIElement[]>;
 | |
| 
 | |
|     constructor(state, options: {
 | |
|         tagsSource: UIEventSource<any>,
 | |
|         tagRenderings: TagRenderingConfig[], units: Unit[],
 | |
|         showAllQuestionsAtOnce?: boolean | UIEventSource<boolean>
 | |
|     }) {
 | |
| 
 | |
|         const skippedQuestions: UIEventSource<number[]> = new UIEventSource<number[]>([])
 | |
| 
 | |
|         const tagsSource = options.tagsSource
 | |
|         const units = options.units
 | |
|         options.showAllQuestionsAtOnce = options.showAllQuestionsAtOnce ?? false
 | |
|         const tagRenderings = options.tagRenderings
 | |
|             .filter(tr => tr.question !== undefined)
 | |
|             .filter(tr => tr.question !== null)
 | |
| 
 | |
| 
 | |
|         const tagRenderingQuestions = tagRenderings
 | |
|             .map((tagRendering, i) =>
 | |
|                 new Lazy(() => new TagRenderingQuestion(tagsSource, tagRendering, state,
 | |
|                     {
 | |
|                         units: units,
 | |
|                         afterSave: () => {
 | |
|                             // We save and indicate progress by pinging and recalculating
 | |
|                             skippedQuestions.ping();
 | |
|                         },
 | |
|                         cancelButton: Translations.t.general.skip.Clone()
 | |
|                             .SetClass("btn btn-secondary")
 | |
|                             .onClick(() => {
 | |
|                                 skippedQuestions.data.push(i);
 | |
|                                 skippedQuestions.ping();
 | |
|                             })
 | |
|                     }
 | |
|                 )));
 | |
| 
 | |
| 
 | |
|         const skippedQuestionsButton = Translations.t.general.skippedQuestions
 | |
|             .onClick(() => {
 | |
|                 skippedQuestions.setData([]);
 | |
|             })
 | |
|         tagsSource.map(tags => {
 | |
|             if (tags === undefined) {
 | |
|                 return undefined;
 | |
|             }
 | |
|             for (let i = 0; i < tagRenderingQuestions.length; i++) {
 | |
|                 let tagRendering = tagRenderings[i];
 | |
| 
 | |
|                 if (skippedQuestions.data.indexOf(i) >= 0) {
 | |
|                     continue;
 | |
|                 }
 | |
|                 if (tagRendering.IsKnown(tags)) {
 | |
|                     continue;
 | |
|                 }
 | |
|                 if (tagRendering.condition) {
 | |
|                     if (!tagRendering.condition.matchesProperties(tags)) {
 | |
|                         // Filtered away by the condition, so it is kindof known
 | |
|                         continue;
 | |
|                     }
 | |
|                 }
 | |
| 
 | |
|                 // this value is NOT known - this is the question we have to show!
 | |
|                 return i
 | |
|             }
 | |
|             return undefined; // The questions are depleted
 | |
|         }, [skippedQuestions]);
 | |
| 
 | |
|         const questionsToAsk: Store<BaseUIElement[]> = tagsSource.map(tags => {
 | |
|             if (tags === undefined) {
 | |
|                 return [];
 | |
|             }
 | |
|             const qs = []
 | |
|             for (let i = 0; i < tagRenderingQuestions.length; i++) {
 | |
|                 let tagRendering = tagRenderings[i];
 | |
| 
 | |
|                 if (skippedQuestions.data.indexOf(i) >= 0) {
 | |
|                     continue;
 | |
|                 }
 | |
|                 if (tagRendering.IsKnown(tags)) {
 | |
|                     continue;
 | |
|                 }
 | |
|                 if (tagRendering.condition &&
 | |
|                     !tagRendering.condition.matchesProperties(tags)) {
 | |
|                     // Filtered away by the condition, so it is kindof known
 | |
|                     continue;
 | |
|                 }
 | |
| 
 | |
|                 // this value is NOT known - this is the question we have to show!
 | |
|                 qs.push(tagRenderingQuestions[i])
 | |
|             }
 | |
|             return qs
 | |
|         }, [skippedQuestions])
 | |
| 
 | |
|         super(questionsToAsk.map(allQuestions => {
 | |
|                 const els: BaseUIElement[] = []
 | |
|                 if (options.showAllQuestionsAtOnce === true || options.showAllQuestionsAtOnce["data"]) {
 | |
|                     els.push(...questionsToAsk.data)
 | |
|                 } else {
 | |
|                     els.push(allQuestions[0])
 | |
|                 }
 | |
| 
 | |
|                 if (skippedQuestions.data.length > 0) {
 | |
|                     els.push(skippedQuestionsButton)
 | |
|                 }
 | |
| 
 | |
|                 return new Combine(els).SetClass("block mb-8")
 | |
|             })
 | |
|         )
 | |
| 
 | |
|         this.skippedQuestions = skippedQuestions;
 | |
|         this.restingQuestions = questionsToAsk
 | |
| 
 | |
| 
 | |
|     }
 | |
| 
 | |
| } |