diff --git a/app/assets/javascripts/components/annotations/annotation_form.ts b/app/assets/javascripts/components/annotations/annotation_form.ts index a3a70b4c69..cbf412d866 100644 --- a/app/assets/javascripts/components/annotations/annotation_form.ts +++ b/app/assets/javascripts/components/annotations/annotation_form.ts @@ -8,6 +8,10 @@ import "components/saved_annotations/saved_annotation_input"; import { unsafeHTML } from "lit/directives/unsafe-html.js"; import { annotationState } from "state/Annotations"; import { userAnnotationState } from "state/UserAnnotations"; +import { savedAnnotationState } from "state/SavedAnnotations"; +import { courseState } from "state/Courses"; +import { exerciseState } from "state/Exercises"; +import { userState } from "state/Users"; // Min and max of the annotation text is defined in the annotation model. const maxLength = 10_000; @@ -44,10 +48,18 @@ export class AnnotationForm extends watchMixin(ShadowlessLitElement) { @property({ state: true }) _savedAnnotationId = ""; @property({ state: true }) - savedAnnotationTitle: string; + _savedAnnotationTitle: string; @property({ state: true }) saveAnnotation = false; + get savedAnnotationTitle(): string { + return this._savedAnnotationTitle || this._annotationText.split(/\s+/).slice(0, 5).join(" ").slice(0, 40); + } + + set savedAnnotationTitle(title: string) { + this._savedAnnotationTitle = title; + } + inputRef: Ref = createRef(); titleRef: Ref = createRef(); @@ -176,95 +188,121 @@ export class AnnotationForm extends watchMixin(ShadowlessLitElement) { this.inputRef.value.focus(); } + updated(changedProperties: Map): void { + // Focus the newly shown title input if the user wants to save the annotation. + if (changedProperties.has("saveAnnotation") && this.saveAnnotation) { + this.titleRef.value.focus(); + this.titleRef.value.select(); + } + } + toggleSaveAnnotation(): void { this.saveAnnotation = !this.saveAnnotation; - if (this.saveAnnotation && !this.savedAnnotationTitle) { - // Take the first five words, with a max of 40 chars as default title - this.savedAnnotationTitle = this._annotationText.split(/\s+/).slice(0, 5).join(" ").slice(0, 40); - } } + get canSaveAnnotation(): boolean { + return !annotationState.isQuestionMode && /* REMOVE AFTER CLOSED BETA */ isBetaCourse(); + } + + get potentialSavedAnnotationsExist(): boolean { + return (savedAnnotationState.getList(new Map([ + ["course_id", courseState.id.toString()], + ["exercise_id", exerciseState.id.toString()], + ["user_id", userState.id.toString()] + ])) || []).length > 0; + } + + render(): TemplateResult { return html`
- ${annotationState.isQuestionMode || /* REMOVE AFTER CLOSED BETA */ !isBetaCourse() ? "" : html` - - `} -
- ${annotationState.isQuestionMode || /* REMOVE AFTER CLOSED BETA */ !isBetaCourse() ? "" : html` - - `} - -
- ${unsafeHTML(I18n.t("js.user_annotation.help"))} - ${annotationState.isQuestionMode ? html` - ${unsafeHTML(I18n.t("js.user_annotation.help_student"))} - ` : ""} - - ${I18n.formatNumber(this._annotationText.length)} / ${I18n.formatNumber(maxLength)} - -
-
- ${annotationState.isQuestionMode || /* REMOVE AFTER CLOSED BETA */ !isBetaCourse() ? "" : html` -
-
- - +
+
+
+ +
+ ${unsafeHTML(I18n.t("js.user_annotation.help"))} + ${annotationState.isQuestionMode ? html` + ${unsafeHTML(I18n.t("js.user_annotation.help_student"))} + ` : ""} + + ${I18n.formatNumber(this._annotationText.length)} / ${I18n.formatNumber(maxLength)} + +
- ${ this.saveAnnotation ? html` -
- - this.handleUpdateTitle()} - value=${this.savedAnnotationTitle} - id="saved-annotation-title" - > + ${ this.canSaveAnnotation && this.potentialSavedAnnotationsExist ? html` +
+
- ` : html``} - `} -
- - + ` : ""} +
+
+
+ ${ this.canSaveAnnotation && this._savedAnnotationId == "" ? html` +
+
+ + +
+ ${this.saveAnnotation ? html` +
+ this.handleUpdateTitle()} + value=${this.savedAnnotationTitle} + id="saved-annotation-title" + > + +
+ `: ""} +
+ ` : ""} +
+
+ + +
`; diff --git a/app/assets/javascripts/components/datalist_input.ts b/app/assets/javascripts/components/datalist_input.ts index fc07e8447b..405087ddf4 100644 --- a/app/assets/javascripts/components/datalist_input.ts +++ b/app/assets/javascripts/components/datalist_input.ts @@ -17,6 +17,7 @@ export type Option = {label: string, value: string, extra?: string}; * The extra string is added in the options and also used to match the input * @prop {String} value - the initial value for this field * @prop {String} placeholder - placeholder text shown in input + * @prop {Boolean} disabled - whether the input is disabled * * @fires input - on value change, event details contain {label: string, value: string} */ @@ -30,6 +31,8 @@ export class DatalistInput extends watchMixin(ShadowlessLitElement) { value: string; @property({ type: String }) placeholder: string; + @property({ type: Boolean }) + disabled = false; inputRef: Ref = createRef(); @@ -191,9 +194,10 @@ export class DatalistInput extends watchMixin(ShadowlessLitElement) { placeholder="${this.placeholder}" @keydown=${e => this.keydown(e)} @focus=${() => this.requestUpdate()} + .disabled="${this.disabled}" >