Skip to content

Commit

Permalink
SAK-50010 rubrics Update comment textarea on switching criterion (sak…
Browse files Browse the repository at this point in the history
  • Loading branch information
adrianfish authored Jul 17, 2024
1 parent d3ca978 commit efbf463
Show file tree
Hide file tree
Showing 5 changed files with 132 additions and 144 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -476,6 +476,10 @@ sakai-rubric-student-comment {
background-color: unset;
}
}

div.rubric-comment-body {
min-width: 180px;
}
}

.rubric-criterion-comment-title {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -173,17 +173,13 @@ export class SakaiGrader extends graderRenderingMixin(gradableDataMixin(SakaiEle

document.getElementById("grader").addEventListener("hide.bs.offcanvas", e => {

this.querySelector("sakai-rubric-grading")?.closeCommentEditors();

if (this.modified || this.querySelector("sakai-grader-file-picker")?.hasFiles()) {
e.preventDefault();
this._save({ closeSidebarTimeout: 2000 });
}
});

document.getElementById("grader").addEventListener("hide.bs.offcanvas", () => {

this.querySelectorAll(".rubric-comment-trigger").forEach(trigger => {
bootstrap.Popover.getInstance(trigger).hide();
});
});

document.getElementById("grader").addEventListener("hidden.bs.offcanvas", () => {
Expand Down Expand Up @@ -237,17 +233,13 @@ export class SakaiGrader extends graderRenderingMixin(gradableDataMixin(SakaiEle

this._rubricShowing = false;
this.querySelector("sakai-rubric-grading")?.displayGradingTab();
}

_doneWithRubric() {
this.updateComplete.then(() => {

this.querySelector("#grader-rubric-link").focus();

this.querySelector("sakai-rubric-grading-button").setHasEvaluation();
this.querySelector("sakai-rubric-evaluation-remover").setHasEvaluation();
this.requestUpdate();

this._closeRubric();
this.querySelector("#grader-rubric-link").focus();
this.querySelector("sakai-rubric-grading-button").setHasEvaluation();
this.querySelector("sakai-rubric-evaluation-remover").setHasEvaluation();
});
}

_replaceWithEditor(id, changedCallback) {
Expand All @@ -259,7 +251,7 @@ export class SakaiGrader extends graderRenderingMixin(gradableDataMixin(SakaiEle

editor.on("change", e => {

changedCallback && changedCallback(e.editor.getData());
changedCallback?.(e.editor.getData());
this.modified = true;
});

Expand Down Expand Up @@ -640,7 +632,7 @@ export class SakaiGrader extends graderRenderingMixin(gradableDataMixin(SakaiEle
filtered = filtered.filter(s => s.graded);
}

if (this.currentGroups && this.currentGroups.length === 1 && this.currentGroups[0].includes("/group")) {
if (this.currentGroups?.length === 1 && this.currentGroups[0].includes("/group")) {
const group = this.groups.find(g => g.reference === this.currentGroups[0]);
filtered = filtered.filter(s => group.users.includes(s.firstSubmitterId));
}
Expand Down Expand Up @@ -671,7 +663,7 @@ export class SakaiGrader extends graderRenderingMixin(gradableDataMixin(SakaiEle
}

_areSettingsInAction() {
return (this.currentGroups && this.currentGroups.length > 0 && this.currentGroups[0] !== `/site/${portal.siteId}`) || this._submittedOnly || this._ungradedOnly || this._gradedOnly;
return (this.currentGroups?.length > 0 && this.currentGroups[0] !== `/site/${portal.siteId}`) || this._submittedOnly || this._ungradedOnly || this._gradedOnly;
}

_getSubmitter(submission) {
Expand Down Expand Up @@ -758,7 +750,7 @@ export class SakaiGrader extends graderRenderingMixin(gradableDataMixin(SakaiEle
if (!confirm(this.i18n.confirm_remove_private_notes)) return false;

this._submission.privateNotes = "";
this.privateNotesEditor && this.privateNotesEditor.setData("");
this.privateNotesEditor?.setData("");
this.modified = true;
this._gradeOrCommentsModified = true;
this._privateNotesRemoved = true;
Expand All @@ -769,7 +761,7 @@ export class SakaiGrader extends graderRenderingMixin(gradableDataMixin(SakaiEle
if (!confirm(this.i18n.confirm_remove_feedback_comment)) return false;

this._submission.feedbackComment = "";
this.feedbackCommentEditor && this.feedbackCommentEditor.setData("");
this.feedbackCommentEditor?.setData("");
this.modified = true;
this._gradeOrCommentsModified = true;
this._feedbackCommentRemoved = true;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -401,41 +401,43 @@ export const graderRenderingMixin = Base => class extends Base {
${this._renderGradeInputs(this.i18n["gen.assign.gra"])}
<!-- start hasAssociatedRubric -->
${this.hasAssociatedRubric === "true" ? html`
<div class="d-flex align-items-center mt-3">
<div>
<button id="grader-rubric-button"
class="btn btn-link"
@click=${this._toggleRubric}
aria-label="${this.i18n.grading_rubric}"
title="${this.i18n.grading_rubric}"
aria-controls="grader-rubric-block grader-controls-block">
${this.i18n.rubric}
</button>
</div>
<div>
<sakai-rubric-grading-button
id="grader-rubric-link"
aria-label="${this.i18n.grading_rubric}"
title="${this.i18n.grading_rubric}"
@click=${this._toggleRubric}
site-id="${portal.siteId}"
tool-id="${this.toolId}"
entity-id="${this.entityId}"
evaluated-item-id="${this._submission.id}"
aria-controls="grader-rubric-block grader-controls-block"
only-show-if-evaluated>
</sakai-rubric-grading-button>
<sakai-rubric-evaluation-remover
class="ms-2"
site-id="${portal.siteId}"
tool-id="${this.toolId}"
entity-id="${this.entityId}"
evaluated-item-id="${this._submission.id}"
@evaluation-removed=${this._onEvaluationRemoved}
only-show-if-evaluated>
</sakai-rubric-evaluation-remover>
${!this._rubricShowing ? html`
<div class="d-flex align-items-center mt-3">
<div>
<button id="grader-rubric-button"
class="btn btn-link"
@click=${this._toggleRubric}
aria-label="${this.i18n.grading_rubric}"
title="${this.i18n.grading_rubric}"
aria-controls="grader-rubric-block grader-controls-block">
${this.i18n.rubric}
</button>
</div>
<div>
<sakai-rubric-grading-button
id="grader-rubric-link"
aria-label="${this.i18n.grading_rubric}"
title="${this.i18n.grading_rubric}"
@click=${this._toggleRubric}
site-id="${portal.siteId}"
tool-id="${this.toolId}"
entity-id="${this.entityId}"
evaluated-item-id="${this._submission.id}"
aria-controls="grader-rubric-block grader-controls-block"
only-show-if-evaluated>
</sakai-rubric-grading-button>
<sakai-rubric-evaluation-remover
class="ms-2"
site-id="${portal.siteId}"
tool-id="${this.toolId}"
entity-id="${this.entityId}"
evaluated-item-id="${this._submission.id}"
@evaluation-removed=${this._onEvaluationRemoved}
only-show-if-evaluated>
</sakai-rubric-evaluation-remover>
</div>
</div>
</div>
` : nothing}
<div id="grader-rubric-block" class="ms-2 ${this._rubricShowing ? "d-block" : "d-none"}">
<sakai-rubric-grading
Expand All @@ -455,7 +457,7 @@ export const graderRenderingMixin = Base => class extends Base {
<button class="btn btn-primary"
title="${this.i18n.rubric_done_tooltip}"
aria-label="${this.i18n.rubric_done_tooltip}"
@click=${this._doneWithRubric}>
@click=${this._closeRubric}>
${this.i18n["gen.don"]}
</button>
</div>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,10 @@ export class SakaiRubricGrading extends rubricsApiMixin(RubricsElement) {
}
}

closeCommentEditors() {
this.querySelectorAll("sakai-rubric-grading-comment").forEach(c => c.hideEditor());
}

shouldUpdate() {
return this._i18n && this.association;
}
Expand Down Expand Up @@ -114,12 +118,12 @@ export class SakaiRubricGrading extends rubricsApiMixin(RubricsElement) {
<option value="${CRITERIA_SUMMARY}">${this._i18n.criteria_summary}</option>
</select>
<div id="rubric-grading-or-preview-${this.instanceSalt}" class="rubric-tab-content rubrics-visible mt-2">
<div id="rubric-grading-or-preview-${this.instanceSalt}" class="rubric-tab-content rubrics-visible mt-1">
${this._evaluation && this._evaluation.status === "DRAFT" && !this.isPeerOrSelf ? html`
<div class="sak-banner-warn">
${this.tr("draft_evaluation", [ this.tr(`draft_evaluation_${this.toolId}`) ])}
</div>
` : nothing }
` : nothing }
<div class="criterion grading style-scope sakai-rubric-criteria-grading">
${this._criteria.map(c => html`
<div id="criterion_row_${c.id}" class="criterion-row">
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,109 +17,95 @@ export class SakaiRubricGradingComment extends RubricsElement {
this.randombit = Math.floor(Math.random() * 15001);
}


set criterion(newValue) {

const oldValue = this._criterion;
this._criterion = newValue;
this._criterion.comments = newValue.comments && newValue.comments.indexOf("null") === 0 ? "" : newValue.comments;
this.requestUpdate("criterion", oldValue);
hideEditor() {
bootstrap.Dropdown.getOrCreateInstance(this.querySelector(".dropdown-menu"))?.hide();
}

get criterion() { return this._criterion; }
_setupEditor() {

firstUpdated() {
const editorOptions = {
startupFocus: true,
versionCheck: false,
removePlugins: "wordcount",
height: 60,
};

this.setupEditor();
if (sakai && sakai.editor) {
editorOptions.toolbarSet = "BasicText";
} else {
editorOptions.toolbar = [ [ "Bold", "Italic", "Underline" ] ];
}

const trigger = this.querySelector("button.rubric-comment-trigger");
const popover = this.querySelector("div.rubric-comment-popover");
const editorKey = `criterion-${this.criterion.id}-${this.evaluatedItemId}-comment-${this.randombit}`;
const editorFunction = sakai && sakai.editor ? sakai.editor.launch : CKEDITOR.replace;
this._commentEditor = editorFunction(editorKey, editorOptions);

this._commentEditor.focus();

this._commentEditor.on("blur", () => {

// When we click away from the comment editor we need to save the comment, but only if the comment has been updated
if (this._commentEditor.checkDirty()) {
this.criterion.comments = this._commentEditor.getData();
const updateEvent = new CustomEvent("update-comment", {
detail: {
evaluatedItemId: this.evaluatedItemId,
entityId: this.entityId,
criterionId: this.criterion.id,
value: this.criterion.comments
},
bubbles: true, composed: true });
this.dispatchEvent(updateEvent);
this.requestUpdate();
}

this.hideEditor();
});
}

trigger.addEventListener("show.bs.popover", () => popover.classList.remove("d-none"));
_updateEditor() {

new bootstrap.Popover(trigger, {
content: popover,
html: true,
this._commentEditor?.setData(this.criterion.comments, () => {
this._commentEditor.updateElement();
this._commentEditor.resetDirty();
});
}

firstUpdated() { this._setupEditor(); }

updated() { this._updateEditor(); }

render() {

return html`
<button type="button"
class="btn icon-button rubric-comment-trigger"
@click=${this.toggleEditor}>
<i class="bi bi-chat${this.criterion.comments ? "-fill" : ""} ${this.criterion.comments ? "active" : ""}"></i>
</button>
<div class="rubric-comment-popover d-none">
<div class="fw-bold rubric-criterion-comment-title">${this.tr("comment_for_criterion", [ this.criterion.title ])}</div>
<div>
<textarea
<div class="dropdown">
<button class="btn btn-icon"
type="button"
data-bs-toggle="dropdown"
data-bs-auto-close="false"
aria-label="${this._i18n.criterion_comment}"
class="form-control"
name="rbcs-${this.evaluatedItemId}-${this.entityId}-criterion-comment-${this.criterion.id}"
.value=${this.criterion.comments === undefined ? null : this.criterion.comments}
id="criterion-${this.criterion.id}-${this.evaluatedItemId}-comment-${this.randombit}">
</textarea>
</div>
<div class="buttons act float-end">
<button class="active btn-xs done" @click="${this.hideTooltip}">${this._i18n.done}</button>
aria-expanded="false">
<i class="bi bi-chat${this.criterion.comments ? "-fill" : ""} ${this.criterion.comments ? "active" : ""}"></i>
</button>
<div class="rubric-comment-dropdown dropdown-menu">
<div class="m-2 rubric-comment-body">
<div class="fw-bold rubric-criterion-comment-title">${this.tr("comment_for_criterion", [ this.criterion.title ])}</div>
<div>
<textarea
aria-label="${this._i18n.criterion_comment}"
class="form-control"
name="rbcs-${this.evaluatedItemId}-${this.entityId}-criterion-comment-${this.criterion.id}"
.value=${this.criterion.comments === undefined ? null : this.criterion.comments}
id="criterion-${this.criterion.id}-${this.evaluatedItemId}-comment-${this.randombit}">
</textarea>
</div>
<div class="buttons act float-end">
<button type="button" class="active btn-xs" @click=${this.hideEditor}>${this._i18n.done}</button>
</div>
</div>
</div>
</div>
`;
}

hideTooltip() {
bootstrap.Popover.getInstance(this.querySelector("button.rubric-comment-trigger"))?.hide();
}

setupEditor() {

const editorKey = `criterion-${this.criterion.id}-${this.evaluatedItemId}-comment-${this.randombit}`;
const editorOptions = {
startupFocus: true,
versionCheck: false,
removePlugins: "wordcount",
height: 60,
};
let editorFunction;
if (sakai && sakai.editor) {
editorOptions.toolbarSet = "BasicText";
editorFunction = sakai.editor.launch;
} else {
editorOptions.toolbar = [ [ "Bold", "Italic", "Underline" ] ] ;
editorFunction = CKEDITOR.replace;
}

try {
const commentEditor = editorFunction(editorKey, editorOptions);

commentEditor.focus();

commentEditor.on("blur", () => {

// When we click away from the comment editor we need to save the comment, but only if the comment has been updated
const updatedComments = commentEditor.getData();
const nonEmptyComment = this.criterion.comments !== undefined || updatedComments.trim().length > 0;
if (this.criterion.comments !== updatedComments && nonEmptyComment) {
this.criterion.comments = updatedComments;
const updateEvent = new CustomEvent("update-comment", {
detail: {
evaluatedItemId: this.evaluatedItemId,
entityId: this.entityId,
criterionId: this.criterion.id,
value: this.criterion.comments
},
bubbles: true, composed: true });
this.dispatchEvent(updateEvent);
this.requestUpdate();
}

this.hideTooltip();
});
} catch (error) {
console.error(error);
}
}
}

0 comments on commit efbf463

Please sign in to comment.