Enforces comments in a specific format when documents are edited.
- Tags
- Identifier
de.smartics.userscripts.confluence.force-comment
- Type
- Repository
- Since
- 1.0
The script checks in the Confluence page editor whether or not the comment adheres to the required format. If not the page cannot be saved.
If the change is either a feature or a fix, then the watchers of the page will be notified.
Code
The code of the script for reference.
/*
* Copyright 2019-2024 Kronseder & Reiner GmbH, smartics
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
"use strict";
AJS.toInit(function () {
const logToConsole = false;
const commentPrefixes = ["change: ", "feat: ", "fix: ", "refactor: ", "style: ", "chore: "];
const notificationRequiredIndex = 2;
if (logToConsole) {
AJS.log("[force-comment] Force comment with: " + commentPrefixes);
}
const isValidComment = function (comment) {
if (comment) {
for (let i = 0; i < commentPrefixes.length; i++) {
const commentPrefix = commentPrefixes[i];
if (comment.startsWith(commentPrefix) &&
comment.length > commentPrefix.length) {
return true;
}
}
}
return false;
};
const requiresNotification = function (comment) {
if (comment) {
for (let i = 0; i <= notificationRequiredIndex; i++) {
const commentPrefix = commentPrefixes[i];
if (comment.startsWith(commentPrefix)) {
return true;
}
}
}
return false;
};
const updateNotification = function (comment) {
const $notify = AJS.$('#notifyWatchers');
if (requiresNotification(comment)) {
$notify.prop('checked', true);
} else {
$notify.prop('checked', false);
}
};
const monitorPublishButtonStatus = function () {
const comment = AJS.$('#versionComment').val();
if (logToConsole) AJS.log("[force-comment] Checking comment: " + comment);
const currentStatus = AJS.$('#rte-button-publish').prop('disabled');
if (!isValidComment(comment)) {
if (logToConsole) AJS.log("[force-comment] Comment '" + comment + "' is not valid, therefore disabling publish button.");
if (!currentStatus) {
AJS.$('#rte-button-publish').prop('disabled', true);
updateNotification(comment);
}
} else {
if (logToConsole) AJS.log("[force-comment] Comment '" + comment + "' is valid, therefore enabling publish button.");
if (currentStatus) {
AJS.$('#rte-button-publish').prop('disabled', false);
updateNotification(comment);
}
}
};
const createHelpDialog = function ($element) {
if (AJS.$("#userscripts-commitMessages-helpDialog-show-button").length) {
return;
}
const button = AJS.$("<button id=\"userscripts-commitMessages-helpDialog-show-button\" class=\"aui-button toolbar-item\" style=\"margin-right: 10px;\"><span class=\"aui-icon aui-icon-small aui-iconfont-question-filled\">Help on Commit Message Format</span></button>\n");
$element.before(button);
AJS.$("#userscripts-commitMessages-helpDialog-show-button").on('click', function (e) {
e.preventDefault();
const dialog = AJS.$("<section\n" +
" id=\"userscripts-commitMessages-helpDialog\"\n" +
" class=\"aui-dialog2 aui-dialog2-medium aui-layer\"\n" +
" role=\"dialog\"\n" +
" tabindex=\"-1\"\n" +
" data-aui-modal=\"false\"" +
" data-aui-remove-on-hide=\"true\"" +
" aria-labelledby=\"userscripts-commitMessages-helpDialog-show-button--heading\"\n" +
" hidden\n" +
">\n" +
" <header class=\"aui-dialog2-header\">\n" +
" <h1 class=\"aui-dialog2-header-main\" id=\"userscripts-commitMessages-helpDialog-show-button--heading\">Help: Commit message format</h1>\n" +
" </header>\n" +
" <div class=\"aui-dialog2-content\">\n" +
" <p>Use the following format for your commit messages.</p>\n" +
"<table class=\"aui\">\n" +
" <thead>\n" +
" <tr>\n" +
" <th id=\"type\">Type</th>\n" +
" <th id=\"description\">Description</th>\n" +
" <th id=\"notify\" style=\"text-align:center;\">Notify</th>\n" +
" <th id=\"example\">Example</th>\n" +
" </tr>\n" +
" </thead>\n" +
" <tbody>\n" +
" <tr>\n" +
" <td headers=\"type\" style=\"font-weight: bold;\">Change</td>\n" +
" <td headers=\"description\">Alters or removes an existing feature.</td>\n" +
" <td headers=\"notify\" style=\"text-align:center;\">\n<span class=\"aui-icon aui-icon-small aui-iconfont-approve\">Checks the 'Notify watchers' checkbox</span></td>\n" +
" <td headers=\"example\">\n" +
" <code>change: Replace response code format.</code>\n" +
" </td>\n" +
" </tr>\n" +
" <tr>\n" +
" <td headers=\"type\" style=\"font-weight: bold;\">Feature</td>\n" +
" <td headers=\"description\">Adds essential new information.</td>\n" +
" <td headers=\"notify\" style=\"text-align:center;\">\n<span class=\"aui-icon aui-icon-small aui-iconfont-approve\">Checks the 'Notify watchers' checkbox</span></td>\n" +
" <td headers=\"example\">\n" +
" <code>feat: Add section on error handling.</code>\n" +
" </td>\n" +
" </tr>\n" +
" <tr>\n" +
" <td headers=\"type\" style=\"font-weight: bold;\">Fix</td>\n" +
" <td headers=\"description\">Fixes an issue or false information.</td>\n" +
" <td headers=\"notify\" style=\"text-align:center;\">\n<span class=\"aui-icon aui-icon-small aui-iconfont-approve\">Checks the 'Notify watchers' checkbox</span></td>\n" +
" <td headers=\"example\">\n" +
" <code>fix: Clarify section on user administration which is misleading.</code>\n" +
" </td>\n" +
" </tr>\n" +
" <tr>\n" +
" <td headers=\"type\" style=\"font-weight: bold;\">Refactor</td>\n" +
" <td headers=\"description\">Reorganize sections or rename elements.</td>\n" +
" <td headers=\"notify\" style=\"text-align:center;\">\n<span class=\"aui-icon aui-icon-small aui-iconfont-cross-circle\">Unchecks the 'Notify watchers' checkbox</span></td>\n" +
" <td headers=\"example\">\n" +
" <code>refactor: Split administration section into three subsections.</code>\n" +
" </td>\n" +
" </tr>\n" +
" <tr>\n" +
" <td headers=\"type\" style=\"font-weight: bold;\">Style</td>\n" +
" <td headers=\"description\">Change the wording, remove typos, or fix grammar.</td>\n" +
" <td headers=\"notify\" style=\"text-align:center;\">\n<span class=\"aui-icon aui-icon-small aui-iconfont-cross-circle\">Unchecks the 'Notify watchers' checkbox</span></td>\n" +
" <td headers=\"example\">\n" +
" <code>style: Replace with active voice to address the reader.</code>\n" +
" </td>\n" +
" </tr>\n" +
" <tr>\n" +
" <td headers=\"type\" style=\"font-weight: bold;\">Chore</td>\n" +
" <td headers=\"description\">Necessary adjustments without regards to content.</td>\n" +
" <td headers=\"notify\" style=\"text-align:center;\">\n<span class=\"aui-icon aui-icon-small aui-iconfont-cross-circle\">Unchecks the 'Notify watchers' checkbox</span></td>\n" +
" <td headers=\"example\">\n" +
" <code>chore: Update icon to higher resolution.</code>\n" +
" </td>\n" +
" </tr>\n" +
" </tbody>\n" +
"</table>" +
" </div>\n" +
" <footer class=\"aui-dialog2-footer\">\n" +
" <div class=\"aui-dialog2-footer-actions\">\n" +
" <button id=\"userscripts-commitMessages-helpDialog-submit-button\" class=\"aui-button aui-button-primary\">Okay</button>\n" +
" </div>\n" +
" </footer>\n" +
"</section>");
$element.before(dialog);
AJS.$("#userscripts-commitMessages-helpDialog-submit-button").on('click', function (e) {
e.preventDefault();
AJS.dialog2("#userscripts-commitMessages-helpDialog").hide();
});
AJS.dialog2("#userscripts-commitMessages-helpDialog").show();
});
};
AJS.$(function () {
if (logToConsole) {
AJS.log("[force-comment] Analysing page elements: " + commentPrefixes);
}
const $versionComment = AJS.$('#versionComment');
if ($versionComment.length) {
createHelpDialog($versionComment);
const $publishButton = AJS.$('#rte-button-publish');
const $notify = AJS.$('#notifyWatchers');
if ($publishButton.length && $notify.length) {
$versionComment.bind("input change", function () {
const comment = $versionComment.val();
if (isValidComment(comment)) {
$publishButton.prop('disabled', false);
updateNotification(comment);
} else {
$publishButton.prop('disabled', true);
}
});
USERSCRIPT4C_SYNC.monitorPage(monitorPublishButtonStatus, AJS.$("#savebar-container"));
const comment = $versionComment.val();
if (!isValidComment(comment)) {
$publishButton.prop('disabled', true);
}
}
}
});
});
Details
Describing the use case for this script. First the use case for the author then for the userscripts administrator.
Commenting Changes
When opening a page where this script enforces the format of a comment, the Save button will be deactivated per default.
Users who do not know how to work with comments, may click the Help button ().
Entering a valid comment will activate the Save button.
If the comment does not meet the constraints, then the page cannot be saved.
If the comment is indicating a new feature, then the checkbox for Notify watchers will be checked.
Configuration of Userscript
Typically there is no need to enforce specific comments for each and every change for a page on a Confluence server. Typically versioned documents are located in a specific space. To activate the script for spaces with versioned documents, the userscripts administrator may define a space category, like versioned
, to be set.
Configure the space category via the Space Tools.
Once the categories contain a category 'versioned
', as specified in the activation record via activation-space-categories
, the space will enforce the comment on every document.