From face3879c1930809fd44eaf1afbfc39fa599a5bb Mon Sep 17 00:00:00 2001 From: Jan Lohage Date: Tue, 5 Jan 2021 17:13:20 +0100 Subject: [PATCH 1/3] Propagate changes of md-rendered checkboxes on an issue page to the server --- web_src/js/index.js | 3 ++ web_src/js/markdown/checkboxes.js | 71 +++++++++++++++++++++++++++++++ 2 files changed, 74 insertions(+) create mode 100644 web_src/js/markdown/checkboxes.js diff --git a/web_src/js/index.js b/web_src/js/index.js index ef674ad6a6b90..87898c67e16f3 100644 --- a/web_src/js/index.js +++ b/web_src/js/index.js @@ -15,6 +15,7 @@ import initHeatmap from './features/heatmap.js'; import initProject from './features/projects.js'; import initServiceWorker from './features/serviceworker.js'; import initMarkdownAnchors from './markdown/anchors.js'; +import initMarkdownCheckboxes from './markdown/checkboxes.js'; import renderMarkdownContent from './markdown/content.js'; import attachTribute from './features/tribute.js'; import createColorPicker from './features/colorpicker.js'; @@ -2571,6 +2572,8 @@ $(document).ready(async () => { renderMarkdownContent(), initGithook(), ]); + + initMarkdownCheckboxes(); }); function changeHash(hash) { diff --git a/web_src/js/markdown/checkboxes.js b/web_src/js/markdown/checkboxes.js new file mode 100644 index 0000000000000..e066e307c08cc --- /dev/null +++ b/web_src/js/markdown/checkboxes.js @@ -0,0 +1,71 @@ +/** + * Affects first comment of issue page only! + * + * Attaches `change` handlers to the markdown rendered checkboxes. + * When a checkbox value changes, the corresponding [ ] or [x] in the markdown string is set accordingly and sent to the server. + * On success it updates the raw-content on error it resets the checkbox to its original value. + */ +export default function initMarkdownCheckboxes() { + const $segment = $('.page-content.issue .comment.first .segment'); + const $checkboxes = $segment.find('.render-content.markdown input:checkbox'); + const $rawContent = $segment.find('.raw-content'); + + const url = $segment.find('.edit-content-zone').data('update-url'); + const context = $segment.find('.edit-content-zone').data('context'); + + const checkboxMarkdownPattern = /\[[ x]]/g; + + const enableAll = () => $checkboxes.removeAttr('disabled'); + const disableAll = () => $checkboxes.attr('disabled', 'disabled'); + + const onChange = async (ev, cbIndex) => { + const $cb = $(ev.target); + const checkboxMarkdown = $cb.is(':checked') ? '[x]' : '[ ]'; + + const oldContent = $rawContent.text(); + const newContent = oldContent.replace(checkboxMarkdownPattern, replaceNthMatchWith(cbIndex, checkboxMarkdown)); + + if (newContent !== oldContent) { + disableAll(); + + try { + await submit(newContent, url, context); + $rawContent.text(newContent); + } catch (e) { + $cb.prop('checked', !$cb.is(':checked')); + + console.error(e); + } finally { + enableAll(); + } + } + }; + + enableAll(); + $checkboxes.each((cbIndex, cb) => { + $(cb).on('change', (ev) => onChange(ev, cbIndex)); + }); +} + +function submit (content, url, context) { + const csrf = window.config.csrf; + + return $.post(url, { + _csrf: csrf, + context, + content, + }); +} + + +function replaceNthMatchWith(n, replaceWith) { + let matchIndex = 0; + + return (match) => { + if (n === matchIndex++) { + return replaceWith; + } + + return match; + }; +} From 6e824dcb81a6585d3d0c0290ca5995ec5fa096f1 Mon Sep 17 00:00:00 2001 From: Jan Lohage Date: Tue, 5 Jan 2021 18:13:26 +0100 Subject: [PATCH 2/3] Make it work for in any comment block --- web_src/js/markdown/checkboxes.js | 67 +++++++++++++++---------------- 1 file changed, 33 insertions(+), 34 deletions(-) diff --git a/web_src/js/markdown/checkboxes.js b/web_src/js/markdown/checkboxes.js index e066e307c08cc..84a3451b1c020 100644 --- a/web_src/js/markdown/checkboxes.js +++ b/web_src/js/markdown/checkboxes.js @@ -1,52 +1,52 @@ +const checkboxMarkdownPattern = /\[[ x]]/g; + /** - * Affects first comment of issue page only! - * - * Attaches `change` handlers to the markdown rendered checkboxes. + * Attaches `change` handlers to markdown rendered checkboxes in comments. * When a checkbox value changes, the corresponding [ ] or [x] in the markdown string is set accordingly and sent to the server. * On success it updates the raw-content on error it resets the checkbox to its original value. */ export default function initMarkdownCheckboxes() { - const $segment = $('.page-content.issue .comment.first .segment'); - const $checkboxes = $segment.find('.render-content.markdown input:checkbox'); - const $rawContent = $segment.find('.raw-content'); - - const url = $segment.find('.edit-content-zone').data('update-url'); - const context = $segment.find('.edit-content-zone').data('context'); + $('.comment .segment').each((_, segment) => { + const $segment = $(segment); + const $checkboxes = $segment.find('.render-content.markdown input:checkbox'); - const checkboxMarkdownPattern = /\[[ x]]/g; + const onChange = async (ev, cbIndex) => { + const $cb = $(ev.target); + const checkboxMarkdown = $cb.is(':checked') ? '[x]' : '[ ]'; - const enableAll = () => $checkboxes.removeAttr('disabled'); - const disableAll = () => $checkboxes.attr('disabled', 'disabled'); + const $rawContent = $segment.find('.raw-content'); + const oldContent = $rawContent.text(); + const newContent = oldContent.replace(checkboxMarkdownPattern, replaceNthMatchWith(cbIndex, checkboxMarkdown)); - const onChange = async (ev, cbIndex) => { - const $cb = $(ev.target); - const checkboxMarkdown = $cb.is(':checked') ? '[x]' : '[ ]'; + if (newContent !== oldContent) { + disableAll($checkboxes); - const oldContent = $rawContent.text(); - const newContent = oldContent.replace(checkboxMarkdownPattern, replaceNthMatchWith(cbIndex, checkboxMarkdown)); + try { + const url = $segment.find('.edit-content-zone').data('update-url'); + const context = $segment.find('.edit-content-zone').data('context'); - if (newContent !== oldContent) { - disableAll(); + await submit(newContent, url, context); + $rawContent.text(newContent); + } catch (e) { + $cb.prop('checked', !$cb.is(':checked')); - try { - await submit(newContent, url, context); - $rawContent.text(newContent); - } catch (e) { - $cb.prop('checked', !$cb.is(':checked')); - - console.error(e); - } finally { - enableAll(); + console.error(e); + } finally { + enableAll($checkboxes); + } } - } - }; + }; - enableAll(); - $checkboxes.each((cbIndex, cb) => { - $(cb).on('change', (ev) => onChange(ev, cbIndex)); + enableAll($checkboxes); + $checkboxes.each((cbIndex, cb) => { + $(cb).on('change', (ev) => onChange(ev, cbIndex)); + }); }); } +function enableAll ($checkboxes) { $checkboxes.removeAttr('disabled') } +function disableAll ($checkboxes) { $checkboxes.attr('disabled', 'disabled') } + function submit (content, url, context) { const csrf = window.config.csrf; @@ -57,7 +57,6 @@ function submit (content, url, context) { }); } - function replaceNthMatchWith(n, replaceWith) { let matchIndex = 0; From 4ac7ad5d0cf9259f37273738542578a59ca92977 Mon Sep 17 00:00:00 2001 From: Jan Lohage Date: Wed, 6 Jan 2021 12:35:55 +0100 Subject: [PATCH 3/3] More consistent variable naming --- web_src/js/markdown/checkboxes.js | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/web_src/js/markdown/checkboxes.js b/web_src/js/markdown/checkboxes.js index 84a3451b1c020..9c4d3f150c76a 100644 --- a/web_src/js/markdown/checkboxes.js +++ b/web_src/js/markdown/checkboxes.js @@ -10,13 +10,13 @@ export default function initMarkdownCheckboxes() { const $segment = $(segment); const $checkboxes = $segment.find('.render-content.markdown input:checkbox'); - const onChange = async (ev, cbIndex) => { - const $cb = $(ev.target); - const checkboxMarkdown = $cb.is(':checked') ? '[x]' : '[ ]'; + const onChange = async (ev, checkboxIndex) => { + const $checkbox = $(ev.target); + const checkboxMarkdown = $checkbox.is(':checked') ? '[x]' : '[ ]'; const $rawContent = $segment.find('.raw-content'); const oldContent = $rawContent.text(); - const newContent = oldContent.replace(checkboxMarkdownPattern, replaceNthMatchWith(cbIndex, checkboxMarkdown)); + const newContent = oldContent.replace(checkboxMarkdownPattern, replaceNthMatchWith(checkboxIndex, checkboxMarkdown)); if (newContent !== oldContent) { disableAll($checkboxes); @@ -28,7 +28,7 @@ export default function initMarkdownCheckboxes() { await submit(newContent, url, context); $rawContent.text(newContent); } catch (e) { - $cb.prop('checked', !$cb.is(':checked')); + $checkbox.prop('checked', !$checkbox.is(':checked')); console.error(e); } finally { @@ -38,8 +38,8 @@ export default function initMarkdownCheckboxes() { }; enableAll($checkboxes); - $checkboxes.each((cbIndex, cb) => { - $(cb).on('change', (ev) => onChange(ev, cbIndex)); + $checkboxes.each((checkboxIndex, checkboxElement) => { + $(checkboxElement).on('change', (ev) => onChange(ev, checkboxIndex)); }); }); }