diff --git a/src/components.d.ts b/src/components.d.ts index 43b2786..53efc79 100644 --- a/src/components.d.ts +++ b/src/components.d.ts @@ -1,67 +1,70 @@ /* tslint:disable */ /** * This is an autogenerated file created by the Stencil compiler. * It contains typing information for all components that exist in this project. */ import '@stencil/core'; export namespace Components { interface WikiDataSpinner {} interface WikiDataSpinnerAttributes extends StencilHTMLAttributes {} - interface WikidataCaptchaJs {} + interface WikidataCaptchaJs { + 'language': string; + } interface WikidataCaptchaJsAttributes extends StencilHTMLAttributes { + 'language'?: string; 'onWikiIsHuman'?: (event: CustomEvent) => void; } } declare global { interface StencilElementInterfaces { 'WikiDataSpinner': Components.WikiDataSpinner; 'WikidataCaptchaJs': Components.WikidataCaptchaJs; } interface StencilIntrinsicElements { 'wiki-data-spinner': Components.WikiDataSpinnerAttributes; 'wikidata-captcha-js': Components.WikidataCaptchaJsAttributes; } interface HTMLWikiDataSpinnerElement extends Components.WikiDataSpinner, HTMLStencilElement {} var HTMLWikiDataSpinnerElement: { prototype: HTMLWikiDataSpinnerElement; new (): HTMLWikiDataSpinnerElement; }; interface HTMLWikidataCaptchaJsElement extends Components.WikidataCaptchaJs, HTMLStencilElement {} var HTMLWikidataCaptchaJsElement: { prototype: HTMLWikidataCaptchaJsElement; new (): HTMLWikidataCaptchaJsElement; }; interface HTMLElementTagNameMap { 'wiki-data-spinner': HTMLWikiDataSpinnerElement 'wikidata-captcha-js': HTMLWikidataCaptchaJsElement } interface ElementTagNameMap { 'wiki-data-spinner': HTMLWikiDataSpinnerElement; 'wikidata-captcha-js': HTMLWikidataCaptchaJsElement; } export namespace JSX { export interface Element {} export interface IntrinsicElements extends StencilIntrinsicElements { [tagName: string]: any; } } export interface HTMLAttributes extends StencilHTMLAttributes {} } diff --git a/src/components/wiki-captcha-js/wiki-captcha-js.css b/src/components/wiki-captcha-js/wiki-captcha-js.css index bce5bb0..e9013d3 100644 --- a/src/components/wiki-captcha-js/wiki-captcha-js.css +++ b/src/components/wiki-captcha-js/wiki-captcha-js.css @@ -1,129 +1,139 @@ :host { font-family: sans-serif; /*border: 2px solid var(--color-primary, black);*/ margin: 2rem; padding: 1rem; display: block; max-width: 100%; - min-height: 26rem; + min-height: 10rem; box-shadow: 0 2px 8px rgba(0,0,0,.26); border-radius: 3px; width: 20rem; overflow: hidden; } .wiki-captcha-box { font-family: sans-serif; display: flex; flex-direction: column; align-items: center; justify-content: center; max-width: 100%; min-height: 100%; padding-left: 1rem; padding-right: 1rem; } .wiki-captcha-error { color: red; margin-bottom: 0; } .wiki-captcha-img-container { display: flex; flex-wrap: wrap; width: 15rem; max-width: 100%; justify-content: center; border-radius: 3px; overflow: hidden; align-self: center; - /*border: 2px solid var(--color-primary, black);*/ + border: 1px solid grey; box-shadow: 0 2px 8px rgba(0,0,0,.5); } .wiki-captcha-img, .wiki-captcha-img-selected { width: 100%; height: 6rem; flex: 1 0 30%; /* 3 images per row */ } .wiki-captcha-img-overlay { display: inline-block; position: relative; width: 33.3%; height: 6rem; z-index: 1; cursor: pointer; } .wiki-captcha-img-overlay-on:after { content: ''; position: absolute; top: 0; right: 0; bottom: 0; left: 0; background: rgba(117, 1, 117, 0.5); } .wiki-captcha-img-overlay-off:after { content: ''; position: absolute; top: 0; right: 0; bottom: 0; left: 0; background: rgba(117, 1, 117, 0.0); } .wiki-captcha-footer { display: flex; align-items: center; padding-top: .5rem; } .wiki-captcha-powered-by { display: flex; justify-content: flex-end; padding-top: .5rem; } .wiki-captcha-powered-by-icon { max-width: 20%; } .wiki-captcha-submit { } button, button:focus { outline: none; } button { font: inherit; padding: 0.25rem 0.5rem; border: 1px solid var(--color-primary, black); background: var(--color-primary, black); color: var(--color-primary-inverse, white); cursor: pointer; + border-radius: 3px; } button:hover, button:active { background: var(--color-primary-highlight, grey); border-color: var(--color-primary-highlight, grey); } button:disabled { background: #ccc; border-color: #ccc; color: white; cursor: not-allowed; } p { align-self: center; } + +input { + min-width: 100%; + font: inherit; + outline: none; + overflow: hidden; + border-radius: 3px; + border: none; +} diff --git a/src/components/wiki-captcha-js/wiki-captcha-js.tsx b/src/components/wiki-captcha-js/wiki-captcha-js.tsx index 30accaf..3dad633 100644 --- a/src/components/wiki-captcha-js/wiki-captcha-js.tsx +++ b/src/components/wiki-captcha-js/wiki-captcha-js.tsx @@ -1,154 +1,193 @@ -import {Component, EventEmitter, State, Event} from '@stencil/core'; -import {AnswerDto, UserAnswerDto, UserAnswersResponseDto, WikiApiDto} from './wiki-api.dto'; +import {Component, Event, EventEmitter, Prop, State} from '@stencil/core'; +import { + AnswerDto, + QUESTION_TYPES, + QuestionDto, + UserAnswerDto, + UserAnswersResponseDto, + WikiApiDto +} from './wiki-api.dto'; +// import {WikiDataFactory} from "../../test/factory"; @Component({ tag: 'wikidata-captcha-js', styleUrl: './wiki-captcha-js.css', shadow: true }) export class WikiCaptchaJs { + private readonly QUESTION_INDEX = 0; private readonly WIKI_DATA_URL = 'http://192.168.1.142:8080'; private readonly WIKI_DATA_ICON = 'https://upload.wikimedia.org/wikipedia/commons/6/66/Wikidata-logo-en.svg'; private readonly IMAGES_PER_CAPTCHA = 9; + private captchaInput: HTMLInputElement; + private currentQuestion: QuestionDto; + + @Prop({ mutable: true, reflectToAttr: true }) language: string = 'en'; @State() private questionList: WikiApiDto; @State() private loading = false; @State() private error = false; @Event({bubbles: true, composed: true}) wikiIsHuman: EventEmitter; + componentWillLoad() { + this.language = 'en'; + } + componentDidLoad() { this.fetchQuestions(); } render() { - let question = null; let questionText = null; let images = null; let htmlContent = null; + this.currentQuestion = null; + this.captchaInput = null; if (this.questionList && this.questionList.questionList.length > 0) { - question = this.questionList.questionList[0]; - questionText = question.questionText; + this.currentQuestion = this.questionList.questionList[this.QUESTION_INDEX]; + questionText = this.currentQuestion.questionText; - const maxImageSize = question.answersAvailable.length < this.IMAGES_PER_CAPTCHA ? question.answersAvailable.length : this.IMAGES_PER_CAPTCHA; - images = (question.answersAvailable.slice(0, maxImageSize).map(a => - (
- possible captcha answer -
)) - ); + switch (this.currentQuestion.questionType) { + case QUESTION_TYPES.IMAGE: + images = this.renderImageQuestionContent(this.currentQuestion); + break; + case QUESTION_TYPES.FREE_TEXT: + images = ( (this.captchaInput = el)}/>); + break; + case QUESTION_TYPES.OPTIONS: + default: + this.error = true; + } } if (this.error) { htmlContent = [

Oops, something went wrong!

, this.renderFooter()]; } else if (this.loading) { htmlContent = ; } else { htmlContent = [

{questionText}

,
{images}
, this.renderFooter()] } return (
{htmlContent}
); } renderFooter() { let submitHtml = null; if (!this.error) { submitHtml = (
); } return ( ); } + renderImageQuestionContent(question: QuestionDto) { + const maxImageSize = question.answersAvailable.length < this.IMAGES_PER_CAPTCHA ? question.answersAvailable.length : this.IMAGES_PER_CAPTCHA; + return question.answersAvailable.slice(0, maxImageSize).map(a => + (
+ possible captcha answer +
)); + } + onImageClick(answer: AnswerDto, event: Event) { if (!answer.userAnswer) { answer.userAnswer = new UserAnswerDto(); answer.userAnswer.selected = false; } answer.userAnswer.selected = !answer.userAnswer.selected; const divElement = event.target as HTMLDivElement; if (answer.userAnswer.selected) { divElement.classList.remove('wiki-captcha-img-overlay-off'); divElement.classList.add('wiki-captcha-img-overlay-on'); } else { divElement.classList.remove('wiki-captcha-img-overlay-on'); divElement.classList.add('wiki-captcha-img-overlay-off'); } } onSubmitCaptchaAnswers() { this.loading = true; this.error = false; + switch (this.currentQuestion.questionType) { + case QUESTION_TYPES.FREE_TEXT: + this.currentQuestion.answersAvailable[0].userAnswer = new UserAnswerDto(); + this.currentQuestion.answersAvailable[0].userAnswer.userInput = this.captchaInput.value; + break; + } + console.log('BODY', this.questionList); fetch( this.WIKI_DATA_URL + '/answers', { method: 'PUT', headers: { 'Content-Type': 'application/json', 'Accept': 'application/json' }, body: JSON.stringify(this.questionList) } ) .then(res => res.json()) .then((respParsed) => { this.loading = false; this.error = false; const response = respParsed as UserAnswersResponseDto; this.wikiIsHuman.emit(response.human); this.fetchQuestions(); }) .catch(err => { console.log(err); this.loading = false; this.error = true; }); } fetchQuestions() { this.loading = true; this.error = false; const requestBody = { - 'language': 'en', + 'language': this.language, 'appid': 1 }; fetch( this.WIKI_DATA_URL + '/questions', { method: 'POST', headers: { 'Content-Type': 'application/json', 'Accept': 'application/json' }, body: JSON.stringify(requestBody) } ) .then(res => res.json()) .then(parsedRes => { this.questionList = parsedRes as WikiApiDto; + // this.questionList = new WikiDataFactory().getQuestions(); this.loading = false; this.error = false; }) .catch(err => { console.log(err); this.loading = false; this.error = true; }); } } diff --git a/src/index.html b/src/index.html index 08733b4..12f4c02 100644 --- a/src/index.html +++ b/src/index.html @@ -1,54 +1,62 @@ Stencil Component Starter + +
- +
diff --git a/src/test/factory.ts b/src/test/factory.ts index 383c0cf..20b437f 100644 --- a/src/test/factory.ts +++ b/src/test/factory.ts @@ -1,36 +1,48 @@ import {AnswerDto, QUESTION_TYPES, QuestionDto, WikiApiDto} from '../components/wiki-captcha-js/wiki-api.dto'; export class WikiDataFactory { public getQuestions(): WikiApiDto { const questions = new WikiApiDto(); questions.sessionId = 'abcd'; questions.questionList = []; - questions.questionList.push(this.getSingleQuestion()); + questions.questionList.push(this.getSingleQuestionImg()); + questions.questionList.push(this.getSingleQuestionInput()); return questions; } - private getSingleQuestion(): QuestionDto { + private getSingleQuestionInput(): QuestionDto { + const question = new QuestionDto(); + question.questionId = '1'; + question.questionText = 'How many moons does Earth have?'; + question.questionType = QUESTION_TYPES.FREE_TEXT; + question.answersAvailable = []; + question.answersAvailable.push(this.getAnswer('', '1')); + return question; + } + + private getSingleQuestionImg(): QuestionDto { const question = new QuestionDto(); question.questionId = '1'; question.questionText = 'Select ALL images with men'; question.questionType = QUESTION_TYPES.IMAGE; question.answersAvailable = []; question.answersAvailable.push(this.getAnswer('https://upload.wikimedia.org/wikipedia/commons/f/ff/Human-man.png')); question.answersAvailable.push(this.getAnswer('https://upload.wikimedia.org/wikipedia/commons/5/56/Donald_Trump_official_portrait.jpg')); question.answersAvailable.push(this.getAnswer('https://upload.wikimedia.org/wikipedia/commons/1/12/Billie_Holiday_0001_original.jpg')); question.answersAvailable.push(this.getAnswer('https://upload.wikimedia.org/wikipedia/commons/b/bf/Angela_Merkel._Tallinn_Digital_Summit.jpg')); question.answersAvailable.push(this.getAnswer('https://upload.wikimedia.org/wikipedia/commons/f/ff/Human-man.png')); question.answersAvailable.push(this.getAnswer('https://upload.wikimedia.org/wikipedia/commons/f/ff/Human-man.png')); question.answersAvailable.push(this.getAnswer('https://upload.wikimedia.org/wikipedia/commons/f/ff/Human-man.png')); question.answersAvailable.push(this.getAnswer('https://upload.wikimedia.org/wikipedia/commons/f/ff/Human-man.png')); question.answersAvailable.push(this.getAnswer('https://upload.wikimedia.org/wikipedia/commons/f/ff/Human-man.png')); return question; } - private getAnswer(img: string): AnswerDto { + private getAnswer(img: string, text?: string): AnswerDto { const answer = new AnswerDto(); answer.imgUrl = img; + answer.text = text; return answer; } }