aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.eslintignore2
-rw-r--r--.eslintrc6
-rw-r--r--package-lock.json136
-rw-r--r--package.json4
-rw-r--r--src/main/assets/scripts.js54
5 files changed, 175 insertions, 27 deletions
diff --git a/.eslintignore b/.eslintignore
new file mode 100644
index 00000000..e6ddcb62
--- /dev/null
+++ b/.eslintignore
@@ -0,0 +1,2 @@
+src/main/resources/static/scripts.js
+target/**
diff --git a/.eslintrc b/.eslintrc
index e1b73925..2eacc84c 100644
--- a/.eslintrc
+++ b/.eslintrc
@@ -2,7 +2,8 @@
// Extend existing configuration
// from ESlint and eslint-plugin-react defaults.
"extends": [
- "eslint:recommended"
+ "eslint:recommended",
+ "plugin:jsdoc/recommended"
//, "plugin:react/recommended"
],
// Enable ES6 support. If you want to use custom Babel
@@ -19,7 +20,8 @@
// Enable custom plugin known as eslint-plugin-react
"plugins": [
// "react"
- "only-ascii"
+ "only-ascii",
+ "jsdoc"
],
// http://eslint.org/docs/rules/
"rules": {
diff --git a/package-lock.json b/package-lock.json
index 15e09798..5d1bb662 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -27,6 +27,7 @@
"cross-env": "^7.0.3",
"cssnano": "^5.1.10",
"eslint": "8.16.0",
+ "eslint-plugin-jsdoc": "^39.3.2",
"eslint-plugin-only-ascii": "0.0.0",
"eslint-webpack-plugin": "^3.1.1",
"file-loader": "^6.2.0",
@@ -1887,6 +1888,20 @@
"node": ">=10.0.0"
}
},
+ "node_modules/@es-joy/jsdoccomment": {
+ "version": "0.31.0",
+ "resolved": "https://registry.npmjs.org/@es-joy/jsdoccomment/-/jsdoccomment-0.31.0.tgz",
+ "integrity": "sha512-tc1/iuQcnaiSIUVad72PBierDFpsxdUHtEF/OrfqvM1CBAsIoMP51j52jTMb3dXriwhieTo289InzZj72jL3EQ==",
+ "dev": true,
+ "dependencies": {
+ "comment-parser": "1.3.1",
+ "esquery": "^1.4.0",
+ "jsdoc-type-pratt-parser": "~3.1.0"
+ },
+ "engines": {
+ "node": "^14 || ^16 || ^17 || ^18"
+ }
+ },
"node_modules/@eslint/eslintrc": {
"version": "1.3.0",
"resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-1.3.0.tgz",
@@ -2842,6 +2857,15 @@
"integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==",
"dev": true
},
+ "node_modules/comment-parser": {
+ "version": "1.3.1",
+ "resolved": "https://registry.npmjs.org/comment-parser/-/comment-parser-1.3.1.tgz",
+ "integrity": "sha512-B52sN2VNghyq5ofvUsqZjmk6YkihBX5vMSChmSK9v4ShjKf3Vk5Xcmgpw4o+iIgtrnM/u5FiMpz9VKb8lpBveA==",
+ "dev": true,
+ "engines": {
+ "node": ">= 12.0.0"
+ }
+ },
"node_modules/commondir": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/commondir/-/commondir-1.0.1.tgz",
@@ -3715,6 +3739,54 @@
"url": "https://opencollective.com/eslint"
}
},
+ "node_modules/eslint-plugin-jsdoc": {
+ "version": "39.3.2",
+ "resolved": "https://registry.npmjs.org/eslint-plugin-jsdoc/-/eslint-plugin-jsdoc-39.3.2.tgz",
+ "integrity": "sha512-RSGN94RYzIJS/WfW3l6cXzRLfJWxvJgNQZ4w0WCaxJWDJMigtwTsILEAfKqmmPkT2rwMH/s3C7G5ChDE6cwPJg==",
+ "dev": true,
+ "dependencies": {
+ "@es-joy/jsdoccomment": "~0.31.0",
+ "comment-parser": "1.3.1",
+ "debug": "^4.3.4",
+ "escape-string-regexp": "^4.0.0",
+ "esquery": "^1.4.0",
+ "semver": "^7.3.7",
+ "spdx-expression-parse": "^3.0.1"
+ },
+ "engines": {
+ "node": "^14 || ^16 || ^17 || ^18"
+ },
+ "peerDependencies": {
+ "eslint": "^7.0.0 || ^8.0.0"
+ }
+ },
+ "node_modules/eslint-plugin-jsdoc/node_modules/escape-string-regexp": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz",
+ "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==",
+ "dev": true,
+ "engines": {
+ "node": ">=10"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/eslint-plugin-jsdoc/node_modules/semver": {
+ "version": "7.3.7",
+ "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.7.tgz",
+ "integrity": "sha512-QlYTucUYOews+WeEujDoEGziz4K6c47V/Bd+LjSSYcA94p+DmINdf7ncaUinThfvZyu13lN9OY1XDxt8C0Tw0g==",
+ "dev": true,
+ "dependencies": {
+ "lru-cache": "^6.0.0"
+ },
+ "bin": {
+ "semver": "bin/semver.js"
+ },
+ "engines": {
+ "node": ">=10"
+ }
+ },
"node_modules/eslint-plugin-only-ascii": {
"version": "0.0.0",
"resolved": "https://registry.npmjs.org/eslint-plugin-only-ascii/-/eslint-plugin-only-ascii-0.0.0.tgz",
@@ -4921,6 +4993,15 @@
"js-yaml": "bin/js-yaml.js"
}
},
+ "node_modules/jsdoc-type-pratt-parser": {
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/jsdoc-type-pratt-parser/-/jsdoc-type-pratt-parser-3.1.0.tgz",
+ "integrity": "sha512-MgtD0ZiCDk9B+eI73BextfRrVQl0oyzRG8B2BjORts6jbunj4ScKPcyXGTbB6eXL4y9TzxCm6hyeLq/2ASzNdw==",
+ "dev": true,
+ "engines": {
+ "node": ">=12.0.0"
+ }
+ },
"node_modules/jsesc": {
"version": "2.5.2",
"resolved": "https://registry.npmjs.org/jsesc/-/jsesc-2.5.2.tgz",
@@ -9507,6 +9588,17 @@
"integrity": "sha512-6nFkfkmSeV/rqSaS4oWHgmpnYw194f6hmWF5is6b0J1naJZoiD0NTc9AiUwPHvWsowkjuHErCZT1wa0jg+BLIA==",
"dev": true
},
+ "@es-joy/jsdoccomment": {
+ "version": "0.31.0",
+ "resolved": "https://registry.npmjs.org/@es-joy/jsdoccomment/-/jsdoccomment-0.31.0.tgz",
+ "integrity": "sha512-tc1/iuQcnaiSIUVad72PBierDFpsxdUHtEF/OrfqvM1CBAsIoMP51j52jTMb3dXriwhieTo289InzZj72jL3EQ==",
+ "dev": true,
+ "requires": {
+ "comment-parser": "1.3.1",
+ "esquery": "^1.4.0",
+ "jsdoc-type-pratt-parser": "~3.1.0"
+ }
+ },
"@eslint/eslintrc": {
"version": "1.3.0",
"resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-1.3.0.tgz",
@@ -10265,6 +10357,12 @@
"integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==",
"dev": true
},
+ "comment-parser": {
+ "version": "1.3.1",
+ "resolved": "https://registry.npmjs.org/comment-parser/-/comment-parser-1.3.1.tgz",
+ "integrity": "sha512-B52sN2VNghyq5ofvUsqZjmk6YkihBX5vMSChmSK9v4ShjKf3Vk5Xcmgpw4o+iIgtrnM/u5FiMpz9VKb8lpBveA==",
+ "dev": true
+ },
"commondir": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/commondir/-/commondir-1.0.1.tgz",
@@ -10976,6 +11074,38 @@
}
}
},
+ "eslint-plugin-jsdoc": {
+ "version": "39.3.2",
+ "resolved": "https://registry.npmjs.org/eslint-plugin-jsdoc/-/eslint-plugin-jsdoc-39.3.2.tgz",
+ "integrity": "sha512-RSGN94RYzIJS/WfW3l6cXzRLfJWxvJgNQZ4w0WCaxJWDJMigtwTsILEAfKqmmPkT2rwMH/s3C7G5ChDE6cwPJg==",
+ "dev": true,
+ "requires": {
+ "@es-joy/jsdoccomment": "~0.31.0",
+ "comment-parser": "1.3.1",
+ "debug": "^4.3.4",
+ "escape-string-regexp": "^4.0.0",
+ "esquery": "^1.4.0",
+ "semver": "^7.3.7",
+ "spdx-expression-parse": "^3.0.1"
+ },
+ "dependencies": {
+ "escape-string-regexp": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz",
+ "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==",
+ "dev": true
+ },
+ "semver": {
+ "version": "7.3.7",
+ "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.7.tgz",
+ "integrity": "sha512-QlYTucUYOews+WeEujDoEGziz4K6c47V/Bd+LjSSYcA94p+DmINdf7ncaUinThfvZyu13lN9OY1XDxt8C0Tw0g==",
+ "dev": true,
+ "requires": {
+ "lru-cache": "^6.0.0"
+ }
+ }
+ }
+ },
"eslint-plugin-only-ascii": {
"version": "0.0.0",
"resolved": "https://registry.npmjs.org/eslint-plugin-only-ascii/-/eslint-plugin-only-ascii-0.0.0.tgz",
@@ -11743,6 +11873,12 @@
"argparse": "^2.0.1"
}
},
+ "jsdoc-type-pratt-parser": {
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/jsdoc-type-pratt-parser/-/jsdoc-type-pratt-parser-3.1.0.tgz",
+ "integrity": "sha512-MgtD0ZiCDk9B+eI73BextfRrVQl0oyzRG8B2BjORts6jbunj4ScKPcyXGTbB6eXL4y9TzxCm6hyeLq/2ASzNdw==",
+ "dev": true
+ },
"jsesc": {
"version": "2.5.2",
"resolved": "https://registry.npmjs.org/jsesc/-/jsesc-2.5.2.tgz",
diff --git a/package.json b/package.json
index cb36149a..d482af96 100644
--- a/package.json
+++ b/package.json
@@ -6,7 +6,8 @@
"test": "echo \"Error: no test specified\" && exit 1",
"compile:css": "postcss --verbose --map style.css.map src/main/assets/style.css -d src/main/resources/static/",
"compile:js": "webpack",
- "compile": "cross-env NODE_ENV=production concurrently \"npm run compile:css\" \"npm run compile:js\""
+ "compile": "cross-env NODE_ENV=production concurrently \"npm run compile:css\" \"npm run compile:js\"",
+ "lint": "eslint ."
},
"repository": {
"type": "git",
@@ -38,6 +39,7 @@
"cross-env": "^7.0.3",
"cssnano": "^5.1.10",
"eslint": "8.16.0",
+ "eslint-plugin-jsdoc": "^39.3.2",
"eslint-plugin-only-ascii": "0.0.0",
"eslint-webpack-plugin": "^3.1.1",
"file-loader": "^6.2.0",
diff --git a/src/main/assets/scripts.js b/src/main/assets/scripts.js
index d5ceb86e..87fdf7a4 100644
--- a/src/main/assets/scripts.js
+++ b/src/main/assets/scripts.js
@@ -9,13 +9,14 @@ import svg4everybody from 'svg4everybody';
/**
* Autosize textarea
+ *
* @param {HTMLTextAreaElement} el textarea element
*/
function autosize(el) {
let offset = el.offsetHeight - el.clientHeight;
el.addEventListener('input', (ev) => {
- const textarea = /** @type HTMLTextAreaElement */ (ev.target);
+ const textarea = /** @type {HTMLTextAreaElement} */ (ev.target);
textarea.style.height = 'auto';
textarea.style.height = (textarea.scrollHeight + offset) + 'px';
});
@@ -23,8 +24,9 @@ function autosize(el) {
/**
* Display an icon from the evil-icons set
+ *
* @param {string} name Icon name from the iconset
- * @returns HTML markup for the selected icon
+ * @returns {string} HTML markup for the selected icon
*/
function evilIcon(name) {
return `<div class="icon icon--${name}"><svg class="icon__cnt"><use xmlns:xlink="http://www.w3.org/1999/xlink" xlink:href="/sprite.svg#${name}-icon"></use></svg></div>`;
@@ -87,6 +89,7 @@ const translations = {
/**
* Detect window language
+ *
* @returns {string} Detected language
*/
function getLang() {
@@ -223,6 +226,7 @@ function updateRepliesCounter() {
/**
* Submit form on Ctrl+Enter
+ *
* @param {HTMLElement} formEl Target form element
* @param {KeyboardEvent} ev Keyboard event
*/
@@ -230,17 +234,18 @@ function postformListener(formEl, ev) {
if (ev.ctrlKey && (ev.keyCode == 10 || ev.keyCode == 13)) {
let form = formEl.closest('form');
if (!form.onsubmit || form.submit()) {
- /** @type HTMLInputElement */ (form.querySelector('input[type="submit"]')).click();
+ /** @type {HTMLInputElement} */ (form.querySelector('input[type="submit"]')).click();
}
}
}
/**
* Close dialog on Esc
+ *
* @param {KeyboardEvent} ev Keyboard event
*/
function closeDialogListener(ev) {
- ev = ev || /** @type KeyboardEvent */ (window.event);
+ ev = ev || /** @type {KeyboardEvent} */ (window.event);
if (ev.keyCode == 27) {
closeDialog();
}
@@ -273,13 +278,13 @@ function showCommentForm(mid, rid) {
formTarget.remove();
let form = reply.querySelector('form');
- let submitButton = /** @type HTMLInputElement */ (form.querySelector('input[type="submit"]'));
+ let submitButton = /** @type {HTMLInputElement} */ (form.querySelector('input[type="submit"]'));
let attachButton = form.querySelector('.msg-comment .attach-photo');
- attachButton.addEventListener('click', e => attachCommentPhoto(/** @type HTMLDivElement */ (e.target)));
+ attachButton.addEventListener('click', e => attachCommentPhoto(/** @type {HTMLDivElement} */ (e.target)));
- let textarea = /** @type HTMLTextAreaElement */ (form.querySelector('.msg-comment textarea'));
- textarea.addEventListener('keypress', e => postformListener(/** @type HTMLElement */ (e.target), e));
+ let textarea = /** @type {HTMLTextAreaElement} */ (form.querySelector('.msg-comment textarea'));
+ textarea.addEventListener('keypress', e => postformListener(/** @type {HTMLElement} */ (e.target), e));
autosize(textarea);
let validateMessage = () => {
@@ -318,7 +323,7 @@ function showCommentForm(mid, rid) {
e.preventDefault();
});
}
- /** @type HTMLTextAreaElement */ (reply.querySelector('.msg-comment textarea')).focus();
+ /** @type {HTMLTextAreaElement} */ (reply.querySelector('.msg-comment textarea')).focus();
}
function attachInput() {
@@ -332,6 +337,7 @@ function attachInput() {
/**
* "Attach" button
+ *
* @param {HTMLDivElement} div
*/
function attachCommentPhoto(div) {
@@ -395,7 +401,7 @@ function closeDialog() {
function checkUsername() {
var uname = document.querySelector('#username').textContent,
- style = /** @type HTMLElement */ (document.querySelector('#username')).style;
+ style = /** @type {HTMLElement} */ (document.querySelector('#username')).style;
fetch('/api/users?uname=' + uname)
.then(handleErrors)
.then(function() {
@@ -554,15 +560,15 @@ ready(() => {
e.target.removeEventListener('click', insertPMButtons);
e.preventDefault();
};
- /** @type HTMLTextAreaElement[] */ (Array.from(document.querySelectorAll('textarea.replypm'))).forEach(function(e) {
+ /** @type {HTMLTextAreaElement[]} */ (Array.from(document.querySelectorAll('textarea.replypm'))).forEach(function(e) {
e.addEventListener('click', insertPMButtons);
e.addEventListener('keypress', function(e) {
- postformListener(/** @type HTMLElement */ (e.target), e);
+ postformListener(/** @type {HTMLElement} */ (e.target), e);
});
});
- /** @type HTMLTextAreaElement[] */ (Array.from(document.querySelectorAll('#postmsg textarea'))).forEach(function(e) {
+ /** @type {HTMLTextAreaElement[]} */ (Array.from(document.querySelectorAll('#postmsg textarea'))).forEach(function(e) {
e.addEventListener('keypress', function(e) {
- postformListener(/** @type HTMLElement */ (e.target), e);
+ postformListener(/** @type {HTMLElement} */ (e.target), e);
});
});
@@ -581,10 +587,10 @@ ready(() => {
});
let opMessage = document.querySelector('.msgthread');
if (opMessage) {
- let replyTextarea = /** @type HTMLTextAreaElement */ (opMessage.querySelector('textarea.reply'));
+ let replyTextarea = /** @type {HTMLTextAreaElement} */ (opMessage.querySelector('textarea.reply'));
if (replyTextarea) {
replyTextarea.addEventListener('focus', e => showCommentForm(pageMID, 0));
- replyTextarea.addEventListener('keypress', e => postformListener(/** @type HTMLElement */ (e.target), e));
+ replyTextarea.addEventListener('keypress', e => postformListener(/** @type {HTMLElement} */ (e.target), e));
if (!window.location.hash) {
replyTextarea.focus();
}
@@ -593,7 +599,7 @@ ready(() => {
}
}
- var postmsg = /** @type HTMLFormElement */(document.getElementById('postmsg'));
+ var postmsg = /** @type {HTMLFormElement} */(document.getElementById('postmsg'));
if (postmsg) {
Array.from(document.querySelectorAll('a')).filter(t => t.href.indexOf('?') >= 0).forEach(t => {
t.addEventListener('click', e => {
@@ -629,7 +635,7 @@ ready(() => {
e.preventDefault();
});
}
- /** @type HTMLFormElement[] */ (Array.from(document.querySelectorAll('.pmmsg'))).forEach(pmmsg => {
+ /** @type {HTMLFormElement[]} */ (Array.from(document.querySelectorAll('.pmmsg'))).forEach(pmmsg => {
pmmsg.addEventListener('submit', e => {
let formData = new FormData(pmmsg);
fetch('/api/pm' + '?hash=' + document.getElementById('body').getAttribute('data-hash'), {
@@ -660,13 +666,13 @@ ready(() => {
e.addEventListener('click', function(e) {
setPrivacy(
e.target,
- /** @type HTMLElement */(e.target).closest('article').getAttribute('data-mid'));
+ /** @type {HTMLElement} */(e.target).closest('article').getAttribute('data-mid'));
e.preventDefault();
});
});
Array.from(document.querySelectorAll('.ir a[data-fname], .msg-media a[data-fname]')).forEach(function(el) {
el.addEventListener('click', function(e) {
- let fname = /** @type HTMLElement */ (e.target).closest('[data-fname]').getAttribute('data-fname');
+ let fname = /** @type {HTMLElement} */ (e.target).closest('[data-fname]').getAttribute('data-fname');
if (!showPhotoDialog(fname)) {
e.preventDefault();
}
@@ -684,7 +690,7 @@ ready(() => {
e.addEventListener('click', function(e) {
likeMessage(
e.target,
- /** @type HTMLElement */(e.target).closest('article').getAttribute('data-mid'));
+ /** @type {HTMLElement} */(e.target).closest('article').getAttribute('data-mid'));
e.preventDefault();
});
});
@@ -705,10 +711,10 @@ ready(() => {
var unfoldall = document.getElementById('unfoldall');
if (unfoldall) {
unfoldall.addEventListener('click', function(e) {
- /** @type HTMLElement[] */ (Array.from(document.querySelectorAll('#replies>li'))).forEach(function(e) {
+ /** @type {HTMLElement[]} */ (Array.from(document.querySelectorAll('#replies>li'))).forEach(function(e) {
e.style.display = 'block';
});
- /** @type HTMLElement[] */ (Array.from(document.querySelectorAll('#replies .msg-comments'))).forEach(function(e) {
+ /** @type {HTMLElement[]} */ (Array.from(document.querySelectorAll('#replies .msg-comments'))).forEach(function(e) {
e.style.display = 'none';
});
e.preventDefault();
@@ -758,7 +764,7 @@ ready(() => {
}
});
let location = window.location.href;
- /** @type HTMLLinkElement[] */ (Array.from(document.querySelectorAll('#header_wrapper a'))).forEach(el => {
+ /** @type {HTMLLinkElement[]} */ (Array.from(document.querySelectorAll('#header_wrapper a'))).forEach(el => {
if (el.href === location) {
el.classList.add('active');
el.setAttribute('disabled', 'disabled');